adding rtos-32 support

This commit is contained in:
skarg
2005-04-22 17:53:19 +00:00
parent ba7e028795
commit 4c5d314f4a
7 changed files with 1167 additions and 0 deletions
+396
View File
@@ -0,0 +1,396 @@
/**************************************************************************
*
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*********************************************************************/
#include <stdint.h> // for standard integer types uint8_t etc.
#include <stdbool.h> // for the standard bool type.
// commonly used comparison address for ethernet
uint8_t Ethernet_Broadcast[MAX_MAC_LEN] =
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
// commonly used empty address for ethernet quick compare
uint8_t Ethernet_Empty_MAC[MAX_MAC_LEN] = { 0, 0, 0, 0, 0, 0 };
// my local device data - MAC address
uint8_t Ethernet_MAC_Address[MAX_MAC_LEN] = { 0, 0, 0, 0, 0, 0 };
// static IP address assignment (default)
static BYTE TargetIP[] = {192, 168, 0, 50};
// net mask - set to be subnet restrictive
static BYTE NetMask[] = {255, 255, 255, 0};
// gateway - set to zero if not available or required
static BYTE DefaultGateway[] = {0, 0, 0, 0};
// DNS - set to zero if not available or required
static BYTE DNSServer[] = {0, 0, 0, 0};
// the actual socket for Ethernet
// SOCKET_ERROR means no open interface
static int Ethernet_Interface = SOCKET_ERROR;
bool ethernet_valid(void)
{
return (Ethernet_Interface != SOCKET_ERROR);
}
void ethernet_cleanup(void)
{
if (ethernet_valid())
xn_interface_close(Ethernet_Interface);
Ethernet_Interface = SOCKET_ERROR;
return;
}
/* function to find the local ethernet MAC address */
static int get_local_hwaddr(int iface, unsigned char *mac)
{
struct _iface_info ii; // contains the hwaddr of the Ethernet interface
/* determine the local MAC address */
xn_interface_info(iface, &ii);
mac[0] = ii.my_ethernet_address[0];
mac[1] = ii.my_ethernet_address[1];
mac[2] = ii.my_ethernet_address[2];
mac[3] = ii.my_ethernet_address[3];
mac[4] = ii.my_ethernet_address[4];
mac[5] = ii.my_ethernet_address[5];
return rv;
}
static void ethernet_error(const char * Msg)
{
printf("%s, error code: %s\n", Msg, xn_geterror_string(WSAGetLastError()));
exit(1);
}
bool ethernet_init(char *interface_name)
{
struct _iface_info ii; // contains the hwaddr of the Ethernet interface
// FIXME: what about other drivers other than DAVICOM?
(void)interface_name;
RTKernelInit(0); // get the kernel going
if (!RTKDebugVersion()) // switch of all diagnostics and error messages of RTIP-32
xn_callbacks()->cb_wr_screen_string_fnc = NULL;
CLKSetTimerIntVal(10*1000); // 10 millisecond tick
RTKDelay(1);
RTCMOSSetSystemTime(); // get the right time-of-day
Ethernet_Interface = xn_rtip_init(); // Initialize the RTIP stack
if (Ethernet_Interface == SOCKET_ERROR)
ethernet_error("xn_rtip_init failed");
atexit(ethernet_cleanup); // make sure the driver is shut down properly
RTCallDebugger(RT_DBG_CALLRESET, (DWORD)exit, 0); // even if we get restarted by the debugger
// PCI device ignores the IRQ and IO parameters
Ethernet_Interface = xn_interface_open_config(
DAVICOM_DEVICE, MINOR_0, 0, 0, 0);
if (Ethernet_Interface == SOCKET_ERROR)
{
fprintf(stderr,"ethernet: Davicom driver failed to initialize\r\n");
return false;
}
xn_interface_info(Ethernet_Interface, &ii);
printf("ethernet: MAC address: %02x-%02x-%02x-%02x-%02x-%02x\n",
ii.my_ethernet_address[0], ii.my_ethernet_address[1],
ii.my_ethernet_address[2], ii.my_ethernet_address[3],
ii.my_ethernet_address[4], ii.my_ethernet_address[5]);
// Set the IP address and interface
printf("ethernet: static IP address %i.%i.%i.%i\n",
TargetIP[0], TargetIP[1], TargetIP[2], TargetIP[3]);
if (xn_set_ip(Ethernet_Interface, TargetIP, NetMask) == SOCKET_ERROR)
{
// FIXME: is this because of a duplicate address? Tell user...
fprintf(stderr,"ethernet: failed to set IP address!\r\n");
return false;
}
// add a route in the routing table
// ip_ffaddr is apparently some global...
xn_rt_add(RT_DEFAULT, ip_ffaddr, DefaultGateway, 1,
Ethernet_Interface, RT_INF);
xn_set_server_list((DWORD*)DNSServer, 1);
return ethernet_valid();
}
/* function to send a packet out the 802.2 socket */
/* returns 0 on success, non-zero on failure */
int ethernet_send(
BACNET_ADDRESS *dest, // destination address
BACNET_ADDRESS *src, // source address
uint8_t *pdu, // any data to be sent - may be null
unsigned pdu_len) // number of bytes of data
{
int status = -1;
int bytes = 0;
uint8_t mtu[MAX_MPDU] = { 0 };
int mtu_len = 0;
int i = 0;
// don't waste time if the socket is not valid
if (Ethernet_Interface < 0)
{
fprintf(stderr, "ethernet: 802.2 socket is invalid!\n");
return status;
}
/* load destination ethernet MAC address */
if (dest->mac_len == 6)
{
for (i = 0; i < 6; i++)
{
mtu[mtu_len] = dest->mac[i];
mtu_len++;
}
}
else
{
fprintf(stderr, "ethernet: invalid destination MAC address!\n");
return status;
}
/* load source ethernet MAC address */
if (src->mac_len == 6)
{
for (i = 0; i < 6; i++)
{
mtu[mtu_len] = src->mac[i];
mtu_len++;
}
}
else
{
fprintf(stderr, "ethernet: invalid source MAC address!\n");
return status;
}
if ((14 + 3 + pdu_len) > MAX_MPDU)
{
fprintf(stderr, "ethernet: PDU is too big to send!\n");
return status;
}
/* packet length */
mtu_len += encode_unsigned16(&mtu[12],
3 /*DSAP,SSAP,LLC*/ + pdu_len);
// Logical PDU portion
mtu[mtu_len++] = 0x82; /* DSAP for BACnet */
mtu[mtu_len++] = 0x82; /* SSAP for BACnet */
mtu[mtu_len++] = 0x03; /* Control byte in header */
memcpy(&mtu[mtu_len], pdu, pdu_len);
mtu_len += pdu_len;
/* Send the packet */
bytes =
sendto(Ethernet_Interface, &mtu, mtu_len, 0,
(struct sockaddr *) &eth_addr, sizeof(struct sockaddr));
/* did it get sent? */
if (bytes < 0) {
fprintf(stderr,"ethernet: Error sending packet: %s\n",
strerror(errno));
return status;
}
// got this far - must be good!
status = 0;
return status;
}
/* function to send a packet out the 802.2 socket */
/* returns zero on success, non-zero on failure */
int ethernet_send_pdu(
BACNET_ADDRESS *dest, // destination address
uint8_t *pdu, // any data to be sent - may be null
unsigned pdu_len) // number of bytes of data
{
int i = 0; // counter
BACNET_ADDRESS src = {0}; // source address
for (i = 0; i < 6; i++)
{
src.mac[i] = Ethernet_MAC_Address[i];
src.mac_len++;
}
/* function to send a packet out the 802.2 socket */
/* returns 1 on success, 0 on failure */
return ethernet_send(dest, // destination address
&src, // source address
pdu, // any data to be sent - may be null
pdu_len); // number of bytes of data
}
// receives an 802.2 framed packet
// returns the number of octets in the PDU, or zero on failure
uint16_t ethernet_receive(
BACNET_ADDRESS *src, // source address
uint8_t *pdu, // PDU data
uint16_t max_pdu, // amount of space available in the PDU
unsigned timeout) // number of milliseconds to wait for a packet
{
int received_bytes;
uint8_t buf[MAX_MPDU] = {0}; // data
uint16_t pdu_len = 0; // return value
fd_set read_fds;
int max;
struct timeval select_timeout;
/* Make sure the socket is open */
if (Ethernet_Interface <= 0)
return 0;
/* we could just use a non-blocking socket, but that consumes all
the CPU time. We can use a timeout; it is only supported as
a select. */
if (timeout >= 1000)
{
select_timeout.tv_sec = timeout / 1000;
select_timeout.tv_usec =
1000 * (timeout - select_timeout.tv_sec * 1000);
}
else
{
select_timeout.tv_sec = 0;
select_timeout.tv_usec = 1000 * timeout;
}
FD_ZERO(&read_fds);
FD_SET(Ethernet_Interface, &read_fds);
max = Ethernet_Interface;
if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0)
received_bytes = read(Ethernet_Interface, &buf[0], MAX_MPDU);
else
return 0;
/* See if there is a problem */
if (received_bytes < 0) {
// EAGAIN Non-blocking I/O has been selected
// using O_NONBLOCK and no data
// was immediately available for reading.
if (errno != EAGAIN)
fprintf(stderr,"ethernet: Read error in receiving packet: %s\n",
strerror(errno));
return 0;
}
if (received_bytes == 0)
return 0;
/* the signature of an 802.2 BACnet packet */
if ((buf[14] != 0x82) && (buf[15] != 0x82)) {
//fprintf(stderr,"ethernet: Non-BACnet packet\n");
return 0;
}
// copy the source address
src->mac_len = 6;
memmove(src->mac, &buf[6], 6);
// check destination address for when
// the Ethernet card is in promiscious mode
if ((memcmp(&buf[0], Ethernet_MAC_Address,6) != 0)
&& (memcmp(&buf[0], Ethernet_Broadcast, 6) != 0))
{
//fprintf(stderr, "ethernet: This packet isn't for us\n");
return 0;
}
(void)decode_unsigned16(&buf[12],&pdu_len);
pdu_len -= 3 /* DSAP, SSAP, LLC Control */ ;
// copy the buffer into the PDU
if (pdu_len < max_pdu)
memmove(&pdu[0],&buf[17],pdu_len);
return pdu_len;
}
void ethernet_get_my_address(BACNET_ADDRESS *my_address)
{
int i = 0;
my_address->mac_len = 0;
for (i = 0; i < 6; i++)
{
my_address->mac[i] = Ethernet_MAC_Address[i];
my_address->mac_len++;
}
my_address->net = 0; // local only, no routing
my_address->len = 0;
for (i = 0; i < MAX_MAC_LEN; i++)
{
my_address->adr[i] = 0;
}
return;
}
void ethernet_set_broadcast_address(
BACNET_ADDRESS *dest) // destination address
{
int i = 0; // counter
if (dest)
{
for (i = 0; i < 6; i++)
{
dest->mac[i] = Ethernet_Broadcast[i];
}
dest->mac_len = 6;
dest->net = BACNET_BROADCAST_NETWORK;
dest->len = 0; // denotes broadcast address
for (i = 0; i < MAX_MAC_LEN; i++)
{
dest->adr[i] = 0;
}
}
return;
}
void ethernet_debug_address(
const char *info,
BACNET_ADDRESS *dest)
{
int i = 0; // counter
if (info)
fprintf(stderr,"%s",info);
if (dest)
{
fprintf(stderr,"Address:\n");
fprintf(stderr," MAC Length=%d\n",dest->mac_len);
fprintf(stderr," MAC Address=");
for (i = 0; i < MAX_MAC_LEN; i++)
{
fprintf(stderr,"%02X ",(unsigned)dest->mac[i]);
}
fprintf(stderr,"\n");
fprintf(stderr," Net=%hu\n",dest->net);
fprintf(stderr," Len=%d\n",dest->len);
fprintf(stderr," Adr=");
for (i = 0; i < MAX_MAC_LEN; i++)
{
fprintf(stderr,"%02X ",(unsigned)dest->adr[i]);
}
fprintf(stderr,"\n");
}
return;
}
+24
View File
@@ -0,0 +1,24 @@
// * The target computer is IBM-PC-AT compatible.
// * There is a minimum of 4 MB of RAM installed.
#ifdef DEBUGDOS
Region RealModeVectors 0 1k RAM NoAccess // interrupt vectors
Region BIOSDataArea 1k 3k RAM ReadOnly // BIOS data area
Region DOSMem 4k 252k RAM
Region LowMem 256k 256k RAM
#else
Region = RealModeVectors 0, 4k, RAM, NoAccess // interrupt vectors
// note: locate only has 4k granularity so the 0-1k will be readonly
// Region = RealModeVectors 0, 1k, RAM, NoAccess // interrupt vectors
// Region = BIOSDataArea 1k, 3k, RAM, ReadOnly // BIOS data area
Region = LowMem 4k, 508k, RAM, Assign // Conventional memory
#endif
Region = MoreLowMem 512k, 128k, RAM, Assign // Reserved BIOS ext
Region = MonoText B0000h 4k, Device, ReadWrite // Mono text video mem
Region = ColorText B8000h, 4k, Device, ReadWrite // Text mode video ram
Region = DiskOnChip D0000h, 8k, Device, ReadWrite // Driver Ampro Card
Region = DiskOnChip1 E8000h, 32k, Device, ReadWrite // Driver WinSys Card
Region = HighMem 1M, 3M, RAM, Assign // 3mb ext mem on target
Virtual HeapMem 1G
Virtual StackMem 2G
Virtual ProgMem 3G
+128
View File
@@ -0,0 +1,128 @@
/**************************************************************************
*
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*********************************************************************/
#include <rttarget.h>
#include <rtkernel.h>
#include <windows.h>
extern void RTEmuInit(void);
#ifdef _MSC_VER
#define VOIDEXPORT _declspec(dllexport) void __cdecl
#else
#define VOIDEXPORT void __export __cdecl
#endif
/* DISK SYSTEM */
#ifdef DOC // include DiskOnChip driver
#include <rtfiles.h>
#define RTF_MAX_FILES 16 // support for more open files (default is 8)
#define RTF_BUFFERS_IN_BSS // we do not need file I/O before the run-time
#include <rtfdata.c> // system is initialized
//#define READ_HEAD_BUFFER_SIZE 2048+4
//static BYTE ReadAheadBuffer[READ_HEAD_BUFFER_SIZE];
static RTFDrvFLPYData FLPYDriveAData = {0};
static RTFDrvDOCData DOCDriveData = {0};
static RTFDrvIDEData IDEDriveData = {0};
RTFDevice RTFDeviceList[] =
{
/* type,number,flags,driver,driverdata */
{ RTF_DEVICE_FLOPPY, 0, 0, &RTFDrvFloppy, &FLPYDriveAData},
{ RTF_DEVICE_FDISK , 0, 0, &RTFDrvDOC, &DOCDriveData},
{ RTF_DEVICE_FDISK , 0, 0, &RTFDrvIDE, &IDEDriveData},
{ 0 , 0, 0, NULL, NULL}
};
#endif
/* END OF DISK SYSTEM */
/* RTTarget only defines 64 Win32 handles, which are not enough for BACstac */
/* the following code is from the RTTarget manual, page 106 */
#define MAXHANDLES 1024
#define MAXOBJECTS 1024
#define MAXTYPES 32
RTW32Handle RTHandleTable[MAXHANDLES] = {{0}};
int RTHandleCount = MAXHANDLES;
RTW32Object RTObjectTable[MAXOBJECTS] = {{0}};
int RTObjectCount = MAXOBJECTS;
RTW32Types RTTypeTable[MAXTYPES] = {{0}};
int RTTypeCount = MAXTYPES;
#if 0
/* We can embed some files in the RTB file, like a binary
file used for configuring a remote device, using
'Locate File filename HighMem' in the config (.CFG) file.
However, the default setup for RTFiles and RTTarget
doesn't include the RAM files, so we need to specify
that here, as well as the LPT, console, and FAT.
From RTFiles-32 manual, ch. 7, "Using RTFiles-32 with
RTTarget-32" */
RTFileSystem Console =
{ RT_FS_CONSOLE, 0, 0, &RTConsoleFileSystem };
RTFileSystem LPTFiles =
{ RT_FS_LPT_DEVICE, 0, 0, &RTLPTFileSystem };
/* logical drive Z: can be used to access the RAM drive */
RTFileSystem RAMFiles =
{ RT_FS_FILE,1 << ('Z'-'A'), 0, &RTRAMFileSystem };
/* logical drive A: through D: are reserved for FAT */
RTFileSystem FATFiles =
{ RT_FS_FILE | RT_FS_IS_DEFAULT, 0x0F, 0x03, &RTFilesFileSystem };
RTFileSystem *RTFileSystemList[] =
{
&Console,
&LPTFiles,
&RAMFiles,
&FATFiles,
NULL,
};
#endif
/*-----------------------------------*/
VOIDEXPORT Init(void)
{
(void)RTSetFlags(RT_MM_VIRTUAL, 1); // this is the better method
(void)RTCMOSExtendHeap(); // get as much memory as we can
RTCMOSSetSystemTime(); // get the right date and time
RTEmuInit(); // set up floating point emulation
// pizza - RTHaltCPL3 appears to cause problems with file handling
//RTIdleHandler = (void RTTAPI *)RTHaltCPL3; // low power when idle
// not needed with pre-emptive
//RTKTimeSlice(2); // allow same priority task switch
RTKConfig.Flags |= RF_PREEMPTIVE; // preemptive multitasking
RTKConfig.Flags |= RF_WIN32MUTEX_MUTEX; // Win32 mutexes are RTK32 mutexes
RTKConfig.Flags |= RF_FPCONTEXT; // saves floating point context for tasks
RTKConfig.HookedIRQs |= 1 << 1; // hook the keyboard IRQ
RTKConfig.DefaultTaskStackSize = 1024*8; // for Win32 task stacks req = 0
}
+340
View File
@@ -0,0 +1,340 @@
/**************************************************************************
*
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*********************************************************************/
// This is one way to use the embedded BACnet stack under RTOS-32
// compiled with Borland C++ 5.02
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include "config.h"
#include "bacdef.h"
#include "npdu.h"
#include "apdu.h"
#include "device.h"
#include "rp.h"
#include "iam.h"
#include "whois.h"
#include "reject.h"
#include "abort.h"
#include "bacerror.h"
#include "ethernet.h"
// buffers used for transmit and receive
static uint8_t Tx_Buf[MAX_MPDU] = {0};
static uint8_t Rx_Buf[MAX_MPDU] = {0};
static uint8_t Temp_Buf[MAX_APDU] = {0};
// flag to send an I-Am
bool I_Am_Request = true;
void UnrecognizedServiceHandler(
uint8_t *service_request,
uint16_t service_len,
BACNET_ADDRESS *dest,
BACNET_CONFIRMED_SERVICE_DATA *service_data)
{
BACNET_ADDRESS src;
int pdu_len = 0;
ethernet_get_my_address(&src);
// encode the NPDU portion of the packet
pdu_len = npdu_encode_apdu(
&Tx_Buf[0],
dest,
&src,
false, // true for confirmed messages
MESSAGE_PRIORITY_NORMAL);
// encode the APDU portion of the packet
pdu_len += reject_encode_apdu(
&Tx_Buf[pdu_len],
service_data->invoke_id,
REJECT_REASON_UNRECOGNIZED_SERVICE);
(void)ethernet_send_pdu(
dest, // destination address
&Tx_Buf[0],
pdu_len); // number of bytes of data
fprintf(stderr,"Sent Reject!\n");
}
// FIXME: if we handle multiple ports, then a port neutral version
// of this would be nice. Then it could be moved into iam.c
void Send_IAm(void)
{
int pdu_len = 0;
BACNET_ADDRESS dest;
// I-Am is a global broadcast
ethernet_set_broadcast_address(&dest);
// encode the NPDU portion of the packet
pdu_len = npdu_encode_apdu(
&Tx_Buf[0],
&dest,
NULL,
false, // true for confirmed messages
MESSAGE_PRIORITY_NORMAL);
// encode the APDU portion of the packet
pdu_len += iam_encode_apdu(
&Tx_Buf[pdu_len],
Device_Object_Instance_Number(),
MAX_APDU,
SEGMENTATION_NONE,
Device_Vendor_Identifier());
(void)ethernet_send_pdu(
&dest, // destination address
&Tx_Buf[0],
pdu_len); // number of bytes of data
fprintf(stderr,"Sent I-Am Request!\n");
}
void WhoIsHandler(
uint8_t *service_request,
uint16_t service_len,
BACNET_ADDRESS *src)
{
int len = 0;
int32_t low_limit = 0;
int32_t high_limit = 0;
fprintf(stderr,"Received Who-Is Request!\n");
len = whois_decode_service_request(
service_request,
service_len,
&low_limit,
&high_limit);
if (len == 0)
I_Am_Request = true;
else if (len != -1)
{
if ((Device_Object_Instance_Number() >= low_limit) &&
(Device_Object_Instance_Number() <= high_limit))
I_Am_Request = true;
}
return;
}
void ReadPropertyHandler(
uint8_t *service_request,
uint16_t service_len,
BACNET_ADDRESS *src,
BACNET_CONFIRMED_SERVICE_DATA *service_data)
{
BACNET_READ_PROPERTY_DATA rp_data;
int len = 0;
int pdu_len = 0;
BACNET_OBJECT_TYPE object_type;
uint32_t object_instance;
BACNET_PROPERTY_ID object_property;
int32_t array_index;
BACNET_ADDRESS my_address;
fprintf(stderr,"Received Read-Property Request!\n");
len = rp_decode_service_request(
service_request,
service_len,
&object_type,
&object_instance,
&object_property,
&array_index);
// prepare a reply
ethernet_get_my_address(&my_address);
// encode the NPDU portion of the packet
pdu_len = npdu_encode_apdu(
&Tx_Buf[0],
src,
&my_address,
false, // true for confirmed messages
MESSAGE_PRIORITY_NORMAL);
// bad encoding - send an abort
if (len == -1)
{
pdu_len += abort_encode_apdu(
&Tx_Buf[pdu_len],
service_data->invoke_id,
ABORT_REASON_OTHER);
(void)ethernet_send_pdu(
src, // destination address
&Tx_Buf[0],
pdu_len); // number of bytes of data
fprintf(stderr,"Sent Abort!\n");
}
else if (service_data->segmented_message)
{
pdu_len += abort_encode_apdu(
&Tx_Buf[pdu_len],
service_data->invoke_id,
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED);
(void)ethernet_send_pdu(
src, // destination address
&Tx_Buf[0],
pdu_len); // number of bytes of data
}
else
{
switch (object_type)
{
case OBJECT_DEVICE:
// FIXME: probably need a length limitation sent with encode
// FIXME: might need to return error codes
len = Device_Encode_Property_APDU(
&Temp_Buf[0],
object_property,
array_index);
if (len > 0)
{
// encode the APDU portion of the packet
rp_data.object_type = object_type;
rp_data.object_instance = object_instance;
rp_data.object_property = object_property;
rp_data.array_index = array_index;
rp_data.application_data = &Temp_Buf[0];
rp_data.application_data_len = len;
// FIXME: probably need a length limitation sent with encode
pdu_len += rp_ack_encode_apdu(
&Tx_Buf[pdu_len],
service_data->invoke_id,
&rp_data);
(void)ethernet_send_pdu(
src, // destination address
&Tx_Buf[0],
pdu_len); // number of bytes of data
fprintf(stderr,"Sent Read Property Ack!\n");
}
else
{
pdu_len += bacerror_encode_apdu(
&Tx_Buf[pdu_len],
service_data->invoke_id,
SERVICE_CONFIRMED_READ_PROPERTY,
ERROR_CLASS_PROPERTY,
ERROR_CODE_UNKNOWN_PROPERTY);
(void)ethernet_send_pdu(
src, // destination address
&Tx_Buf[0],
pdu_len); // number of bytes of data
fprintf(stderr,"Sent Unknown Property Error!\n");
}
break;
default:
pdu_len += bacerror_encode_apdu(
&Tx_Buf[pdu_len],
service_data->invoke_id,
SERVICE_CONFIRMED_READ_PROPERTY,
ERROR_CLASS_OBJECT,
ERROR_CODE_UNKNOWN_OBJECT);
(void)ethernet_send_pdu(
src, // destination address
&Tx_Buf[0],
pdu_len); // number of bytes of data
fprintf(stderr,"Sent Unknown Object Error!\n");
break;
}
}
return;
}
static void Init_Device_Parameters(void)
{
// configure my initial values
Device_Set_Object_Instance_Number(111);
Device_Set_Vendor_Name("Lithonia Lighting");
Device_Set_Vendor_Identifier(42);
Device_Set_Model_Name("Simple BACnet Server");
Device_Set_Firmware_Revision("1.00");
Device_Set_Application_Software_Version("none");
Device_Set_Description("Example of a simple BACnet server");
return;
}
static void Init_Service_Handlers(void)
{
// we need to handle who-is to support dynamic device binding
apdu_set_unconfirmed_handler(
SERVICE_UNCONFIRMED_WHO_IS,
WhoIsHandler);
// set the handler for all the services we don't implement
// It is required to send the proper reject message...
apdu_set_unrecognized_service_handler_handler(
UnrecognizedServiceHandler);
// we must implement read property - it's required!
apdu_set_confirmed_handler(
SERVICE_CONFIRMED_READ_PROPERTY,
ReadPropertyHandler);
}
int main(int argc, char *argv[])
{
BACNET_ADDRESS src = {0}; // address where message came from
uint16_t pdu_len = 0;
unsigned timeout = 100; // milliseconds
Init_Device_Parameters();
Init_Service_Handlers();
// init the physical layer
if (!ethernet_init("eth0"))
return 1;
// loop forever
for (;;)
{
// input
// returns 0 bytes on timeout
pdu_len = ethernet_receive(
&src,
&Rx_Buf[0],
MAX_MPDU,
timeout);
// process
if (pdu_len)
{
npdu_handler(
&src,
&Rx_Buf[0],
pdu_len);
}
if (I_Am_Request)
{
I_Am_Request = false;
Send_IAm();
}
// output
// blink LEDs, Turn on or off outputs, etc
}
return 0;
}
+153
View File
@@ -0,0 +1,153 @@
#
# Simple makefile to build an RTB executable for RTOS-32
#
# This makefile assumes Borland bcc32 development environment
# on Windows NT/9x/2000/XP
#
!ifndef RTOS32_DIR
RTOS32_DIR_Not_Defined:
@echo .
@echo You must define environment variable RTOS32_DIR to for this build.
!endif
!ifndef BORLAND_DIR
BORLAND_DIR_Not_Defined:
@echo .
@echo You must define environment variable BORLAND_DIR to compile
!endif
PRODUCT = bacnet
PRODUCT_RTB = $(PRODUCT).rtb
PRODUCT_EXE = $(PRODUCT).exe
SRCS = init.c main.c ethernet.c \
..\..\bacdcode.c \
..\..\bigend.c \
..\..\whois.c \
..\..\iam.c \
..\..\rp.c \
..\..\device.c \
..\..\abort.c \
..\..\reject.c \
..\..\bacerror.c \
..\..\apdu.c \
..\..\npdu.c
OBJS = $(SRCS:.c=.obj)
# Compiler definitions
#
CC = $(BORLAND_DIR)\bin\bcc32 +bcc32.cfg
LINK = $(BORLAND_DIR)\bin\tlink32
TLIB = $(BORLAND_DIR)\bin\tlib
LOCATE = $(RTOS32_DIR)\bin\rtloc
#
# Include directories
#
CC_DIR = $(BORLAND_DIR)\BIN
CC_INCLDIR = $(BORLAND_DIR)\include
INCL_DIRS = -I$(BORLAND_DIR)\include;$(RTOS32_DIR)\include
DEFINES = -DDOC
CFLAGS = $(INCL_DIRS) $(CS_FLAGS) $(DEFINES)
# Libraries
#
RTOS32_LIB_DIR = $(RTOS32_DIR)\libbc
C_LIB_DIR = $(BORLAND_DIR)\lib
LIBDIR = $(RTOS32_LIB_DIR);$(C_LIB_DIR)
LIBS = $(RTOS32_LIB_DIR)\RTFILES.LIB \
$(RTOS32_LIB_DIR)\RTFSK32.LIB \
$(RTOS32_LIB_DIR)\DRVDOC.LIB \
$(RTOS32_LIB_DIR)\RTIP.LIB \
$(RTOS32_LIB_DIR)\RTK32.LIB \
$(RTOS32_LIB_DIR)\FLTEMUMT.LIB \
$(RTOS32_LIB_DIR)\DRVRT32.LIB \
$(RTOS32_LIB_DIR)\RTEMUMT.LIB \
$(RTOS32_LIB_DIR)\RTT32.LIB \
$(RTOS32_LIB_DIR)\RTTHEAP.LIB \
$(C_LIB_DIR)\DPMI32.lib \
$(C_LIB_DIR)\IMPORT32.lib \
$(C_LIB_DIR)\CW32MT.lib
#
# Main target
#
# This should be the first one in the makefile
all : $(PRODUCT_RTB) monitor.rtb
monitor.rtb: monitor.cfg hardware.cfg
$(LOCATE) monitor
# debug using COM3 (ISA Card) as the debug port
# boot from floppy
debugcom3: hardware.cfg software.cfg $(PRODUCT_RTB) monitor.rtb
$(LOCATE) -DDEBUGCOM3 monitor
$(LOCATE) -d- -DMONITOR -DDEBUGCOM3 $(PRODUCT) software.cfg
$(PRODUCT_RTB): bcc32.cfg hardware.cfg software.cfg $(PRODUCT_EXE)
@echo Running Locate on $(PRODUCT)
$(LOCATE) $(PRODUCT) software.cfg
# Linker specific: the link below is for BCC linker/compiler. If you link
# with a different linker - please change accordingly.
#
# need a temp response file (@&&) because command line is too long
$(PRODUCT_EXE) : $(OBJS)
@echo Running Linker for $(PRODUCT_EXE)
$(LINK) -L$(LINKER_LIB) -m -c -s -v @&&| # temp response file, starts with |
$(BORLAND_DIR)\lib\c0x32.obj $** # $** lists each dependency
$<
$*.map
$(LIBS)
| # end of temp response file
#
# Utilities
clean :
@echo Deleting obj files, $(PRODUCT_EXE), $(PRODUCT_RTB) and map files.
del *.obj
del $(PRODUCT_EXE)
del $(PRODUCT_RTB)
del *.map
del bcc32.cfg
install : $(PRODUCT)
copy $(PRODUCT) ..\bin
#
# Generic rules
#
.SUFFIXES: .cpp .c .sbr .obj
#
# cc generic rule
#
.c.obj:
@echo Compiling $@ from $<
$(CC) $(CFLAGS) -c -o$@ $<
# Compiler configuration file
bcc32.cfg :
Copy &&|
-y #include line numbers in OBJ's
-v #include debug info
-w+ #turn on all warnings
-Od #disable all optimizations
#-a4 #32 bit data alignment
#-M # generate link map
#-ls # linker options
#-WM- #not multithread
-WM #multithread
-w-aus # ignore warning assigned a value that is never used
-w-sig # ignore warning conversion may lose sig digits
| $@
# EOF: makefile
+46
View File
@@ -0,0 +1,46 @@
// Configuration files for the RTTarget-32 Debug Monitor and Borland C/C++.
// Some general parameters for this file are:
//
// * The default disk boot code is used to boot the system from
// a floppy disk, hard disk, or ROM disk.
// * Pageing is enabled.
// * The program privilege level is set to 3 for maximum protection.
// * Boot code and the Monitor are placed in low (conventional) memory.
// * The target PC is assumed to have a color display.
// * The target PC uses COM1 to communicated with the host.
// * 115200 baud is used for host - target communication.
@HARDWARE.CFG // pull in hardware definitions
Locate BootCode BIOSBOOT.EXE LowMem // boot from disk
Locate BootData BootData LowMem 0 16 // boot stuff must be in conventional memory
Locate DiskBuffer DiskIO LowMem 16k 16k // needed by disk boot code
CPL = 0
Locate Section CODE LowMem 1 // Monitor's code section
Locate Header Monitor LowMem 0 4 // and header
Locate Section DATA LowMem 2 // data section
Locate Stack Stack LowMem 1k 4 // and a small stack, no heap
Locate PageTable Pages LowMem
Locate DecompCode Expand LowMem // include decompression stuff
Locate DecompData ExBuffer LowMem
Locate Copy CODE LowMem // compress everything
Locate Copy DATA LowMem // ditto
Locate Copy Pages LowMem // ditto
#ifdef DEBUGCOM1
COMPort COM1 115200 // use COM1 with 115200 baud
VideoRAM = None // program output sent to debugger - clrscr() crashes it.
#elifdef DEBUGCOM3
COMPort COM3 115200 9 // use COM3 IRQ9 115200 baud - Everex EV170 serial card
VideoRAM = ColorText // program output sent to debugger - clrscr() crashes it.
#else
COMPort COM3 115200 9 // use COM3 IRQ9 115200 baud - Everex EV170 serial card
VideoRAM = ColorText // program output sent to Graphic Card
#endif
IgnoreMsg "No heap" // the monitor does not need a heap
+80
View File
@@ -0,0 +1,80 @@
// Configuration files for the application and Borland C/C++.
// Some general parameters for this file are:
// * The program will run under the control of the debugger or is
// downloaded using RTRun.
// * Paging is enabled.
// * The program privilege level is set to 3 for maximum protection.
// * Boot code and the Monitor are placed in low (conventional) memory.
// * The program is placed in high (extended) memory.
// * Unused low memory is remapped and appended to the high memory area.
// * The Turbo Debugger symbol tables are pulled in to support
// task positions at source level.
@HARDWARE.CFG
#ifdef DEBUGDOS
#define BOOT_DOS
#endif
#ifdef TSYS_DOS
#define BOOT_DOS
#endif
#ifsection .text // redefine some section names for BCB
#define CODE .text
#define DATA .data
#endif
// Either use the monitor, or create bootable code.
#ifdef MONITOR
Reserve Monitor // leave room for Debug Monitor
#elifdef BOOT_DOS
Locate BootCode BIOSBOOT.EXE LowMem // boot from disk, bios, or DOS
Locate BootData BootData LowMem // must be in conventional mem
Locate DiskBuffer DiskIO LowMem 16k 16k // needed by disk boot code
NoFPU=0 // Check FPU
CPL = 3 // normal priveleges
VideoRAM ColorText // program output sent to Graphics Card
#else
Locate BootCode BIOSBOOT.EXE LowMem // boot from disk
Locate BootData BootData LowMem 0 16 // must be in conventional mem
Locate DiskBuffer DiskIO LowMem 16k 16k // needed by disk boot code
NoFPU=0 // Check FPU
CPL = 3 // normal priveleges
VideoRAM ColorText // program output sent to Graphic Card
#endif
FillRAM HeapMem // remap unused RAM
Locate Header Application LowMem // application header
Locate PageTable Paging LowMem 20k // paging to use this
Locate NTSection CODE ProgMem->HighMem // code section
Locate NTSection DATA ProgMem->HighMem // data section
#ifsection .tls // the following sections are not generated by all linker versions
Locate NTSection .tls ProgMem->HighMem // TLS data section
Locate NTSection .rdata ProgMem->HighMem // TLS directory
#endif
Locate Stack Stack StackMem->LowMem 16k // stack space for main()
Locate Heap Heap HeapMem // and the rest for the heap
// Compression needed if we are short on disk space - but shortens download
// Note that this is discardable, unless we use -d- option of RTLoc
Locate DecompCode Expand LowMem // include decompression stuff
Locate DecompData ExBuffer LowMem
Locate Copy Paging LowMem // compress Paging
Locate Copy CODE HighMem // compress CODE
Locate Copy DATA HighMem // compress DATA
#ifndef TSYS_CARD
Locate Nothing FloppyDMA MoreLowMem 18k 64k ReadWrite // floppy driver
#endif
Init _Init // do some standard initializations (see init.c)
CommandLine "bacnet.exe"