Indented.
This commit is contained in:
@@ -15,4 +15,4 @@ typedef signed long int32_t; /* 4 bytes -2147483647 to 2147483647 */
|
||||
/* typedef signed long long int64_t; */
|
||||
/* typedef unsigned long long uint64_t; */
|
||||
|
||||
#endif /* STDINT_H */
|
||||
#endif /* STDINT_H */
|
||||
|
||||
+105
-93
@@ -32,12 +32,12 @@
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include "bacdcode.h"
|
||||
#include "bip.h"
|
||||
#include "eth.h"
|
||||
#include "net.h" /* custom per port */
|
||||
#include "net.h" /* custom per port */
|
||||
|
||||
static int BIP_Socket = -1;
|
||||
/* port to use - stored in host byte order */
|
||||
@@ -47,22 +47,26 @@ static struct in_addr BIP_Address;
|
||||
/* Broadcast Address - stored in host byte order */
|
||||
static struct in_addr BIP_Broadcast_Address;
|
||||
|
||||
void bip_set_socket(int sock_fd)
|
||||
void bip_set_socket(
|
||||
int sock_fd)
|
||||
{
|
||||
BIP_Socket = sock_fd;
|
||||
}
|
||||
|
||||
int bip_socket(void)
|
||||
int bip_socket(
|
||||
void)
|
||||
{
|
||||
return BIP_Socket;
|
||||
}
|
||||
|
||||
bool bip_valid(void)
|
||||
bool bip_valid(
|
||||
void)
|
||||
{
|
||||
return (BIP_Socket != -1);
|
||||
}
|
||||
|
||||
void bip_cleanup(void)
|
||||
void bip_cleanup(
|
||||
void)
|
||||
{
|
||||
/* if (bip_valid()) */
|
||||
/* close(BIP_Socket); */
|
||||
@@ -72,142 +76,149 @@ void bip_cleanup(void)
|
||||
}
|
||||
|
||||
/* set using network byte order */
|
||||
void bip_set_addr(uint32_t net_address)
|
||||
void bip_set_addr(
|
||||
uint32_t net_address)
|
||||
{
|
||||
/* BIP_Address.s_addr = ntohl(net_address); */
|
||||
BIP_Address.s_addr = net_address;
|
||||
}
|
||||
|
||||
/* returns host byte order */
|
||||
uint32_t bip_get_addr(void)
|
||||
uint32_t bip_get_addr(
|
||||
void)
|
||||
{
|
||||
return BIP_Address.s_addr;
|
||||
}
|
||||
|
||||
/* set using network byte order */
|
||||
void bip_set_broadcast_addr(uint32_t net_address)
|
||||
void bip_set_broadcast_addr(
|
||||
uint32_t net_address)
|
||||
{
|
||||
/* BIP_Broadcast_Address.s_addr = ntohl(net_address); */
|
||||
BIP_Broadcast_Address.s_addr = net_address;
|
||||
}
|
||||
|
||||
/* returns host byte order */
|
||||
uint32_t bip_get_broadcast_addr(void)
|
||||
uint32_t bip_get_broadcast_addr(
|
||||
void)
|
||||
{
|
||||
return BIP_Broadcast_Address.s_addr;
|
||||
}
|
||||
|
||||
/* set using host byte order */
|
||||
void bip_set_port(uint16_t port)
|
||||
void bip_set_port(
|
||||
uint16_t port)
|
||||
{
|
||||
BIP_Port = port;
|
||||
}
|
||||
|
||||
/* returns host byte order */
|
||||
uint16_t bip_get_port(void)
|
||||
uint16_t bip_get_port(
|
||||
void)
|
||||
{
|
||||
return BIP_Port;
|
||||
}
|
||||
|
||||
/* function to send a packet out the BACnet/IP socket (Annex J) */
|
||||
/* returns number of bytes sent on success, negative number on failure */
|
||||
int bip_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
int bip_send_pdu(
|
||||
BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len)
|
||||
{ /* number of bytes of data */
|
||||
{ /* number of bytes of data */
|
||||
|
||||
struct sockaddr_in bip_dest;
|
||||
uint8_t mtu[4];
|
||||
int mtu_len = 0;
|
||||
int bytes_sent = 0;
|
||||
UDP_HDR udphdr;
|
||||
IP_HDR iphdr;
|
||||
uint8_t mac[6];
|
||||
struct sockaddr_in bip_dest;
|
||||
uint8_t mtu[4];
|
||||
int mtu_len = 0;
|
||||
int bytes_sent = 0;
|
||||
UDP_HDR udphdr;
|
||||
IP_HDR iphdr;
|
||||
uint8_t mac[6];
|
||||
|
||||
(void) npdu_data;
|
||||
|
||||
/* assumes that the driver has already been initialized */
|
||||
(void) npdu_data;
|
||||
|
||||
/* assumes that the driver has already been initialized */
|
||||
/* if (BIP_Socket < 0) */
|
||||
/* return BIP_Socket; */
|
||||
|
||||
mtu[0] = BVLL_TYPE_BACNET_IP;
|
||||
bip_dest.sin_family = AF_INET;
|
||||
|
||||
if (dest->mac_len == 6)
|
||||
{
|
||||
memcpy(&(bip_dest.sin_addr.s_addr),&dest->mac[0],4);
|
||||
decode_unsigned16(&dest->mac[4], &(bip_dest.sin_port));
|
||||
memset(&(bip_dest.sin_zero), '\0', 8);
|
||||
mtu[1] = BVLC_ORIGINAL_UNICAST_NPDU;
|
||||
}
|
||||
/* broadcast */
|
||||
else if (dest->mac_len == 0)
|
||||
{
|
||||
bip_dest.sin_addr.s_addr = BIP_Broadcast_Address.s_addr;
|
||||
bip_dest.sin_port = htons(BIP_Port);
|
||||
memset(&(bip_dest.sin_zero), '\0', 8);
|
||||
mtu[1] = BVLC_ORIGINAL_BROADCAST_NPDU;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
|
||||
mtu_len = 2;
|
||||
mtu_len += encode_unsigned16(&mtu[mtu_len], (uint16_t) (pdu_len + 4 /*inclusive */ ));
|
||||
mtu_len += pdu_len;
|
||||
|
||||
/* IP address should be in network byte order */
|
||||
ARPIsResolved(bip_dest.sin_addr.s_addr, mac);
|
||||
mtu[0] = BVLL_TYPE_BACNET_IP;
|
||||
bip_dest.sin_family = AF_INET;
|
||||
|
||||
iphdr.vhl = 0x45;
|
||||
iphdr.tos = 0;
|
||||
iphdr.iplen = htons(mtu_len + sizeof(IP_HDR) + sizeof(UDP_HDR));
|
||||
++ipid;
|
||||
iphdr.ipid = htons(ipid);
|
||||
iphdr.ipoffset[0] = iphdr.ipoffset[1] = 0;
|
||||
iphdr.ttl = UIP_TTL;
|
||||
iphdr.proto = UIP_PROTO_UDP;
|
||||
iphdr.ipchksum = 0;
|
||||
iphdr.srcipaddr = BIP_Address.s_addr;
|
||||
iphdr.destipaddr = bip_dest.sin_addr.s_addr;
|
||||
|
||||
/* Calculate IP checksum. */
|
||||
iphdr.ipchksum = ~(ip_getchksum((uint8_t*)&iphdr));
|
||||
if (dest->mac_len == 6) {
|
||||
memcpy(&(bip_dest.sin_addr.s_addr), &dest->mac[0], 4);
|
||||
decode_unsigned16(&dest->mac[4], &(bip_dest.sin_port));
|
||||
memset(&(bip_dest.sin_zero), '\0', 8);
|
||||
mtu[1] = BVLC_ORIGINAL_UNICAST_NPDU;
|
||||
}
|
||||
/* broadcast */
|
||||
else if (dest->mac_len == 0) {
|
||||
bip_dest.sin_addr.s_addr = BIP_Broadcast_Address.s_addr;
|
||||
bip_dest.sin_port = htons(BIP_Port);
|
||||
memset(&(bip_dest.sin_zero), '\0', 8);
|
||||
mtu[1] = BVLC_ORIGINAL_BROADCAST_NPDU;
|
||||
} else
|
||||
return -1;
|
||||
|
||||
/* Ports are sent in Network byte order. BIP_Port is stored in Host byte order */
|
||||
udphdr.srcport = htons(BIP_Port);
|
||||
udphdr.destport = bip_dest.sin_port;
|
||||
udphdr.udplen = htons(mtu_len + sizeof(UDP_HDR));
|
||||
/* Not using UDP checksums */
|
||||
udphdr.udpchksum = 0;
|
||||
mtu_len = 2;
|
||||
mtu_len +=
|
||||
encode_unsigned16(&mtu[mtu_len],
|
||||
(uint16_t) (pdu_len + 4 /*inclusive */ ));
|
||||
mtu_len += pdu_len;
|
||||
|
||||
/* IP address should be in network byte order */
|
||||
ARPIsResolved(bip_dest.sin_addr.s_addr, mac);
|
||||
|
||||
iphdr.vhl = 0x45;
|
||||
iphdr.tos = 0;
|
||||
iphdr.iplen = htons(mtu_len + sizeof(IP_HDR) + sizeof(UDP_HDR));
|
||||
++ipid;
|
||||
iphdr.ipid = htons(ipid);
|
||||
iphdr.ipoffset[0] = iphdr.ipoffset[1] = 0;
|
||||
iphdr.ttl = UIP_TTL;
|
||||
iphdr.proto = UIP_PROTO_UDP;
|
||||
iphdr.ipchksum = 0;
|
||||
iphdr.srcipaddr = BIP_Address.s_addr;
|
||||
iphdr.destipaddr = bip_dest.sin_addr.s_addr;
|
||||
|
||||
/* Calculate IP checksum. */
|
||||
iphdr.ipchksum = ~(ip_getchksum((uint8_t *) & iphdr));
|
||||
|
||||
/* Ports are sent in Network byte order. BIP_Port is stored in Host byte order */
|
||||
udphdr.srcport = htons(BIP_Port);
|
||||
udphdr.destport = bip_dest.sin_port;
|
||||
udphdr.udplen = htons(mtu_len + sizeof(UDP_HDR));
|
||||
/* Not using UDP checksums */
|
||||
udphdr.udpchksum = 0;
|
||||
|
||||
EthernetSendHeader(mac, UIP_ETHTYPE_IP);
|
||||
EthernetSend((uint8_t *) & iphdr, sizeof(IP_HDR));
|
||||
EthernetSend((uint8_t *) & udphdr, sizeof(UDP_HDR));
|
||||
EthernetSend(mtu, 4);
|
||||
EthernetSend(pdu, pdu_len);
|
||||
EthernetFlush();
|
||||
uip_stat.ip.sent++;
|
||||
|
||||
EthernetSendHeader(mac, UIP_ETHTYPE_IP);
|
||||
EthernetSend((uint8_t*)&iphdr, sizeof(IP_HDR));
|
||||
EthernetSend((uint8_t*)&udphdr, sizeof(UDP_HDR));
|
||||
EthernetSend(mtu, 4);
|
||||
EthernetSend(pdu, pdu_len);
|
||||
EthernetFlush();
|
||||
uip_stat.ip.sent++;
|
||||
|
||||
}
|
||||
|
||||
/* receives a BACnet/IP packet */
|
||||
/* returns the number of octets in the PDU, or zero on failure */
|
||||
uint16_t bip_receive(BACNET_ADDRESS * src, /* source address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t max_pdu, /* amount of space available in the PDU */
|
||||
uint16_t bip_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 */
|
||||
return 0;
|
||||
{ /* number of milliseconds to wait for a packet */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bip_get_my_address(BACNET_ADDRESS * my_address)
|
||||
void bip_get_my_address(
|
||||
BACNET_ADDRESS * my_address)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
my_address->mac_len = 6;
|
||||
(void) encode_unsigned32(&my_address->mac[0],
|
||||
htonl(BIP_Address.s_addr));
|
||||
(void) encode_unsigned32(&my_address->mac[0], htonl(BIP_Address.s_addr));
|
||||
(void) encode_unsigned16(&my_address->mac[4], htons(BIP_Port));
|
||||
my_address->net = 0; /* local only, no routing */
|
||||
my_address->len = 0; /* no SLEN */
|
||||
@@ -219,9 +230,10 @@ void bip_get_my_address(BACNET_ADDRESS * my_address)
|
||||
return;
|
||||
}
|
||||
|
||||
void bip_get_broadcast_address(BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
void bip_get_broadcast_address(
|
||||
BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
|
||||
if (dest) {
|
||||
dest->mac_len = 6;
|
||||
@@ -229,7 +241,7 @@ void bip_get_broadcast_address(BACNET_ADDRESS * dest)
|
||||
htonl(BIP_Broadcast_Address.s_addr));
|
||||
(void) encode_unsigned16(&dest->mac[4], htons(BIP_Port));
|
||||
dest->net = BACNET_BROADCAST_NETWORK;
|
||||
dest->len = 0; /* no SLEN */
|
||||
dest->len = 0; /* no SLEN */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
/* no SADR */
|
||||
dest->adr[i] = 0;
|
||||
|
||||
@@ -29,21 +29,20 @@
|
||||
#include "stdint.h"
|
||||
|
||||
struct sockaddr {
|
||||
uint16_t sa_family;
|
||||
char sa_data[14];
|
||||
uint16_t sa_family;
|
||||
char sa_data[14];
|
||||
};
|
||||
|
||||
|
||||
struct in_addr {
|
||||
uint32_t s_addr; /* load with inet_aton() */
|
||||
uint32_t s_addr; /* load with inet_aton() */
|
||||
};
|
||||
|
||||
struct sockaddr_in
|
||||
{
|
||||
int16_t sin_family; /* e.g. AF_INET */
|
||||
uint16_t sin_port; /* e.g. htons(3490) */
|
||||
struct in_addr sin_addr; /* see struct in_addr, below */
|
||||
char sin_zero[8]; /* zero this if you want to */
|
||||
struct sockaddr_in {
|
||||
int16_t sin_family; /* e.g. AF_INET */
|
||||
uint16_t sin_port; /* e.g. htons(3490) */
|
||||
struct in_addr sin_addr; /* see struct in_addr, below */
|
||||
char sin_zero[8]; /* zero this if you want to */
|
||||
};
|
||||
|
||||
|
||||
@@ -74,42 +73,47 @@ typedef int socklen_t;
|
||||
((((uint32_t)(n) & 0xFF000000)) >> 24))
|
||||
|
||||
|
||||
#define AF_UNIX 1 /* local to host (pipes, portals) */
|
||||
#define AF_INET 2 /* internetwork: UDP, TCP, etc. */
|
||||
#define AF_IMPLINK 3 /* arpanet imp addresses */
|
||||
#define AF_PUP 4 /* pup protocols: e.g. BSP */
|
||||
#define AF_CHAOS 5 /* mit CHAOS protocols */
|
||||
#define AF_NS 6 /* XEROX NS protocols */
|
||||
#define AF_IPX AF_NS /* IPX protocols: IPX, SPX, etc. */
|
||||
#define AF_ISO 7 /* ISO protocols */
|
||||
#define AF_OSI AF_ISO /* OSI is ISO */
|
||||
#define AF_ECMA 8 /* european computer manufacturers */
|
||||
#define AF_DATAKIT 9 /* datakit protocols */
|
||||
#define AF_CCITT 10 /* CCITT protocols, X.25 etc */
|
||||
#define AF_SNA 11 /* IBM SNA */
|
||||
#define AF_DECnet 12 /* DECnet */
|
||||
#define AF_DLI 13 /* Direct data link interface */
|
||||
#define AF_LAT 14 /* LAT */
|
||||
#define AF_HYLINK 15 /* NSC Hyperchannel */
|
||||
#define AF_APPLETALK 16 /* AppleTalk */
|
||||
#define AF_NETBIOS 17 /* NetBios-style addresses */
|
||||
#define AF_VOICEVIEW 18 /* VoiceView */
|
||||
#define AF_FIREFOX 19 /* Protocols from Firefox */
|
||||
#define AF_UNKNOWN1 20 /* Somebody is using this! */
|
||||
#define AF_BAN 21 /* Banyan */
|
||||
#define AF_ATM 22 /* Native ATM Services */
|
||||
#define AF_INET6 23 /* Internetwork Version 6 */
|
||||
#define AF_CLUSTER 24 /* Microsoft Wolfpack */
|
||||
#define AF_12844 25 /* IEEE 1284.4 WG AF */
|
||||
#define AF_IRDA 26 /* IrDA */
|
||||
#define AF_NETDES 28 /* Network Designers OSI & gateway
|
||||
enabled protocols */
|
||||
#define AF_UNIX 1 /* local to host (pipes, portals) */
|
||||
#define AF_INET 2 /* internetwork: UDP, TCP, etc. */
|
||||
#define AF_IMPLINK 3 /* arpanet imp addresses */
|
||||
#define AF_PUP 4 /* pup protocols: e.g. BSP */
|
||||
#define AF_CHAOS 5 /* mit CHAOS protocols */
|
||||
#define AF_NS 6 /* XEROX NS protocols */
|
||||
#define AF_IPX AF_NS /* IPX protocols: IPX, SPX, etc. */
|
||||
#define AF_ISO 7 /* ISO protocols */
|
||||
#define AF_OSI AF_ISO /* OSI is ISO */
|
||||
#define AF_ECMA 8 /* european computer manufacturers */
|
||||
#define AF_DATAKIT 9 /* datakit protocols */
|
||||
#define AF_CCITT 10 /* CCITT protocols, X.25 etc */
|
||||
#define AF_SNA 11 /* IBM SNA */
|
||||
#define AF_DECnet 12 /* DECnet */
|
||||
#define AF_DLI 13 /* Direct data link interface */
|
||||
#define AF_LAT 14 /* LAT */
|
||||
#define AF_HYLINK 15 /* NSC Hyperchannel */
|
||||
#define AF_APPLETALK 16 /* AppleTalk */
|
||||
#define AF_NETBIOS 17 /* NetBios-style addresses */
|
||||
#define AF_VOICEVIEW 18 /* VoiceView */
|
||||
#define AF_FIREFOX 19 /* Protocols from Firefox */
|
||||
#define AF_UNKNOWN1 20 /* Somebody is using this! */
|
||||
#define AF_BAN 21 /* Banyan */
|
||||
#define AF_ATM 22 /* Native ATM Services */
|
||||
#define AF_INET6 23 /* Internetwork Version 6 */
|
||||
#define AF_CLUSTER 24 /* Microsoft Wolfpack */
|
||||
#define AF_12844 25 /* IEEE 1284.4 WG AF */
|
||||
#define AF_IRDA 26 /* IrDA */
|
||||
#define AF_NETDES 28 /* Network Designers OSI & gateway
|
||||
enabled protocols */
|
||||
#define AF_TCNPROCESS 29
|
||||
#define AF_TCNMESSAGE 30
|
||||
#define AF_ICLFXBM 31
|
||||
|
||||
#define AF_MAX 32
|
||||
|
||||
extern void set_address(uint32_t *net_address, uint8_t octet1, uint8_t octet2, uint8_t octet3, uint8_t octet4);
|
||||
extern void set_address(
|
||||
uint32_t * net_address,
|
||||
uint8_t octet1,
|
||||
uint8_t octet2,
|
||||
uint8_t octet3,
|
||||
uint8_t octet4);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
/* Analog Input = Photocell */
|
||||
#define MAX_ANALOG_INPUTS 2
|
||||
#if (MAX_ANALOG_INPUTS > 9)
|
||||
#error Modify the Analog_Input_Name to handle multiple digits
|
||||
#error Modify the Analog_Input_Name to handle multiple digits
|
||||
#endif
|
||||
|
||||
static uint8_t Present_Value[MAX_ANALOG_INPUTS];
|
||||
@@ -44,7 +44,8 @@ static uint8_t Present_Value[MAX_ANALOG_INPUTS];
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Analog_Input_Valid_Instance(uint32_t object_instance)
|
||||
bool Analog_Input_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ANALOG_INPUTS)
|
||||
return true;
|
||||
@@ -53,95 +54,104 @@ bool Analog_Input_Valid_Instance(uint32_t object_instance)
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Analog_Input_Count(void)
|
||||
unsigned Analog_Input_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_ANALOG_INPUTS;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
uint32_t Analog_Input_Index_To_Instance(unsigned index)
|
||||
uint32_t Analog_Input_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
char *Analog_Input_Name(uint32_t object_instance)
|
||||
char *Analog_Input_Name(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
static char text_string[16] = "AI-0"; /* okay for single thread */
|
||||
static char text_string[16] = "AI-0"; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_ANALOG_INPUTS) {
|
||||
text_string[3] = '0' + (uint8_t)object_instance;
|
||||
text_string[3] = '0' + (uint8_t) object_instance;
|
||||
return text_string;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static float Analog_Input_Present_Value(uint32_t object_instance)
|
||||
static float Analog_Input_Present_Value(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
float value = 0.0;
|
||||
|
||||
if (object_instance < MAX_ANALOG_INPUTS)
|
||||
value = Present_Value[object_instance];
|
||||
|
||||
return value;
|
||||
float value = 0.0;
|
||||
|
||||
if (object_instance < MAX_ANALOG_INPUTS)
|
||||
value = Present_Value[object_instance];
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* return apdu length, or -1 on error */
|
||||
/* assumption - object has already exists */
|
||||
int Analog_Input_Encode_Property_APDU(uint8_t * apdu,
|
||||
int Analog_Input_Encode_Property_APDU(
|
||||
uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
int32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
|
||||
(void) array_index;
|
||||
switch (property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len = encode_application_object_id(&apdu[0], OBJECT_ANALOG_INPUT,
|
||||
object_instance);
|
||||
break;
|
||||
/* note: Name and Description don't have to be the same.
|
||||
You could make Description writable and different */
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Analog_Input_Name(object_instance));
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0],
|
||||
OBJECT_ANALOG_INPUT);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
apdu_len = encode_application_real(&apdu[0],
|
||||
Analog_Input_Present_Value(object_instance));
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_UNITS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT);
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ANALOG_INPUT,
|
||||
object_instance);
|
||||
break;
|
||||
/* note: Name and Description don't have to be the same.
|
||||
You could make Description writable and different */
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Analog_Input_Name(object_instance));
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0],
|
||||
OBJECT_ANALOG_INPUT);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
apdu_len = encode_application_real(&apdu[0],
|
||||
Analog_Input_Present_Value(object_instance));
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_UNITS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT);
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
@@ -152,7 +162,8 @@ int Analog_Input_Encode_Property_APDU(uint8_t * apdu,
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
void testAnalogInput(Test * pTest)
|
||||
void testAnalogInput(
|
||||
Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
@@ -168,8 +179,7 @@ void testAnalogInput(Test * pTest)
|
||||
/* FIXME: we should do a lot more testing here... */
|
||||
len = Analog_Input_Encode_Property_APDU(&apdu[0],
|
||||
instance,
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
ct_test(pTest, len >= 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
@@ -182,7 +192,8 @@ void testAnalogInput(Test * pTest)
|
||||
}
|
||||
|
||||
#ifdef TEST_ANALOG_INPUT
|
||||
int main(void)
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -199,5 +210,5 @@ int main(void)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_ANALOG_INPUT */
|
||||
#endif /* TEST */
|
||||
#endif /* TEST_ANALOG_INPUT */
|
||||
#endif /* TEST */
|
||||
|
||||
+1528
-1505
File diff suppressed because it is too large
Load Diff
+190
-172
@@ -31,12 +31,12 @@
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
|
||||
#define MAX_ANALOG_VALUES 4
|
||||
#if (MAX_ANALOG_VALUES > 9)
|
||||
#error Modify the Analog_Value_Name to handle multiple digits
|
||||
#error Modify the Analog_Value_Name to handle multiple digits
|
||||
#endif
|
||||
|
||||
/* we choose to have a NULL level in our system represented by */
|
||||
@@ -54,7 +54,8 @@ static uint8_t Present_Value[MAX_ANALOG_VALUES];
|
||||
/* we need to have our arrays initialized before answering any calls */
|
||||
static bool Analog_Value_Initialized = false;
|
||||
|
||||
void Analog_Value_Init(void)
|
||||
void Analog_Value_Init(
|
||||
void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
@@ -73,7 +74,8 @@ void Analog_Value_Init(void)
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Analog_Value_Valid_Instance(uint32_t object_instance)
|
||||
bool Analog_Value_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
Analog_Value_Init();
|
||||
if (object_instance < MAX_ANALOG_VALUES)
|
||||
@@ -84,7 +86,8 @@ bool Analog_Value_Valid_Instance(uint32_t object_instance)
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Analog_Value_Count(void)
|
||||
unsigned Analog_Value_Count(
|
||||
void)
|
||||
{
|
||||
Analog_Value_Init();
|
||||
return MAX_ANALOG_VALUES;
|
||||
@@ -93,7 +96,8 @@ unsigned Analog_Value_Count(void)
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the instance */
|
||||
/* that correlates to the correct index */
|
||||
uint32_t Analog_Value_Index_To_Instance(unsigned index)
|
||||
uint32_t Analog_Value_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
Analog_Value_Init();
|
||||
return index;
|
||||
@@ -102,7 +106,8 @@ uint32_t Analog_Value_Index_To_Instance(unsigned index)
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned Analog_Value_Instance_To_Index(uint32_t object_instance)
|
||||
unsigned Analog_Value_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_ANALOG_VALUES;
|
||||
|
||||
@@ -113,7 +118,8 @@ unsigned Analog_Value_Instance_To_Index(uint32_t object_instance)
|
||||
return index;
|
||||
}
|
||||
|
||||
static float Analog_Value_Present_Value(uint32_t object_instance)
|
||||
static float Analog_Value_Present_Value(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
float value = ANALOG_RELINQUISH_DEFAULT;
|
||||
unsigned index = 0;
|
||||
@@ -128,12 +134,13 @@ static float Analog_Value_Present_Value(uint32_t object_instance)
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
char *Analog_Value_Name(uint32_t object_instance)
|
||||
char *Analog_Value_Name(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
static char text_string[16] = "AV-0"; /* okay for single thread */
|
||||
static char text_string[16] = "AV-0"; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_ANALOG_VALUES) {
|
||||
text_string[3] = '0' + (uint8_t)object_instance;
|
||||
text_string[3] = '0' + (uint8_t) object_instance;
|
||||
return text_string;
|
||||
}
|
||||
|
||||
@@ -141,13 +148,15 @@ char *Analog_Value_Name(uint32_t object_instance)
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
int Analog_Value_Encode_Property_APDU(uint8_t * apdu,
|
||||
int Analog_Value_Encode_Property_APDU(
|
||||
uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
int32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
float real_value = (float) 1.414;
|
||||
@@ -160,110 +169,118 @@ int Analog_Value_Encode_Property_APDU(uint8_t * apdu,
|
||||
|
||||
Analog_Value_Init();
|
||||
switch (property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len = encode_application_object_id(&apdu[0], OBJECT_ANALOG_VALUE,
|
||||
object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Analog_Value_Name(object_instance));
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], OBJECT_ANALOG_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
real_value = Analog_Value_Present_Value(object_instance);
|
||||
apdu_len = encode_application_real(&apdu[0], real_value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
#if 0
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
state = Analog_Value_Out_Of_Service[object_index];
|
||||
#endif
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_UNITS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT);
|
||||
break;
|
||||
#if 0
|
||||
case PROP_PRIORITY_ARRAY:
|
||||
/* Array element zero is the number of elements in the array */
|
||||
if (array_index == 0)
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], BACNET_MAX_PRIORITY);
|
||||
/* if no index was specified, then try to encode the entire list */
|
||||
/* into one packet. */
|
||||
else if (array_index == BACNET_ARRAY_ALL) {
|
||||
encode_application_object_id(&apdu[0], OBJECT_ANALOG_VALUE,
|
||||
object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Analog_Value_Name(object_instance));
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_ANALOG_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
real_value = Analog_Value_Present_Value(object_instance);
|
||||
apdu_len = encode_application_real(&apdu[0], real_value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
#if 0
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
|
||||
/* FIXME: check if we have room before adding it to APDU */
|
||||
if (Present_Value[object_index][i] ==
|
||||
ANALOG_LEVEL_NULL)
|
||||
len = encode_application_null(&apdu[apdu_len]);
|
||||
else {
|
||||
real_value = Present_Value[object_index][i];
|
||||
len = encode_application_real(&apdu[apdu_len], real_value);
|
||||
}
|
||||
/* add it if we have room */
|
||||
if ((apdu_len + len) < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
*error_class = ERROR_CLASS_SERVICES;
|
||||
*error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
if (array_index <= BACNET_MAX_PRIORITY) {
|
||||
if (Present_Value[object_index][array_index - 1] ==
|
||||
ANALOG_LEVEL_NULL)
|
||||
apdu_len = encode_application_null(&apdu[0]);
|
||||
else {
|
||||
real_value =
|
||||
Present_Value[object_index][array_index - 1];
|
||||
apdu_len = encode_application_real(&apdu[0], real_value);
|
||||
state = Analog_Value_Out_Of_Service[object_index];
|
||||
#endif
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_UNITS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT);
|
||||
break;
|
||||
#if 0
|
||||
case PROP_PRIORITY_ARRAY:
|
||||
/* Array element zero is the number of elements in the array */
|
||||
if (array_index == 0)
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], BACNET_MAX_PRIORITY);
|
||||
/* if no index was specified, then try to encode the entire list */
|
||||
/* into one packet. */
|
||||
else if (array_index == BACNET_ARRAY_ALL) {
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
|
||||
/* FIXME: check if we have room before adding it to APDU */
|
||||
if (Present_Value[object_index][i] == ANALOG_LEVEL_NULL)
|
||||
len = encode_application_null(&apdu[apdu_len]);
|
||||
else {
|
||||
real_value = Present_Value[object_index][i];
|
||||
len =
|
||||
encode_application_real(&apdu[apdu_len],
|
||||
real_value);
|
||||
}
|
||||
/* add it if we have room */
|
||||
if ((apdu_len + len) < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
*error_class = ERROR_CLASS_SERVICES;
|
||||
*error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = -1;
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
if (array_index <= BACNET_MAX_PRIORITY) {
|
||||
if (Present_Value[object_index][array_index - 1] ==
|
||||
ANALOG_LEVEL_NULL)
|
||||
apdu_len = encode_application_null(&apdu[0]);
|
||||
else {
|
||||
real_value =
|
||||
Present_Value[object_index][array_index - 1];
|
||||
apdu_len =
|
||||
encode_application_real(&apdu[0], real_value);
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case PROP_RELINQUISH_DEFAULT:
|
||||
real_value = ANALOG_RELINQUISH_DEFAULT;
|
||||
apdu_len = encode_application_real(&apdu[0], real_value);
|
||||
break;
|
||||
break;
|
||||
case PROP_RELINQUISH_DEFAULT:
|
||||
real_value = ANALOG_RELINQUISH_DEFAULT;
|
||||
apdu_len = encode_application_real(&apdu[0], real_value);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Analog_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
bool Analog_Value_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
@@ -284,80 +301,80 @@ bool Analog_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
/* FIXME: len == 0: unable to decode? */
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_REAL) {
|
||||
priority = wp_data->priority;
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
|
||||
(priority != 6 /* reserved */ ) &&
|
||||
(value.type.Real >= 0.0) && (value.type.Real <= 100.0)) {
|
||||
level = (uint8_t) value.type.Real;
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->
|
||||
object_instance);
|
||||
priority--;
|
||||
Present_Value[object_index] = level;
|
||||
/* Note: you could set the physical output here if we
|
||||
are the highest priority.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. This comment may apply to the
|
||||
main loop (i.e. check out of service before changing output) */
|
||||
status = true;
|
||||
} else if (priority == 6) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_REAL) {
|
||||
priority = wp_data->priority;
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
|
||||
(priority != 6 /* reserved */ ) &&
|
||||
(value.type.Real >= 0.0) && (value.type.Real <= 100.0)) {
|
||||
level = (uint8_t) value.type.Real;
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->
|
||||
object_instance);
|
||||
priority--;
|
||||
Present_Value[object_index] = level;
|
||||
/* Note: you could set the physical output here if we
|
||||
are the highest priority.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. This comment may apply to the
|
||||
main loop (i.e. check out of service before changing output) */
|
||||
status = true;
|
||||
} else if (priority == 6) {
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
#if 0
|
||||
} else if (value.tag == BACNET_APPLICATION_TAG_NULL) {
|
||||
level = ANALOG_LEVEL_NULL;
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->object_instance);
|
||||
priority = wp_data->priority;
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
|
||||
priority--;
|
||||
Present_Value[object_index][priority] = level;
|
||||
/* Note: you could set the physical output here to the next
|
||||
highest priority, or to the relinquish default if no
|
||||
priorities are set.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. This comment may apply to the
|
||||
main loop (i.e. check out of service before changing output) */
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#if 0
|
||||
} else if (value.tag == BACNET_APPLICATION_TAG_NULL) {
|
||||
level = ANALOG_LEVEL_NULL;
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->object_instance);
|
||||
priority = wp_data->priority;
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
|
||||
priority--;
|
||||
Present_Value[object_index][priority] = level;
|
||||
/* Note: you could set the physical output here to the next
|
||||
highest priority, or to the relinquish default if no
|
||||
priorities are set.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. This comment may apply to the
|
||||
main loop (i.e. check out of service before changing output) */
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) {
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->object_instance);
|
||||
Analog_Value_Out_Of_Service[object_index] = value.type.Boolean;
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
} else {
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#if 0
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) {
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->object_instance);
|
||||
Analog_Value_Out_Of_Service[object_index] = value.type.Boolean;
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
@@ -369,7 +386,8 @@ bool Analog_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
void testAnalog_Value(Test * pTest)
|
||||
void testAnalog_Value(
|
||||
Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
@@ -384,8 +402,7 @@ void testAnalog_Value(Test * pTest)
|
||||
|
||||
len = Analog_Value_Encode_Property_APDU(&apdu[0],
|
||||
instance,
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
@@ -398,7 +415,8 @@ void testAnalog_Value(Test * pTest)
|
||||
}
|
||||
|
||||
#ifdef TEST_ANALOG_VALUE
|
||||
int main(void)
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -415,5 +433,5 @@ int main(void)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_ANALOG_VALUE */
|
||||
#endif /* TEST */
|
||||
#endif /* TEST_ANALOG_VALUE */
|
||||
#endif /* TEST */
|
||||
|
||||
@@ -35,26 +35,28 @@
|
||||
|
||||
#define MAX_BINARY_INPUTS 8
|
||||
#if (MAX_BINARY_INPUTS > 9)
|
||||
#error Modify the Binary_Input_Name to handle multiple digits
|
||||
#error Modify the Binary_Input_Name to handle multiple digits
|
||||
#endif
|
||||
|
||||
static BACNET_BINARY_PV Present_Value[MAX_BINARY_INPUTS];
|
||||
|
||||
static void Binary_Input_Initialize(void)
|
||||
static void Binary_Input_Initialize(
|
||||
void)
|
||||
{
|
||||
static bool initialized = false;
|
||||
unsigned i;
|
||||
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
for (i = 0; i < MAX_BINARY_INPUTS; i++) {
|
||||
Present_Value[i] = BINARY_INACTIVE;
|
||||
static bool initialized = false;
|
||||
unsigned i;
|
||||
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
for (i = 0; i < MAX_BINARY_INPUTS; i++) {
|
||||
Present_Value[i] = BINARY_INACTIVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
bool Binary_Input_Valid_Instance(uint32_t object_instance)
|
||||
bool Binary_Input_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_BINARY_INPUTS)
|
||||
return true;
|
||||
@@ -63,13 +65,15 @@ bool Binary_Input_Valid_Instance(uint32_t object_instance)
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Binary_Input_Count(void)
|
||||
unsigned Binary_Input_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_BINARY_INPUTS;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances.*/
|
||||
uint32_t Binary_Input_Index_To_Instance(unsigned index)
|
||||
uint32_t Binary_Input_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
@@ -77,7 +81,8 @@ uint32_t Binary_Input_Index_To_Instance(unsigned index)
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned Binary_Input_Instance_To_Index(uint32_t object_instance)
|
||||
unsigned Binary_Input_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_BINARY_INPUTS;
|
||||
|
||||
@@ -87,8 +92,8 @@ unsigned Binary_Input_Instance_To_Index(uint32_t object_instance)
|
||||
return index;
|
||||
}
|
||||
|
||||
static BACNET_BINARY_PV Binary_Input_Present_Value(uint32_t
|
||||
object_instance)
|
||||
static BACNET_BINARY_PV Binary_Input_Present_Value(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
BACNET_BINARY_PV value = BINARY_INACTIVE;
|
||||
unsigned index = 0;
|
||||
@@ -96,18 +101,19 @@ static BACNET_BINARY_PV Binary_Input_Present_Value(uint32_t
|
||||
Binary_Input_Initialize();
|
||||
index = Binary_Input_Instance_To_Index(object_instance);
|
||||
if (index < MAX_BINARY_INPUTS) {
|
||||
value = Present_Value[index];
|
||||
value = Present_Value[index];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
char *Binary_Input_Name(uint32_t object_instance)
|
||||
char *Binary_Input_Name(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
static char text_string[16] = "BI-0"; /* okay for single thread */
|
||||
static char text_string[16] = "BI-0"; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_BINARY_INPUTS) {
|
||||
text_string[3] = '0' + (uint8_t)object_instance;
|
||||
text_string[3] = '0' + (uint8_t) object_instance;
|
||||
return text_string;
|
||||
}
|
||||
|
||||
@@ -116,13 +122,15 @@ char *Binary_Input_Name(uint32_t object_instance)
|
||||
|
||||
/* return apdu length, or -1 on error */
|
||||
/* assumption - object already exists, and has been bounds checked */
|
||||
int Binary_Input_Encode_Property_APDU(uint8_t * apdu,
|
||||
int Binary_Input_Encode_Property_APDU(
|
||||
uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
int32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
BACNET_POLARITY polarity = POLARITY_NORMAL;
|
||||
@@ -132,48 +140,52 @@ int Binary_Input_Encode_Property_APDU(uint8_t * apdu,
|
||||
(void) array_index;
|
||||
Binary_Input_Initialize();
|
||||
switch (property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len = encode_application_object_id(&apdu[0], OBJECT_BINARY_INPUT,
|
||||
object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
/* note: object name must be unique in our device */
|
||||
characterstring_init_ansi(&char_string,
|
||||
Binary_Input_Name(object_instance));
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], OBJECT_BINARY_INPUT);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
value = Binary_Input_Present_Value(object_instance);
|
||||
apdu_len = encode_application_enumerated(&apdu[0],value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
/* note: see the details in the standard on how to use these */
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
/* note: see the details in the standard on how to use this */
|
||||
apdu_len = encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_POLARITY:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], polarity);
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_BINARY_INPUT,
|
||||
object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
/* note: object name must be unique in our device */
|
||||
characterstring_init_ansi(&char_string,
|
||||
Binary_Input_Name(object_instance));
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_BINARY_INPUT);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
value = Binary_Input_Present_Value(object_instance);
|
||||
apdu_len = encode_application_enumerated(&apdu[0], value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
/* note: see the details in the standard on how to use these */
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
/* note: see the details in the standard on how to use this */
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_POLARITY:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], polarity);
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
@@ -184,7 +196,8 @@ int Binary_Input_Encode_Property_APDU(uint8_t * apdu,
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
void testBinaryInput(Test * pTest)
|
||||
void testBinaryInput(
|
||||
Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
@@ -200,8 +213,7 @@ void testBinaryInput(Test * pTest)
|
||||
/* FIXME: we should do a lot more testing here... */
|
||||
len = Binary_Input_Encode_Property_APDU(&apdu[0],
|
||||
instance,
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
ct_test(pTest, len >= 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
@@ -214,7 +226,8 @@ void testBinaryInput(Test * pTest)
|
||||
}
|
||||
|
||||
#ifdef TEST_BINARY_INPUT
|
||||
int main(void)
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -231,5 +244,5 @@ int main(void)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_BINARY_INPUT */
|
||||
#endif /* TEST */
|
||||
#endif /* TEST_BINARY_INPUT */
|
||||
#endif /* TEST */
|
||||
|
||||
@@ -14,28 +14,30 @@
|
||||
#include "board.h"
|
||||
|
||||
/* global variables */
|
||||
unsigned long blinkcount;
|
||||
unsigned long blinkcount;
|
||||
|
||||
void blinker(
|
||||
unsigned char code)
|
||||
{
|
||||
|
||||
void blinker(unsigned char code) {
|
||||
|
||||
volatile AT91PS_PIO pPIO = AT91C_BASE_PIOA; /* pointer to PIO register structure */
|
||||
volatile unsigned int j,k; /* loop counters */
|
||||
volatile unsigned int j, k; /* loop counters */
|
||||
|
||||
/* endless loop */
|
||||
while (1) {
|
||||
while (1) {
|
||||
/* count out the proper number of blinks */
|
||||
for (j = code; j != 0; j--) {
|
||||
for (j = code; j != 0; j--) {
|
||||
/* turn LED1 (DS1) on */
|
||||
pPIO->PIO_CODR = LED1;
|
||||
/* wait 250 msec */
|
||||
for (k = 600000; k != 0; k-- );
|
||||
for (k = 600000; k != 0; k--);
|
||||
/* turn LED1 (DS1) off */
|
||||
pPIO->PIO_SODR = LED1;
|
||||
/* wait 250 msec */
|
||||
for (k = 600000; k != 0; k-- );
|
||||
for (k = 600000; k != 0; k--);
|
||||
}
|
||||
/* wait 2 seconds */
|
||||
for (k = 5000000; (code != 0) && (k != 0); k-- );
|
||||
for (k = 5000000; (code != 0) && (k != 0); k--);
|
||||
blinkcount++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
// fitness for any particular purpose, or against the infringements of
|
||||
// intellectual property rights of others.
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
// File Name: Board.h
|
||||
// Object: AT91SAM7S Evaluation Board Features Definition File.
|
||||
// File Name: Board.h
|
||||
// Object: AT91SAM7S Evaluation Board Features Definition File.
|
||||
//
|
||||
// Creation: JPP 16/June/2004
|
||||
// Creation: JPP 16/June/2004
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
#ifndef Board_h
|
||||
#define Board_h
|
||||
@@ -35,10 +35,10 @@
|
||||
//------------------------
|
||||
// Leds Definition
|
||||
//------------------------
|
||||
#define LED1 (1<<0) // PA0
|
||||
#define LED2 (1<<1) // PA1
|
||||
#define LED3 (1<<2) // PA2
|
||||
#define LED4 (1<<3) // PA3
|
||||
#define LED1 (1<<0) // PA0
|
||||
#define LED2 (1<<1) // PA1
|
||||
#define LED3 (1<<2) // PA2
|
||||
#define LED4 (1<<3) // PA3
|
||||
#define NB_LEB 4
|
||||
#define LED_MASK (LED1|LED2|LED3|LED4)
|
||||
|
||||
@@ -46,34 +46,34 @@
|
||||
//----------------------------------
|
||||
// Push Buttons Definition
|
||||
//-----------------------------------
|
||||
#define SW1_MASK (1<<19) // PA19
|
||||
#define SW2_MASK (1<<20) // PA20
|
||||
#define SW3_MASK (1<<15) // PA15
|
||||
#define SW4_MASK (1<<14) // PA14
|
||||
#define SW1_MASK (1<<19) // PA19
|
||||
#define SW2_MASK (1<<20) // PA20
|
||||
#define SW3_MASK (1<<15) // PA15
|
||||
#define SW4_MASK (1<<14) // PA14
|
||||
#define SW_MASK (SW1_MASK|SW2_MASK|SW3_MASK|SW4_MASK)
|
||||
|
||||
#define SW1 (1<<19) // PA19
|
||||
#define SW2 (1<<20) // PA20
|
||||
#define SW3 (1<<15) // PA15
|
||||
#define SW4 (1<<14) // PA14
|
||||
#define SW1 (1<<19) // PA19
|
||||
#define SW2 (1<<20) // PA20
|
||||
#define SW3 (1<<15) // PA15
|
||||
#define SW4 (1<<14) // PA14
|
||||
|
||||
//-------------------------
|
||||
// USART Definition
|
||||
//-------------------------
|
||||
// SUB-D 9 points J3 DBGU
|
||||
#define DBGU_RXD AT91C_PA9_DRXD // JP11 must be close
|
||||
#define DBGU_TXD AT91C_PA10_DTXD // JP12 must be close
|
||||
#define AT91C_DBGU_BAUD 115200 // Baud rate
|
||||
#define US_RXD_PIN AT91C_PA5_RXD0 // JP9 must be close
|
||||
#define US_TXD_PIN AT91C_PA6_TXD0 // JP7 must be close
|
||||
#define US_RTS_PIN AT91C_PA7_RTS0 // JP8 must be close
|
||||
#define US_CTS_PIN AT91C_PA8_CTS0 // JP6 must be close
|
||||
#define DBGU_RXD AT91C_PA9_DRXD // JP11 must be close
|
||||
#define DBGU_TXD AT91C_PA10_DTXD // JP12 must be close
|
||||
#define AT91C_DBGU_BAUD 115200 // Baud rate
|
||||
#define US_RXD_PIN AT91C_PA5_RXD0 // JP9 must be close
|
||||
#define US_TXD_PIN AT91C_PA6_TXD0 // JP7 must be close
|
||||
#define US_RTS_PIN AT91C_PA7_RTS0 // JP8 must be close
|
||||
#define US_CTS_PIN AT91C_PA8_CTS0 // JP6 must be close
|
||||
|
||||
//--------------
|
||||
// Master Clock
|
||||
//--------------
|
||||
#define EXT_OC 18432000 // Exetrnal ocilator MAINCK
|
||||
#define MCK 47923200 // MCK (PLLRC div by 2)
|
||||
#define MCKKHz (MCK/1000) //
|
||||
#define EXT_OC 18432000 // Exetrnal ocilator MAINCK
|
||||
#define MCK 47923200 // MCK (PLLRC div by 2)
|
||||
#define MCKKHz (MCK/1000) //
|
||||
|
||||
#endif // Board_h
|
||||
#endif // Board_h
|
||||
|
||||
+155
-140
@@ -31,31 +31,33 @@
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
|
||||
#define MAX_BINARY_VALUES 8
|
||||
#if (MAX_BINARY_VALUES > 9)
|
||||
#error Modify the Binary_Value_Name to handle multiple digits
|
||||
#error Modify the Binary_Value_Name to handle multiple digits
|
||||
#endif
|
||||
|
||||
static BACNET_BINARY_PV Present_Value[MAX_BINARY_VALUES];
|
||||
|
||||
static void Binary_Value_Initialize(void)
|
||||
static void Binary_Value_Initialize(
|
||||
void)
|
||||
{
|
||||
static bool initialized = false;
|
||||
unsigned i;
|
||||
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
for (i = 0; i < MAX_BINARY_VALUES; i++) {
|
||||
Present_Value[i] = BINARY_INACTIVE;
|
||||
static bool initialized = false;
|
||||
unsigned i;
|
||||
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
for (i = 0; i < MAX_BINARY_VALUES; i++) {
|
||||
Present_Value[i] = BINARY_INACTIVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
bool Binary_Value_Valid_Instance(uint32_t object_instance)
|
||||
bool Binary_Value_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_BINARY_VALUES)
|
||||
return true;
|
||||
@@ -64,19 +66,22 @@ bool Binary_Value_Valid_Instance(uint32_t object_instance)
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Binary_Value_Count(void)
|
||||
unsigned Binary_Value_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_BINARY_VALUES;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
uint32_t Binary_Value_Index_To_Instance(unsigned index)
|
||||
uint32_t Binary_Value_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Binary_Value_Instance_To_Index(uint32_t object_instance)
|
||||
unsigned Binary_Value_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_BINARY_VALUES;
|
||||
|
||||
@@ -86,8 +91,8 @@ unsigned Binary_Value_Instance_To_Index(uint32_t object_instance)
|
||||
return index;
|
||||
}
|
||||
|
||||
static BACNET_BINARY_PV Binary_Value_Present_Value(uint32_t
|
||||
object_instance)
|
||||
static BACNET_BINARY_PV Binary_Value_Present_Value(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
BACNET_BINARY_PV value = BINARY_INACTIVE;
|
||||
|
||||
@@ -100,12 +105,13 @@ static BACNET_BINARY_PV Binary_Value_Present_Value(uint32_t
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
char *Binary_Value_Name(uint32_t object_instance)
|
||||
char *Binary_Value_Name(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
static char text_string[16] = "BV-0"; /* okay for single thread */
|
||||
static char text_string[16] = "BV-0"; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_BINARY_VALUES) {
|
||||
text_string[3] = '0' + (uint8_t)object_instance;
|
||||
text_string[3] = '0' + (uint8_t) object_instance;
|
||||
return text_string;
|
||||
}
|
||||
|
||||
@@ -113,13 +119,15 @@ char *Binary_Value_Name(uint32_t object_instance)
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
int Binary_Value_Encode_Property_APDU(uint8_t * apdu,
|
||||
int Binary_Value_Encode_Property_APDU(
|
||||
uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
int32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
BACNET_BINARY_PV present_value = BINARY_INACTIVE;
|
||||
@@ -127,58 +135,64 @@ int Binary_Value_Encode_Property_APDU(uint8_t * apdu,
|
||||
|
||||
Binary_Value_Initialize();
|
||||
switch (property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len = encode_application_object_id(&apdu[0], OBJECT_BINARY_VALUE,
|
||||
object_instance);
|
||||
break;
|
||||
/* note: Name and Description don't have to be the same.
|
||||
You could make Description writable and different */
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Binary_Value_Name(object_instance));
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], OBJECT_BINARY_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
present_value = Binary_Value_Present_Value(object_instance);
|
||||
apdu_len = encode_application_enumerated(&apdu[0], present_value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
/* note: see the details in the standard on how to use these */
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
/* note: see the details in the standard on how to use this */
|
||||
apdu_len = encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_POLARITY:
|
||||
/* FIXME: figure out the polarity */
|
||||
apdu_len = encode_application_enumerated(&apdu[0], polarity);
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_BINARY_VALUE,
|
||||
object_instance);
|
||||
break;
|
||||
/* note: Name and Description don't have to be the same.
|
||||
You could make Description writable and different */
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Binary_Value_Name(object_instance));
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_BINARY_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
present_value = Binary_Value_Present_Value(object_instance);
|
||||
apdu_len = encode_application_enumerated(&apdu[0], present_value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
/* note: see the details in the standard on how to use these */
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
/* note: see the details in the standard on how to use this */
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_POLARITY:
|
||||
/* FIXME: figure out the polarity */
|
||||
apdu_len = encode_application_enumerated(&apdu[0], polarity);
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Binary_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
bool Binary_Value_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
@@ -198,85 +212,85 @@ bool Binary_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
/* FIXME: len == 0: unable to decode? */
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_ENUMERATED) {
|
||||
priority = wp_data->priority;
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
|
||||
(priority != 6 /* reserved */ ) &&
|
||||
(value.type.Enumerated >= MIN_BINARY_PV) &&
|
||||
(value.type.Enumerated <= MAX_BINARY_PV)) {
|
||||
level = value.type.Enumerated;
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index(wp_data->
|
||||
object_instance);
|
||||
priority--;
|
||||
/* NOTE: this Binary value has no priority array */
|
||||
Present_Value[object_index] = level;
|
||||
/* Note: you could set the physical output here if we
|
||||
are the highest priority.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. */
|
||||
status = true;
|
||||
} else if (priority == 6) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_ENUMERATED) {
|
||||
priority = wp_data->priority;
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
|
||||
(priority != 6 /* reserved */ ) &&
|
||||
(value.type.Enumerated >= MIN_BINARY_PV) &&
|
||||
(value.type.Enumerated <= MAX_BINARY_PV)) {
|
||||
level = value.type.Enumerated;
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index(wp_data->
|
||||
object_instance);
|
||||
priority--;
|
||||
/* NOTE: this Binary value has no priority array */
|
||||
Present_Value[object_index] = level;
|
||||
/* Note: you could set the physical output here if we
|
||||
are the highest priority.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. */
|
||||
status = true;
|
||||
} else if (priority == 6) {
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else if (value.tag == BACNET_APPLICATION_TAG_NULL) {
|
||||
#if 0
|
||||
/* NOTE: this Binary Value has no priority array */
|
||||
level = BINARY_NULL;
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index(wp_data->object_instance);
|
||||
priority = wp_data->priority;
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
|
||||
priority--;
|
||||
Binary_Value_Level[object_index][priority] = level;
|
||||
/* Note: you could set the physical output here to the next
|
||||
highest priority, or to the relinquish default if no
|
||||
priorities are set.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. This comment may apply to the
|
||||
main loop (i.e. check out of service before changing output) */
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
#else
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
#endif
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
} else if (value.tag == BACNET_APPLICATION_TAG_NULL) {
|
||||
break;
|
||||
#if 0
|
||||
/* NOTE: this Binary Value has no priority array */
|
||||
level = BINARY_NULL;
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index(wp_data->object_instance);
|
||||
priority = wp_data->priority;
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
|
||||
priority--;
|
||||
Binary_Value_Level[object_index][priority] = level;
|
||||
/* Note: you could set the physical output here to the next
|
||||
highest priority, or to the relinquish default if no
|
||||
priorities are set.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. This comment may apply to the
|
||||
main loop (i.e. check out of service before changing output) */
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) {
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index(wp_data->object_instance);
|
||||
Binary_Value_Out_Of_Service[object_index] = value.type.Boolean;
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
#else
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
break;
|
||||
#endif
|
||||
} else {
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#if 0
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) {
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index(wp_data->object_instance);
|
||||
Binary_Value_Out_Of_Service[object_index] = value.type.Boolean;
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
@@ -287,7 +301,8 @@ bool Binary_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
void testBinary_Value(Test * pTest)
|
||||
void testBinary_Value(
|
||||
Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
@@ -302,8 +317,7 @@ void testBinary_Value(Test * pTest)
|
||||
|
||||
len = Binary_Value_Encode_Property_APDU(&apdu[0],
|
||||
instance,
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
@@ -316,7 +330,8 @@ void testBinary_Value(Test * pTest)
|
||||
}
|
||||
|
||||
#ifdef TEST_BINARY_VALUE
|
||||
int main(void)
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -333,5 +348,5 @@ int main(void)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_BINARY_VALUE */
|
||||
#endif /* TEST */
|
||||
#endif /* TEST_BINARY_VALUE */
|
||||
#endif /* TEST */
|
||||
|
||||
@@ -53,13 +53,15 @@ static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL;
|
||||
BACNET_REINITIALIZED_STATE_OF_DEVICE Reinitialize_State =
|
||||
REINITIALIZED_STATE_IDLE;
|
||||
|
||||
void Device_Reinit(void)
|
||||
void Device_Reinit(
|
||||
void)
|
||||
{
|
||||
dcc_set_status_duration(COMMUNICATION_ENABLE, 0);
|
||||
Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE);
|
||||
}
|
||||
|
||||
void Device_Init(void)
|
||||
void Device_Init(
|
||||
void)
|
||||
{
|
||||
Reinitialize_State = REINITIALIZED_STATE_IDLE;
|
||||
dcc_set_status_duration(COMMUNICATION_ENABLE, 0);
|
||||
@@ -71,14 +73,16 @@ void Device_Init(void)
|
||||
}
|
||||
|
||||
/* methods to manipulate the data */
|
||||
uint32_t Device_Object_Instance_Number(void)
|
||||
uint32_t Device_Object_Instance_Number(
|
||||
void)
|
||||
{
|
||||
return Object_Instance_Number;
|
||||
}
|
||||
|
||||
bool Device_Set_Object_Instance_Number(uint32_t object_id)
|
||||
bool Device_Set_Object_Instance_Number(
|
||||
uint32_t object_id)
|
||||
{
|
||||
bool status = true; /* return value */
|
||||
bool status = true; /* return value */
|
||||
|
||||
if (object_id <= BACNET_MAX_INSTANCE) {
|
||||
Object_Instance_Number = object_id;
|
||||
@@ -94,69 +98,81 @@ bool Device_Set_Object_Instance_Number(uint32_t object_id)
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Device_Valid_Object_Instance_Number(uint32_t object_id)
|
||||
bool Device_Valid_Object_Instance_Number(
|
||||
uint32_t object_id)
|
||||
{
|
||||
/* BACnet allows for a wildcard instance number */
|
||||
return ((Object_Instance_Number == object_id) ||
|
||||
(object_id == BACNET_MAX_INSTANCE));
|
||||
}
|
||||
|
||||
BACNET_DEVICE_STATUS Device_System_Status(void)
|
||||
BACNET_DEVICE_STATUS Device_System_Status(
|
||||
void)
|
||||
{
|
||||
return System_Status;
|
||||
}
|
||||
|
||||
void Device_Set_System_Status(BACNET_DEVICE_STATUS status)
|
||||
void Device_Set_System_Status(
|
||||
BACNET_DEVICE_STATUS status)
|
||||
{
|
||||
if (status < MAX_DEVICE_STATUS)
|
||||
System_Status = status;
|
||||
}
|
||||
|
||||
uint16_t Device_Vendor_Identifier(void)
|
||||
uint16_t Device_Vendor_Identifier(
|
||||
void)
|
||||
{
|
||||
return BACNET_VENDOR_ID;
|
||||
}
|
||||
|
||||
uint8_t Device_Protocol_Version(void)
|
||||
uint8_t Device_Protocol_Version(
|
||||
void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t Device_Protocol_Revision(void)
|
||||
uint8_t Device_Protocol_Revision(
|
||||
void)
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
|
||||
/* FIXME: MAX_APDU is defined in config.ini - set it! */
|
||||
uint16_t Device_Max_APDU_Length_Accepted(void)
|
||||
uint16_t Device_Max_APDU_Length_Accepted(
|
||||
void)
|
||||
{
|
||||
return MAX_APDU;
|
||||
}
|
||||
|
||||
BACNET_SEGMENTATION Device_Segmentation_Supported(void)
|
||||
BACNET_SEGMENTATION Device_Segmentation_Supported(
|
||||
void)
|
||||
{
|
||||
return SEGMENTATION_NONE;
|
||||
}
|
||||
|
||||
uint16_t Device_APDU_Timeout(void)
|
||||
uint16_t Device_APDU_Timeout(
|
||||
void)
|
||||
{
|
||||
return 60000;
|
||||
}
|
||||
|
||||
|
||||
uint8_t Device_Number_Of_APDU_Retries(void)
|
||||
uint8_t Device_Number_Of_APDU_Retries(
|
||||
void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t Device_Database_Revision(void)
|
||||
uint8_t Device_Database_Revision(
|
||||
void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned Device_Object_List_Count(void)
|
||||
unsigned Device_Object_List_Count(
|
||||
void)
|
||||
{
|
||||
unsigned count = 1; /* at least 1 for device object */
|
||||
unsigned count = 1; /* at least 1 for device object */
|
||||
|
||||
/* FIXME: add objects as needed */
|
||||
count += Binary_Input_Count();
|
||||
@@ -167,8 +183,10 @@ unsigned Device_Object_List_Count(void)
|
||||
return count;
|
||||
}
|
||||
|
||||
bool Device_Object_List_Identifier(unsigned array_index,
|
||||
int *object_type, uint32_t * instance)
|
||||
bool Device_Object_List_Identifier(
|
||||
unsigned array_index,
|
||||
int *object_type,
|
||||
uint32_t * instance)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned object_index = 0;
|
||||
@@ -238,13 +256,15 @@ bool Device_Object_List_Identifier(unsigned array_index,
|
||||
}
|
||||
|
||||
/* return the length of the apdu encoded or -1 for error */
|
||||
int Device_Encode_Property_APDU(uint8_t * apdu,
|
||||
int Device_Encode_Property_APDU(
|
||||
uint8_t * apdu,
|
||||
BACNET_PROPERTY_ID property,
|
||||
int32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
int len = 0; /* apdu len intermediate value */
|
||||
int apdu_len = 0; /* return value */
|
||||
int len = 0; /* apdu len intermediate value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned i = 0;
|
||||
@@ -256,203 +276,221 @@ int Device_Encode_Property_APDU(uint8_t * apdu,
|
||||
|
||||
/* FIXME: change the hardcoded names to suit your application */
|
||||
switch (property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len = encode_application_object_id(&apdu[0], OBJECT_DEVICE,
|
||||
Object_Instance_Number);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
characterstring_init_ansi(&char_string, Object_Name);
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], OBJECT_DEVICE);
|
||||
break;
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string, "BACnet Demo");
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_SYSTEM_STATUS:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], Device_System_Status());
|
||||
break;
|
||||
case PROP_VENDOR_NAME:
|
||||
characterstring_init_ansi(&char_string, BACNET_VENDOR_NAME);
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_VENDOR_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], Device_Vendor_Identifier());
|
||||
break;
|
||||
case PROP_MODEL_NAME:
|
||||
characterstring_init_ansi(&char_string, "GNU Demo");
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_FIRMWARE_REVISION:
|
||||
characterstring_init_ansi(&char_string, BACnet_Version);
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_APPLICATION_SOFTWARE_VERSION:
|
||||
characterstring_init_ansi(&char_string, "1.0");
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_LOCATION:
|
||||
characterstring_init_ansi(&char_string, "USA");
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_PROTOCOL_VERSION:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], Device_Protocol_Version());
|
||||
break;
|
||||
case PROP_PROTOCOL_REVISION:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], Device_Protocol_Revision());
|
||||
break;
|
||||
/* BACnet Legacy Support */
|
||||
case PROP_PROTOCOL_CONFORMANCE_CLASS:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], 1);
|
||||
break;
|
||||
case PROP_PROTOCOL_SERVICES_SUPPORTED:
|
||||
/* Note: list of services that are executed, not initiated. */
|
||||
bitstring_init(&bit_string);
|
||||
for (i = 0; i < MAX_BACNET_SERVICES_SUPPORTED; i++) {
|
||||
/* automatic lookup based on handlers set */
|
||||
bitstring_set_bit(&bit_string, (uint8_t) i,
|
||||
apdu_service_supported(i));
|
||||
}
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED:
|
||||
/* Note: this is the list of objects that can be in this device,
|
||||
not a list of objects that this device can access */
|
||||
bitstring_init(&bit_string);
|
||||
for (i = 0; i < MAX_ASHRAE_OBJECT_TYPE; i++) {
|
||||
/* FIXME: if ReadProperty used an array of Functions... */
|
||||
/* initialize all the object types to not-supported */
|
||||
bitstring_set_bit(&bit_string, (uint8_t) i, false);
|
||||
}
|
||||
/* FIXME: indicate the objects that YOU support */
|
||||
bitstring_set_bit(&bit_string, OBJECT_DEVICE, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_ANALOG_VALUE, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_BINARY_VALUE, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_ANALOG_INPUT, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_BINARY_INPUT, true);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_OBJECT_LIST:
|
||||
count = Device_Object_List_Count();
|
||||
/* Array element zero is the number of objects in the list */
|
||||
if (array_index == 0)
|
||||
apdu_len = encode_application_unsigned(&apdu[0], count);
|
||||
/* if no index was specified, then try to encode the entire list */
|
||||
/* into one packet. Note that more than likely you will have */
|
||||
/* to return an error if the number of encoded objects exceeds */
|
||||
/* your maximum APDU size. */
|
||||
else if (array_index == BACNET_ARRAY_ALL) {
|
||||
for (i = 1; i <= count; i++) {
|
||||
if (Device_Object_List_Identifier(i, &object_type,
|
||||
&instance)) {
|
||||
len =
|
||||
encode_application_object_id(&apdu[apdu_len],
|
||||
object_type, instance);
|
||||
apdu_len += len;
|
||||
/* assume next one is the same size as this one */
|
||||
/* can we all fit into the APDU? */
|
||||
if ((apdu_len + len) >= MAX_APDU) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len = encode_application_object_id(&apdu[0], OBJECT_DEVICE,
|
||||
Object_Instance_Number);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
characterstring_init_ansi(&char_string, Object_Name);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], OBJECT_DEVICE);
|
||||
break;
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string, "BACnet Demo");
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_SYSTEM_STATUS:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
Device_System_Status());
|
||||
break;
|
||||
case PROP_VENDOR_NAME:
|
||||
characterstring_init_ansi(&char_string, BACNET_VENDOR_NAME);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_VENDOR_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
Device_Vendor_Identifier());
|
||||
break;
|
||||
case PROP_MODEL_NAME:
|
||||
characterstring_init_ansi(&char_string, "GNU Demo");
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_FIRMWARE_REVISION:
|
||||
characterstring_init_ansi(&char_string, BACnet_Version);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_APPLICATION_SOFTWARE_VERSION:
|
||||
characterstring_init_ansi(&char_string, "1.0");
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_LOCATION:
|
||||
characterstring_init_ansi(&char_string, "USA");
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_PROTOCOL_VERSION:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
Device_Protocol_Version());
|
||||
break;
|
||||
case PROP_PROTOCOL_REVISION:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
Device_Protocol_Revision());
|
||||
break;
|
||||
/* BACnet Legacy Support */
|
||||
case PROP_PROTOCOL_CONFORMANCE_CLASS:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], 1);
|
||||
break;
|
||||
case PROP_PROTOCOL_SERVICES_SUPPORTED:
|
||||
/* Note: list of services that are executed, not initiated. */
|
||||
bitstring_init(&bit_string);
|
||||
for (i = 0; i < MAX_BACNET_SERVICES_SUPPORTED; i++) {
|
||||
/* automatic lookup based on handlers set */
|
||||
bitstring_set_bit(&bit_string, (uint8_t) i,
|
||||
apdu_service_supported(i));
|
||||
}
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED:
|
||||
/* Note: this is the list of objects that can be in this device,
|
||||
not a list of objects that this device can access */
|
||||
bitstring_init(&bit_string);
|
||||
for (i = 0; i < MAX_ASHRAE_OBJECT_TYPE; i++) {
|
||||
/* FIXME: if ReadProperty used an array of Functions... */
|
||||
/* initialize all the object types to not-supported */
|
||||
bitstring_set_bit(&bit_string, (uint8_t) i, false);
|
||||
}
|
||||
/* FIXME: indicate the objects that YOU support */
|
||||
bitstring_set_bit(&bit_string, OBJECT_DEVICE, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_ANALOG_VALUE, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_BINARY_VALUE, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_ANALOG_INPUT, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_BINARY_INPUT, true);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_OBJECT_LIST:
|
||||
count = Device_Object_List_Count();
|
||||
/* Array element zero is the number of objects in the list */
|
||||
if (array_index == 0)
|
||||
apdu_len = encode_application_unsigned(&apdu[0], count);
|
||||
/* if no index was specified, then try to encode the entire list */
|
||||
/* into one packet. Note that more than likely you will have */
|
||||
/* to return an error if the number of encoded objects exceeds */
|
||||
/* your maximum APDU size. */
|
||||
else if (array_index == BACNET_ARRAY_ALL) {
|
||||
for (i = 1; i <= count; i++) {
|
||||
if (Device_Object_List_Identifier(i, &object_type,
|
||||
&instance)) {
|
||||
len =
|
||||
encode_application_object_id(&apdu[apdu_len],
|
||||
object_type, instance);
|
||||
apdu_len += len;
|
||||
/* assume next one is the same size as this one */
|
||||
/* can we all fit into the APDU? */
|
||||
if ((apdu_len + len) >= MAX_APDU) {
|
||||
*error_class = ERROR_CLASS_SERVICES;
|
||||
*error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* error: internal error? */
|
||||
*error_class = ERROR_CLASS_SERVICES;
|
||||
*error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
|
||||
*error_code = ERROR_CODE_OTHER;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* error: internal error? */
|
||||
*error_class = ERROR_CLASS_SERVICES;
|
||||
*error_code = ERROR_CODE_OTHER;
|
||||
}
|
||||
} else {
|
||||
if (Device_Object_List_Identifier(array_index, &object_type,
|
||||
&instance))
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], object_type,
|
||||
instance);
|
||||
else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (Device_Object_List_Identifier(array_index, &object_type,
|
||||
&instance))
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], object_type,
|
||||
instance);
|
||||
else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PROP_MAX_APDU_LENGTH_ACCEPTED:
|
||||
apdu_len = encode_application_unsigned(&apdu[0],
|
||||
Device_Max_APDU_Length_Accepted());
|
||||
break;
|
||||
case PROP_SEGMENTATION_SUPPORTED:
|
||||
apdu_len = encode_application_enumerated(&apdu[0],
|
||||
Device_Segmentation_Supported());
|
||||
break;
|
||||
case PROP_APDU_TIMEOUT:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], Device_APDU_Timeout());
|
||||
break;
|
||||
case PROP_NUMBER_OF_APDU_RETRIES:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
Device_Number_Of_APDU_Retries());
|
||||
break;
|
||||
case PROP_DEVICE_ADDRESS_BINDING:
|
||||
/* FIXME: encode the list here, if it exists */
|
||||
break;
|
||||
case PROP_DATABASE_REVISION:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], Device_Database_Revision());
|
||||
break;
|
||||
case PROP_MAX_INFO_FRAMES:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], dlmstp_max_info_frames());
|
||||
break;
|
||||
case PROP_MAX_MASTER:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], dlmstp_max_master());
|
||||
break;
|
||||
case PROP_LOCAL_TIME:
|
||||
/* FIXME: if you support time */
|
||||
local_time.hour = 0;
|
||||
local_time.min = 0;
|
||||
local_time.sec = 0;
|
||||
local_time.hundredths = 0;
|
||||
apdu_len = encode_application_time(&apdu[0], &local_time);
|
||||
break;
|
||||
case PROP_UTC_OFFSET:
|
||||
/* Note: BACnet Time Zone is inverse of everybody else */
|
||||
apdu_len = encode_application_signed(&apdu[0], 5 /* EST */ );
|
||||
break;
|
||||
case PROP_LOCAL_DATE:
|
||||
/* FIXME: if you support date */
|
||||
local_date.year = 2006; /* AD */
|
||||
local_date.month = 4; /* Jan=1..Dec=12 */
|
||||
local_date.day = 11; /* 1..31 */
|
||||
local_date.wday = 0; /* 1=Mon..7=Sun */
|
||||
apdu_len = encode_application_date(&apdu[0], &local_date);
|
||||
break;
|
||||
case PROP_DAYLIGHT_SAVINGS_STATUS:
|
||||
/* FIXME: if you support time/date */
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case 9600:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], RS485_Get_Baud_Rate());
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
break;
|
||||
case PROP_MAX_APDU_LENGTH_ACCEPTED:
|
||||
apdu_len = encode_application_unsigned(&apdu[0],
|
||||
Device_Max_APDU_Length_Accepted());
|
||||
break;
|
||||
case PROP_SEGMENTATION_SUPPORTED:
|
||||
apdu_len = encode_application_enumerated(&apdu[0],
|
||||
Device_Segmentation_Supported());
|
||||
break;
|
||||
case PROP_APDU_TIMEOUT:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], Device_APDU_Timeout());
|
||||
break;
|
||||
case PROP_NUMBER_OF_APDU_RETRIES:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
Device_Number_Of_APDU_Retries());
|
||||
break;
|
||||
case PROP_DEVICE_ADDRESS_BINDING:
|
||||
/* FIXME: encode the list here, if it exists */
|
||||
break;
|
||||
case PROP_DATABASE_REVISION:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
Device_Database_Revision());
|
||||
break;
|
||||
case PROP_MAX_INFO_FRAMES:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
dlmstp_max_info_frames());
|
||||
break;
|
||||
case PROP_MAX_MASTER:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], dlmstp_max_master());
|
||||
break;
|
||||
case PROP_LOCAL_TIME:
|
||||
/* FIXME: if you support time */
|
||||
local_time.hour = 0;
|
||||
local_time.min = 0;
|
||||
local_time.sec = 0;
|
||||
local_time.hundredths = 0;
|
||||
apdu_len = encode_application_time(&apdu[0], &local_time);
|
||||
break;
|
||||
case PROP_UTC_OFFSET:
|
||||
/* Note: BACnet Time Zone is inverse of everybody else */
|
||||
apdu_len = encode_application_signed(&apdu[0], 5 /* EST */ );
|
||||
break;
|
||||
case PROP_LOCAL_DATE:
|
||||
/* FIXME: if you support date */
|
||||
local_date.year = 2006; /* AD */
|
||||
local_date.month = 4; /* Jan=1..Dec=12 */
|
||||
local_date.day = 11; /* 1..31 */
|
||||
local_date.wday = 0; /* 1=Mon..7=Sun */
|
||||
apdu_len = encode_application_date(&apdu[0], &local_date);
|
||||
break;
|
||||
case PROP_DAYLIGHT_SAVINGS_STATUS:
|
||||
/* FIXME: if you support time/date */
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case 9600:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], RS485_Get_Baud_Rate());
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
bool Device_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
int len = 0;
|
||||
@@ -469,98 +507,98 @@ bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
/* FIXME: len == 0: unable to decode? */
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_OBJECT_ID) {
|
||||
if ((value.type.Object_Id.type == OBJECT_DEVICE) &&
|
||||
(Device_Set_Object_Instance_Number(value.type.
|
||||
Object_Id.instance))) {
|
||||
/* we could send an I-Am broadcast to let the world know */
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case PROP_MAX_INFO_FRAMES:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
if (value.type.Unsigned_Int <= 255) {
|
||||
dlmstp_set_max_info_frames(value.type.Unsigned_Int);
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case PROP_MAX_MASTER:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
if ((value.type.Unsigned_Int > 0) &&
|
||||
(value.type.Unsigned_Int <= 127)) {
|
||||
dlmstp_set_max_master(value.type.Unsigned_Int);
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) {
|
||||
uint8_t encoding;
|
||||
size_t len;
|
||||
|
||||
encoding =
|
||||
characterstring_encoding(&value.type.Character_String);
|
||||
len = characterstring_length(&value.type.Character_String);
|
||||
if (encoding == CHARACTER_ANSI_X34) {
|
||||
if (len <= 20) {
|
||||
/* FIXME: set the name */
|
||||
/* Display_Set_Name(
|
||||
characterstring_value(&value.type.Character_String)); */
|
||||
/* FIXME: All the object names in a device must be unique.
|
||||
Disallow setting the Device Object Name to any objects in
|
||||
the device. */
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_OBJECT_ID) {
|
||||
if ((value.type.Object_Id.type == OBJECT_DEVICE) &&
|
||||
(Device_Set_Object_Instance_Number(value.type.
|
||||
Object_Id.instance))) {
|
||||
/* we could send an I-Am broadcast to let the world know */
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case 9600:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
if (value.type.Unsigned_Int > 115200) {
|
||||
RS485_Set_Baud_Rate(value.type.Unsigned_Int);
|
||||
status = true;
|
||||
break;
|
||||
case PROP_MAX_INFO_FRAMES:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
if (value.type.Unsigned_Int <= 255) {
|
||||
dlmstp_set_max_info_frames(value.type.Unsigned_Int);
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
case PROP_MAX_MASTER:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
if ((value.type.Unsigned_Int > 0) &&
|
||||
(value.type.Unsigned_Int <= 127)) {
|
||||
dlmstp_set_max_master(value.type.Unsigned_Int);
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) {
|
||||
uint8_t encoding;
|
||||
size_t len;
|
||||
|
||||
encoding =
|
||||
characterstring_encoding(&value.type.Character_String);
|
||||
len = characterstring_length(&value.type.Character_String);
|
||||
if (encoding == CHARACTER_ANSI_X34) {
|
||||
if (len <= 20) {
|
||||
/* FIXME: set the name */
|
||||
/* Display_Set_Name(
|
||||
characterstring_value(&value.type.Character_String)); */
|
||||
/* FIXME: All the object names in a device must be unique.
|
||||
Disallow setting the Device Object Name to any objects in
|
||||
the device. */
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case 9600:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
if (value.type.Unsigned_Int > 115200) {
|
||||
RS485_Set_Baud_Rate(value.type.Unsigned_Int);
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -62,52 +62,39 @@ int Encode_Property_APDU(
|
||||
*error_class = ERROR_CLASS_OBJECT;
|
||||
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
/* handle each object type */
|
||||
switch(object_type) {
|
||||
switch (object_type) {
|
||||
case OBJECT_DEVICE:
|
||||
if (Device_Valid_Object_Instance_Number(object_instance)) {
|
||||
apdu_len = Device_Encode_Property_APDU(
|
||||
&apdu[0],
|
||||
property,
|
||||
array_index,
|
||||
error_class, error_code);
|
||||
apdu_len = Device_Encode_Property_APDU(&apdu[0],
|
||||
property, array_index, error_class, error_code);
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_INPUT:
|
||||
if (Analog_Input_Valid_Instance(object_instance)) {
|
||||
apdu_len = Analog_Input_Encode_Property_APDU(
|
||||
&apdu[0],
|
||||
apdu_len = Analog_Input_Encode_Property_APDU(&apdu[0],
|
||||
object_instance,
|
||||
property,
|
||||
array_index,
|
||||
error_class, error_code);
|
||||
property, array_index, error_class, error_code);
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_VALUE:
|
||||
if (Analog_Value_Valid_Instance(object_instance)) {
|
||||
apdu_len = Analog_Value_Encode_Property_APDU(&Temp_Buf[0],
|
||||
object_instance,
|
||||
property,
|
||||
array_index,
|
||||
error_class, error_code);
|
||||
property, array_index, error_class, error_code);
|
||||
}
|
||||
break;
|
||||
case OBJECT_BINARY_INPUT:
|
||||
if (Binary_Input_Valid_Instance(object_instance)) {
|
||||
apdu_len = Binary_Input_Encode_Property_APDU(
|
||||
&apdu[0],
|
||||
apdu_len = Binary_Input_Encode_Property_APDU(&apdu[0],
|
||||
object_instance,
|
||||
property,
|
||||
array_index,
|
||||
error_class, error_code);
|
||||
property, array_index, error_class, error_code);
|
||||
}
|
||||
break;
|
||||
case OBJECT_BINARY_VALUE:
|
||||
if (Binary_Value_Valid_Instance(object_instance)) {
|
||||
apdu_len = Binary_Value_Encode_Property_APDU(&Temp_Buf[0],
|
||||
object_instance,
|
||||
property,
|
||||
array_index,
|
||||
error_class, error_code);
|
||||
property, array_index, error_class, error_code);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -119,9 +106,11 @@ int Encode_Property_APDU(
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
void handler_read_property(uint8_t * service_request,
|
||||
void handler_read_property(
|
||||
uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
{
|
||||
BACNET_READ_PROPERTY_DATA data;
|
||||
int len = 0;
|
||||
@@ -154,13 +143,10 @@ void handler_read_property(uint8_t * service_request,
|
||||
}
|
||||
/* most cases will be error */
|
||||
error = true;
|
||||
len = Encode_Property_APDU(
|
||||
&Temp_Buf[0],
|
||||
len = Encode_Property_APDU(&Temp_Buf[0],
|
||||
data.object_type,
|
||||
data.object_instance,
|
||||
data.object_property,
|
||||
data.array_index,
|
||||
&error_class, &error_code);
|
||||
data.object_property, data.array_index, &error_class, &error_code);
|
||||
if (len >= 0) {
|
||||
/* encode the APDU portion of the packet */
|
||||
data.application_data = &Temp_Buf[0];
|
||||
@@ -183,7 +169,7 @@ void handler_read_property(uint8_t * service_request,
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_READ_PROPERTY, error_class, error_code);
|
||||
}
|
||||
RP_ABORT:
|
||||
RP_ABORT:
|
||||
pdu_len += len;
|
||||
bytes_sent = datalink_send_pdu(src, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
|
||||
@@ -46,9 +46,11 @@
|
||||
/* too big to reside on stack frame for PIC */
|
||||
static BACNET_WRITE_PROPERTY_DATA wp_data;
|
||||
|
||||
void handler_write_property(uint8_t * service_request,
|
||||
void handler_write_property(
|
||||
uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
{
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
@@ -70,8 +72,7 @@ void handler_write_property(uint8_t * service_request,
|
||||
goto WP_ABORT;
|
||||
}
|
||||
/* decode the service request only */
|
||||
len = wp_decode_service_request(service_request,
|
||||
service_len, &wp_data);
|
||||
len = wp_decode_service_request(service_request, service_len, &wp_data);
|
||||
/* bad decoding or something we didn't understand - send an abort */
|
||||
if (len <= 0) {
|
||||
len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
@@ -80,67 +81,61 @@ void handler_write_property(uint8_t * service_request,
|
||||
}
|
||||
/* handle the object type */
|
||||
switch (wp_data.object_type) {
|
||||
case OBJECT_DEVICE:
|
||||
if (Device_Write_Property(&wp_data, &error_class, &error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
} else {
|
||||
case OBJECT_DEVICE:
|
||||
if (Device_Write_Property(&wp_data, &error_class, &error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class, error_code);
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_INPUT:
|
||||
case OBJECT_BINARY_INPUT:
|
||||
error_class = ERROR_CLASS_PROPERTY;
|
||||
error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_INPUT:
|
||||
case OBJECT_BINARY_INPUT:
|
||||
error_class = ERROR_CLASS_PROPERTY;
|
||||
error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY,
|
||||
error_class, error_code);
|
||||
break;
|
||||
case OBJECT_BINARY_VALUE:
|
||||
if (Binary_Value_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
} else {
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY,
|
||||
error_class, error_code);
|
||||
break;
|
||||
case OBJECT_BINARY_VALUE:
|
||||
if (Binary_Value_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class, error_code);
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_VALUE:
|
||||
if (Analog_Value_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class, error_code);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_VALUE:
|
||||
if (Analog_Value_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY,
|
||||
error_class, error_code);
|
||||
break;
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY,
|
||||
error_class, error_code);
|
||||
break;
|
||||
}
|
||||
WP_ABORT:
|
||||
WP_ABORT:
|
||||
pdu_len += len;
|
||||
bytes_sent = datalink_send_pdu(src, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
|
||||
@@ -20,9 +20,12 @@
|
||||
|
||||
// The following functions must be write in ARM mode this function called directly
|
||||
// by exception vector
|
||||
extern void AT91F_Spurious_handler(void);
|
||||
extern void AT91F_Default_IRQ_handler(void);
|
||||
extern void AT91F_Default_FIQ_handler(void);
|
||||
extern void AT91F_Spurious_handler(
|
||||
void);
|
||||
extern void AT91F_Default_IRQ_handler(
|
||||
void);
|
||||
extern void AT91F_Default_FIQ_handler(
|
||||
void);
|
||||
|
||||
//*----------------------------------------------------------------------------
|
||||
//* \fn AT91F_LowLevelInit
|
||||
@@ -30,31 +33,33 @@ extern void AT91F_Default_FIQ_handler(void);
|
||||
//* this function can be use a Stack, depending the compilation
|
||||
//* optimization mode
|
||||
//*----------------------------------------------------------------------------
|
||||
void LowLevelInit(void)
|
||||
void LowLevelInit(
|
||||
void)
|
||||
{
|
||||
int i;
|
||||
AT91PS_PMC pPMC = AT91C_BASE_PMC;
|
||||
|
||||
int i;
|
||||
AT91PS_PMC pPMC = AT91C_BASE_PMC;
|
||||
|
||||
//* Set Flash Wait sate
|
||||
// Single Cycle Access at Up to 30 MHz, or 40
|
||||
// if MCK = 48054841 I have 50 Cycle for 1 usecond ( flied MC_FMR->FMCN
|
||||
// result: AT91C_MC_FMR = 0x00320100 (MC Flash Mode Register)
|
||||
AT91C_BASE_MC->MC_FMR = (((AT91C_MC_FMCN) & (50 <<16)) | AT91C_MC_FWS_1FWS);
|
||||
AT91C_BASE_MC->MC_FMR =
|
||||
(((AT91C_MC_FMCN) & (50 << 16)) | AT91C_MC_FWS_1FWS);
|
||||
|
||||
//* Watchdog Disable
|
||||
// result: AT91C_WDTC_WDMR = 0x00008000 (Watchdog Mode Register)
|
||||
AT91C_BASE_WDTC->WDTC_WDMR= AT91C_WDTC_WDDIS;
|
||||
AT91C_BASE_WDTC->WDTC_WDMR = AT91C_WDTC_WDDIS;
|
||||
|
||||
//* Set MCK at 48 054 841
|
||||
// 1 Enabling the Main Oscillator:
|
||||
// SCK = 1/32768 = 30.51 uSecond
|
||||
// Start up time = 8 * 6 / SCK = 56 * 30.51 = 1,46484375 ms
|
||||
// result: AT91C_CKGR_MOR = 0x00000601 (Main Oscillator Register)
|
||||
pPMC->PMC_MOR = ((AT91C_CKGR_OSCOUNT & (0x06<<8)) | AT91C_CKGR_MOSCEN);
|
||||
|
||||
pPMC->PMC_MOR = ((AT91C_CKGR_OSCOUNT & (0x06 << 8)) | AT91C_CKGR_MOSCEN);
|
||||
|
||||
// Wait the startup time
|
||||
while(!(pPMC->PMC_SR & AT91C_PMC_MOSCS));
|
||||
|
||||
while (!(pPMC->PMC_SR & AT91C_PMC_MOSCS));
|
||||
|
||||
// PMC Clock Generator PLL Register setup
|
||||
//
|
||||
// The following settings are used: DIV = 14
|
||||
@@ -73,12 +78,11 @@ void LowLevelInit(void)
|
||||
// OUT = 0 (not used)
|
||||
// result: AT91C_CKGR_PLLR = 0x00000000480A0E (PLL Register)
|
||||
pPMC->PMC_PLLR = ((AT91C_CKGR_DIV & 14) |
|
||||
(AT91C_CKGR_PLLCOUNT & (10<<8)) |
|
||||
(AT91C_CKGR_MUL & (72<<16)));
|
||||
(AT91C_CKGR_PLLCOUNT & (10 << 8)) | (AT91C_CKGR_MUL & (72 << 16)));
|
||||
|
||||
// Wait the startup time (until PMC Status register LOCK bit is set)
|
||||
while(!(pPMC->PMC_SR & AT91C_PMC_LOCK));
|
||||
|
||||
while (!(pPMC->PMC_SR & AT91C_PMC_LOCK));
|
||||
|
||||
// PMC Master Clock (MCK) Register setup
|
||||
//
|
||||
// CSS = 3 (PLLCK clock selected)
|
||||
@@ -88,14 +92,11 @@ void LowLevelInit(void)
|
||||
// Note: Master Clock MCK = 48054841 hz (this is the CPU clock speed)
|
||||
// result: AT91C_PMC_MCKR = 0x00000007 (Master Clock Register)
|
||||
pPMC->PMC_MCKR = AT91C_PMC_CSS_PLL_CLK | AT91C_PMC_PRES_CLK_2;
|
||||
|
||||
|
||||
// Set up the default interrupts handler vectors
|
||||
AT91C_BASE_AIC->AIC_SVR[0] = (int) AT91F_Default_FIQ_handler;
|
||||
for (i = 1; i < 31; i++)
|
||||
{
|
||||
for (i = 1; i < 31; i++) {
|
||||
AT91C_BASE_AIC->AIC_SVR[i] = (int) AT91F_Default_IRQ_handler;
|
||||
}
|
||||
AT91C_BASE_AIC->AIC_SPU = (int) AT91F_Spurious_handler;
|
||||
AT91C_BASE_AIC->AIC_SPU = (int) AT91F_Spurious_handler;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -21,19 +21,24 @@
|
||||
#define FIQ_MASK 0x00000040
|
||||
#define INT_MASK (IRQ_MASK | FIQ_MASK)
|
||||
|
||||
static inline unsigned __get_cpsr(void)
|
||||
static inline unsigned __get_cpsr(
|
||||
void)
|
||||
{
|
||||
unsigned long retval;
|
||||
asm volatile (" mrs %0, cpsr" : "=r" (retval) : /* no inputs */ );
|
||||
asm volatile (
|
||||
" mrs %0, cpsr":"=r" (retval): /* no inputs */ );
|
||||
return retval;
|
||||
}
|
||||
|
||||
static inline void __set_cpsr(unsigned val)
|
||||
static inline void __set_cpsr(
|
||||
unsigned val)
|
||||
{
|
||||
asm volatile (" msr cpsr, %0" : /* no outputs */ : "r" (val) );
|
||||
asm volatile (
|
||||
" msr cpsr, %0": /* no outputs */ :"r" (val));
|
||||
}
|
||||
|
||||
unsigned disableIRQ(void)
|
||||
unsigned disableIRQ(
|
||||
void)
|
||||
{
|
||||
unsigned _cpsr;
|
||||
_cpsr = __get_cpsr();
|
||||
@@ -41,7 +46,8 @@ unsigned disableIRQ(void)
|
||||
return _cpsr;
|
||||
}
|
||||
|
||||
unsigned restoreIRQ(unsigned oldCPSR)
|
||||
unsigned restoreIRQ(
|
||||
unsigned oldCPSR)
|
||||
{
|
||||
unsigned _cpsr;
|
||||
|
||||
@@ -50,7 +56,8 @@ unsigned restoreIRQ(unsigned oldCPSR)
|
||||
return _cpsr;
|
||||
}
|
||||
|
||||
unsigned enableIRQ(void)
|
||||
unsigned enableIRQ(
|
||||
void)
|
||||
{
|
||||
unsigned _cpsr;
|
||||
|
||||
@@ -59,7 +66,8 @@ unsigned enableIRQ(void)
|
||||
return _cpsr;
|
||||
}
|
||||
|
||||
unsigned disableFIQ(void)
|
||||
unsigned disableFIQ(
|
||||
void)
|
||||
{
|
||||
unsigned _cpsr;
|
||||
|
||||
@@ -68,7 +76,8 @@ unsigned disableFIQ(void)
|
||||
return _cpsr;
|
||||
}
|
||||
|
||||
unsigned restoreFIQ(unsigned oldCPSR)
|
||||
unsigned restoreFIQ(
|
||||
unsigned oldCPSR)
|
||||
{
|
||||
unsigned _cpsr;
|
||||
|
||||
@@ -77,7 +86,8 @@ unsigned restoreFIQ(unsigned oldCPSR)
|
||||
return _cpsr;
|
||||
}
|
||||
|
||||
unsigned enableFIQ(void)
|
||||
unsigned enableFIQ(
|
||||
void)
|
||||
{
|
||||
unsigned _cpsr;
|
||||
|
||||
|
||||
@@ -48,9 +48,12 @@
|
||||
// *******************************************************
|
||||
// FIXME: use header files? External References
|
||||
// *******************************************************
|
||||
extern void LowLevelInit(void);
|
||||
extern unsigned enableIRQ(void);
|
||||
extern unsigned enableFIQ(void);
|
||||
extern void LowLevelInit(
|
||||
void);
|
||||
extern unsigned enableIRQ(
|
||||
void);
|
||||
extern unsigned enableFIQ(
|
||||
void);
|
||||
|
||||
// *******************************************************
|
||||
// FIXME: use header files? Global Variables
|
||||
@@ -64,7 +67,8 @@ static unsigned long LED_Timer_3 = 0;
|
||||
static unsigned long LED_Timer_4 = 1000;
|
||||
static unsigned long DCC_Timer = 1000;
|
||||
|
||||
static void millisecond_timer(void)
|
||||
static void millisecond_timer(
|
||||
void)
|
||||
{
|
||||
while (Timer_Milliseconds) {
|
||||
Timer_Milliseconds--;
|
||||
@@ -87,11 +91,12 @@ static void millisecond_timer(void)
|
||||
/* note: MS/TP silence timer is updated in ISR */
|
||||
}
|
||||
|
||||
static void init(void)
|
||||
static void init(
|
||||
void)
|
||||
{
|
||||
/* Initialize the Parallel I/O Controller A Peripheral Clock */
|
||||
volatile AT91PS_PMC pPMC = AT91C_BASE_PMC;
|
||||
pPMC->PMC_PCER = pPMC->PMC_PCSR | (1<<AT91C_ID_PIOA);
|
||||
volatile AT91PS_PMC pPMC = AT91C_BASE_PMC;
|
||||
pPMC->PMC_PCER = pPMC->PMC_PCSR | (1 << AT91C_ID_PIOA);
|
||||
|
||||
// Set up the LEDs (PA0 - PA3)
|
||||
volatile AT91PS_PIO pPIO = AT91C_BASE_PIOA;
|
||||
@@ -112,23 +117,23 @@ static void init(void)
|
||||
volatile AT91PS_AIC pAIC = AT91C_BASE_AIC;
|
||||
// Disable FIQ interrupt in
|
||||
// AIC Interrupt Disable Command Register
|
||||
pAIC->AIC_IDCR = (1<<AT91C_ID_FIQ);
|
||||
pAIC->AIC_IDCR = (1 << AT91C_ID_FIQ);
|
||||
// Set the interrupt source type in
|
||||
// AIC Source Mode Register[0]
|
||||
pAIC->AIC_SMR[AT91C_ID_FIQ] =
|
||||
(AT91C_AIC_SRCTYPE_INT_EDGE_TRIGGERED);
|
||||
pAIC->AIC_SMR[AT91C_ID_FIQ] = (AT91C_AIC_SRCTYPE_INT_EDGE_TRIGGERED);
|
||||
// Clear the FIQ interrupt in
|
||||
// AIC Interrupt Clear Command Register
|
||||
pAIC->AIC_ICCR = (1<<AT91C_ID_FIQ);
|
||||
pAIC->AIC_ICCR = (1 << AT91C_ID_FIQ);
|
||||
// Remove disable FIQ interrupt in
|
||||
// AIC Interrupt Disable Command Register
|
||||
pAIC->AIC_IDCR = (0<<AT91C_ID_FIQ);
|
||||
pAIC->AIC_IDCR = (0 << AT91C_ID_FIQ);
|
||||
// Enable the FIQ interrupt in
|
||||
// AIC Interrupt Enable Command Register
|
||||
pAIC->AIC_IECR = (1<<AT91C_ID_FIQ);
|
||||
pAIC->AIC_IECR = (1 << AT91C_ID_FIQ);
|
||||
}
|
||||
|
||||
static void bacnet_init(void)
|
||||
static void bacnet_init(
|
||||
void)
|
||||
{
|
||||
#if defined(BACDL_MSTP)
|
||||
RS485_Set_Baud_Rate(38400);
|
||||
@@ -140,8 +145,7 @@ static void bacnet_init(void)
|
||||
Device_Set_Object_Instance_Number(22222);
|
||||
#ifndef DLMSTP_TEST
|
||||
/* we need to handle who-is to support dynamic device binding */
|
||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS,
|
||||
handler_who_is);
|
||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
||||
/* Set the handlers for any confirmed services that we support. */
|
||||
/* We must implement read property - it's required! */
|
||||
apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY,
|
||||
@@ -157,14 +161,16 @@ static void bacnet_init(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
int main (void) {
|
||||
unsigned long IdleCount = 0; // idle loop blink counter
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
unsigned long IdleCount = 0; // idle loop blink counter
|
||||
bool LED1_Off_Enabled = true;
|
||||
bool LED2_Off_Enabled = true;
|
||||
bool LED3_Off_Enabled = true;
|
||||
uint16_t pdu_len = 0;
|
||||
BACNET_ADDRESS src; /* source address */
|
||||
uint8_t pdu[MAX_MPDU]; /* PDU data */
|
||||
uint8_t pdu[MAX_MPDU]; /* PDU data */
|
||||
// Set up the LEDs (PA0 - PA3)
|
||||
volatile AT91PS_PIO pPIO = AT91C_BASE_PIOA;
|
||||
|
||||
@@ -177,9 +183,9 @@ int main (void) {
|
||||
// enable interrupts
|
||||
enableIRQ();
|
||||
enableFIQ();
|
||||
/* broadcast an I-Am on startup */
|
||||
/* broadcast an I-Am on startup */
|
||||
iam_send(&Handler_Transmit_Buffer[0]);
|
||||
// endless blink loop
|
||||
// endless blink loop
|
||||
while (1) {
|
||||
millisecond_timer();
|
||||
if (!DCC_Timer) {
|
||||
@@ -187,8 +193,7 @@ int main (void) {
|
||||
DCC_Timer = 1000;
|
||||
}
|
||||
/* USART Tx turns the LED on, we turn it off */
|
||||
if (((pPIO->PIO_ODSR & LED1) == LED1) && (LED1_Off_Enabled))
|
||||
{
|
||||
if (((pPIO->PIO_ODSR & LED1) == LED1) && (LED1_Off_Enabled)) {
|
||||
LED1_Off_Enabled = false;
|
||||
/* wait */
|
||||
LED_Timer_1 = 20;
|
||||
@@ -199,8 +204,7 @@ int main (void) {
|
||||
LED1_Off_Enabled = true;
|
||||
}
|
||||
/* USART Rx turns the LED on, we turn it off */
|
||||
if (((pPIO->PIO_ODSR & LED2) == LED2) && (LED2_Off_Enabled))
|
||||
{
|
||||
if (((pPIO->PIO_ODSR & LED2) == LED2) && (LED2_Off_Enabled)) {
|
||||
LED2_Off_Enabled = false;
|
||||
/* wait */
|
||||
LED_Timer_2 = 20;
|
||||
@@ -211,8 +215,7 @@ int main (void) {
|
||||
LED2_Off_Enabled = true;
|
||||
}
|
||||
/* switch or NPDU turns on the LED, we turn it off */
|
||||
if (((pPIO->PIO_ODSR & LED3) == LED3) && (LED3_Off_Enabled))
|
||||
{
|
||||
if (((pPIO->PIO_ODSR & LED3) == LED3) && (LED3_Off_Enabled)) {
|
||||
LED3_Off_Enabled = false;
|
||||
/* wait */
|
||||
LED_Timer_3 = 500;
|
||||
@@ -224,7 +227,7 @@ int main (void) {
|
||||
}
|
||||
/* Blink LED every second */
|
||||
if (!LED_Timer_4) {
|
||||
if ((pPIO->PIO_ODSR & LED4) == LED4) {
|
||||
if ((pPIO->PIO_ODSR & LED4) == LED4) {
|
||||
/* turn on */
|
||||
pPIO->PIO_CODR = LED4;
|
||||
} else {
|
||||
|
||||
@@ -62,52 +62,51 @@ static int RS485_Baud = 38400;
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Initialize(void)
|
||||
void RS485_Initialize(
|
||||
void)
|
||||
{
|
||||
/* Enable the USART0 clock in the Power Management Controller */
|
||||
volatile AT91PS_PMC pPMC = AT91C_BASE_PMC;
|
||||
pPMC->PMC_PCER = pPMC->PMC_PCSR | (1<<AT91C_ID_US0);
|
||||
pPMC->PMC_PCER = pPMC->PMC_PCSR | (1 << AT91C_ID_US0);
|
||||
|
||||
/* Disable and clear USART0 interrupt
|
||||
in AIC Interrupt Disable Command Register */
|
||||
volatile AT91PS_AIC pAIC = AT91C_BASE_AIC;
|
||||
pAIC->AIC_IDCR = (1<<AT91C_ID_US0);
|
||||
pAIC->AIC_ICCR = (1<<AT91C_ID_US0);
|
||||
|
||||
pAIC->AIC_IDCR = (1 << AT91C_ID_US0);
|
||||
pAIC->AIC_ICCR = (1 << AT91C_ID_US0);
|
||||
|
||||
/* enable the peripheral by disabling the pin in the PIO controller */
|
||||
*AT91C_PIOA_PDR = AT91C_PA5_RXD0 | AT91C_PA6_TXD0 | AT91C_PA7_RTS0;
|
||||
|
||||
RS485_Interface->US_CR =
|
||||
AT91C_US_RSTRX | /* Reset Receiver */
|
||||
AT91C_US_RSTTX | /* Reset Transmitter */
|
||||
AT91C_US_RSTSTA | /* Clear status register */
|
||||
AT91C_US_RXDIS | /* Receiver Disable */
|
||||
AT91C_US_TXDIS; /* Transmitter Disable */
|
||||
RS485_Interface->US_CR = AT91C_US_RSTRX | /* Reset Receiver */
|
||||
AT91C_US_RSTTX | /* Reset Transmitter */
|
||||
AT91C_US_RSTSTA | /* Clear status register */
|
||||
AT91C_US_RXDIS | /* Receiver Disable */
|
||||
AT91C_US_TXDIS; /* Transmitter Disable */
|
||||
|
||||
RS485_Interface->US_MR =
|
||||
AT91C_US_USMODE_RS485 | /* RS-485 Mode - RTS auto assert */
|
||||
AT91C_US_CLKS_CLOCK | /* Clock = MCK */
|
||||
AT91C_US_CHRL_8_BITS | /* 8-bit Data */
|
||||
AT91C_US_PAR_NONE | /* No Parity */
|
||||
AT91C_US_NBSTOP_1_BIT; /* 1 Stop Bit */
|
||||
RS485_Interface->US_MR = AT91C_US_USMODE_RS485 | /* RS-485 Mode - RTS auto assert */
|
||||
AT91C_US_CLKS_CLOCK | /* Clock = MCK */
|
||||
AT91C_US_CHRL_8_BITS | /* 8-bit Data */
|
||||
AT91C_US_PAR_NONE | /* No Parity */
|
||||
AT91C_US_NBSTOP_1_BIT; /* 1 Stop Bit */
|
||||
|
||||
/* set the Time Guard to release RTS after x bit times */
|
||||
RS485_Interface->US_TTGR = 1;
|
||||
|
||||
|
||||
/* Receiver Time-out disabled */
|
||||
RS485_Interface->US_RTOR = 0;
|
||||
|
||||
/* baud rate */
|
||||
RS485_Interface->US_BRGR = MCK/16/RS485_Baud;
|
||||
RS485_Interface->US_BRGR = MCK / 16 / RS485_Baud;
|
||||
|
||||
RS485_Interface->US_CR = AT91C_US_RXEN | /* Receiver Enable */
|
||||
AT91C_US_TXEN; /* Transmitter Enable */
|
||||
|
||||
RS485_Interface->US_CR =
|
||||
AT91C_US_RXEN | /* Receiver Enable */
|
||||
AT91C_US_TXEN; /* Transmitter Enable */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void RS485_Cleanup(void)
|
||||
void RS485_Cleanup(
|
||||
void)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -118,7 +117,8 @@ void RS485_Cleanup(void)
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
uint32_t RS485_Get_Baud_Rate(void)
|
||||
uint32_t RS485_Get_Baud_Rate(
|
||||
void)
|
||||
{
|
||||
return RS485_Baud;
|
||||
}
|
||||
@@ -129,7 +129,8 @@ uint32_t RS485_Get_Baud_Rate(void)
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
bool RS485_Set_Baud_Rate(uint32_t baud)
|
||||
bool RS485_Set_Baud_Rate(
|
||||
uint32_t baud)
|
||||
{
|
||||
bool valid = true;
|
||||
|
||||
@@ -141,7 +142,7 @@ bool RS485_Set_Baud_Rate(uint32_t baud)
|
||||
case 76800:
|
||||
case 115200:
|
||||
RS485_Baud = baud;
|
||||
RS485_Interface->US_BRGR = MCK/16/baud;
|
||||
RS485_Interface->US_BRGR = MCK / 16 / baud;
|
||||
/* FIXME: store the baud rate */
|
||||
break;
|
||||
default:
|
||||
@@ -158,14 +159,15 @@ bool RS485_Set_Baud_Rate(uint32_t baud)
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Turnaround_Delay(void)
|
||||
void RS485_Turnaround_Delay(
|
||||
void)
|
||||
{
|
||||
uint16_t turnaround_time;
|
||||
|
||||
|
||||
/* delay after reception before trasmitting - per MS/TP spec */
|
||||
/* wait a minimum 40 bit times since reception */
|
||||
/* at least 1 ms for errors: rounding, clock tick */
|
||||
turnaround_time = 1 + ((Tturnaround*1000UL)/RS485_Baud);
|
||||
turnaround_time = 1 + ((Tturnaround * 1000UL) / RS485_Baud);
|
||||
while (Timer_Silence() < turnaround_time) {
|
||||
/* do nothing - wait for timer to increment */
|
||||
};
|
||||
@@ -177,9 +179,10 @@ void RS485_Turnaround_Delay(void)
|
||||
* ALGORITHM: none
|
||||
* NOTES: The Atmel ARM7 has an automatic enable/disable in RS485 mode.
|
||||
*****************************************************************************/
|
||||
void RS485_Transmitter_Enable(bool enable)
|
||||
void RS485_Transmitter_Enable(
|
||||
bool enable)
|
||||
{
|
||||
(void)enable;
|
||||
(void) enable;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@@ -189,9 +192,9 @@ void RS485_Transmitter_Enable(bool enable)
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Send_Data(
|
||||
uint8_t * buffer, /* data to send */
|
||||
uint16_t nbytes) /* number of bytes of data */
|
||||
{
|
||||
uint8_t * buffer, /* data to send */
|
||||
uint16_t nbytes)
|
||||
{ /* number of bytes of data */
|
||||
/* LED on send */
|
||||
volatile AT91PS_PIO pPIO = AT91C_BASE_PIOA;
|
||||
/* LED ON */
|
||||
@@ -218,7 +221,8 @@ void RS485_Send_Data(
|
||||
* ALGORITHM: none
|
||||
* NOTES: Clears any error flags.
|
||||
*****************************************************************************/
|
||||
bool RS485_ReceiveError(void)
|
||||
bool RS485_ReceiveError(
|
||||
void)
|
||||
{
|
||||
bool ReceiveError = false;
|
||||
/* LED on send */
|
||||
@@ -242,25 +246,27 @@ bool RS485_ReceiveError(void)
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
bool RS485_DataAvailable(uint8_t *DataRegister)
|
||||
bool RS485_DataAvailable(
|
||||
uint8_t * DataRegister)
|
||||
{
|
||||
bool DataAvailable = false;
|
||||
/* LED on send */
|
||||
volatile AT91PS_PIO pPIO = AT91C_BASE_PIOA;
|
||||
|
||||
if ( RS485_Interface->US_CSR & AT91C_US_RXRDY) {
|
||||
|
||||
if (RS485_Interface->US_CSR & AT91C_US_RXRDY) {
|
||||
/* data is available */
|
||||
*DataRegister = RS485_Interface->US_RHR;
|
||||
DataAvailable = true;
|
||||
/* LED ON */
|
||||
pPIO->PIO_CODR = LED2;
|
||||
}
|
||||
|
||||
|
||||
return DataAvailable;
|
||||
}
|
||||
|
||||
#ifdef TEST_RS485
|
||||
int main(void)
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
unsigned i = 0;
|
||||
uint8_t DataRegister;
|
||||
@@ -270,11 +276,10 @@ int main(void)
|
||||
/* receive task */
|
||||
for (;;) {
|
||||
if (RS485_ReceiveError()) {
|
||||
fprintf(stderr,"ERROR ");
|
||||
fprintf(stderr, "ERROR ");
|
||||
} else if (RS485_DataAvailable(&DataRegister)) {
|
||||
fprintf(stderr,"%02X ",DataRegister);
|
||||
fprintf(stderr, "%02X ", DataRegister);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -30,24 +30,31 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void RS485_Initialize(void);
|
||||
void RS485_Initialize(
|
||||
void);
|
||||
|
||||
void RS485_Transmitter_Enable(bool enable);
|
||||
void RS485_Transmitter_Enable(
|
||||
bool enable);
|
||||
|
||||
void RS485_Send_Data(
|
||||
uint8_t * buffer, /* data to send */
|
||||
uint16_t nbytes); /* number of bytes of data */
|
||||
|
||||
bool RS485_ReceiveError(void);
|
||||
bool RS485_DataAvailable(uint8_t *data);
|
||||
bool RS485_ReceiveError(
|
||||
void);
|
||||
bool RS485_DataAvailable(
|
||||
uint8_t * data);
|
||||
|
||||
void RS485_Turnaround_Delay(void);
|
||||
uint32_t RS485_Get_Baud_Rate(void);
|
||||
bool RS485_Set_Baud_Rate(uint32_t baud);
|
||||
void RS485_Turnaround_Delay(
|
||||
void);
|
||||
uint32_t RS485_Get_Baud_Rate(
|
||||
void);
|
||||
bool RS485_Set_Baud_Rate(
|
||||
uint32_t baud);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -50,7 +50,9 @@ volatile unsigned long Timer_Milliseconds;
|
||||
/* MS/TP Silence Timer */
|
||||
static volatile int SilenceTime;
|
||||
|
||||
static void Timer0_Setup(int milliseconds) {
|
||||
static void Timer0_Setup(
|
||||
int milliseconds)
|
||||
{
|
||||
// TC Block Control Register TC_BCR (read/write)
|
||||
//
|
||||
// |------------------------------------------------------------------|------|
|
||||
@@ -214,7 +216,7 @@ static void Timer0_Setup(int milliseconds) {
|
||||
//
|
||||
// TIMER_CLOCK5 = (MCK / 1024) / 1000
|
||||
// = 48054841 / 1024 / 1000 = 46.928
|
||||
pTC->TC_RC = ((MCK/1024/1000)+1)*milliseconds;
|
||||
pTC->TC_RC = ((MCK / 1024 / 1000) + 1) * milliseconds;
|
||||
|
||||
// TC Interrupt Enable Register TC_IER (write-only)
|
||||
//
|
||||
@@ -297,9 +299,11 @@ static void Timer0_Setup(int milliseconds) {
|
||||
// Modified by Steve Karg
|
||||
// simplified and changed to a millisecond count-up timer
|
||||
// *****************************************************************************
|
||||
static void Timer0IrqHandler (void) {
|
||||
static void Timer0IrqHandler(
|
||||
void)
|
||||
{
|
||||
|
||||
volatile AT91PS_TC pTC = AT91C_BASE_TC0; // pointer to timer channel 0 register structure
|
||||
volatile AT91PS_TC pTC = AT91C_BASE_TC0; // pointer to timer channel 0 register structure
|
||||
unsigned int dummy; // temporary
|
||||
|
||||
// read TC0 Status Register to clear interrupt
|
||||
@@ -310,12 +314,14 @@ static void Timer0IrqHandler (void) {
|
||||
SilenceTime++;
|
||||
}
|
||||
|
||||
int Timer_Silence(void)
|
||||
int Timer_Silence(
|
||||
void)
|
||||
{
|
||||
return SilenceTime;
|
||||
}
|
||||
|
||||
void Timer_Silence_Reset(void)
|
||||
void Timer_Silence_Reset(
|
||||
void)
|
||||
{
|
||||
SilenceTime = 0;
|
||||
}
|
||||
@@ -330,33 +336,33 @@ void Timer_Silence_Reset(void)
|
||||
// Moved timer startup code from main
|
||||
// modified the peripheral clock init
|
||||
// *****************************************************************************
|
||||
void TimerInit(void)
|
||||
void TimerInit(
|
||||
void)
|
||||
{
|
||||
// enable the Timer0 peripheral clock
|
||||
volatile AT91PS_PMC pPMC = AT91C_BASE_PMC;
|
||||
pPMC->PMC_PCER = pPMC->PMC_PCSR | (1<<AT91C_ID_TC0);
|
||||
pPMC->PMC_PCER = pPMC->PMC_PCSR | (1 << AT91C_ID_TC0);
|
||||
// Set up the AIC registers for Timer 0
|
||||
volatile AT91PS_AIC pAIC = AT91C_BASE_AIC;
|
||||
volatile AT91PS_AIC pAIC = AT91C_BASE_AIC;
|
||||
// Disable timer 0 interrupt
|
||||
// in AIC Interrupt Disable Command Register
|
||||
pAIC->AIC_IDCR = (1<<AT91C_ID_TC0);
|
||||
pAIC->AIC_IDCR = (1 << AT91C_ID_TC0);
|
||||
// Set the TC0 IRQ handler address in
|
||||
// AIC Source Vector Register[12]
|
||||
pAIC->AIC_SVR[AT91C_ID_TC0] =
|
||||
(unsigned int)Timer0IrqHandler;
|
||||
pAIC->AIC_SVR[AT91C_ID_TC0] = (unsigned int) Timer0IrqHandler;
|
||||
// Set the interrupt source type and priority
|
||||
// in AIC Source Mode Register[12]
|
||||
pAIC->AIC_SMR[AT91C_ID_TC0] =
|
||||
(AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE | 0x4 );
|
||||
(AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE | 0x4);
|
||||
// Clear the TC0 interrupt
|
||||
// in AIC Interrupt Clear Command Register
|
||||
pAIC->AIC_ICCR = (1<<AT91C_ID_TC0);
|
||||
pAIC->AIC_ICCR = (1 << AT91C_ID_TC0);
|
||||
// Remove disable timer 0 interrupt
|
||||
// in AIC Interrupt Disable Command Reg
|
||||
pAIC->AIC_IDCR = (0<<AT91C_ID_TC0);
|
||||
pAIC->AIC_IDCR = (0 << AT91C_ID_TC0);
|
||||
// Enable the TC0 interrupt
|
||||
// in AIC Interrupt Enable Command Register
|
||||
pAIC->AIC_IECR = (1<<AT91C_ID_TC0);
|
||||
pAIC->AIC_IECR = (1 << AT91C_ID_TC0);
|
||||
// Setup timer0 to generate a 1 msec periodic interrupt
|
||||
Timer0_Setup(1);
|
||||
}
|
||||
|
||||
@@ -32,13 +32,16 @@ extern volatile unsigned long Timer_Milliseconds;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void TimerInit(void);
|
||||
int Timer_Silence(void);
|
||||
void Timer_Silence_Reset(void);
|
||||
void TimerInit(
|
||||
void);
|
||||
int Timer_Silence(
|
||||
void);
|
||||
void Timer_Silence_Reset(
|
||||
void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
/* Analog Input = Photocell */
|
||||
#define MAX_ANALOG_INPUTS 9
|
||||
#if (MAX_ANALOG_INPUTS > 9)
|
||||
#error Modify the Analog_Input_Name to handle multiple digits
|
||||
#error Modify the Analog_Input_Name to handle multiple digits
|
||||
#endif
|
||||
|
||||
float Present_Value[MAX_ANALOG_INPUTS];
|
||||
@@ -44,7 +44,8 @@ float Present_Value[MAX_ANALOG_INPUTS];
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Analog_Input_Valid_Instance(uint32_t object_instance)
|
||||
bool Analog_Input_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ANALOG_INPUTS)
|
||||
return true;
|
||||
@@ -53,30 +54,34 @@ bool Analog_Input_Valid_Instance(uint32_t object_instance)
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Analog_Input_Count(void)
|
||||
unsigned Analog_Input_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_ANALOG_INPUTS;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
uint32_t Analog_Input_Index_To_Instance(unsigned index)
|
||||
uint32_t Analog_Input_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Analog_Input_Instance_To_Index(uint32_t object_instance)
|
||||
unsigned Analog_Input_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
return object_instance;
|
||||
}
|
||||
|
||||
|
||||
char *Analog_Input_Name(uint32_t object_instance)
|
||||
char *Analog_Input_Name(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
static char text_string[5] = "AI-0"; /* okay for single thread */
|
||||
static char text_string[5] = "AI-0"; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_ANALOG_INPUTS) {
|
||||
text_string[3] = '0' + (uint8_t)object_instance;
|
||||
text_string[3] = '0' + (uint8_t) object_instance;
|
||||
return text_string;
|
||||
}
|
||||
|
||||
@@ -85,13 +90,15 @@ char *Analog_Input_Name(uint32_t object_instance)
|
||||
|
||||
/* return apdu length, or -1 on error */
|
||||
/* assumption - object has already exists */
|
||||
int Analog_Input_Encode_Property_APDU(uint8_t * apdu,
|
||||
int Analog_Input_Encode_Property_APDU(
|
||||
uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
int32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index;
|
||||
@@ -99,50 +106,53 @@ int Analog_Input_Encode_Property_APDU(uint8_t * apdu,
|
||||
|
||||
(void) array_index;
|
||||
switch (property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len = encode_application_object_id(&apdu[0], OBJECT_ANALOG_INPUT,
|
||||
object_instance);
|
||||
break;
|
||||
/* note: Name and Description don't have to be the same.
|
||||
You could make Description writable and different.
|
||||
Note that Object-Name must be unique in this device */
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Analog_Input_Name(object_instance));
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0],
|
||||
OBJECT_ANALOG_INPUT);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
object_index = Analog_Input_Instance_To_Index(object_instance);
|
||||
apdu_len = encode_application_real(&apdu[0],
|
||||
Present_Value[object_index]);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_UNITS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT);
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ANALOG_INPUT,
|
||||
object_instance);
|
||||
break;
|
||||
/* note: Name and Description don't have to be the same.
|
||||
You could make Description writable and different.
|
||||
Note that Object-Name must be unique in this device */
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Analog_Input_Name(object_instance));
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0],
|
||||
OBJECT_ANALOG_INPUT);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
object_index = Analog_Input_Instance_To_Index(object_instance);
|
||||
apdu_len = encode_application_real(&apdu[0],
|
||||
Present_Value[object_index]);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_UNITS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT);
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
|
||||
@@ -41,7 +41,8 @@
|
||||
#include "bacenum.h"
|
||||
#include "handlers.h"
|
||||
|
||||
bool apdu_service_supported(BACNET_SERVICES_SUPPORTED service_supported)
|
||||
bool apdu_service_supported(
|
||||
BACNET_SERVICES_SUPPORTED service_supported)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
@@ -57,13 +58,15 @@ bool apdu_service_supported(BACNET_SERVICES_SUPPORTED service_supported)
|
||||
return status;
|
||||
}
|
||||
|
||||
uint16_t apdu_decode_confirmed_service_request(uint8_t * apdu, /* APDU data */
|
||||
uint16_t apdu_decode_confirmed_service_request(
|
||||
uint8_t * apdu, /* APDU data */
|
||||
uint16_t apdu_len,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data,
|
||||
uint8_t * service_choice,
|
||||
uint8_t ** service_request, uint16_t * service_request_len)
|
||||
uint8_t ** service_request,
|
||||
uint16_t * service_request_len)
|
||||
{
|
||||
uint16_t len = 0; /* counts where we are in PDU */
|
||||
uint16_t len = 0; /* counts where we are in PDU */
|
||||
|
||||
service_data->segmented_message = (apdu[0] & BIT3) ? true : false;
|
||||
service_data->more_follows = (apdu[0] & BIT2) ? true : false;
|
||||
@@ -84,55 +87,56 @@ uint16_t apdu_decode_confirmed_service_request(uint8_t * apdu, /* APDU data */
|
||||
return len;
|
||||
}
|
||||
|
||||
void apdu_handler(BACNET_ADDRESS * src, uint8_t * apdu, /* APDU data */
|
||||
void apdu_handler(
|
||||
BACNET_ADDRESS * src,
|
||||
uint8_t * apdu, /* APDU data */
|
||||
uint16_t apdu_len)
|
||||
{
|
||||
BACNET_CONFIRMED_SERVICE_DATA service_data = { 0 };
|
||||
uint8_t service_choice = 0;
|
||||
uint8_t *service_request = NULL;
|
||||
uint16_t service_request_len = 0;
|
||||
uint16_t len = 0; /* counts where we are in PDU */
|
||||
uint16_t len = 0; /* counts where we are in PDU */
|
||||
|
||||
if (apdu) {
|
||||
/* PDU Type */
|
||||
switch (apdu[0] & 0xF0) {
|
||||
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
|
||||
len = apdu_decode_confirmed_service_request(&apdu[0], /* APDU data */
|
||||
apdu_len,
|
||||
&service_data,
|
||||
&service_choice, &service_request, &service_request_len);
|
||||
if (service_choice == SERVICE_CONFIRMED_READ_PROPERTY) {
|
||||
handler_read_property(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
}
|
||||
#if 0
|
||||
else if (service_choice == SERVICE_CONFIRMED_WRITE_PROPERTY) {
|
||||
handler_write_property(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
}
|
||||
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
|
||||
len = apdu_decode_confirmed_service_request(&apdu[0], /* APDU data */
|
||||
apdu_len,
|
||||
&service_data,
|
||||
&service_choice, &service_request, &service_request_len);
|
||||
if (service_choice == SERVICE_CONFIRMED_READ_PROPERTY) {
|
||||
handler_read_property(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
}
|
||||
#if 0
|
||||
else if (service_choice == SERVICE_CONFIRMED_WRITE_PROPERTY) {
|
||||
handler_write_property(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
handler_unrecognized_service(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
|
||||
service_choice = apdu[1];
|
||||
service_request = &apdu[2];
|
||||
service_request_len = apdu_len - 2;
|
||||
if (service_choice == SERVICE_UNCONFIRMED_WHO_IS) {
|
||||
handler_who_is(service_request,
|
||||
service_request_len, src);
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_SIMPLE_ACK:
|
||||
case PDU_TYPE_COMPLEX_ACK:
|
||||
case PDU_TYPE_SEGMENT_ACK:
|
||||
case PDU_TYPE_ERROR:
|
||||
case PDU_TYPE_REJECT:
|
||||
case PDU_TYPE_ABORT:
|
||||
default:
|
||||
break;
|
||||
else {
|
||||
handler_unrecognized_service(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
|
||||
service_choice = apdu[1];
|
||||
service_request = &apdu[2];
|
||||
service_request_len = apdu_len - 2;
|
||||
if (service_choice == SERVICE_UNCONFIRMED_WHO_IS) {
|
||||
handler_who_is(service_request, service_request_len, src);
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_SIMPLE_ACK:
|
||||
case PDU_TYPE_COMPLEX_ACK:
|
||||
case PDU_TYPE_SEGMENT_ACK:
|
||||
case PDU_TYPE_ERROR:
|
||||
case PDU_TYPE_REJECT:
|
||||
case PDU_TYPE_ABORT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
@@ -31,12 +31,12 @@
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
|
||||
#define MAX_ANALOG_VALUES 9
|
||||
#if (MAX_ANALOG_VALUES > 9)
|
||||
#error Modify the Analog_Value_Name to handle multiple digits
|
||||
#error Modify the Analog_Value_Name to handle multiple digits
|
||||
#endif
|
||||
|
||||
float Present_Value[MAX_ANALOG_VALUES];
|
||||
@@ -44,7 +44,8 @@ float Present_Value[MAX_ANALOG_VALUES];
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Analog_Value_Valid_Instance(uint32_t object_instance)
|
||||
bool Analog_Value_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ANALOG_VALUES)
|
||||
return true;
|
||||
@@ -54,7 +55,8 @@ bool Analog_Value_Valid_Instance(uint32_t object_instance)
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Analog_Value_Count(void)
|
||||
unsigned Analog_Value_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_ANALOG_VALUES;
|
||||
}
|
||||
@@ -62,7 +64,8 @@ unsigned Analog_Value_Count(void)
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the instance */
|
||||
/* that correlates to the correct index */
|
||||
uint32_t Analog_Value_Index_To_Instance(unsigned index)
|
||||
uint32_t Analog_Value_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
@@ -70,18 +73,20 @@ uint32_t Analog_Value_Index_To_Instance(unsigned index)
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned Analog_Value_Instance_To_Index(uint32_t object_instance)
|
||||
unsigned Analog_Value_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
return object_instance;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
char *Analog_Value_Name(uint32_t object_instance)
|
||||
char *Analog_Value_Name(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
static char text_string[5] = "AV-0"; /* okay for single thread */
|
||||
static char text_string[5] = "AV-0"; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_ANALOG_VALUES) {
|
||||
text_string[3] = '0' + (uint8_t)object_instance;
|
||||
text_string[3] = '0' + (uint8_t) object_instance;
|
||||
return text_string;
|
||||
}
|
||||
|
||||
@@ -89,65 +94,74 @@ char *Analog_Value_Name(uint32_t object_instance)
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
int Analog_Value_Encode_Property_APDU(uint8_t * apdu,
|
||||
int Analog_Value_Encode_Property_APDU(
|
||||
uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
int32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index;
|
||||
|
||||
|
||||
switch (property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len = encode_application_object_id(&apdu[0], OBJECT_ANALOG_VALUE,
|
||||
object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Analog_Value_Name(object_instance));
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], OBJECT_ANALOG_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
apdu_len = encode_application_real(&apdu[0], Present_Value[object_index]);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_UNITS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT);
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ANALOG_VALUE,
|
||||
object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Analog_Value_Name(object_instance));
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_ANALOG_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
apdu_len =
|
||||
encode_application_real(&apdu[0], Present_Value[object_index]);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_UNITS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT);
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Analog_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
bool Analog_Value_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
@@ -166,22 +180,21 @@ bool Analog_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
/* FIXME: len == 0: unable to decode? */
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_REAL) {
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->
|
||||
object_instance);
|
||||
Present_Value[object_index] = value.type.Real;
|
||||
status = true;
|
||||
} else {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_REAL) {
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->object_instance);
|
||||
Present_Value[object_index] = value.type.Real;
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
@@ -192,7 +205,8 @@ bool Analog_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
void testAnalog_Value(Test * pTest)
|
||||
void testAnalog_Value(
|
||||
Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
@@ -207,8 +221,7 @@ void testAnalog_Value(Test * pTest)
|
||||
|
||||
len = Analog_Value_Encode_Property_APDU(&apdu[0],
|
||||
instance,
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
@@ -221,7 +234,8 @@ void testAnalog_Value(Test * pTest)
|
||||
}
|
||||
|
||||
#ifdef TEST_ANALOG_VALUE
|
||||
int main(void)
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -238,5 +252,5 @@ int main(void)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_ANALOG_VALUE */
|
||||
#endif /* TEST */
|
||||
#endif /* TEST_ANALOG_VALUE */
|
||||
#endif /* TEST */
|
||||
|
||||
@@ -15,4 +15,4 @@
|
||||
#define BITMASK_FLIP(x,y) ((x) ^= (y))
|
||||
#define BITMASK_CHECK(x,y) ((x) & (y))
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -53,7 +53,8 @@ static uint32_t Object_Instance_Number = 260001;
|
||||
static char Object_Name[32] = "ATmega168 Device";
|
||||
static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL;
|
||||
|
||||
void Device_Init(void)
|
||||
void Device_Init(
|
||||
void)
|
||||
{
|
||||
/* Reinitialize_State = REINITIALIZED_STATE_IDLE; */
|
||||
/* dcc_set_status_duration(COMMUNICATION_ENABLE, 0); */
|
||||
@@ -65,14 +66,16 @@ void Device_Init(void)
|
||||
}
|
||||
|
||||
/* methods to manipulate the data */
|
||||
uint32_t Device_Object_Instance_Number(void)
|
||||
uint32_t Device_Object_Instance_Number(
|
||||
void)
|
||||
{
|
||||
return Object_Instance_Number;
|
||||
}
|
||||
|
||||
bool Device_Set_Object_Instance_Number(uint32_t object_id)
|
||||
bool Device_Set_Object_Instance_Number(
|
||||
uint32_t object_id)
|
||||
{
|
||||
bool status = true; /* return value */
|
||||
bool status = true; /* return value */
|
||||
|
||||
if (object_id <= BACNET_MAX_INSTANCE) {
|
||||
Object_Instance_Number = object_id;
|
||||
@@ -88,21 +91,24 @@ bool Device_Set_Object_Instance_Number(uint32_t object_id)
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Device_Valid_Object_Instance_Number(uint32_t object_id)
|
||||
bool Device_Valid_Object_Instance_Number(
|
||||
uint32_t object_id)
|
||||
{
|
||||
/* BACnet allows for a wildcard instance number */
|
||||
return ((Object_Instance_Number == object_id) ||
|
||||
(object_id == BACNET_MAX_INSTANCE));
|
||||
}
|
||||
|
||||
uint16_t Device_Vendor_Identifier(void)
|
||||
uint16_t Device_Vendor_Identifier(
|
||||
void)
|
||||
{
|
||||
return BACNET_VENDOR_ID;
|
||||
}
|
||||
|
||||
unsigned Device_Object_List_Count(void)
|
||||
unsigned Device_Object_List_Count(
|
||||
void)
|
||||
{
|
||||
unsigned count = 1; /* at least 1 for device object */
|
||||
unsigned count = 1; /* at least 1 for device object */
|
||||
|
||||
/* FIXME: add objects as needed */
|
||||
#if 0
|
||||
@@ -115,8 +121,10 @@ unsigned Device_Object_List_Count(void)
|
||||
return count;
|
||||
}
|
||||
|
||||
bool Device_Object_List_Identifier(unsigned array_index,
|
||||
int *object_type, uint32_t * instance)
|
||||
bool Device_Object_List_Identifier(
|
||||
unsigned array_index,
|
||||
int *object_type,
|
||||
uint32_t * instance)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned object_index = 0;
|
||||
@@ -185,18 +193,20 @@ bool Device_Object_List_Identifier(unsigned array_index,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* return the length of the apdu encoded or -1 for error */
|
||||
int Device_Encode_Property_APDU(uint8_t * apdu,
|
||||
int Device_Encode_Property_APDU(
|
||||
uint8_t * apdu,
|
||||
BACNET_PROPERTY_ID property,
|
||||
int32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
int len = 0; /* apdu len intermediate value */
|
||||
int apdu_len = 0; /* return value */
|
||||
int len = 0; /* apdu len intermediate value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned i = 0;
|
||||
@@ -206,168 +216,175 @@ int Device_Encode_Property_APDU(uint8_t * apdu,
|
||||
|
||||
/* FIXME: change the hardcoded names to suit your application */
|
||||
switch (property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len = encode_application_object_id(&apdu[0], OBJECT_DEVICE,
|
||||
Object_Instance_Number);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string, Object_Name);
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], OBJECT_DEVICE);
|
||||
break;
|
||||
case PROP_SYSTEM_STATUS:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], System_Status);
|
||||
break;
|
||||
case PROP_VENDOR_NAME:
|
||||
characterstring_init_ansi(&char_string, BACNET_VENDOR_NAME);
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_VENDOR_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], Device_Vendor_Identifier());
|
||||
break;
|
||||
case PROP_MODEL_NAME:
|
||||
characterstring_init_ansi(&char_string, "GNU Demo");
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_FIRMWARE_REVISION:
|
||||
characterstring_init_ansi(&char_string, BACnet_Version);
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_APPLICATION_SOFTWARE_VERSION:
|
||||
characterstring_init_ansi(&char_string, "1.0");
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_PROTOCOL_VERSION:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], 1);
|
||||
break;
|
||||
case PROP_PROTOCOL_REVISION:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], 5);
|
||||
break;
|
||||
case PROP_PROTOCOL_SERVICES_SUPPORTED:
|
||||
/* Note: list of services that are executed, not initiated. */
|
||||
bitstring_init(&bit_string);
|
||||
for (i = 0; i < MAX_BACNET_SERVICES_SUPPORTED; i++) {
|
||||
/* automatic lookup based on handlers set */
|
||||
bitstring_set_bit(&bit_string, (uint8_t) i,
|
||||
apdu_service_supported(i));
|
||||
}
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED:
|
||||
/* Note: this is the list of objects that can be in this device,
|
||||
not a list of objects that this device can access */
|
||||
bitstring_init(&bit_string);
|
||||
/* must have the bit string as big as it can be */
|
||||
for (i = 0; i < MAX_ASHRAE_OBJECT_TYPE; i++) {
|
||||
/* initialize all the object types to not-supported */
|
||||
bitstring_set_bit(&bit_string, (uint8_t) i, false);
|
||||
}
|
||||
/* FIXME: indicate the objects that YOU support */
|
||||
bitstring_set_bit(&bit_string, OBJECT_DEVICE, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_ANALOG_VALUE, true);
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len = encode_application_object_id(&apdu[0], OBJECT_DEVICE,
|
||||
Object_Instance_Number);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string, Object_Name);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], OBJECT_DEVICE);
|
||||
break;
|
||||
case PROP_SYSTEM_STATUS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], System_Status);
|
||||
break;
|
||||
case PROP_VENDOR_NAME:
|
||||
characterstring_init_ansi(&char_string, BACNET_VENDOR_NAME);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_VENDOR_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
Device_Vendor_Identifier());
|
||||
break;
|
||||
case PROP_MODEL_NAME:
|
||||
characterstring_init_ansi(&char_string, "GNU Demo");
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_FIRMWARE_REVISION:
|
||||
characterstring_init_ansi(&char_string, BACnet_Version);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_APPLICATION_SOFTWARE_VERSION:
|
||||
characterstring_init_ansi(&char_string, "1.0");
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_PROTOCOL_VERSION:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], 1);
|
||||
break;
|
||||
case PROP_PROTOCOL_REVISION:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], 5);
|
||||
break;
|
||||
case PROP_PROTOCOL_SERVICES_SUPPORTED:
|
||||
/* Note: list of services that are executed, not initiated. */
|
||||
bitstring_init(&bit_string);
|
||||
for (i = 0; i < MAX_BACNET_SERVICES_SUPPORTED; i++) {
|
||||
/* automatic lookup based on handlers set */
|
||||
bitstring_set_bit(&bit_string, (uint8_t) i,
|
||||
apdu_service_supported(i));
|
||||
}
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED:
|
||||
/* Note: this is the list of objects that can be in this device,
|
||||
not a list of objects that this device can access */
|
||||
bitstring_init(&bit_string);
|
||||
/* must have the bit string as big as it can be */
|
||||
for (i = 0; i < MAX_ASHRAE_OBJECT_TYPE; i++) {
|
||||
/* initialize all the object types to not-supported */
|
||||
bitstring_set_bit(&bit_string, (uint8_t) i, false);
|
||||
}
|
||||
/* FIXME: indicate the objects that YOU support */
|
||||
bitstring_set_bit(&bit_string, OBJECT_DEVICE, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_ANALOG_VALUE, true);
|
||||
#if 0
|
||||
bitstring_set_bit(&bit_string, OBJECT_ANALOG_INPUT, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_BINARY_VALUE, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_BINARY_INPUT, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_ANALOG_INPUT, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_BINARY_VALUE, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_BINARY_INPUT, true);
|
||||
#endif
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_OBJECT_LIST:
|
||||
count = Device_Object_List_Count();
|
||||
/* Array element zero is the number of objects in the list */
|
||||
if (array_index == 0)
|
||||
apdu_len = encode_application_unsigned(&apdu[0], count);
|
||||
/* if no index was specified, then try to encode the entire list */
|
||||
/* into one packet. Note that more than likely you will have */
|
||||
/* to return an error if the number of encoded objects exceeds */
|
||||
/* your maximum APDU size. */
|
||||
else if (array_index == BACNET_ARRAY_ALL) {
|
||||
for (i = 1; i <= count; i++) {
|
||||
if (Device_Object_List_Identifier(i, &object_type,
|
||||
&instance)) {
|
||||
len =
|
||||
encode_application_object_id(&apdu[apdu_len],
|
||||
object_type, instance);
|
||||
apdu_len += len;
|
||||
/* assume next one is the same size as this one */
|
||||
/* can we all fit into the APDU? */
|
||||
if ((apdu_len + len) >= MAX_APDU) {
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_OBJECT_LIST:
|
||||
count = Device_Object_List_Count();
|
||||
/* Array element zero is the number of objects in the list */
|
||||
if (array_index == 0)
|
||||
apdu_len = encode_application_unsigned(&apdu[0], count);
|
||||
/* if no index was specified, then try to encode the entire list */
|
||||
/* into one packet. Note that more than likely you will have */
|
||||
/* to return an error if the number of encoded objects exceeds */
|
||||
/* your maximum APDU size. */
|
||||
else if (array_index == BACNET_ARRAY_ALL) {
|
||||
for (i = 1; i <= count; i++) {
|
||||
if (Device_Object_List_Identifier(i, &object_type,
|
||||
&instance)) {
|
||||
len =
|
||||
encode_application_object_id(&apdu[apdu_len],
|
||||
object_type, instance);
|
||||
apdu_len += len;
|
||||
/* assume next one is the same size as this one */
|
||||
/* can we all fit into the APDU? */
|
||||
if ((apdu_len + len) >= MAX_APDU) {
|
||||
*error_class = ERROR_CLASS_SERVICES;
|
||||
*error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* error: internal error? */
|
||||
*error_class = ERROR_CLASS_SERVICES;
|
||||
*error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
|
||||
*error_code = ERROR_CODE_OTHER;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* error: internal error? */
|
||||
*error_class = ERROR_CLASS_SERVICES;
|
||||
*error_code = ERROR_CODE_OTHER;
|
||||
}
|
||||
} else {
|
||||
if (Device_Object_List_Identifier(array_index, &object_type,
|
||||
&instance))
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], object_type,
|
||||
instance);
|
||||
else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (Device_Object_List_Identifier(array_index, &object_type,
|
||||
&instance))
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], object_type,
|
||||
instance);
|
||||
else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PROP_MAX_APDU_LENGTH_ACCEPTED:
|
||||
apdu_len = encode_application_unsigned(&apdu[0],
|
||||
MAX_APDU);
|
||||
break;
|
||||
case PROP_SEGMENTATION_SUPPORTED:
|
||||
apdu_len = encode_application_enumerated(&apdu[0],
|
||||
SEGMENTATION_NONE);
|
||||
break;
|
||||
case PROP_APDU_TIMEOUT:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], 60000);
|
||||
break;
|
||||
case PROP_NUMBER_OF_APDU_RETRIES:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], 0);
|
||||
break;
|
||||
case PROP_DEVICE_ADDRESS_BINDING:
|
||||
/* FIXME: encode the list here, if it exists */
|
||||
break;
|
||||
case PROP_DATABASE_REVISION:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], 0);
|
||||
break;
|
||||
case PROP_MAX_INFO_FRAMES:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], dlmstp_max_info_frames());
|
||||
break;
|
||||
case PROP_MAX_MASTER:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], dlmstp_max_master());
|
||||
break;
|
||||
case 9600:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], RS485_Get_Baud_Rate());
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
break;
|
||||
case PROP_MAX_APDU_LENGTH_ACCEPTED:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], MAX_APDU);
|
||||
break;
|
||||
case PROP_SEGMENTATION_SUPPORTED:
|
||||
apdu_len = encode_application_enumerated(&apdu[0],
|
||||
SEGMENTATION_NONE);
|
||||
break;
|
||||
case PROP_APDU_TIMEOUT:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], 60000);
|
||||
break;
|
||||
case PROP_NUMBER_OF_APDU_RETRIES:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], 0);
|
||||
break;
|
||||
case PROP_DEVICE_ADDRESS_BINDING:
|
||||
/* FIXME: encode the list here, if it exists */
|
||||
break;
|
||||
case PROP_DATABASE_REVISION:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], 0);
|
||||
break;
|
||||
case PROP_MAX_INFO_FRAMES:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
dlmstp_max_info_frames());
|
||||
break;
|
||||
case PROP_MAX_MASTER:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], dlmstp_max_master());
|
||||
break;
|
||||
case 9600:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], RS485_Get_Baud_Rate());
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
#if 0
|
||||
bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
bool Device_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
int len = 0;
|
||||
@@ -384,98 +401,98 @@ bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
/* FIXME: len == 0: unable to decode? */
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_OBJECT_ID) {
|
||||
if ((value.type.Object_Id.type == OBJECT_DEVICE) &&
|
||||
(Device_Set_Object_Instance_Number(value.type.
|
||||
Object_Id.instance))) {
|
||||
/* we could send an I-Am broadcast to let the world know */
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case PROP_MAX_INFO_FRAMES:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
if (value.type.Unsigned_Int <= 255) {
|
||||
dlmstp_set_max_info_frames(value.type.Unsigned_Int);
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case PROP_MAX_MASTER:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
if ((value.type.Unsigned_Int > 0) &&
|
||||
(value.type.Unsigned_Int <= 127)) {
|
||||
dlmstp_set_max_master(value.type.Unsigned_Int);
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) {
|
||||
uint8_t encoding;
|
||||
size_t len;
|
||||
|
||||
encoding =
|
||||
characterstring_encoding(&value.type.Character_String);
|
||||
len = characterstring_length(&value.type.Character_String);
|
||||
if (encoding == CHARACTER_ANSI_X34) {
|
||||
if (len <= 20) {
|
||||
/* FIXME: set the name */
|
||||
/* Display_Set_Name(
|
||||
characterstring_value(&value.type.Character_String)); */
|
||||
/* FIXME: All the object names in a device must be unique.
|
||||
Disallow setting the Device Object Name to any objects in
|
||||
the device. */
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_OBJECT_ID) {
|
||||
if ((value.type.Object_Id.type == OBJECT_DEVICE) &&
|
||||
(Device_Set_Object_Instance_Number(value.type.
|
||||
Object_Id.instance))) {
|
||||
/* we could send an I-Am broadcast to let the world know */
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case 9600:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
if (value.type.Unsigned_Int > 115200) {
|
||||
RS485_Set_Baud_Rate(value.type.Unsigned_Int);
|
||||
status = true;
|
||||
break;
|
||||
case PROP_MAX_INFO_FRAMES:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
if (value.type.Unsigned_Int <= 255) {
|
||||
dlmstp_set_max_info_frames(value.type.Unsigned_Int);
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
case PROP_MAX_MASTER:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
if ((value.type.Unsigned_Int > 0) &&
|
||||
(value.type.Unsigned_Int <= 127)) {
|
||||
dlmstp_set_max_master(value.type.Unsigned_Int);
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) {
|
||||
uint8_t encoding;
|
||||
size_t len;
|
||||
|
||||
encoding =
|
||||
characterstring_encoding(&value.type.Character_String);
|
||||
len = characterstring_length(&value.type.Character_String);
|
||||
if (encoding == CHARACTER_ANSI_X34) {
|
||||
if (len <= 20) {
|
||||
/* FIXME: set the name */
|
||||
/* Display_Set_Name(
|
||||
characterstring_value(&value.type.Character_String)); */
|
||||
/* FIXME: All the object names in a device must be unique.
|
||||
Disallow setting the Device Object Name to any objects in
|
||||
the device. */
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case 9600:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
if (value.type.Unsigned_Int > 115200) {
|
||||
RS485_Set_Baud_Rate(value.type.Unsigned_Int);
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -64,24 +64,18 @@ int Encode_Property_APDU(
|
||||
*error_class = ERROR_CLASS_OBJECT;
|
||||
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
/* handle each object type */
|
||||
switch(object_type) {
|
||||
switch (object_type) {
|
||||
case OBJECT_DEVICE:
|
||||
if (Device_Valid_Object_Instance_Number(object_instance)) {
|
||||
apdu_len = Device_Encode_Property_APDU(
|
||||
&apdu[0],
|
||||
property,
|
||||
array_index,
|
||||
error_class, error_code);
|
||||
apdu_len = Device_Encode_Property_APDU(&apdu[0],
|
||||
property, array_index, error_class, error_code);
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_VALUE:
|
||||
if (Analog_Value_Valid_Instance(object_instance)) {
|
||||
apdu_len = Analog_Value_Encode_Property_APDU(
|
||||
&apdu[0],
|
||||
apdu_len = Analog_Value_Encode_Property_APDU(&apdu[0],
|
||||
object_instance,
|
||||
property,
|
||||
array_index,
|
||||
error_class, error_code);
|
||||
property, array_index, error_class, error_code);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -93,9 +87,11 @@ int Encode_Property_APDU(
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
void handler_read_property(uint8_t * service_request,
|
||||
void handler_read_property(
|
||||
uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
{
|
||||
BACNET_READ_PROPERTY_DATA data;
|
||||
int len = 0;
|
||||
@@ -125,13 +121,10 @@ void handler_read_property(uint8_t * service_request,
|
||||
} else {
|
||||
/* most cases will be error */
|
||||
error = true;
|
||||
len = Encode_Property_APDU(
|
||||
&Temp_Buf[0],
|
||||
len = Encode_Property_APDU(&Temp_Buf[0],
|
||||
data.object_type,
|
||||
data.object_instance,
|
||||
data.object_property,
|
||||
data.array_index,
|
||||
&error_class, &error_code);
|
||||
data.object_property, data.array_index, &error_class, &error_code);
|
||||
if (len >= 0) {
|
||||
/* encode the APDU portion of the packet */
|
||||
data.application_data = &Temp_Buf[0];
|
||||
@@ -145,18 +138,18 @@ void handler_read_property(uint8_t * service_request,
|
||||
}
|
||||
if (error) {
|
||||
switch (len) {
|
||||
/* BACnet APDU too small to fit data, so proper response is Abort */
|
||||
case -2:
|
||||
len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true);
|
||||
break;
|
||||
case -1:
|
||||
default:
|
||||
len = bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_READ_PROPERTY, error_class, error_code);
|
||||
break;
|
||||
/* BACnet APDU too small to fit data, so proper response is Abort */
|
||||
case -2:
|
||||
len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true);
|
||||
break;
|
||||
case -1:
|
||||
default:
|
||||
len = bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_READ_PROPERTY, error_class, error_code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pdu_len += len;
|
||||
|
||||
@@ -39,8 +39,10 @@
|
||||
|
||||
bool Send_I_Am = true;
|
||||
|
||||
void handler_who_is(uint8_t * service_request,
|
||||
uint16_t service_len, BACNET_ADDRESS * src)
|
||||
void handler_who_is(
|
||||
uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src)
|
||||
{
|
||||
int len = 0;
|
||||
int32_t low_limit = 0;
|
||||
@@ -55,8 +57,7 @@ void handler_who_is(uint8_t * service_request,
|
||||
} else if (len != -1) {
|
||||
/* is my device id within the limits? */
|
||||
target_device = Device_Object_Instance_Number();
|
||||
if (((target_device >= low_limit) &&
|
||||
(target_device <= high_limit))
|
||||
if (((target_device >= low_limit) && (target_device <= high_limit))
|
||||
||
|
||||
/* BACnet wildcard is the max instance number - everyone responds */
|
||||
((BACNET_MAX_INSTANCE >= (uint32_t) low_limit) &&
|
||||
|
||||
@@ -48,9 +48,11 @@
|
||||
/* too big to reside on stack frame for PIC */
|
||||
static BACNET_WRITE_PROPERTY_DATA wp_data;
|
||||
|
||||
void handler_write_property(uint8_t * service_request,
|
||||
void handler_write_property(
|
||||
uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
{
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
@@ -61,8 +63,7 @@ void handler_write_property(uint8_t * service_request,
|
||||
BACNET_ADDRESS my_address;
|
||||
|
||||
/* decode the service request only */
|
||||
len = wp_decode_service_request(service_request,
|
||||
service_len, &wp_data);
|
||||
len = wp_decode_service_request(service_request, service_len, &wp_data);
|
||||
/* encode the NPDU portion of the packet */
|
||||
datalink_get_my_address(&my_address);
|
||||
npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
|
||||
@@ -79,66 +80,66 @@ void handler_write_property(uint8_t * service_request,
|
||||
} else {
|
||||
switch (wp_data.object_type) {
|
||||
#if 0
|
||||
case OBJECT_DEVICE:
|
||||
if (Device_Write_Property(&wp_data, &error_class, &error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
} else {
|
||||
case OBJECT_DEVICE:
|
||||
if (Device_Write_Property(&wp_data, &error_class, &error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_INPUT:
|
||||
case OBJECT_BINARY_INPUT:
|
||||
error_class = ERROR_CLASS_PROPERTY;
|
||||
error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_INPUT:
|
||||
case OBJECT_BINARY_INPUT:
|
||||
error_class = ERROR_CLASS_PROPERTY;
|
||||
error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY,
|
||||
error_class, error_code);
|
||||
break;
|
||||
case OBJECT_BINARY_VALUE:
|
||||
if (Binary_Value_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
}
|
||||
break;
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY,
|
||||
error_class, error_code);
|
||||
break;
|
||||
case OBJECT_BINARY_VALUE:
|
||||
if (Binary_Value_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case OBJECT_ANALOG_VALUE:
|
||||
if (Analog_Value_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
} else {
|
||||
case OBJECT_ANALOG_VALUE:
|
||||
if (Analog_Value_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY,
|
||||
error_class, error_code);
|
||||
break;
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY,
|
||||
error_class, error_code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pdu_len += len;
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#define HARDWARE_H
|
||||
|
||||
/* The processor clock frequency */
|
||||
#define F_CPU (7372800)
|
||||
#define F_CPU (7372800)
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
@@ -39,11 +39,14 @@
|
||||
http://www.avrfreaks.net/wiki/index.php/Documentation:AVR_GCC/IarToAvrgcc*/
|
||||
|
||||
/* dummy function */
|
||||
bool dcc_communication_enabled(void) {
|
||||
bool dcc_communication_enabled(
|
||||
void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void init(void)
|
||||
void init(
|
||||
void)
|
||||
{
|
||||
/* Initialize the Clock Prescaler for ATmega48/88/168 */
|
||||
/* The default CLKPSx bits are factory set to 0011 */
|
||||
@@ -51,17 +54,17 @@ void init(void)
|
||||
CLKPR = _BV(CLKPCE);
|
||||
/* CLKPS3 CLKPS2 CLKPS1 CLKPS0 Clock Division Factor
|
||||
------ ------ ------ ------ ---------------------
|
||||
0 0 0 0 1
|
||||
0 0 0 1 2
|
||||
0 0 1 0 4
|
||||
0 0 1 1 8
|
||||
0 1 0 0 16
|
||||
0 1 0 1 32
|
||||
0 1 1 0 64
|
||||
0 1 1 1 128
|
||||
1 0 0 0 256
|
||||
1 x x x Reserved
|
||||
*/
|
||||
0 0 0 0 1
|
||||
0 0 0 1 2
|
||||
0 0 1 0 4
|
||||
0 0 1 1 8
|
||||
0 1 0 0 16
|
||||
0 1 0 1 32
|
||||
0 1 1 0 64
|
||||
0 1 1 1 128
|
||||
1 0 0 0 256
|
||||
1 x x x Reserved
|
||||
*/
|
||||
/* Set the CLKPS3..0 bits to Prescaler of 1 */
|
||||
CLKPR = 0;
|
||||
/* Initialize I/O ports */
|
||||
@@ -75,7 +78,7 @@ void init(void)
|
||||
PORTD = 0;
|
||||
|
||||
/* Configure the watchdog timer - Disabled for testing */
|
||||
BIT_CLEAR(MCUSR,WDRF);
|
||||
BIT_CLEAR(MCUSR, WDRF);
|
||||
WDTCSR = 0;
|
||||
|
||||
/* Configure USART */
|
||||
@@ -85,11 +88,11 @@ void init(void)
|
||||
Timer_Initialize();
|
||||
|
||||
/* Set the LED ports OFF */
|
||||
BIT_SET(PORTD,PD4);
|
||||
BIT_SET(PORTD,PD5);
|
||||
BIT_SET(PORTD, PD4);
|
||||
BIT_SET(PORTD, PD5);
|
||||
/* Configure the LED ports as outputs */
|
||||
BIT_SET(DDRD,DDD4);
|
||||
BIT_SET(DDRD,DDD5);
|
||||
BIT_SET(DDRD, DDD4);
|
||||
BIT_SET(DDRD, DDD5);
|
||||
|
||||
/* Enable global interrupts */
|
||||
sei();
|
||||
@@ -97,23 +100,26 @@ void init(void)
|
||||
|
||||
static uint8_t NPDU_Timer;
|
||||
|
||||
static void NDPU_Timers(void)
|
||||
static void NDPU_Timers(
|
||||
void)
|
||||
{
|
||||
if (NPDU_Timer) {
|
||||
NPDU_Timer--;
|
||||
if (NPDU_Timer == 0) {
|
||||
BIT_SET(PORTD,PD5);
|
||||
BIT_SET(PORTD, PD5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void NPDU_LED_On(void)
|
||||
static void NPDU_LED_On(
|
||||
void)
|
||||
{
|
||||
BIT_CLEAR(PORTD,PD5);
|
||||
BIT_CLEAR(PORTD, PD5);
|
||||
NPDU_Timer = 20;
|
||||
}
|
||||
|
||||
void task_milliseconds(void)
|
||||
void task_milliseconds(
|
||||
void)
|
||||
{
|
||||
while (Timer_Milliseconds) {
|
||||
Timer_Milliseconds--;
|
||||
@@ -125,31 +131,33 @@ void task_milliseconds(void)
|
||||
|
||||
static uint8_t Address_Switch;
|
||||
|
||||
void input_switch_read(void)
|
||||
void input_switch_read(
|
||||
void)
|
||||
{
|
||||
uint8_t value;
|
||||
static uint8_t old_value = 0;
|
||||
|
||||
value = BITMASK_CHECK(PINC,0x0F) | (BITMASK_CHECK(PINB,0x07)<<4);
|
||||
value = BITMASK_CHECK(PINC, 0x0F) | (BITMASK_CHECK(PINB, 0x07) << 4);
|
||||
if (value != old_value) {
|
||||
old_value = value;
|
||||
} else {
|
||||
if (old_value != Address_Switch) {
|
||||
Address_Switch = old_value;
|
||||
Address_Switch = old_value;
|
||||
#if defined(BACDL_MSTP)
|
||||
dlmstp_set_mac_address(Address_Switch);
|
||||
dlmstp_set_mac_address(Address_Switch);
|
||||
#endif
|
||||
Device_Set_Object_Instance_Number(86000 + Address_Switch);
|
||||
Device_Set_Object_Instance_Number(86000 + Address_Switch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t PDUBuffer[MAX_MPDU];
|
||||
int main(void)
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
uint16_t pdu_len = 0;
|
||||
BACNET_ADDRESS src; /* source address */
|
||||
|
||||
|
||||
init();
|
||||
#if defined(BACDL_MSTP)
|
||||
RS485_Set_Baud_Rate(38400);
|
||||
|
||||
@@ -70,10 +70,11 @@ static uint32_t RS485_Baud = 9600;
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Initialize(void)
|
||||
void RS485_Initialize(
|
||||
void)
|
||||
{
|
||||
/* enable Transmit and Receive */
|
||||
UCSR0B = _BV(TXEN0) | _BV(RXEN0);
|
||||
UCSR0B = _BV(TXEN0) | _BV(RXEN0);
|
||||
|
||||
/* Set USART Control and Status Register n C */
|
||||
/* Asynchronous USART 8-bit data, No parity, 1 stop */
|
||||
@@ -84,16 +85,16 @@ void RS485_Initialize(void)
|
||||
/* Clock Polarity: UCPOLn = 0 when asynchronous mode is used. */
|
||||
UCSR0C = _BV(UCSZ01) | _BV(UCSZ00);
|
||||
/* Clear Power Reduction USART0 */
|
||||
BIT_CLEAR(PRR,PRUSART0);
|
||||
BIT_CLEAR(PRR, PRUSART0);
|
||||
/* Use port PD2 for RTS - enable and disable of Transceiver Tx/Rx */
|
||||
/* Set port bit as Output - initially receiving */
|
||||
BIT_CLEAR(PORTD,PD2);
|
||||
BIT_SET(DDRD,DDD2);
|
||||
BIT_CLEAR(PORTD, PD2);
|
||||
BIT_SET(DDRD, DDD2);
|
||||
/* Configure Transmit and Receive LEDs - initially off */
|
||||
BIT_SET(PORTD,PD6);
|
||||
BIT_SET(PORTD,PD7);
|
||||
BIT_SET(DDRD,DDD6);
|
||||
BIT_SET(DDRD,DDD7);
|
||||
BIT_SET(PORTD, PD6);
|
||||
BIT_SET(PORTD, PD7);
|
||||
BIT_SET(DDRD, DDD6);
|
||||
BIT_SET(DDRD, DDD7);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -104,7 +105,8 @@ void RS485_Initialize(void)
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
uint32_t RS485_Get_Baud_Rate(void)
|
||||
uint32_t RS485_Get_Baud_Rate(
|
||||
void)
|
||||
{
|
||||
return RS485_Baud;
|
||||
}
|
||||
@@ -115,7 +117,8 @@ uint32_t RS485_Get_Baud_Rate(void)
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
bool RS485_Set_Baud_Rate(uint32_t baud)
|
||||
bool RS485_Set_Baud_Rate(
|
||||
uint32_t baud)
|
||||
{
|
||||
bool valid = true;
|
||||
|
||||
@@ -128,7 +131,7 @@ bool RS485_Set_Baud_Rate(uint32_t baud)
|
||||
case 115200:
|
||||
RS485_Baud = baud;
|
||||
/* 2x speed mode */
|
||||
BIT_SET(UCSR0A,U2X0);
|
||||
BIT_SET(UCSR0A, U2X0);
|
||||
/* configure baud rate */
|
||||
UBRR0 = (F_CPU / (8UL * RS485_Baud)) - 1;
|
||||
/* FIXME: store the baud rate */
|
||||
@@ -147,14 +150,15 @@ bool RS485_Set_Baud_Rate(uint32_t baud)
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Turnaround_Delay(void)
|
||||
void RS485_Turnaround_Delay(
|
||||
void)
|
||||
{
|
||||
uint16_t turnaround_time;
|
||||
|
||||
|
||||
/* delay after reception before trasmitting - per MS/TP spec */
|
||||
/* wait a minimum 40 bit times since reception */
|
||||
/* at least 1 ms for errors: rounding, clock tick */
|
||||
turnaround_time = 1 + ((Tturnaround*1000UL)/RS485_Baud);
|
||||
turnaround_time = 1 + ((Tturnaround * 1000UL) / RS485_Baud);
|
||||
while (Timer_Silence() < turnaround_time) {
|
||||
/* do nothing - wait for timer to increment */
|
||||
};
|
||||
@@ -166,18 +170,19 @@ void RS485_Turnaround_Delay(void)
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Transmitter_Enable(bool enable)
|
||||
void RS485_Transmitter_Enable(
|
||||
bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
BIT_SET(PORTD,PD2);
|
||||
BIT_SET(PORTD, PD2);
|
||||
} else {
|
||||
#if Tpostdrive1
|
||||
_delay_us(Tpostdrive1/RS485_Baud);
|
||||
#endif
|
||||
#if Tpostdrive2
|
||||
_delay_us(Tpostdrive2/RS485_Baud);
|
||||
#endif
|
||||
BIT_CLEAR(PORTD,PD2);
|
||||
#if Tpostdrive1
|
||||
_delay_us(Tpostdrive1 / RS485_Baud);
|
||||
#endif
|
||||
#if Tpostdrive2
|
||||
_delay_us(Tpostdrive2 / RS485_Baud);
|
||||
#endif
|
||||
BIT_CLEAR(PORTD, PD2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,18 +192,19 @@ void RS485_Transmitter_Enable(bool enable)
|
||||
* ALGORITHM: none
|
||||
* NOTES: expected to be called once a millisecond
|
||||
*****************************************************************************/
|
||||
void RS485_LED_Timers(void)
|
||||
void RS485_LED_Timers(
|
||||
void)
|
||||
{
|
||||
if (LED1_Off_Timer) {
|
||||
LED1_Off_Timer--;
|
||||
if (LED1_Off_Timer == 0) {
|
||||
BIT_SET(PORTD,PD6);
|
||||
BIT_SET(PORTD, PD6);
|
||||
}
|
||||
}
|
||||
if (LED3_Off_Timer) {
|
||||
LED3_Off_Timer--;
|
||||
if (LED3_Off_Timer == 0) {
|
||||
BIT_SET(PORTD,PD7);
|
||||
BIT_SET(PORTD, PD7);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -209,9 +215,10 @@ void RS485_LED_Timers(void)
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
static void RS485_LED1_On(void)
|
||||
static void RS485_LED1_On(
|
||||
void)
|
||||
{
|
||||
BIT_CLEAR(PORTD,PD6);
|
||||
BIT_CLEAR(PORTD, PD6);
|
||||
LED1_Off_Timer = 20;
|
||||
}
|
||||
|
||||
@@ -221,9 +228,10 @@ static void RS485_LED1_On(void)
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
static void RS485_LED3_On(void)
|
||||
static void RS485_LED3_On(
|
||||
void)
|
||||
{
|
||||
BIT_CLEAR(PORTD,PD7);
|
||||
BIT_CLEAR(PORTD, PD7);
|
||||
LED3_Off_Timer = 20;
|
||||
}
|
||||
|
||||
@@ -234,27 +242,27 @@ static void RS485_LED3_On(void)
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Send_Data(
|
||||
uint8_t * buffer, /* data to send */
|
||||
uint16_t nbytes) /* number of bytes of data */
|
||||
{
|
||||
uint8_t * buffer, /* data to send */
|
||||
uint16_t nbytes)
|
||||
{ /* number of bytes of data */
|
||||
RS485_LED3_On();
|
||||
while (nbytes) {
|
||||
while (!BIT_CHECK(UCSR0A,UDRE0)) {
|
||||
while (!BIT_CHECK(UCSR0A, UDRE0)) {
|
||||
/* do nothing - wait until Tx buffer is empty */
|
||||
}
|
||||
UDR0 = *buffer;
|
||||
buffer++;
|
||||
nbytes--;
|
||||
}
|
||||
while (!BIT_CHECK(UCSR0A,UDRE0)) {
|
||||
while (!BIT_CHECK(UCSR0A, UDRE0)) {
|
||||
/* do nothing - wait until Tx buffer is empty */
|
||||
}
|
||||
/* is the frame sent? */
|
||||
while (!BIT_CHECK(UCSR0A,TXC0)) {
|
||||
while (!BIT_CHECK(UCSR0A, TXC0)) {
|
||||
/* do nothing - wait until the entire frame in the
|
||||
Transmit Shift Register has been shifted out */
|
||||
}
|
||||
BIT_CLEAR(UCSR0A,TXC0);
|
||||
BIT_CLEAR(UCSR0A, TXC0);
|
||||
/* per MSTP spec, sort of */
|
||||
Timer_Silence_Reset();
|
||||
}
|
||||
@@ -266,31 +274,32 @@ void RS485_Send_Data(
|
||||
* ALGORITHM: autobaud - if there are a lot of errors, switch baud rate
|
||||
* NOTES: Clears any error flags.
|
||||
*****************************************************************************/
|
||||
bool RS485_ReceiveError(void)
|
||||
bool RS485_ReceiveError(
|
||||
void)
|
||||
{
|
||||
bool ReceiveError = false;
|
||||
uint8_t dummy_data;
|
||||
|
||||
/* check for framing error */
|
||||
#if 0
|
||||
if (BIT_CHECK(UCSR0A,FE0)) {
|
||||
#if 0
|
||||
if (BIT_CHECK(UCSR0A, FE0)) {
|
||||
/* FIXME: how do I clear the error flags? */
|
||||
BITMASK_CLEAR(UCSR0A,(_BV(FE0) | _BV(DOR0) | _BV(UPE0)));
|
||||
BITMASK_CLEAR(UCSR0A, (_BV(FE0) | _BV(DOR0) | _BV(UPE0)));
|
||||
ReceiveError = true;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
/* check for overrun error */
|
||||
if (BIT_CHECK(UCSR0A,DOR0)) {
|
||||
if (BIT_CHECK(UCSR0A, DOR0)) {
|
||||
/* flush the receive buffer */
|
||||
do {
|
||||
dummy_data = UDR0;
|
||||
} while (BIT_CHECK(UCSR0A,RXC0));
|
||||
} while (BIT_CHECK(UCSR0A, RXC0));
|
||||
ReceiveError = true;
|
||||
}
|
||||
if (ReceiveError) {
|
||||
RS485_LED1_On();
|
||||
}
|
||||
|
||||
|
||||
return ReceiveError;
|
||||
}
|
||||
|
||||
@@ -300,12 +309,13 @@ bool RS485_ReceiveError(void)
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
bool RS485_DataAvailable(uint8_t *data)
|
||||
bool RS485_DataAvailable(
|
||||
uint8_t * data)
|
||||
{
|
||||
bool DataAvailable = false;
|
||||
|
||||
/* check for data */
|
||||
if (BIT_CHECK(UCSR0A,RXC0)) {
|
||||
if (BIT_CHECK(UCSR0A, RXC0)) {
|
||||
*data = UDR0;
|
||||
DataAvailable = true;
|
||||
RS485_LED1_On();
|
||||
@@ -315,7 +325,8 @@ bool RS485_DataAvailable(uint8_t *data)
|
||||
}
|
||||
|
||||
#ifdef TEST_RS485
|
||||
int main(void)
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
unsigned i = 0;
|
||||
uint8_t DataRegister;
|
||||
@@ -325,11 +336,10 @@ int main(void)
|
||||
/* receive task */
|
||||
for (;;) {
|
||||
if (RS485_ReceiveError()) {
|
||||
fprintf(stderr,"ERROR ");
|
||||
fprintf(stderr, "ERROR ");
|
||||
} else if (RS485_DataAvailable(&DataRegister)) {
|
||||
fprintf(stderr,"%02X ",DataRegister);
|
||||
fprintf(stderr, "%02X ", DataRegister);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* TEST_RS485 */
|
||||
|
||||
#endif /* TEST_RS485 */
|
||||
|
||||
@@ -40,26 +40,34 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void RS485_Initialize(void);
|
||||
void RS485_Initialize(
|
||||
void);
|
||||
|
||||
void RS485_Transmitter_Enable(bool enable);
|
||||
void RS485_Transmitter_Enable(
|
||||
bool enable);
|
||||
|
||||
void RS485_Send_Data(
|
||||
uint8_t * buffer, /* data to send */
|
||||
uint16_t nbytes); /* number of bytes of data */
|
||||
|
||||
bool RS485_ReceiveError(void);
|
||||
bool RS485_DataAvailable(uint8_t *data);
|
||||
bool RS485_ReceiveError(
|
||||
void);
|
||||
bool RS485_DataAvailable(
|
||||
uint8_t * data);
|
||||
|
||||
void RS485_Turnaround_Delay(void);
|
||||
uint32_t RS485_Get_Baud_Rate(void);
|
||||
bool RS485_Set_Baud_Rate(uint32_t baud);
|
||||
void RS485_Turnaround_Delay(
|
||||
void);
|
||||
uint32_t RS485_Get_Baud_Rate(
|
||||
void);
|
||||
bool RS485_Set_Baud_Rate(
|
||||
uint32_t baud);
|
||||
|
||||
void RS485_LED_Timers(void);
|
||||
void RS485_LED_Timers(
|
||||
void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -41,30 +41,31 @@ volatile uint8_t Timer_Milliseconds = 0;
|
||||
static volatile uint16_t SilenceTime;
|
||||
|
||||
/* Configure the Timer */
|
||||
void Timer_Initialize(void)
|
||||
void Timer_Initialize(
|
||||
void)
|
||||
{
|
||||
/* Normal Operation */
|
||||
TCCR1A = 0;
|
||||
/* CSn2 CSn1 CSn0 Description
|
||||
---- ---- ---- -----------
|
||||
0 0 0 No Clock Source
|
||||
0 0 1 No prescaling
|
||||
0 1 0 CLKio/8
|
||||
0 1 1 CLKio/64
|
||||
1 0 0 CLKio/256
|
||||
1 0 1 CLKio/1024
|
||||
1 1 0 Falling Edge of T0 (external)
|
||||
1 1 1 Rising Edge of T0 (external)
|
||||
*/
|
||||
0 0 0 No Clock Source
|
||||
0 0 1 No prescaling
|
||||
0 1 0 CLKio/8
|
||||
0 1 1 CLKio/64
|
||||
1 0 0 CLKio/256
|
||||
1 0 1 CLKio/1024
|
||||
1 1 0 Falling Edge of T0 (external)
|
||||
1 1 1 Rising Edge of T0 (external)
|
||||
*/
|
||||
TCCR0B = _BV(CS01) | _BV(CS00);
|
||||
/* Clear any TOV1 Flag set when the timer overflowed */
|
||||
BIT_CLEAR(TIFR0,TOV0);
|
||||
BIT_CLEAR(TIFR0, TOV0);
|
||||
/* Initial value */
|
||||
TCNT0 = TIMER_COUNT;
|
||||
/* Enable the overflow interrupt */
|
||||
BIT_SET(TIMSK0,TOIE0);
|
||||
BIT_SET(TIMSK0, TOIE0);
|
||||
/* Clear the Power Reduction Timer/Counter0 */
|
||||
BIT_CLEAR(PRR,PRTIM0);
|
||||
BIT_CLEAR(PRR, PRTIM0);
|
||||
}
|
||||
|
||||
/* Timer interupt */
|
||||
@@ -77,13 +78,14 @@ ISR(TIMER0_OVF_vect)
|
||||
/* Overflow Flag is automatically cleared */
|
||||
/* Update the global timer */
|
||||
if (Timer_Milliseconds < 0xFF)
|
||||
Timer_Milliseconds++;
|
||||
Timer_Milliseconds++;
|
||||
if (SilenceTime < 0xFFFF)
|
||||
SilenceTime++;
|
||||
}
|
||||
|
||||
/* Public access to the Silence Timer */
|
||||
uint16_t Timer_Silence(void)
|
||||
uint16_t Timer_Silence(
|
||||
void)
|
||||
{
|
||||
uint16_t timer;
|
||||
uint8_t sreg;
|
||||
@@ -97,7 +99,8 @@ uint16_t Timer_Silence(void)
|
||||
}
|
||||
|
||||
/* Public reset of the Silence Timer */
|
||||
void Timer_Silence_Reset(void)
|
||||
void Timer_Silence_Reset(
|
||||
void)
|
||||
{
|
||||
uint8_t sreg;
|
||||
|
||||
|
||||
@@ -29,14 +29,16 @@ extern volatile uint8_t Timer_Milliseconds;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void Timer_Initialize(void);
|
||||
uint16_t Timer_Silence(void);
|
||||
void Timer_Silence_Reset(void);
|
||||
void Timer_Initialize(
|
||||
void);
|
||||
uint16_t Timer_Silence(
|
||||
void);
|
||||
void Timer_Silence_Reset(
|
||||
void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -80,12 +80,14 @@ clockp Clock Prescaler DataRate
|
||||
|
||||
*/
|
||||
|
||||
bool arcnet_valid(void)
|
||||
bool arcnet_valid(
|
||||
void)
|
||||
{
|
||||
return (ARCNET_Sock_FD >= 0);
|
||||
}
|
||||
|
||||
void arcnet_cleanup(void)
|
||||
void arcnet_cleanup(
|
||||
void)
|
||||
{
|
||||
if (arcnet_valid())
|
||||
close(ARCNET_Sock_FD);
|
||||
@@ -94,11 +96,12 @@ void arcnet_cleanup(void)
|
||||
return;
|
||||
}
|
||||
|
||||
static int arcnet_bind(char *interface_name)
|
||||
static int arcnet_bind(
|
||||
char *interface_name)
|
||||
{
|
||||
int sock_fd = -1; /* return value */
|
||||
int sock_fd = -1; /* return value */
|
||||
struct ifreq ifr;
|
||||
int rv; /* return value - error value from df or ioctl call */
|
||||
int rv; /* return value - error value from df or ioctl call */
|
||||
int uid = 0;
|
||||
|
||||
/* check to see if we are being run as root */
|
||||
@@ -116,8 +119,7 @@ static int arcnet_bind(char *interface_name)
|
||||
/* Then follow it by: # modprobe af_packet */
|
||||
if ((sock_fd = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ALL))) < 0) {
|
||||
/* Error occured */
|
||||
fprintf(stderr,
|
||||
"arcnet: Error opening socket: %s\n", strerror(errno));
|
||||
fprintf(stderr, "arcnet: Error opening socket: %s\n", strerror(errno));
|
||||
fprintf(stderr,
|
||||
"You might need to add the following to modules.conf\n"
|
||||
"(or in /etc/modutils/alias on Debian with update-modules):\n"
|
||||
@@ -157,7 +159,7 @@ static int arcnet_bind(char *interface_name)
|
||||
}
|
||||
strncpy(ifr.ifr_name, interface_name, sizeof(ifr.ifr_name));
|
||||
rv = ioctl(sock_fd, SIOCGIFHWADDR, &ifr);
|
||||
if (rv != -1) /* worked okay */
|
||||
if (rv != -1) /* worked okay */
|
||||
ARCNET_MAC_Address = ifr.ifr_hwaddr.sa_data[0];
|
||||
/* copy this info into the local copy since bind wiped it out */
|
||||
ARCNET_Socket_Address.sa_family = ARPHRD_ARCNET;
|
||||
@@ -176,7 +178,8 @@ static int arcnet_bind(char *interface_name)
|
||||
return sock_fd;
|
||||
}
|
||||
|
||||
bool arcnet_init(char *interface_name)
|
||||
bool arcnet_init(
|
||||
char *interface_name)
|
||||
{
|
||||
if (interface_name)
|
||||
ARCNET_Sock_FD = arcnet_bind(interface_name);
|
||||
@@ -188,11 +191,12 @@ bool arcnet_init(char *interface_name)
|
||||
|
||||
/* function to send a PDU out the socket */
|
||||
/* returns number of bytes sent on success, negative on failure */
|
||||
int arcnet_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
int arcnet_send_pdu(
|
||||
BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len)
|
||||
{ /* number of bytes of data */
|
||||
{ /* number of bytes of data */
|
||||
BACNET_ADDRESS src = { 0 }; /* source address */
|
||||
int bytes = 0;
|
||||
uint8_t mtu[512] = { 0 };
|
||||
@@ -240,19 +244,19 @@ int arcnet_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
sizeof(ARCNET_Socket_Address));
|
||||
/* did it get sent? */
|
||||
if (bytes < 0)
|
||||
fprintf(stderr, "arcnet: Error sending packet: %s\n",
|
||||
strerror(errno));
|
||||
fprintf(stderr, "arcnet: Error sending packet: %s\n", strerror(errno));
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/* receives an framed packet */
|
||||
/* returns the number of octets in the PDU, or zero on failure */
|
||||
uint16_t arcnet_receive(BACNET_ADDRESS * src, /* source address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t max_pdu, /* amount of space available in the PDU */
|
||||
uint16_t arcnet_receive(
|
||||
BACNET_ADDRESS * src, /* source address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t max_pdu, /* amount of space available in the PDU */
|
||||
unsigned timeout)
|
||||
{ /* milliseconds to wait for a packet */
|
||||
{ /* milliseconds to wait for a packet */
|
||||
int received_bytes;
|
||||
uint8_t buf[512] = { 0 }; /* data */
|
||||
uint16_t pdu_len = 0; /* return value */
|
||||
@@ -347,7 +351,8 @@ uint16_t arcnet_receive(BACNET_ADDRESS * src, /* source address */
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
void arcnet_get_my_address(BACNET_ADDRESS * my_address)
|
||||
void arcnet_get_my_address(
|
||||
BACNET_ADDRESS * my_address)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
@@ -362,15 +367,16 @@ void arcnet_get_my_address(BACNET_ADDRESS * my_address)
|
||||
return;
|
||||
}
|
||||
|
||||
void arcnet_get_broadcast_address(BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
void arcnet_get_broadcast_address(
|
||||
BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
|
||||
if (dest) {
|
||||
dest->mac[0] = ARCNET_BROADCAST;
|
||||
dest->mac_len = 1;
|
||||
dest->net = BACNET_BROADCAST_NETWORK;
|
||||
dest->len = 0; /* always zero when DNET is broadcast */
|
||||
dest->len = 0; /* always zero when DNET is broadcast */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
dest->adr[i] = 0;
|
||||
}
|
||||
|
||||
@@ -32,19 +32,21 @@
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include "bacdcode.h"
|
||||
#include "bip.h"
|
||||
#include "net.h"
|
||||
|
||||
bool BIP_Debug = false;
|
||||
|
||||
static int get_local_ifr_ioctl(char *ifname, struct ifreq *ifr,
|
||||
static int get_local_ifr_ioctl(
|
||||
char *ifname,
|
||||
struct ifreq *ifr,
|
||||
int request)
|
||||
{
|
||||
int fd;
|
||||
int rv; /* return value */
|
||||
int rv; /* return value */
|
||||
|
||||
strncpy(ifr->ifr_name, ifname, sizeof(ifr->ifr_name));
|
||||
fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
|
||||
@@ -56,12 +58,14 @@ static int get_local_ifr_ioctl(char *ifname, struct ifreq *ifr,
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int get_local_address_ioctl(char *ifname,
|
||||
struct in_addr *addr, int request)
|
||||
static int get_local_address_ioctl(
|
||||
char *ifname,
|
||||
struct in_addr *addr,
|
||||
int request)
|
||||
{
|
||||
struct ifreq ifr = { {{0}} };
|
||||
struct sockaddr_in *tcpip_address;
|
||||
int rv; /* return value */
|
||||
int rv; /* return value */
|
||||
|
||||
rv = get_local_ifr_ioctl(ifname, &ifr, request);
|
||||
if (rv >= 0) {
|
||||
@@ -73,7 +77,8 @@ static int get_local_address_ioctl(char *ifname,
|
||||
}
|
||||
|
||||
/* on Linux, ifname is eth0, ath0, arc0, and others. */
|
||||
static void bip_set_interface(char *ifname)
|
||||
static void bip_set_interface(
|
||||
char *ifname)
|
||||
{
|
||||
struct in_addr local_address;
|
||||
struct in_addr broadcast_address;
|
||||
@@ -90,8 +95,7 @@ static void bip_set_interface(char *ifname)
|
||||
fprintf(stderr, "IP Address: %s\n", inet_ntoa(local_address));
|
||||
}
|
||||
/* setup local broadcast address */
|
||||
rv = get_local_address_ioctl(ifname, &broadcast_address,
|
||||
SIOCGIFBRDADDR);
|
||||
rv = get_local_address_ioctl(ifname, &broadcast_address, SIOCGIFBRDADDR);
|
||||
if (rv < 0) {
|
||||
broadcast_address.s_addr = ~0;
|
||||
}
|
||||
@@ -100,14 +104,14 @@ static void bip_set_interface(char *ifname)
|
||||
fprintf(stderr, "IP Broadcast Address: %s\n",
|
||||
inet_ntoa(broadcast_address));
|
||||
fprintf(stderr, "UDP Port: 0x%04X [%hu]\n",
|
||||
bip_get_port(),
|
||||
bip_get_port());
|
||||
bip_get_port(), bip_get_port());
|
||||
}
|
||||
}
|
||||
|
||||
bool bip_init(char *ifname)
|
||||
bool bip_init(
|
||||
char *ifname)
|
||||
{
|
||||
int status = 0; /* return from socket lib calls */
|
||||
int status = 0; /* return from socket lib calls */
|
||||
struct sockaddr_in sin;
|
||||
int sockopt = 0;
|
||||
int sock_fd = -1;
|
||||
|
||||
+153
-150
@@ -63,26 +63,30 @@ static uint8_t RxBuffer[MAX_MPDU];
|
||||
/* Timer that indicates line silence - and functions */
|
||||
static uint16_t SilenceTime;
|
||||
#define INCREMENT_AND_LIMIT_UINT16(x) {if (x < 0xFFFF) x++;}
|
||||
static uint16_t Timer_Silence(void)
|
||||
static uint16_t Timer_Silence(
|
||||
void)
|
||||
{
|
||||
return SilenceTime;
|
||||
}
|
||||
static void Timer_Silence_Reset(void)
|
||||
static void Timer_Silence_Reset(
|
||||
void)
|
||||
{
|
||||
SilenceTime = 0;
|
||||
}
|
||||
|
||||
static void dlmstp_millisecond_timer(void)
|
||||
static void dlmstp_millisecond_timer(
|
||||
void)
|
||||
{
|
||||
INCREMENT_AND_LIMIT_UINT16(SilenceTime);
|
||||
}
|
||||
|
||||
static void *dlmstp_milliseconds_task(void *pArg)
|
||||
static void *dlmstp_milliseconds_task(
|
||||
void *pArg)
|
||||
{
|
||||
struct timespec timeOut,remains;
|
||||
struct timespec timeOut, remains;
|
||||
|
||||
timeOut.tv_sec = 0;
|
||||
timeOut.tv_nsec = 1000000; /* 1 millisecond */
|
||||
timeOut.tv_nsec = 1000000; /* 1 millisecond */
|
||||
|
||||
for (;;) {
|
||||
nanosleep(&timeOut, &remains);
|
||||
@@ -92,7 +96,8 @@ static void *dlmstp_milliseconds_task(void *pArg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void dlmstp_reinit(void)
|
||||
void dlmstp_reinit(
|
||||
void)
|
||||
{
|
||||
/*RS485_Reinit(); */
|
||||
dlmstp_set_mac_address(DEFAULT_MAC_ADDRESS);
|
||||
@@ -101,22 +106,21 @@ void dlmstp_reinit(void)
|
||||
}
|
||||
|
||||
/* returns number of bytes sent on success, zero on failure */
|
||||
int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
int dlmstp_send_pdu(
|
||||
BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len)
|
||||
{ /* number of bytes of data */
|
||||
{ /* number of bytes of data */
|
||||
DLMSTP_PACKET packet;
|
||||
int bytes_sent = 0;
|
||||
ssize_t rc = 0;
|
||||
|
||||
if (pdu_len) {
|
||||
if (npdu_data->data_expecting_reply) {
|
||||
packet.frame_type =
|
||||
FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY;
|
||||
packet.frame_type = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY;
|
||||
} else {
|
||||
packet.frame_type =
|
||||
FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY;
|
||||
packet.frame_type = FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY;
|
||||
}
|
||||
packet.pdu_len = pdu_len;
|
||||
memmove(&packet.pdu[0], &pdu[0], pdu_len);
|
||||
@@ -132,11 +136,11 @@ int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
/* copy the packet if one is received.
|
||||
Return the length of the packet */
|
||||
uint16_t dlmstp_receive(
|
||||
BACNET_ADDRESS * src, /* source address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t max_pdu, /* amount of space available in the PDU */
|
||||
unsigned timeout) /* milliseconds to wait for a packet */
|
||||
{
|
||||
BACNET_ADDRESS * src, /* source address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t max_pdu, /* amount of space available in the PDU */
|
||||
unsigned timeout)
|
||||
{ /* milliseconds to wait for a packet */
|
||||
uint16_t pdu_len = 0;
|
||||
int received_bytes = 0;
|
||||
DLMSTP_PACKET packet;
|
||||
@@ -161,10 +165,7 @@ uint16_t dlmstp_receive(
|
||||
max = Receive_Client_SockFD;
|
||||
|
||||
if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0) {
|
||||
received_bytes = read(
|
||||
Receive_Client_SockFD,
|
||||
&packet,
|
||||
sizeof(packet));
|
||||
received_bytes = read(Receive_Client_SockFD, &packet, sizeof(packet));
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
@@ -198,7 +199,8 @@ uint16_t dlmstp_receive(
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
static void *dlmstp_fsm_receive_task(void *pArg)
|
||||
static void *dlmstp_fsm_receive_task(
|
||||
void *pArg)
|
||||
{
|
||||
bool received_frame = false;
|
||||
|
||||
@@ -221,12 +223,13 @@ static void *dlmstp_fsm_receive_task(void *pArg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *dlmstp_fsm_master_task(void *pArg)
|
||||
static void *dlmstp_fsm_master_task(
|
||||
void *pArg)
|
||||
{
|
||||
struct timespec timeOut,remains;
|
||||
struct timespec timeOut, remains;
|
||||
|
||||
timeOut.tv_sec = 0;
|
||||
timeOut.tv_nsec = 100000; /* .1 millisecond */
|
||||
timeOut.tv_nsec = 100000; /* .1 millisecond */
|
||||
|
||||
for (;;) {
|
||||
nanosleep(&timeOut, &remains);
|
||||
@@ -241,7 +244,9 @@ static void *dlmstp_fsm_master_task(void *pArg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void dlmstp_fill_bacnet_address(BACNET_ADDRESS * src, uint8_t mstp_address)
|
||||
void dlmstp_fill_bacnet_address(
|
||||
BACNET_ADDRESS * src,
|
||||
uint8_t mstp_address)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
@@ -266,7 +271,7 @@ void dlmstp_fill_bacnet_address(BACNET_ADDRESS * src, uint8_t mstp_address)
|
||||
|
||||
/* for the MS/TP state machine to use for putting received data */
|
||||
uint16_t MSTP_Put_Receive(
|
||||
volatile struct mstp_port_struct_t *mstp_port)
|
||||
volatile struct mstp_port_struct_t *mstp_port)
|
||||
{
|
||||
DLMSTP_PACKET packet;
|
||||
uint16_t pdu_len = mstp_port->DataLength;
|
||||
@@ -276,11 +281,8 @@ uint16_t MSTP_Put_Receive(
|
||||
pdu_len = sizeof(packet.pdu);
|
||||
if (pdu_len) {
|
||||
MSTP_Packets++;
|
||||
memmove(&packet.pdu[0],
|
||||
(void *) & mstp_port->InputBuffer[0],
|
||||
pdu_len);
|
||||
dlmstp_fill_bacnet_address(&packet.address,
|
||||
mstp_port->SourceAddress);
|
||||
memmove(&packet.pdu[0], (void *) &mstp_port->InputBuffer[0], pdu_len);
|
||||
dlmstp_fill_bacnet_address(&packet.address, mstp_port->SourceAddress);
|
||||
packet.pdu_len = pdu_len;
|
||||
/* ready is not used in this scheme */
|
||||
packet.ready = true;
|
||||
@@ -293,10 +295,10 @@ uint16_t MSTP_Put_Receive(
|
||||
/* for the MS/TP state machine to use for getting data to send */
|
||||
/* Return: amount of PDU data */
|
||||
int dlmstp_get_transmit_packet(
|
||||
DLMSTP_PACKET *packet,
|
||||
unsigned timeout) /* milliseconds to wait for a packet */
|
||||
{
|
||||
int received_bytes = 0; /* return value */
|
||||
DLMSTP_PACKET * packet,
|
||||
unsigned timeout)
|
||||
{ /* milliseconds to wait for a packet */
|
||||
int received_bytes = 0; /* return value */
|
||||
struct timeval select_timeout;
|
||||
fd_set read_fds;
|
||||
int max = 0;
|
||||
@@ -318,10 +320,8 @@ int dlmstp_get_transmit_packet(
|
||||
max = Transmit_Client_SockFD;
|
||||
|
||||
if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0) {
|
||||
received_bytes = read(
|
||||
Transmit_Client_SockFD,
|
||||
packet,
|
||||
sizeof(DLMSTP_PACKET));
|
||||
received_bytes = read(Transmit_Client_SockFD,
|
||||
packet, sizeof(DLMSTP_PACKET));
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
@@ -347,10 +347,10 @@ int dlmstp_get_transmit_packet(
|
||||
/* for the MS/TP state machine to use for getting data to send */
|
||||
/* Return: amount of PDU data */
|
||||
uint16_t MSTP_Get_Send(
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
unsigned timeout) /* milliseconds to wait for a packet */
|
||||
{
|
||||
uint16_t pdu_len = 0; /* return value */
|
||||
volatile struct mstp_port_struct_t * mstp_port,
|
||||
unsigned timeout)
|
||||
{ /* milliseconds to wait for a packet */
|
||||
uint16_t pdu_len = 0; /* return value */
|
||||
int received_bytes = 0;
|
||||
DLMSTP_PACKET packet;
|
||||
uint8_t destination = 0; /* destination address */
|
||||
@@ -368,25 +368,21 @@ uint16_t MSTP_Get_Send(
|
||||
return 0;
|
||||
}
|
||||
/* convert the PDU into the MSTP Frame */
|
||||
pdu_len = MSTP_Create_Frame(
|
||||
&mstp_port->OutputBuffer[0], /* <-- loading this */
|
||||
pdu_len = MSTP_Create_Frame(&mstp_port->OutputBuffer[0], /* <-- loading this */
|
||||
mstp_port->OutputBufferSize,
|
||||
packet.frame_type,
|
||||
destination,
|
||||
mstp_port->This_Station,
|
||||
&packet.pdu[0],
|
||||
packet.pdu_len);
|
||||
destination, mstp_port->This_Station, &packet.pdu[0], packet.pdu_len);
|
||||
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
bool dlmstp_compare_data_expecting_reply(
|
||||
uint8_t *request_pdu,
|
||||
uint8_t * request_pdu,
|
||||
uint16_t request_pdu_len,
|
||||
uint8_t src_address,
|
||||
uint8_t *reply_pdu,
|
||||
uint8_t * reply_pdu,
|
||||
uint16_t reply_pdu_len,
|
||||
BACNET_ADDRESS *dest_address)
|
||||
BACNET_ADDRESS * dest_address)
|
||||
{
|
||||
uint16_t offset;
|
||||
/* One way to check the message is to compare NPDU
|
||||
@@ -414,12 +410,12 @@ bool dlmstp_compare_data_expecting_reply(
|
||||
if (request.pdu_type != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) {
|
||||
return false;
|
||||
}
|
||||
request.invoke_id = request_pdu[offset+2];
|
||||
request.invoke_id = request_pdu[offset + 2];
|
||||
/* segmented message? */
|
||||
if (request_pdu[offset] & BIT3)
|
||||
request.service_choice = request_pdu[offset+5];
|
||||
request.service_choice = request_pdu[offset + 5];
|
||||
else
|
||||
request.service_choice = request_pdu[offset+3];
|
||||
request.service_choice = request_pdu[offset + 3];
|
||||
/* decode the reply data */
|
||||
bacnet_address_copy(&reply.address, dest_address);
|
||||
offset = npdu_decode(&reply_pdu[0],
|
||||
@@ -432,32 +428,32 @@ bool dlmstp_compare_data_expecting_reply(
|
||||
reply.pdu_type = reply_pdu[offset] & 0xF0;
|
||||
switch (reply.pdu_type) {
|
||||
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
|
||||
reply.invoke_id = reply_pdu[offset+2];
|
||||
reply.invoke_id = reply_pdu[offset + 2];
|
||||
/* segmented message? */
|
||||
if (reply_pdu[offset] & BIT3)
|
||||
reply.service_choice = reply_pdu[offset+5];
|
||||
reply.service_choice = reply_pdu[offset + 5];
|
||||
else
|
||||
reply.service_choice = reply_pdu[offset+3];
|
||||
reply.service_choice = reply_pdu[offset + 3];
|
||||
break;
|
||||
case PDU_TYPE_SIMPLE_ACK:
|
||||
reply.invoke_id = reply_pdu[offset+1];
|
||||
reply.service_choice = reply_pdu[offset+2];
|
||||
reply.invoke_id = reply_pdu[offset + 1];
|
||||
reply.service_choice = reply_pdu[offset + 2];
|
||||
break;
|
||||
case PDU_TYPE_COMPLEX_ACK:
|
||||
reply.invoke_id = reply_pdu[offset+1];
|
||||
reply.invoke_id = reply_pdu[offset + 1];
|
||||
/* segmented message? */
|
||||
if (reply_pdu[offset] & BIT3)
|
||||
reply.service_choice = reply_pdu[offset+4];
|
||||
reply.service_choice = reply_pdu[offset + 4];
|
||||
else
|
||||
reply.service_choice = reply_pdu[offset+2];
|
||||
reply.service_choice = reply_pdu[offset + 2];
|
||||
break;
|
||||
case PDU_TYPE_ERROR:
|
||||
reply.invoke_id = reply_pdu[offset+1];
|
||||
reply.service_choice = reply_pdu[offset+2];
|
||||
reply.invoke_id = reply_pdu[offset + 1];
|
||||
reply.service_choice = reply_pdu[offset + 2];
|
||||
break;
|
||||
case PDU_TYPE_REJECT:
|
||||
case PDU_TYPE_ABORT:
|
||||
reply.invoke_id = reply_pdu[offset+1];
|
||||
reply.invoke_id = reply_pdu[offset + 1];
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
@@ -490,12 +486,12 @@ bool dlmstp_compare_data_expecting_reply(
|
||||
}
|
||||
|
||||
uint16_t MSTP_Get_Reply(
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
unsigned timeout) /* milliseconds to wait for a packet */
|
||||
{
|
||||
volatile struct mstp_port_struct_t * mstp_port,
|
||||
unsigned timeout)
|
||||
{ /* milliseconds to wait for a packet */
|
||||
int received_bytes = 0;
|
||||
DLMSTP_PACKET Transmit_Packet;
|
||||
uint16_t pdu_len = 0; /* return value */
|
||||
uint16_t pdu_len = 0; /* return value */
|
||||
uint8_t destination = 0; /* destination address */
|
||||
bool matched = false;
|
||||
|
||||
@@ -508,39 +504,36 @@ uint16_t MSTP_Get_Reply(
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
if ((MAX_HEADER + Transmit_Packet.pdu_len) > MAX_MPDU) {
|
||||
if ((MAX_HEADER + Transmit_Packet.pdu_len) > MAX_MPDU) {
|
||||
return 0;
|
||||
}
|
||||
/* is this the reply to the DER? */
|
||||
matched = dlmstp_compare_data_expecting_reply(
|
||||
&mstp_port->InputBuffer[0],
|
||||
matched = dlmstp_compare_data_expecting_reply(&mstp_port->InputBuffer[0],
|
||||
mstp_port->DataLength,
|
||||
mstp_port->SourceAddress,
|
||||
&Transmit_Packet.pdu[0],
|
||||
Transmit_Packet.pdu_len,
|
||||
&Transmit_Packet.address);
|
||||
Transmit_Packet.pdu_len, &Transmit_Packet.address);
|
||||
if (matched) {
|
||||
/* convert the PDU into the MSTP Frame */
|
||||
pdu_len = MSTP_Create_Frame(
|
||||
&mstp_port->OutputBuffer[0], /* <-- loading this */
|
||||
pdu_len = MSTP_Create_Frame(&mstp_port->OutputBuffer[0], /* <-- loading this */
|
||||
mstp_port->OutputBufferSize,
|
||||
Transmit_Packet.frame_type,
|
||||
destination,
|
||||
mstp_port->This_Station,
|
||||
&Transmit_Packet.pdu[0],
|
||||
Transmit_Packet.pdu_len);
|
||||
&Transmit_Packet.pdu[0], Transmit_Packet.pdu_len);
|
||||
/* not used here, but setting it anyway */
|
||||
Transmit_Packet.ready = false;
|
||||
} else {
|
||||
/* put it back into the queue */
|
||||
(void)write(Transmit_Server_SockFD,
|
||||
&Transmit_Packet, sizeof(Transmit_Packet));
|
||||
(void) write(Transmit_Server_SockFD,
|
||||
&Transmit_Packet, sizeof(Transmit_Packet));
|
||||
}
|
||||
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
void dlmstp_set_mac_address(uint8_t mac_address)
|
||||
void dlmstp_set_mac_address(
|
||||
uint8_t mac_address)
|
||||
{
|
||||
/* Master Nodes can only have address 0-127 */
|
||||
if (mac_address <= 127) {
|
||||
@@ -557,7 +550,8 @@ void dlmstp_set_mac_address(uint8_t mac_address)
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t dlmstp_my_address(void)
|
||||
uint8_t dlmstp_my_address(
|
||||
void)
|
||||
{
|
||||
return MSTP_Port.This_Station;
|
||||
}
|
||||
@@ -569,7 +563,8 @@ uint8_t dlmstp_my_address(void)
|
||||
/* nodes. This may be used to allocate more or less of the available link */
|
||||
/* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */
|
||||
/* node, its value shall be 1. */
|
||||
void dlmstp_set_max_info_frames(uint8_t max_info_frames)
|
||||
void dlmstp_set_max_info_frames(
|
||||
uint8_t max_info_frames)
|
||||
{
|
||||
if (max_info_frames >= 1) {
|
||||
MSTP_Port.Nmax_info_frames = max_info_frames;
|
||||
@@ -583,7 +578,8 @@ void dlmstp_set_max_info_frames(uint8_t max_info_frames)
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t dlmstp_max_info_frames(void)
|
||||
uint8_t dlmstp_max_info_frames(
|
||||
void)
|
||||
{
|
||||
return MSTP_Port.Nmax_info_frames;
|
||||
}
|
||||
@@ -593,7 +589,8 @@ uint8_t dlmstp_max_info_frames(void)
|
||||
/* allowable address for master nodes. The value of Max_Master shall be */
|
||||
/* less than or equal to 127. If Max_Master is not writable in a node, */
|
||||
/* its value shall be 127. */
|
||||
void dlmstp_set_max_master(uint8_t max_master)
|
||||
void dlmstp_set_max_master(
|
||||
uint8_t max_master)
|
||||
{
|
||||
if (max_master <= 127) {
|
||||
if (MSTP_Port.This_Station <= max_master) {
|
||||
@@ -609,14 +606,16 @@ void dlmstp_set_max_master(uint8_t max_master)
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t dlmstp_max_master(void)
|
||||
uint8_t dlmstp_max_master(
|
||||
void)
|
||||
{
|
||||
return MSTP_Port.Nmax_master;
|
||||
}
|
||||
|
||||
void dlmstp_get_my_address(BACNET_ADDRESS * my_address)
|
||||
void dlmstp_get_my_address(
|
||||
BACNET_ADDRESS * my_address)
|
||||
{
|
||||
int i = 0; /* counter */
|
||||
int i = 0; /* counter */
|
||||
|
||||
my_address->mac_len = 1;
|
||||
my_address->mac[0] = MSTP_Port.This_Station;
|
||||
@@ -629,15 +628,16 @@ void dlmstp_get_my_address(BACNET_ADDRESS * my_address)
|
||||
return;
|
||||
}
|
||||
|
||||
void dlmstp_get_broadcast_address(BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
void dlmstp_get_broadcast_address(
|
||||
BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
|
||||
if (dest) {
|
||||
dest->mac_len = 1;
|
||||
dest->mac[0] = MSTP_BROADCAST_ADDRESS;
|
||||
dest->net = BACNET_BROADCAST_NETWORK;
|
||||
dest->len = 0; /* always zero when DNET is broadcast */
|
||||
dest->len = 0; /* always zero when DNET is broadcast */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
dest->adr[i] = 0;
|
||||
}
|
||||
@@ -647,84 +647,90 @@ void dlmstp_get_broadcast_address(BACNET_ADDRESS * dest)
|
||||
}
|
||||
|
||||
/* RS485 Baud Rate 9600, 19200, 38400, 57600, 115200 */
|
||||
void dlmstp_set_baud_rate(uint32_t baud)
|
||||
void dlmstp_set_baud_rate(
|
||||
uint32_t baud)
|
||||
{
|
||||
RS485_Set_Baud_Rate(baud);
|
||||
}
|
||||
|
||||
uint32_t dlmstp_baud_rate(void)
|
||||
uint32_t dlmstp_baud_rate(
|
||||
void)
|
||||
{
|
||||
return RS485_Get_Baud_Rate();
|
||||
return RS485_Get_Baud_Rate();
|
||||
}
|
||||
|
||||
static int create_named_server_socket (const char *filename)
|
||||
static int create_named_server_socket(
|
||||
const char *filename)
|
||||
{
|
||||
struct sockaddr_un name;
|
||||
int sock;
|
||||
size_t size;
|
||||
|
||||
/* Create the socket. */
|
||||
sock = socket (PF_LOCAL, SOCK_DGRAM, 0);
|
||||
sock = socket(PF_LOCAL, SOCK_DGRAM, 0);
|
||||
if (sock < 0) {
|
||||
#if PRINT_ENABLED
|
||||
perror ("socket");
|
||||
perror("socket");
|
||||
#endif
|
||||
exit (EXIT_FAILURE);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sock, sizeof(sock));
|
||||
/* Bind a name to the socket. */
|
||||
name.sun_family = AF_LOCAL;
|
||||
strncpy (name.sun_path, filename, sizeof (name.sun_path));
|
||||
strncpy(name.sun_path, filename, sizeof(name.sun_path));
|
||||
/* The size of the address is
|
||||
the offset of the start of the filename,
|
||||
plus its length,
|
||||
plus one for the terminating null byte.
|
||||
Alternatively you can just do:
|
||||
size = SUN_LEN (&name);
|
||||
*/
|
||||
size = (offsetof (struct sockaddr_un, sun_path)
|
||||
+ strlen (name.sun_path) + 1);
|
||||
if (bind (sock, (struct sockaddr *) &name, size) < 0) {
|
||||
the offset of the start of the filename,
|
||||
plus its length,
|
||||
plus one for the terminating null byte.
|
||||
Alternatively you can just do:
|
||||
size = SUN_LEN (&name);
|
||||
*/
|
||||
size = (offsetof(struct sockaddr_un,
|
||||
sun_path)
|
||||
+ strlen (name.sun_path) + 1);
|
||||
if (bind(sock, (struct sockaddr *) &name, size) < 0) {
|
||||
#if PRINT_ENABLED
|
||||
perror ("bind");
|
||||
perror("bind");
|
||||
#endif
|
||||
exit (EXIT_FAILURE);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
/* used by the client */
|
||||
static int connect_named_server_socket (const char *filename)
|
||||
static int connect_named_server_socket(
|
||||
const char *filename)
|
||||
{
|
||||
struct sockaddr_un name;
|
||||
int sock;
|
||||
size_t size;
|
||||
|
||||
/* Create the socket. */
|
||||
sock = socket (PF_LOCAL, SOCK_DGRAM, 0);
|
||||
sock = socket(PF_LOCAL, SOCK_DGRAM, 0);
|
||||
if (sock < 0) {
|
||||
#if PRINT_ENABLED
|
||||
perror ("socket");
|
||||
perror("socket");
|
||||
#endif
|
||||
exit (EXIT_FAILURE);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
strncpy (name.sun_path, filename, sizeof (name.sun_path));
|
||||
strncpy(name.sun_path, filename, sizeof(name.sun_path));
|
||||
/* The size of the address is
|
||||
the offset of the start of the filename,
|
||||
plus its length,
|
||||
plus one for the terminating null byte.
|
||||
Alternatively you can just do:
|
||||
size = SUN_LEN (&name);
|
||||
*/
|
||||
size = (offsetof (struct sockaddr_un, sun_path)
|
||||
+ strlen (name.sun_path) + 1);
|
||||
the offset of the start of the filename,
|
||||
plus its length,
|
||||
plus one for the terminating null byte.
|
||||
Alternatively you can just do:
|
||||
size = SUN_LEN (&name);
|
||||
*/
|
||||
size = (offsetof(struct sockaddr_un,
|
||||
sun_path)
|
||||
+ strlen (name.sun_path) + 1);
|
||||
|
||||
if (connect(sock, (struct sockaddr *) &name, size) < 0) {
|
||||
#if PRINT_ENABLED
|
||||
perror ("client: can't connect to socket");
|
||||
perror("client: can't connect to socket");
|
||||
#endif
|
||||
exit (EXIT_FAILURE);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return sock;
|
||||
@@ -733,7 +739,8 @@ static int connect_named_server_socket (const char *filename)
|
||||
static char *dlmstp_transmit_socket_name = "/tmp/BACnet_MSTP_Tx";
|
||||
static char *dlmstp_receive_socket_name = "/tmp/BACnet_MSTP_Rx";
|
||||
|
||||
void dlmstp_cleanup(void)
|
||||
void dlmstp_cleanup(
|
||||
void)
|
||||
{
|
||||
remove(dlmstp_transmit_socket_name);
|
||||
remove(dlmstp_receive_socket_name);
|
||||
@@ -741,7 +748,8 @@ void dlmstp_cleanup(void)
|
||||
/* nothing to do for static buffers */
|
||||
}
|
||||
|
||||
bool dlmstp_init(char *ifname)
|
||||
bool dlmstp_init(
|
||||
char *ifname)
|
||||
{
|
||||
int rc = 0;
|
||||
pthread_t hThread;
|
||||
@@ -763,7 +771,7 @@ bool dlmstp_init(char *ifname)
|
||||
if (ifname) {
|
||||
RS485_Set_Interface(ifname);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,"MS/TP Interface: %s\n", ifname);
|
||||
fprintf(stderr, "MS/TP Interface: %s\n", ifname);
|
||||
#endif
|
||||
}
|
||||
RS485_Initialize();
|
||||
@@ -790,12 +798,9 @@ bool dlmstp_init(char *ifname)
|
||||
dlmstp_set_max_info_frames(DEFAULT_MAX_INFO_FRAMES);
|
||||
#endif
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,"MS/TP MAC: %02X\n",
|
||||
MSTP_Port.This_Station);
|
||||
fprintf(stderr,"MS/TP Max_Master: %02X\n",
|
||||
MSTP_Port.Nmax_master);
|
||||
fprintf(stderr,"MS/TP Max_Info_Frames: %u\n",
|
||||
MSTP_Port.Nmax_info_frames);
|
||||
fprintf(stderr, "MS/TP MAC: %02X\n", MSTP_Port.This_Station);
|
||||
fprintf(stderr, "MS/TP Max_Master: %02X\n", MSTP_Port.Nmax_master);
|
||||
fprintf(stderr, "MS/TP Max_Info_Frames: %u\n", MSTP_Port.Nmax_info_frames);
|
||||
#endif
|
||||
|
||||
/* start our MilliSec task */
|
||||
@@ -812,16 +817,18 @@ bool dlmstp_init(char *ifname)
|
||||
|
||||
static char *Network_Interface = NULL;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
int main(
|
||||
int argc,
|
||||
char *argv[])
|
||||
{
|
||||
uint16_t bytes_received = 0;
|
||||
BACNET_ADDRESS src; /* source address */
|
||||
uint8_t pdu[MAX_APDU]; /* PDU data */
|
||||
uint8_t pdu[MAX_APDU]; /* PDU data */
|
||||
#if (defined(MSTP_TEST_REQUEST) && MSTP_TEST_REQUEST)
|
||||
struct timespec timeOut, remains;
|
||||
|
||||
timeOut.tv_sec = 1;
|
||||
timeOut.tv_nsec = 0; /* 1 millisecond */
|
||||
timeOut.tv_nsec = 0; /* 1 millisecond */
|
||||
#endif
|
||||
/* argv has the "/dev/ttyS0" or some other device */
|
||||
if (argc > 1) {
|
||||
@@ -835,18 +842,14 @@ int main(int argc, char *argv[])
|
||||
/* forever task */
|
||||
for (;;) {
|
||||
#if (defined(MSTP_TEST_REQUEST) && MSTP_TEST_REQUEST)
|
||||
MSTP_Create_And_Send_Frame(
|
||||
&MSTP_Port,
|
||||
MSTP_Create_And_Send_Frame(&MSTP_Port,
|
||||
FRAME_TYPE_TEST_REQUEST,
|
||||
MSTP_Port.SourceAddress,
|
||||
MSTP_Port.This_Station,
|
||||
NULL, 0);
|
||||
MSTP_Port.SourceAddress, MSTP_Port.This_Station, NULL, 0);
|
||||
nanosleep(&timeOut, &remains);
|
||||
#endif
|
||||
bytes_received =
|
||||
dlmstp_receive(&src, &pdu[0], sizeof(pdu), 10000);
|
||||
bytes_received = dlmstp_receive(&src, &pdu[0], sizeof(pdu), 10000);
|
||||
if (bytes_received) {
|
||||
fprintf(stderr,"Received NPDU!\n");
|
||||
fprintf(stderr, "Received NPDU!\n");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
|
||||
#include "net.h"
|
||||
#include "bacdef.h"
|
||||
@@ -52,12 +52,14 @@ uint8_t Ethernet_MAC_Address[MAX_MAC_LEN] = { 0 };
|
||||
static int eth802_sockfd = -1; /* 802.2 file handle */
|
||||
static struct sockaddr eth_addr = { 0 }; /* used for binding 802.2 */
|
||||
|
||||
bool ethernet_valid(void)
|
||||
bool ethernet_valid(
|
||||
void)
|
||||
{
|
||||
return (eth802_sockfd >= 0);
|
||||
}
|
||||
|
||||
void ethernet_cleanup(void)
|
||||
void ethernet_cleanup(
|
||||
void)
|
||||
{
|
||||
if (ethernet_valid())
|
||||
close(eth802_sockfd);
|
||||
@@ -75,7 +77,8 @@ void ethernet_cleanup(void)
|
||||
to EAGAIN (or EWOULDBLOCK).
|
||||
Thanks to Bjorn Reese for this code.
|
||||
----------------------------------------------------------------------*/
|
||||
int setNonblocking(int fd)
|
||||
int setNonblocking(
|
||||
int fd)
|
||||
{
|
||||
int flags;
|
||||
|
||||
@@ -85,9 +88,11 @@ int setNonblocking(int fd)
|
||||
}
|
||||
|
||||
/* opens an 802.2 socket to receive and send packets */
|
||||
static int ethernet_bind(struct sockaddr *eth_addr, char *interface_name)
|
||||
static int ethernet_bind(
|
||||
struct sockaddr *eth_addr,
|
||||
char *interface_name)
|
||||
{
|
||||
int sock_fd = -1; /* return value */
|
||||
int sock_fd = -1; /* return value */
|
||||
int uid = 0;
|
||||
|
||||
fprintf(stderr, "ethernet: opening \"%s\"\n", interface_name);
|
||||
@@ -122,15 +127,13 @@ static int ethernet_bind(struct sockaddr *eth_addr, char *interface_name)
|
||||
/* Clear the memory before copying */
|
||||
memset(eth_addr->sa_data, '\0', sizeof(eth_addr->sa_data));
|
||||
/* Strcpy the interface name into the address */
|
||||
strncpy(eth_addr->sa_data, interface_name,
|
||||
sizeof(eth_addr->sa_data) - 1);
|
||||
strncpy(eth_addr->sa_data, interface_name, sizeof(eth_addr->sa_data) - 1);
|
||||
fprintf(stderr, "ethernet: binding \"%s\"\n", eth_addr->sa_data);
|
||||
/* Attempt to bind the socket to the interface */
|
||||
if (bind(sock_fd, eth_addr, sizeof(struct sockaddr)) != 0) {
|
||||
/* Bind problem, close socket and return */
|
||||
fprintf(stderr,
|
||||
"ethernet: Unable to bind 802.2 socket : %s\n",
|
||||
strerror(errno));
|
||||
"ethernet: Unable to bind 802.2 socket : %s\n", strerror(errno));
|
||||
fprintf(stderr,
|
||||
"You might need to add the following to modules.conf\n"
|
||||
"(or in /etc/modutils/alias on Debian with update-modules):\n"
|
||||
@@ -148,11 +151,13 @@ static int ethernet_bind(struct sockaddr *eth_addr, char *interface_name)
|
||||
}
|
||||
|
||||
/* function to find the local ethernet MAC address */
|
||||
static int get_local_hwaddr(const char *ifname, unsigned char *mac)
|
||||
static int get_local_hwaddr(
|
||||
const char *ifname,
|
||||
unsigned char *mac)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
int fd;
|
||||
int rv; /* return value - error value from df or ioctl call */
|
||||
int rv; /* return value - error value from df or ioctl call */
|
||||
|
||||
/* determine the local MAC address */
|
||||
strcpy(ifr.ifr_name, ifname);
|
||||
@@ -161,14 +166,15 @@ static int get_local_hwaddr(const char *ifname, unsigned char *mac)
|
||||
rv = fd;
|
||||
else {
|
||||
rv = ioctl(fd, SIOCGIFHWADDR, &ifr);
|
||||
if (rv >= 0) /* worked okay */
|
||||
if (rv >= 0) /* worked okay */
|
||||
memcpy(mac, ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool ethernet_init(char *interface_name)
|
||||
bool ethernet_init(
|
||||
char *interface_name)
|
||||
{
|
||||
if (interface_name) {
|
||||
get_local_hwaddr(interface_name, Ethernet_MAC_Address);
|
||||
@@ -183,12 +189,13 @@ bool ethernet_init(char *interface_name)
|
||||
|
||||
/* function to send a packet out the 802.2 socket */
|
||||
/* returns number of bytes sent on success, negative on failure */
|
||||
int ethernet_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
int ethernet_send_pdu(
|
||||
BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len)
|
||||
{ /* number of bytes of data */
|
||||
int i = 0; /* counter */
|
||||
{ /* number of bytes of data */
|
||||
int i = 0; /* counter */
|
||||
int bytes = 0;
|
||||
BACNET_ADDRESS src = { 0 }; /* source address for npdu */
|
||||
uint8_t mtu[MAX_MPDU] = { 0 }; /* our buffer */
|
||||
@@ -226,9 +233,9 @@ int ethernet_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
return -3;
|
||||
}
|
||||
/* Logical PDU portion */
|
||||
mtu[14] = 0x82; /* DSAP for BACnet */
|
||||
mtu[15] = 0x82; /* SSAP for BACnet */
|
||||
mtu[16] = 0x03; /* Control byte in header */
|
||||
mtu[14] = 0x82; /* DSAP for BACnet */
|
||||
mtu[15] = 0x82; /* SSAP for BACnet */
|
||||
mtu[16] = 0x03; /* Control byte in header */
|
||||
mtu_len = 17;
|
||||
if ((mtu_len + pdu_len) > MAX_MPDU) {
|
||||
fprintf(stderr, "ethernet: PDU is too big to send!\n");
|
||||
@@ -253,11 +260,12 @@ int ethernet_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
|
||||
/* 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 */
|
||||
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 */
|
||||
{ /* 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 */
|
||||
@@ -334,7 +342,8 @@ uint16_t ethernet_receive(BACNET_ADDRESS * src, /* source address */
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
void ethernet_set_my_address(BACNET_ADDRESS * my_address)
|
||||
void ethernet_set_my_address(
|
||||
BACNET_ADDRESS * my_address)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
@@ -345,7 +354,8 @@ void ethernet_set_my_address(BACNET_ADDRESS * my_address)
|
||||
return;
|
||||
}
|
||||
|
||||
void ethernet_get_my_address(BACNET_ADDRESS * my_address)
|
||||
void ethernet_get_my_address(
|
||||
BACNET_ADDRESS * my_address)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
@@ -363,9 +373,10 @@ void ethernet_get_my_address(BACNET_ADDRESS * my_address)
|
||||
return;
|
||||
}
|
||||
|
||||
void ethernet_get_broadcast_address(BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
void ethernet_get_broadcast_address(
|
||||
BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
|
||||
if (dest) {
|
||||
for (i = 0; i < 6; i++) {
|
||||
@@ -373,7 +384,7 @@ void ethernet_get_broadcast_address(BACNET_ADDRESS * dest)
|
||||
}
|
||||
dest->mac_len = 6;
|
||||
dest->net = BACNET_BROADCAST_NETWORK;
|
||||
dest->len = 0; /* always zero when DNET is broadcast */
|
||||
dest->len = 0; /* always zero when DNET is broadcast */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
dest->adr[i] = 0;
|
||||
}
|
||||
@@ -382,9 +393,11 @@ void ethernet_get_broadcast_address(BACNET_ADDRESS * dest)
|
||||
return;
|
||||
}
|
||||
|
||||
void ethernet_debug_address(const char *info, BACNET_ADDRESS * dest)
|
||||
void ethernet_debug_address(
|
||||
const char *info,
|
||||
BACNET_ADDRESS * dest)
|
||||
{
|
||||
int i = 0; /* counter */
|
||||
int i = 0; /* counter */
|
||||
|
||||
if (info)
|
||||
fprintf(stderr, "%s", info);
|
||||
|
||||
@@ -50,8 +50,10 @@ bool Who_Is_Request = true;
|
||||
/* buffers used for receiving */
|
||||
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||
|
||||
static void LocalIAmHandler(uint8_t * service_request,
|
||||
uint16_t service_len, BACNET_ADDRESS * src)
|
||||
static void LocalIAmHandler(
|
||||
uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src)
|
||||
{
|
||||
int len = 0;
|
||||
uint32_t device_id = 0;
|
||||
@@ -73,7 +75,8 @@ static void LocalIAmHandler(uint8_t * service_request,
|
||||
return;
|
||||
}
|
||||
|
||||
static void Read_Properties(void)
|
||||
static void Read_Properties(
|
||||
void)
|
||||
{
|
||||
uint32_t device_id = 0;
|
||||
bool status = false;
|
||||
@@ -154,13 +157,12 @@ static void Read_Properties(void)
|
||||
return;
|
||||
}
|
||||
|
||||
static void Init_Service_Handlers(void)
|
||||
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,
|
||||
handler_who_is);
|
||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_I_AM,
|
||||
LocalIAmHandler);
|
||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_I_AM, LocalIAmHandler);
|
||||
|
||||
/* set the handler for all the services we don't implement */
|
||||
/* It is required to send the proper reject message... */
|
||||
@@ -181,7 +183,8 @@ static void Init_Service_Handlers(void)
|
||||
handler_atomic_read_file_ack);
|
||||
}
|
||||
|
||||
static void print_address_cache(void)
|
||||
static void print_address_cache(
|
||||
void)
|
||||
{
|
||||
unsigned i, j;
|
||||
BACNET_ADDRESS address;
|
||||
@@ -202,7 +205,8 @@ static void print_address_cache(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void print_tsm_stats(void)
|
||||
static void print_tsm_stats(
|
||||
void)
|
||||
{
|
||||
int idle = 0;
|
||||
int total = 0;
|
||||
@@ -212,7 +216,8 @@ static void print_tsm_stats(void)
|
||||
fprintf(stderr, "TSM: %d idle of %d transactions\n", idle, total);
|
||||
}
|
||||
|
||||
static void sig_handler(int signo)
|
||||
static void sig_handler(
|
||||
int signo)
|
||||
{
|
||||
datalink_cleanup();
|
||||
print_address_cache();
|
||||
@@ -221,12 +226,14 @@ static void sig_handler(int signo)
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
int main(
|
||||
int argc,
|
||||
char *argv[])
|
||||
{
|
||||
BACNET_ADDRESS src = { 0 }; /* address where message came from */
|
||||
uint16_t pdu_len = 0;
|
||||
unsigned timeout = 100; /* milliseconds */
|
||||
unsigned count = 0; /* milliseconds */
|
||||
unsigned count = 0; /* milliseconds */
|
||||
time_t start_time;
|
||||
time_t new_time = 0;
|
||||
|
||||
@@ -280,15 +287,15 @@ int main(int argc, char *argv[])
|
||||
/* some round robin task switching */
|
||||
count++;
|
||||
switch (count) {
|
||||
case 1:
|
||||
/* used for testing, but kind of noisy on the network */
|
||||
/*Read_Properties(); */
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
default:
|
||||
count = 0;
|
||||
break;
|
||||
case 1:
|
||||
/* used for testing, but kind of noisy on the network */
|
||||
/*Read_Properties(); */
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
default:
|
||||
count = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* blink LEDs, Turn on or off outputs, etc */
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
#include <net/route.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <features.h> /* for the glibc version number */
|
||||
#include <features.h> /* for the glibc version number */
|
||||
#if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1
|
||||
#include <netpacket/packet.h>
|
||||
#include <net/ethernet.h> /* the L2 protocols */
|
||||
|
||||
@@ -76,7 +76,8 @@ static struct termios RS485_oldtio;
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*********************************************************************/
|
||||
void RS485_Set_Interface(char *ifname)
|
||||
void RS485_Set_Interface(
|
||||
char *ifname)
|
||||
{
|
||||
/* note: expects a constant char, or char from the heap */
|
||||
RS485_Port_Name = ifname;
|
||||
@@ -88,15 +89,21 @@ void RS485_Set_Interface(char *ifname)
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
uint32_t RS485_Get_Baud_Rate(void)
|
||||
uint32_t RS485_Get_Baud_Rate(
|
||||
void)
|
||||
{
|
||||
switch (RS485_Baud) {
|
||||
case B19200: return 19200;
|
||||
case B38400: return 38400;
|
||||
case B57600: return 57600;
|
||||
case B115200: return 115200;
|
||||
case B19200:
|
||||
return 19200;
|
||||
case B38400:
|
||||
return 38400;
|
||||
case B57600:
|
||||
return 57600;
|
||||
case B115200:
|
||||
return 115200;
|
||||
default:
|
||||
case B9600: return 9600;
|
||||
case B9600:
|
||||
return 9600;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +113,8 @@ uint32_t RS485_Get_Baud_Rate(void)
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
bool RS485_Set_Baud_Rate(uint32_t baud)
|
||||
bool RS485_Set_Baud_Rate(
|
||||
uint32_t baud)
|
||||
{
|
||||
bool valid = true;
|
||||
|
||||
@@ -140,10 +148,10 @@ bool RS485_Set_Baud_Rate(uint32_t baud)
|
||||
|
||||
/* Transmits a Frame on the wire */
|
||||
void RS485_Send_Frame(
|
||||
struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
||||
uint16_t nbytes) /* number of bytes of data (up to 501) */
|
||||
{
|
||||
struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
||||
uint16_t nbytes)
|
||||
{ /* number of bytes of data (up to 501) */
|
||||
uint8_t turnaround_time;
|
||||
uint32_t baud;
|
||||
ssize_t written = 0;
|
||||
@@ -163,12 +171,12 @@ void RS485_Send_Frame(
|
||||
};
|
||||
}
|
||||
/*
|
||||
On success, the number of bytes written are returned (zero indicates
|
||||
nothing was written). On error, -1 is returned, and errno is set
|
||||
appropriately. If count is zero and the file descriptor refers to a
|
||||
regular file, 0 will be returned without causing any other effect. For
|
||||
a special file, the results are not portable.
|
||||
*/
|
||||
On success, the number of bytes written are returned (zero indicates
|
||||
nothing was written). On error, -1 is returned, and errno is set
|
||||
appropriately. If count is zero and the file descriptor refers to a
|
||||
regular file, 0 will be returned without causing any other effect. For
|
||||
a special file, the results are not portable.
|
||||
*/
|
||||
written = write(RS485_Handle, buffer, nbytes);
|
||||
|
||||
/* per MSTP spec, sort of */
|
||||
@@ -180,18 +188,19 @@ void RS485_Send_Frame(
|
||||
}
|
||||
|
||||
/* called by timer, interrupt(?) or other thread */
|
||||
void RS485_Check_UART_Data(struct mstp_port_struct_t *mstp_port)
|
||||
void RS485_Check_UART_Data(
|
||||
struct mstp_port_struct_t *mstp_port)
|
||||
{
|
||||
uint8_t buf[1];
|
||||
int count;
|
||||
|
||||
|
||||
if (mstp_port->ReceiveError == true) {
|
||||
/* wait for state machine to clear this */
|
||||
}
|
||||
/* wait for state machine to read from the DataRegister */
|
||||
else if (mstp_port->DataAvailable == false) {
|
||||
/* check for data */
|
||||
count = read(RS485_Handle,buf,sizeof(buf));
|
||||
count = read(RS485_Handle, buf, sizeof(buf));
|
||||
/* if error, */
|
||||
/* ReceiveError = TRUE; */
|
||||
/* return; */
|
||||
@@ -203,23 +212,24 @@ void RS485_Check_UART_Data(struct mstp_port_struct_t *mstp_port)
|
||||
}
|
||||
}
|
||||
|
||||
void RS485_Cleanup(void)
|
||||
void RS485_Cleanup(
|
||||
void)
|
||||
{
|
||||
/* restore the old port settings */
|
||||
tcsetattr(RS485_Handle,TCSANOW,&RS485_oldtio);
|
||||
tcsetattr(RS485_Handle, TCSANOW, &RS485_oldtio);
|
||||
close(RS485_Handle);
|
||||
}
|
||||
|
||||
|
||||
void RS485_Initialize(void)
|
||||
void RS485_Initialize(
|
||||
void)
|
||||
{
|
||||
struct termios newtio;
|
||||
|
||||
/*
|
||||
Open device for reading and writing.
|
||||
*/
|
||||
RS485_Handle = open(RS485_Port_Name,
|
||||
O_RDWR | O_NOCTTY | O_NDELAY );
|
||||
Open device for reading and writing.
|
||||
*/
|
||||
RS485_Handle = open(RS485_Port_Name, O_RDWR | O_NOCTTY | O_NDELAY);
|
||||
if (RS485_Handle < 0) {
|
||||
perror(RS485_Port_Name);
|
||||
exit(-1);
|
||||
@@ -232,17 +242,17 @@ void RS485_Initialize(void)
|
||||
fcntl(RS485_Handle, F_SETFL, 0);
|
||||
#endif
|
||||
/* save current serial port settings */
|
||||
tcgetattr(RS485_Handle,&RS485_oldtio);
|
||||
tcgetattr(RS485_Handle, &RS485_oldtio);
|
||||
/* clear struct for new port settings */
|
||||
bzero(&newtio, sizeof(newtio));
|
||||
/*
|
||||
BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed.
|
||||
CRTSCTS : output hardware flow control (only used if the cable has
|
||||
all necessary lines. See sect. 7 of Serial-HOWTO)
|
||||
CS8 : 8n1 (8bit,no parity,1 stopbit)
|
||||
CLOCAL : local connection, no modem contol
|
||||
CREAD : enable receiving characters
|
||||
*/
|
||||
BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed.
|
||||
CRTSCTS : output hardware flow control (only used if the cable has
|
||||
all necessary lines. See sect. 7 of Serial-HOWTO)
|
||||
CS8 : 8n1 (8bit,no parity,1 stopbit)
|
||||
CLOCAL : local connection, no modem contol
|
||||
CREAD : enable receiving characters
|
||||
*/
|
||||
newtio.c_cflag = RS485_Baud | CS8 | CLOCAL | CREAD;
|
||||
/* Raw input */
|
||||
newtio.c_iflag = 0;
|
||||
@@ -251,18 +261,20 @@ void RS485_Initialize(void)
|
||||
/* no processing */
|
||||
newtio.c_lflag = 0;
|
||||
/* activate the settings for the port after flushing I/O */
|
||||
tcsetattr(RS485_Handle,TCSAFLUSH,&newtio);
|
||||
tcsetattr(RS485_Handle, TCSAFLUSH, &newtio);
|
||||
/* destructor */
|
||||
atexit(RS485_Cleanup);
|
||||
}
|
||||
|
||||
#ifdef TEST_RS485
|
||||
#include <string.h>
|
||||
int main(int argc, char *argv[])
|
||||
int main(
|
||||
int argc,
|
||||
char *argv[])
|
||||
{
|
||||
uint8_t buf[8];
|
||||
char *wbuf = {"BACnet!"};
|
||||
size_t wlen = strlen(wbuf)+1;
|
||||
char *wbuf = { "BACnet!" };
|
||||
size_t wlen = strlen(wbuf) + 1;
|
||||
unsigned i = 0;
|
||||
size_t written = 0;
|
||||
int rlen;
|
||||
@@ -276,11 +288,11 @@ int main(int argc, char *argv[])
|
||||
|
||||
for (;;) {
|
||||
written = write(RS485_Handle, wbuf, wlen);
|
||||
rlen = read(RS485_Handle,buf,sizeof(buf));
|
||||
rlen = read(RS485_Handle, buf, sizeof(buf));
|
||||
/* print any characters received */
|
||||
if (rlen > 0) {
|
||||
for (i = 0; i < rlen; i++) {
|
||||
fprintf(stderr,"%02X ",buf[i]);
|
||||
fprintf(stderr, "%02X ", buf[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,23 +41,29 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void RS485_Set_Interface(char *ifname);
|
||||
void RS485_Set_Interface(
|
||||
char *ifname);
|
||||
|
||||
void RS485_Initialize(void);
|
||||
void RS485_Initialize(
|
||||
void);
|
||||
|
||||
void RS485_Send_Frame(volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||
void RS485_Send_Frame(
|
||||
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
||||
uint16_t nbytes); /* number of bytes of data (up to 501) */
|
||||
|
||||
void RS485_Check_UART_Data(
|
||||
volatile struct mstp_port_struct_t *mstp_port); /* port specific data */
|
||||
uint32_t RS485_Get_Baud_Rate(void);
|
||||
bool RS485_Set_Baud_Rate(uint32_t baud);
|
||||
void RS485_Cleanup(void);
|
||||
uint32_t RS485_Get_Baud_Rate(
|
||||
void);
|
||||
bool RS485_Set_Baud_Rate(
|
||||
uint32_t baud);
|
||||
void RS485_Cleanup(
|
||||
void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -58,23 +58,27 @@ static uint8_t RxBuffer[MAX_MPDU];
|
||||
static uint8_t TxBuffer[MAX_MPDU];
|
||||
static uint16_t SilenceTime;
|
||||
#define INCREMENT_AND_LIMIT_UINT16(x) {if (x < 0xFFFF) x++;}
|
||||
static uint16_t Timer_Silence(void)
|
||||
static uint16_t Timer_Silence(
|
||||
void)
|
||||
{
|
||||
return SilenceTime;
|
||||
}
|
||||
static void Timer_Silence_Reset(void)
|
||||
static void Timer_Silence_Reset(
|
||||
void)
|
||||
{
|
||||
SilenceTime = 0;
|
||||
}
|
||||
|
||||
static void dlmstp_millisecond_timer(void)
|
||||
static void dlmstp_millisecond_timer(
|
||||
void)
|
||||
{
|
||||
INCREMENT_AND_LIMIT_UINT16(SilenceTime);
|
||||
}
|
||||
|
||||
void *milliseconds_task(void *pArg)
|
||||
|
||||
void *milliseconds_task(
|
||||
void *pArg)
|
||||
{
|
||||
struct timespec timeOut,remains;
|
||||
struct timespec timeOut, remains;
|
||||
|
||||
timeOut.tv_sec = 0;
|
||||
timeOut.tv_nsec = 10000000; /* 1 milliseconds */
|
||||
@@ -89,35 +93,36 @@ void *milliseconds_task(void *pArg)
|
||||
|
||||
/* functions used by the MS/TP state machine to put or get data */
|
||||
uint16_t MSTP_Put_Receive(
|
||||
volatile struct mstp_port_struct_t *mstp_port)
|
||||
volatile struct mstp_port_struct_t * mstp_port)
|
||||
{
|
||||
(void)mstp_port;
|
||||
|
||||
(void) mstp_port;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* for the MS/TP state machine to use for getting data to send */
|
||||
/* Return: amount of PDU data */
|
||||
uint16_t MSTP_Get_Send(
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
unsigned timeout) /* milliseconds to wait for a packet */
|
||||
{
|
||||
(void)mstp_port;
|
||||
(void)timeout;
|
||||
volatile struct mstp_port_struct_t * mstp_port,
|
||||
unsigned timeout)
|
||||
{ /* milliseconds to wait for a packet */
|
||||
(void) mstp_port;
|
||||
(void) timeout;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t MSTP_Get_Reply(
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
unsigned timeout) /* milliseconds to wait for a packet */
|
||||
{
|
||||
(void)mstp_port;
|
||||
(void)timeout;
|
||||
volatile struct mstp_port_struct_t * mstp_port,
|
||||
unsigned timeout)
|
||||
{ /* milliseconds to wait for a packet */
|
||||
(void) mstp_port;
|
||||
(void) timeout;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* returns a delta timestamp */
|
||||
int timestamp_ms(void)
|
||||
int timestamp_ms(
|
||||
void)
|
||||
{
|
||||
struct timeval tv;
|
||||
int delta_ticks = 0;
|
||||
@@ -125,7 +130,7 @@ int timestamp_ms(void)
|
||||
static long last_ticks = 0;
|
||||
int rv = 0;
|
||||
|
||||
rv = gettimeofday(&tv,NULL);
|
||||
rv = gettimeofday(&tv, NULL);
|
||||
if (rv == -1)
|
||||
ticks = 0;
|
||||
else
|
||||
@@ -144,7 +149,7 @@ static void print_received_packet(
|
||||
int timestamp = 0;
|
||||
|
||||
timestamp = timestamp_ms();
|
||||
fprintf(stderr,"%03d ",timestamp);
|
||||
fprintf(stderr, "%03d ", timestamp);
|
||||
/* Preamble: two octet preamble: X`55', X`FF' */
|
||||
/* Frame Type: one octet */
|
||||
/* Destination Address: one octet address */
|
||||
@@ -161,25 +166,23 @@ static void print_received_packet(
|
||||
mstp_port->DestinationAddress,
|
||||
mstp_port->SourceAddress,
|
||||
HI_BYTE(mstp_port->DataLength),
|
||||
LO_BYTE(mstp_port->DataLength),
|
||||
mstp_port->HeaderCRCActual);
|
||||
LO_BYTE(mstp_port->DataLength), mstp_port->HeaderCRCActual);
|
||||
if (mstp_port->DataLength) {
|
||||
for (i = 0; i < mstp_port->DataLength; i++) {
|
||||
fprintf(stderr,"%02X ",
|
||||
mstp_port->InputBuffer[i]);
|
||||
fprintf(stderr, "%02X ", mstp_port->InputBuffer[i]);
|
||||
}
|
||||
fprintf(stderr,
|
||||
"%02X %02X ",
|
||||
mstp_port->DataCRCActualMSB,
|
||||
mstp_port->DataCRCActualLSB);
|
||||
"%02X %02X ",
|
||||
mstp_port->DataCRCActualMSB, mstp_port->DataCRCActualLSB);
|
||||
}
|
||||
fprintf(stderr,"%s",
|
||||
mstptext_frame_type(mstp_port->FrameType));
|
||||
fprintf(stderr,"\n");
|
||||
fprintf(stderr, "%s", mstptext_frame_type(mstp_port->FrameType));
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
/* simple test to packetize the data and print it */
|
||||
int main(int argc, char *argv[])
|
||||
int main(
|
||||
int argc,
|
||||
char *argv[])
|
||||
{
|
||||
volatile struct mstp_port_struct_t *mstp_port;
|
||||
int rc = 0;
|
||||
@@ -195,7 +198,7 @@ int main(int argc, char *argv[])
|
||||
if (argc > 2) {
|
||||
my_mac = strtol(argv[2], NULL, 0);
|
||||
if (my_mac > 127)
|
||||
my_mac = 127;
|
||||
my_mac = 127;
|
||||
}
|
||||
RS485_Set_Baud_Rate(38400);
|
||||
RS485_Initialize();
|
||||
@@ -229,4 +232,3 @@ int main(int argc, char *argv[])
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,8 @@ static uint8_t Present_Value[MAX_ANALOG_INPUTS];
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Analog_Input_Valid_Instance(uint32_t object_instance)
|
||||
bool Analog_Input_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ANALOG_INPUTS)
|
||||
return true;
|
||||
@@ -50,18 +51,21 @@ bool Analog_Input_Valid_Instance(uint32_t object_instance)
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Analog_Input_Count(void)
|
||||
unsigned Analog_Input_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_ANALOG_INPUTS;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
uint32_t Analog_Input_Index_To_Instance(unsigned index)
|
||||
uint32_t Analog_Input_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
char *Analog_Input_Name(uint32_t object_instance)
|
||||
char *Analog_Input_Name(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
static char text_string[16] = ""; /* okay for single thread */
|
||||
|
||||
@@ -73,72 +77,78 @@ char *Analog_Input_Name(uint32_t object_instance)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static float Analog_Input_Present_Value(uint32_t object_instance)
|
||||
static float Analog_Input_Present_Value(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
float value = 0.0;
|
||||
|
||||
if (object_instance < MAX_ANALOG_INPUTS)
|
||||
value = Present_Value[object_instance];
|
||||
|
||||
return value;
|
||||
float value = 0.0;
|
||||
|
||||
if (object_instance < MAX_ANALOG_INPUTS)
|
||||
value = Present_Value[object_instance];
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* return apdu length, or -1 on error */
|
||||
/* assumption - object has already exists */
|
||||
int Analog_Input_Encode_Property_APDU(uint8_t * apdu,
|
||||
int Analog_Input_Encode_Property_APDU(
|
||||
uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
int32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
|
||||
(void) array_index;
|
||||
switch (property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len = encode_application_object_id(&apdu[0], OBJECT_ANALOG_INPUT,
|
||||
object_instance);
|
||||
break;
|
||||
/* note: Name and Description don't have to be the same.
|
||||
You could make Description writable and different */
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Analog_Input_Name(object_instance));
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0],
|
||||
OBJECT_ANALOG_INPUT);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
apdu_len = encode_application_real(&apdu[0],
|
||||
Analog_Input_Present_Value(object_instance));
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_UNITS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT);
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ANALOG_INPUT,
|
||||
object_instance);
|
||||
break;
|
||||
/* note: Name and Description don't have to be the same.
|
||||
You could make Description writable and different */
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Analog_Input_Name(object_instance));
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0],
|
||||
OBJECT_ANALOG_INPUT);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
apdu_len = encode_application_real(&apdu[0],
|
||||
Analog_Input_Present_Value(object_instance));
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_UNITS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT);
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
@@ -149,7 +159,8 @@ int Analog_Input_Encode_Property_APDU(uint8_t * apdu,
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
void testAnalogInput(Test * pTest)
|
||||
void testAnalogInput(
|
||||
Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
@@ -165,8 +176,7 @@ void testAnalogInput(Test * pTest)
|
||||
/* FIXME: we should do a lot more testing here... */
|
||||
len = Analog_Input_Encode_Property_APDU(&apdu[0],
|
||||
instance,
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
ct_test(pTest, len >= 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
@@ -179,7 +189,8 @@ void testAnalogInput(Test * pTest)
|
||||
}
|
||||
|
||||
#ifdef TEST_ANALOG_INPUT
|
||||
int main(void)
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -196,5 +207,5 @@ int main(void)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_ANALOG_INPUT */
|
||||
#endif /* TEST */
|
||||
#endif /* TEST_ANALOG_INPUT */
|
||||
#endif /* TEST */
|
||||
|
||||
+187
-169
@@ -32,7 +32,7 @@
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
|
||||
#define MAX_ANALOG_VALUES 4
|
||||
@@ -52,7 +52,8 @@ static uint8_t Present_Value[MAX_ANALOG_VALUES];
|
||||
/* we need to have our arrays initialized before answering any calls */
|
||||
static bool Analog_Value_Initialized = false;
|
||||
|
||||
void Analog_Value_Init(void)
|
||||
void Analog_Value_Init(
|
||||
void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
@@ -71,7 +72,8 @@ void Analog_Value_Init(void)
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Analog_Value_Valid_Instance(uint32_t object_instance)
|
||||
bool Analog_Value_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
Analog_Value_Init();
|
||||
if (object_instance < MAX_ANALOG_VALUES)
|
||||
@@ -82,7 +84,8 @@ bool Analog_Value_Valid_Instance(uint32_t object_instance)
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Analog_Value_Count(void)
|
||||
unsigned Analog_Value_Count(
|
||||
void)
|
||||
{
|
||||
Analog_Value_Init();
|
||||
return MAX_ANALOG_VALUES;
|
||||
@@ -91,7 +94,8 @@ unsigned Analog_Value_Count(void)
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the instance */
|
||||
/* that correlates to the correct index */
|
||||
uint32_t Analog_Value_Index_To_Instance(unsigned index)
|
||||
uint32_t Analog_Value_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
Analog_Value_Init();
|
||||
return index;
|
||||
@@ -100,7 +104,8 @@ uint32_t Analog_Value_Index_To_Instance(unsigned index)
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned Analog_Value_Instance_To_Index(uint32_t object_instance)
|
||||
unsigned Analog_Value_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_ANALOG_VALUES;
|
||||
|
||||
@@ -111,7 +116,8 @@ unsigned Analog_Value_Instance_To_Index(uint32_t object_instance)
|
||||
return index;
|
||||
}
|
||||
|
||||
static float Analog_Value_Present_Value(uint32_t object_instance)
|
||||
static float Analog_Value_Present_Value(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
float value = ANALOG_RELINQUISH_DEFAULT;
|
||||
unsigned index = 0;
|
||||
@@ -127,7 +133,8 @@ static float Analog_Value_Present_Value(uint32_t object_instance)
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
char *Analog_Value_Name(uint32_t object_instance)
|
||||
char *Analog_Value_Name(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
|
||||
@@ -140,14 +147,16 @@ char *Analog_Value_Name(uint32_t object_instance)
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
int Analog_Value_Encode_Property_APDU(uint8_t * apdu,
|
||||
int Analog_Value_Encode_Property_APDU(
|
||||
uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
int32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
float real_value = (float) 1.414;
|
||||
@@ -157,110 +166,118 @@ int Analog_Value_Encode_Property_APDU(uint8_t * apdu,
|
||||
|
||||
Analog_Value_Init();
|
||||
switch (property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len = encode_application_object_id(&apdu[0], OBJECT_ANALOG_VALUE,
|
||||
object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Analog_Value_Name(object_instance));
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], OBJECT_ANALOG_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
real_value = Analog_Value_Present_Value(object_instance);
|
||||
apdu_len = encode_application_real(&apdu[0], real_value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
#if 0
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
state = Analog_Value_Out_Of_Service[object_index];
|
||||
#endif
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_UNITS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT);
|
||||
break;
|
||||
#if 0
|
||||
case PROP_PRIORITY_ARRAY:
|
||||
/* Array element zero is the number of elements in the array */
|
||||
if (array_index == 0)
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], BACNET_MAX_PRIORITY);
|
||||
/* if no index was specified, then try to encode the entire list */
|
||||
/* into one packet. */
|
||||
else if (array_index == BACNET_ARRAY_ALL) {
|
||||
encode_application_object_id(&apdu[0], OBJECT_ANALOG_VALUE,
|
||||
object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Analog_Value_Name(object_instance));
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_ANALOG_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
real_value = Analog_Value_Present_Value(object_instance);
|
||||
apdu_len = encode_application_real(&apdu[0], real_value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
#if 0
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
|
||||
/* FIXME: check if we have room before adding it to APDU */
|
||||
if (Present_Value[object_index][i] ==
|
||||
ANALOG_LEVEL_NULL)
|
||||
len = encode_application_null(&apdu[apdu_len]);
|
||||
else {
|
||||
real_value = Present_Value[object_index][i];
|
||||
len = encode_application_real(&apdu[apdu_len], real_value);
|
||||
}
|
||||
/* add it if we have room */
|
||||
if ((apdu_len + len) < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
*error_class = ERROR_CLASS_SERVICES;
|
||||
*error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
if (array_index <= BACNET_MAX_PRIORITY) {
|
||||
if (Present_Value[object_index][array_index - 1] ==
|
||||
ANALOG_LEVEL_NULL)
|
||||
apdu_len = encode_application_null(&apdu[0]);
|
||||
else {
|
||||
real_value =
|
||||
Present_Value[object_index][array_index - 1];
|
||||
apdu_len = encode_application_real(&apdu[0], real_value);
|
||||
state = Analog_Value_Out_Of_Service[object_index];
|
||||
#endif
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_UNITS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT);
|
||||
break;
|
||||
#if 0
|
||||
case PROP_PRIORITY_ARRAY:
|
||||
/* Array element zero is the number of elements in the array */
|
||||
if (array_index == 0)
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], BACNET_MAX_PRIORITY);
|
||||
/* if no index was specified, then try to encode the entire list */
|
||||
/* into one packet. */
|
||||
else if (array_index == BACNET_ARRAY_ALL) {
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
|
||||
/* FIXME: check if we have room before adding it to APDU */
|
||||
if (Present_Value[object_index][i] == ANALOG_LEVEL_NULL)
|
||||
len = encode_application_null(&apdu[apdu_len]);
|
||||
else {
|
||||
real_value = Present_Value[object_index][i];
|
||||
len =
|
||||
encode_application_real(&apdu[apdu_len],
|
||||
real_value);
|
||||
}
|
||||
/* add it if we have room */
|
||||
if ((apdu_len + len) < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
*error_class = ERROR_CLASS_SERVICES;
|
||||
*error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = -1;
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
if (array_index <= BACNET_MAX_PRIORITY) {
|
||||
if (Present_Value[object_index][array_index - 1] ==
|
||||
ANALOG_LEVEL_NULL)
|
||||
apdu_len = encode_application_null(&apdu[0]);
|
||||
else {
|
||||
real_value =
|
||||
Present_Value[object_index][array_index - 1];
|
||||
apdu_len =
|
||||
encode_application_real(&apdu[0], real_value);
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case PROP_RELINQUISH_DEFAULT:
|
||||
real_value = ANALOG_RELINQUISH_DEFAULT;
|
||||
apdu_len = encode_application_real(&apdu[0], real_value);
|
||||
break;
|
||||
break;
|
||||
case PROP_RELINQUISH_DEFAULT:
|
||||
real_value = ANALOG_RELINQUISH_DEFAULT;
|
||||
apdu_len = encode_application_real(&apdu[0], real_value);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Analog_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
bool Analog_Value_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
@@ -281,80 +298,80 @@ bool Analog_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
/* FIXME: len == 0: unable to decode? */
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_REAL) {
|
||||
priority = wp_data->priority;
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
|
||||
(priority != 6 /* reserved */ ) &&
|
||||
(value.type.Real >= 0.0) && (value.type.Real <= 100.0)) {
|
||||
level = (uint8_t) value.type.Real;
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->
|
||||
object_instance);
|
||||
priority--;
|
||||
Present_Value[object_index] = level;
|
||||
/* Note: you could set the physical output here if we
|
||||
are the highest priority.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. This comment may apply to the
|
||||
main loop (i.e. check out of service before changing output) */
|
||||
status = true;
|
||||
} else if (priority == 6) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_REAL) {
|
||||
priority = wp_data->priority;
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
|
||||
(priority != 6 /* reserved */ ) &&
|
||||
(value.type.Real >= 0.0) && (value.type.Real <= 100.0)) {
|
||||
level = (uint8_t) value.type.Real;
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->
|
||||
object_instance);
|
||||
priority--;
|
||||
Present_Value[object_index] = level;
|
||||
/* Note: you could set the physical output here if we
|
||||
are the highest priority.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. This comment may apply to the
|
||||
main loop (i.e. check out of service before changing output) */
|
||||
status = true;
|
||||
} else if (priority == 6) {
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
#if 0
|
||||
} else if (value.tag == BACNET_APPLICATION_TAG_NULL) {
|
||||
level = ANALOG_LEVEL_NULL;
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->object_instance);
|
||||
priority = wp_data->priority;
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
|
||||
priority--;
|
||||
Present_Value[object_index][priority] = level;
|
||||
/* Note: you could set the physical output here to the next
|
||||
highest priority, or to the relinquish default if no
|
||||
priorities are set.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. This comment may apply to the
|
||||
main loop (i.e. check out of service before changing output) */
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#if 0
|
||||
} else if (value.tag == BACNET_APPLICATION_TAG_NULL) {
|
||||
level = ANALOG_LEVEL_NULL;
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->object_instance);
|
||||
priority = wp_data->priority;
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
|
||||
priority--;
|
||||
Present_Value[object_index][priority] = level;
|
||||
/* Note: you could set the physical output here to the next
|
||||
highest priority, or to the relinquish default if no
|
||||
priorities are set.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. This comment may apply to the
|
||||
main loop (i.e. check out of service before changing output) */
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) {
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->object_instance);
|
||||
Analog_Value_Out_Of_Service[object_index] = value.type.Boolean;
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
} else {
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#if 0
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) {
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->object_instance);
|
||||
Analog_Value_Out_Of_Service[object_index] = value.type.Boolean;
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
@@ -366,7 +383,8 @@ bool Analog_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
void testAnalog_Value(Test * pTest)
|
||||
void testAnalog_Value(
|
||||
Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
@@ -381,8 +399,7 @@ void testAnalog_Value(Test * pTest)
|
||||
|
||||
len = Analog_Value_Encode_Property_APDU(&apdu[0],
|
||||
instance,
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
@@ -395,7 +412,8 @@ void testAnalog_Value(Test * pTest)
|
||||
}
|
||||
|
||||
#ifdef TEST_ANALOG_VALUE
|
||||
int main(void)
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -412,5 +430,5 @@ int main(void)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_ANALOG_VALUE */
|
||||
#endif /* TEST */
|
||||
#endif /* TEST_ANALOG_VALUE */
|
||||
#endif /* TEST */
|
||||
|
||||
@@ -37,21 +37,23 @@
|
||||
|
||||
static BACNET_BINARY_PV Present_Value[MAX_BINARY_INPUTS];
|
||||
|
||||
static void Binary_Input_Initialize(void)
|
||||
static void Binary_Input_Initialize(
|
||||
void)
|
||||
{
|
||||
static bool initialized = false;
|
||||
unsigned i;
|
||||
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
for (i = 0; i < MAX_BINARY_INPUTS; i++) {
|
||||
Present_Value[i] = BINARY_INACTIVE;
|
||||
static bool initialized = false;
|
||||
unsigned i;
|
||||
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
for (i = 0; i < MAX_BINARY_INPUTS; i++) {
|
||||
Present_Value[i] = BINARY_INACTIVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
bool Binary_Input_Valid_Instance(uint32_t object_instance)
|
||||
bool Binary_Input_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_BINARY_INPUTS)
|
||||
return true;
|
||||
@@ -60,13 +62,15 @@ bool Binary_Input_Valid_Instance(uint32_t object_instance)
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Binary_Input_Count(void)
|
||||
unsigned Binary_Input_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_BINARY_INPUTS;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances.*/
|
||||
uint32_t Binary_Input_Index_To_Instance(unsigned index)
|
||||
uint32_t Binary_Input_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
@@ -74,7 +78,8 @@ uint32_t Binary_Input_Index_To_Instance(unsigned index)
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned Binary_Input_Instance_To_Index(uint32_t object_instance)
|
||||
unsigned Binary_Input_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_BINARY_INPUTS;
|
||||
|
||||
@@ -84,8 +89,8 @@ unsigned Binary_Input_Instance_To_Index(uint32_t object_instance)
|
||||
return index;
|
||||
}
|
||||
|
||||
static BACNET_BINARY_PV Binary_Input_Present_Value(uint32_t
|
||||
object_instance)
|
||||
static BACNET_BINARY_PV Binary_Input_Present_Value(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
BACNET_BINARY_PV value = BINARY_INACTIVE;
|
||||
unsigned index = 0;
|
||||
@@ -93,13 +98,14 @@ static BACNET_BINARY_PV Binary_Input_Present_Value(uint32_t
|
||||
Binary_Input_Initialize();
|
||||
index = Binary_Input_Instance_To_Index(object_instance);
|
||||
if (index < MAX_BINARY_INPUTS) {
|
||||
value = Present_Value[index];
|
||||
value = Present_Value[index];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
char *Binary_Input_Name(uint32_t object_instance)
|
||||
char *Binary_Input_Name(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
static char text_string[16] = ""; /* okay for single thread */
|
||||
|
||||
@@ -113,13 +119,15 @@ char *Binary_Input_Name(uint32_t object_instance)
|
||||
|
||||
/* return apdu length, or -1 on error */
|
||||
/* assumption - object already exists, and has been bounds checked */
|
||||
int Binary_Input_Encode_Property_APDU(uint8_t * apdu,
|
||||
int Binary_Input_Encode_Property_APDU(
|
||||
uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
int32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
BACNET_POLARITY polarity = POLARITY_NORMAL;
|
||||
@@ -129,48 +137,52 @@ int Binary_Input_Encode_Property_APDU(uint8_t * apdu,
|
||||
(void) array_index;
|
||||
Binary_Input_Initialize();
|
||||
switch (property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len = encode_application_object_id(&apdu[0], OBJECT_BINARY_INPUT,
|
||||
object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
/* note: object name must be unique in our device */
|
||||
characterstring_init_ansi(&char_string,
|
||||
Binary_Input_Name(object_instance));
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], OBJECT_BINARY_INPUT);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
value = Binary_Input_Present_Value(object_instance);
|
||||
apdu_len = encode_application_enumerated(&apdu[0],value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
/* note: see the details in the standard on how to use these */
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
/* note: see the details in the standard on how to use this */
|
||||
apdu_len = encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_POLARITY:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], polarity);
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_BINARY_INPUT,
|
||||
object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
/* note: object name must be unique in our device */
|
||||
characterstring_init_ansi(&char_string,
|
||||
Binary_Input_Name(object_instance));
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_BINARY_INPUT);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
value = Binary_Input_Present_Value(object_instance);
|
||||
apdu_len = encode_application_enumerated(&apdu[0], value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
/* note: see the details in the standard on how to use these */
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
/* note: see the details in the standard on how to use this */
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_POLARITY:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], polarity);
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
@@ -181,7 +193,8 @@ int Binary_Input_Encode_Property_APDU(uint8_t * apdu,
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
void testBinaryInput(Test * pTest)
|
||||
void testBinaryInput(
|
||||
Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
@@ -197,8 +210,7 @@ void testBinaryInput(Test * pTest)
|
||||
/* FIXME: we should do a lot more testing here... */
|
||||
len = Binary_Input_Encode_Property_APDU(&apdu[0],
|
||||
instance,
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
ct_test(pTest, len >= 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
@@ -211,7 +223,8 @@ void testBinaryInput(Test * pTest)
|
||||
}
|
||||
|
||||
#ifdef TEST_BINARY_INPUT
|
||||
int main(void)
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -228,5 +241,5 @@ int main(void)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_BINARY_INPUT */
|
||||
#endif /* TEST */
|
||||
#endif /* TEST_BINARY_INPUT */
|
||||
#endif /* TEST */
|
||||
|
||||
+152
-137
@@ -31,28 +31,30 @@
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
|
||||
#define MAX_BINARY_VALUES 8
|
||||
|
||||
static BACNET_BINARY_PV Present_Value[MAX_BINARY_VALUES];
|
||||
|
||||
static void Binary_Value_Initialize(void)
|
||||
static void Binary_Value_Initialize(
|
||||
void)
|
||||
{
|
||||
static bool initialized = false;
|
||||
unsigned i;
|
||||
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
for (i = 0; i < MAX_BINARY_VALUES; i++) {
|
||||
Present_Value[i] = BINARY_INACTIVE;
|
||||
static bool initialized = false;
|
||||
unsigned i;
|
||||
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
for (i = 0; i < MAX_BINARY_VALUES; i++) {
|
||||
Present_Value[i] = BINARY_INACTIVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
bool Binary_Value_Valid_Instance(uint32_t object_instance)
|
||||
bool Binary_Value_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_BINARY_VALUES)
|
||||
return true;
|
||||
@@ -61,19 +63,22 @@ bool Binary_Value_Valid_Instance(uint32_t object_instance)
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Binary_Value_Count(void)
|
||||
unsigned Binary_Value_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_BINARY_VALUES;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
uint32_t Binary_Value_Index_To_Instance(unsigned index)
|
||||
uint32_t Binary_Value_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Binary_Value_Instance_To_Index(uint32_t object_instance)
|
||||
unsigned Binary_Value_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_BINARY_VALUES;
|
||||
|
||||
@@ -83,8 +88,8 @@ unsigned Binary_Value_Instance_To_Index(uint32_t object_instance)
|
||||
return index;
|
||||
}
|
||||
|
||||
static BACNET_BINARY_PV Binary_Value_Present_Value(uint32_t
|
||||
object_instance)
|
||||
static BACNET_BINARY_PV Binary_Value_Present_Value(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
BACNET_BINARY_PV value = BINARY_INACTIVE;
|
||||
|
||||
@@ -97,7 +102,8 @@ static BACNET_BINARY_PV Binary_Value_Present_Value(uint32_t
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
char *Binary_Value_Name(uint32_t object_instance)
|
||||
char *Binary_Value_Name(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
static char text_string[16] = ""; /* okay for single thread */
|
||||
|
||||
@@ -110,14 +116,16 @@ char *Binary_Value_Name(uint32_t object_instance)
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
int Binary_Value_Encode_Property_APDU(uint8_t * apdu,
|
||||
int Binary_Value_Encode_Property_APDU(
|
||||
uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
int32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
BACNET_BINARY_PV present_value = BINARY_INACTIVE;
|
||||
@@ -128,58 +136,64 @@ int Binary_Value_Encode_Property_APDU(uint8_t * apdu,
|
||||
|
||||
Binary_Value_Initialize();
|
||||
switch (property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len = encode_application_object_id(&apdu[0], OBJECT_BINARY_VALUE,
|
||||
object_instance);
|
||||
break;
|
||||
/* note: Name and Description don't have to be the same.
|
||||
You could make Description writable and different */
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Binary_Value_Name(object_instance));
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], OBJECT_BINARY_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
present_value = Binary_Value_Present_Value(object_instance);
|
||||
apdu_len = encode_application_enumerated(&apdu[0], present_value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
/* note: see the details in the standard on how to use these */
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
/* note: see the details in the standard on how to use this */
|
||||
apdu_len = encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_POLARITY:
|
||||
/* FIXME: figure out the polarity */
|
||||
apdu_len = encode_application_enumerated(&apdu[0], polarity);
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_BINARY_VALUE,
|
||||
object_instance);
|
||||
break;
|
||||
/* note: Name and Description don't have to be the same.
|
||||
You could make Description writable and different */
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Binary_Value_Name(object_instance));
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_BINARY_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
present_value = Binary_Value_Present_Value(object_instance);
|
||||
apdu_len = encode_application_enumerated(&apdu[0], present_value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
/* note: see the details in the standard on how to use these */
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
/* note: see the details in the standard on how to use this */
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_POLARITY:
|
||||
/* FIXME: figure out the polarity */
|
||||
apdu_len = encode_application_enumerated(&apdu[0], polarity);
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Binary_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
bool Binary_Value_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
@@ -199,85 +213,85 @@ bool Binary_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
/* FIXME: len == 0: unable to decode? */
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_ENUMERATED) {
|
||||
priority = wp_data->priority;
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
|
||||
(priority != 6 /* reserved */ ) &&
|
||||
(value.type.Enumerated >= MIN_BINARY_PV) &&
|
||||
(value.type.Enumerated <= MAX_BINARY_PV)) {
|
||||
level = value.type.Enumerated;
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index(wp_data->
|
||||
object_instance);
|
||||
priority--;
|
||||
/* NOTE: this Binary value has no priority array */
|
||||
Present_Value[object_index] = level;
|
||||
/* Note: you could set the physical output here if we
|
||||
are the highest priority.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. */
|
||||
status = true;
|
||||
} else if (priority == 6) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_ENUMERATED) {
|
||||
priority = wp_data->priority;
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
|
||||
(priority != 6 /* reserved */ ) &&
|
||||
(value.type.Enumerated >= MIN_BINARY_PV) &&
|
||||
(value.type.Enumerated <= MAX_BINARY_PV)) {
|
||||
level = value.type.Enumerated;
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index(wp_data->
|
||||
object_instance);
|
||||
priority--;
|
||||
/* NOTE: this Binary value has no priority array */
|
||||
Present_Value[object_index] = level;
|
||||
/* Note: you could set the physical output here if we
|
||||
are the highest priority.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. */
|
||||
status = true;
|
||||
} else if (priority == 6) {
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else if (value.tag == BACNET_APPLICATION_TAG_NULL) {
|
||||
#if 0
|
||||
/* NOTE: this Binary Value has no priority array */
|
||||
level = BINARY_NULL;
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index(wp_data->object_instance);
|
||||
priority = wp_data->priority;
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
|
||||
priority--;
|
||||
Binary_Value_Level[object_index][priority] = level;
|
||||
/* Note: you could set the physical output here to the next
|
||||
highest priority, or to the relinquish default if no
|
||||
priorities are set.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. This comment may apply to the
|
||||
main loop (i.e. check out of service before changing output) */
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
#else
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
#endif
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
} else if (value.tag == BACNET_APPLICATION_TAG_NULL) {
|
||||
break;
|
||||
#if 0
|
||||
/* NOTE: this Binary Value has no priority array */
|
||||
level = BINARY_NULL;
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index(wp_data->object_instance);
|
||||
priority = wp_data->priority;
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
|
||||
priority--;
|
||||
Binary_Value_Level[object_index][priority] = level;
|
||||
/* Note: you could set the physical output here to the next
|
||||
highest priority, or to the relinquish default if no
|
||||
priorities are set.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. This comment may apply to the
|
||||
main loop (i.e. check out of service before changing output) */
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) {
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index(wp_data->object_instance);
|
||||
Binary_Value_Out_Of_Service[object_index] = value.type.Boolean;
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
#else
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
break;
|
||||
#endif
|
||||
} else {
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#if 0
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) {
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index(wp_data->object_instance);
|
||||
Binary_Value_Out_Of_Service[object_index] = value.type.Boolean;
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
@@ -288,7 +302,8 @@ bool Binary_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
void testBinary_Value(Test * pTest)
|
||||
void testBinary_Value(
|
||||
Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
@@ -303,8 +318,7 @@ void testBinary_Value(Test * pTest)
|
||||
|
||||
len = Binary_Value_Encode_Property_APDU(&apdu[0],
|
||||
instance,
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
@@ -317,7 +331,8 @@ void testBinary_Value(Test * pTest)
|
||||
}
|
||||
|
||||
#ifdef TEST_BINARY_VALUE
|
||||
int main(void)
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -334,5 +349,5 @@ int main(void)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_BINARY_VALUE */
|
||||
#endif /* TEST */
|
||||
#endif /* TEST_BINARY_VALUE */
|
||||
#endif /* TEST */
|
||||
|
||||
@@ -25,14 +25,14 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h> /* for memmove */
|
||||
#include <string.h> /* for memmove */
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacstr.h"
|
||||
#include "bacenum.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "apdu.h"
|
||||
#include "device.h" /* me */
|
||||
#include "device.h" /* me */
|
||||
#include "dlmstp.h"
|
||||
#include "rs485.h"
|
||||
#include "ai.h"
|
||||
@@ -53,13 +53,15 @@ static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL;
|
||||
BACNET_REINITIALIZED_STATE_OF_DEVICE Reinitialize_State =
|
||||
REINITIALIZED_STATE_IDLE;
|
||||
|
||||
void Device_Reinit(void)
|
||||
void Device_Reinit(
|
||||
void)
|
||||
{
|
||||
dcc_set_status_duration(COMMUNICATION_ENABLE, 0);
|
||||
Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE);
|
||||
}
|
||||
|
||||
void Device_Init(void)
|
||||
void Device_Init(
|
||||
void)
|
||||
{
|
||||
Reinitialize_State = REINITIALIZED_STATE_IDLE;
|
||||
dcc_set_status_duration(COMMUNICATION_ENABLE, 0);
|
||||
@@ -71,14 +73,16 @@ void Device_Init(void)
|
||||
}
|
||||
|
||||
/* methods to manipulate the data */
|
||||
uint32_t Device_Object_Instance_Number(void)
|
||||
uint32_t Device_Object_Instance_Number(
|
||||
void)
|
||||
{
|
||||
return Object_Instance_Number;
|
||||
}
|
||||
|
||||
bool Device_Set_Object_Instance_Number(uint32_t object_id)
|
||||
bool Device_Set_Object_Instance_Number(
|
||||
uint32_t object_id)
|
||||
{
|
||||
bool status = true; /* return value */
|
||||
bool status = true; /* return value */
|
||||
|
||||
if (object_id <= BACNET_MAX_INSTANCE) {
|
||||
Object_Instance_Number = object_id;
|
||||
@@ -94,71 +98,83 @@ bool Device_Set_Object_Instance_Number(uint32_t object_id)
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Device_Valid_Object_Instance_Number(uint32_t object_id)
|
||||
bool Device_Valid_Object_Instance_Number(
|
||||
uint32_t object_id)
|
||||
{
|
||||
/* BACnet allows for a wildcard instance number */
|
||||
return ((Object_Instance_Number == object_id) ||
|
||||
(object_id == BACNET_MAX_INSTANCE));
|
||||
}
|
||||
|
||||
BACNET_DEVICE_STATUS Device_System_Status(void)
|
||||
BACNET_DEVICE_STATUS Device_System_Status(
|
||||
void)
|
||||
{
|
||||
return System_Status;
|
||||
}
|
||||
|
||||
void Device_Set_System_Status(BACNET_DEVICE_STATUS status)
|
||||
void Device_Set_System_Status(
|
||||
BACNET_DEVICE_STATUS status)
|
||||
{
|
||||
if (status < MAX_DEVICE_STATUS)
|
||||
System_Status = status;
|
||||
}
|
||||
|
||||
uint16_t Device_Vendor_Identifier(void)
|
||||
uint16_t Device_Vendor_Identifier(
|
||||
void)
|
||||
{
|
||||
return BACNET_VENDOR_ID;
|
||||
}
|
||||
|
||||
uint8_t Device_Protocol_Version(void)
|
||||
uint8_t Device_Protocol_Version(
|
||||
void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t Device_Protocol_Revision(void)
|
||||
uint8_t Device_Protocol_Revision(
|
||||
void)
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
|
||||
/* FIXME: MAX_APDU is defined in config.ini - set it! */
|
||||
uint16_t Device_Max_APDU_Length_Accepted(void)
|
||||
uint16_t Device_Max_APDU_Length_Accepted(
|
||||
void)
|
||||
{
|
||||
return MAX_APDU;
|
||||
}
|
||||
|
||||
BACNET_SEGMENTATION Device_Segmentation_Supported(void)
|
||||
BACNET_SEGMENTATION Device_Segmentation_Supported(
|
||||
void)
|
||||
{
|
||||
return SEGMENTATION_NONE;
|
||||
}
|
||||
|
||||
uint16_t Device_APDU_Timeout(void)
|
||||
uint16_t Device_APDU_Timeout(
|
||||
void)
|
||||
{
|
||||
return 60000;
|
||||
}
|
||||
|
||||
|
||||
uint8_t Device_Number_Of_APDU_Retries(void)
|
||||
uint8_t Device_Number_Of_APDU_Retries(
|
||||
void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t Device_Database_Revision(void)
|
||||
uint8_t Device_Database_Revision(
|
||||
void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Since many network clients depend on the object list */
|
||||
/* for discovery, it must be consistent! */
|
||||
unsigned Device_Object_List_Count(void)
|
||||
unsigned Device_Object_List_Count(
|
||||
void)
|
||||
{
|
||||
unsigned count = 1; /* at least 1 for device object */
|
||||
unsigned count = 1; /* at least 1 for device object */
|
||||
|
||||
/* FIXME: add objects as needed */
|
||||
count += Binary_Value_Count();
|
||||
@@ -171,8 +187,10 @@ unsigned Device_Object_List_Count(void)
|
||||
|
||||
/* Since many network clients depend on the object list */
|
||||
/* for discovery, it must be consistent! */
|
||||
bool Device_Object_List_Identifier(unsigned array_index,
|
||||
int *object_type, uint32_t * instance)
|
||||
bool Device_Object_List_Identifier(
|
||||
unsigned array_index,
|
||||
int *object_type,
|
||||
uint32_t * instance)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned object_index = 0;
|
||||
@@ -242,13 +260,15 @@ bool Device_Object_List_Identifier(unsigned array_index,
|
||||
}
|
||||
|
||||
/* return the length of the apdu encoded or -1 for error */
|
||||
int Device_Encode_Property_APDU(uint8_t * apdu,
|
||||
int Device_Encode_Property_APDU(
|
||||
uint8_t * apdu,
|
||||
BACNET_PROPERTY_ID property,
|
||||
int32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
int len = 0; /* apdu len intermediate value */
|
||||
int apdu_len = 0; /* return value */
|
||||
int len = 0; /* apdu len intermediate value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned i = 0;
|
||||
@@ -263,208 +283,226 @@ int Device_Encode_Property_APDU(uint8_t * apdu,
|
||||
|
||||
/* FIXME: change the hardcoded names to suit your application */
|
||||
switch (property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len = encode_application_object_id(&apdu[0], OBJECT_DEVICE,
|
||||
Object_Instance_Number);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
(void) strcpypgm2ram(&string_buffer[0], "PIC18F6720 Device");
|
||||
characterstring_init_ansi(&char_string, string_buffer);
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], OBJECT_DEVICE);
|
||||
break;
|
||||
case PROP_DESCRIPTION:
|
||||
(void) strcpypgm2ram(&string_buffer[0], "BACnet Demo");
|
||||
characterstring_init_ansi(&char_string, string_buffer);
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_SYSTEM_STATUS:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], Device_System_Status());
|
||||
break;
|
||||
case PROP_VENDOR_NAME:
|
||||
(void) strcpypgm2ram(&string_buffer[0], BACNET_VENDOR_NAME);
|
||||
characterstring_init_ansi(&char_string, string_buffer);
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_VENDOR_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], Device_Vendor_Identifier());
|
||||
break;
|
||||
case PROP_MODEL_NAME:
|
||||
(void) strcpypgm2ram(&string_buffer[0], "GNU Demo");
|
||||
characterstring_init_ansi(&char_string, string_buffer);
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_FIRMWARE_REVISION:
|
||||
characterstring_init_ansi(&char_string, BACnet_Version);
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_APPLICATION_SOFTWARE_VERSION:
|
||||
(void) strcpypgm2ram(&string_buffer[0], "1.0");
|
||||
characterstring_init_ansi(&char_string, string_buffer);
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_LOCATION:
|
||||
(void) strcpypgm2ram(&string_buffer[0], "USA");
|
||||
characterstring_init_ansi(&char_string, string_buffer);
|
||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_PROTOCOL_VERSION:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], Device_Protocol_Version());
|
||||
break;
|
||||
case PROP_PROTOCOL_REVISION:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], Device_Protocol_Revision());
|
||||
break;
|
||||
/* BACnet Legacy Support */
|
||||
case PROP_PROTOCOL_CONFORMANCE_CLASS:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], 1);
|
||||
break;
|
||||
case PROP_PROTOCOL_SERVICES_SUPPORTED:
|
||||
/* Note: list of services that are executed, not initiated. */
|
||||
bitstring_init(&bit_string);
|
||||
for (i = 0; i < MAX_BACNET_SERVICES_SUPPORTED; i++) {
|
||||
/* automatic lookup based on handlers set */
|
||||
bitstring_set_bit(&bit_string, (uint8_t) i,
|
||||
apdu_service_supported(i));
|
||||
}
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED:
|
||||
/* Note: this is the list of objects that can be in this device,
|
||||
not a list of objects that this device can access */
|
||||
bitstring_init(&bit_string);
|
||||
for (i = 0; i < MAX_ASHRAE_OBJECT_TYPE; i++) {
|
||||
/* initialize all the object types to not-supported */
|
||||
bitstring_set_bit(&bit_string, (uint8_t) i, false);
|
||||
}
|
||||
/* FIXME: indicate the objects that YOU support */
|
||||
bitstring_set_bit(&bit_string, OBJECT_DEVICE, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_ANALOG_VALUE, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_BINARY_VALUE, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_ANALOG_INPUT, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_BINARY_INPUT, true);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_OBJECT_LIST:
|
||||
count = Device_Object_List_Count();
|
||||
/* Array element zero is the number of objects in the list */
|
||||
if (array_index == 0)
|
||||
apdu_len = encode_application_unsigned(&apdu[0], count);
|
||||
/* if no index was specified, then try to encode the entire list */
|
||||
/* into one packet. Note that more than likely you will have */
|
||||
/* to return an error if the number of encoded objects exceeds */
|
||||
/* your maximum APDU size. */
|
||||
else if (array_index == BACNET_ARRAY_ALL) {
|
||||
for (i = 1; i <= count; i++) {
|
||||
if (Device_Object_List_Identifier(i, &object_type,
|
||||
&instance)) {
|
||||
len =
|
||||
encode_application_object_id(&apdu[apdu_len],
|
||||
object_type, instance);
|
||||
apdu_len += len;
|
||||
/* assume next one is the same size as this one */
|
||||
/* can we all fit into the APDU? */
|
||||
if ((apdu_len + len) >= MAX_APDU) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len = encode_application_object_id(&apdu[0], OBJECT_DEVICE,
|
||||
Object_Instance_Number);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
(void) strcpypgm2ram(&string_buffer[0], "PIC18F6720 Device");
|
||||
characterstring_init_ansi(&char_string, string_buffer);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], OBJECT_DEVICE);
|
||||
break;
|
||||
case PROP_DESCRIPTION:
|
||||
(void) strcpypgm2ram(&string_buffer[0], "BACnet Demo");
|
||||
characterstring_init_ansi(&char_string, string_buffer);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_SYSTEM_STATUS:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
Device_System_Status());
|
||||
break;
|
||||
case PROP_VENDOR_NAME:
|
||||
(void) strcpypgm2ram(&string_buffer[0], BACNET_VENDOR_NAME);
|
||||
characterstring_init_ansi(&char_string, string_buffer);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_VENDOR_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
Device_Vendor_Identifier());
|
||||
break;
|
||||
case PROP_MODEL_NAME:
|
||||
(void) strcpypgm2ram(&string_buffer[0], "GNU Demo");
|
||||
characterstring_init_ansi(&char_string, string_buffer);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_FIRMWARE_REVISION:
|
||||
characterstring_init_ansi(&char_string, BACnet_Version);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_APPLICATION_SOFTWARE_VERSION:
|
||||
(void) strcpypgm2ram(&string_buffer[0], "1.0");
|
||||
characterstring_init_ansi(&char_string, string_buffer);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_LOCATION:
|
||||
(void) strcpypgm2ram(&string_buffer[0], "USA");
|
||||
characterstring_init_ansi(&char_string, string_buffer);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_PROTOCOL_VERSION:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
Device_Protocol_Version());
|
||||
break;
|
||||
case PROP_PROTOCOL_REVISION:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
Device_Protocol_Revision());
|
||||
break;
|
||||
/* BACnet Legacy Support */
|
||||
case PROP_PROTOCOL_CONFORMANCE_CLASS:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], 1);
|
||||
break;
|
||||
case PROP_PROTOCOL_SERVICES_SUPPORTED:
|
||||
/* Note: list of services that are executed, not initiated. */
|
||||
bitstring_init(&bit_string);
|
||||
for (i = 0; i < MAX_BACNET_SERVICES_SUPPORTED; i++) {
|
||||
/* automatic lookup based on handlers set */
|
||||
bitstring_set_bit(&bit_string, (uint8_t) i,
|
||||
apdu_service_supported(i));
|
||||
}
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED:
|
||||
/* Note: this is the list of objects that can be in this device,
|
||||
not a list of objects that this device can access */
|
||||
bitstring_init(&bit_string);
|
||||
for (i = 0; i < MAX_ASHRAE_OBJECT_TYPE; i++) {
|
||||
/* initialize all the object types to not-supported */
|
||||
bitstring_set_bit(&bit_string, (uint8_t) i, false);
|
||||
}
|
||||
/* FIXME: indicate the objects that YOU support */
|
||||
bitstring_set_bit(&bit_string, OBJECT_DEVICE, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_ANALOG_VALUE, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_BINARY_VALUE, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_ANALOG_INPUT, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_BINARY_INPUT, true);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_OBJECT_LIST:
|
||||
count = Device_Object_List_Count();
|
||||
/* Array element zero is the number of objects in the list */
|
||||
if (array_index == 0)
|
||||
apdu_len = encode_application_unsigned(&apdu[0], count);
|
||||
/* if no index was specified, then try to encode the entire list */
|
||||
/* into one packet. Note that more than likely you will have */
|
||||
/* to return an error if the number of encoded objects exceeds */
|
||||
/* your maximum APDU size. */
|
||||
else if (array_index == BACNET_ARRAY_ALL) {
|
||||
for (i = 1; i <= count; i++) {
|
||||
if (Device_Object_List_Identifier(i, &object_type,
|
||||
&instance)) {
|
||||
len =
|
||||
encode_application_object_id(&apdu[apdu_len],
|
||||
object_type, instance);
|
||||
apdu_len += len;
|
||||
/* assume next one is the same size as this one */
|
||||
/* can we all fit into the APDU? */
|
||||
if ((apdu_len + len) >= MAX_APDU) {
|
||||
*error_class = ERROR_CLASS_SERVICES;
|
||||
*error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* error: internal error? */
|
||||
*error_class = ERROR_CLASS_SERVICES;
|
||||
*error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
|
||||
*error_code = ERROR_CODE_OTHER;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* error: internal error? */
|
||||
*error_class = ERROR_CLASS_SERVICES;
|
||||
*error_code = ERROR_CODE_OTHER;
|
||||
}
|
||||
} else {
|
||||
if (Device_Object_List_Identifier(array_index, &object_type,
|
||||
&instance))
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], object_type,
|
||||
instance);
|
||||
else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (Device_Object_List_Identifier(array_index, &object_type,
|
||||
&instance))
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], object_type,
|
||||
instance);
|
||||
else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PROP_MAX_APDU_LENGTH_ACCEPTED:
|
||||
apdu_len = encode_application_unsigned(&apdu[0],
|
||||
Device_Max_APDU_Length_Accepted());
|
||||
break;
|
||||
case PROP_SEGMENTATION_SUPPORTED:
|
||||
apdu_len = encode_application_enumerated(&apdu[0],
|
||||
Device_Segmentation_Supported());
|
||||
break;
|
||||
case PROP_APDU_TIMEOUT:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], Device_APDU_Timeout());
|
||||
break;
|
||||
case PROP_NUMBER_OF_APDU_RETRIES:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
Device_Number_Of_APDU_Retries());
|
||||
break;
|
||||
case PROP_DEVICE_ADDRESS_BINDING:
|
||||
/* FIXME: encode the list here, if it exists */
|
||||
break;
|
||||
case PROP_DATABASE_REVISION:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], Device_Database_Revision());
|
||||
break;
|
||||
case PROP_MAX_INFO_FRAMES:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], dlmstp_max_info_frames());
|
||||
break;
|
||||
case PROP_MAX_MASTER:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], dlmstp_max_master());
|
||||
break;
|
||||
case PROP_LOCAL_TIME:
|
||||
/* FIXME: if you support time */
|
||||
local_time.hour = 0;
|
||||
local_time.min = 0;
|
||||
local_time.sec = 0;
|
||||
local_time.hundredths = 0;
|
||||
apdu_len = encode_application_time(&apdu[0], &local_time);
|
||||
break;
|
||||
case PROP_UTC_OFFSET:
|
||||
/* Note: BACnet Time Zone is inverse of everybody else */
|
||||
apdu_len = encode_application_signed(&apdu[0], 5 /* EST */ );
|
||||
break;
|
||||
case PROP_LOCAL_DATE:
|
||||
/* FIXME: if you support date */
|
||||
local_date.year = 2006; /* AD */
|
||||
local_date.month = 4; /* Jan=1..Dec=12 */
|
||||
local_date.day = 11; /* 1..31 */
|
||||
local_date.wday = 0; /* 1=Mon..7=Sun */
|
||||
apdu_len = encode_application_date(&apdu[0], &local_date);
|
||||
break;
|
||||
case PROP_DAYLIGHT_SAVINGS_STATUS:
|
||||
/* FIXME: if you support time/date */
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case 9600:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], RS485_Get_Baud_Rate());
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
break;
|
||||
case PROP_MAX_APDU_LENGTH_ACCEPTED:
|
||||
apdu_len = encode_application_unsigned(&apdu[0],
|
||||
Device_Max_APDU_Length_Accepted());
|
||||
break;
|
||||
case PROP_SEGMENTATION_SUPPORTED:
|
||||
apdu_len = encode_application_enumerated(&apdu[0],
|
||||
Device_Segmentation_Supported());
|
||||
break;
|
||||
case PROP_APDU_TIMEOUT:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], Device_APDU_Timeout());
|
||||
break;
|
||||
case PROP_NUMBER_OF_APDU_RETRIES:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
Device_Number_Of_APDU_Retries());
|
||||
break;
|
||||
case PROP_DEVICE_ADDRESS_BINDING:
|
||||
/* FIXME: encode the list here, if it exists */
|
||||
break;
|
||||
case PROP_DATABASE_REVISION:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
Device_Database_Revision());
|
||||
break;
|
||||
case PROP_MAX_INFO_FRAMES:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
dlmstp_max_info_frames());
|
||||
break;
|
||||
case PROP_MAX_MASTER:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], dlmstp_max_master());
|
||||
break;
|
||||
case PROP_LOCAL_TIME:
|
||||
/* FIXME: if you support time */
|
||||
local_time.hour = 0;
|
||||
local_time.min = 0;
|
||||
local_time.sec = 0;
|
||||
local_time.hundredths = 0;
|
||||
apdu_len = encode_application_time(&apdu[0], &local_time);
|
||||
break;
|
||||
case PROP_UTC_OFFSET:
|
||||
/* Note: BACnet Time Zone is inverse of everybody else */
|
||||
apdu_len = encode_application_signed(&apdu[0], 5 /* EST */ );
|
||||
break;
|
||||
case PROP_LOCAL_DATE:
|
||||
/* FIXME: if you support date */
|
||||
local_date.year = 2006; /* AD */
|
||||
local_date.month = 4; /* Jan=1..Dec=12 */
|
||||
local_date.day = 11; /* 1..31 */
|
||||
local_date.wday = 0; /* 1=Mon..7=Sun */
|
||||
apdu_len = encode_application_date(&apdu[0], &local_date);
|
||||
break;
|
||||
case PROP_DAYLIGHT_SAVINGS_STATUS:
|
||||
/* FIXME: if you support time/date */
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case 9600:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], RS485_Get_Baud_Rate());
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
|
||||
bool Device_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
int len = 0;
|
||||
@@ -481,98 +519,98 @@ bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
/* FIXME: len == 0: unable to decode? */
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_OBJECT_ID) {
|
||||
if ((value.type.Object_Id.type == OBJECT_DEVICE) &&
|
||||
(Device_Set_Object_Instance_Number(value.type.
|
||||
Object_Id.instance))) {
|
||||
/* we could send an I-Am broadcast to let the world know */
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case PROP_MAX_INFO_FRAMES:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
if (value.type.Unsigned_Int <= 255) {
|
||||
dlmstp_set_max_info_frames(value.type.Unsigned_Int);
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case PROP_MAX_MASTER:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
if ((value.type.Unsigned_Int > 0) &&
|
||||
(value.type.Unsigned_Int <= 127)) {
|
||||
dlmstp_set_max_master(value.type.Unsigned_Int);
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) {
|
||||
uint8_t encoding;
|
||||
size_t len;
|
||||
|
||||
encoding =
|
||||
characterstring_encoding(&value.type.Character_String);
|
||||
len = characterstring_length(&value.type.Character_String);
|
||||
if (encoding == CHARACTER_ANSI_X34) {
|
||||
if (len <= 20) {
|
||||
/* FIXME: set the name */
|
||||
/* Display_Set_Name(
|
||||
characterstring_value(&value.type.Character_String)); */
|
||||
/* FIXME: All the object names in a device must be unique.
|
||||
Disallow setting the Device Object Name to any objects in
|
||||
the device. */
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_OBJECT_ID) {
|
||||
if ((value.type.Object_Id.type == OBJECT_DEVICE) &&
|
||||
(Device_Set_Object_Instance_Number(value.type.
|
||||
Object_Id.instance))) {
|
||||
/* we could send an I-Am broadcast to let the world know */
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case 9600:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
if (value.type.Unsigned_Int > 115200) {
|
||||
RS485_Set_Baud_Rate(value.type.Unsigned_Int);
|
||||
status = true;
|
||||
break;
|
||||
case PROP_MAX_INFO_FRAMES:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
if (value.type.Unsigned_Int <= 255) {
|
||||
dlmstp_set_max_info_frames(value.type.Unsigned_Int);
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
case PROP_MAX_MASTER:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
if ((value.type.Unsigned_Int > 0) &&
|
||||
(value.type.Unsigned_Int <= 127)) {
|
||||
dlmstp_set_max_master(value.type.Unsigned_Int);
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) {
|
||||
uint8_t encoding;
|
||||
size_t len;
|
||||
|
||||
encoding =
|
||||
characterstring_encoding(&value.type.Character_String);
|
||||
len = characterstring_length(&value.type.Character_String);
|
||||
if (encoding == CHARACTER_ANSI_X34) {
|
||||
if (len <= 20) {
|
||||
/* FIXME: set the name */
|
||||
/* Display_Set_Name(
|
||||
characterstring_value(&value.type.Character_String)); */
|
||||
/* FIXME: All the object names in a device must be unique.
|
||||
Disallow setting the Device Object Name to any objects in
|
||||
the device. */
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case 9600:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
if (value.type.Unsigned_Int > 115200) {
|
||||
RS485_Set_Baud_Rate(value.type.Unsigned_Int);
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
|
||||
@@ -49,12 +49,14 @@ volatile struct mstp_port_struct_t MSTP_Port;
|
||||
|
||||
#define INCREMENT_AND_LIMIT_UINT16(x) {if (x < 0xFFFF) x++;}
|
||||
|
||||
void dlmstp_millisecond_timer(void)
|
||||
void dlmstp_millisecond_timer(
|
||||
void)
|
||||
{
|
||||
INCREMENT_AND_LIMIT_UINT16(MSTP_Port.SilenceTimer);
|
||||
}
|
||||
|
||||
void dlmstp_reinit(void)
|
||||
void dlmstp_reinit(
|
||||
void)
|
||||
{
|
||||
RS485_Reinit();
|
||||
dlmstp_set_my_address(DEFAULT_MAC_ADDRESS);
|
||||
@@ -62,7 +64,8 @@ void dlmstp_reinit(void)
|
||||
dlmstp_set_max_master(DEFAULT_MAX_MASTER);
|
||||
}
|
||||
|
||||
void dlmstp_init(void)
|
||||
void dlmstp_init(
|
||||
void)
|
||||
{
|
||||
uint8_t data;
|
||||
|
||||
@@ -74,17 +77,17 @@ void dlmstp_init(void)
|
||||
MSTP_Port.InputBuffer = &Receive_Buffer.pdu[0];
|
||||
MSTP_Init(&MSTP_Port);
|
||||
/* FIXME: implement your data storage */
|
||||
data = 64; /* I2C_Read_Byte(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
EEPROM_MSTP_MAC_ADDR); */
|
||||
data = 64; /* I2C_Read_Byte(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
EEPROM_MSTP_MAC_ADDR); */
|
||||
if (data <= 127)
|
||||
MSTP_Port.This_Station = data;
|
||||
else
|
||||
dlmstp_set_my_address(DEFAULT_MAC_ADDRESS);
|
||||
/* FIXME: implement your data storage */
|
||||
data = 127; /* I2C_Read_Byte(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
EEPROM_MSTP_MAX_MASTER_ADDR); */
|
||||
data = 127; /* I2C_Read_Byte(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
EEPROM_MSTP_MAX_MASTER_ADDR); */
|
||||
if ((data <= 127) && (data >= MSTP_Port.This_Station))
|
||||
MSTP_Port.Nmax_master = data;
|
||||
else
|
||||
@@ -100,30 +103,31 @@ void dlmstp_init(void)
|
||||
dlmstp_set_max_info_frames(DEFAULT_MAX_INFO_FRAMES);
|
||||
}
|
||||
|
||||
void dlmstp_cleanup(void)
|
||||
void dlmstp_cleanup(
|
||||
void)
|
||||
{
|
||||
/* nothing to do for static buffers */
|
||||
}
|
||||
|
||||
/* returns number of bytes sent on success, zero on failure */
|
||||
int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
int dlmstp_send_pdu(
|
||||
BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len)
|
||||
{ /* number of bytes of data */
|
||||
{ /* number of bytes of data */
|
||||
int bytes_sent = 0;
|
||||
unsigned npdu_len = 0;
|
||||
uint8_t frame_type = 0;
|
||||
uint8_t destination = 0; /* destination address */
|
||||
BACNET_ADDRESS src;
|
||||
unsigned i = 0; /* loop counter */
|
||||
unsigned i = 0; /* loop counter */
|
||||
|
||||
if (MSTP_Port.TxReady == false) {
|
||||
if (npdu_data->data_expecting_reply)
|
||||
MSTP_Port.TxFrameType = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY;
|
||||
else
|
||||
MSTP_Port.TxFrameType =
|
||||
FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY;
|
||||
MSTP_Port.TxFrameType = FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY;
|
||||
|
||||
/* load destination MAC address */
|
||||
if (dest && dest->mac_len == 1) {
|
||||
@@ -148,7 +152,8 @@ int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
return bytes_sent;
|
||||
}
|
||||
|
||||
void dlmstp_task(void)
|
||||
void dlmstp_task(
|
||||
void)
|
||||
{
|
||||
uint8_t bytes_remaining;
|
||||
bool received_frame;
|
||||
@@ -184,7 +189,9 @@ void dlmstp_task(void)
|
||||
return;
|
||||
}
|
||||
|
||||
void dlmstp_fill_bacnet_address(BACNET_ADDRESS * src, uint8_t mstp_address)
|
||||
void dlmstp_fill_bacnet_address(
|
||||
BACNET_ADDRESS * src,
|
||||
uint8_t mstp_address)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
@@ -208,17 +215,19 @@ void dlmstp_fill_bacnet_address(BACNET_ADDRESS * src, uint8_t mstp_address)
|
||||
}
|
||||
|
||||
/* for the MS/TP state machine to use for putting received data */
|
||||
uint16_t dlmstp_put_receive(uint8_t src, /* source MS/TP address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t dlmstp_put_receive(
|
||||
uint8_t src, /* source MS/TP address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t pdu_len)
|
||||
{ /* amount of PDU data */
|
||||
{ /* amount of PDU data */
|
||||
/* PDU is already in the Receive_Buffer */
|
||||
dlmstp_fill_bacnet_address(&Receive_Buffer.address, src);
|
||||
Receive_Buffer.pdu_len = pdu_len;
|
||||
Receive_Buffer.ready = true;
|
||||
}
|
||||
|
||||
void dlmstp_set_my_address(uint8_t mac_address)
|
||||
void dlmstp_set_my_address(
|
||||
uint8_t mac_address)
|
||||
{
|
||||
/* Master Nodes can only have address 0-127 */
|
||||
if (mac_address <= 127) {
|
||||
@@ -235,7 +244,8 @@ void dlmstp_set_my_address(uint8_t mac_address)
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t dlmstp_my_address(void)
|
||||
uint8_t dlmstp_my_address(
|
||||
void)
|
||||
{
|
||||
return MSTP_Port.This_Station;
|
||||
}
|
||||
@@ -247,7 +257,8 @@ uint8_t dlmstp_my_address(void)
|
||||
/* nodes. This may be used to allocate more or less of the available link */
|
||||
/* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */
|
||||
/* node, its value shall be 1. */
|
||||
void dlmstp_set_max_info_frames(uint8_t max_info_frames)
|
||||
void dlmstp_set_max_info_frames(
|
||||
uint8_t max_info_frames)
|
||||
{
|
||||
if (max_info_frames >= 1) {
|
||||
MSTP_Port.Nmax_info_frames = max_info_frames;
|
||||
@@ -261,7 +272,8 @@ void dlmstp_set_max_info_frames(uint8_t max_info_frames)
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned dlmstp_max_info_frames(void)
|
||||
unsigned dlmstp_max_info_frames(
|
||||
void)
|
||||
{
|
||||
return MSTP_Port.Nmax_info_frames;
|
||||
}
|
||||
@@ -271,7 +283,8 @@ unsigned dlmstp_max_info_frames(void)
|
||||
/* allowable address for master nodes. The value of Max_Master shall be */
|
||||
/* less than or equal to 127. If Max_Master is not writable in a node, */
|
||||
/* its value shall be 127. */
|
||||
void dlmstp_set_max_master(uint8_t max_master)
|
||||
void dlmstp_set_max_master(
|
||||
uint8_t max_master)
|
||||
{
|
||||
if (max_master <= 127) {
|
||||
if (MSTP_Port.This_Station <= max_master) {
|
||||
@@ -287,14 +300,16 @@ void dlmstp_set_max_master(uint8_t max_master)
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t dlmstp_max_master(void)
|
||||
uint8_t dlmstp_max_master(
|
||||
void)
|
||||
{
|
||||
return MSTP_Port.Nmax_master;
|
||||
}
|
||||
|
||||
void dlmstp_get_my_address(BACNET_ADDRESS * my_address)
|
||||
void dlmstp_get_my_address(
|
||||
BACNET_ADDRESS * my_address)
|
||||
{
|
||||
int i = 0; /* counter */
|
||||
int i = 0; /* counter */
|
||||
|
||||
my_address->mac_len = 1;
|
||||
my_address->mac[0] = MSTP_Port.This_Station;
|
||||
@@ -307,15 +322,16 @@ void dlmstp_get_my_address(BACNET_ADDRESS * my_address)
|
||||
return;
|
||||
}
|
||||
|
||||
void dlmstp_get_broadcast_address(BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
void dlmstp_get_broadcast_address(
|
||||
BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
|
||||
if (dest) {
|
||||
dest->mac_len = 1;
|
||||
dest->mac[0] = MSTP_BROADCAST_ADDRESS;
|
||||
dest->net = BACNET_BROADCAST_NETWORK;
|
||||
dest->len = 0; /* always zero when DNET is broadcast */
|
||||
dest->len = 0; /* always zero when DNET is broadcast */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
dest->adr[i] = 0;
|
||||
}
|
||||
|
||||
@@ -46,10 +46,10 @@
|
||||
#define MAX_MPDU (MAX_HEADER+MAX_PDU)
|
||||
|
||||
typedef struct dlmstp_packet {
|
||||
bool ready; /* true if ready to be sent or received */
|
||||
bool ready; /* true if ready to be sent or received */
|
||||
BACNET_ADDRESS address; /* source address */
|
||||
uint8_t frame_type; /* type of message */
|
||||
unsigned pdu_len; /* packet length */
|
||||
uint8_t frame_type; /* type of message */
|
||||
unsigned pdu_len; /* packet length */
|
||||
uint8_t pdu[MAX_MPDU]; /* packet */
|
||||
} DLMSTP_PACKET;
|
||||
|
||||
@@ -58,18 +58,24 @@ extern uint16_t MSTP_Packets;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void dlmstp_reinit(void);
|
||||
void dlmstp_init(void);
|
||||
void dlmstp_cleanup(void);
|
||||
void dlmstp_millisecond_timer(void);
|
||||
void dlmstp_task(void);
|
||||
void dlmstp_reinit(
|
||||
void);
|
||||
void dlmstp_init(
|
||||
void);
|
||||
void dlmstp_cleanup(
|
||||
void);
|
||||
void dlmstp_millisecond_timer(
|
||||
void);
|
||||
void dlmstp_task(
|
||||
void);
|
||||
|
||||
/* returns number of bytes sent on success, negative on failure */
|
||||
int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
int dlmstp_send_pdu(
|
||||
BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len); /* number of bytes of data */
|
||||
|
||||
/* This parameter represents the value of the Max_Info_Frames property of */
|
||||
@@ -79,32 +85,41 @@ extern "C" {
|
||||
/* nodes. This may be used to allocate more or less of the available link */
|
||||
/* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */
|
||||
/* node, its value shall be 1. */
|
||||
void dlmstp_set_max_info_frames(uint8_t max_info_frames);
|
||||
unsigned dlmstp_max_info_frames(void);
|
||||
void dlmstp_set_max_info_frames(
|
||||
uint8_t max_info_frames);
|
||||
unsigned dlmstp_max_info_frames(
|
||||
void);
|
||||
|
||||
/* This parameter represents the value of the Max_Master property of the */
|
||||
/* node's Device object. The value of Max_Master specifies the highest */
|
||||
/* allowable address for master nodes. The value of Max_Master shall be */
|
||||
/* less than or equal to 127. If Max_Master is not writable in a node, */
|
||||
/* its value shall be 127. */
|
||||
void dlmstp_set_max_master(uint8_t max_master);
|
||||
uint8_t dlmstp_max_master(void);
|
||||
void dlmstp_set_max_master(
|
||||
uint8_t max_master);
|
||||
uint8_t dlmstp_max_master(
|
||||
void);
|
||||
|
||||
/* MAC address for MS/TP */
|
||||
void dlmstp_set_my_address(uint8_t my_address);
|
||||
uint8_t dlmstp_my_address(void);
|
||||
void dlmstp_set_my_address(
|
||||
uint8_t my_address);
|
||||
uint8_t dlmstp_my_address(
|
||||
void);
|
||||
|
||||
/* BACnet address used in datalink */
|
||||
void dlmstp_get_my_address(BACNET_ADDRESS * my_address);
|
||||
void dlmstp_get_broadcast_address(BACNET_ADDRESS * dest); /* destination address */
|
||||
void dlmstp_get_my_address(
|
||||
BACNET_ADDRESS * my_address);
|
||||
void dlmstp_get_broadcast_address(
|
||||
BACNET_ADDRESS * dest); /* destination address */
|
||||
|
||||
/* MS/TP state machine functions */
|
||||
uint16_t dlmstp_put_receive(uint8_t src, /* source MS/TP address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t dlmstp_put_receive(
|
||||
uint8_t src, /* source MS/TP address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t pdu_len);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -46,9 +46,11 @@
|
||||
|
||||
static uint8_t Temp_Buf[MAX_APDU] = { 0 };
|
||||
|
||||
void handler_read_property(uint8_t * service_request,
|
||||
void handler_read_property(
|
||||
uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
{
|
||||
BACNET_READ_PROPERTY_DATA data;
|
||||
int len = 0;
|
||||
@@ -83,98 +85,98 @@ void handler_read_property(uint8_t * service_request,
|
||||
/* most cases will be error */
|
||||
error = true;
|
||||
switch (data.object_type) {
|
||||
case OBJECT_DEVICE:
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
if (Device_Valid_Object_Instance_Number(data.object_instance)) {
|
||||
len = Device_Encode_Property_APDU(&Temp_Buf[0],
|
||||
data.object_property,
|
||||
data.array_index, &error_class, &error_code);
|
||||
if (len >= 0) {
|
||||
/* encode the APDU portion of the packet */
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
error = false;
|
||||
case OBJECT_DEVICE:
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
if (Device_Valid_Object_Instance_Number(data.object_instance)) {
|
||||
len = Device_Encode_Property_APDU(&Temp_Buf[0],
|
||||
data.object_property,
|
||||
data.array_index, &error_class, &error_code);
|
||||
if (len >= 0) {
|
||||
/* encode the APDU portion of the packet */
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
error = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_INPUT:
|
||||
if (Analog_Input_Valid_Instance(data.object_instance)) {
|
||||
len = Analog_Input_Encode_Property_APDU(&Temp_Buf[0],
|
||||
data.object_instance,
|
||||
data.object_property,
|
||||
data.array_index, &error_class, &error_code);
|
||||
if (len >= 0) {
|
||||
/* encode the APDU portion of the packet */
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
error = false;
|
||||
break;
|
||||
case OBJECT_ANALOG_INPUT:
|
||||
if (Analog_Input_Valid_Instance(data.object_instance)) {
|
||||
len = Analog_Input_Encode_Property_APDU(&Temp_Buf[0],
|
||||
data.object_instance,
|
||||
data.object_property,
|
||||
data.array_index, &error_class, &error_code);
|
||||
if (len >= 0) {
|
||||
/* encode the APDU portion of the packet */
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
error = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OBJECT_BINARY_INPUT:
|
||||
if (Binary_Input_Valid_Instance(data.object_instance)) {
|
||||
len = Binary_Input_Encode_Property_APDU(&Temp_Buf[0],
|
||||
data.object_instance,
|
||||
data.object_property,
|
||||
data.array_index, &error_class, &error_code);
|
||||
if (len >= 0) {
|
||||
/* encode the APDU portion of the packet */
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
error = false;
|
||||
break;
|
||||
case OBJECT_BINARY_INPUT:
|
||||
if (Binary_Input_Valid_Instance(data.object_instance)) {
|
||||
len = Binary_Input_Encode_Property_APDU(&Temp_Buf[0],
|
||||
data.object_instance,
|
||||
data.object_property,
|
||||
data.array_index, &error_class, &error_code);
|
||||
if (len >= 0) {
|
||||
/* encode the APDU portion of the packet */
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
error = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OBJECT_BINARY_VALUE:
|
||||
if (Binary_Value_Valid_Instance(data.object_instance)) {
|
||||
len = Binary_Value_Encode_Property_APDU(&Temp_Buf[0],
|
||||
data.object_instance,
|
||||
data.object_property,
|
||||
data.array_index, &error_class, &error_code);
|
||||
if (len >= 0) {
|
||||
/* encode the APDU portion of the packet */
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
error = false;
|
||||
break;
|
||||
case OBJECT_BINARY_VALUE:
|
||||
if (Binary_Value_Valid_Instance(data.object_instance)) {
|
||||
len = Binary_Value_Encode_Property_APDU(&Temp_Buf[0],
|
||||
data.object_instance,
|
||||
data.object_property,
|
||||
data.array_index, &error_class, &error_code);
|
||||
if (len >= 0) {
|
||||
/* encode the APDU portion of the packet */
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
error = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_VALUE:
|
||||
if (Analog_Value_Valid_Instance(data.object_instance)) {
|
||||
len = Analog_Value_Encode_Property_APDU(&Temp_Buf[0],
|
||||
data.object_instance,
|
||||
data.object_property,
|
||||
data.array_index, &error_class, &error_code);
|
||||
if (len >= 0) {
|
||||
/* encode the APDU portion of the packet */
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
error = false;
|
||||
break;
|
||||
case OBJECT_ANALOG_VALUE:
|
||||
if (Analog_Value_Valid_Instance(data.object_instance)) {
|
||||
len = Analog_Value_Encode_Property_APDU(&Temp_Buf[0],
|
||||
data.object_instance,
|
||||
data.object_property,
|
||||
data.array_index, &error_class, &error_code);
|
||||
if (len >= 0) {
|
||||
/* encode the APDU portion of the packet */
|
||||
data.application_data = &Temp_Buf[0];
|
||||
data.application_data_len = len;
|
||||
/* FIXME: probably need a length limitation sent with encode */
|
||||
len =
|
||||
rp_ack_encode_apdu(&Handler_Transmit_Buffer
|
||||
[pdu_len], service_data->invoke_id, &data);
|
||||
error = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (error) {
|
||||
if (len == -2) {
|
||||
@@ -188,7 +190,7 @@ void handler_read_property(uint8_t * service_request,
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_READ_PROPERTY, error_class, error_code);
|
||||
}
|
||||
RP_ABORT:
|
||||
RP_ABORT:
|
||||
pdu_len += len;
|
||||
bytes_sent = datalink_send_pdu(src, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
|
||||
@@ -45,9 +45,11 @@
|
||||
/* too big to reside on stack frame for PIC */
|
||||
static BACNET_WRITE_PROPERTY_DATA wp_data;
|
||||
|
||||
void handler_write_property(uint8_t * service_request,
|
||||
void handler_write_property(
|
||||
uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
{
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
@@ -69,104 +71,94 @@ void handler_write_property(uint8_t * service_request,
|
||||
goto WP_ABORT;
|
||||
}
|
||||
/* decode the service request only */
|
||||
len = wp_decode_service_request(service_request,
|
||||
service_len, &wp_data);
|
||||
len = wp_decode_service_request(service_request, service_len, &wp_data);
|
||||
/* bad decoding or something we didn't understand - send an abort */
|
||||
if (len <= 0) {
|
||||
len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, ABORT_REASON_OTHER, true);
|
||||
goto WP_ABORT;
|
||||
}
|
||||
switch (wp_data.object_type) {
|
||||
case OBJECT_DEVICE:
|
||||
if (Device_Write_Property(&wp_data, &error_class, &error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Write Property Simple Ack for Device!\n");
|
||||
#endif
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Write Property Error for Device!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_INPUT:
|
||||
case OBJECT_BINARY_INPUT:
|
||||
error_class = ERROR_CLASS_PROPERTY;
|
||||
error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY,
|
||||
error_class, error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Write Access Error!\n");
|
||||
#endif
|
||||
break;
|
||||
case OBJECT_BINARY_VALUE:
|
||||
if (Binary_Value_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Write Property Simple Ack for BV!\n");
|
||||
#endif
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Write Access Error for BV!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_VALUE:
|
||||
if (Analog_Value_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Write Property Simple Ack for AV!\n");
|
||||
#endif
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Write Access Error for AV!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
default:
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY,
|
||||
error_class, error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Unknown Object Error!\n");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
WP_ABORT:
|
||||
switch (wp_data.object_type) {
|
||||
case OBJECT_DEVICE:
|
||||
if (Device_Write_Property(&wp_data, &error_class, &error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Sending Write Property Simple Ack for Device!\n");
|
||||
#endif
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class, error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Write Property Error for Device!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_INPUT:
|
||||
case OBJECT_BINARY_INPUT:
|
||||
error_class = ERROR_CLASS_PROPERTY;
|
||||
error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY,
|
||||
error_class, error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Write Access Error!\n");
|
||||
#endif
|
||||
break;
|
||||
case OBJECT_BINARY_VALUE:
|
||||
if (Binary_Value_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Write Property Simple Ack for BV!\n");
|
||||
#endif
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class, error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Write Access Error for BV!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_VALUE:
|
||||
if (Analog_Value_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Write Property Simple Ack for AV!\n");
|
||||
#endif
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class, error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Write Access Error for AV!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
default:
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY,
|
||||
error_class, error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Sending Unknown Object Error!\n");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
WP_ABORT:
|
||||
pdu_len += len;
|
||||
bytes_sent = datalink_send_pdu(src, &npdu_data,
|
||||
&Handler_Transmit_Buffer[0], pdu_len);
|
||||
|
||||
@@ -132,8 +132,8 @@ typedef union {
|
||||
uint8_t Program:1;
|
||||
uint8_t Run:1;
|
||||
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t Input1:1;
|
||||
uint8_t Input2:1;
|
||||
uint8_t Input3:1;
|
||||
@@ -141,35 +141,35 @@ typedef union {
|
||||
uint8_t Input5:1;
|
||||
uint8_t Input6:1;
|
||||
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t Input7:1;
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t Input8:1;
|
||||
uint8_t Photocell:1;
|
||||
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t Remote:1;
|
||||
uint8_t Relay8:1;
|
||||
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t Relay7:1;
|
||||
uint8_t Relay6:1;
|
||||
uint8_t Relay5:1;
|
||||
uint8_t Relay4:1;
|
||||
uint8_t Relay3:1;
|
||||
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t:1;
|
||||
uint8_t Relay2:1;
|
||||
uint8_t Relay1:1;
|
||||
uint8_t Holiday:1;
|
||||
@@ -268,4 +268,4 @@ extern volatile LED_REGS Blink;
|
||||
extern uint8_t Piezo_Timer;
|
||||
extern volatile bool DataPortLocked;
|
||||
|
||||
#endif /* HARDWARE_H */
|
||||
#endif /* HARDWARE_H */
|
||||
|
||||
@@ -31,30 +31,42 @@
|
||||
/* from main.c */
|
||||
extern volatile uint8_t Milliseconds;
|
||||
|
||||
void InterruptHandlerHigh(void);
|
||||
void InterruptHandlerLow(void);
|
||||
void Interrupt_Timer2(void);
|
||||
void Interrupt_Timer3(void);
|
||||
void Interrupt_Timer4(void);
|
||||
void Interrupt_USART_Rx(void);
|
||||
void Interrupt_USART_Tx(void);
|
||||
void Interrupt_CCP2(void);
|
||||
void INT0_Interrupt(void);
|
||||
void InterruptHandlerHigh(
|
||||
void);
|
||||
void InterruptHandlerLow(
|
||||
void);
|
||||
void Interrupt_Timer2(
|
||||
void);
|
||||
void Interrupt_Timer3(
|
||||
void);
|
||||
void Interrupt_Timer4(
|
||||
void);
|
||||
void Interrupt_USART_Rx(
|
||||
void);
|
||||
void Interrupt_USART_Tx(
|
||||
void);
|
||||
void Interrupt_CCP2(
|
||||
void);
|
||||
void INT0_Interrupt(
|
||||
void);
|
||||
|
||||
#pragma code InterruptVectorHigh = 0x08
|
||||
void InterruptVectorHigh(void)
|
||||
void InterruptVectorHigh(
|
||||
void)
|
||||
{
|
||||
/* jump to interrupt routine */
|
||||
_asm goto InterruptHandlerHigh _endasm}
|
||||
#pragma code
|
||||
#pragma code InterruptVectorLow = 0x18
|
||||
void InterruptVectorLow(void)
|
||||
void InterruptVectorLow(
|
||||
void)
|
||||
{
|
||||
/* jump to interrupt routine */
|
||||
_asm goto InterruptHandlerLow _endasm}
|
||||
#pragma code
|
||||
#pragma interrupt InterruptHandlerHigh
|
||||
void InterruptHandlerHigh(void)
|
||||
void InterruptHandlerHigh(
|
||||
void)
|
||||
{
|
||||
#if 0
|
||||
/* check for USART Rx int */
|
||||
@@ -84,7 +96,8 @@ void InterruptHandlerHigh(void)
|
||||
#pragma interruptlow InterruptHandlerLow save = PROD, section(".tmpdata"), TABLAT, TBLPTR, section \
|
||||
("MATH_DATA")
|
||||
|
||||
void InterruptHandlerLow(void)
|
||||
void InterruptHandlerLow(
|
||||
void)
|
||||
{
|
||||
/* check for timer2 int */
|
||||
if ((PIR1bits.TMR2IF) && (PIE1bits.TMR2IE)) {
|
||||
@@ -168,23 +181,27 @@ void InterruptHandlerLow(void)
|
||||
*/
|
||||
}
|
||||
|
||||
void Interrupt_Timer2(void)
|
||||
void Interrupt_Timer2(
|
||||
void)
|
||||
{
|
||||
}
|
||||
|
||||
void Interrupt_Timer3(void)
|
||||
void Interrupt_Timer3(
|
||||
void)
|
||||
{
|
||||
}
|
||||
|
||||
/* Timer4 is set to go off every 1ms. This is our system tick */
|
||||
void Interrupt_Timer4(void)
|
||||
void Interrupt_Timer4(
|
||||
void)
|
||||
{
|
||||
/* Milisecond is our system tick */
|
||||
if (Milliseconds < 0xFF)
|
||||
++Milliseconds;
|
||||
}
|
||||
|
||||
void Interrupt_CCP2(void)
|
||||
void Interrupt_CCP2(
|
||||
void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h> /* for memmove */
|
||||
#include <string.h> /* for memmove */
|
||||
#include <p18F6720.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -87,16 +87,16 @@
|
||||
#else
|
||||
#pragma config WDT = ON, WDTPS = 128
|
||||
#pragma config DEBUG = OFF
|
||||
#endif /* USE_ICD */
|
||||
#endif /* USE_ICD */
|
||||
|
||||
volatile uint8_t Milliseconds = 0;
|
||||
volatile uint8_t Zero_Cross_Timeout = 0;
|
||||
|
||||
static void BACnet_Service_Handlers_Init(void)
|
||||
static void BACnet_Service_Handlers_Init(
|
||||
void)
|
||||
{
|
||||
/* we need to handle who-is to support dynamic device binding */
|
||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS,
|
||||
handler_who_is);
|
||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
||||
/* Set the handlers for any confirmed services that we support. */
|
||||
/* We must implement read property - it's required! */
|
||||
apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY,
|
||||
@@ -107,8 +107,7 @@ static void BACnet_Service_Handlers_Init(void)
|
||||
handler_write_property);
|
||||
#if 0
|
||||
apdu_set_unconfirmed_handler
|
||||
(SERVICE_UNCONFIRMED_UTC_TIME_SYNCHRONIZATION,
|
||||
handler_timesync_utc);
|
||||
(SERVICE_UNCONFIRMED_UTC_TIME_SYNCHRONIZATION, handler_timesync_utc);
|
||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_TIME_SYNCHRONIZATION,
|
||||
handler_timesync);
|
||||
#endif
|
||||
@@ -118,7 +117,8 @@ static void BACnet_Service_Handlers_Init(void)
|
||||
handler_device_communication_control);
|
||||
}
|
||||
|
||||
void Reinitialize(void)
|
||||
void Reinitialize(
|
||||
void)
|
||||
{
|
||||
uint8_t i;
|
||||
char name = 0;
|
||||
@@ -126,30 +126,32 @@ void Reinitialize(void)
|
||||
_asm reset _endasm return;
|
||||
}
|
||||
|
||||
void Global_Int(enum INT_STATE state)
|
||||
void Global_Int(
|
||||
enum INT_STATE state)
|
||||
{
|
||||
static uint8_t intstate = 0;
|
||||
|
||||
switch (state) {
|
||||
case INT_DISABLED:
|
||||
intstate >>= 2;
|
||||
intstate |= (INTCON & 0xC0);
|
||||
break;
|
||||
case INT_ENABLED:
|
||||
INTCONbits.GIE = 1;
|
||||
INTCONbits.PEIE = 1;
|
||||
intstate <<= 2;
|
||||
break;
|
||||
case INT_RESTORE:
|
||||
INTCON |= (intstate & 0xC0);
|
||||
intstate <<= 2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case INT_DISABLED:
|
||||
intstate >>= 2;
|
||||
intstate |= (INTCON & 0xC0);
|
||||
break;
|
||||
case INT_ENABLED:
|
||||
INTCONbits.GIE = 1;
|
||||
INTCONbits.PEIE = 1;
|
||||
intstate <<= 2;
|
||||
break;
|
||||
case INT_RESTORE:
|
||||
INTCON |= (intstate & 0xC0);
|
||||
intstate <<= 2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Hardware_Initialize(void)
|
||||
void Hardware_Initialize(
|
||||
void)
|
||||
{
|
||||
/* PORTA.0 Input - Photocell PORTA.1 Output - LED Row6 PORTA.2 Output
|
||||
* - LED Row5 PORTA.3 Output - LED Row4 PORTA.4 Input - Square Wave
|
||||
@@ -247,7 +249,8 @@ void Hardware_Initialize(void)
|
||||
Global_Int(INT_ENABLED);
|
||||
}
|
||||
|
||||
void Initialize_Variables(void)
|
||||
void Initialize_Variables(
|
||||
void)
|
||||
{
|
||||
/* Check to see if we need to initialize our eeproms */
|
||||
ENABLE_TIMER4_INT();
|
||||
@@ -259,7 +262,8 @@ void Initialize_Variables(void)
|
||||
Milliseconds = 0;
|
||||
}
|
||||
|
||||
void MainTasks(void)
|
||||
void MainTasks(
|
||||
void)
|
||||
{
|
||||
static uint16_t millisecond_counter = 0;
|
||||
/* Handle our millisecond counters */
|
||||
@@ -274,7 +278,8 @@ void MainTasks(void)
|
||||
}
|
||||
}
|
||||
|
||||
void main(void)
|
||||
void main(
|
||||
void)
|
||||
{
|
||||
RCONbits.NOT_POR = 1;
|
||||
RCONbits.NOT_RI = 1;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -199,7 +199,7 @@ struct mstp_port_struct_t {
|
||||
/* This array is only used for APDU messages */
|
||||
uint8_t TxBuffer[MAX_MPDU];
|
||||
unsigned TxLength;
|
||||
bool TxReady; /* true if ready to be sent or received */
|
||||
bool TxReady; /* true if ready to be sent or received */
|
||||
uint8_t TxFrameType; /* type of message - needed by MS/TP */
|
||||
};
|
||||
|
||||
@@ -220,27 +220,32 @@ struct mstp_port_struct_t {
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void MSTP_Init(volatile struct mstp_port_struct_t *mstp_port);
|
||||
void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t
|
||||
void MSTP_Init(
|
||||
volatile struct mstp_port_struct_t *mstp_port);
|
||||
void MSTP_Receive_Frame_FSM(
|
||||
volatile struct mstp_port_struct_t
|
||||
*mstp_port);
|
||||
bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t
|
||||
bool MSTP_Master_Node_FSM(
|
||||
volatile struct mstp_port_struct_t
|
||||
*mstp_port);
|
||||
|
||||
/* returns true if line is active */
|
||||
bool MSTP_Line_Active(volatile struct mstp_port_struct_t *mstp_port);
|
||||
bool MSTP_Line_Active(
|
||||
volatile struct mstp_port_struct_t *mstp_port);
|
||||
|
||||
unsigned MSTP_Create_Frame(uint8_t * buffer, /* where frame is loaded */
|
||||
unsigned MSTP_Create_Frame(
|
||||
uint8_t * buffer, /* where frame is loaded */
|
||||
unsigned buffer_len, /* amount of space available */
|
||||
uint8_t frame_type, /* type of frame to send - see defines */
|
||||
uint8_t destination, /* destination address */
|
||||
uint8_t source, /* source address */
|
||||
uint8_t * data, /* any data to be sent - may be null */
|
||||
uint8_t source, /* source address */
|
||||
uint8_t * data, /* any data to be sent - may be null */
|
||||
unsigned data_len); /* number of bytes of data (up to 501) */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -57,11 +57,12 @@ volatile uint8_t RS485_Tx_Buffer[MAX_MPDU];
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Send_Frame(volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
||||
void RS485_Send_Frame(
|
||||
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
||||
uint16_t nbytes)
|
||||
{ /* number of bytes of data (up to 501) */
|
||||
uint16_t i = 0; /* loop counter */
|
||||
{ /* number of bytes of data (up to 501) */
|
||||
uint16_t i = 0; /* loop counter */
|
||||
uint8_t turnaround_time;
|
||||
|
||||
if (!buffer)
|
||||
@@ -117,8 +118,8 @@ void RS485_Send_Frame(volatile struct mstp_port_struct_t *mstp_port, /* port
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
uint8_t RS485_Check_UART_Data(volatile struct mstp_port_struct_t *
|
||||
mstp_port)
|
||||
uint8_t RS485_Check_UART_Data(
|
||||
volatile struct mstp_port_struct_t * mstp_port)
|
||||
{
|
||||
/* check for data */
|
||||
if (RS485_Comstat.Rx_Bytes) {
|
||||
@@ -151,7 +152,8 @@ uint8_t RS485_Check_UART_Data(volatile struct mstp_port_struct_t *
|
||||
|
||||
NOTES: none
|
||||
*************************************************************************** */
|
||||
void RS485_Interrupt_Rx(void)
|
||||
void RS485_Interrupt_Rx(
|
||||
void)
|
||||
{
|
||||
char dummy;
|
||||
|
||||
@@ -184,7 +186,8 @@ void RS485_Interrupt_Rx(void)
|
||||
|
||||
NOTES: none
|
||||
*************************************************************************** */
|
||||
void RS485_Interrupt_Tx(void)
|
||||
void RS485_Interrupt_Tx(
|
||||
void)
|
||||
{
|
||||
if (RS485_Comstat.Tx_Bytes) {
|
||||
/* Get the data byte */
|
||||
@@ -214,7 +217,8 @@ void RS485_Interrupt_Tx(void)
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
uint32_t RS485_Get_Baud_Rate(void)
|
||||
uint32_t RS485_Get_Baud_Rate(
|
||||
void)
|
||||
{
|
||||
return RS485_Baud_Rate;
|
||||
}
|
||||
@@ -225,22 +229,23 @@ uint32_t RS485_Get_Baud_Rate(void)
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
bool RS485_Set_Baud_Rate(uint32_t baud)
|
||||
bool RS485_Set_Baud_Rate(
|
||||
uint32_t baud)
|
||||
{
|
||||
bool valid = true;
|
||||
|
||||
switch (baud) {
|
||||
case 9600:
|
||||
case 19200:
|
||||
case 38400:
|
||||
case 57600:
|
||||
case 76800:
|
||||
case 115200:
|
||||
RS485_Baud_Rate = baud;
|
||||
break;
|
||||
default:
|
||||
valid = false;
|
||||
break;
|
||||
case 9600:
|
||||
case 19200:
|
||||
case 38400:
|
||||
case 57600:
|
||||
case 76800:
|
||||
case 115200:
|
||||
RS485_Baud_Rate = baud;
|
||||
break;
|
||||
default:
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
@@ -262,7 +267,8 @@ bool RS485_Set_Baud_Rate(uint32_t baud)
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Initialize_Port(void)
|
||||
void RS485_Initialize_Port(
|
||||
void)
|
||||
{
|
||||
|
||||
/* Reset USART registers to POR state */
|
||||
@@ -292,35 +298,35 @@ void RS485_Initialize_Port(void)
|
||||
1250000 0
|
||||
*/
|
||||
switch (RS485_Baud_Rate) {
|
||||
case 19200:
|
||||
SPBRG2 = 64;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
case 38400:
|
||||
SPBRG2 = 32;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
case 57600:
|
||||
SPBRG2 = 21;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
case 76800:
|
||||
SPBRG2 = 3;
|
||||
TXSTA2bits.BRGH = 0;
|
||||
break;
|
||||
case 115200:
|
||||
SPBRG2 = 10;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
case 9600:
|
||||
SPBRG2 = 129;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
default:
|
||||
SPBRG2 = 129;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
RS485_Set_Baud_Rate(9600);
|
||||
break;
|
||||
case 19200:
|
||||
SPBRG2 = 64;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
case 38400:
|
||||
SPBRG2 = 32;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
case 57600:
|
||||
SPBRG2 = 21;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
case 76800:
|
||||
SPBRG2 = 3;
|
||||
TXSTA2bits.BRGH = 0;
|
||||
break;
|
||||
case 115200:
|
||||
SPBRG2 = 10;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
case 9600:
|
||||
SPBRG2 = 129;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
default:
|
||||
SPBRG2 = 129;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
RS485_Set_Baud_Rate(9600);
|
||||
break;
|
||||
}
|
||||
/* select async mode */
|
||||
TXSTA2bits.SYNC = 0;
|
||||
@@ -341,14 +347,16 @@ void RS485_Initialize_Port(void)
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Disable_Port(void)
|
||||
void RS485_Disable_Port(
|
||||
void)
|
||||
{
|
||||
RCSTA2 &= 0x4F; /* Disable the receiver */
|
||||
RCSTA2 &= 0x4F; /* Disable the receiver */
|
||||
TXSTA2bits.TXEN = 0; /* and transmitter */
|
||||
PIE3 &= 0xCF; /* Disable both interrupts */
|
||||
PIE3 &= 0xCF; /* Disable both interrupts */
|
||||
}
|
||||
|
||||
void RS485_Reinit(void)
|
||||
void RS485_Reinit(
|
||||
void)
|
||||
{
|
||||
RS485_Set_Baud_Rate(38400);
|
||||
}
|
||||
@@ -359,7 +367,8 @@ void RS485_Reinit(void)
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Initialize(void)
|
||||
void RS485_Initialize(
|
||||
void)
|
||||
{
|
||||
/* Init the Rs485 buffers */
|
||||
RS485_Comstat.RxHead = 0;
|
||||
|
||||
@@ -58,27 +58,36 @@ extern uint32_t RS485_Baud_Rate;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void RS485_Reinit(void);
|
||||
void RS485_Initialize(void);
|
||||
void RS485_Reinit(
|
||||
void);
|
||||
void RS485_Initialize(
|
||||
void);
|
||||
|
||||
void RS485_Disable(void);
|
||||
void RS485_Disable(
|
||||
void);
|
||||
|
||||
void RS485_Send_Frame(volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||
void RS485_Send_Frame(
|
||||
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
||||
uint16_t nbytes); /* number of bytes of data (up to 501) */
|
||||
|
||||
uint8_t RS485_Check_UART_Data(volatile struct mstp_port_struct_t *mstp_port); /* port specific data */
|
||||
uint8_t RS485_Check_UART_Data(
|
||||
volatile struct mstp_port_struct_t *mstp_port); /* port specific data */
|
||||
|
||||
void RS485_Interrupt_Rx(void);
|
||||
void RS485_Interrupt_Rx(
|
||||
void);
|
||||
|
||||
void RS485_Interrupt_Tx(void);
|
||||
void RS485_Interrupt_Tx(
|
||||
void);
|
||||
|
||||
uint32_t RS485_Get_Baud_Rate(void);
|
||||
bool RS485_Set_Baud_Rate(uint32_t baud);
|
||||
uint32_t RS485_Get_Baud_Rate(
|
||||
void);
|
||||
bool RS485_Set_Baud_Rate(
|
||||
uint32_t baud);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -15,4 +15,4 @@ typedef signed long int32_t; /* 4 bytes -2147483647 to 2147483647 */
|
||||
/* typedef signed long long int64_t; */
|
||||
/* typedef unsigned long long uint64_t; */
|
||||
|
||||
#endif /* STDINT_H */
|
||||
#endif /* STDINT_H */
|
||||
|
||||
@@ -32,15 +32,16 @@
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include "bacdcode.h"
|
||||
#include "bip.h"
|
||||
|
||||
static int interface = SOCKET_ERROR; /* SOCKET_ERROR means no open interface */
|
||||
|
||||
/*-----------------------------------*/
|
||||
static void Error(const char *Msg)
|
||||
static void Error(
|
||||
const char *Msg)
|
||||
{
|
||||
int Code = WSAGetLastError();
|
||||
#ifdef HOST
|
||||
@@ -53,7 +54,8 @@ static void Error(const char *Msg)
|
||||
|
||||
#ifndef HOST
|
||||
/*-----------------------------------*/
|
||||
void InterfaceCleanup(void)
|
||||
void InterfaceCleanup(
|
||||
void)
|
||||
{
|
||||
if (interface != SOCKET_ERROR) {
|
||||
xn_interface_close(interface);
|
||||
@@ -64,7 +66,8 @@ void InterfaceCleanup(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void NetInitialize(void)
|
||||
static void NetInitialize(
|
||||
void)
|
||||
/* initialize the TCP/IP stack */
|
||||
{
|
||||
int Result;
|
||||
@@ -78,7 +81,7 @@ static void NetInitialize(void)
|
||||
RTURegisterCallback(USBAX772);
|
||||
RTURegisterCallback(USBKeyboard); /* support USB keyboards */
|
||||
FindUSBControllers(); /* install USB host controllers */
|
||||
Sleep(2000); /* give the USB stack time to enumerate devices */
|
||||
Sleep(2000); /* give the USB stack time to enumerate devices */
|
||||
#endif
|
||||
|
||||
#ifdef DHCP
|
||||
@@ -129,16 +132,16 @@ static void NetInitialize(void)
|
||||
|
||||
#if DEVICE_ID == PRISM_PCMCIA_DEVICE || DEVICE_ID == PRISM_DEVICE
|
||||
xn_wlan_setup(interface, /* iface_no: value returned by xn_interface_open_config() */
|
||||
"network name", /* SSID : network name set in the access point */
|
||||
"station name", /* Name : name of this node */
|
||||
0, /* Channel : 0 for access points, 1..14 for ad-hoc */
|
||||
0, /* KeyIndex: 0 .. 3 */
|
||||
"12345", /* WEP Key : key to use (5 or 13 bytes) */
|
||||
0); /* Flags : see manual and Wlanapi.h for details */
|
||||
Sleep(1000); /* wireless devices need a little time before they can be used */
|
||||
#endif /* WLAN device */
|
||||
"network name", /* SSID : network name set in the access point */
|
||||
"station name", /* Name : name of this node */
|
||||
0, /* Channel : 0 for access points, 1..14 for ad-hoc */
|
||||
0, /* KeyIndex: 0 .. 3 */
|
||||
"12345", /* WEP Key : key to use (5 or 13 bytes) */
|
||||
0); /* Flags : see manual and Wlanapi.h for details */
|
||||
Sleep(1000); /* wireless devices need a little time before they can be used */
|
||||
#endif /* WLAN device */
|
||||
|
||||
#if defined(AUTO_IP) /* use xn_autoip() to get an IP address */
|
||||
#if defined(AUTO_IP) /* use xn_autoip() to get an IP address */
|
||||
Result = xn_autoip(interface, MinIP, MaxIP, NetMask, TargetIP);
|
||||
if (Result == SOCKET_ERROR)
|
||||
Error("xn_autoip failed");
|
||||
@@ -146,11 +149,10 @@ static void NetInitialize(void)
|
||||
printf("Auto-assigned IP address %i.%i.%i.%i\n", TargetIP[0],
|
||||
TargetIP[1], TargetIP[2], TargetIP[3]);
|
||||
/* define default gateway and DNS server */
|
||||
xn_rt_add(RT_DEFAULT, ip_ffaddr, DefaultGateway, 1, interface,
|
||||
RT_INF);
|
||||
xn_rt_add(RT_DEFAULT, ip_ffaddr, DefaultGateway, 1, interface, RT_INF);
|
||||
xn_set_server_list((DWORD *) DNSServer, 1);
|
||||
}
|
||||
#elif defined(DHCP) /* use DHCP */
|
||||
#elif defined(DHCP) /* use DHCP */
|
||||
{
|
||||
DHCP_param param[] = { {SUBNET_MASK, 1}
|
||||
, {DNS_OP, 1}
|
||||
@@ -180,7 +182,7 @@ static void NetInitialize(void)
|
||||
xn_set_server_list((DWORD *) DNSServer, 1);
|
||||
#endif
|
||||
|
||||
#else /* HOST defined, run on Windows */
|
||||
#else /* HOST defined, run on Windows */
|
||||
|
||||
WSADATA wd;
|
||||
Result = WSAStartup(0x0101, &wd);
|
||||
@@ -198,7 +200,8 @@ static void NetInitialize(void)
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
******************************************************************/
|
||||
static void RTIP_To_Network_Address(BYTE * octet_address,
|
||||
static void RTIP_To_Network_Address(
|
||||
BYTE * octet_address,
|
||||
struct in_addr *addr)
|
||||
{
|
||||
uint32_t ip_address = 0; /* for decoding the subnet mask */
|
||||
@@ -209,7 +212,8 @@ static void RTIP_To_Network_Address(BYTE * octet_address,
|
||||
return;
|
||||
}
|
||||
|
||||
static void set_broadcast_address(uint32_t net_address)
|
||||
static void set_broadcast_address(
|
||||
uint32_t net_address)
|
||||
{
|
||||
long broadcast_address = 0;
|
||||
long mask = 0;
|
||||
@@ -238,15 +242,16 @@ static void set_broadcast_address(uint32_t net_address)
|
||||
#endif
|
||||
}
|
||||
|
||||
bool bip_init(char *ifname)
|
||||
bool bip_init(
|
||||
char *ifname)
|
||||
{
|
||||
int rv = 0; /* return from socket lib calls */
|
||||
int rv = 0; /* return from socket lib calls */
|
||||
struct sockaddr_in sin = { -1 };
|
||||
int value = 1;
|
||||
int sock_fd = -1;
|
||||
struct in_addr my_addr;
|
||||
|
||||
(void)ifname;
|
||||
(void) ifname;
|
||||
|
||||
NetInitialize();
|
||||
|
||||
|
||||
@@ -42,9 +42,10 @@ static uint8_t PDU_Buffer[MAX_MPDU];
|
||||
/* local MS/TP port data */
|
||||
static volatile struct mstp_port_struct_t MSTP_Port;
|
||||
|
||||
void dlmstp_init(char *ifname)
|
||||
void dlmstp_init(
|
||||
char *ifname)
|
||||
{
|
||||
(void)ifname;
|
||||
(void) ifname;
|
||||
/* initialize buffer */
|
||||
Receive_Buffer.ready = false;
|
||||
Receive_Buffer.pdu_len = 0;
|
||||
@@ -53,17 +54,19 @@ void dlmstp_init(char *ifname)
|
||||
MSTP_Init(&MSTP_Port, MSTP_Port.This_Station);
|
||||
}
|
||||
|
||||
void dlmstp_cleanup(void)
|
||||
void dlmstp_cleanup(
|
||||
void)
|
||||
{
|
||||
/* nothing to do for static buffers */
|
||||
}
|
||||
|
||||
/* returns number of bytes sent on success, zero on failure */
|
||||
int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
int dlmstp_send_pdu(
|
||||
BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len)
|
||||
{ /* number of bytes of data */
|
||||
{ /* number of bytes of data */
|
||||
int bytes_sent = 0;
|
||||
uint8_t frame_type = 0;
|
||||
uint8_t destination = 0; /* destination address */
|
||||
@@ -74,8 +77,7 @@ int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
if (npdu_data->confirmed_message)
|
||||
MSTP_Port.TxFrameType = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY;
|
||||
else
|
||||
MSTP_Port.TxFrameType =
|
||||
FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY;
|
||||
MSTP_Port.TxFrameType = FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY;
|
||||
|
||||
/* load destination MAC address */
|
||||
if (dest && dest->mac_len == 1) {
|
||||
@@ -109,16 +111,18 @@ int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
}
|
||||
|
||||
/* called about once a millisecond */
|
||||
void dlmstp_millisecond_timer(void)
|
||||
void dlmstp_millisecond_timer(
|
||||
void)
|
||||
{
|
||||
MSTP_Millisecond_Timer(&MSTP_Port);
|
||||
}
|
||||
|
||||
/* returns the number of octets in the PDU, or zero on failure */
|
||||
/* This function is expecting to be polled. */
|
||||
uint16_t dlmstp_receive(BACNET_ADDRESS * src, /* source address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t max_pdu, /* amount of space available in the PDU */
|
||||
uint16_t dlmstp_receive(
|
||||
BACNET_ADDRESS * src, /* source address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t max_pdu, /* amount of space available in the PDU */
|
||||
unsigned timeout)
|
||||
{
|
||||
uint16_t pdu_len = 0;
|
||||
@@ -137,8 +141,7 @@ uint16_t dlmstp_receive(BACNET_ADDRESS * src, /* source address */
|
||||
}
|
||||
/* see if there is a packet available */
|
||||
if (Receive_Buffer.ready) {
|
||||
memmove(src, &Receive_Buffer.address,
|
||||
sizeof(Receive_Buffer.address));
|
||||
memmove(src, &Receive_Buffer.address, sizeof(Receive_Buffer.address));
|
||||
pdu_len = Receive_Buffer.pdu_len;
|
||||
memmove(&pdu[0], &Receive_Buffer.pdu[0], max_pdu);
|
||||
Receive_Buffer.ready = false;
|
||||
@@ -147,7 +150,9 @@ uint16_t dlmstp_receive(BACNET_ADDRESS * src, /* source address */
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
void dlmstp_fill_bacnet_address(BACNET_ADDRESS * src, uint8_t mstp_address)
|
||||
void dlmstp_fill_bacnet_address(
|
||||
BACNET_ADDRESS * src,
|
||||
uint8_t mstp_address)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
@@ -171,8 +176,9 @@ void dlmstp_fill_bacnet_address(BACNET_ADDRESS * src, uint8_t mstp_address)
|
||||
}
|
||||
|
||||
/* for the MS/TP state machine to use for putting received data */
|
||||
uint16_t dlmstp_put_receive(uint8_t src, /* source MS/TP address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t dlmstp_put_receive(
|
||||
uint8_t src, /* source MS/TP address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t pdu_len)
|
||||
{
|
||||
if (Receive_Buffer.ready) {
|
||||
@@ -191,7 +197,8 @@ uint16_t dlmstp_put_receive(uint8_t src, /* source MS/TP address */
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
void dlmstp_set_my_address(uint8_t mac_address)
|
||||
void dlmstp_set_my_address(
|
||||
uint8_t mac_address)
|
||||
{
|
||||
/* FIXME: Master Nodes can only have address 1-127 */
|
||||
MSTP_Port.This_Station = mac_address;
|
||||
@@ -206,14 +213,16 @@ void dlmstp_set_my_address(uint8_t mac_address)
|
||||
/* nodes. This may be used to allocate more or less of the available link */
|
||||
/* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */
|
||||
/* node, its value shall be 1. */
|
||||
void dlmstp_set_max_info_frames(unsigned max_info_frames)
|
||||
void dlmstp_set_max_info_frames(
|
||||
unsigned max_info_frames)
|
||||
{
|
||||
MSTP_Port.Nmax_info_frames = max_info_frames;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned dlmstp_max_info_frames(void)
|
||||
unsigned dlmstp_max_info_frames(
|
||||
void)
|
||||
{
|
||||
return MSTP_Port.Nmax_info_frames;
|
||||
}
|
||||
@@ -223,21 +232,24 @@ unsigned dlmstp_max_info_frames(void)
|
||||
/* allowable address for master nodes. The value of Max_Master shall be */
|
||||
/* less than or equal to 127. If Max_Master is not writable in a node, */
|
||||
/* its value shall be 127. */
|
||||
void dlmstp_set_max_master(uint8_t max_master)
|
||||
void dlmstp_set_max_master(
|
||||
uint8_t max_master)
|
||||
{
|
||||
MSTP_Port.Nmax_master = max_master;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t dlmstp_max_master(void)
|
||||
uint8_t dlmstp_max_master(
|
||||
void)
|
||||
{
|
||||
return MSTP_Port.Nmax_master;
|
||||
}
|
||||
|
||||
void dlmstp_get_my_address(BACNET_ADDRESS * my_address)
|
||||
void dlmstp_get_my_address(
|
||||
BACNET_ADDRESS * my_address)
|
||||
{
|
||||
int i = 0; /* counter */
|
||||
int i = 0; /* counter */
|
||||
|
||||
my_address->mac_len = 1;
|
||||
my_address->mac[0] = MSTP_Port.This_Station;
|
||||
@@ -250,15 +262,16 @@ void dlmstp_get_my_address(BACNET_ADDRESS * my_address)
|
||||
return;
|
||||
}
|
||||
|
||||
void dlmstp_get_broadcast_address(BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
void dlmstp_get_broadcast_address(
|
||||
BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
|
||||
if (dest) {
|
||||
dest->mac_len = 1;
|
||||
dest->mac[0] = MSTP_BROADCAST_ADDRESS;
|
||||
dest->net = BACNET_BROADCAST_NETWORK;
|
||||
dest->len = 0; /* len=0 denotes broadcast address */
|
||||
dest->len = 0; /* len=0 denotes broadcast address */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
dest->adr[i] = 0;
|
||||
}
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include <stdio.h> /* for the standard bool type. */
|
||||
#include <stdlib.h> /* for the standard bool type. */
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include <stdio.h> /* for the standard bool type. */
|
||||
#include <stdlib.h> /* for the standard bool type. */
|
||||
#include <rttarget.h>
|
||||
#include <rtk32.h>
|
||||
#include <clock.h>
|
||||
@@ -49,12 +49,14 @@ static SOCKET Ethernet_Socket = -1;
|
||||
/* used for binding 802.2 */
|
||||
static struct sockaddr Ethernet_Address = { 0 };
|
||||
|
||||
bool ethernet_valid(void)
|
||||
bool ethernet_valid(
|
||||
void)
|
||||
{
|
||||
return (Ethernet_Socket != -1);
|
||||
}
|
||||
|
||||
void ethernet_cleanup(void)
|
||||
void ethernet_cleanup(
|
||||
void)
|
||||
{
|
||||
if (ethernet_valid())
|
||||
closesocket(Ethernet_Socket);
|
||||
@@ -63,7 +65,8 @@ void ethernet_cleanup(void)
|
||||
return;
|
||||
}
|
||||
|
||||
bool ethernet_init(char *interface_name)
|
||||
bool ethernet_init(
|
||||
char *interface_name)
|
||||
{
|
||||
int value = 1;
|
||||
|
||||
@@ -85,12 +88,13 @@ bool ethernet_init(char *interface_name)
|
||||
|
||||
/* function to send a packet out the 802.2 socket */
|
||||
/* returns bytes sent on success, negative number on failure */
|
||||
int ethernet_send(BACNET_ADDRESS * dest, /* destination address */
|
||||
int ethernet_send(
|
||||
BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_ADDRESS * src, /* source address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len)
|
||||
{ /* number of bytes of data */
|
||||
{ /* number of bytes of data */
|
||||
int bytes = 0;
|
||||
uint8_t mtu[MAX_MPDU] = { 0 };
|
||||
int mtu_len = 0;
|
||||
@@ -128,8 +132,7 @@ int ethernet_send(BACNET_ADDRESS * dest, /* destination address */
|
||||
return -4;
|
||||
}
|
||||
/* packet length */
|
||||
mtu_len += encode_unsigned16(&mtu[12],
|
||||
3 /*DSAP,SSAP,LLC */ + pdu_len);
|
||||
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 */
|
||||
@@ -156,12 +159,13 @@ int ethernet_send(BACNET_ADDRESS * dest, /* destination address */
|
||||
|
||||
/* function to send a packet out the 802.2 socket */
|
||||
/* returns bytes sent on success, negative number on failure */
|
||||
int ethernet_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
int ethernet_send_pdu(
|
||||
BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len)
|
||||
{ /* number of bytes of data */
|
||||
int i = 0; /* counter */
|
||||
{ /* number of bytes of data */
|
||||
int i = 0; /* counter */
|
||||
BACNET_ADDRESS src = { 0 }; /* source address */
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
@@ -173,18 +177,19 @@ int ethernet_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
/* 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 */
|
||||
npdu_data, pdu, /* any data to be sent - may be null */
|
||||
pdu_len); /* number of bytes of data */
|
||||
&src, /* source address */
|
||||
npdu_data, 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 */
|
||||
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 */
|
||||
{ /* 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 */
|
||||
@@ -212,8 +217,7 @@ uint16_t ethernet_receive(BACNET_ADDRESS * src, /* source address */
|
||||
max = Ethernet_Socket;
|
||||
|
||||
if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0)
|
||||
received_bytes =
|
||||
recv(Ethernet_Socket, (char *) &buf[0], MAX_MPDU, 0);
|
||||
received_bytes = recv(Ethernet_Socket, (char *) &buf[0], MAX_MPDU, 0);
|
||||
else
|
||||
return 0;
|
||||
|
||||
@@ -262,7 +266,8 @@ uint16_t ethernet_receive(BACNET_ADDRESS * src, /* source address */
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
void ethernet_get_my_address(BACNET_ADDRESS * my_address)
|
||||
void ethernet_get_my_address(
|
||||
BACNET_ADDRESS * my_address)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
@@ -280,7 +285,8 @@ void ethernet_get_my_address(BACNET_ADDRESS * my_address)
|
||||
return;
|
||||
}
|
||||
|
||||
void ethernet_set_my_address(BACNET_ADDRESS * my_address)
|
||||
void ethernet_set_my_address(
|
||||
BACNET_ADDRESS * my_address)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
@@ -291,9 +297,10 @@ void ethernet_set_my_address(BACNET_ADDRESS * my_address)
|
||||
return;
|
||||
}
|
||||
|
||||
void ethernet_get_broadcast_address(BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
void ethernet_get_broadcast_address(
|
||||
BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
|
||||
if (dest) {
|
||||
for (i = 0; i < 6; i++) {
|
||||
@@ -301,7 +308,7 @@ void ethernet_get_broadcast_address(BACNET_ADDRESS * dest)
|
||||
}
|
||||
dest->mac_len = 6;
|
||||
dest->net = BACNET_BROADCAST_NETWORK;
|
||||
dest->len = 0; /* denotes broadcast address */
|
||||
dest->len = 0; /* denotes broadcast address */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
dest->adr[i] = 0;
|
||||
}
|
||||
@@ -310,9 +317,11 @@ void ethernet_get_broadcast_address(BACNET_ADDRESS * dest)
|
||||
return;
|
||||
}
|
||||
|
||||
void ethernet_debug_address(const char *info, BACNET_ADDRESS * dest)
|
||||
void ethernet_debug_address(
|
||||
const char *info,
|
||||
BACNET_ADDRESS * dest)
|
||||
{
|
||||
int i = 0; /* counter */
|
||||
int i = 0; /* counter */
|
||||
|
||||
if (info)
|
||||
fprintf(stderr, "%s", info);
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
#include <rtkernel.h>
|
||||
#include <windows.h>
|
||||
|
||||
extern void RTEmuInit(void);
|
||||
extern void RTEmuInit(
|
||||
void);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define VOIDEXPORT _declspec(dllexport) void __cdecl
|
||||
@@ -36,11 +37,11 @@ extern void RTEmuInit(void);
|
||||
#endif
|
||||
|
||||
/* DISK SYSTEM */
|
||||
#ifdef DOC /* include DiskOnChip driver */
|
||||
#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 */
|
||||
#include <rtfdata.c> /* system is initialized */
|
||||
|
||||
/*#define READ_HEAD_BUFFER_SIZE 2048+4 */
|
||||
|
||||
@@ -89,8 +90,7 @@ 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 };
|
||||
RTFileSystem RAMFiles = { RT_FS_FILE, 1 << ('Z' - 'A'), 0, &RTRAMFileSystem };
|
||||
|
||||
/* logical drive A: through D: are reserved for FAT */
|
||||
RTFileSystem FATFiles =
|
||||
@@ -106,12 +106,13 @@ RTFileSystem *RTFileSystemList[] = {
|
||||
#endif
|
||||
|
||||
/*-----------------------------------*/
|
||||
VOIDEXPORT Init(void)
|
||||
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 */
|
||||
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 */
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <conio.h> /* for kbhit */
|
||||
#include <conio.h> /* for kbhit */
|
||||
#include "config.h"
|
||||
#include "bacdef.h"
|
||||
#include "npdu.h"
|
||||
@@ -45,23 +45,23 @@
|
||||
#define _USER32_
|
||||
#define _KERNEL32_
|
||||
#include <windows.h>
|
||||
#include <rttarget.h> /* for RTCMOSSetSystemTime */
|
||||
#include <rtfiles.h> /* file system */
|
||||
#include <rtfsys.h> /* file system */
|
||||
#include <rttarget.h> /* for RTCMOSSetSystemTime */
|
||||
#include <rtfiles.h> /* file system */
|
||||
#include <rtfsys.h> /* file system */
|
||||
#include <Rttbios.h>
|
||||
#endif
|
||||
#include <rtcom.h> /* serial port driver */
|
||||
#include <itimer.h> /* time measurement & timer interrupt rate control */
|
||||
#include <rtkeybrd.h> /* interrupt handler for the keyboard */
|
||||
#include <rtcom.h> /* serial port driver */
|
||||
#include <itimer.h> /* time measurement & timer interrupt rate control */
|
||||
#include <rtkeybrd.h> /* interrupt handler for the keyboard */
|
||||
|
||||
/* buffers used for transmit and receive */
|
||||
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||
|
||||
static void Init_Service_Handlers(void)
|
||||
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,
|
||||
handler_who_is);
|
||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
||||
/* 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
|
||||
@@ -73,10 +73,11 @@ static void Init_Service_Handlers(void)
|
||||
handler_write_property);
|
||||
}
|
||||
|
||||
void millisecond_task(void)
|
||||
void millisecond_task(
|
||||
void)
|
||||
{
|
||||
Time ticks = 0; /* task cycle */
|
||||
int i = 0; /* loop counter */
|
||||
Time ticks = 0; /* task cycle */
|
||||
int i = 0; /* loop counter */
|
||||
|
||||
ticks = RTKGetTime() + MilliSecsToTicks(1);
|
||||
while (TRUE) {
|
||||
@@ -86,11 +87,12 @@ void millisecond_task(void)
|
||||
}
|
||||
}
|
||||
|
||||
void RTOS_Initialize(void)
|
||||
void RTOS_Initialize(
|
||||
void)
|
||||
{
|
||||
/* allow OS to setup IRQ 1 by using a dummy call */
|
||||
(void) kbhit();
|
||||
RTKernelInit(5); /* get the kernel going */
|
||||
RTKernelInit(5); /* get the kernel going */
|
||||
RTKeybrdInit();
|
||||
/*(void)CPUMoniInit(); /* not needed - just monitor idle task */ */
|
||||
RTComInit();
|
||||
@@ -128,7 +130,9 @@ void RTOS_Initialize(void)
|
||||
RTKCreateTask(millisecond_task, 16, 1024 * 8, "millisec task");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
int main(
|
||||
int argc,
|
||||
char *argv[])
|
||||
{
|
||||
BACNET_ADDRESS src = { 0 }; /* address where message came from */
|
||||
uint16_t pdu_len = 0;
|
||||
|
||||
+873
-860
File diff suppressed because it is too large
Load Diff
@@ -201,7 +201,7 @@ struct mstp_port_struct_t {
|
||||
/* This array is only used for APDU messages */
|
||||
uint8_t TxBuffer[MAX_MPDU];
|
||||
unsigned TxLength;
|
||||
bool TxReady; /* true if ready to be sent or received */
|
||||
bool TxReady; /* true if ready to be sent or received */
|
||||
uint8_t TxFrameType; /* type of message - needed by MS/TP */
|
||||
};
|
||||
|
||||
@@ -215,30 +215,36 @@ struct mstp_port_struct_t {
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void MSTP_Init(volatile struct mstp_port_struct_t *mstp_port,
|
||||
void MSTP_Init(
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
uint8_t this_station_mac);
|
||||
void MSTP_Millisecond_Timer(volatile struct mstp_port_struct_t
|
||||
void MSTP_Millisecond_Timer(
|
||||
volatile struct mstp_port_struct_t
|
||||
*mstp_port);
|
||||
void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t
|
||||
void MSTP_Receive_Frame_FSM(
|
||||
volatile struct mstp_port_struct_t
|
||||
*mstp_port);
|
||||
bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t
|
||||
bool MSTP_Master_Node_FSM(
|
||||
volatile struct mstp_port_struct_t
|
||||
*mstp_port);
|
||||
|
||||
/* returns true if line is active */
|
||||
bool MSTP_Line_Active(volatile struct mstp_port_struct_t *mstp_port);
|
||||
bool MSTP_Line_Active(
|
||||
volatile struct mstp_port_struct_t *mstp_port);
|
||||
|
||||
unsigned MSTP_Create_Frame(uint8_t * buffer, /* where frame is loaded */
|
||||
unsigned MSTP_Create_Frame(
|
||||
uint8_t * buffer, /* where frame is loaded */
|
||||
unsigned buffer_len, /* amount of space available */
|
||||
uint8_t frame_type, /* type of frame to send - see defines */
|
||||
uint8_t destination, /* destination address */
|
||||
uint8_t source, /* source address */
|
||||
uint8_t * data, /* any data to be sent - may be null */
|
||||
uint8_t source, /* source address */
|
||||
uint8_t * data, /* any data to be sent - may be null */
|
||||
unsigned data_len); /* number of bytes of data (up to 501) */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -31,17 +31,17 @@
|
||||
/* #define AUTO_IP // use xn_autoip() to get an IP address */
|
||||
/* #define DHCP // if you enable this, you must also link library dhcpc.lib */
|
||||
|
||||
#if defined(AUTO_IP) /* use xn_autoip() to get an IP address */
|
||||
#if defined(AUTO_IP) /* use xn_autoip() to get an IP address */
|
||||
static BYTE TargetIP[] = { 0, 0, 0, 0 }; /* will be filled at run-time */
|
||||
static BYTE NetMask[] = { 255, 255, 255, 0 };
|
||||
static BYTE MinIP[] = { 192, 168, 0, 128 };
|
||||
static BYTE MaxIP[] = { 192, 168, 0, 255 };
|
||||
static BYTE DefaultGateway[] = { 192, 168, 0, 1 }; /* set to zero if not available or required */
|
||||
static BYTE DNSServer[] = { 192, 168, 0, 1 }; /* ditto */
|
||||
#elif defined(DHCP) /* use DHCP */
|
||||
#elif defined(DHCP) /* use DHCP */
|
||||
#include <dhcpcapi.h>
|
||||
static BYTE TargetIP[] = { 0, 0, 0, 0 }; /* will be filled at run-time */
|
||||
#else /* static IP address assignment (default) */
|
||||
#else /* static IP address assignment (default) */
|
||||
static BYTE TargetIP[] = { 192, 168, 0, 50 };
|
||||
static BYTE NetMask[] = { 255, 255, 255, 0 };
|
||||
static BYTE DefaultGateway[] = { 192, 168, 0, 1 }; /* set to zero if not available or required */
|
||||
@@ -59,8 +59,8 @@ static BYTE DNSServer[] = { 192, 168, 0, 1 }; /* ditto */
|
||||
/* PCI devices if you do not have a BIOS */
|
||||
|
||||
#define ED_IO_ADD 0x300 /* I/O address of the device */
|
||||
#define ED_IRQ 5 /* IRQ of the device */
|
||||
#define ED_MEM_ADD 0 /* Memory Window (only some devices) */
|
||||
#define ED_IRQ 5 /* IRQ of the device */
|
||||
#define ED_MEM_ADD 0 /* Memory Window (only some devices) */
|
||||
|
||||
/* Define function to pull in the required driver */
|
||||
|
||||
@@ -87,17 +87,17 @@ static BYTE DNSServer[] = { 192, 168, 0, 1 }; /* ditto */
|
||||
#elif DEVICE_ID == RHINE_DEVICE
|
||||
#define BIND_DRIVER xn_bind_rhine
|
||||
#elif DEVICE_ID == AX172_DEVICE
|
||||
#include <rtusb.h> /* must also link Rtusb.lib and UsbInit.cpp */
|
||||
#include <rtusb.h> /* must also link Rtusb.lib and UsbInit.cpp */
|
||||
#define BIND_DRIVER xn_bind_ax172
|
||||
#elif DEVICE_ID == AX772_DEVICE
|
||||
#include <rtusb.h> /* must also link Rtusb.lib and UsbInit.cpp */
|
||||
#include <rtusb.h> /* must also link Rtusb.lib and UsbInit.cpp */
|
||||
#define BIND_DRIVER xn_bind_ax772
|
||||
#elif DEVICE_ID == PRISM_DEVICE
|
||||
#include <wlanapi.h> /* must also link Wlan.lib */
|
||||
#include <wlanapi.h> /* must also link Wlan.lib */
|
||||
#define BIND_DRIVER xn_bind_prism
|
||||
#elif DEVICE_ID == PRISM_PCMCIA_DEVICE
|
||||
#include <rtpcmcia.h>
|
||||
#include <wlanapi.h> /* must also link Wlan.lib */
|
||||
#include <wlanapi.h> /* must also link Wlan.lib */
|
||||
#define BIND_DRIVER xn_bind_prism_pcmcia
|
||||
#else
|
||||
#error Invalid DEVICE_ID value
|
||||
|
||||
@@ -57,10 +57,13 @@ static FineTime RS485_Debug_Transmit_Timer;
|
||||
#endif
|
||||
|
||||
#if PRINT_ENABLED_RS485
|
||||
void RS485_Print_Frame(int port, FineTime timer, uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
||||
void RS485_Print_Frame(
|
||||
int port,
|
||||
FineTime timer,
|
||||
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
||||
uint16_t nbytes)
|
||||
{
|
||||
uint16_t i; /* byte counter */
|
||||
uint16_t i; /* byte counter */
|
||||
unsigned long duration; /* measures the time from last output to this one */
|
||||
unsigned long seconds;
|
||||
unsigned long milliseconds;
|
||||
@@ -79,33 +82,36 @@ void RS485_Print_Frame(int port, FineTime timer, uint8_t * buffer, /* frame
|
||||
}
|
||||
#endif
|
||||
|
||||
static void RS485_Standard_Port_Settings(long port, long *pIRQ,
|
||||
static void RS485_Standard_Port_Settings(
|
||||
long port,
|
||||
long *pIRQ,
|
||||
long *pBase)
|
||||
{
|
||||
switch (port) {
|
||||
case COM1:
|
||||
*pBase = (long) 0x3F8;
|
||||
*pIRQ = 4L;
|
||||
break;
|
||||
case COM2:
|
||||
*pBase = (long) 0x2F8;
|
||||
*pIRQ = 3L;
|
||||
break;
|
||||
case COM3:
|
||||
*pBase = (long) 0x3E8;
|
||||
*pIRQ = 4L;
|
||||
break;
|
||||
case COM4:
|
||||
*pBase = (long) 0x2E8;
|
||||
*pIRQ = 3L;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case COM1:
|
||||
*pBase = (long) 0x3F8;
|
||||
*pIRQ = 4L;
|
||||
break;
|
||||
case COM2:
|
||||
*pBase = (long) 0x2F8;
|
||||
*pIRQ = 3L;
|
||||
break;
|
||||
case COM3:
|
||||
*pBase = (long) 0x3E8;
|
||||
*pIRQ = 4L;
|
||||
break;
|
||||
case COM4:
|
||||
*pBase = (long) 0x2E8;
|
||||
*pIRQ = 3L;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int TestCOMPort(int Base)
|
||||
{ /* base address of UART */
|
||||
static int TestCOMPort(
|
||||
int Base)
|
||||
{ /* base address of UART */
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
@@ -117,11 +123,12 @@ static int TestCOMPort(int Base)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static RS485_Open_Port(int port, /* COM port number - COM1 = 0 */
|
||||
long baud, /* baud rate */
|
||||
unsigned base, /* io base address */
|
||||
static RS485_Open_Port(
|
||||
int port, /* COM port number - COM1 = 0 */
|
||||
long baud, /* baud rate */
|
||||
unsigned base, /* io base address */
|
||||
int irq)
|
||||
{ /* hardware IRQ number */
|
||||
{ /* hardware IRQ number */
|
||||
if (!TestCOMPort(base))
|
||||
return;
|
||||
|
||||
@@ -148,21 +155,22 @@ static RS485_Open_Port(int port, /* COM port number - COM1 = 0 */
|
||||
return;
|
||||
}
|
||||
|
||||
void RS485_Initialize(void)
|
||||
void RS485_Initialize(
|
||||
void)
|
||||
{
|
||||
#if PRINT_ENABLED_RS485
|
||||
MarkTime(&RS485_Debug_Transmit_Timer);
|
||||
#endif
|
||||
RS485_Standard_Port_Settings(RS485_Port, &RS485_IRQ_Number,
|
||||
&RS485_Base);
|
||||
RS485_Standard_Port_Settings(RS485_Port, &RS485_IRQ_Number, &RS485_Base);
|
||||
RS485_Open_Port(RS485_Port, RS485_Baud, RS485_Base, RS485_IRQ_Number);
|
||||
}
|
||||
|
||||
void RS485_Send_Frame(volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
||||
void RS485_Send_Frame(
|
||||
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
||||
uint16_t nbytes)
|
||||
{ /* number of bytes of data (up to 501) */
|
||||
bool status = true; /* return value */
|
||||
{ /* number of bytes of data (up to 501) */
|
||||
bool status = true; /* return value */
|
||||
|
||||
RS485_TRANSMIT_ENABLE(RS485_Port);
|
||||
SendBlock(RS485_Port, (char *) buffer, nbytes);
|
||||
@@ -184,8 +192,9 @@ void RS485_Send_Frame(volatile struct mstp_port_struct_t *mstp_port, /* port
|
||||
return;
|
||||
}
|
||||
|
||||
void RS485_Check_UART_Data(volatile struct mstp_port_struct_t *mstp_port)
|
||||
{ /* port specific data */
|
||||
void RS485_Check_UART_Data(
|
||||
volatile struct mstp_port_struct_t *mstp_port)
|
||||
{ /* port specific data */
|
||||
COMData com_data = 0; /* byte from COM driver */
|
||||
unsigned timeout = 1; /* milliseconds to wait for a character */
|
||||
static Duration ticks = 0; /* duration to wait for data */
|
||||
|
||||
@@ -41,17 +41,20 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void RS485_Initialize(void);
|
||||
void RS485_Initialize(
|
||||
void);
|
||||
|
||||
void RS485_Send_Frame(volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||
void RS485_Send_Frame(
|
||||
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
||||
uint16_t nbytes); /* number of bytes of data (up to 501) */
|
||||
|
||||
void RS485_Check_UART_Data(volatile struct mstp_port_struct_t *mstp_port); /* port specific data */
|
||||
void RS485_Check_UART_Data(
|
||||
volatile struct mstp_port_struct_t *mstp_port); /* port specific data */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -16,4 +16,4 @@ typedef signed long int32_t; /* 4 bytes -2147483647 to 2147483647 */
|
||||
/* typedef signed long long int64_t; */
|
||||
/* typedef unsigned long long uint64_t; */
|
||||
|
||||
#endif /* STDINT_H */
|
||||
#endif /* STDINT_H */
|
||||
|
||||
@@ -34,15 +34,16 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include "bacdcode.h"
|
||||
#include "bip.h"
|
||||
#include "net.h"
|
||||
|
||||
bool BIP_Debug = false;
|
||||
/* To fill a need, we invent the gethostaddr() function. */
|
||||
static long gethostaddr(void)
|
||||
static long gethostaddr(
|
||||
void)
|
||||
{
|
||||
struct hostent *host_ent;
|
||||
char host_name[255];
|
||||
@@ -54,16 +55,17 @@ static long gethostaddr(void)
|
||||
return -1;
|
||||
if (BIP_Debug) {
|
||||
printf("host: %s at %u.%u.%u.%u\n", host_name,
|
||||
((uint8_t*)host_ent->h_addr)[0],
|
||||
((uint8_t*)host_ent->h_addr)[1],
|
||||
((uint8_t*)host_ent->h_addr)[2],
|
||||
((uint8_t*)host_ent->h_addr)[3]);
|
||||
((uint8_t *) host_ent->h_addr)[0],
|
||||
((uint8_t *) host_ent->h_addr)[1],
|
||||
((uint8_t *) host_ent->h_addr)[2],
|
||||
((uint8_t *) host_ent->h_addr)[3]);
|
||||
}
|
||||
/* note: network byte order */
|
||||
return *(long *) host_ent->h_addr;
|
||||
}
|
||||
|
||||
static void set_broadcast_address(uint32_t net_address)
|
||||
static void set_broadcast_address(
|
||||
uint32_t net_address)
|
||||
{
|
||||
#if USE_INADDR
|
||||
/* Note: sometimes INADDR_BROADCAST does not let me get
|
||||
@@ -91,14 +93,16 @@ static void set_broadcast_address(uint32_t net_address)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void cleanup(void)
|
||||
static void cleanup(
|
||||
void)
|
||||
{
|
||||
WSACleanup();
|
||||
}
|
||||
|
||||
|
||||
/* on Windows, ifname is the dotted ip address of the interface */
|
||||
void bip_set_interface(char *ifname)
|
||||
void bip_set_interface(
|
||||
char *ifname)
|
||||
{
|
||||
struct in_addr address;
|
||||
|
||||
@@ -117,7 +121,8 @@ void bip_set_interface(char *ifname)
|
||||
}
|
||||
}
|
||||
|
||||
static char *winsock_error_code_text(int code)
|
||||
static char *winsock_error_code_text(
|
||||
int code)
|
||||
{
|
||||
switch (code) {
|
||||
case WSAEACCES:
|
||||
@@ -135,7 +140,8 @@ static char *winsock_error_code_text(int code)
|
||||
case WSAEWOULDBLOCK:
|
||||
return "Operation would block.";
|
||||
case WSAEINPROGRESS:
|
||||
return "Operation now in progress. This error is returned if any Windows Sockets API function is called while a blocking function is in progress.";
|
||||
return
|
||||
"Operation now in progress. This error is returned if any Windows Sockets API function is called while a blocking function is in progress.";
|
||||
case WSAENOTSOCK:
|
||||
return "Socket operation on nonsocket.";
|
||||
case WSAEDESTADDRREQ:
|
||||
@@ -161,7 +167,8 @@ static char *winsock_error_code_text(int code)
|
||||
case WSAEADDRNOTAVAIL:
|
||||
return "Cannot assign requested address.";
|
||||
case WSAENETDOWN:
|
||||
return "Network is down. This error may be reported at any time if the Windows Sockets implementation detects an underlying failure.";
|
||||
return
|
||||
"Network is down. This error may be reported at any time if the Windows Sockets implementation detects an underlying failure.";
|
||||
case WSAENETUNREACH:
|
||||
return "Network is unreachable.";
|
||||
case WSAENETRESET:
|
||||
@@ -194,41 +201,43 @@ static char *winsock_error_code_text(int code)
|
||||
return "No route to host.";
|
||||
case WSASYSNOTREADY:
|
||||
return "Returned by WSAStartup(), "
|
||||
"indicating that the network subsystem is unusable.";
|
||||
"indicating that the network subsystem is unusable.";
|
||||
case WSAVERNOTSUPPORTED:
|
||||
return "Returned by WSAStartup(), "
|
||||
"indicating that the Windows Sockets DLL cannot support "
|
||||
"this application.";
|
||||
"indicating that the Windows Sockets DLL cannot support "
|
||||
"this application.";
|
||||
case WSANOTINITIALISED:
|
||||
return "Winsock not initialized. "
|
||||
"This message is returned by any function except WSAStartup(), "
|
||||
"indicating that a successful WSAStartup() has not yet "
|
||||
"been performed.";
|
||||
"This message is returned by any function except WSAStartup(), "
|
||||
"indicating that a successful WSAStartup() has not yet "
|
||||
"been performed.";
|
||||
case WSAEDISCON:
|
||||
return "Disconnect.";
|
||||
case WSAHOST_NOT_FOUND:
|
||||
return "Host not found. "
|
||||
"This message indicates that the key "
|
||||
"(name, address, and so on) was not found.";
|
||||
"This message indicates that the key "
|
||||
"(name, address, and so on) was not found.";
|
||||
case WSATRY_AGAIN:
|
||||
return "Nonauthoritative host not found. "
|
||||
"This error may suggest that the name service itself "
|
||||
"is not functioning.";
|
||||
"This error may suggest that the name service itself "
|
||||
"is not functioning.";
|
||||
case WSANO_RECOVERY:
|
||||
return "Nonrecoverable error. "
|
||||
"This error may suggest that the name service itself "
|
||||
"is not functioning.";
|
||||
"This error may suggest that the name service itself "
|
||||
"is not functioning.";
|
||||
case WSANO_DATA:
|
||||
return "Valid name, no data record of requested type. "
|
||||
"This error indicates that the key "
|
||||
"(name, address, and so on) was not found.";
|
||||
default: return "unknown";
|
||||
"This error indicates that the key "
|
||||
"(name, address, and so on) was not found.";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
bool bip_init(char *ifname)
|
||||
bool bip_init(
|
||||
char *ifname)
|
||||
{
|
||||
int rv = 0; /* return from socket lib calls */
|
||||
int rv = 0; /* return from socket lib calls */
|
||||
struct sockaddr_in sin = { -1 };
|
||||
int value = 1;
|
||||
int sock_fd = -1;
|
||||
@@ -243,8 +252,7 @@ bool bip_init(char *ifname)
|
||||
if (Result != 0) {
|
||||
Code = WSAGetLastError();
|
||||
printf("TCP/IP stack initialization failed\n"
|
||||
" error code: %i %s\n",
|
||||
Code, winsock_error_code_text(Code));
|
||||
" error code: %i %s\n", Code, winsock_error_code_text(Code));
|
||||
exit(1);
|
||||
}
|
||||
atexit(cleanup);
|
||||
@@ -258,8 +266,7 @@ bool bip_init(char *ifname)
|
||||
if (address.s_addr == (unsigned) -1) {
|
||||
Code = WSAGetLastError();
|
||||
printf("Get host address failed\n"
|
||||
" error code: %i %s\n",
|
||||
Code, winsock_error_code_text(Code));
|
||||
" error code: %i %s\n", Code, winsock_error_code_text(Code));
|
||||
exit(1);
|
||||
}
|
||||
bip_set_addr(address.s_addr);
|
||||
@@ -276,8 +283,7 @@ bool bip_init(char *ifname)
|
||||
fprintf(stderr, "IP Broadcast Address: %s\n",
|
||||
inet_ntoa(broadcast_address));
|
||||
fprintf(stderr, "UDP Port: 0x%04X [%hu]\n",
|
||||
bip_get_port(),
|
||||
bip_get_port());
|
||||
bip_get_port(), bip_get_port());
|
||||
}
|
||||
/* assumes that the driver has already been initialized */
|
||||
sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
|
||||
+135
-122
@@ -58,21 +58,25 @@ static uint8_t RxBuffer[MAX_MPDU];
|
||||
/* Timer that indicates line silence - and functions */
|
||||
static uint16_t SilenceTime;
|
||||
#define INCREMENT_AND_LIMIT_UINT16(x) {if (x < 0xFFFF) x++;}
|
||||
static uint16_t Timer_Silence(void)
|
||||
static uint16_t Timer_Silence(
|
||||
void)
|
||||
{
|
||||
return SilenceTime;
|
||||
}
|
||||
static void Timer_Silence_Reset(void)
|
||||
static void Timer_Silence_Reset(
|
||||
void)
|
||||
{
|
||||
SilenceTime = 0;
|
||||
}
|
||||
|
||||
void dlmstp_millisecond_timer(void)
|
||||
void dlmstp_millisecond_timer(
|
||||
void)
|
||||
{
|
||||
INCREMENT_AND_LIMIT_UINT16(SilenceTime);
|
||||
}
|
||||
|
||||
void dlmstp_reinit(void)
|
||||
void dlmstp_reinit(
|
||||
void)
|
||||
{
|
||||
/*RS485_Reinit(); */
|
||||
dlmstp_set_mac_address(DEFAULT_MAC_ADDRESS);
|
||||
@@ -80,7 +84,8 @@ void dlmstp_reinit(void)
|
||||
dlmstp_set_max_master(DEFAULT_MAX_MASTER);
|
||||
}
|
||||
|
||||
void dlmstp_cleanup(void)
|
||||
void dlmstp_cleanup(
|
||||
void)
|
||||
{
|
||||
/* nothing to do for static buffers */
|
||||
if (Received_Frame_Flag) {
|
||||
@@ -92,11 +97,12 @@ void dlmstp_cleanup(void)
|
||||
}
|
||||
|
||||
/* returns number of bytes sent on success, zero on failure */
|
||||
int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
int dlmstp_send_pdu(
|
||||
BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len)
|
||||
{ /* number of bytes of data */
|
||||
{ /* number of bytes of data */
|
||||
int bytes_sent = 0;
|
||||
unsigned i = 0;
|
||||
|
||||
@@ -121,18 +127,18 @@ int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
}
|
||||
|
||||
uint16_t dlmstp_receive(
|
||||
BACNET_ADDRESS * src, /* source address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t max_pdu, /* amount of space available in the PDU */
|
||||
unsigned timeout) /* milliseconds to wait for a packet */
|
||||
{
|
||||
BACNET_ADDRESS * src, /* source address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t max_pdu, /* amount of space available in the PDU */
|
||||
unsigned timeout)
|
||||
{ /* milliseconds to wait for a packet */
|
||||
uint16_t pdu_len = 0;
|
||||
DWORD wait_status = 0;
|
||||
|
||||
(void)max_pdu;
|
||||
(void) max_pdu;
|
||||
/* see if there is a packet available, and a place
|
||||
to put the reply (if necessary) and process it */
|
||||
wait_status = WaitForSingleObject(Receive_Packet_Flag,timeout);
|
||||
wait_status = WaitForSingleObject(Receive_Packet_Flag, timeout);
|
||||
if (wait_status == WAIT_OBJECT_0) {
|
||||
if (Receive_Packet.ready) {
|
||||
if (Receive_Packet.pdu_len) {
|
||||
@@ -144,8 +150,7 @@ uint16_t dlmstp_receive(
|
||||
}
|
||||
if (pdu) {
|
||||
memmove(pdu,
|
||||
&Receive_Packet.pdu,
|
||||
sizeof(Receive_Packet.pdu));
|
||||
&Receive_Packet.pdu, sizeof(Receive_Packet.pdu));
|
||||
}
|
||||
pdu_len = Receive_Packet.pdu_len;
|
||||
}
|
||||
@@ -156,12 +161,14 @@ uint16_t dlmstp_receive(
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
static void dlmstp_receive_fsm_task(void *pArg)
|
||||
static void dlmstp_receive_fsm_task(
|
||||
void *pArg)
|
||||
{
|
||||
bool received_frame;
|
||||
|
||||
(void)pArg;
|
||||
(void)SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
|
||||
(void) pArg;
|
||||
(void) SetThreadPriority(GetCurrentThread(),
|
||||
THREAD_PRIORITY_TIME_CRITICAL);
|
||||
while (TRUE) {
|
||||
/* only do receive state machine while we don't have a frame */
|
||||
if ((MSTP_Port.ReceivedValidFrame == false) &&
|
||||
@@ -180,12 +187,14 @@ static void dlmstp_receive_fsm_task(void *pArg)
|
||||
}
|
||||
}
|
||||
|
||||
static void dlmstp_master_fsm_task(void *pArg)
|
||||
static void dlmstp_master_fsm_task(
|
||||
void *pArg)
|
||||
{
|
||||
DWORD dwMilliseconds = 0;
|
||||
|
||||
(void)pArg;
|
||||
(void)SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
|
||||
(void) pArg;
|
||||
(void) SetThreadPriority(GetCurrentThread(),
|
||||
THREAD_PRIORITY_TIME_CRITICAL);
|
||||
while (TRUE) {
|
||||
switch (MSTP_Port.master_state) {
|
||||
case MSTP_MASTER_STATE_IDLE:
|
||||
@@ -202,22 +211,26 @@ static void dlmstp_master_fsm_task(void *pArg)
|
||||
break;
|
||||
}
|
||||
if (dwMilliseconds)
|
||||
WaitForSingleObject(Received_Frame_Flag,dwMilliseconds);
|
||||
WaitForSingleObject(Received_Frame_Flag, dwMilliseconds);
|
||||
MSTP_Master_Node_FSM(&MSTP_Port);
|
||||
}
|
||||
}
|
||||
|
||||
static void dlmstp_millisecond_task(void *pArg)
|
||||
static void dlmstp_millisecond_task(
|
||||
void *pArg)
|
||||
{
|
||||
(void)pArg;
|
||||
(void)SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
|
||||
(void) pArg;
|
||||
(void) SetThreadPriority(GetCurrentThread(),
|
||||
THREAD_PRIORITY_TIME_CRITICAL);
|
||||
for (;;) {
|
||||
dlmstp_millisecond_timer();
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
void dlmstp_fill_bacnet_address(BACNET_ADDRESS * src, uint8_t mstp_address)
|
||||
void dlmstp_fill_bacnet_address(
|
||||
BACNET_ADDRESS * src,
|
||||
uint8_t mstp_address)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
@@ -242,7 +255,7 @@ void dlmstp_fill_bacnet_address(BACNET_ADDRESS * src, uint8_t mstp_address)
|
||||
|
||||
/* for the MS/TP state machine to use for putting received data */
|
||||
uint16_t MSTP_Put_Receive(
|
||||
volatile struct mstp_port_struct_t *mstp_port)
|
||||
volatile struct mstp_port_struct_t *mstp_port)
|
||||
{
|
||||
uint16_t pdu_len = 0;
|
||||
BOOL rc;
|
||||
@@ -252,9 +265,8 @@ uint16_t MSTP_Put_Receive(
|
||||
pdu_len = mstp_port->DataLength;
|
||||
if (pdu_len > sizeof(Receive_Packet.pdu))
|
||||
pdu_len = sizeof(Receive_Packet.pdu);
|
||||
memmove((void *) & Receive_Packet.pdu[0],
|
||||
(void *) & mstp_port->InputBuffer[0],
|
||||
pdu_len);
|
||||
memmove((void *) &Receive_Packet.pdu[0],
|
||||
(void *) &mstp_port->InputBuffer[0], pdu_len);
|
||||
dlmstp_fill_bacnet_address(&Receive_Packet.address,
|
||||
mstp_port->SourceAddress);
|
||||
Receive_Packet.pdu_len = mstp_port->DataLength;
|
||||
@@ -268,13 +280,13 @@ uint16_t MSTP_Put_Receive(
|
||||
/* for the MS/TP state machine to use for getting data to send */
|
||||
/* Return: amount of PDU data */
|
||||
uint16_t MSTP_Get_Send(
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
unsigned timeout) /* milliseconds to wait for a packet */
|
||||
{
|
||||
volatile struct mstp_port_struct_t * mstp_port,
|
||||
unsigned timeout)
|
||||
{ /* milliseconds to wait for a packet */
|
||||
uint16_t pdu_len = 0;
|
||||
uint8_t destination = 0; /* destination address */
|
||||
|
||||
(void)timeout;
|
||||
(void) timeout;
|
||||
if (!Transmit_Packet.ready) {
|
||||
return 0;
|
||||
}
|
||||
@@ -288,26 +300,24 @@ uint16_t MSTP_Get_Send(
|
||||
return 0;
|
||||
}
|
||||
/* convert the PDU into the MSTP Frame */
|
||||
pdu_len = MSTP_Create_Frame(
|
||||
&mstp_port->OutputBuffer[0], /* <-- loading this */
|
||||
pdu_len = MSTP_Create_Frame(&mstp_port->OutputBuffer[0], /* <-- loading this */
|
||||
mstp_port->OutputBufferSize,
|
||||
Transmit_Packet.frame_type,
|
||||
destination,
|
||||
mstp_port->This_Station,
|
||||
&Transmit_Packet.pdu[0],
|
||||
Transmit_Packet.pdu_len);
|
||||
&Transmit_Packet.pdu[0], Transmit_Packet.pdu_len);
|
||||
Transmit_Packet.ready = false;
|
||||
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
bool dlmstp_compare_data_expecting_reply(
|
||||
uint8_t *request_pdu,
|
||||
uint8_t * request_pdu,
|
||||
uint16_t request_pdu_len,
|
||||
uint8_t src_address,
|
||||
uint8_t *reply_pdu,
|
||||
uint8_t * reply_pdu,
|
||||
uint16_t reply_pdu_len,
|
||||
BACNET_ADDRESS *dest_address)
|
||||
BACNET_ADDRESS * dest_address)
|
||||
{
|
||||
uint16_t offset;
|
||||
/* One way to check the message is to compare NPDU
|
||||
@@ -335,12 +345,12 @@ bool dlmstp_compare_data_expecting_reply(
|
||||
if (request.pdu_type != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) {
|
||||
return false;
|
||||
}
|
||||
request.invoke_id = request_pdu[offset+2];
|
||||
request.invoke_id = request_pdu[offset + 2];
|
||||
/* segmented message? */
|
||||
if (request_pdu[offset] & BIT3)
|
||||
request.service_choice = request_pdu[offset+5];
|
||||
request.service_choice = request_pdu[offset + 5];
|
||||
else
|
||||
request.service_choice = request_pdu[offset+3];
|
||||
request.service_choice = request_pdu[offset + 3];
|
||||
/* decode the reply data */
|
||||
bacnet_address_copy(&reply.address, dest_address);
|
||||
offset = npdu_decode(&reply_pdu[0],
|
||||
@@ -353,32 +363,32 @@ bool dlmstp_compare_data_expecting_reply(
|
||||
reply.pdu_type = reply_pdu[offset] & 0xF0;
|
||||
switch (reply.pdu_type) {
|
||||
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
|
||||
reply.invoke_id = reply_pdu[offset+2];
|
||||
reply.invoke_id = reply_pdu[offset + 2];
|
||||
/* segmented message? */
|
||||
if (reply_pdu[offset] & BIT3)
|
||||
reply.service_choice = reply_pdu[offset+5];
|
||||
reply.service_choice = reply_pdu[offset + 5];
|
||||
else
|
||||
reply.service_choice = reply_pdu[offset+3];
|
||||
reply.service_choice = reply_pdu[offset + 3];
|
||||
break;
|
||||
case PDU_TYPE_SIMPLE_ACK:
|
||||
reply.invoke_id = reply_pdu[offset+1];
|
||||
reply.service_choice = reply_pdu[offset+2];
|
||||
reply.invoke_id = reply_pdu[offset + 1];
|
||||
reply.service_choice = reply_pdu[offset + 2];
|
||||
break;
|
||||
case PDU_TYPE_COMPLEX_ACK:
|
||||
reply.invoke_id = reply_pdu[offset+1];
|
||||
reply.invoke_id = reply_pdu[offset + 1];
|
||||
/* segmented message? */
|
||||
if (reply_pdu[offset] & BIT3)
|
||||
reply.service_choice = reply_pdu[offset+4];
|
||||
reply.service_choice = reply_pdu[offset + 4];
|
||||
else
|
||||
reply.service_choice = reply_pdu[offset+2];
|
||||
reply.service_choice = reply_pdu[offset + 2];
|
||||
break;
|
||||
case PDU_TYPE_ERROR:
|
||||
reply.invoke_id = reply_pdu[offset+1];
|
||||
reply.service_choice = reply_pdu[offset+2];
|
||||
reply.invoke_id = reply_pdu[offset + 1];
|
||||
reply.service_choice = reply_pdu[offset + 2];
|
||||
break;
|
||||
case PDU_TYPE_REJECT:
|
||||
case PDU_TYPE_ABORT:
|
||||
reply.invoke_id = reply_pdu[offset+1];
|
||||
reply.invoke_id = reply_pdu[offset + 1];
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
@@ -412,14 +422,14 @@ bool dlmstp_compare_data_expecting_reply(
|
||||
|
||||
/* Get the reply to a DATA_EXPECTING_REPLY frame, or nothing */
|
||||
uint16_t MSTP_Get_Reply(
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
unsigned timeout) /* milliseconds to wait for a packet */
|
||||
{
|
||||
uint16_t pdu_len = 0; /* return value */
|
||||
volatile struct mstp_port_struct_t * mstp_port,
|
||||
unsigned timeout)
|
||||
{ /* milliseconds to wait for a packet */
|
||||
uint16_t pdu_len = 0; /* return value */
|
||||
uint8_t destination = 0; /* destination address */
|
||||
bool matched = false;
|
||||
|
||||
(void)timeout;
|
||||
(void) timeout;
|
||||
if (!Transmit_Packet.ready) {
|
||||
return 0;
|
||||
}
|
||||
@@ -433,29 +443,26 @@ uint16_t MSTP_Get_Reply(
|
||||
return 0;
|
||||
}
|
||||
/* is this the reply to the DER? */
|
||||
matched = dlmstp_compare_data_expecting_reply(
|
||||
&mstp_port->InputBuffer[0],
|
||||
matched = dlmstp_compare_data_expecting_reply(&mstp_port->InputBuffer[0],
|
||||
mstp_port->DataLength,
|
||||
mstp_port->SourceAddress,
|
||||
&Transmit_Packet.pdu[0],
|
||||
Transmit_Packet.pdu_len,
|
||||
&Transmit_Packet.address);
|
||||
Transmit_Packet.pdu_len, &Transmit_Packet.address);
|
||||
if (!matched)
|
||||
return 0;
|
||||
/* convert the PDU into the MSTP Frame */
|
||||
pdu_len = MSTP_Create_Frame(
|
||||
&mstp_port->OutputBuffer[0], /* <-- loading this */
|
||||
pdu_len = MSTP_Create_Frame(&mstp_port->OutputBuffer[0], /* <-- loading this */
|
||||
mstp_port->OutputBufferSize,
|
||||
Transmit_Packet.frame_type,
|
||||
destination, mstp_port->This_Station,
|
||||
&Transmit_Packet.pdu[0],
|
||||
Transmit_Packet.pdu_len);
|
||||
&Transmit_Packet.pdu[0], Transmit_Packet.pdu_len);
|
||||
Transmit_Packet.ready = false;
|
||||
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
void dlmstp_set_mac_address(uint8_t mac_address)
|
||||
void dlmstp_set_mac_address(
|
||||
uint8_t mac_address)
|
||||
{
|
||||
/* Master Nodes can only have address 0-127 */
|
||||
if (mac_address <= 127) {
|
||||
@@ -472,7 +479,8 @@ void dlmstp_set_mac_address(uint8_t mac_address)
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t dlmstp_mac_address(void)
|
||||
uint8_t dlmstp_mac_address(
|
||||
void)
|
||||
{
|
||||
return MSTP_Port.This_Station;
|
||||
}
|
||||
@@ -484,7 +492,8 @@ uint8_t dlmstp_mac_address(void)
|
||||
/* nodes. This may be used to allocate more or less of the available link */
|
||||
/* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */
|
||||
/* node, its value shall be 1. */
|
||||
void dlmstp_set_max_info_frames(uint8_t max_info_frames)
|
||||
void dlmstp_set_max_info_frames(
|
||||
uint8_t max_info_frames)
|
||||
{
|
||||
if (max_info_frames >= 1) {
|
||||
MSTP_Port.Nmax_info_frames = max_info_frames;
|
||||
@@ -498,7 +507,8 @@ void dlmstp_set_max_info_frames(uint8_t max_info_frames)
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t dlmstp_max_info_frames(void)
|
||||
uint8_t dlmstp_max_info_frames(
|
||||
void)
|
||||
{
|
||||
return MSTP_Port.Nmax_info_frames;
|
||||
}
|
||||
@@ -508,7 +518,8 @@ uint8_t dlmstp_max_info_frames(void)
|
||||
/* allowable address for master nodes. The value of Max_Master shall be */
|
||||
/* less than or equal to 127. If Max_Master is not writable in a node, */
|
||||
/* its value shall be 127. */
|
||||
void dlmstp_set_max_master(uint8_t max_master)
|
||||
void dlmstp_set_max_master(
|
||||
uint8_t max_master)
|
||||
{
|
||||
if (max_master <= 127) {
|
||||
if (MSTP_Port.This_Station <= max_master) {
|
||||
@@ -524,25 +535,29 @@ void dlmstp_set_max_master(uint8_t max_master)
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t dlmstp_max_master(void)
|
||||
uint8_t dlmstp_max_master(
|
||||
void)
|
||||
{
|
||||
return MSTP_Port.Nmax_master;
|
||||
}
|
||||
|
||||
/* RS485 Baud Rate 9600, 19200, 38400, 57600, 115200 */
|
||||
void dlmstp_set_baud_rate(uint32_t baud)
|
||||
void dlmstp_set_baud_rate(
|
||||
uint32_t baud)
|
||||
{
|
||||
RS485_Set_Baud_Rate(baud);
|
||||
}
|
||||
|
||||
uint32_t dlmstp_baud_rate(void)
|
||||
uint32_t dlmstp_baud_rate(
|
||||
void)
|
||||
{
|
||||
return RS485_Get_Baud_Rate();
|
||||
return RS485_Get_Baud_Rate();
|
||||
}
|
||||
|
||||
void dlmstp_get_my_address(BACNET_ADDRESS * my_address)
|
||||
void dlmstp_get_my_address(
|
||||
BACNET_ADDRESS * my_address)
|
||||
{
|
||||
int i = 0; /* counter */
|
||||
int i = 0; /* counter */
|
||||
|
||||
my_address->mac_len = 1;
|
||||
my_address->mac[0] = MSTP_Port.This_Station;
|
||||
@@ -555,15 +570,16 @@ void dlmstp_get_my_address(BACNET_ADDRESS * my_address)
|
||||
return;
|
||||
}
|
||||
|
||||
void dlmstp_get_broadcast_address(BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
void dlmstp_get_broadcast_address(
|
||||
BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
|
||||
if (dest) {
|
||||
dest->mac_len = 1;
|
||||
dest->mac[0] = MSTP_BROADCAST_ADDRESS;
|
||||
dest->net = BACNET_BROADCAST_NETWORK;
|
||||
dest->len = 0; /* always zero when DNET is broadcast */
|
||||
dest->len = 0; /* always zero when DNET is broadcast */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
dest->adr[i] = 0;
|
||||
}
|
||||
@@ -572,7 +588,8 @@ void dlmstp_get_broadcast_address(BACNET_ADDRESS * dest)
|
||||
return;
|
||||
}
|
||||
|
||||
bool dlmstp_init(char *ifname)
|
||||
bool dlmstp_init(
|
||||
char *ifname)
|
||||
{
|
||||
unsigned long hThread = 0;
|
||||
uint32_t arg_value = 0;
|
||||
@@ -580,10 +597,10 @@ bool dlmstp_init(char *ifname)
|
||||
/* initialize packet queue */
|
||||
Receive_Packet.ready = false;
|
||||
Receive_Packet.pdu_len = 0;
|
||||
Receive_Packet_Flag = CreateSemaphore (NULL,0,1,"dlmstpReceivePacket");
|
||||
Receive_Packet_Flag = CreateSemaphore(NULL, 0, 1, "dlmstpReceivePacket");
|
||||
if (Receive_Packet_Flag == NULL)
|
||||
exit(1);
|
||||
Received_Frame_Flag = CreateSemaphore (NULL,0,1,"dlsmtpReceiveFrame");
|
||||
Received_Frame_Flag = CreateSemaphore(NULL, 0, 1, "dlsmtpReceiveFrame");
|
||||
if (Received_Frame_Flag == NULL) {
|
||||
CloseHandle(Receive_Packet_Flag);
|
||||
exit(1);
|
||||
@@ -593,7 +610,7 @@ bool dlmstp_init(char *ifname)
|
||||
if (ifname) {
|
||||
RS485_Set_Interface(ifname);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,"MS/TP Interface: %s\n", ifname);
|
||||
fprintf(stderr, "MS/TP Interface: %s\n", ifname);
|
||||
#endif
|
||||
}
|
||||
RS485_Initialize();
|
||||
@@ -608,17 +625,17 @@ bool dlmstp_init(char *ifname)
|
||||
uint8_t data;
|
||||
|
||||
/* FIXME: implement your data storage */
|
||||
data = 64; /* I2C_Read_Byte(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
EEPROM_MSTP_MAC_ADDR); */
|
||||
data = 64; /* I2C_Read_Byte(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
EEPROM_MSTP_MAC_ADDR); */
|
||||
if (data <= 127)
|
||||
MSTP_Port.This_Station = data;
|
||||
else
|
||||
dlmstp_set_my_address(DEFAULT_MAC_ADDRESS);
|
||||
/* FIXME: implement your data storage */
|
||||
data = 127; /* I2C_Read_Byte(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
EEPROM_MSTP_MAX_MASTER_ADDR); */
|
||||
data = 127; /* I2C_Read_Byte(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
EEPROM_MSTP_MAX_MASTER_ADDR); */
|
||||
if ((data <= 127) && (data >= MSTP_Port.This_Station))
|
||||
MSTP_Port.Nmax_master = data;
|
||||
else
|
||||
@@ -634,23 +651,20 @@ bool dlmstp_init(char *ifname)
|
||||
dlmstp_set_max_info_frames(DEFAULT_MAX_INFO_FRAMES);
|
||||
#endif
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,"MS/TP MAC: %02X\n",
|
||||
MSTP_Port.This_Station);
|
||||
fprintf(stderr,"MS/TP Max_Master: %02X\n",
|
||||
MSTP_Port.Nmax_master);
|
||||
fprintf(stderr,"MS/TP Max_Info_Frames: %u\n",
|
||||
MSTP_Port.Nmax_info_frames);
|
||||
fprintf(stderr, "MS/TP MAC: %02X\n", MSTP_Port.This_Station);
|
||||
fprintf(stderr, "MS/TP Max_Master: %02X\n", MSTP_Port.Nmax_master);
|
||||
fprintf(stderr, "MS/TP Max_Info_Frames: %u\n", MSTP_Port.Nmax_info_frames);
|
||||
#endif
|
||||
/* start the threads */
|
||||
hThread = _beginthread(dlmstp_millisecond_task,4096,&arg_value);
|
||||
hThread = _beginthread(dlmstp_millisecond_task, 4096, &arg_value);
|
||||
if (hThread == 0) {
|
||||
fprintf(stderr, "Failed to start timer task\n");
|
||||
}
|
||||
hThread = _beginthread(dlmstp_receive_fsm_task,4096,&arg_value);
|
||||
hThread = _beginthread(dlmstp_receive_fsm_task, 4096, &arg_value);
|
||||
if (hThread == 0) {
|
||||
fprintf(stderr, "Failed to start recive FSM task\n");
|
||||
}
|
||||
hThread = _beginthread(dlmstp_master_fsm_task,4096,&arg_value);
|
||||
hThread = _beginthread(dlmstp_master_fsm_task, 4096, &arg_value);
|
||||
if (hThread == 0) {
|
||||
fprintf(stderr, "Failed to start Master Node FSM task\n");
|
||||
}
|
||||
@@ -661,26 +675,26 @@ bool dlmstp_init(char *ifname)
|
||||
#ifdef TEST_DLMSTP
|
||||
#include <stdio.h>
|
||||
|
||||
void apdu_handler(BACNET_ADDRESS * src, /* source address */
|
||||
uint8_t * apdu, /* APDU data */
|
||||
uint16_t pdu_len) /* for confirmed messages */
|
||||
{
|
||||
(void)src;
|
||||
(void)apdu;
|
||||
(void)pdu_len;
|
||||
void apdu_handler(
|
||||
BACNET_ADDRESS * src, /* source address */
|
||||
uint8_t * apdu, /* APDU data */
|
||||
uint16_t pdu_len)
|
||||
{ /* for confirmed messages */
|
||||
(void) src;
|
||||
(void) apdu;
|
||||
(void) pdu_len;
|
||||
}
|
||||
|
||||
/* returns a delta timestamp */
|
||||
uint32_t timestamp_ms(void)
|
||||
uint32_t timestamp_ms(
|
||||
void)
|
||||
{
|
||||
DWORD ticks = 0, delta_ticks = 0;
|
||||
static DWORD last_ticks = 0;
|
||||
|
||||
ticks = GetTickCount();
|
||||
delta_ticks =
|
||||
(ticks >= last_ticks ?
|
||||
ticks - last_ticks :
|
||||
MAXDWORD - last_ticks);
|
||||
(ticks >= last_ticks ? ticks - last_ticks : MAXDWORD - last_ticks);
|
||||
last_ticks = ticks;
|
||||
|
||||
return delta_ticks;
|
||||
@@ -688,7 +702,9 @@ uint32_t timestamp_ms(void)
|
||||
|
||||
static char *Network_Interface = NULL;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
int main(
|
||||
int argc,
|
||||
char *argv[])
|
||||
{
|
||||
uint16_t pdu_len = 0;
|
||||
|
||||
@@ -703,14 +719,11 @@ int main(int argc, char *argv[])
|
||||
dlmstp_init(Network_Interface);
|
||||
/* forever task */
|
||||
for (;;) {
|
||||
pdu_len = dlmstp_receive(NULL,NULL,0,INFINITE);
|
||||
pdu_len = dlmstp_receive(NULL, NULL, 0, INFINITE);
|
||||
#if 0
|
||||
MSTP_Create_And_Send_Frame(
|
||||
&MSTP_Port,
|
||||
MSTP_Create_And_Send_Frame(&MSTP_Port,
|
||||
FRAME_TYPE_TEST_REQUEST,
|
||||
MSTP_Port.SourceAddress,
|
||||
MSTP_Port.This_Station,
|
||||
NULL, 0);
|
||||
MSTP_Port.SourceAddress, MSTP_Port.This_Station, NULL, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include <assert.h>
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
@@ -78,19 +78,24 @@ static unsigned eth_timeout = 100;
|
||||
/* couple of external func for runtime error logging, you can simply */
|
||||
/* replace them with standard "printf(...)" */
|
||||
/* Logging extern functions: Info level */
|
||||
extern void LogInfo(const char *msg);
|
||||
extern void LogInfo(
|
||||
const char *msg);
|
||||
/* Logging extern functions: Error level*/
|
||||
extern void LogError(const char *msg);
|
||||
extern void LogError(
|
||||
const char *msg);
|
||||
/* Logging extern functions: Debug level*/
|
||||
extern void LogDebug(const char *msg);
|
||||
extern void LogDebug(
|
||||
const char *msg);
|
||||
|
||||
|
||||
bool ethernet_valid(void)
|
||||
bool ethernet_valid(
|
||||
void)
|
||||
{
|
||||
return (pcap_eth802_fp != NULL);
|
||||
}
|
||||
|
||||
void ethernet_cleanup(void)
|
||||
void ethernet_cleanup(
|
||||
void)
|
||||
{
|
||||
if (pcap_eth802_fp) {
|
||||
pcap_close(pcap_eth802_fp);
|
||||
@@ -99,7 +104,8 @@ void ethernet_cleanup(void)
|
||||
LogInfo("ethernet.c: ethernet_cleanup() ok.\n");
|
||||
}
|
||||
|
||||
void ethernet_set_timeout(unsigned timeout)
|
||||
void ethernet_set_timeout(
|
||||
unsigned timeout)
|
||||
{
|
||||
eth_timeout = timeout;
|
||||
}
|
||||
@@ -129,7 +135,8 @@ int setNonblocking(int fd)
|
||||
}
|
||||
*/
|
||||
|
||||
bool ethernet_init(char *if_name)
|
||||
bool ethernet_init(
|
||||
char *if_name)
|
||||
{
|
||||
PPACKET_OID_DATA pOidData;
|
||||
LPADAPTER lpAdapter;
|
||||
@@ -197,11 +204,11 @@ bool ethernet_init(char *if_name)
|
||||
*/
|
||||
/* Open the output device */
|
||||
pcap_eth802_fp = pcap_open(if_name, /* name of the device */
|
||||
MAX_MPDU, /* portion of the packet to capture */
|
||||
MAX_MPDU, /* portion of the packet to capture */
|
||||
PCAP_OPENFLAG_PROMISCUOUS, /* promiscuous mode */
|
||||
eth_timeout, /* read timeout */
|
||||
NULL, /* authentication on the remote machine */
|
||||
pcap_errbuf /* error buffer */
|
||||
eth_timeout, /* read timeout */
|
||||
NULL, /* authentication on the remote machine */
|
||||
pcap_errbuf /* error buffer */
|
||||
);
|
||||
if (pcap_eth802_fp == NULL) {
|
||||
PacketCloseAdapter(lpAdapter);
|
||||
@@ -222,10 +229,11 @@ bool ethernet_init(char *if_name)
|
||||
|
||||
/* function to send a packet out the 802.2 socket */
|
||||
/* returns bytes sent success, negative on failure */
|
||||
int ethernet_send(BACNET_ADDRESS * dest, /* destination address */
|
||||
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 */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len /* number of bytes of data */
|
||||
)
|
||||
{
|
||||
int bytes = 0;
|
||||
@@ -235,8 +243,7 @@ int ethernet_send(BACNET_ADDRESS * dest, /* destination address */
|
||||
|
||||
/* don't waste time if the socket is not valid */
|
||||
if (!ethernet_valid()) {
|
||||
LogError
|
||||
("ethernet.c: invalid 802.2 ethernet interface descriptor!\n");
|
||||
LogError("ethernet.c: invalid 802.2 ethernet interface descriptor!\n");
|
||||
return -1;
|
||||
}
|
||||
/* load destination ethernet MAC address */
|
||||
@@ -265,8 +272,7 @@ int ethernet_send(BACNET_ADDRESS * dest, /* destination address */
|
||||
return -4;
|
||||
}
|
||||
/* packet length */
|
||||
mtu_len +=
|
||||
encode_unsigned16(&mtu[12], 3 /*DSAP,SSAP,LLC */ + pdu_len);
|
||||
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 */
|
||||
@@ -290,12 +296,13 @@ int ethernet_send(BACNET_ADDRESS * dest, /* destination address */
|
||||
|
||||
/* function to send a packet out the 802.2 socket */
|
||||
/* returns number of bytes sent on success, negative 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 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 */
|
||||
int i = 0; /* counter */
|
||||
BACNET_ADDRESS src = { 0 }; /* source address */
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
@@ -305,18 +312,19 @@ int ethernet_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
/* 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 */
|
||||
&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. we ommit it due to winpcap API. */
|
||||
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. we ommit it due to winpcap API. */
|
||||
)
|
||||
{
|
||||
struct pcap_pkthdr *header;
|
||||
@@ -326,8 +334,7 @@ uint16_t ethernet_receive(BACNET_ADDRESS * src, /* source address */
|
||||
|
||||
/* Make sure the socket is open */
|
||||
if (!ethernet_valid()) {
|
||||
LogError
|
||||
("ethernet.c: invalid 802.2 ethernet interface descriptor!\n");
|
||||
LogError("ethernet.c: invalid 802.2 ethernet interface descriptor!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -374,7 +381,8 @@ uint16_t ethernet_receive(BACNET_ADDRESS * src, /* source address */
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
void ethernet_set_my_address(BACNET_ADDRESS * my_address)
|
||||
void ethernet_set_my_address(
|
||||
BACNET_ADDRESS * my_address)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
@@ -385,7 +393,8 @@ void ethernet_set_my_address(BACNET_ADDRESS * my_address)
|
||||
return;
|
||||
}
|
||||
|
||||
void ethernet_get_my_address(BACNET_ADDRESS * my_address)
|
||||
void ethernet_get_my_address(
|
||||
BACNET_ADDRESS * my_address)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
@@ -403,9 +412,10 @@ void ethernet_get_my_address(BACNET_ADDRESS * my_address)
|
||||
return;
|
||||
}
|
||||
|
||||
void ethernet_get_broadcast_address(BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
void ethernet_get_broadcast_address(
|
||||
BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
|
||||
if (dest) {
|
||||
for (i = 0; i < 6; i++) {
|
||||
@@ -413,7 +423,7 @@ void ethernet_get_broadcast_address(BACNET_ADDRESS * dest)
|
||||
}
|
||||
dest->mac_len = 6;
|
||||
dest->net = BACNET_BROADCAST_NETWORK;
|
||||
dest->len = 0; /* denotes broadcast address */
|
||||
dest->len = 0; /* denotes broadcast address */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
dest->adr[i] = 0;
|
||||
}
|
||||
@@ -422,9 +432,11 @@ void ethernet_get_broadcast_address(BACNET_ADDRESS * dest)
|
||||
return;
|
||||
}
|
||||
|
||||
void ethernet_debug_address(const char *info, BACNET_ADDRESS * dest)
|
||||
void ethernet_debug_address(
|
||||
const char *info,
|
||||
BACNET_ADDRESS * dest)
|
||||
{
|
||||
int i = 0; /* counter */
|
||||
int i = 0; /* counter */
|
||||
char msgBuf[200];
|
||||
|
||||
if (info) {
|
||||
@@ -439,15 +451,14 @@ void ethernet_debug_address(const char *info, BACNET_ADDRESS * dest)
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
sprintf(msgBuf, "%02X ", (unsigned) dest->mac[i]);
|
||||
LogInfo(msgBuf);
|
||||
} /* for */
|
||||
} /* for */
|
||||
LogInfo("\n");
|
||||
sprintf(msgBuf,
|
||||
" Net=%hu\n Len=%d\n Adr=", dest->net, dest->len);
|
||||
sprintf(msgBuf, " Net=%hu\n Len=%d\n Adr=", dest->net, dest->len);
|
||||
LogInfo(msgBuf);
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
sprintf(msgBuf, "%02X ", (unsigned) dest->adr[i]);
|
||||
LogInfo(msgBuf);
|
||||
} /* for */
|
||||
} /* for */
|
||||
LogInfo("\n");
|
||||
}
|
||||
/* if ( dest ) */
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <conio.h> /* for kbhit and getch */
|
||||
#include <conio.h> /* for kbhit and getch */
|
||||
#include "iam.h"
|
||||
#include "address.h"
|
||||
#include "config.h"
|
||||
@@ -49,7 +49,8 @@ static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||
static bool Who_Is_Request = true;
|
||||
bool I_Am_Request = true;
|
||||
|
||||
static void Read_Properties(void)
|
||||
static void Read_Properties(
|
||||
void)
|
||||
{
|
||||
uint32_t device_id = 0;
|
||||
bool status = false;
|
||||
@@ -123,8 +124,10 @@ static void Read_Properties(void)
|
||||
return;
|
||||
}
|
||||
|
||||
static void LocalIAmHandler(uint8_t * service_request,
|
||||
uint16_t service_len, BACNET_ADDRESS * src)
|
||||
static void LocalIAmHandler(
|
||||
uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src)
|
||||
{
|
||||
int len = 0;
|
||||
uint32_t device_id = 0;
|
||||
@@ -146,13 +149,12 @@ static void LocalIAmHandler(uint8_t * service_request,
|
||||
return;
|
||||
}
|
||||
|
||||
static void Init_Service_Handlers(void)
|
||||
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,
|
||||
handler_who_is);
|
||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_I_AM,
|
||||
LocalIAmHandler);
|
||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_I_AM, LocalIAmHandler);
|
||||
|
||||
/* set the handler for all the services we don't implement */
|
||||
/* It is required to send the proper reject message... */
|
||||
@@ -168,9 +170,11 @@ static void Init_Service_Handlers(void)
|
||||
handler_read_property_ack);
|
||||
}
|
||||
|
||||
static void print_address(char *name, BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
static void print_address(
|
||||
char *name,
|
||||
BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
|
||||
if (dest) {
|
||||
printf("%s: ", name);
|
||||
@@ -181,7 +185,8 @@ static void print_address(char *name, BACNET_ADDRESS * dest)
|
||||
}
|
||||
}
|
||||
|
||||
static void print_address_cache(void)
|
||||
static void print_address_cache(
|
||||
void)
|
||||
{
|
||||
int i, j;
|
||||
BACNET_ADDRESS address;
|
||||
@@ -202,7 +207,9 @@ static void print_address_cache(void)
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
int main(
|
||||
int argc,
|
||||
char *argv[])
|
||||
{
|
||||
BACNET_ADDRESS src = { 0 }; /* address where message came from */
|
||||
uint16_t pdu_len = 0;
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
B&B Electronics USOPTL4
|
||||
SerialGear USB-COMi-SI-M
|
||||
*/
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
@@ -88,41 +88,44 @@ static DWORD RS485_RTSControl = RTS_CONTROL_DISABLE;
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Set_Interface(char *ifname)
|
||||
void RS485_Set_Interface(
|
||||
char *ifname)
|
||||
{
|
||||
/* note: expects a constant char, or char from the heap */
|
||||
RS485_Port_Name = ifname;
|
||||
}
|
||||
|
||||
static void RS485_Print_Error(void)
|
||||
static void RS485_Print_Error(
|
||||
void)
|
||||
{
|
||||
char * szExtended = ""; /* error string translated from error code */
|
||||
char *szExtended = ""; /* error string translated from error code */
|
||||
DWORD dwExtSize;
|
||||
DWORD dwErr;
|
||||
|
||||
dwErr = GetLastError();
|
||||
fprintf(stderr,"Error %lu:\r\n", dwErr);
|
||||
fprintf(stderr, "Error %lu:\r\n", dwErr);
|
||||
/* Get error string from system */
|
||||
dwExtSize = FormatMessage(
|
||||
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | 80 ,
|
||||
NULL, dwErr,
|
||||
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
|
||||
(LPTSTR) szExtended, 0, NULL);
|
||||
fprintf(stderr,"%s\r\n", szExtended);
|
||||
dwExtSize =
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | 80, NULL, dwErr,
|
||||
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), (LPTSTR) szExtended, 0,
|
||||
NULL);
|
||||
fprintf(stderr, "%s\r\n", szExtended);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void RS485_Configure_Status(void)
|
||||
static void RS485_Configure_Status(
|
||||
void)
|
||||
{
|
||||
DCB dcb = {0};
|
||||
DCB dcb = { 0 };
|
||||
COMMTIMEOUTS ctNew;
|
||||
|
||||
|
||||
dcb.DCBlength = sizeof(dcb);
|
||||
/* get current DCB settings */
|
||||
if (!GetCommState(RS485_Handle, &dcb)) {
|
||||
fprintf(stderr,"Unable to get status from %s\n", RS485_Port_Name);
|
||||
fprintf(stderr, "Unable to get status from %s\n", RS485_Port_Name);
|
||||
RS485_Print_Error();
|
||||
exit(1);
|
||||
}
|
||||
@@ -130,49 +133,49 @@ static void RS485_Configure_Status(void)
|
||||
/* update DCB rate, byte size, parity, and stop bits size */
|
||||
dcb.BaudRate = RS485_Baud;
|
||||
dcb.ByteSize = RS485_ByteSize;
|
||||
dcb.Parity = RS485_Parity;
|
||||
dcb.Parity = RS485_Parity;
|
||||
dcb.StopBits = RS485_StopBits;
|
||||
|
||||
/* update flow control settings */
|
||||
dcb.fDtrControl = RS485_DTRControl;
|
||||
dcb.fRtsControl = RS485_RTSControl;
|
||||
dcb.fDtrControl = RS485_DTRControl;
|
||||
dcb.fRtsControl = RS485_RTSControl;
|
||||
/*
|
||||
dcb.fOutxCtsFlow = CTSOUTFLOW(TTYInfo);
|
||||
dcb.fOutxDsrFlow = DSROUTFLOW(TTYInfo);
|
||||
dcb.fDsrSensitivity = DSRINFLOW(TTYInfo);
|
||||
dcb.fOutX = XONXOFFOUTFLOW(TTYInfo);
|
||||
dcb.fInX = XONXOFFINFLOW(TTYInfo);
|
||||
dcb.fTXContinueOnXoff = TXAFTERXOFFSENT(TTYInfo);
|
||||
dcb.XonChar = XONCHAR(TTYInfo);
|
||||
dcb.XoffChar = XOFFCHAR(TTYInfo);
|
||||
dcb.XonLim = XONLIMIT(TTYInfo);
|
||||
dcb.XoffLim = XOFFLIMIT(TTYInfo);
|
||||
// DCB settings not in the user's control
|
||||
dcb.fParity = TRUE;
|
||||
*/
|
||||
dcb.fOutxCtsFlow = CTSOUTFLOW(TTYInfo);
|
||||
dcb.fOutxDsrFlow = DSROUTFLOW(TTYInfo);
|
||||
dcb.fDsrSensitivity = DSRINFLOW(TTYInfo);
|
||||
dcb.fOutX = XONXOFFOUTFLOW(TTYInfo);
|
||||
dcb.fInX = XONXOFFINFLOW(TTYInfo);
|
||||
dcb.fTXContinueOnXoff = TXAFTERXOFFSENT(TTYInfo);
|
||||
dcb.XonChar = XONCHAR(TTYInfo);
|
||||
dcb.XoffChar = XOFFCHAR(TTYInfo);
|
||||
dcb.XonLim = XONLIMIT(TTYInfo);
|
||||
dcb.XoffLim = XOFFLIMIT(TTYInfo);
|
||||
// DCB settings not in the user's control
|
||||
dcb.fParity = TRUE;
|
||||
*/
|
||||
if (!SetCommState(RS485_Handle, &dcb)) {
|
||||
fprintf(stderr,"Unable to set status on %s\n", RS485_Port_Name);
|
||||
fprintf(stderr, "Unable to set status on %s\n", RS485_Port_Name);
|
||||
RS485_Print_Error();
|
||||
}
|
||||
/* configure the COM port timeout values */
|
||||
ctNew.ReadIntervalTimeout = MAXDWORD;
|
||||
ctNew.ReadTotalTimeoutMultiplier = MAXDWORD;
|
||||
ctNew.ReadTotalTimeoutConstant = 1000;
|
||||
ctNew.ReadIntervalTimeout = MAXDWORD;
|
||||
ctNew.ReadTotalTimeoutMultiplier = MAXDWORD;
|
||||
ctNew.ReadTotalTimeoutConstant = 1000;
|
||||
ctNew.WriteTotalTimeoutMultiplier = 0;
|
||||
ctNew.WriteTotalTimeoutConstant = 0;
|
||||
ctNew.WriteTotalTimeoutConstant = 0;
|
||||
if (!SetCommTimeouts(RS485_Handle, &ctNew)) {
|
||||
RS485_Print_Error();
|
||||
}
|
||||
/* Get rid of any stray characters */
|
||||
if (!PurgeComm(RS485_Handle, PURGE_TXABORT | PURGE_RXABORT)) {
|
||||
fprintf(stderr,"Unable to purge %s\n", RS485_Port_Name);
|
||||
fprintf(stderr, "Unable to purge %s\n", RS485_Port_Name);
|
||||
RS485_Print_Error();
|
||||
}
|
||||
/* Set the Comm buffer size */
|
||||
SetupComm(RS485_Handle, MAX_MPDU, MAX_MPDU);
|
||||
/* raise DTR */
|
||||
if (!EscapeCommFunction(RS485_Handle, SETDTR)) {
|
||||
fprintf(stderr,"Unable to set DTR on %s\n", RS485_Port_Name);
|
||||
fprintf(stderr, "Unable to set DTR on %s\n", RS485_Port_Name);
|
||||
RS485_Print_Error();
|
||||
}
|
||||
}
|
||||
@@ -184,22 +187,19 @@ static void RS485_Configure_Status(void)
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Initialize(void)
|
||||
void RS485_Initialize(
|
||||
void)
|
||||
{
|
||||
RS485_Handle = CreateFile(
|
||||
RS485_Port_Name,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
0,
|
||||
OPEN_EXISTING,
|
||||
/*FILE_FLAG_OVERLAPPED*/0,
|
||||
RS485_Handle = CreateFile(RS485_Port_Name,
|
||||
GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
|
||||
/*FILE_FLAG_OVERLAPPED */ 0,
|
||||
0);
|
||||
if (RS485_Handle == INVALID_HANDLE_VALUE) {
|
||||
fprintf(stderr,"Unable to open %s\n", RS485_Port_Name);
|
||||
fprintf(stderr, "Unable to open %s\n", RS485_Port_Name);
|
||||
RS485_Print_Error();
|
||||
exit(1);
|
||||
}
|
||||
if (!GetCommTimeouts( RS485_Handle, &RS485_Timeouts)) {
|
||||
if (!GetCommTimeouts(RS485_Handle, &RS485_Timeouts)) {
|
||||
RS485_Print_Error();
|
||||
}
|
||||
RS485_Configure_Status();
|
||||
@@ -207,13 +207,14 @@ void RS485_Initialize(void)
|
||||
return;
|
||||
}
|
||||
|
||||
void RS485_Cleanup(void)
|
||||
void RS485_Cleanup(
|
||||
void)
|
||||
{
|
||||
if (!EscapeCommFunction(RS485_Handle, CLRDTR)) {
|
||||
RS485_Print_Error();
|
||||
}
|
||||
|
||||
if (!SetCommTimeouts(RS485_Handle, &RS485_Timeouts)) {
|
||||
if (!SetCommTimeouts(RS485_Handle, &RS485_Timeouts)) {
|
||||
RS485_Print_Error();
|
||||
}
|
||||
|
||||
@@ -226,15 +227,21 @@ void RS485_Cleanup(void)
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
uint32_t RS485_Get_Baud_Rate(void)
|
||||
uint32_t RS485_Get_Baud_Rate(
|
||||
void)
|
||||
{
|
||||
switch (RS485_Baud) {
|
||||
case CBR_19200: return 19200;
|
||||
case CBR_38400: return 38400;
|
||||
case CBR_57600: return 57600;
|
||||
case CBR_115200: return 115200;
|
||||
case CBR_19200:
|
||||
return 19200;
|
||||
case CBR_38400:
|
||||
return 38400;
|
||||
case CBR_57600:
|
||||
return 57600;
|
||||
case CBR_115200:
|
||||
return 115200;
|
||||
default:
|
||||
case CBR_9600: return 9600;
|
||||
case CBR_9600:
|
||||
return 9600;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,29 +251,30 @@ uint32_t RS485_Get_Baud_Rate(void)
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
bool RS485_Set_Baud_Rate(uint32_t baud)
|
||||
bool RS485_Set_Baud_Rate(
|
||||
uint32_t baud)
|
||||
{
|
||||
bool valid = true;
|
||||
|
||||
switch (baud) {
|
||||
case 9600:
|
||||
RS485_Baud = CBR_9600;
|
||||
break;
|
||||
case 19200:
|
||||
RS485_Baud = CBR_19200;
|
||||
break;
|
||||
case 38400:
|
||||
RS485_Baud = CBR_38400;
|
||||
break;
|
||||
case 57600:
|
||||
RS485_Baud = CBR_57600;
|
||||
break;
|
||||
case 115200:
|
||||
RS485_Baud = CBR_115200;
|
||||
break;
|
||||
default:
|
||||
valid = false;
|
||||
break;
|
||||
case 9600:
|
||||
RS485_Baud = CBR_9600;
|
||||
break;
|
||||
case 19200:
|
||||
RS485_Baud = CBR_19200;
|
||||
break;
|
||||
case 38400:
|
||||
RS485_Baud = CBR_38400;
|
||||
break;
|
||||
case 57600:
|
||||
RS485_Baud = CBR_57600;
|
||||
break;
|
||||
case 115200:
|
||||
RS485_Baud = CBR_115200;
|
||||
break;
|
||||
default:
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
@@ -278,11 +286,11 @@ bool RS485_Set_Baud_Rate(uint32_t baud)
|
||||
|
||||
/* Transmits a Frame on the wire */
|
||||
void RS485_Send_Frame(
|
||||
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
||||
uint16_t nbytes) /* number of bytes of data (up to 501) */
|
||||
{
|
||||
DWORD dwWritten = 0;
|
||||
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
||||
uint16_t nbytes)
|
||||
{ /* number of bytes of data (up to 501) */
|
||||
DWORD dwWritten = 0;
|
||||
|
||||
if (mstp_port) {
|
||||
uint32_t baud;
|
||||
@@ -310,7 +318,8 @@ void RS485_Send_Frame(
|
||||
}
|
||||
|
||||
/* called by timer, interrupt(?) or other thread */
|
||||
void RS485_Check_UART_Data(volatile struct mstp_port_struct_t *mstp_port)
|
||||
void RS485_Check_UART_Data(
|
||||
volatile struct mstp_port_struct_t *mstp_port)
|
||||
{
|
||||
char lpBuf[1];
|
||||
DWORD dwRead = 0;
|
||||
@@ -322,7 +331,7 @@ void RS485_Check_UART_Data(volatile struct mstp_port_struct_t *mstp_port)
|
||||
else if (mstp_port->DataAvailable == false) {
|
||||
/* check for data */
|
||||
if (!ReadFile(RS485_Handle, lpBuf, sizeof(lpBuf), &dwRead, NULL)) {
|
||||
if (GetLastError() != ERROR_IO_PENDING) {
|
||||
if (GetLastError() != ERROR_IO_PENDING) {
|
||||
mstp_port->ReceiveError = TRUE;
|
||||
}
|
||||
} else {
|
||||
@@ -335,10 +344,11 @@ void RS485_Check_UART_Data(volatile struct mstp_port_struct_t *mstp_port)
|
||||
}
|
||||
|
||||
#ifdef TEST_RS485
|
||||
static void test_transmit_task(void *pArg)
|
||||
static void test_transmit_task(
|
||||
void *pArg)
|
||||
{
|
||||
char *TxBuf = "BACnet MS/TP";
|
||||
size_t len = strlen(TxBuf)+1;
|
||||
size_t len = strlen(TxBuf) + 1;
|
||||
|
||||
while (TRUE) {
|
||||
Sleep(1000);
|
||||
@@ -346,7 +356,8 @@ static void test_transmit_task(void *pArg)
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
unsigned long hThread = 0;
|
||||
uint32_t arg_value = 0;
|
||||
@@ -357,13 +368,13 @@ int main(void)
|
||||
RS485_Set_Interface("COM4");
|
||||
RS485_Set_Baud_Rate(38400);
|
||||
RS485_Initialize();
|
||||
#if 0
|
||||
#if 0
|
||||
/* create a task for synchronous transmit */
|
||||
hThread = _beginthread(test_transmit_task,4096,&arg_value);
|
||||
hThread = _beginthread(test_transmit_task, 4096, &arg_value);
|
||||
if (hThread == 0) {
|
||||
fprintf(stderr, "Failed to start transmit task\n");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
/* receive task */
|
||||
for (;;) {
|
||||
if (!ReadFile(RS485_Handle, lpBuf, sizeof(lpBuf), &dwRead, NULL)) {
|
||||
@@ -374,12 +385,11 @@ int main(void)
|
||||
/* print any characters received */
|
||||
if (dwRead) {
|
||||
for (i = 0; i < dwRead; i++) {
|
||||
fprintf(stderr,"%02X ",lpBuf[i]);
|
||||
fprintf(stderr, "%02X ", lpBuf[i]);
|
||||
}
|
||||
}
|
||||
dwRead = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* TEST_ABORT */
|
||||
|
||||
#endif /* TEST_ABORT */
|
||||
|
||||
@@ -41,22 +41,28 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void RS485_Set_Interface(char *ifname);
|
||||
void RS485_Set_Interface(
|
||||
char *ifname);
|
||||
|
||||
void RS485_Initialize(void);
|
||||
void RS485_Initialize(
|
||||
void);
|
||||
|
||||
void RS485_Send_Frame(volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||
void RS485_Send_Frame(
|
||||
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
||||
uint16_t nbytes); /* number of bytes of data (up to 501) */
|
||||
|
||||
void RS485_Check_UART_Data(volatile struct mstp_port_struct_t *mstp_port); /* port specific data */
|
||||
void RS485_Check_UART_Data(
|
||||
volatile struct mstp_port_struct_t *mstp_port); /* port specific data */
|
||||
|
||||
uint32_t RS485_Get_Baud_Rate(void);
|
||||
bool RS485_Set_Baud_Rate(uint32_t baud);
|
||||
uint32_t RS485_Get_Baud_Rate(
|
||||
void);
|
||||
bool RS485_Set_Baud_Rate(
|
||||
uint32_t baud);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -56,23 +56,27 @@ static uint8_t RxBuffer[MAX_MPDU];
|
||||
static uint8_t TxBuffer[MAX_MPDU];
|
||||
static uint16_t SilenceTime;
|
||||
#define INCREMENT_AND_LIMIT_UINT16(x) {if (x < 0xFFFF) x++;}
|
||||
static uint16_t Timer_Silence(void)
|
||||
static uint16_t Timer_Silence(
|
||||
void)
|
||||
{
|
||||
return SilenceTime;
|
||||
}
|
||||
static void Timer_Silence_Reset(void)
|
||||
static void Timer_Silence_Reset(
|
||||
void)
|
||||
{
|
||||
SilenceTime = 0;
|
||||
}
|
||||
|
||||
static void dlmstp_millisecond_timer(void)
|
||||
static void dlmstp_millisecond_timer(
|
||||
void)
|
||||
{
|
||||
INCREMENT_AND_LIMIT_UINT16(SilenceTime);
|
||||
}
|
||||
|
||||
void *milliseconds_task(void *pArg)
|
||||
void *milliseconds_task(
|
||||
void *pArg)
|
||||
{
|
||||
(void)pArg;
|
||||
(void) pArg;
|
||||
for (;;) {
|
||||
Sleep(1);
|
||||
dlmstp_millisecond_timer();
|
||||
@@ -85,28 +89,28 @@ void *milliseconds_task(void *pArg)
|
||||
uint16_t MSTP_Put_Receive(
|
||||
volatile struct mstp_port_struct_t *mstp_port)
|
||||
{
|
||||
(void)mstp_port;
|
||||
|
||||
(void) mstp_port;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* for the MS/TP state machine to use for getting data to send */
|
||||
/* Return: amount of PDU data */
|
||||
uint16_t MSTP_Get_Send(
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
unsigned timeout) /* milliseconds to wait for a packet */
|
||||
{
|
||||
(void)mstp_port;
|
||||
(void)timeout;
|
||||
volatile struct mstp_port_struct_t * mstp_port,
|
||||
unsigned timeout)
|
||||
{ /* milliseconds to wait for a packet */
|
||||
(void) mstp_port;
|
||||
(void) timeout;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t MSTP_Get_Reply(
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
unsigned timeout) /* milliseconds to wait for a packet */
|
||||
{
|
||||
(void)mstp_port;
|
||||
(void)timeout;
|
||||
volatile struct mstp_port_struct_t * mstp_port,
|
||||
unsigned timeout)
|
||||
{ /* milliseconds to wait for a packet */
|
||||
(void) mstp_port;
|
||||
(void) timeout;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -131,27 +135,25 @@ static void print_received_packet(
|
||||
mstp_port->DestinationAddress,
|
||||
mstp_port->SourceAddress,
|
||||
HI_BYTE(mstp_port->DataLength),
|
||||
LO_BYTE(mstp_port->DataLength),
|
||||
mstp_port->HeaderCRCActual);
|
||||
LO_BYTE(mstp_port->DataLength), mstp_port->HeaderCRCActual);
|
||||
if (mstp_port->DataLength) {
|
||||
for (i = 0; i < mstp_port->DataLength; i++) {
|
||||
fprintf(stderr,"%02X ",
|
||||
mstp_port->InputBuffer[i]);
|
||||
fprintf(stderr, "%02X ", mstp_port->InputBuffer[i]);
|
||||
}
|
||||
fprintf(stderr,
|
||||
"%02X %02X ",
|
||||
mstp_port->DataCRCActualMSB,
|
||||
mstp_port->DataCRCActualLSB);
|
||||
"%02X %02X ",
|
||||
mstp_port->DataCRCActualMSB, mstp_port->DataCRCActualLSB);
|
||||
}
|
||||
fprintf(stderr,"%s",
|
||||
mstptext_frame_type(mstp_port->FrameType));
|
||||
fprintf(stderr,"\n");
|
||||
fprintf(stderr, "%s", mstptext_frame_type(mstp_port->FrameType));
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
static char *Network_Interface = NULL;
|
||||
|
||||
/* simple test to packetize the data and print it */
|
||||
int main(int argc, char *argv[])
|
||||
int main(
|
||||
int argc,
|
||||
char *argv[])
|
||||
{
|
||||
volatile struct mstp_port_struct_t *mstp_port;
|
||||
int rc = 0;
|
||||
@@ -168,7 +170,7 @@ int main(int argc, char *argv[])
|
||||
if (argc > 2) {
|
||||
my_mac = strtol(argv[2], NULL, 0);
|
||||
if (my_mac > 127)
|
||||
my_mac = 127;
|
||||
my_mac = 127;
|
||||
}
|
||||
/* initialize our interface */
|
||||
RS485_Set_Interface(Network_Interface);
|
||||
@@ -186,7 +188,7 @@ int main(int argc, char *argv[])
|
||||
MSTP_Init(&MSTP_Port);
|
||||
mstp_port->Lurking = true;
|
||||
/* start our MilliSec task */
|
||||
hThread = _beginthread(milliseconds_task,4096,&arg_value);
|
||||
hThread = _beginthread(milliseconds_task, 4096, &arg_value);
|
||||
if (hThread == 0) {
|
||||
fprintf(stderr, "Failed to start timer task\n");
|
||||
}
|
||||
@@ -207,4 +209,3 @@ int main(int argc, char *argv[])
|
||||
|
||||
//return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ typedef signed char int8_t; /* 1 byte -127 to 127 */
|
||||
typedef unsigned short uint16_t; /* 2 bytes 0 to 65535 */
|
||||
typedef signed short int16_t; /* 2 bytes -32767 to 32767 */
|
||||
/*typedef unsigned short long uint24_t; // 3 bytes 0 to 16777215 */
|
||||
typedef unsigned uint32_t; /* 4 bytes 0 to 4294967295 */
|
||||
typedef unsigned uint32_t; /* 4 bytes 0 to 4294967295 */
|
||||
typedef int int32_t; /* 4 bytes -2147483647 to 2147483647 */
|
||||
/* typedef signed long long int64_t; */
|
||||
/* typedef unsigned long long uint64_t; */
|
||||
@@ -24,8 +24,8 @@ typedef int int32_t; /* 4 bytes -2147483647 to 2147483647 */
|
||||
#define INT16_MAX 32767
|
||||
#define INT32_MAX 2147483647
|
||||
|
||||
#define UINT8_MAX 0xff /* 255U */
|
||||
#define UINT16_MAX 0xffff /* 65535U */
|
||||
#define UINT32_MAX 0xffffffff /* 4294967295U */
|
||||
#define UINT8_MAX 0xff /* 255U */
|
||||
#define UINT16_MAX 0xffff /* 65535U */
|
||||
#define UINT32_MAX 0xffffffff /* 4294967295U */
|
||||
|
||||
#endif /* STDINT_H */
|
||||
#endif /* STDINT_H */
|
||||
|
||||
Reference in New Issue
Block a user