running the indent on the files.

This commit is contained in:
skarg
2006-02-18 23:11:25 +00:00
parent b1d46ffa8c
commit d6a891f0d1
58 changed files with 4781 additions and 5862 deletions
+25 -43
View File
@@ -35,63 +35,45 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
/* unconfirmed requests */ /* unconfirmed requests */
void Send_WhoIs( void Send_WhoIs(int32_t low_limit, int32_t high_limit);
int32_t low_limit,
int32_t high_limit);
void Send_WhoHas_Object( void Send_WhoHas_Object(int32_t low_limit,
int32_t low_limit, int32_t high_limit,
int32_t high_limit, BACNET_OBJECT_TYPE object_type, uint32_t object_instance);
BACNET_OBJECT_TYPE object_type,
uint32_t object_instance);
void Send_WhoHas_Name( void Send_WhoHas_Name(int32_t low_limit,
int32_t low_limit, int32_t high_limit, char *object_name);
int32_t high_limit,
char *object_name);
void Send_I_Have( void Send_I_Have(uint32_t device_id,
uint32_t device_id, BACNET_OBJECT_TYPE object_type,
BACNET_OBJECT_TYPE object_type, uint32_t object_instance, char *object_name);
uint32_t object_instance,
char *object_name);
/* returns the invoke ID for confirmed request, or 0 if failed */ /* returns the invoke ID for confirmed request, or 0 if failed */
uint8_t Send_Read_Property_Request( uint8_t Send_Read_Property_Request(uint32_t device_id, /* destination device */
uint32_t device_id, /* destination device */ BACNET_OBJECT_TYPE object_type,
BACNET_OBJECT_TYPE object_type, uint32_t object_instance,
uint32_t object_instance, BACNET_PROPERTY_ID object_property, int32_t array_index);
BACNET_PROPERTY_ID object_property,
int32_t array_index);
/* returns the invoke ID for confirmed request, or 0 if failed */ /* returns the invoke ID for confirmed request, or 0 if failed */
uint8_t Send_Write_Property_Request( uint8_t Send_Write_Property_Request(uint32_t device_id, // destination device
uint32_t device_id, // destination device BACNET_OBJECT_TYPE object_type,
BACNET_OBJECT_TYPE object_type, uint32_t object_instance,
uint32_t object_instance, BACNET_PROPERTY_ID object_property,
BACNET_PROPERTY_ID object_property, BACNET_APPLICATION_DATA_VALUE * object_value,
BACNET_APPLICATION_DATA_VALUE *object_value, uint8_t priority, int32_t array_index);
uint8_t priority,
int32_t array_index);
/* returns the invoke ID for confirmed request, or 0 if failed */ /* returns the invoke ID for confirmed request, or 0 if failed */
uint8_t Send_Reinitialize_Device_Request( uint8_t Send_Reinitialize_Device_Request(uint32_t device_id,
uint32_t device_id, BACNET_REINITIALIZED_STATE state, char *password);
BACNET_REINITIALIZED_STATE state,
char *password);
/* returns the invoke ID for confirmed request, or 0 if failed */ /* returns the invoke ID for confirmed request, or 0 if failed */
uint8_t Send_Device_Communication_Control_Request( uint8_t Send_Device_Communication_Control_Request(uint32_t device_id, uint16_t timeDuration, /* 0=optional */
uint32_t device_id, BACNET_COMMUNICATION_ENABLE_DISABLE state, char *password); /* NULL=optional */
uint16_t timeDuration, /* 0=optional */
BACNET_COMMUNICATION_ENABLE_DISABLE state,
char *password); /* NULL=optional */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+72 -106
View File
@@ -41,116 +41,82 @@
#include "ao.h" #include "ao.h"
#include "bacfile.h" #include "bacfile.h"
void handler_atomic_read_file( void handler_atomic_read_file(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len,
uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data)
BACNET_ADDRESS *src,
BACNET_CONFIRMED_SERVICE_DATA *service_data)
{ {
BACNET_ATOMIC_READ_FILE_DATA data; BACNET_ATOMIC_READ_FILE_DATA data;
int len = 0; int len = 0;
int pdu_len = 0; int pdu_len = 0;
BACNET_ADDRESS my_address; BACNET_ADDRESS my_address;
bool send = false; bool send = false;
bool error = false; bool error = false;
int bytes_sent = 0; int bytes_sent = 0;
BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT; BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT;
BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT; BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT;
fprintf(stderr,"Received Atomic-Read-File Request!\n"); fprintf(stderr, "Received Atomic-Read-File Request!\n");
len = arf_decode_service_request( len = arf_decode_service_request(service_request, service_len, &data);
service_request, if (len < 0)
service_len, fprintf(stderr, "Unable to decode Atomic-Read-File Request!\n");
&data); // prepare a reply
if (len < 0) datalink_get_my_address(&my_address);
fprintf(stderr,"Unable to decode Atomic-Read-File Request!\n"); // encode the NPDU portion of the packet
// prepare a reply pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], src, &my_address, false, // true for confirmed messages
datalink_get_my_address(&my_address); MESSAGE_PRIORITY_NORMAL);
// encode the NPDU portion of the packet // bad decoding - send an abort
pdu_len = npdu_encode_apdu( if (len < 0) {
&Handler_Transmit_Buffer[0], pdu_len += abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
src, service_data->invoke_id, ABORT_REASON_OTHER);
&my_address, fprintf(stderr, "Sending Abort!\n");
false, // true for confirmed messages
MESSAGE_PRIORITY_NORMAL);
// bad decoding - send an abort
if (len < 0)
{
pdu_len += abort_encode_apdu(
&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
ABORT_REASON_OTHER);
fprintf(stderr,"Sending Abort!\n");
send = true;
}
else if (service_data->segmented_message)
{
pdu_len += abort_encode_apdu(
&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED);
fprintf(stderr,"Sending Abort!\n");
send = true;
}
else
{
if (data.access == FILE_STREAM_ACCESS)
{
if (data.type.stream.requestedOctetCount <
octetstring_capacity(&data.fileData))
{
if (bacfile_read_data(&data))
{
pdu_len += arf_ack_encode_apdu(
&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
&data);
send = true;
}
else
{
send = true;
error = true;
}
}
else
{
pdu_len += abort_encode_apdu(
&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED);
fprintf(stderr,"Sending Abort!\n");
send = true; send = true;
} } else if (service_data->segmented_message) {
pdu_len += abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED);
fprintf(stderr, "Sending Abort!\n");
send = true;
} else {
if (data.access == FILE_STREAM_ACCESS) {
if (data.type.stream.requestedOctetCount <
octetstring_capacity(&data.fileData)) {
if (bacfile_read_data(&data)) {
pdu_len +=
arf_ack_encode_apdu(&Handler_Transmit_Buffer
[pdu_len], service_data->invoke_id, &data);
send = true;
} else {
send = true;
error = true;
}
} else {
pdu_len +=
abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED);
fprintf(stderr, "Sending Abort!\n");
send = true;
}
} else {
error_class = ERROR_CLASS_SERVICES;
error_code = ERROR_CODE_INVALID_FILE_ACCESS_METHOD;
send = true;
error = true;
}
} }
else if (error) {
{ pdu_len += bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
error_class = ERROR_CLASS_SERVICES; service_data->invoke_id,
error_code = ERROR_CODE_INVALID_FILE_ACCESS_METHOD; SERVICE_CONFIRMED_ATOMIC_READ_FILE, error_class, error_code);
send = true; fprintf(stderr, "Sending Error!\n");
error = true; send = true;
}
if (send) {
bytes_sent = datalink_send_pdu(src, // destination address
&Handler_Transmit_Buffer[0], pdu_len); // number of bytes of data
if (bytes_sent <= 0)
fprintf(stderr, "Failed to send PDU (%s)!\n", strerror(errno));
} }
}
if (error)
{
pdu_len += bacerror_encode_apdu(
&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
SERVICE_CONFIRMED_ATOMIC_READ_FILE,
error_class,
error_code);
fprintf(stderr,"Sending Error!\n");
send = true;
}
if (send)
{
bytes_sent = datalink_send_pdu(
src, // destination address
&Handler_Transmit_Buffer[0],
pdu_len); // number of bytes of data
if (bytes_sent <= 0)
fprintf(stderr,"Failed to send PDU (%s)!\n", strerror(errno));
}
return; return;
} }
+33 -45
View File
@@ -47,54 +47,42 @@
// that someone can read from us. It is common to // that someone can read from us. It is common to
// use the description as the file name. // use the description as the file name.
#if BACFILE #if BACFILE
void handler_atomic_read_file_ack( void handler_atomic_read_file_ack(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len,
uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_ACK_DATA * service_data)
BACNET_ADDRESS *src,
BACNET_CONFIRMED_SERVICE_ACK_DATA *service_data)
{ {
int len = 0; int len = 0;
BACNET_ATOMIC_READ_FILE_DATA data; BACNET_ATOMIC_READ_FILE_DATA data;
FILE *pFile = NULL; FILE *pFile = NULL;
char *pFilename = NULL; char *pFilename = NULL;
uint32_t instance = 0; uint32_t instance = 0;
(void)src; (void) src;
// get the file instance from the tsm data before freeing it // get the file instance from the tsm data before freeing it
instance = bacfile_instance_from_tsm(service_data->invoke_id); instance = bacfile_instance_from_tsm(service_data->invoke_id);
len = arf_ack_decode_service_request( len = arf_ack_decode_service_request(service_request,
service_request, service_len, &data);
service_len, fprintf(stderr, "Received Read-File Ack!\n");
&data); if ((len > 0) && (instance <= BACNET_MAX_INSTANCE)) {
fprintf(stderr,"Received Read-File Ack!\n"); // write the data received to the file specified
if ((len > 0) && (instance <= BACNET_MAX_INSTANCE)) if (data.access == FILE_STREAM_ACCESS) {
{ pFilename = bacfile_name(instance);
// write the data received to the file specified if (pFilename) {
if (data.access == FILE_STREAM_ACCESS) pFile = fopen(pFilename, "rb");
{ if (pFile) {
pFilename = bacfile_name(instance); (void) fseek(pFile,
if (pFilename) data.type.stream.fileStartPosition, SEEK_SET);
{ if (fwrite(octetstring_value(&data.fileData),
pFile = fopen(pFilename, "rb"); octetstring_length(&data.fileData), 1,
if (pFile) pFile) != 1)
{ fprintf(stderr, "Failed to write to %s (%u)!\n",
(void)fseek(pFile, pFilename, instance);
data.type.stream.fileStartPosition, fclose(pFile);
SEEK_SET); }
if (fwrite(octetstring_value(&data.fileData), }
octetstring_length(&data.fileData),1,pFile) != 1) } else if (data.access == FILE_RECORD_ACCESS) {
fprintf(stderr,"Failed to write to %s (%u)!\n", // FIXME: add handling for Record Access
pFilename, instance);
fclose(pFile);
} }
}
} }
else if (data.access == FILE_RECORD_ACCESS)
{
// FIXME: add handling for Record Access
}
}
} }
#endif #endif
+67 -97
View File
@@ -40,106 +40,76 @@
static char *My_Password = "AnnaRoseKarg"; static char *My_Password = "AnnaRoseKarg";
void handler_device_communication_control( void handler_device_communication_control(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len,
uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data)
BACNET_ADDRESS *src,
BACNET_CONFIRMED_SERVICE_DATA *service_data)
{ {
uint16_t timeDuration = 0; uint16_t timeDuration = 0;
BACNET_COMMUNICATION_ENABLE_DISABLE state = COMMUNICATION_ENABLE; BACNET_COMMUNICATION_ENABLE_DISABLE state = COMMUNICATION_ENABLE;
BACNET_CHARACTER_STRING password; BACNET_CHARACTER_STRING password;
int len = 0; int len = 0;
int pdu_len = 0; int pdu_len = 0;
BACNET_ADDRESS my_address; BACNET_ADDRESS my_address;
int bytes_sent = 0; int bytes_sent = 0;
// decode the service request only // decode the service request only
len = dcc_decode_service_request( len = dcc_decode_service_request(service_request,
service_request, service_len, &timeDuration, &state, &password);
service_len, fprintf(stderr, "DeviceCommunicationControl!\n");
&timeDuration, if (len > 0)
&state, fprintf(stderr, "DeviceCommunicationControl: "
&password); "timeout=%u state=%u password=%s\n",
fprintf(stderr,"DeviceCommunicationControl!\n"); (unsigned) timeDuration,
if (len > 0) (unsigned) state, characterstring_value(&password));
fprintf(stderr,"DeviceCommunicationControl: "
"timeout=%u state=%u password=%s\n",
(unsigned)timeDuration,
(unsigned)state,
characterstring_value(&password));
else
fprintf(stderr,"DeviceCommunicationControl: "
"Unable to decode request!\n");
// prepare a reply
datalink_get_my_address(&my_address);
// encode the NPDU portion of the packet
pdu_len = npdu_encode_apdu(
&Handler_Transmit_Buffer[0],
src,
&my_address,
false, // true for confirmed messages
MESSAGE_PRIORITY_NORMAL);
// bad decoding or something we didn't understand - send an abort
if (len == -1)
{
pdu_len += abort_encode_apdu(
&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
ABORT_REASON_OTHER);
fprintf(stderr,"DeviceCommunicationControl: "
"Sending Abort - could not decode.\n");
}
else if (service_data->segmented_message)
{
pdu_len += abort_encode_apdu(
&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED);
fprintf(stderr,"DeviceCommunicationControl: "
"Sending Abort - segmented message.\n");
}
else if (state >= MAX_BACNET_COMMUNICATION_ENABLE_DISABLE)
{
pdu_len += reject_encode_apdu(
&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
REJECT_REASON_UNDEFINED_ENUMERATION);
fprintf(stderr,"DeviceCommunicationControl: "
"Sending Reject - undefined enumeration\n");
}
else
{
if (characterstring_ansi_same(&password,My_Password))
{
pdu_len += encode_simple_ack(
&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL);
fprintf(stderr,"DeviceCommunicationControl: "
"Sending Simple Ack!\n");
dcc_set_status_duration(state,timeDuration);
}
else else
{ fprintf(stderr, "DeviceCommunicationControl: "
pdu_len += bacerror_encode_apdu( "Unable to decode request!\n");
&Handler_Transmit_Buffer[pdu_len], // prepare a reply
service_data->invoke_id, datalink_get_my_address(&my_address);
SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL, // encode the NPDU portion of the packet
ERROR_CLASS_SERVICES, pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], src, &my_address, false, // true for confirmed messages
ERROR_CODE_PASSWORD_FAILURE); MESSAGE_PRIORITY_NORMAL);
fprintf(stderr,"DeviceCommunicationControl: " // bad decoding or something we didn't understand - send an abort
"Sending Error - password failure.\n"); if (len == -1) {
pdu_len += abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id, ABORT_REASON_OTHER);
fprintf(stderr, "DeviceCommunicationControl: "
"Sending Abort - could not decode.\n");
} else if (service_data->segmented_message) {
pdu_len += abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED);
fprintf(stderr, "DeviceCommunicationControl: "
"Sending Abort - segmented message.\n");
} else if (state >= MAX_BACNET_COMMUNICATION_ENABLE_DISABLE) {
pdu_len += reject_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id, REJECT_REASON_UNDEFINED_ENUMERATION);
fprintf(stderr, "DeviceCommunicationControl: "
"Sending Reject - undefined enumeration\n");
} else {
if (characterstring_ansi_same(&password, My_Password)) {
pdu_len += encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL);
fprintf(stderr, "DeviceCommunicationControl: "
"Sending Simple Ack!\n");
dcc_set_status_duration(state, timeDuration);
} else {
pdu_len +=
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL,
ERROR_CLASS_SERVICES, ERROR_CODE_PASSWORD_FAILURE);
fprintf(stderr,
"DeviceCommunicationControl: "
"Sending Error - password failure.\n");
}
} }
} bytes_sent = datalink_send_pdu(src, // destination address
bytes_sent = datalink_send_pdu( &Handler_Transmit_Buffer[0], pdu_len); // number of bytes of data
src, // destination address if (bytes_sent <= 0)
&Handler_Transmit_Buffer[0], fprintf(stderr, "DeviceCommunicationControl: "
pdu_len); // number of bytes of data "Failed to send PDU (%s)!\n", strerror(errno));
if (bytes_sent <= 0)
fprintf(stderr,"DeviceCommunicationControl: "
"Failed to send PDU (%s)!\n",
strerror(errno));
return; return;
} }
+30 -49
View File
@@ -32,61 +32,42 @@
#include "iam.h" #include "iam.h"
#include "address.h" #include "address.h"
void handler_i_am_add( void handler_i_am_add(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len, BACNET_ADDRESS * src)
uint16_t service_len,
BACNET_ADDRESS *src)
{ {
int len = 0; int len = 0;
uint32_t device_id = 0; uint32_t device_id = 0;
unsigned max_apdu = 0; unsigned max_apdu = 0;
int segmentation = 0; int segmentation = 0;
uint16_t vendor_id = 0; uint16_t vendor_id = 0;
(void)service_len; (void) service_len;
len = iam_decode_service_request( len = iam_decode_service_request(service_request,
service_request, &device_id, &max_apdu, &segmentation, &vendor_id);
&device_id, fprintf(stderr, "Received I-Am Request");
&max_apdu, if (len != -1) {
&segmentation, fprintf(stderr, " from %u!\n", device_id);
&vendor_id); address_add(device_id, max_apdu, src);
fprintf(stderr,"Received I-Am Request"); } else
if (len != -1) fprintf(stderr, "!\n");
{
fprintf(stderr," from %u!\n",device_id);
address_add(device_id,
max_apdu,
src);
}
else
fprintf(stderr,"!\n");
return; return;
} }
void handler_i_am_bind( void handler_i_am_bind(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len, BACNET_ADDRESS * src)
uint16_t service_len,
BACNET_ADDRESS *src)
{ {
int len = 0; int len = 0;
uint32_t device_id = 0; uint32_t device_id = 0;
unsigned max_apdu = 0; unsigned max_apdu = 0;
int segmentation = 0; int segmentation = 0;
uint16_t vendor_id = 0; uint16_t vendor_id = 0;
(void)service_len; (void) service_len;
len = iam_decode_service_request( len = iam_decode_service_request(service_request,
service_request, &device_id, &max_apdu, &segmentation, &vendor_id);
&device_id, // only add address if requested to bind
&max_apdu, address_add_binding(device_id, max_apdu, src);
&segmentation,
&vendor_id);
// only add address if requested to bind
address_add_binding(device_id,
max_apdu,
src);
return; return;
} }
+17 -24
View File
@@ -32,31 +32,24 @@
#include "bactext.h" #include "bactext.h"
#include "ihave.h" #include "ihave.h"
void handler_i_have( void handler_i_have(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len, BACNET_ADDRESS * src)
uint16_t service_len,
BACNET_ADDRESS *src)
{ {
int len = 0; int len = 0;
BACNET_I_HAVE_DATA data; BACNET_I_HAVE_DATA data;
(void)service_len; (void) service_len;
(void)src; (void) src;
len = ihave_decode_service_request( len = ihave_decode_service_request(service_request,
service_request, service_len, &data);
service_len, if (len != -1) {
&data); fprintf(stderr, "I-Have: %s %d from %s %u!\r\n",
if (len != -1) bactext_object_type_name(data.object_id.type),
{ data.object_id.instance,
fprintf(stderr,"I-Have: %s %d from %s %u!\r\n", bactext_object_type_name(data.device_id.type),
bactext_object_type_name(data.object_id.type), data.device_id.instance);
data.object_id.instance, } else
bactext_object_type_name(data.device_id.type), fprintf(stderr, "I-Have: received, but unable to decode!\n");
data.device_id.instance);
}
else
fprintf(stderr,"I-Have: received, but unable to decode!\n");
return; return;
} }
+65 -90
View File
@@ -40,99 +40,74 @@
static BACNET_CHARACTER_STRING My_Password; static BACNET_CHARACTER_STRING My_Password;
void handler_reinitialize_device( void handler_reinitialize_device(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len,
uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data)
BACNET_ADDRESS *src,
BACNET_CONFIRMED_SERVICE_DATA *service_data)
{ {
BACNET_REINITIALIZED_STATE state; BACNET_REINITIALIZED_STATE state;
BACNET_CHARACTER_STRING password; BACNET_CHARACTER_STRING password;
int len = 0; int len = 0;
int pdu_len = 0; int pdu_len = 0;
BACNET_ADDRESS my_address; BACNET_ADDRESS my_address;
int bytes_sent = 0; int bytes_sent = 0;
// decode the service request only // decode the service request only
len = rd_decode_service_request( len = rd_decode_service_request(service_request,
service_request, service_len, &state, &password);
service_len, fprintf(stderr, "ReinitializeDevice!\n");
&state, if (len > 0)
&password); fprintf(stderr, "ReinitializeDevice: state=%u password=%s\n",
fprintf(stderr,"ReinitializeDevice!\n"); (unsigned) state, characterstring_value(&password));
if (len > 0)
fprintf(stderr,"ReinitializeDevice: state=%u password=%s\n",
(unsigned)state,
characterstring_value(&password));
else
fprintf(stderr,"ReinitializeDevice: Unable to decode request!\n");
// prepare a reply
datalink_get_my_address(&my_address);
// encode the NPDU portion of the packet
pdu_len = npdu_encode_apdu(
&Handler_Transmit_Buffer[0],
src,
&my_address,
false, // true for confirmed messages
MESSAGE_PRIORITY_NORMAL);
// bad decoding or something we didn't understand - send an abort
if (len == -1)
{
pdu_len += abort_encode_apdu(
&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
ABORT_REASON_OTHER);
fprintf(stderr,"ReinitializeDevice: Sending Abort - could not decode.\n");
}
else if (service_data->segmented_message)
{
pdu_len += abort_encode_apdu(
&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED);
fprintf(stderr,"ReinitializeDevice: Sending Abort - segmented message.\n");
}
else if (state >= MAX_BACNET_REINITIALIZED_STATE)
{
pdu_len += reject_encode_apdu(
&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
REJECT_REASON_UNDEFINED_ENUMERATION);
fprintf(stderr,"ReinitializeDevice: Sending Reject - undefined enumeration\n");
}
else
{
characterstring_init_ansi(&My_Password,"Jesus");
if (characterstring_same(&password,&My_Password))
{
pdu_len += encode_simple_ack(
&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
SERVICE_CONFIRMED_REINITIALIZE_DEVICE);
fprintf(stderr,"ReinitializeDevice: Sending Simple Ack!\n");
/* FIXME: now you can reboot, restart, quit, or something clever */
/* Note: you can use a mix of state and password to do specific stuff */
/* Note: if you don't do something clever like actually restart,
you probably should clear any DCC status and timeouts */
}
else else
{ fprintf(stderr, "ReinitializeDevice: Unable to decode request!\n");
pdu_len += bacerror_encode_apdu( // prepare a reply
&Handler_Transmit_Buffer[pdu_len], datalink_get_my_address(&my_address);
service_data->invoke_id, // encode the NPDU portion of the packet
SERVICE_CONFIRMED_REINITIALIZE_DEVICE, pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], src, &my_address, false, // true for confirmed messages
ERROR_CLASS_SERVICES, MESSAGE_PRIORITY_NORMAL);
ERROR_CODE_PASSWORD_FAILURE); // bad decoding or something we didn't understand - send an abort
fprintf(stderr,"ReinitializeDevice: Sending Error - password failure.\n"); if (len == -1) {
pdu_len += abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id, ABORT_REASON_OTHER);
fprintf(stderr,
"ReinitializeDevice: Sending Abort - could not decode.\n");
} else if (service_data->segmented_message) {
pdu_len += abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED);
fprintf(stderr,
"ReinitializeDevice: Sending Abort - segmented message.\n");
} else if (state >= MAX_BACNET_REINITIALIZED_STATE) {
pdu_len += reject_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id, REJECT_REASON_UNDEFINED_ENUMERATION);
fprintf(stderr,
"ReinitializeDevice: Sending Reject - undefined enumeration\n");
} else {
characterstring_init_ansi(&My_Password, "Jesus");
if (characterstring_same(&password, &My_Password)) {
pdu_len += encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
SERVICE_CONFIRMED_REINITIALIZE_DEVICE);
fprintf(stderr, "ReinitializeDevice: Sending Simple Ack!\n");
/* FIXME: now you can reboot, restart, quit, or something clever */
/* Note: you can use a mix of state and password to do specific stuff */
/* Note: if you don't do something clever like actually restart,
you probably should clear any DCC status and timeouts */
} else {
pdu_len +=
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
SERVICE_CONFIRMED_REINITIALIZE_DEVICE,
ERROR_CLASS_SERVICES, ERROR_CODE_PASSWORD_FAILURE);
fprintf(stderr,
"ReinitializeDevice: Sending Error - password failure.\n");
}
} }
} bytes_sent = datalink_send_pdu(src, // destination address
bytes_sent = datalink_send_pdu( &Handler_Transmit_Buffer[0], pdu_len); // number of bytes of data
src, // destination address if (bytes_sent <= 0)
&Handler_Transmit_Buffer[0], fprintf(stderr, "ReinitializeDevice: Failed to send PDU (%s)!\n",
pdu_len); // number of bytes of data strerror(errno));
if (bytes_sent <= 0)
fprintf(stderr,"ReinitializeDevice: Failed to send PDU (%s)!\n",
strerror(errno));
return; return;
} }
+136 -194
View File
@@ -43,206 +43,148 @@
#include "bacfile.h" #include "bacfile.h"
#endif #endif
static uint8_t Temp_Buf[MAX_APDU] = {0}; static uint8_t Temp_Buf[MAX_APDU] = { 0 };
void handler_read_property( void handler_read_property(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len,
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; BACNET_READ_PROPERTY_DATA data;
int len = 0; int len = 0;
int pdu_len = 0; int pdu_len = 0;
BACNET_ADDRESS my_address; BACNET_ADDRESS my_address;
bool send = false; bool send = false;
bool error = false; bool error = false;
int bytes_sent = 0; int bytes_sent = 0;
BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT; BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT;
BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT; BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT;
len = rp_decode_service_request( len = rp_decode_service_request(service_request, service_len, &data);
service_request, if (len <= 0)
service_len, fprintf(stderr, "Unable to decode Read-Property Request!\n");
&data); // prepare a reply
if (len <= 0) datalink_get_my_address(&my_address);
fprintf(stderr,"Unable to decode Read-Property Request!\n"); // encode the NPDU portion of the packet
// prepare a reply pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], src, &my_address, false, // true for confirmed messages
datalink_get_my_address(&my_address); MESSAGE_PRIORITY_NORMAL);
// encode the NPDU portion of the packet // bad decoding - send an abort
pdu_len = npdu_encode_apdu( if (len == -1) {
&Handler_Transmit_Buffer[0], pdu_len += abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
src, service_data->invoke_id, ABORT_REASON_OTHER);
&my_address, fprintf(stderr, "Sending Abort!\n");
false, // true for confirmed messages send = true;
MESSAGE_PRIORITY_NORMAL); } else if (service_data->segmented_message) {
// bad decoding - send an abort pdu_len += abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
if (len == -1) service_data->invoke_id,
{ ABORT_REASON_SEGMENTATION_NOT_SUPPORTED);
pdu_len += abort_encode_apdu( fprintf(stderr, "Sending Abort!\n");
&Handler_Transmit_Buffer[pdu_len], send = true;
service_data->invoke_id, } else {
ABORT_REASON_OTHER); switch (data.object_type) {
fprintf(stderr,"Sending Abort!\n"); case OBJECT_DEVICE:
send = true;
}
else if (service_data->segmented_message)
{
pdu_len += abort_encode_apdu(
&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED);
fprintf(stderr,"Sending Abort!\n");
send = true;
}
else
{
switch (data.object_type)
{
case OBJECT_DEVICE:
// FIXME: probably need a length limitation sent with encode
if (data.object_instance == Device_Object_Instance_Number())
{
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 // FIXME: probably need a length limitation sent with encode
pdu_len += rp_ack_encode_apdu( if (data.object_instance == Device_Object_Instance_Number()) {
&Handler_Transmit_Buffer[pdu_len], len = Device_Encode_Property_APDU(&Temp_Buf[0],
service_data->invoke_id, data.object_property,
&data); data.array_index, &error_class, &error_code);
fprintf(stderr,"Sending Read Property Ack!\n"); if (len >= 0) {
send = true; // encode the APDU portion of the packet
} data.application_data = &Temp_Buf[0];
else data.application_data_len = len;
// FIXME: probably need a length limitation sent with encode
pdu_len +=
rp_ack_encode_apdu(&Handler_Transmit_Buffer
[pdu_len], service_data->invoke_id, &data);
fprintf(stderr, "Sending Read Property Ack!\n");
send = true;
} else
error = true;
} else
error = true;
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
pdu_len +=
rp_ack_encode_apdu(&Handler_Transmit_Buffer
[pdu_len], service_data->invoke_id, &data);
fprintf(stderr, "Sending Read Property Ack!\n");
send = true;
} else
error = true;
} else
error = true;
break;
case OBJECT_ANALOG_OUTPUT:
if (Analog_Output_Valid_Instance(data.object_instance)) {
len = Analog_Output_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
pdu_len +=
rp_ack_encode_apdu(&Handler_Transmit_Buffer
[pdu_len], service_data->invoke_id, &data);
fprintf(stderr, "Sending Read Property Ack!\n");
send = true;
} else
error = true;
} else
error = true;
break;
#if BACFILE
case OBJECT_FILE:
if (bacfile_valid_instance(data.object_instance)) {
len = bacfile_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
pdu_len +=
rp_ack_encode_apdu(&Handler_Transmit_Buffer
[pdu_len], service_data->invoke_id, &data);
fprintf(stderr, "Sending Read Property Ack!\n");
send = true;
} else
error = true;
} else
error = true;
break;
#endif
default:
error = true; error = true;
break;
} }
else
error = true;
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
pdu_len += rp_ack_encode_apdu(
&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
&data);
fprintf(stderr,"Sending Read Property Ack!\n");
send = true;
}
else
error = true;
}
else
error = true;
break;
case OBJECT_ANALOG_OUTPUT:
if (Analog_Output_Valid_Instance(data.object_instance))
{
len = Analog_Output_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
pdu_len += rp_ack_encode_apdu(
&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
&data);
fprintf(stderr,"Sending Read Property Ack!\n");
send = true;
}
else
error = true;
}
else
error = true;
break;
#if BACFILE
case OBJECT_FILE:
if (bacfile_valid_instance(data.object_instance))
{
len = bacfile_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
pdu_len += rp_ack_encode_apdu(
&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
&data);
fprintf(stderr,"Sending Read Property Ack!\n");
send = true;
}
else
error = true;
}
else
error = true;
break;
#endif
default:
error = true;
break;
} }
} if (error) {
if (error) pdu_len += bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
{ service_data->invoke_id,
pdu_len += bacerror_encode_apdu( SERVICE_CONFIRMED_READ_PROPERTY, error_class, error_code);
&Handler_Transmit_Buffer[pdu_len], fprintf(stderr, "Sending Read Property Error!\n");
service_data->invoke_id, send = true;
SERVICE_CONFIRMED_READ_PROPERTY, }
error_class, if (send) {
error_code); bytes_sent = datalink_send_pdu(src, // destination address
fprintf(stderr,"Sending Read Property Error!\n"); &Handler_Transmit_Buffer[0], pdu_len); // number of bytes of data
send = true; if (bytes_sent <= 0)
} fprintf(stderr, "Failed to send PDU (%s)!\n", strerror(errno));
if (send) }
{
bytes_sent = datalink_send_pdu(
src, // destination address
&Handler_Transmit_Buffer[0],
pdu_len); // number of bytes of data
if (bytes_sent <= 0)
fprintf(stderr,"Failed to send PDU (%s)!\n", strerror(errno));
}
return; return;
} }
+60 -73
View File
@@ -42,85 +42,72 @@
#include "txbuf.h" #include "txbuf.h"
/* for debugging... */ /* for debugging... */
static void PrintReadPropertyData(BACNET_READ_PROPERTY_DATA *data) static void PrintReadPropertyData(BACNET_READ_PROPERTY_DATA * data)
{ {
BACNET_APPLICATION_DATA_VALUE value; /* for decode value data */ BACNET_APPLICATION_DATA_VALUE value; /* for decode value data */
int len = 0; int len = 0;
uint8_t *application_data; uint8_t *application_data;
int application_data_len; int application_data_len;
bool first_value = true; bool first_value = true;
bool print_brace = false; bool print_brace = false;
if (data) if (data) {
{ #if 0
#if 0 if (data->array_index == BACNET_ARRAY_ALL)
if (data->array_index == BACNET_ARRAY_ALL) fprintf(stderr, "%s #%u %s\n",
fprintf(stderr,"%s #%u %s\n", bactext_object_type_name(data->object_type),
bactext_object_type_name(data->object_type), data->object_instance,
data->object_instance, bactext_property_name(data->object_property));
bactext_property_name(data->object_property));
else
fprintf(stderr,"%s #%u %s[%d]\n",
bactext_object_type_name(data->object_type),
data->object_instance,
bactext_property_name(data->object_property),
data->array_index);
#endif
application_data = data->application_data;
application_data_len = data->application_data_len;
/* value? need to loop until all of the len is gone... */
for (;;)
{
len = bacapp_decode_application_data(
application_data,
application_data_len,
&value);
if (first_value && (len < application_data_len))
{
first_value = false;
fprintf(stdout,"{");
print_brace = true;
}
bacapp_print_value(stdout,&value,data->object_property);
if (len)
{
if (len < application_data_len)
{
application_data += len;
application_data_len -= len;
/* there's more! */
fprintf(stdout,",");
}
else else
break; fprintf(stderr, "%s #%u %s[%d]\n",
} bactext_object_type_name(data->object_type),
else data->object_instance,
break; bactext_property_name(data->object_property),
data->array_index);
#endif
application_data = data->application_data;
application_data_len = data->application_data_len;
/* value? need to loop until all of the len is gone... */
for (;;) {
len = bacapp_decode_application_data(application_data,
application_data_len, &value);
if (first_value && (len < application_data_len)) {
first_value = false;
fprintf(stdout, "{");
print_brace = true;
}
bacapp_print_value(stdout, &value, data->object_property);
if (len) {
if (len < application_data_len) {
application_data += len;
application_data_len -= len;
/* there's more! */
fprintf(stdout, ",");
} else
break;
} else
break;
}
if (print_brace)
fprintf(stdout, "}");
fprintf(stdout, "\r\n");
} }
if (print_brace)
fprintf(stdout,"}");
fprintf(stdout,"\r\n");
}
} }
void handler_read_property_ack( void handler_read_property_ack(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len,
uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_ACK_DATA * service_data)
BACNET_ADDRESS *src,
BACNET_CONFIRMED_SERVICE_ACK_DATA *service_data)
{ {
int len = 0; int len = 0;
BACNET_READ_PROPERTY_DATA data; BACNET_READ_PROPERTY_DATA data;
(void)src; (void) src;
(void)service_data; /* we could use these... */ (void) service_data; /* we could use these... */
len = rp_ack_decode_service_request( len = rp_ack_decode_service_request(service_request,
service_request, service_len, &data);
service_len, #if 0
&data); fprintf(stderr, "Received Read-Property Ack!\n");
#if 0 #endif
fprintf(stderr,"Received Read-Property Ack!\n"); if (len > 0)
#endif PrintReadPropertyData(&data);
if (len > 0)
PrintReadPropertyData(&data);
} }
+43 -57
View File
@@ -35,65 +35,51 @@
#include "device.h" #include "device.h"
#include "client.h" #include "client.h"
void handler_who_has( void handler_who_has(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len, BACNET_ADDRESS * src)
uint16_t service_len,
BACNET_ADDRESS *src)
{ {
int len = 0; int len = 0;
BACNET_WHO_HAS_DATA data; BACNET_WHO_HAS_DATA data;
bool directed_to_me = false; bool directed_to_me = false;
int object_type = 0; int object_type = 0;
uint32_t object_instance = 0; uint32_t object_instance = 0;
char *object_name = NULL; char *object_name = NULL;
bool found = false; bool found = false;
(void)src; (void) src;
len = whohas_decode_service_request( len = whohas_decode_service_request(service_request,
service_request, service_len, &data);
service_len, if (len > 0) {
&data); if ((data.low_limit == -1) || (data.high_limit == -1))
if (len > 0) directed_to_me = true;
{ else if ((Device_Object_Instance_Number() >=
if ((data.low_limit == -1) || (data.high_limit == -1)) (uint32_t) data.low_limit)
directed_to_me = true; && (Device_Object_Instance_Number() <=
else if ((Device_Object_Instance_Number() >= (uint32_t)data.low_limit) && (uint32_t) data.high_limit))
(Device_Object_Instance_Number() <= (uint32_t)data.high_limit)) directed_to_me = true;
directed_to_me = true; if (directed_to_me) {
if (directed_to_me) /* do we have such an object? If so, send an I-Have.
{ note: we should have only 1 of such an object */
/* do we have such an object? If so, send an I-Have. if (data.object_name) {
note: we should have only 1 of such an object */ /* valid name in my device? */
if (data.object_name) object_name = characterstring_value(&data.object.name);
{ found = Device_Valid_Object_Name(object_name,
/* valid name in my device? */ &object_type, &object_instance);
object_name = characterstring_value(&data.object.name); if (found)
found = Device_Valid_Object_Name( Send_I_Have(Device_Object_Instance_Number(),
object_name, object_type, object_instance, object_name);
&object_type, } else {
&object_instance); /* valid object in my device? */
if (found) object_name =
Send_I_Have( Device_Valid_Object_Id(data.object.identifier.type,
Device_Object_Instance_Number(), data.object.identifier.instance);
object_type, if (object_name)
object_instance, Send_I_Have(Device_Object_Instance_Number(),
object_name); data.object.identifier.type,
} data.object.identifier.instance, object_name);
else }
{ }
/* valid object in my device? */
object_name = Device_Valid_Object_Id(
data.object.identifier.type,
data.object.identifier.instance);
if (object_name)
Send_I_Have(
Device_Object_Instance_Number(),
data.object.identifier.type,
data.object.identifier.instance,
object_name);
}
} }
}
return; return;
} }
+18 -24
View File
@@ -37,31 +37,25 @@
/* global flag to send an I-Am */ /* global flag to send an I-Am */
bool I_Am_Request = true; bool I_Am_Request = true;
void handler_who_is( void handler_who_is(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len, BACNET_ADDRESS * src)
uint16_t service_len,
BACNET_ADDRESS *src)
{ {
int len = 0; int len = 0;
int32_t low_limit = 0; int32_t low_limit = 0;
int32_t high_limit = 0; int32_t high_limit = 0;
(void)src; (void) src;
len = whois_decode_service_request( len = whois_decode_service_request(service_request,
service_request, service_len, &low_limit, &high_limit);
service_len, /* in our simple system, we just set a flag and let the main loop
&low_limit, send the I-Am request. */
&high_limit); if (len == 0)
/* in our simple system, we just set a flag and let the main loop I_Am_Request = true;
send the I-Am request. */ else if (len != -1) {
if (len == 0) if ((Device_Object_Instance_Number() >= (uint32_t) low_limit) &&
I_Am_Request = true; (Device_Object_Instance_Number() <= (uint32_t) high_limit))
else if (len != -1) I_Am_Request = true;
{ }
if ((Device_Object_Instance_Number() >= (uint32_t)low_limit) &&
(Device_Object_Instance_Number() <= (uint32_t)high_limit))
I_Am_Request = true;
}
return; return;
} }
+91 -122
View File
@@ -43,132 +43,101 @@
#include "bacfile.h" #include "bacfile.h"
#endif #endif
void handler_write_property( void handler_write_property(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len,
uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data)
BACNET_ADDRESS *src,
BACNET_CONFIRMED_SERVICE_DATA *service_data)
{ {
BACNET_WRITE_PROPERTY_DATA wp_data; BACNET_WRITE_PROPERTY_DATA wp_data;
int len = 0; int len = 0;
int pdu_len = 0; int pdu_len = 0;
BACNET_ADDRESS my_address; BACNET_ADDRESS my_address;
BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT; BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT;
BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT; BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT;
int bytes_sent = 0; int bytes_sent = 0;
// decode the service request only // decode the service request only
len = wp_decode_service_request( len = wp_decode_service_request(service_request,
service_request, service_len, &wp_data);
service_len, fprintf(stderr, "Received Write-Property Request!\n");
&wp_data); if (len > 0)
fprintf(stderr,"Received Write-Property Request!\n"); fprintf(stderr, "type=%u instance=%u property=%u index=%d\n",
if (len > 0) wp_data.object_type,
fprintf(stderr,"type=%u instance=%u property=%u index=%d\n", wp_data.object_instance,
wp_data.object_type, wp_data.object_property, wp_data.array_index);
wp_data.object_instance, else
wp_data.object_property, fprintf(stderr, "Unable to decode Write-Property Request!\n");
wp_data.array_index); // prepare a reply
else datalink_get_my_address(&my_address);
fprintf(stderr,"Unable to decode Write-Property Request!\n"); // encode the NPDU portion of the packet
// prepare a reply pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], src, &my_address, false, // true for confirmed messages
datalink_get_my_address(&my_address); MESSAGE_PRIORITY_NORMAL);
// encode the NPDU portion of the packet // bad decoding or something we didn't understand - send an abort
pdu_len = npdu_encode_apdu( if (len == -1) {
&Handler_Transmit_Buffer[0], pdu_len += abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
src, service_data->invoke_id, ABORT_REASON_OTHER);
&my_address, fprintf(stderr, "Sending Abort!\n");
false, // true for confirmed messages } else if (service_data->segmented_message) {
MESSAGE_PRIORITY_NORMAL); pdu_len += abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
// bad decoding or something we didn't understand - send an abort
if (len == -1)
{
pdu_len += abort_encode_apdu(
&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
ABORT_REASON_OTHER);
fprintf(stderr,"Sending Abort!\n");
}
else if (service_data->segmented_message)
{
pdu_len += abort_encode_apdu(
&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED);
fprintf(stderr,"Sending Abort!\n");
}
else
{
switch (wp_data.object_type)
{
case OBJECT_DEVICE:
if (Device_Write_Property(&wp_data,&error_class,&error_code))
{
pdu_len += encode_simple_ack(
&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id, service_data->invoke_id,
SERVICE_CONFIRMED_WRITE_PROPERTY); ABORT_REASON_SEGMENTATION_NOT_SUPPORTED);
fprintf(stderr,"Sending Write Property Simple Ack!\n"); fprintf(stderr, "Sending Abort!\n");
} else {
switch (wp_data.object_type) {
case OBJECT_DEVICE:
if (Device_Write_Property(&wp_data, &error_class, &error_code)) {
pdu_len +=
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
SERVICE_CONFIRMED_WRITE_PROPERTY);
fprintf(stderr, "Sending Write Property Simple Ack!\n");
} else {
pdu_len +=
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
error_code);
fprintf(stderr, "Sending Write Property Error!\n");
}
break;
case OBJECT_ANALOG_INPUT:
error_class = ERROR_CLASS_PROPERTY;
error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
pdu_len +=
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY,
error_class, error_code);
fprintf(stderr, "Sending Write Access Error!\n");
break;
case OBJECT_ANALOG_OUTPUT:
if (Analog_Output_Write_Property(&wp_data, &error_class,
&error_code)) {
pdu_len +=
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
SERVICE_CONFIRMED_WRITE_PROPERTY);
fprintf(stderr, "Sending Write Property Simple Ack!\n");
} else {
pdu_len +=
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
error_code);
fprintf(stderr, "Sending Write Access Error!\n");
}
break;
default:
pdu_len +=
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY,
error_class, error_code);
fprintf(stderr, "Sending Unknown Object Error!\n");
break;
} }
else
{
pdu_len += bacerror_encode_apdu(
&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
SERVICE_CONFIRMED_WRITE_PROPERTY,
error_class,
error_code);
fprintf(stderr,"Sending Write Property Error!\n");
}
break;
case OBJECT_ANALOG_INPUT:
error_class = ERROR_CLASS_PROPERTY;
error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
pdu_len += bacerror_encode_apdu(
&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
SERVICE_CONFIRMED_WRITE_PROPERTY,
error_class,
error_code);
fprintf(stderr,"Sending Write Access Error!\n");
break;
case OBJECT_ANALOG_OUTPUT:
if (Analog_Output_Write_Property(&wp_data,&error_class,&error_code))
{
pdu_len += encode_simple_ack(
&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
SERVICE_CONFIRMED_WRITE_PROPERTY);
fprintf(stderr,"Sending Write Property Simple Ack!\n");
}
else
{
pdu_len += bacerror_encode_apdu(
&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
SERVICE_CONFIRMED_WRITE_PROPERTY,
error_class,
error_code);
fprintf(stderr,"Sending Write Access Error!\n");
}
break;
default:
pdu_len += bacerror_encode_apdu(
&Handler_Transmit_Buffer[pdu_len],
service_data->invoke_id,
SERVICE_CONFIRMED_WRITE_PROPERTY,
error_class,
error_code);
fprintf(stderr,"Sending Unknown Object Error!\n");
break;
} }
} bytes_sent = datalink_send_pdu(src, // destination address
bytes_sent = datalink_send_pdu( &Handler_Transmit_Buffer[0], pdu_len); // number of bytes of data
src, // destination address if (bytes_sent <= 0)
&Handler_Transmit_Buffer[0], fprintf(stderr, "Failed to send PDU (%s)!\n", strerror(errno));
pdu_len); // number of bytes of data
if (bytes_sent <= 0)
fprintf(stderr,"Failed to send PDU (%s)!\n", strerror(errno));
return; return;
} }
+44 -63
View File
@@ -37,83 +37,64 @@ extern bool I_Am_Request;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
void handler_unrecognized_service( void handler_unrecognized_service(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len,
uint16_t service_len, BACNET_ADDRESS * dest,
BACNET_ADDRESS *dest, BACNET_CONFIRMED_SERVICE_DATA * service_data);
BACNET_CONFIRMED_SERVICE_DATA *service_data);
void handler_who_is( void handler_who_is(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len, BACNET_ADDRESS * src);
uint16_t service_len,
BACNET_ADDRESS *src);
void handler_who_has( void handler_who_has(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len, BACNET_ADDRESS * src);
uint16_t service_len,
BACNET_ADDRESS *src);
void handler_i_am_add( void handler_i_am_add(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len, BACNET_ADDRESS * src);
uint16_t service_len,
BACNET_ADDRESS *src);
void handler_i_am_bind( void handler_i_am_bind(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len, BACNET_ADDRESS * src);
uint16_t service_len,
BACNET_ADDRESS *src);
void handler_read_property( void handler_read_property(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len,
uint16_t service_len, BACNET_ADDRESS * src,
BACNET_ADDRESS *src, BACNET_CONFIRMED_SERVICE_DATA * service_data);
BACNET_CONFIRMED_SERVICE_DATA *service_data);
void handler_read_property_ack( void handler_read_property_ack(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len,
uint16_t service_len, BACNET_ADDRESS * src,
BACNET_ADDRESS *src, BACNET_CONFIRMED_SERVICE_ACK_DATA * service_data);
BACNET_CONFIRMED_SERVICE_ACK_DATA *service_data);
void handler_write_property( void handler_write_property(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len,
uint16_t service_len, BACNET_ADDRESS * src,
BACNET_ADDRESS *src, BACNET_CONFIRMED_SERVICE_DATA * service_data);
BACNET_CONFIRMED_SERVICE_DATA *service_data);
void handler_atomic_read_file( void handler_atomic_read_file(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len,
uint16_t service_len, BACNET_ADDRESS * src,
BACNET_ADDRESS *src, BACNET_CONFIRMED_SERVICE_DATA * service_data);
BACNET_CONFIRMED_SERVICE_DATA *service_data);
void handler_atomic_read_file_ack( void handler_atomic_read_file_ack(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len,
uint16_t service_len, BACNET_ADDRESS * src,
BACNET_ADDRESS *src, BACNET_CONFIRMED_SERVICE_ACK_DATA * service_data);
BACNET_CONFIRMED_SERVICE_ACK_DATA *service_data);
void handler_reinitialize_device( void handler_reinitialize_device(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len,
uint16_t service_len, BACNET_ADDRESS * src,
BACNET_ADDRESS *src, BACNET_CONFIRMED_SERVICE_DATA * service_data);
BACNET_CONFIRMED_SERVICE_DATA *service_data);
void handler_device_communication_control( void handler_device_communication_control(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len,
uint16_t service_len, BACNET_ADDRESS * src,
BACNET_ADDRESS *src, BACNET_CONFIRMED_SERVICE_DATA * service_data);
BACNET_CONFIRMED_SERVICE_DATA *service_data);
void handler_i_have( void handler_i_have(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len, BACNET_ADDRESS * src);
uint16_t service_len,
BACNET_ADDRESS *src);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+21 -31
View File
@@ -34,40 +34,30 @@
#include "npdu.h" #include "npdu.h"
#include "reject.h" #include "reject.h"
void handler_unrecognized_service( void handler_unrecognized_service(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len,
uint16_t service_len, BACNET_ADDRESS * dest, BACNET_CONFIRMED_SERVICE_DATA * service_data)
BACNET_ADDRESS *dest,
BACNET_CONFIRMED_SERVICE_DATA *service_data)
{ {
BACNET_ADDRESS src; BACNET_ADDRESS src;
int pdu_len = 0; int pdu_len = 0;
int bytes_sent = 0; int bytes_sent = 0;
(void)service_request; (void) service_request;
(void)service_len; (void) service_len;
datalink_get_my_address(&src); datalink_get_my_address(&src);
// encode the NPDU portion of the packet // encode the NPDU portion of the packet
pdu_len = npdu_encode_apdu( pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], dest, &src, false, // true for confirmed messages
&Handler_Transmit_Buffer[0], MESSAGE_PRIORITY_NORMAL);
dest,
&src,
false, // true for confirmed messages
MESSAGE_PRIORITY_NORMAL);
// encode the APDU portion of the packet // encode the APDU portion of the packet
pdu_len += reject_encode_apdu( pdu_len += reject_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, REJECT_REASON_UNRECOGNIZED_SERVICE);
service_data->invoke_id,
REJECT_REASON_UNRECOGNIZED_SERVICE);
bytes_sent = datalink_send_pdu( bytes_sent = datalink_send_pdu(dest, // destination address
dest, // destination address &Handler_Transmit_Buffer[0], pdu_len); // number of bytes of data
&Handler_Transmit_Buffer[0], if (bytes_sent > 0)
pdu_len); // number of bytes of data fprintf(stderr, "Sent Reject!\n");
if (bytes_sent > 0) else
fprintf(stderr,"Sent Reject!\n"); fprintf(stderr, "Failed to Send Reject (%s)!\n", strerror(errno));
else
fprintf(stderr,"Failed to Send Reject (%s)!\n", strerror(errno));
} }
+47 -64
View File
@@ -41,73 +41,56 @@
#include "handlers.h" #include "handlers.h"
#include "txbuf.h" #include "txbuf.h"
uint8_t Send_Device_Communication_Control_Request( uint8_t Send_Device_Communication_Control_Request(uint32_t device_id, uint16_t timeDuration, /* 0=optional */
uint32_t device_id, BACNET_COMMUNICATION_ENABLE_DISABLE state, char *password)
uint16_t timeDuration, /* 0=optional */ { /* NULL=optional */
BACNET_COMMUNICATION_ENABLE_DISABLE state, BACNET_ADDRESS dest;
char *password) /* NULL=optional */ BACNET_ADDRESS my_address;
{ unsigned max_apdu = 0;
BACNET_ADDRESS dest; uint8_t invoke_id = 0;
BACNET_ADDRESS my_address; bool status = false;
unsigned max_apdu = 0; int pdu_len = 0;
uint8_t invoke_id = 0; int bytes_sent = 0;
bool status = false; BACNET_CHARACTER_STRING password_string;
int pdu_len = 0;
int bytes_sent = 0;
BACNET_CHARACTER_STRING password_string;
if (!dcc_communication_enabled()) if (!dcc_communication_enabled())
return 0; return 0;
/* is the device bound? */ /* is the device bound? */
status = address_get_by_device(device_id, &max_apdu, &dest); status = address_get_by_device(device_id, &max_apdu, &dest);
/* is there a tsm available? */ /* is there a tsm available? */
if (status) if (status)
status = tsm_transaction_available(); status = tsm_transaction_available();
if (status) if (status) {
{ datalink_get_my_address(&my_address);
datalink_get_my_address(&my_address); pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], &dest, &my_address, true, // true for confirmed messages
pdu_len = npdu_encode_apdu( MESSAGE_PRIORITY_NORMAL);
&Handler_Transmit_Buffer[0],
&dest,
&my_address,
true, // true for confirmed messages
MESSAGE_PRIORITY_NORMAL);
invoke_id = tsm_next_free_invokeID(); invoke_id = tsm_next_free_invokeID();
// load the data for the encoding // load the data for the encoding
characterstring_init_ansi(&password_string,password); characterstring_init_ansi(&password_string, password);
pdu_len += dcc_encode_apdu( pdu_len += dcc_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
&Handler_Transmit_Buffer[pdu_len], invoke_id,
invoke_id, timeDuration, state, password ? &password_string : NULL);
timeDuration, /* will it fit in the sender?
state, note: if there is a bottleneck router in between
password?&password_string:NULL); us and the destination, we won't know unless
/* will it fit in the sender? we have a way to check for that and update the
note: if there is a bottleneck router in between max_apdu in the address binding table. */
us and the destination, we won't know unless if ((unsigned) pdu_len < max_apdu) {
we have a way to check for that and update the tsm_set_confirmed_unsegmented_transaction(invoke_id,
max_apdu in the address binding table. */ &dest, &Handler_Transmit_Buffer[0], pdu_len);
if ((unsigned)pdu_len < max_apdu) bytes_sent = datalink_send_pdu(&dest, // destination address
{ &Handler_Transmit_Buffer[0], pdu_len); // number of bytes of data
tsm_set_confirmed_unsegmented_transaction( if (bytes_sent <= 0)
invoke_id, fprintf(stderr,
&dest, "Failed to Send DeviceCommunicationControl Request (%s)!\n",
&Handler_Transmit_Buffer[0], strerror(errno));
pdu_len); } else
bytes_sent = datalink_send_pdu( fprintf(stderr,
&dest, // destination address "Failed to Send DeviceCommunicationControl Request "
&Handler_Transmit_Buffer[0], "(exceeds destination maximum APDU)!\n");
pdu_len); // number of bytes of data
if (bytes_sent <= 0)
fprintf(stderr,"Failed to Send DeviceCommunicationControl Request (%s)!\n",
strerror(errno));
} }
else
fprintf(stderr,"Failed to Send DeviceCommunicationControl Request "
"(exceeds destination maximum APDU)!\n");
}
return invoke_id; return invoke_id;
} }
+28 -37
View File
@@ -43,43 +43,34 @@
#include "txbuf.h" #include "txbuf.h"
/* find a specific device, or use -1 for limit if you want unlimited */ /* find a specific device, or use -1 for limit if you want unlimited */
void Send_I_Have( void Send_I_Have(uint32_t device_id,
uint32_t device_id, BACNET_OBJECT_TYPE object_type,
BACNET_OBJECT_TYPE object_type, uint32_t object_instance, char *object_name)
uint32_t object_instance,
char *object_name)
{ {
int pdu_len = 0; int pdu_len = 0;
BACNET_ADDRESS dest; BACNET_ADDRESS dest;
int bytes_sent = 0; int bytes_sent = 0;
BACNET_I_HAVE_DATA data; BACNET_I_HAVE_DATA data;
/* if we are forbidden to send, don't send! */ /* if we are forbidden to send, don't send! */
if (!dcc_communication_enabled()) if (!dcc_communication_enabled())
return; return;
/* Who-Has is a global broadcast */ /* Who-Has is a global broadcast */
datalink_get_broadcast_address(&dest); datalink_get_broadcast_address(&dest);
/* encode the NPDU portion of the packet */ /* encode the NPDU portion of the packet */
pdu_len = npdu_encode_apdu( pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], &dest, NULL, false, /* true for confirmed messages */
&Handler_Transmit_Buffer[0], MESSAGE_PRIORITY_NORMAL);
&dest, /* encode the APDU portion of the packet */
NULL, data.device_id.type = OBJECT_DEVICE;
false, /* true for confirmed messages */ data.device_id.instance = device_id;
MESSAGE_PRIORITY_NORMAL); data.object_id.type = object_type;
/* encode the APDU portion of the packet */ data.object_id.instance = object_instance;
data.device_id.type = OBJECT_DEVICE; characterstring_init_ansi(&data.object_name, object_name);
data.device_id.instance = device_id; pdu_len += ihave_encode_apdu(&Handler_Transmit_Buffer[pdu_len], &data);
data.object_id.type = object_type; /* send the data */
data.object_id.instance = object_instance; bytes_sent = datalink_send_pdu(&dest, // destination address
characterstring_init_ansi(&data.object_name,object_name); &Handler_Transmit_Buffer[0], pdu_len); // number of bytes of data
pdu_len += ihave_encode_apdu( if (bytes_sent <= 0)
&Handler_Transmit_Buffer[pdu_len], fprintf(stderr, "Failed to Send I-Have Reply (%s)!\n",
&data); strerror(errno));
/* send the data */
bytes_sent = datalink_send_pdu(
&dest, // destination address
&Handler_Transmit_Buffer[0],
pdu_len); // number of bytes of data
if (bytes_sent <= 0)
fprintf(stderr,"Failed to Send I-Have Reply (%s)!\n", strerror(errno));
} }
+44 -61
View File
@@ -42,71 +42,54 @@
#include "handlers.h" #include "handlers.h"
#include "txbuf.h" #include "txbuf.h"
uint8_t Send_Reinitialize_Device_Request( uint8_t Send_Reinitialize_Device_Request(uint32_t device_id,
uint32_t device_id, BACNET_REINITIALIZED_STATE state, char *password)
BACNET_REINITIALIZED_STATE state,
char *password)
{ {
BACNET_ADDRESS dest; BACNET_ADDRESS dest;
BACNET_ADDRESS my_address; BACNET_ADDRESS my_address;
unsigned max_apdu = 0; unsigned max_apdu = 0;
uint8_t invoke_id = 0; uint8_t invoke_id = 0;
bool status = false; bool status = false;
int pdu_len = 0; int pdu_len = 0;
int bytes_sent = 0; int bytes_sent = 0;
BACNET_CHARACTER_STRING password_string; BACNET_CHARACTER_STRING password_string;
if (!dcc_communication_enabled()) if (!dcc_communication_enabled())
return 0; return 0;
/* is the device bound? */ /* is the device bound? */
status = address_get_by_device(device_id, &max_apdu, &dest); status = address_get_by_device(device_id, &max_apdu, &dest);
/* is there a tsm available? */ /* is there a tsm available? */
if (status) if (status)
status = tsm_transaction_available(); status = tsm_transaction_available();
if (status) if (status) {
{ datalink_get_my_address(&my_address);
datalink_get_my_address(&my_address); pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], &dest, &my_address, true, // true for confirmed messages
pdu_len = npdu_encode_apdu( MESSAGE_PRIORITY_NORMAL);
&Handler_Transmit_Buffer[0],
&dest,
&my_address,
true, // true for confirmed messages
MESSAGE_PRIORITY_NORMAL);
invoke_id = tsm_next_free_invokeID(); invoke_id = tsm_next_free_invokeID();
// load the data for the encoding // load the data for the encoding
characterstring_init_ansi(&password_string,password); characterstring_init_ansi(&password_string, password);
pdu_len += rd_encode_apdu( pdu_len += rd_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
&Handler_Transmit_Buffer[pdu_len], invoke_id, state, password ? &password_string : NULL);
invoke_id, /* will it fit in the sender?
state, note: if there is a bottleneck router in between
password?&password_string:NULL); us and the destination, we won't know unless
/* will it fit in the sender? we have a way to check for that and update the
note: if there is a bottleneck router in between max_apdu in the address binding table. */
us and the destination, we won't know unless if ((unsigned) pdu_len < max_apdu) {
we have a way to check for that and update the tsm_set_confirmed_unsegmented_transaction(invoke_id,
max_apdu in the address binding table. */ &dest, &Handler_Transmit_Buffer[0], pdu_len);
if ((unsigned)pdu_len < max_apdu) bytes_sent = datalink_send_pdu(&dest, // destination address
{ &Handler_Transmit_Buffer[0], pdu_len); // number of bytes of data
tsm_set_confirmed_unsegmented_transaction( if (bytes_sent <= 0)
invoke_id, fprintf(stderr,
&dest, "Failed to Send ReinitializeDevice Request (%s)!\n",
&Handler_Transmit_Buffer[0], strerror(errno));
pdu_len); } else
bytes_sent = datalink_send_pdu( fprintf(stderr, "Failed to Send ReinitializeDevice Request "
&dest, // destination address "(exceeds destination maximum APDU)!\n");
&Handler_Transmit_Buffer[0],
pdu_len); // number of bytes of data
if (bytes_sent <= 0)
fprintf(stderr,"Failed to Send ReinitializeDevice Request (%s)!\n",
strerror(errno));
} }
else
fprintf(stderr,"Failed to Send ReinitializeDevice Request "
"(exceeds destination maximum APDU)!\n");
}
return invoke_id; return invoke_id;
} }
+49 -64
View File
@@ -43,74 +43,59 @@
#include "txbuf.h" #include "txbuf.h"
/* returns invoke id of 0 if device is not bound or no tsm available */ /* returns invoke id of 0 if device is not bound or no tsm available */
uint8_t Send_Read_Property_Request( uint8_t Send_Read_Property_Request(uint32_t device_id, /* destination device */
uint32_t device_id, /* destination device */ BACNET_OBJECT_TYPE object_type,
BACNET_OBJECT_TYPE object_type, uint32_t object_instance,
uint32_t object_instance, BACNET_PROPERTY_ID object_property, int32_t array_index)
BACNET_PROPERTY_ID object_property,
int32_t array_index)
{ {
BACNET_ADDRESS dest; BACNET_ADDRESS dest;
BACNET_ADDRESS my_address; BACNET_ADDRESS my_address;
unsigned max_apdu = 0; unsigned max_apdu = 0;
uint8_t invoke_id = 0; uint8_t invoke_id = 0;
bool status = false; bool status = false;
int pdu_len = 0; int pdu_len = 0;
int bytes_sent = 0; int bytes_sent = 0;
BACNET_READ_PROPERTY_DATA data; BACNET_READ_PROPERTY_DATA data;
if (!dcc_communication_enabled()) if (!dcc_communication_enabled())
return 0; return 0;
/* is the device bound? */ /* is the device bound? */
status = address_get_by_device(device_id, &max_apdu, &dest); status = address_get_by_device(device_id, &max_apdu, &dest);
/* is there a tsm available? */ /* is there a tsm available? */
if (status) if (status)
status = tsm_transaction_available(); status = tsm_transaction_available();
if (status) if (status) {
{ datalink_get_my_address(&my_address);
datalink_get_my_address(&my_address); pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], &dest, &my_address, true, // true for confirmed messages
pdu_len = npdu_encode_apdu( MESSAGE_PRIORITY_NORMAL);
&Handler_Transmit_Buffer[0],
&dest,
&my_address,
true, // true for confirmed messages
MESSAGE_PRIORITY_NORMAL);
invoke_id = tsm_next_free_invokeID(); invoke_id = tsm_next_free_invokeID();
// load the data for the encoding // load the data for the encoding
data.object_type = object_type; data.object_type = object_type;
data.object_instance = object_instance; data.object_instance = object_instance;
data.object_property = object_property; data.object_property = object_property;
data.array_index = array_index; data.array_index = array_index;
pdu_len += rp_encode_apdu( pdu_len += rp_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
&Handler_Transmit_Buffer[pdu_len], invoke_id, &data);
invoke_id, /* will it fit in the sender?
&data); note: if there is a bottleneck router in between
/* will it fit in the sender? us and the destination, we won't know unless
note: if there is a bottleneck router in between we have a way to check for that and update the
us and the destination, we won't know unless max_apdu in the address binding table. */
we have a way to check for that and update the if ((unsigned) pdu_len < max_apdu) {
max_apdu in the address binding table. */ tsm_set_confirmed_unsegmented_transaction(invoke_id,
if ((unsigned)pdu_len < max_apdu) &dest, &Handler_Transmit_Buffer[0], pdu_len);
{ bytes_sent = datalink_send_pdu(&dest, // destination address
tsm_set_confirmed_unsegmented_transaction( &Handler_Transmit_Buffer[0], pdu_len); // number of bytes of data
invoke_id, if (bytes_sent <= 0)
&dest, fprintf(stderr,
&Handler_Transmit_Buffer[0], "Failed to Send ReadProperty Request (%s)!\n",
pdu_len); strerror(errno));
bytes_sent = datalink_send_pdu( } else
&dest, // destination address fprintf(stderr, "Failed to Send ReadProperty Request "
&Handler_Transmit_Buffer[0], "(exceeds destination maximum APDU)!\n");
pdu_len); // number of bytes of data
if (bytes_sent <= 0)
fprintf(stderr,"Failed to Send ReadProperty Request (%s)!\n",
strerror(errno));
} }
else
fprintf(stderr,"Failed to Send ReadProperty Request "
"(exceeds destination maximum APDU)!\n");
}
return invoke_id; return invoke_id;
} }
+56 -72
View File
@@ -43,83 +43,67 @@
#include "txbuf.h" #include "txbuf.h"
/* find a specific device, or use -1 for limit if you want unlimited */ /* find a specific device, or use -1 for limit if you want unlimited */
void Send_WhoHas_Name( void Send_WhoHas_Name(int32_t low_limit,
int32_t low_limit, int32_t high_limit, char *object_name)
int32_t high_limit,
char *object_name)
{ {
int pdu_len = 0; int pdu_len = 0;
BACNET_ADDRESS dest; BACNET_ADDRESS dest;
int bytes_sent = 0; int bytes_sent = 0;
BACNET_WHO_HAS_DATA data; BACNET_WHO_HAS_DATA data;
/* if we are forbidden to send, don't send! */ /* if we are forbidden to send, don't send! */
if (!dcc_communication_enabled()) if (!dcc_communication_enabled())
return; return;
/* Who-Has is a global broadcast */ /* Who-Has is a global broadcast */
datalink_get_broadcast_address(&dest); datalink_get_broadcast_address(&dest);
/* encode the NPDU portion of the packet */ /* encode the NPDU portion of the packet */
pdu_len = npdu_encode_apdu( pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], &dest, NULL, false, /* true for confirmed messages */
&Handler_Transmit_Buffer[0], MESSAGE_PRIORITY_NORMAL);
&dest, /* encode the APDU portion of the packet */
NULL, data.low_limit = low_limit;
false, /* true for confirmed messages */ data.high_limit = high_limit;
MESSAGE_PRIORITY_NORMAL); data.object_name = true;
/* encode the APDU portion of the packet */ characterstring_init_ansi(&data.object.name, object_name);
data.low_limit = low_limit; pdu_len += whohas_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
data.high_limit = high_limit; &data);
data.object_name = true; /* send the data */
characterstring_init_ansi(&data.object.name,object_name); bytes_sent = datalink_send_pdu(&dest, // destination address
pdu_len += whohas_encode_apdu( &Handler_Transmit_Buffer[0], pdu_len); // number of bytes of data
&Handler_Transmit_Buffer[pdu_len], if (bytes_sent <= 0)
&data); fprintf(stderr, "Failed to Send Who-Has Request (%s)!\n",
/* send the data */ strerror(errno));
bytes_sent = datalink_send_pdu(
&dest, // destination address
&Handler_Transmit_Buffer[0],
pdu_len); // number of bytes of data
if (bytes_sent <= 0)
fprintf(stderr,"Failed to Send Who-Has Request (%s)!\n", strerror(errno));
} }
/* find a specific device, or use -1 for limit if you want unlimited */ /* find a specific device, or use -1 for limit if you want unlimited */
void Send_WhoHas_Object( void Send_WhoHas_Object(int32_t low_limit,
int32_t low_limit, int32_t high_limit,
int32_t high_limit, BACNET_OBJECT_TYPE object_type, uint32_t object_instance)
BACNET_OBJECT_TYPE object_type,
uint32_t object_instance)
{ {
int pdu_len = 0; int pdu_len = 0;
BACNET_ADDRESS dest; BACNET_ADDRESS dest;
int bytes_sent = 0; int bytes_sent = 0;
BACNET_WHO_HAS_DATA data; BACNET_WHO_HAS_DATA data;
/* if we are forbidden to send, don't send! */ /* if we are forbidden to send, don't send! */
if (!dcc_communication_enabled()) if (!dcc_communication_enabled())
return; return;
/* Who-Has is a global broadcast */ /* Who-Has is a global broadcast */
datalink_get_broadcast_address(&dest); datalink_get_broadcast_address(&dest);
/* encode the NPDU portion of the packet */ /* encode the NPDU portion of the packet */
pdu_len = npdu_encode_apdu( pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], &dest, NULL, false, /* true for confirmed messages */
&Handler_Transmit_Buffer[0], MESSAGE_PRIORITY_NORMAL);
&dest, /* encode the APDU portion of the packet */
NULL, data.low_limit = low_limit;
false, /* true for confirmed messages */ data.high_limit = high_limit;
MESSAGE_PRIORITY_NORMAL); data.object_name = false;
/* encode the APDU portion of the packet */ data.object.identifier.type = object_type;
data.low_limit = low_limit; data.object.identifier.instance = object_instance;
data.high_limit = high_limit; pdu_len += whohas_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
data.object_name = false; &data);
data.object.identifier.type = object_type; /* send the data */
data.object.identifier.instance = object_instance; bytes_sent = datalink_send_pdu(&dest, // destination address
pdu_len += whohas_encode_apdu( &Handler_Transmit_Buffer[0], pdu_len); // number of bytes of data
&Handler_Transmit_Buffer[pdu_len], if (bytes_sent <= 0)
&data); fprintf(stderr, "Failed to Send Who-Has Request (%s)!\n",
/* send the data */ strerror(errno));
bytes_sent = datalink_send_pdu(
&dest, // destination address
&Handler_Transmit_Buffer[0],
pdu_len); // number of bytes of data
if (bytes_sent <= 0)
fprintf(stderr,"Failed to Send Who-Has Request (%s)!\n", strerror(errno));
} }
+19 -28
View File
@@ -43,38 +43,29 @@
#include "txbuf.h" #include "txbuf.h"
/* find a specific device, or use -1 for limit if you want unlimited */ /* find a specific device, or use -1 for limit if you want unlimited */
void Send_WhoIs( void Send_WhoIs(int32_t low_limit, int32_t high_limit)
int32_t low_limit,
int32_t high_limit)
{ {
int pdu_len = 0; int pdu_len = 0;
BACNET_ADDRESS dest; BACNET_ADDRESS dest;
int bytes_sent = 0; int bytes_sent = 0;
if (!dcc_communication_enabled()) if (!dcc_communication_enabled())
return; return;
// Who-Is is a global broadcast // Who-Is is a global broadcast
datalink_get_broadcast_address(&dest); datalink_get_broadcast_address(&dest);
// encode the NPDU portion of the packet // encode the NPDU portion of the packet
pdu_len = npdu_encode_apdu( pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], &dest, NULL, false, // true for confirmed messages
&Handler_Transmit_Buffer[0], MESSAGE_PRIORITY_NORMAL);
&dest,
NULL,
false, // true for confirmed messages
MESSAGE_PRIORITY_NORMAL);
// encode the APDU portion of the packet // encode the APDU portion of the packet
pdu_len += whois_encode_apdu( pdu_len += whois_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
&Handler_Transmit_Buffer[pdu_len], low_limit, high_limit);
low_limit,
high_limit);
bytes_sent = datalink_send_pdu( bytes_sent = datalink_send_pdu(&dest, // destination address
&dest, // destination address &Handler_Transmit_Buffer[0], pdu_len); // number of bytes of data
&Handler_Transmit_Buffer[0], if (bytes_sent <= 0)
pdu_len); // number of bytes of data fprintf(stderr, "Failed to Send Who-Is Request (%s)!\n",
if (bytes_sent <= 0) strerror(errno));
fprintf(stderr,"Failed to Send Who-Is Request (%s)!\n", strerror(errno));
} }
+53 -69
View File
@@ -43,79 +43,63 @@
#include "txbuf.h" #include "txbuf.h"
/* returns the invoke ID for confirmed request, or zero on failure */ /* returns the invoke ID for confirmed request, or zero on failure */
uint8_t Send_Write_Property_Request( uint8_t Send_Write_Property_Request(uint32_t device_id, // destination device
uint32_t device_id, // destination device BACNET_OBJECT_TYPE object_type,
BACNET_OBJECT_TYPE object_type, uint32_t object_instance,
uint32_t object_instance, BACNET_PROPERTY_ID object_property,
BACNET_PROPERTY_ID object_property, BACNET_APPLICATION_DATA_VALUE * object_value,
BACNET_APPLICATION_DATA_VALUE *object_value, uint8_t priority, int32_t array_index)
uint8_t priority,
int32_t array_index)
{ {
BACNET_ADDRESS dest; BACNET_ADDRESS dest;
BACNET_ADDRESS my_address; BACNET_ADDRESS my_address;
unsigned max_apdu = 0; unsigned max_apdu = 0;
uint8_t invoke_id = 0; uint8_t invoke_id = 0;
bool status = false; bool status = false;
int pdu_len = 0; int pdu_len = 0;
int bytes_sent = 0; int bytes_sent = 0;
BACNET_WRITE_PROPERTY_DATA data; BACNET_WRITE_PROPERTY_DATA data;
if (!dcc_communication_enabled()) if (!dcc_communication_enabled())
return 0; return 0;
/* is the device bound? */ /* is the device bound? */
status = address_get_by_device(device_id, &max_apdu, &dest); status = address_get_by_device(device_id, &max_apdu, &dest);
/* is there a tsm available? */ /* is there a tsm available? */
if (status) if (status)
status = tsm_transaction_available(); status = tsm_transaction_available();
if (status) if (status) {
{ datalink_get_my_address(&my_address);
datalink_get_my_address(&my_address); pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], &dest, &my_address, true, // true for confirmed messages
pdu_len = npdu_encode_apdu( MESSAGE_PRIORITY_NORMAL);
&Handler_Transmit_Buffer[0],
&dest,
&my_address,
true, // true for confirmed messages
MESSAGE_PRIORITY_NORMAL);
invoke_id = tsm_next_free_invokeID(); invoke_id = tsm_next_free_invokeID();
// load the data for the encoding // load the data for the encoding
data.object_type = object_type; data.object_type = object_type;
data.object_instance = object_instance; data.object_instance = object_instance;
data.object_property = object_property; data.object_property = object_property;
data.array_index = array_index; data.array_index = array_index;
bacapp_copy(&data.value,object_value); bacapp_copy(&data.value, object_value);
data.priority = priority; data.priority = priority;
pdu_len += wp_encode_apdu( pdu_len += wp_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
&Handler_Transmit_Buffer[pdu_len], invoke_id, &data);
invoke_id, /* will it fit in the sender?
&data); note: if there is a bottleneck router in between
/* will it fit in the sender? us and the destination, we won't know unless
note: if there is a bottleneck router in between we have a way to check for that and update the
us and the destination, we won't know unless max_apdu in the address binding table. */
we have a way to check for that and update the if ((unsigned) pdu_len < max_apdu) {
max_apdu in the address binding table. */ tsm_set_confirmed_unsegmented_transaction(invoke_id,
if ((unsigned)pdu_len < max_apdu) &dest, &Handler_Transmit_Buffer[0], pdu_len);
{ bytes_sent = datalink_send_pdu(&dest, // destination address
tsm_set_confirmed_unsegmented_transaction( &Handler_Transmit_Buffer[0], pdu_len); // number of bytes of data
invoke_id, if (bytes_sent <= 0)
&dest, fprintf(stderr,
&Handler_Transmit_Buffer[0], "Failed to Send WriteProperty Request (%s)!\n",
pdu_len); strerror(errno));
bytes_sent = datalink_send_pdu( } else
&dest, // destination address fprintf(stderr, "Failed to Send WriteProperty Request "
&Handler_Transmit_Buffer[0], "(exceeds destination maximum APDU)!\n");
pdu_len); // number of bytes of data
if (bytes_sent <= 0)
fprintf(stderr,"Failed to Send WriteProperty Request (%s)!\n",
strerror(errno));
} }
else
fprintf(stderr,"Failed to Send WriteProperty Request "
"(exceeds destination maximum APDU)!\n");
}
return invoke_id; return invoke_id;
} }
+1 -2
View File
@@ -27,5 +27,4 @@
#include "config.h" #include "config.h"
#include "datalink.h" #include "datalink.h"
uint8_t Handler_Transmit_Buffer[MAX_MPDU] = {0}; uint8_t Handler_Transmit_Buffer[MAX_MPDU] = { 0 };
+74 -83
View File
@@ -31,7 +31,7 @@
#include "bacdef.h" #include "bacdef.h"
#include "bacdcode.h" #include "bacdcode.h"
#include "bacenum.h" #include "bacenum.h"
#include "config.h" // the custom stuff #include "config.h" // the custom stuff
#define MAX_ANALOG_INPUTS 7 #define MAX_ANALOG_INPUTS 7
@@ -40,17 +40,17 @@
// given instance exists // 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) if (object_instance < MAX_ANALOG_INPUTS)
return true; return true;
return false; return false;
} }
// we simply have 0-n object instances. Yours might be // we simply have 0-n object instances. Yours might be
// more complex, and then count how many you have // more complex, and then count how many you have
unsigned Analog_Input_Count(void) unsigned Analog_Input_Count(void)
{ {
return MAX_ANALOG_INPUTS; return MAX_ANALOG_INPUTS;
} }
// we simply have 0-n object instances. Yours might be // we simply have 0-n object instances. Yours might be
@@ -58,81 +58,77 @@ unsigned Analog_Input_Count(void)
// that correlates to the correct index // that correlates to the correct index
uint32_t Analog_Input_Index_To_Instance(unsigned index) uint32_t Analog_Input_Index_To_Instance(unsigned index)
{ {
return index; return index;
} }
char *Analog_Input_Name(uint32_t object_instance) char *Analog_Input_Name(uint32_t object_instance)
{ {
static char text_string[32] = ""; /* okay for single thread */ static char text_string[32] = ""; /* okay for single thread */
if (object_instance < MAX_ANALOG_INPUTS) if (object_instance < MAX_ANALOG_INPUTS) {
{ sprintf(text_string, "ANALOG INPUT %u", object_instance);
sprintf(text_string,"ANALOG INPUT %u",object_instance); return text_string;
return text_string; }
}
return NULL; return NULL;
} }
/* return apdu length, or -1 on error */ /* return apdu length, or -1 on error */
/* assumption - object has already exists */ /* assumption - object has already exists */
int Analog_Input_Encode_Property_APDU( int Analog_Input_Encode_Property_APDU(uint8_t * apdu,
uint8_t *apdu, uint32_t object_instance,
uint32_t object_instance, BACNET_PROPERTY_ID property,
BACNET_PROPERTY_ID property, int32_t array_index,
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_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string; BACNET_CHARACTER_STRING char_string;
float value = 3.14; float value = 3.14;
(void)array_index; (void) array_index;
switch (property) switch (property) {
{
case PROP_OBJECT_IDENTIFIER: case PROP_OBJECT_IDENTIFIER:
apdu_len = encode_tagged_object_id(&apdu[0], OBJECT_ANALOG_INPUT, apdu_len = encode_tagged_object_id(&apdu[0], OBJECT_ANALOG_INPUT,
object_instance); object_instance);
break; break;
case PROP_OBJECT_NAME: case PROP_OBJECT_NAME:
case PROP_DESCRIPTION: case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string, Analog_Input_Name(object_instance)); characterstring_init_ansi(&char_string,
apdu_len = encode_tagged_character_string(&apdu[0], Analog_Input_Name(object_instance));
&char_string); apdu_len = encode_tagged_character_string(&apdu[0], &char_string);
break; break;
case PROP_OBJECT_TYPE: case PROP_OBJECT_TYPE:
apdu_len = encode_tagged_enumerated(&apdu[0], OBJECT_ANALOG_INPUT); apdu_len = encode_tagged_enumerated(&apdu[0], OBJECT_ANALOG_INPUT);
break; break;
case PROP_PRESENT_VALUE: case PROP_PRESENT_VALUE:
apdu_len = encode_tagged_real(&apdu[0], value); apdu_len = encode_tagged_real(&apdu[0], value);
break; break;
case PROP_STATUS_FLAGS: case PROP_STATUS_FLAGS:
bitstring_init(&bit_string); bitstring_init(&bit_string);
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); 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_FAULT, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
apdu_len = encode_tagged_bitstring(&apdu[0], &bit_string); apdu_len = encode_tagged_bitstring(&apdu[0], &bit_string);
break; break;
case PROP_EVENT_STATE: case PROP_EVENT_STATE:
apdu_len = encode_tagged_enumerated(&apdu[0],EVENT_STATE_NORMAL); apdu_len = encode_tagged_enumerated(&apdu[0], EVENT_STATE_NORMAL);
break; break;
case PROP_OUT_OF_SERVICE: case PROP_OUT_OF_SERVICE:
apdu_len = encode_tagged_boolean(&apdu[0],false); apdu_len = encode_tagged_boolean(&apdu[0], false);
break; break;
case PROP_UNITS: case PROP_UNITS:
apdu_len = encode_tagged_enumerated(&apdu[0],UNITS_PERCENT); apdu_len = encode_tagged_enumerated(&apdu[0], UNITS_PERCENT);
break; break;
default: default:
*error_class = ERROR_CLASS_PROPERTY; *error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_UNKNOWN_PROPERTY; *error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = -1; apdu_len = -1;
break; break;
} }
return apdu_len; return apdu_len;
} }
#ifdef TEST #ifdef TEST
@@ -142,34 +138,31 @@ int Analog_Input_Encode_Property_APDU(
void testAnalogInput(Test * pTest) void testAnalogInput(Test * pTest)
{ {
uint8_t apdu[MAX_APDU] = { 0 }; uint8_t apdu[MAX_APDU] = { 0 };
int len = 0; int len = 0;
uint32_t len_value = 0; uint32_t len_value = 0;
uint8_t tag_number = 0; uint8_t tag_number = 0;
BACNET_OBJECT_TYPE decoded_type = OBJECT_ANALOG_OUTPUT; BACNET_OBJECT_TYPE decoded_type = OBJECT_ANALOG_OUTPUT;
uint32_t decoded_instance = 0; uint32_t decoded_instance = 0;
uint32_t instance = 123; uint32_t instance = 123;
BACNET_ERROR_CLASS error_class; BACNET_ERROR_CLASS error_class;
BACNET_ERROR_CODE error_code; BACNET_ERROR_CODE error_code;
// FIXME: we should do a lot more testing here... // FIXME: we should do a lot more testing here...
len = Analog_Input_Encode_Property_APDU( len = Analog_Input_Encode_Property_APDU(&apdu[0],
&apdu[0], instance,
instance, PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
BACNET_ARRAY_ALL, ct_test(pTest, len >= 0);
&error_class, len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
&error_code); ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
ct_test(pTest, len >= 0); len = decode_object_id(&apdu[len],
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len = decode_object_id(&apdu[len],
(int *) &decoded_type, &decoded_instance); (int *) &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == OBJECT_ANALOG_INPUT); ct_test(pTest, decoded_type == OBJECT_ANALOG_INPUT);
ct_test(pTest, decoded_instance == instance); ct_test(pTest, decoded_instance == instance);
return; return;
} }
#ifdef TEST_ANALOG_INPUT #ifdef TEST_ANALOG_INPUT
@@ -192,5 +185,3 @@ int main(void)
} }
#endif /* TEST_ANALOG_INPUT */ #endif /* TEST_ANALOG_INPUT */
#endif /* TEST */ #endif /* TEST */
+12 -15
View File
@@ -31,28 +31,25 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
bool Analog_Input_Valid_Instance(uint32_t object_instance); bool Analog_Input_Valid_Instance(uint32_t object_instance);
unsigned Analog_Input_Count(void); unsigned Analog_Input_Count(void);
uint32_t Analog_Input_Index_To_Instance(unsigned index); uint32_t Analog_Input_Index_To_Instance(unsigned index);
char *Analog_Input_Name(uint32_t object_instance); char *Analog_Input_Name(uint32_t object_instance);
int Analog_Input_Encode_Property_APDU( int Analog_Input_Encode_Property_APDU(uint8_t * apdu,
uint8_t *apdu, uint32_t object_instance,
uint32_t object_instance, BACNET_PROPERTY_ID property,
BACNET_PROPERTY_ID property, int32_t array_index,
int32_t array_index, BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code);
BACNET_ERROR_CLASS *error_class,
BACNET_ERROR_CODE *error_code);
#ifdef TEST #ifdef TEST
#include "ctest.h" #include "ctest.h"
void testAnalogInput(Test * pTest); void testAnalogInput(Test * pTest);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+229 -267
View File
@@ -31,7 +31,7 @@
#include "bacdef.h" #include "bacdef.h"
#include "bacdcode.h" #include "bacdcode.h"
#include "bacenum.h" #include "bacenum.h"
#include "config.h" // the custom stuff #include "config.h" // the custom stuff
#include "wp.h" #include "wp.h"
#define MAX_ANALOG_OUTPUTS 4 #define MAX_ANALOG_OUTPUTS 4
@@ -46,7 +46,8 @@
// Here is our Priority Array. They are supposed to be Real, but // Here is our Priority Array. They are supposed to be Real, but
// we don't have that kind of memory, so we will use a single byte // we don't have that kind of memory, so we will use a single byte
// and load a Real for returning the value when asked. // and load a Real for returning the value when asked.
static uint8_t Analog_Output_Level[MAX_ANALOG_OUTPUTS][BACNET_MAX_PRIORITY]; static uint8_t
Analog_Output_Level[MAX_ANALOG_OUTPUTS][BACNET_MAX_PRIORITY];
// Writable out-of-service allows others to play with our Present Value // Writable out-of-service allows others to play with our Present Value
// without changing the physical output // without changing the physical output
static bool Analog_Output_Out_Of_Service[MAX_ANALOG_OUTPUTS]; static bool Analog_Output_Out_Of_Service[MAX_ANALOG_OUTPUTS];
@@ -56,23 +57,20 @@ static bool Analog_Ouput_Initialized = false;
void Analog_Output_Init(void) void Analog_Output_Init(void)
{ {
unsigned i,j; unsigned i, j;
if (!Analog_Ouput_Initialized) if (!Analog_Ouput_Initialized) {
{ Analog_Ouput_Initialized = true;
Analog_Ouput_Initialized = true;
// initialize all the analog output priority arrays to NULL // initialize all the analog output priority arrays to NULL
for (i = 0; i < MAX_ANALOG_OUTPUTS; i++) for (i = 0; i < MAX_ANALOG_OUTPUTS; i++) {
{ for (j = 0; j < BACNET_MAX_PRIORITY; j++) {
for (j = 0; j < BACNET_MAX_PRIORITY; j++) Analog_Output_Level[i][j] = AO_LEVEL_NULL;
{ }
Analog_Output_Level[i][j] = AO_LEVEL_NULL; }
}
} }
}
return; return;
} }
// we simply have 0-n object instances. Yours might be // we simply have 0-n object instances. Yours might be
@@ -80,19 +78,19 @@ void Analog_Output_Init(void)
// given instance exists // given instance exists
bool Analog_Output_Valid_Instance(uint32_t object_instance) bool Analog_Output_Valid_Instance(uint32_t object_instance)
{ {
Analog_Output_Init(); Analog_Output_Init();
if (object_instance < MAX_ANALOG_OUTPUTS) if (object_instance < MAX_ANALOG_OUTPUTS)
return true; return true;
return false; return false;
} }
// we simply have 0-n object instances. Yours might be // we simply have 0-n object instances. Yours might be
// more complex, and then count how many you have // more complex, and then count how many you have
unsigned Analog_Output_Count(void) unsigned Analog_Output_Count(void)
{ {
Analog_Output_Init(); Analog_Output_Init();
return MAX_ANALOG_OUTPUTS; return MAX_ANALOG_OUTPUTS;
} }
// we simply have 0-n object instances. Yours might be // we simply have 0-n object instances. Yours might be
@@ -100,8 +98,8 @@ unsigned Analog_Output_Count(void)
// that correlates to the correct index // that correlates to the correct index
uint32_t Analog_Output_Index_To_Instance(unsigned index) uint32_t Analog_Output_Index_To_Instance(unsigned index)
{ {
Analog_Output_Init(); Analog_Output_Init();
return index; return index;
} }
// we simply have 0-n object instances. Yours might be // we simply have 0-n object instances. Yours might be
@@ -109,271 +107,240 @@ uint32_t Analog_Output_Index_To_Instance(unsigned index)
// that correlates to the correct instance number // that correlates to the correct instance number
unsigned Analog_Output_Instance_To_Index(uint32_t object_instance) unsigned Analog_Output_Instance_To_Index(uint32_t object_instance)
{ {
unsigned index = MAX_ANALOG_OUTPUTS; unsigned index = MAX_ANALOG_OUTPUTS;
Analog_Output_Init(); Analog_Output_Init();
if (object_instance < MAX_ANALOG_OUTPUTS) if (object_instance < MAX_ANALOG_OUTPUTS)
index = object_instance; index = object_instance;
return index; return index;
} }
static float Analog_Output_Present_Value(uint32_t object_instance) static float Analog_Output_Present_Value(uint32_t object_instance)
{ {
float value = AO_RELINQUISH_DEFAULT; float value = AO_RELINQUISH_DEFAULT;
unsigned index = 0; unsigned index = 0;
unsigned i = 0; unsigned i = 0;
Analog_Output_Init(); Analog_Output_Init();
index = Analog_Output_Instance_To_Index(object_instance); index = Analog_Output_Instance_To_Index(object_instance);
if (index < MAX_ANALOG_OUTPUTS) if (index < MAX_ANALOG_OUTPUTS) {
{ for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
for (i = 0; i < BACNET_MAX_PRIORITY; i++) if (Analog_Output_Level[index][i] != AO_LEVEL_NULL) {
{ value = Analog_Output_Level[index][i];
if (Analog_Output_Level[index][i] != AO_LEVEL_NULL) break;
{ }
value = Analog_Output_Level[index][i]; }
break;
}
} }
}
return value; return value;
} }
/* note: the object name must be unique within this device */ /* note: the object name must be unique within this device */
char *Analog_Output_Name(uint32_t object_instance) char *Analog_Output_Name(uint32_t object_instance)
{ {
static char text_string[32] = ""; /* okay for single thread */ static char text_string[32] = ""; /* okay for single thread */
if (object_instance < MAX_ANALOG_OUTPUTS) if (object_instance < MAX_ANALOG_OUTPUTS) {
{ sprintf(text_string, "ANALOG OUTPUT %u", object_instance);
sprintf(text_string,"ANALOG OUTPUT %u",object_instance); return text_string;
return text_string; }
}
return NULL; return NULL;
} }
/* return apdu len, or -1 on error */ /* return apdu len, or -1 on error */
int Analog_Output_Encode_Property_APDU( int Analog_Output_Encode_Property_APDU(uint8_t * apdu,
uint8_t *apdu, uint32_t object_instance,
uint32_t object_instance, BACNET_PROPERTY_ID property,
BACNET_PROPERTY_ID property, int32_t array_index,
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 len = 0;
int apdu_len = 0; // return value int apdu_len = 0; // return value
BACNET_BIT_STRING bit_string; BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string; BACNET_CHARACTER_STRING char_string;
float real_value = 1.414; float real_value = 1.414;
unsigned object_index = 0; unsigned object_index = 0;
unsigned i = 0; unsigned i = 0;
Analog_Output_Init(); Analog_Output_Init();
switch (property) switch (property) {
{
case PROP_OBJECT_IDENTIFIER: case PROP_OBJECT_IDENTIFIER:
apdu_len = encode_tagged_object_id(&apdu[0], OBJECT_ANALOG_OUTPUT, apdu_len = encode_tagged_object_id(&apdu[0], OBJECT_ANALOG_OUTPUT,
object_instance); object_instance);
break; break;
case PROP_OBJECT_NAME: case PROP_OBJECT_NAME:
case PROP_DESCRIPTION: case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string, Analog_Output_Name(object_instance)); characterstring_init_ansi(&char_string,
apdu_len = encode_tagged_character_string(&apdu[0], Analog_Output_Name(object_instance));
&char_string); apdu_len = encode_tagged_character_string(&apdu[0], &char_string);
break; break;
case PROP_OBJECT_TYPE: case PROP_OBJECT_TYPE:
apdu_len = encode_tagged_enumerated(&apdu[0], OBJECT_ANALOG_OUTPUT); apdu_len =
break; encode_tagged_enumerated(&apdu[0], OBJECT_ANALOG_OUTPUT);
break;
case PROP_PRESENT_VALUE: case PROP_PRESENT_VALUE:
real_value = Analog_Output_Present_Value(object_instance); real_value = Analog_Output_Present_Value(object_instance);
apdu_len = encode_tagged_real(&apdu[0], real_value); apdu_len = encode_tagged_real(&apdu[0], real_value);
break; break;
case PROP_STATUS_FLAGS: case PROP_STATUS_FLAGS:
bitstring_init(&bit_string); bitstring_init(&bit_string);
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); 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_FAULT, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
apdu_len = encode_tagged_bitstring(&apdu[0], &bit_string); apdu_len = encode_tagged_bitstring(&apdu[0], &bit_string);
break; break;
case PROP_EVENT_STATE: case PROP_EVENT_STATE:
apdu_len = encode_tagged_enumerated(&apdu[0],EVENT_STATE_NORMAL); apdu_len = encode_tagged_enumerated(&apdu[0], EVENT_STATE_NORMAL);
break; break;
case PROP_OUT_OF_SERVICE: case PROP_OUT_OF_SERVICE:
apdu_len = encode_tagged_boolean(&apdu[0],false); apdu_len = encode_tagged_boolean(&apdu[0], false);
break; break;
case PROP_UNITS: case PROP_UNITS:
apdu_len = encode_tagged_enumerated(&apdu[0],UNITS_PERCENT); apdu_len = encode_tagged_enumerated(&apdu[0], UNITS_PERCENT);
break; break;
case PROP_PRIORITY_ARRAY: case PROP_PRIORITY_ARRAY:
// Array element zero is the number of elements in the array // Array element zero is the number of elements in the array
if (array_index == BACNET_ARRAY_LENGTH_INDEX) if (array_index == BACNET_ARRAY_LENGTH_INDEX)
apdu_len = encode_tagged_unsigned(&apdu[0], BACNET_MAX_PRIORITY); apdu_len =
// if no index was specified, then try to encode the entire list encode_tagged_unsigned(&apdu[0], BACNET_MAX_PRIORITY);
// into one packet. // if no index was specified, then try to encode the entire list
else if (array_index == BACNET_ARRAY_ALL) // into one packet.
{ else if (array_index == BACNET_ARRAY_ALL) {
object_index = Analog_Output_Instance_To_Index(object_instance); object_index =
for (i = 0; i < BACNET_MAX_PRIORITY; i++) Analog_Output_Instance_To_Index(object_instance);
{ for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
// FIXME: check if we have room before adding it to APDU // FIXME: check if we have room before adding it to APDU
if (Analog_Output_Level[object_index][i] == AO_LEVEL_NULL) if (Analog_Output_Level[object_index][i] == AO_LEVEL_NULL)
len = encode_tagged_null(&apdu[apdu_len]); len = encode_tagged_null(&apdu[apdu_len]);
else else {
{ real_value = Analog_Output_Level[object_index][i];
real_value = Analog_Output_Level[object_index][i]; len = encode_tagged_real(&apdu[apdu_len], real_value);
len = encode_tagged_real(&apdu[apdu_len], real_value); }
} // add it if we have room
// add it if we have room if ((apdu_len + len) < MAX_APDU)
if ((apdu_len + len) < MAX_APDU) apdu_len += len;
apdu_len += len; else {
else *error_class = ERROR_CLASS_SERVICES;
{ *error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
*error_class = ERROR_CLASS_SERVICES; apdu_len = -1;
*error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT; break;
apdu_len = -1; }
break; }
} } else {
object_index =
Analog_Output_Instance_To_Index(object_instance);
if (array_index <= BACNET_MAX_PRIORITY) {
if (Analog_Output_Level[object_index][array_index] ==
AO_LEVEL_NULL)
len = encode_tagged_null(&apdu[apdu_len]);
else {
real_value =
Analog_Output_Level[object_index][array_index];
len = encode_tagged_real(&apdu[apdu_len], real_value);
}
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = -1;
}
} }
}
else
{
object_index = Analog_Output_Instance_To_Index(object_instance);
if (array_index <= BACNET_MAX_PRIORITY)
{
if (Analog_Output_Level[object_index][array_index] == AO_LEVEL_NULL)
len = encode_tagged_null(&apdu[apdu_len]);
else
{
real_value = Analog_Output_Level[object_index][array_index];
len = encode_tagged_real(&apdu[apdu_len], real_value);
}
}
else
{
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = -1;
}
}
break; break;
case PROP_RELINQUISH_DEFAULT: case PROP_RELINQUISH_DEFAULT:
real_value = AO_RELINQUISH_DEFAULT; real_value = AO_RELINQUISH_DEFAULT;
apdu_len = encode_tagged_real(&apdu[0], real_value); apdu_len = encode_tagged_real(&apdu[0], real_value);
break; break;
default: default:
*error_class = ERROR_CLASS_PROPERTY; *error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_UNKNOWN_PROPERTY; *error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = -1; apdu_len = -1;
break; break;
} }
return apdu_len; return apdu_len;
} }
// returns true if successful // returns true if successful
bool Analog_Output_Write_Property( bool Analog_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
BACNET_WRITE_PROPERTY_DATA *wp_data, BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code)
BACNET_ERROR_CLASS *error_class,
BACNET_ERROR_CODE *error_code)
{ {
bool status = false; // return value bool status = false; // return value
unsigned int object_index = 0; unsigned int object_index = 0;
unsigned int priority = 0; unsigned int priority = 0;
uint8_t level = AO_LEVEL_NULL; uint8_t level = AO_LEVEL_NULL;
Analog_Output_Init(); Analog_Output_Init();
if (!Analog_Output_Valid_Instance(wp_data->object_instance)) if (!Analog_Output_Valid_Instance(wp_data->object_instance)) {
{ *error_class = ERROR_CLASS_OBJECT;
*error_class = ERROR_CLASS_OBJECT; *error_code = ERROR_CODE_UNKNOWN_OBJECT;
*error_code = ERROR_CODE_UNKNOWN_OBJECT; return false;
return false; }
} // decode the some of the request
switch (wp_data->object_property) {
// decode the some of the request
switch (wp_data->object_property)
{
case PROP_PRESENT_VALUE: case PROP_PRESENT_VALUE:
if (wp_data->value.tag == BACNET_APPLICATION_TAG_REAL) if (wp_data->value.tag == BACNET_APPLICATION_TAG_REAL) {
{ priority = wp_data->priority;
priority = wp_data->priority; if (priority && (priority <= BACNET_MAX_PRIORITY) &&
if (priority && (priority <= BACNET_MAX_PRIORITY) && (priority != 6 /* reserved */ ) &&
(priority != 6 /* reserved */) && (wp_data->value.type.Real >= 0.0) &&
(wp_data->value.type.Real >= 0.0) && (wp_data->value.type.Real <= 100.0)) {
(wp_data->value.type.Real <= 100.0)) level = (uint8_t) wp_data->value.type.Real;
{ object_index =
level = (uint8_t)wp_data->value.type.Real; Analog_Output_Instance_To_Index(wp_data->
object_index = Analog_Output_Instance_To_Index( object_instance);
wp_data->object_instance); priority--;
priority--; Analog_Output_Level[object_index][priority] = level;
Analog_Output_Level[object_index][priority] = level; // if Out of Service is TRUE, then don't set the
// if Out of Service is TRUE, then don't set the // physical output. This comment may apply to the
// physical output. This comment may apply to the // main loop (i.e. check out of service before changing output)
// main loop (i.e. check out of service before changing output) status = true;
status = true; } else if (priority == 6) {
*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 (wp_data->value.tag == BACNET_APPLICATION_TAG_NULL) {
level = AO_LEVEL_NULL;
object_index =
Analog_Output_Instance_To_Index(wp_data->object_instance);
priority = wp_data->priority;
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
priority--;
Analog_Output_Level[object_index][priority] = level;
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;
} }
else if (priority == 6) break;
{
*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 (wp_data->value.tag == BACNET_APPLICATION_TAG_NULL)
{
level = AO_LEVEL_NULL;
object_index = Analog_Output_Instance_To_Index(
wp_data->object_instance);
priority = wp_data->priority;
if (priority && (priority <= BACNET_MAX_PRIORITY))
{
priority--;
Analog_Output_Level[object_index][priority] = level;
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_OUT_OF_SERVICE: case PROP_OUT_OF_SERVICE:
if (wp_data->value.tag == BACNET_APPLICATION_TAG_BOOLEAN) if (wp_data->value.tag == BACNET_APPLICATION_TAG_BOOLEAN) {
{ object_index =
object_index = Analog_Output_Instance_To_Index( Analog_Output_Instance_To_Index(wp_data->object_instance);
wp_data->object_instance); Analog_Output_Out_Of_Service[object_index] =
Analog_Output_Out_Of_Service[object_index] = wp_data->value.type.Boolean;
wp_data->value.type.Boolean; status = true;
status = true; } else {
} *error_class = ERROR_CLASS_PROPERTY;
else *error_code = ERROR_CODE_INVALID_DATA_TYPE;
{ }
*error_class = ERROR_CLASS_PROPERTY; break;
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
}
break;
default: default:
*error_class = ERROR_CLASS_PROPERTY; *error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED; *error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
break; break;
} }
return status; return status;
} }
@@ -384,33 +351,30 @@ bool Analog_Output_Write_Property(
void testAnalogOutput(Test * pTest) void testAnalogOutput(Test * pTest)
{ {
uint8_t apdu[MAX_APDU] = { 0 }; uint8_t apdu[MAX_APDU] = { 0 };
int len = 0; int len = 0;
uint32_t len_value = 0; uint32_t len_value = 0;
uint8_t tag_number = 0; uint8_t tag_number = 0;
BACNET_OBJECT_TYPE decoded_type = OBJECT_ANALOG_OUTPUT; BACNET_OBJECT_TYPE decoded_type = OBJECT_ANALOG_OUTPUT;
uint32_t decoded_instance = 0; uint32_t decoded_instance = 0;
uint32_t instance = 123; uint32_t instance = 123;
BACNET_ERROR_CLASS error_class; BACNET_ERROR_CLASS error_class;
BACNET_ERROR_CODE error_code; BACNET_ERROR_CODE error_code;
len = Analog_Output_Encode_Property_APDU( len = Analog_Output_Encode_Property_APDU(&apdu[0],
&apdu[0], instance,
instance, PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
BACNET_ARRAY_ALL, ct_test(pTest, len != 0);
&error_class, len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
&error_code); ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
ct_test(pTest, len != 0); len = decode_object_id(&apdu[len],
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len = decode_object_id(&apdu[len],
(int *) &decoded_type, &decoded_instance); (int *) &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == OBJECT_ANALOG_OUTPUT); ct_test(pTest, decoded_type == OBJECT_ANALOG_OUTPUT);
ct_test(pTest, decoded_instance == instance); ct_test(pTest, decoded_instance == instance);
return; return;
} }
#ifdef TEST_ANALOG_OUTPUT #ifdef TEST_ANALOG_OUTPUT
@@ -433,5 +397,3 @@ int main(void)
} }
#endif /* TEST_ANALOG_INPUT */ #endif /* TEST_ANALOG_INPUT */
#endif /* TEST */ #endif /* TEST */
+14 -19
View File
@@ -33,33 +33,28 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
bool Analog_Output_Valid_Instance(uint32_t object_instance); bool Analog_Output_Valid_Instance(uint32_t object_instance);
unsigned Analog_Output_Count(void); unsigned Analog_Output_Count(void);
uint32_t Analog_Output_Index_To_Instance(unsigned index); uint32_t Analog_Output_Index_To_Instance(unsigned index);
char *Analog_Output_Name(uint32_t object_instance); char *Analog_Output_Name(uint32_t object_instance);
int Analog_Output_Encode_Property_APDU( int Analog_Output_Encode_Property_APDU(uint8_t * apdu,
uint8_t *apdu, uint32_t object_instance,
uint32_t object_instance, BACNET_PROPERTY_ID property,
BACNET_PROPERTY_ID property, int32_t array_index,
int32_t array_index, BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code);
BACNET_ERROR_CLASS *error_class,
BACNET_ERROR_CODE *error_code);
bool Analog_Output_Write_Property( bool Analog_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
BACNET_WRITE_PROPERTY_DATA *wp_data, BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code);
BACNET_ERROR_CLASS *error_class,
BACNET_ERROR_CODE *error_code);
#ifdef TEST #ifdef TEST
#include "ctest.h" #include "ctest.h"
void testAnalogOutput(Test * pTest); void testAnalogOutput(Test * pTest);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+178 -225
View File
@@ -39,207 +39,182 @@
#include "arf.h" #include "arf.h"
#include "awf.h" #include "awf.h"
typedef struct typedef struct {
{ uint32_t instance;
uint32_t instance; char *filename;
char *filename;
} BACNET_FILE_LISTING; } BACNET_FILE_LISTING;
static BACNET_FILE_LISTING BACnet_File_Listing[] = static BACNET_FILE_LISTING BACnet_File_Listing[] = {
{ {0, "test.log"},
{0, "test.log"}, {1, "script.txt"},
{1, "script.txt"}, {2, "bacenum.h"},
{2, "bacenum.h"}, {0, NULL} // last file indication
{0, NULL} // last file indication
}; };
char *bacfile_name(uint32_t instance) char *bacfile_name(uint32_t instance)
{ {
uint32_t index = 0; uint32_t index = 0;
char *filename = NULL; char *filename = NULL;
// linear search for file instance match // linear search for file instance match
while (BACnet_File_Listing[index].filename) while (BACnet_File_Listing[index].filename) {
{ if (BACnet_File_Listing[index].instance == instance) {
if (BACnet_File_Listing[index].instance == instance) filename = BACnet_File_Listing[index].filename;
{ break;
filename = BACnet_File_Listing[index].filename; }
break; index++;
} }
index++;
}
return filename; return filename;
} }
bool bacfile_valid_instance(uint32_t object_instance) bool bacfile_valid_instance(uint32_t object_instance)
{ {
return bacfile_name(object_instance) ? true : false; return bacfile_name(object_instance) ? true : false;
} }
uint32_t bacfile_count(void) uint32_t bacfile_count(void)
{ {
uint32_t index = 0; uint32_t index = 0;
// linear search for file instance match // linear search for file instance match
while (BACnet_File_Listing[index].filename) while (BACnet_File_Listing[index].filename) {
{ index++;
index++; }
}
return index; return index;
} }
uint32_t bacfile_index_to_instance(unsigned find_index) uint32_t bacfile_index_to_instance(unsigned find_index)
{ {
uint32_t instance = BACNET_MAX_INSTANCE + 1; uint32_t instance = BACNET_MAX_INSTANCE + 1;
uint32_t index = 0; uint32_t index = 0;
// bounds checking... // bounds checking...
while (BACnet_File_Listing[index].filename) while (BACnet_File_Listing[index].filename) {
{ if (index == find_index) {
if (index == find_index) instance = BACnet_File_Listing[index].instance;
{ break;
instance = BACnet_File_Listing[index].instance; }
break; index++;
} }
index++;
}
return instance; return instance;
} }
static long fsize(FILE *pFile) static long fsize(FILE * pFile)
{ {
long size = 0; long size = 0;
long origin = 0; long origin = 0;
if (pFile) if (pFile) {
{ origin = ftell(pFile);
origin = ftell(pFile); fseek(pFile, 0L, SEEK_END);
fseek(pFile, 0L, SEEK_END); size = ftell(pFile);
size = ftell(pFile); fseek(pFile, origin, SEEK_SET);
fseek(pFile, origin, SEEK_SET); }
} return (size);
return (size);
} }
static unsigned bacfile_file_size(uint32_t object_instance) static unsigned bacfile_file_size(uint32_t object_instance)
{ {
char *pFilename = NULL; char *pFilename = NULL;
FILE *pFile = NULL; FILE *pFile = NULL;
unsigned file_size = 0; unsigned file_size = 0;
pFilename = bacfile_name(object_instance); pFilename = bacfile_name(object_instance);
if (pFilename) if (pFilename) {
{ pFile = fopen(pFilename, "rb");
pFile = fopen(pFilename,"rb"); if (pFile) {
if (pFile) file_size = fsize(pFile);
{ fclose(pFile);
file_size = fsize(pFile); }
fclose(pFile);
} }
}
return file_size; return file_size;
} }
/* return the number of bytes used, or -1 on error */ /* return the number of bytes used, or -1 on error */
int bacfile_encode_property_apdu( int bacfile_encode_property_apdu(uint8_t * apdu,
uint8_t *apdu, uint32_t object_instance,
uint32_t object_instance, BACNET_PROPERTY_ID property,
BACNET_PROPERTY_ID property, int32_t array_index,
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
char text_string[32] = {""}; char text_string[32] = { "" };
BACNET_CHARACTER_STRING char_string; BACNET_CHARACTER_STRING char_string;
(void)array_index; (void) array_index;
switch (property) switch (property) {
{
case PROP_OBJECT_IDENTIFIER: case PROP_OBJECT_IDENTIFIER:
apdu_len = encode_tagged_object_id(&apdu[0], apdu_len = encode_tagged_object_id(&apdu[0],
OBJECT_FILE, OBJECT_FILE, object_instance);
object_instance); break;
break;
case PROP_OBJECT_NAME: case PROP_OBJECT_NAME:
sprintf(text_string,"FILE %d",object_instance); sprintf(text_string, "FILE %d", object_instance);
characterstring_init_ansi(&char_string, text_string); characterstring_init_ansi(&char_string, text_string);
apdu_len = encode_tagged_character_string(&apdu[0], apdu_len = encode_tagged_character_string(&apdu[0], &char_string);
&char_string); break;
break;
case PROP_OBJECT_TYPE: case PROP_OBJECT_TYPE:
apdu_len = encode_tagged_enumerated(&apdu[0], OBJECT_FILE); apdu_len = encode_tagged_enumerated(&apdu[0], OBJECT_FILE);
break; break;
case PROP_DESCRIPTION: case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string, bacfile_name(object_instance)); characterstring_init_ansi(&char_string,
apdu_len = encode_tagged_character_string(&apdu[0], bacfile_name(object_instance));
&char_string); apdu_len = encode_tagged_character_string(&apdu[0], &char_string);
break; break;
case PROP_FILE_TYPE: case PROP_FILE_TYPE:
characterstring_init_ansi(&char_string, "TEXT"); characterstring_init_ansi(&char_string, "TEXT");
apdu_len = encode_tagged_character_string(&apdu[0], apdu_len = encode_tagged_character_string(&apdu[0], &char_string);
&char_string); break;
break;
case PROP_FILE_SIZE: case PROP_FILE_SIZE:
apdu_len = encode_tagged_unsigned(&apdu[0], apdu_len = encode_tagged_unsigned(&apdu[0],
bacfile_file_size(object_instance)); bacfile_file_size(object_instance));
break; break;
case PROP_MODIFICATION_DATE: case PROP_MODIFICATION_DATE:
// FIXME: get the actual value // FIXME: get the actual value
apdu_len = encode_tagged_date(&apdu[0], apdu_len = encode_tagged_date(&apdu[0],
2005, 2005, 12, 25, 7 /* sunday */ );
12, // FIXME: get the actual value
25, apdu_len += encode_tagged_time(&apdu[apdu_len], 12, 0, 0, 0);
7 /* sunday */); break;
// FIXME: get the actual value
apdu_len += encode_tagged_time(&apdu[apdu_len],
12,
0,
0,
0);
break;
case PROP_ARCHIVE: case PROP_ARCHIVE:
// FIXME: get the actual value: note it may be inverse... // FIXME: get the actual value: note it may be inverse...
apdu_len = encode_tagged_boolean(&apdu[0],true); apdu_len = encode_tagged_boolean(&apdu[0], true);
break; break;
case PROP_READ_ONLY: case PROP_READ_ONLY:
// FIXME: get the actual value // FIXME: get the actual value
apdu_len = encode_tagged_boolean(&apdu[0],true); apdu_len = encode_tagged_boolean(&apdu[0], true);
break; break;
case PROP_FILE_ACCESS_METHOD: case PROP_FILE_ACCESS_METHOD:
apdu_len = encode_tagged_enumerated(&apdu[0],FILE_STREAM_ACCESS); apdu_len = encode_tagged_enumerated(&apdu[0], FILE_STREAM_ACCESS);
break; break;
default: default:
*error_class = ERROR_CLASS_PROPERTY; *error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_UNKNOWN_PROPERTY; *error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = -1; apdu_len = -1;
break; break;
} }
return apdu_len; return apdu_len;
} }
uint32_t bacfile_instance(char *filename) uint32_t bacfile_instance(char *filename)
{ {
uint32_t index = 0; uint32_t index = 0;
uint32_t instance = BACNET_MAX_INSTANCE + 1; uint32_t instance = BACNET_MAX_INSTANCE + 1;
// linear search for filename match // linear search for filename match
while (BACnet_File_Listing[index].filename) while (BACnet_File_Listing[index].filename) {
{ if (strcmp(BACnet_File_Listing[index].filename, filename) == 0) {
if (strcmp(BACnet_File_Listing[index].filename,filename) == 0) instance = BACnet_File_Listing[index].instance;
{ break;
instance = BACnet_File_Listing[index].instance; }
break; index++;
} }
index++;
}
return instance; return instance;
} }
#if TSM_ENABLED #if TSM_ENABLED
@@ -248,102 +223,80 @@ uint32_t bacfile_instance(char *filename)
// Another way would be to store the // Another way would be to store the
// invokeID and file instance in a list or table // invokeID and file instance in a list or table
// when the request was sent // when the request was sent
uint32_t bacfile_instance_from_tsm( uint32_t bacfile_instance_from_tsm(uint8_t invokeID)
uint8_t invokeID)
{ {
BACNET_NPDU_DATA npdu_data = {0}; // dummy for getting npdu length BACNET_NPDU_DATA npdu_data = { 0 }; // dummy for getting npdu length
BACNET_CONFIRMED_SERVICE_DATA service_data = {0}; BACNET_CONFIRMED_SERVICE_DATA service_data = { 0 };
uint8_t service_choice = 0; uint8_t service_choice = 0;
uint8_t *service_request = NULL; uint8_t *service_request = NULL;
uint16_t service_request_len = 0; uint16_t service_request_len = 0;
BACNET_ADDRESS dest; // where the original packet was destined BACNET_ADDRESS dest; // where the original packet was destined
uint8_t pdu[MAX_PDU] = {0}; // original sent packet uint8_t pdu[MAX_PDU] = { 0 }; // original sent packet
uint16_t pdu_len = 0; // original packet length uint16_t pdu_len = 0; // original packet length
uint16_t len = 0; // apdu header length uint16_t len = 0; // apdu header length
BACNET_ATOMIC_READ_FILE_DATA data = {0}; BACNET_ATOMIC_READ_FILE_DATA data = { 0 };
uint32_t object_instance = BACNET_MAX_INSTANCE + 1; // return value uint32_t object_instance = BACNET_MAX_INSTANCE + 1; // return value
bool found = false; bool found = false;
int apdu_offset = 0; int apdu_offset = 0;
found = tsm_get_transaction_pdu( found = tsm_get_transaction_pdu(invokeID, &dest, &pdu[0], &pdu_len);
invokeID, if (found) {
&dest, apdu_offset = npdu_decode(&pdu[0], // data to decode
&pdu[0], NULL, // destination address - get the DNET/DLEN/DADR if in there
&pdu_len); NULL, // source address - get the SNET/SLEN/SADR if in there
if (found) &npdu_data); // amount of data to decode
{ if (!npdu_data.network_layer_message &&
apdu_offset = npdu_decode( ((pdu[apdu_offset] & 0xF0) ==
&pdu[0], // data to decode PDU_TYPE_CONFIRMED_SERVICE_REQUEST)) {
NULL, // destination address - get the DNET/DLEN/DADR if in there len = apdu_decode_confirmed_service_request(&pdu[apdu_offset], // APDU data
NULL, // source address - get the SNET/SLEN/SADR if in there pdu_len - apdu_offset,
&npdu_data); // amount of data to decode &service_data,
if (!npdu_data.network_layer_message && &service_choice, &service_request, &service_request_len);
((pdu[apdu_offset] & 0xF0) == PDU_TYPE_CONFIRMED_SERVICE_REQUEST)) if (service_choice == SERVICE_CONFIRMED_ATOMIC_READ_FILE) {
{ len = arf_decode_service_request(service_request,
len = apdu_decode_confirmed_service_request( service_request_len, &data);
&pdu[apdu_offset], // APDU data if (len > 0) {
pdu_len - apdu_offset, if (data.object_type == OBJECT_FILE)
&service_data, object_instance = data.object_instance;
&service_choice, }
&service_request, }
&service_request_len);
if (service_choice == SERVICE_CONFIRMED_ATOMIC_READ_FILE)
{
len = arf_decode_service_request(
service_request,
service_request_len,
&data);
if (len > 0)
{
if (data.object_type == OBJECT_FILE)
object_instance = data.object_instance;
} }
}
} }
}
return object_instance; return object_instance;
} }
#endif #endif
bool bacfile_read_data(BACNET_ATOMIC_READ_FILE_DATA *data) bool bacfile_read_data(BACNET_ATOMIC_READ_FILE_DATA * data)
{ {
char *pFilename = NULL; char *pFilename = NULL;
bool found = false; bool found = false;
FILE *pFile = NULL; FILE *pFile = NULL;
size_t len = 0; size_t len = 0;
pFilename = bacfile_name(data->object_instance); pFilename = bacfile_name(data->object_instance);
if (pFilename) if (pFilename) {
{ found = true;
found = true; pFile = fopen(pFilename, "rb");
pFile = fopen(pFilename,"rb"); if (pFile) {
if (pFile) (void) fseek(pFile,
{ data->type.stream.fileStartPosition, SEEK_SET);
(void)fseek(pFile, len = fread(octetstring_value(&data->fileData), 1,
data->type.stream.fileStartPosition, data->type.stream.requestedOctetCount, pFile);
SEEK_SET); if (len < data->type.stream.requestedOctetCount)
len = fread(octetstring_value(&data->fileData), 1, data->endOfFile = true;
data->type.stream.requestedOctetCount, pFile); else
if (len < data->type.stream.requestedOctetCount) data->endOfFile = false;
octetstring_truncate(&data->fileData, len);
fclose(pFile);
} else {
octetstring_truncate(&data->fileData, 0);
data->endOfFile = true;
}
} else {
octetstring_truncate(&data->fileData, 0);
data->endOfFile = true; data->endOfFile = true;
else
data->endOfFile = false;
octetstring_truncate(&data->fileData,len);
fclose(pFile);
} }
else
{
octetstring_truncate(&data->fileData,0);
data->endOfFile = true;
}
}
else
{
octetstring_truncate(&data->fileData,0);
data->endOfFile = true;
}
return found; return found;
} }
+14 -18
View File
@@ -43,37 +43,33 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
char *bacfile_name(uint32_t instance); char *bacfile_name(uint32_t instance);
bool bacfile_valid_instance(uint32_t object_instance); bool bacfile_valid_instance(uint32_t object_instance);
uint32_t bacfile_count(void); uint32_t bacfile_count(void);
uint32_t bacfile_index_to_instance(unsigned find_index); uint32_t bacfile_index_to_instance(unsigned find_index);
uint32_t bacfile_instance(char *filename); uint32_t bacfile_instance(char *filename);
#if TSM_ENABLED #if TSM_ENABLED
// this is one way to match up the invoke ID with // this is one way to match up the invoke ID with
// the file ID from the AtomicReadFile request. // the file ID from the AtomicReadFile request.
// Another way would be to store the // Another way would be to store the
// invokeID and file instance in a list or table // invokeID and file instance in a list or table
// when the request was sent // when the request was sent
uint32_t bacfile_instance_from_tsm( uint32_t bacfile_instance_from_tsm(uint8_t invokeID);
uint8_t invokeID);
#endif #endif
// AtomicReadFile ACK helper // AtomicReadFile ACK helper
bool bacfile_read_data(BACNET_ATOMIC_READ_FILE_DATA *data); bool bacfile_read_data(BACNET_ATOMIC_READ_FILE_DATA * data);
// handling for read property service // handling for read property service
int bacfile_encode_property_apdu( int bacfile_encode_property_apdu(uint8_t * apdu,
uint8_t *apdu, uint32_t object_instance,
uint32_t object_instance, BACNET_PROPERTY_ID property,
BACNET_PROPERTY_ID property, int32_t array_index,
int32_t array_index, BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code);
BACNET_ERROR_CLASS *error_class,
BACNET_ERROR_CODE *error_code);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
File diff suppressed because it is too large Load Diff
+45 -54
View File
@@ -42,78 +42,69 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
uint32_t Device_Object_Instance_Number(void); uint32_t Device_Object_Instance_Number(void);
bool Device_Set_Object_Instance_Number(uint32_t object_id); bool Device_Set_Object_Instance_Number(uint32_t object_id);
bool Device_Valid_Object_Instance_Number(uint32_t object_id); bool Device_Valid_Object_Instance_Number(uint32_t object_id);
unsigned Device_Object_List_Count(void); unsigned Device_Object_List_Count(void);
bool Device_Object_List_Identifier(unsigned array_index, bool Device_Object_List_Identifier(unsigned array_index,
int *object_type, int *object_type, uint32_t * instance);
uint32_t *instance);
BACNET_DEVICE_STATUS Device_System_Status(void); BACNET_DEVICE_STATUS Device_System_Status(void);
void Device_Set_System_Status(BACNET_DEVICE_STATUS status); void Device_Set_System_Status(BACNET_DEVICE_STATUS status);
const char *Device_Vendor_Name(void); const char *Device_Vendor_Name(void);
bool Device_Set_Vendor_Name(const char *name, size_t length); bool Device_Set_Vendor_Name(const char *name, size_t length);
uint16_t Device_Vendor_Identifier(void); uint16_t Device_Vendor_Identifier(void);
void Device_Set_Vendor_Identifier(uint16_t vendor_id); void Device_Set_Vendor_Identifier(uint16_t vendor_id);
const char *Device_Model_Name(void); const char *Device_Model_Name(void);
bool Device_Set_Model_Name(const char *name, size_t length); bool Device_Set_Model_Name(const char *name, size_t length);
const char *Device_Firmware_Revision(void); const char *Device_Firmware_Revision(void);
bool Device_Set_Firmware_Revision(const char *name, size_t length); bool Device_Set_Firmware_Revision(const char *name, size_t length);
const char *Device_Application_Software_Version(void); const char *Device_Application_Software_Version(void);
bool Device_Set_Application_Software_Version(const char *name, size_t length); bool Device_Set_Application_Software_Version(const char *name,
size_t length);
const char *Device_Description(void); const char *Device_Description(void);
bool Device_Set_Description(const char *name, size_t length); bool Device_Set_Description(const char *name, size_t length);
const char *Device_Location(void); const char *Device_Location(void);
bool Device_Set_Location(const char *name, size_t length); bool Device_Set_Location(const char *name, size_t length);
// some stack-centric constant values - no set methods // some stack-centric constant values - no set methods
uint8_t Device_Protocol_Version(void); uint8_t Device_Protocol_Version(void);
uint8_t Device_Protocol_Revision(void); uint8_t Device_Protocol_Revision(void);
uint16_t Device_Max_APDU_Length_Accepted(void); uint16_t Device_Max_APDU_Length_Accepted(void);
BACNET_SEGMENTATION Device_Segmentation_Supported(void); BACNET_SEGMENTATION Device_Segmentation_Supported(void);
uint16_t Device_APDU_Timeout(void); uint16_t Device_APDU_Timeout(void);
void Device_Set_APDU_Timeout(uint16_t timeout); void Device_Set_APDU_Timeout(uint16_t timeout);
uint8_t Device_Number_Of_APDU_Retries(void); uint8_t Device_Number_Of_APDU_Retries(void);
void Device_Set_Number_Of_APDU_Retries(uint8_t retries); void Device_Set_Number_Of_APDU_Retries(uint8_t retries);
uint8_t Device_Database_Revision(void); uint8_t Device_Database_Revision(void);
void Device_Set_Database_Revision(uint8_t revision); void Device_Set_Database_Revision(uint8_t revision);
bool Device_Valid_Object_Name( bool Device_Valid_Object_Name(const char *object_name,
const char *object_name, int *object_type, uint32_t * object_instance);
int *object_type, char *Device_Valid_Object_Id(int object_type,
uint32_t *object_instance); uint32_t object_instance);
char *Device_Valid_Object_Id(
int object_type,
uint32_t object_instance);
int Device_Encode_Property_APDU( int Device_Encode_Property_APDU(uint8_t * apdu,
uint8_t *apdu, BACNET_PROPERTY_ID property,
BACNET_PROPERTY_ID property, int32_t array_index,
int32_t array_index, BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code);
BACNET_ERROR_CLASS *error_class,
BACNET_ERROR_CODE *error_code);
bool Device_Write_Property( bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
BACNET_WRITE_PROPERTY_DATA *wp_data, BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code);
BACNET_ERROR_CLASS *error_class,
BACNET_ERROR_CODE *error_code);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+275 -350
View File
@@ -28,7 +28,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h> /* for time */ #include <time.h> /* for time */
#include <errno.h> #include <errno.h>
#include "bactext.h" #include "bactext.h"
#include "iam.h" #include "iam.h"
@@ -49,7 +49,7 @@
#include "txbuf.h" #include "txbuf.h"
// buffer used for receive // buffer used for receive
static uint8_t Rx_Buf[MAX_MPDU] = {0}; static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
/* global variables used in this file */ /* global variables used in this file */
static uint32_t Target_File_Object_Instance = BACNET_MAX_INSTANCE; static uint32_t Target_File_Object_Instance = BACNET_MAX_INSTANCE;
@@ -60,397 +60,322 @@ static bool End_Of_File_Detected = false;
static bool Error_Detected = false; static bool Error_Detected = false;
static uint8_t Current_Invoke_ID = 0; static uint8_t Current_Invoke_ID = 0;
static void Atomic_Read_File_Error_Handler( static void Atomic_Read_File_Error_Handler(BACNET_ADDRESS * src,
BACNET_ADDRESS *src, uint8_t invoke_id,
uint8_t invoke_id, BACNET_ERROR_CLASS error_class, BACNET_ERROR_CODE error_code)
BACNET_ERROR_CLASS error_class,
BACNET_ERROR_CODE error_code)
{ {
/* FIXME: verify src and invoke id */ /* FIXME: verify src and invoke id */
(void)src; (void) src;
(void)invoke_id; (void) invoke_id;
printf("\r\nBACnet Error!\r\n"); printf("\r\nBACnet Error!\r\n");
printf("Error Class: %s\r\n", printf("Error Class: %s\r\n", bactext_error_class_name(error_class));
bactext_error_class_name(error_class)); printf("Error Code: %s\r\n", bactext_error_code_name(error_code));
printf("Error Code: %s\r\n", Error_Detected = true;
bactext_error_code_name(error_code));
Error_Detected = true;
} }
void MyAbortHandler( void MyAbortHandler(BACNET_ADDRESS * src,
BACNET_ADDRESS *src, uint8_t invoke_id, uint8_t abort_reason)
uint8_t invoke_id,
uint8_t abort_reason)
{ {
/* FIXME: verify src and invoke id */ /* FIXME: verify src and invoke id */
(void)src; (void) src;
(void)invoke_id; (void) invoke_id;
printf("\r\nBACnet Abort!\r\n"); printf("\r\nBACnet Abort!\r\n");
printf("Abort Reason: %s\r\n", printf("Abort Reason: %s\r\n",
bactext_abort_reason_name(abort_reason)); bactext_abort_reason_name(abort_reason));
Error_Detected = true; Error_Detected = true;
} }
void MyRejectHandler( void MyRejectHandler(BACNET_ADDRESS * src,
BACNET_ADDRESS *src, uint8_t invoke_id, uint8_t reject_reason)
uint8_t invoke_id,
uint8_t reject_reason)
{ {
/* FIXME: verify src and invoke id */ /* FIXME: verify src and invoke id */
(void)src; (void) src;
(void)invoke_id; (void) invoke_id;
printf("\r\nBACnet Reject!\r\n"); printf("\r\nBACnet Reject!\r\n");
printf("Reject Reason: %s\r\n", printf("Reject Reason: %s\r\n",
bactext_reject_reason_name(reject_reason)); bactext_reject_reason_name(reject_reason));
Error_Detected = true; Error_Detected = true;
} }
static uint8_t Send_Atomic_Read_File_Stream( static uint8_t Send_Atomic_Read_File_Stream(uint32_t device_id,
uint32_t device_id, uint32_t file_instance,
uint32_t file_instance, int fileStartPosition, unsigned requestedOctetCount)
int fileStartPosition,
unsigned requestedOctetCount)
{ {
BACNET_ADDRESS dest; BACNET_ADDRESS dest;
BACNET_ADDRESS my_address; BACNET_ADDRESS my_address;
unsigned max_apdu = 0; unsigned max_apdu = 0;
uint8_t invoke_id = 0; uint8_t invoke_id = 0;
bool status = false; bool status = false;
int pdu_len = 0; int pdu_len = 0;
int bytes_sent = 0; int bytes_sent = 0;
BACNET_ATOMIC_READ_FILE_DATA data; BACNET_ATOMIC_READ_FILE_DATA data;
/* is the device bound? */ /* is the device bound? */
status = address_get_by_device(device_id, &max_apdu, &dest); status = address_get_by_device(device_id, &max_apdu, &dest);
/* is there a tsm available? */ /* is there a tsm available? */
if (status) if (status)
status = tsm_transaction_available(); status = tsm_transaction_available();
if (status) if (status) {
{ datalink_get_my_address(&my_address);
datalink_get_my_address(&my_address); pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], &dest, &my_address, true, // true for confirmed messages
pdu_len = npdu_encode_apdu( MESSAGE_PRIORITY_NORMAL);
&Handler_Transmit_Buffer[0],
&dest,
&my_address,
true, // true for confirmed messages
MESSAGE_PRIORITY_NORMAL);
invoke_id = tsm_next_free_invokeID(); invoke_id = tsm_next_free_invokeID();
// load the data for the encoding // load the data for the encoding
data.object_type = OBJECT_FILE; data.object_type = OBJECT_FILE;
data.object_instance = file_instance; data.object_instance = file_instance;
data.access = FILE_STREAM_ACCESS; data.access = FILE_STREAM_ACCESS;
data.type.stream.fileStartPosition = fileStartPosition; data.type.stream.fileStartPosition = fileStartPosition;
data.type.stream.requestedOctetCount = requestedOctetCount; data.type.stream.requestedOctetCount = requestedOctetCount;
pdu_len += arf_encode_apdu( pdu_len += arf_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
&Handler_Transmit_Buffer[pdu_len], invoke_id, &data);
invoke_id, /* will the APDU fit the target device?
&data); note: if there is a bottleneck router in between
/* will the APDU fit the target device? us and the destination, we won't know unless
note: if there is a bottleneck router in between we have a way to check for that and update the
us and the destination, we won't know unless max_apdu in the address binding table. */
we have a way to check for that and update the if ((unsigned) pdu_len < max_apdu) {
max_apdu in the address binding table. */ tsm_set_confirmed_unsegmented_transaction(invoke_id,
if ((unsigned)pdu_len < max_apdu) &dest, &Handler_Transmit_Buffer[0], pdu_len);
{ bytes_sent = datalink_send_pdu(&dest, // destination address
tsm_set_confirmed_unsegmented_transaction( &Handler_Transmit_Buffer[0], pdu_len); // number of bytes of data
invoke_id, if (bytes_sent <= 0)
&dest, fprintf(stderr,
&Handler_Transmit_Buffer[0], "Failed to Send AtomicReadFile Request (%s)!\n",
pdu_len); strerror(errno));
bytes_sent = datalink_send_pdu( } else
&dest, // destination address fprintf(stderr, "Failed to Send AtomicReadFile Request "
&Handler_Transmit_Buffer[0], "(payload exceeds destination maximum APDU)!\n");
pdu_len); // number of bytes of data
if (bytes_sent <= 0)
fprintf(stderr,"Failed to Send AtomicReadFile Request (%s)!\n",
strerror(errno));
} }
else
fprintf(stderr,"Failed to Send AtomicReadFile Request "
"(payload exceeds destination maximum APDU)!\n");
}
return invoke_id; return invoke_id;
} }
static void Send_WhoIs(uint32_t device_id) static void Send_WhoIs(uint32_t device_id)
{ {
int pdu_len = 0; int pdu_len = 0;
BACNET_ADDRESS dest; BACNET_ADDRESS dest;
int bytes_sent = 0; int bytes_sent = 0;
/* Who-Is is a global broadcast */ /* Who-Is is a global broadcast */
datalink_get_broadcast_address(&dest); datalink_get_broadcast_address(&dest);
/* encode the NPDU portion of the packet */ /* encode the NPDU portion of the packet */
pdu_len = npdu_encode_apdu( pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], &dest, NULL, false, // true for confirmed messages
&Handler_Transmit_Buffer[0], MESSAGE_PRIORITY_NORMAL);
&dest,
NULL,
false, // true for confirmed messages
MESSAGE_PRIORITY_NORMAL);
/* encode the APDU portion of the packet */ /* encode the APDU portion of the packet */
pdu_len += whois_encode_apdu( pdu_len += whois_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
&Handler_Transmit_Buffer[pdu_len], device_id, device_id);
device_id,
device_id);
bytes_sent = datalink_send_pdu( bytes_sent = datalink_send_pdu(&dest, /* destination address */
&dest, /* destination address */ &Handler_Transmit_Buffer[0], pdu_len); /* number of bytes of data */
&Handler_Transmit_Buffer[0], if (bytes_sent <= 0)
pdu_len); /* number of bytes of data */ fprintf(stderr, "Failed to Send Who-Is Request (%s)!\n",
if (bytes_sent <= 0) strerror(errno));
fprintf(stderr,"Failed to Send Who-Is Request (%s)!\n", strerror(errno));
} }
static void AtomicReadFileAckHandler( static void AtomicReadFileAckHandler(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len,
uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_ACK_DATA * service_data)
BACNET_ADDRESS *src,
BACNET_CONFIRMED_SERVICE_ACK_DATA *service_data)
{ {
int len = 0; int len = 0;
BACNET_ATOMIC_READ_FILE_DATA data; BACNET_ATOMIC_READ_FILE_DATA data;
FILE *pFile = NULL; /* stream pointer */ FILE *pFile = NULL; /* stream pointer */
size_t octets_written = 0; size_t octets_written = 0;
(void)src; /* FIXME: validate the source address matches */ (void) src; /* FIXME: validate the source address matches */
len = arf_ack_decode_service_request( len = arf_ack_decode_service_request(service_request,
service_request, service_len, &data);
service_len, if (len > 0) {
&data); /* validate the parameters before storing data */
if (len > 0) if ((data.access == FILE_STREAM_ACCESS) &&
{ (service_data->invoke_id == Current_Invoke_ID)) {
/* validate the parameters before storing data */ if (data.type.stream.fileStartPosition == 0)
if ((data.access == FILE_STREAM_ACCESS) && pFile = fopen(Local_File_Name, "wb");
(service_data->invoke_id == Current_Invoke_ID)) else
{ pFile = fopen(Local_File_Name, "rb+");
if (data.type.stream.fileStartPosition == 0) if (pFile) {
pFile = fopen(Local_File_Name, "wb"); /* is there anything to do with this? data.stream.requestedOctetCount */
else (void) fseek(pFile, data.type.stream.fileStartPosition,
pFile = fopen(Local_File_Name, "rb+"); SEEK_SET);
if (pFile) octets_written = fwrite(octetstring_value(&data.fileData), 1, /* unit to write in bytes - in our case, an octet is one byte */
{ octetstring_length(&data.fileData), pFile);
/* is there anything to do with this? data.stream.requestedOctetCount */ if (octets_written != octetstring_length(&data.fileData))
(void)fseek(pFile, data.type.stream.fileStartPosition, SEEK_SET); fprintf(stderr,
octets_written = fwrite( "Unable to write data to file \"%s\".\n",
octetstring_value(&data.fileData), Local_File_Name);
1, /* unit to write in bytes - in our case, an octet is one byte */ else
octetstring_length(&data.fileData), printf("\r%u bytes",
pFile); (data.type.stream.fileStartPosition +
if (octets_written != octetstring_length(&data.fileData)) octets_written));
fprintf(stderr,"Unable to write data to file \"%s\".\n", fclose(pFile);
Local_File_Name); }
else if (data.endOfFile) {
printf("\r%u bytes", End_Of_File_Detected = true;
(data.type.stream.fileStartPosition + octets_written)); printf("\r\n");
fclose(pFile); }
} }
if (data.endOfFile)
{
End_Of_File_Detected = true;
printf("\r\n");
}
} }
}
} }
static void LocalIAmHandler( static void LocalIAmHandler(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len, BACNET_ADDRESS * src)
uint16_t service_len,
BACNET_ADDRESS *src)
{ {
int len = 0; int len = 0;
uint32_t device_id = 0; uint32_t device_id = 0;
unsigned max_apdu = 0; unsigned max_apdu = 0;
int segmentation = 0; int segmentation = 0;
uint16_t vendor_id = 0; uint16_t vendor_id = 0;
(void)src; (void) src;
(void)service_len; (void) service_len;
len = iam_decode_service_request( len = iam_decode_service_request(service_request,
service_request, &device_id, &max_apdu, &segmentation, &vendor_id);
&device_id, if (len != -1) {
&max_apdu, address_add(device_id, max_apdu, src);
&segmentation, } else
&vendor_id); fprintf(stderr, "!\n");
if (len != -1)
{
address_add(device_id,
max_apdu,
src);
}
else
fprintf(stderr,"!\n");
return; return;
} }
static void Init_Service_Handlers(void) static void Init_Service_Handlers(void)
{ {
/* we need to handle who-is /* we need to handle who-is
to support dynamic device binding to us */ to support dynamic device binding to us */
apdu_set_unconfirmed_handler( apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS,
SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
handler_who_is); /* handle i-am to support binding to other devices */
/* handle i-am to support binding to other devices */ apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_I_AM,
apdu_set_unconfirmed_handler( LocalIAmHandler);
SERVICE_UNCONFIRMED_I_AM, /* set the handler for all the services we don't implement
LocalIAmHandler); It is required to send the proper reject message... */
/* set the handler for all the services we don't implement apdu_set_unrecognized_service_handler_handler
It is required to send the proper reject message... */ (handler_unrecognized_service);
apdu_set_unrecognized_service_handler_handler( /* we must implement read property - it's required! */
handler_unrecognized_service); apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY,
/* we must implement read property - it's required! */ handler_read_property);
apdu_set_confirmed_handler( /* handle the data coming back from confirmed requests */
SERVICE_CONFIRMED_READ_PROPERTY, apdu_set_confirmed_ack_handler(SERVICE_CONFIRMED_ATOMIC_READ_FILE,
handler_read_property); AtomicReadFileAckHandler);
/* handle the data coming back from confirmed requests */ /* handle any errors coming back */
apdu_set_confirmed_ack_handler( apdu_set_error_handler(SERVICE_CONFIRMED_ATOMIC_READ_FILE,
SERVICE_CONFIRMED_ATOMIC_READ_FILE, Atomic_Read_File_Error_Handler);
AtomicReadFileAckHandler); apdu_set_abort_handler(MyAbortHandler);
/* handle any errors coming back */ apdu_set_reject_handler(MyRejectHandler);
apdu_set_error_handler(
SERVICE_CONFIRMED_ATOMIC_READ_FILE,
Atomic_Read_File_Error_Handler);
apdu_set_abort_handler(
MyAbortHandler);
apdu_set_reject_handler(
MyRejectHandler);
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
BACNET_ADDRESS src = {0}; // address where message came from BACNET_ADDRESS src = { 0 }; // address where message came from
uint16_t pdu_len = 0; uint16_t pdu_len = 0;
unsigned timeout = 100; // milliseconds unsigned timeout = 100; // milliseconds
unsigned max_apdu = 0; unsigned max_apdu = 0;
time_t elapsed_seconds = 0; time_t elapsed_seconds = 0;
time_t last_seconds = 0; time_t last_seconds = 0;
time_t current_seconds = 0; time_t current_seconds = 0;
time_t timeout_seconds = 0; time_t timeout_seconds = 0;
int fileStartPosition = 0; int fileStartPosition = 0;
unsigned requestedOctetCount = 0; unsigned requestedOctetCount = 0;
uint8_t invoke_id = 0; uint8_t invoke_id = 0;
bool found = false; bool found = false;
uint16_t my_max_apdu = 0; uint16_t my_max_apdu = 0;
if (argc < 4) if (argc < 4) {
{ /* FIXME: what about access method - record or stream? */
/* FIXME: what about access method - record or stream? */ printf("%s device-instance file-instance local-name\r\n",
printf("%s device-instance file-instance local-name\r\n", filename_remove_path(argv[0]));
filename_remove_path(argv[0])); return 0;
return 0;
}
/* decode the command line parameters */
Target_Device_Object_Instance = strtol(argv[1],NULL,0);
Target_File_Object_Instance = strtol(argv[2],NULL,0);
Local_File_Name = argv[3];
if (Target_Device_Object_Instance >= BACNET_MAX_INSTANCE)
{
fprintf(stderr,"device-instance=%u - it must be less than %u\r\n",
Target_Device_Object_Instance,BACNET_MAX_INSTANCE);
return 1;
}
if (Target_File_Object_Instance >= BACNET_MAX_INSTANCE)
{
fprintf(stderr,"file-instance=%u - it must be less than %u\r\n",
Target_File_Object_Instance,BACNET_MAX_INSTANCE+1);
return 1;
}
/* setup my info */
Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE);
address_init();
Init_Service_Handlers();
/* configure standard BACnet/IP port */
bip_set_interface("eth0"); /* for linux */
bip_set_port(0xBAC0);
if (!bip_init())
return 1;
/* configure the timeout values */
last_seconds = time(NULL);
timeout_seconds = (Device_APDU_Timeout() / 1000) *
Device_Number_Of_APDU_Retries();
/* try to bind with the device */
Send_WhoIs(Target_Device_Object_Instance);
/* loop forever */
for (;;)
{
/* increment timer - exit if timed out */
current_seconds = time(NULL);
/* returns 0 bytes on timeout */
pdu_len = bip_receive(
&src,
&Rx_Buf[0],
MAX_MPDU,
timeout);
/* process */
if (pdu_len)
{
npdu_handler(
&src,
&Rx_Buf[0],
pdu_len);
} }
/* at least one second has passed */ /* decode the command line parameters */
if (current_seconds != last_seconds) Target_Device_Object_Instance = strtol(argv[1], NULL, 0);
tsm_timer_milliseconds(((current_seconds - last_seconds) * 1000)); Target_File_Object_Instance = strtol(argv[2], NULL, 0);
if (End_Of_File_Detected || Error_Detected) Local_File_Name = argv[3];
break; if (Target_Device_Object_Instance >= BACNET_MAX_INSTANCE) {
if (I_Am_Request) fprintf(stderr, "device-instance=%u - it must be less than %u\r\n",
{ Target_Device_Object_Instance, BACNET_MAX_INSTANCE);
I_Am_Request = false; return 1;
iam_send(&Handler_Transmit_Buffer[0]);
} }
else if (Target_File_Object_Instance >= BACNET_MAX_INSTANCE) {
{ fprintf(stderr, "file-instance=%u - it must be less than %u\r\n",
/* wait until the device is bound, or timeout and quit */ Target_File_Object_Instance, BACNET_MAX_INSTANCE + 1);
found = address_bind_request( return 1;
Target_Device_Object_Instance, }
&max_apdu, /* setup my info */
&Target_Address); Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE);
if (found) address_init();
{ Init_Service_Handlers();
/* calculate the smaller of our APDU size or theirs /* configure standard BACnet/IP port */
and remove the overhead of the APDU (about 16 octets max). bip_set_interface("eth0"); /* for linux */
note: we could fail if there is a bottle neck (router) bip_set_port(0xBAC0);
and smaller MPDU in betweeen. */ if (!bip_init())
if (max_apdu < MAX_APDU) return 1;
my_max_apdu = max_apdu; /* configure the timeout values */
else last_seconds = time(NULL);
my_max_apdu = MAX_APDU; timeout_seconds = (Device_APDU_Timeout() / 1000) *
requestedOctetCount = my_max_apdu - 16; Device_Number_Of_APDU_Retries();
/* has the previous invoke id expired or returned? /* try to bind with the device */
note: invoke ID = 0 is invalid, so it will be idle */ Send_WhoIs(Target_Device_Object_Instance);
if ((invoke_id == 0) || tsm_invoke_id_free(invoke_id)) /* loop forever */
{ for (;;) {
if (invoke_id != 0)
fileStartPosition += requestedOctetCount;
/* we'll read the file in chunks
less than max_apdu to keep unsegmented */
invoke_id = Send_Atomic_Read_File_Stream(
Target_Device_Object_Instance,
Target_File_Object_Instance,
fileStartPosition,
requestedOctetCount);
Current_Invoke_ID = invoke_id;
}
}
else
{
/* increment timer - exit if timed out */ /* increment timer - exit if timed out */
elapsed_seconds += (current_seconds - last_seconds); current_seconds = time(NULL);
if (elapsed_seconds > timeout_seconds)
break;
}
}
/* keep track of time for next check */
last_seconds = current_seconds;
}
return 0; /* returns 0 bytes on timeout */
pdu_len = bip_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout);
/* process */
if (pdu_len) {
npdu_handler(&src, &Rx_Buf[0], pdu_len);
}
/* at least one second has passed */
if (current_seconds != last_seconds)
tsm_timer_milliseconds(((current_seconds -
last_seconds) * 1000));
if (End_Of_File_Detected || Error_Detected)
break;
if (I_Am_Request) {
I_Am_Request = false;
iam_send(&Handler_Transmit_Buffer[0]);
} else {
/* wait until the device is bound, or timeout and quit */
found = address_bind_request(Target_Device_Object_Instance,
&max_apdu, &Target_Address);
if (found) {
/* calculate the smaller of our APDU size or theirs
and remove the overhead of the APDU (about 16 octets max).
note: we could fail if there is a bottle neck (router)
and smaller MPDU in betweeen. */
if (max_apdu < MAX_APDU)
my_max_apdu = max_apdu;
else
my_max_apdu = MAX_APDU;
requestedOctetCount = my_max_apdu - 16;
/* has the previous invoke id expired or returned?
note: invoke ID = 0 is invalid, so it will be idle */
if ((invoke_id == 0) || tsm_invoke_id_free(invoke_id)) {
if (invoke_id != 0)
fileStartPosition += requestedOctetCount;
/* we'll read the file in chunks
less than max_apdu to keep unsegmented */
invoke_id =
Send_Atomic_Read_File_Stream
(Target_Device_Object_Instance,
Target_File_Object_Instance, fileStartPosition,
requestedOctetCount);
Current_Invoke_ID = invoke_id;
}
} else {
/* increment timer - exit if timed out */
elapsed_seconds += (current_seconds - last_seconds);
if (elapsed_seconds > timeout_seconds)
break;
}
}
/* keep track of time for next check */
last_seconds = current_seconds;
}
return 0;
} }
+154 -189
View File
@@ -28,7 +28,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h> /* for time */ #include <time.h> /* for time */
#include <errno.h> #include <errno.h>
#include "bactext.h" #include "bactext.h"
#include "iam.h" #include "iam.h"
@@ -50,7 +50,7 @@
#include "txbuf.h" #include "txbuf.h"
// buffer used for receive // buffer used for receive
static uint8_t Rx_Buf[MAX_MPDU] = {0}; static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
/* global variables used in this file */ /* global variables used in this file */
static uint32_t Target_Device_Object_Instance = BACNET_MAX_INSTANCE; static uint32_t Target_Device_Object_Instance = BACNET_MAX_INSTANCE;
@@ -62,211 +62,176 @@ static int32_t Target_Object_Index = BACNET_ARRAY_ALL;
static BACNET_ADDRESS Target_Address; static BACNET_ADDRESS Target_Address;
static bool Error_Detected = false; static bool Error_Detected = false;
static void MyErrorHandler( static void MyErrorHandler(BACNET_ADDRESS * src,
BACNET_ADDRESS *src, uint8_t invoke_id,
uint8_t invoke_id, BACNET_ERROR_CLASS error_class, BACNET_ERROR_CODE error_code)
BACNET_ERROR_CLASS error_class,
BACNET_ERROR_CODE error_code)
{ {
/* FIXME: verify src and invoke id */ /* FIXME: verify src and invoke id */
(void)src; (void) src;
(void)invoke_id; (void) invoke_id;
printf("BACnet Error: %s: %s\r\n", printf("BACnet Error: %s: %s\r\n",
bactext_error_class_name(error_class), bactext_error_class_name(error_class),
bactext_error_code_name(error_code)); bactext_error_code_name(error_code));
Error_Detected = true; Error_Detected = true;
} }
void MyAbortHandler( void MyAbortHandler(BACNET_ADDRESS * src,
BACNET_ADDRESS *src, uint8_t invoke_id, uint8_t abort_reason)
uint8_t invoke_id,
uint8_t abort_reason)
{ {
/* FIXME: verify src and invoke id */ /* FIXME: verify src and invoke id */
(void)src; (void) src;
(void)invoke_id; (void) invoke_id;
printf("BACnet Abort: %s\r\n", printf("BACnet Abort: %s\r\n",
bactext_abort_reason_name(abort_reason)); bactext_abort_reason_name(abort_reason));
Error_Detected = true; Error_Detected = true;
} }
void MyRejectHandler( void MyRejectHandler(BACNET_ADDRESS * src,
BACNET_ADDRESS *src, uint8_t invoke_id, uint8_t reject_reason)
uint8_t invoke_id,
uint8_t reject_reason)
{ {
/* FIXME: verify src and invoke id */ /* FIXME: verify src and invoke id */
(void)src; (void) src;
(void)invoke_id; (void) invoke_id;
printf("BACnet Reject: %s\r\n", printf("BACnet Reject: %s\r\n",
bactext_reject_reason_name(reject_reason)); bactext_reject_reason_name(reject_reason));
Error_Detected = true; Error_Detected = true;
} }
static void Init_Service_Handlers(void) static void Init_Service_Handlers(void)
{ {
/* we need to handle who-is /* we need to handle who-is
to support dynamic device binding to us */ to support dynamic device binding to us */
apdu_set_unconfirmed_handler( apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS,
SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
handler_who_is); /* handle i-am to support binding to other devices */
/* handle i-am to support binding to other devices */ apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_I_AM,
apdu_set_unconfirmed_handler( handler_i_am_bind);
SERVICE_UNCONFIRMED_I_AM, /* set the handler for all the services we don't implement
handler_i_am_bind); It is required to send the proper reject message... */
/* set the handler for all the services we don't implement apdu_set_unrecognized_service_handler_handler
It is required to send the proper reject message... */ (handler_unrecognized_service);
apdu_set_unrecognized_service_handler_handler( /* we must implement read property - it's required! */
handler_unrecognized_service); apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY,
/* we must implement read property - it's required! */ handler_read_property);
apdu_set_confirmed_handler( /* handle the data coming back from confirmed requests */
SERVICE_CONFIRMED_READ_PROPERTY, apdu_set_confirmed_ack_handler(SERVICE_CONFIRMED_READ_PROPERTY,
handler_read_property); handler_read_property_ack);
/* handle the data coming back from confirmed requests */ /* handle any errors coming back */
apdu_set_confirmed_ack_handler( apdu_set_error_handler(SERVICE_CONFIRMED_READ_PROPERTY,
SERVICE_CONFIRMED_READ_PROPERTY, MyErrorHandler);
handler_read_property_ack); apdu_set_abort_handler(MyAbortHandler);
/* handle any errors coming back */ apdu_set_reject_handler(MyRejectHandler);
apdu_set_error_handler(
SERVICE_CONFIRMED_READ_PROPERTY,
MyErrorHandler);
apdu_set_abort_handler(
MyAbortHandler);
apdu_set_reject_handler(
MyRejectHandler);
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
BACNET_ADDRESS src = {0}; // address where message came from BACNET_ADDRESS src = { 0 }; // address where message came from
uint16_t pdu_len = 0; uint16_t pdu_len = 0;
unsigned timeout = 100; // milliseconds unsigned timeout = 100; // milliseconds
unsigned max_apdu = 0; unsigned max_apdu = 0;
time_t elapsed_seconds = 0; time_t elapsed_seconds = 0;
time_t last_seconds = 0; time_t last_seconds = 0;
time_t current_seconds = 0; time_t current_seconds = 0;
time_t timeout_seconds = 0; time_t timeout_seconds = 0;
uint8_t invoke_id = 0; uint8_t invoke_id = 0;
bool found = false; bool found = false;
if (argc < 5) if (argc < 5) {
{ printf
printf("%s device-instance object-type object-instance property [index]\r\n", ("%s device-instance object-type object-instance property [index]\r\n",
filename_remove_path(argv[0])); filename_remove_path(argv[0]));
return 0; return 0;
}
/* decode the command line parameters */
Target_Device_Object_Instance = strtol(argv[1],NULL,0);
Target_Object_Type = strtol(argv[2],NULL,0);
Target_Object_Instance = strtol(argv[3],NULL,0);
Target_Object_Property = strtol(argv[4],NULL,0);
if (argc > 5)
Target_Object_Index = strtol(argv[5],NULL,0);
if (Target_Device_Object_Instance >= BACNET_MAX_INSTANCE)
{
fprintf(stderr,"device-instance=%u - it must be less than %u\r\n",
Target_Device_Object_Instance,BACNET_MAX_INSTANCE);
return 1;
}
if (Target_Object_Type > MAX_BACNET_OBJECT_TYPE)
{
fprintf(stderr,"object-type=%u - it must be less than %u\r\n",
Target_Object_Type,MAX_BACNET_OBJECT_TYPE+1);
return 1;
}
if (Target_Object_Instance > BACNET_MAX_INSTANCE)
{
fprintf(stderr,"object-instance=%u - it must be less than %u\r\n",
Target_Object_Instance,BACNET_MAX_INSTANCE+1);
return 1;
}
if (Target_Object_Property > MAX_BACNET_PROPERTY_ID)
{
fprintf(stderr,"object-type=%u - it must be less than %u\r\n",
Target_Object_Property,MAX_BACNET_PROPERTY_ID+1);
return 1;
}
/* setup my info */
Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE);
address_init();
Init_Service_Handlers();
/* configure standard BACnet/IP port */
bip_set_interface("eth0"); /* for linux */
bip_set_port(0xBAC0);
if (!bip_init())
return 1;
/* configure the timeout values */
last_seconds = time(NULL);
timeout_seconds = (Device_APDU_Timeout() / 1000) *
Device_Number_Of_APDU_Retries();
/* no need to spam the world */
I_Am_Request = false;
/* try to bind with the device */
Send_WhoIs(Target_Device_Object_Instance,Target_Device_Object_Instance);
/* loop forever */
for (;;)
{
/* increment timer - exit if timed out */
current_seconds = time(NULL);
/* returns 0 bytes on timeout */
pdu_len = bip_receive(
&src,
&Rx_Buf[0],
MAX_MPDU,
timeout);
/* process */
if (pdu_len)
{
npdu_handler(
&src,
&Rx_Buf[0],
pdu_len);
} }
/* at least one second has passed */ /* decode the command line parameters */
if (current_seconds != last_seconds) Target_Device_Object_Instance = strtol(argv[1], NULL, 0);
tsm_timer_milliseconds(((current_seconds - last_seconds) * 1000)); Target_Object_Type = strtol(argv[2], NULL, 0);
if (Error_Detected) Target_Object_Instance = strtol(argv[3], NULL, 0);
break; Target_Object_Property = strtol(argv[4], NULL, 0);
if (I_Am_Request) if (argc > 5)
{ Target_Object_Index = strtol(argv[5], NULL, 0);
I_Am_Request = false; if (Target_Device_Object_Instance >= BACNET_MAX_INSTANCE) {
iam_send(&Handler_Transmit_Buffer[0]); fprintf(stderr, "device-instance=%u - it must be less than %u\r\n",
Target_Device_Object_Instance, BACNET_MAX_INSTANCE);
return 1;
} }
else if (Target_Object_Type > MAX_BACNET_OBJECT_TYPE) {
{ fprintf(stderr, "object-type=%u - it must be less than %u\r\n",
/* wait until the device is bound, or timeout and quit */ Target_Object_Type, MAX_BACNET_OBJECT_TYPE + 1);
found = address_bind_request( return 1;
Target_Device_Object_Instance, }
&max_apdu, if (Target_Object_Instance > BACNET_MAX_INSTANCE) {
&Target_Address); fprintf(stderr, "object-instance=%u - it must be less than %u\r\n",
if (found) Target_Object_Instance, BACNET_MAX_INSTANCE + 1);
{ return 1;
if (invoke_id == 0) }
{ if (Target_Object_Property > MAX_BACNET_PROPERTY_ID) {
invoke_id = Send_Read_Property_Request( fprintf(stderr, "object-type=%u - it must be less than %u\r\n",
Target_Device_Object_Instance, Target_Object_Property, MAX_BACNET_PROPERTY_ID + 1);
Target_Object_Type, return 1;
Target_Object_Instance, }
Target_Object_Property,
Target_Object_Index); /* setup my info */
} Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE);
else if (tsm_invoke_id_free(invoke_id)) address_init();
break; Init_Service_Handlers();
} /* configure standard BACnet/IP port */
else bip_set_interface("eth0"); /* for linux */
{ bip_set_port(0xBAC0);
if (!bip_init())
return 1;
/* configure the timeout values */
last_seconds = time(NULL);
timeout_seconds = (Device_APDU_Timeout() / 1000) *
Device_Number_Of_APDU_Retries();
/* no need to spam the world */
I_Am_Request = false;
/* try to bind with the device */
Send_WhoIs(Target_Device_Object_Instance,
Target_Device_Object_Instance);
/* loop forever */
for (;;) {
/* increment timer - exit if timed out */ /* increment timer - exit if timed out */
elapsed_seconds += (current_seconds - last_seconds); current_seconds = time(NULL);
if (elapsed_seconds > timeout_seconds)
break;
}
}
/* keep track of time for next check */
last_seconds = current_seconds;
}
return 0; /* returns 0 bytes on timeout */
pdu_len = bip_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout);
/* process */
if (pdu_len) {
npdu_handler(&src, &Rx_Buf[0], pdu_len);
}
/* at least one second has passed */
if (current_seconds != last_seconds)
tsm_timer_milliseconds(((current_seconds -
last_seconds) * 1000));
if (Error_Detected)
break;
if (I_Am_Request) {
I_Am_Request = false;
iam_send(&Handler_Transmit_Buffer[0]);
} else {
/* wait until the device is bound, or timeout and quit */
found = address_bind_request(Target_Device_Object_Instance,
&max_apdu, &Target_Address);
if (found) {
if (invoke_id == 0) {
invoke_id =
Send_Read_Property_Request
(Target_Device_Object_Instance, Target_Object_Type,
Target_Object_Instance, Target_Object_Property,
Target_Object_Index);
} else if (tsm_invoke_id_free(invoke_id))
break;
} else {
/* increment timer - exit if timed out */
elapsed_seconds += (current_seconds - last_seconds);
if (elapsed_seconds > timeout_seconds)
break;
}
}
/* keep track of time for next check */
last_seconds = current_seconds;
}
return 0;
} }
+175 -212
View File
@@ -28,7 +28,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h> /* for time */ #include <time.h> /* for time */
#include <errno.h> #include <errno.h>
#include "bactext.h" #include "bactext.h"
#include "iam.h" #include "iam.h"
@@ -51,253 +51,216 @@
#include "txbuf.h" #include "txbuf.h"
// buffer used for receive // buffer used for receive
static uint8_t Rx_Buf[MAX_MPDU] = {0}; static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
/* global variables used in this file */ /* global variables used in this file */
static uint32_t Target_Device_Object_Instance = BACNET_MAX_INSTANCE; static uint32_t Target_Device_Object_Instance = BACNET_MAX_INSTANCE;
static BACNET_ADDRESS Target_Address; static BACNET_ADDRESS Target_Address;
static BACNET_REINITIALIZED_STATE Reinitialize_State = BACNET_REINIT_COLDSTART; static BACNET_REINITIALIZED_STATE Reinitialize_State =
BACNET_REINIT_COLDSTART;
static char *Reinitialize_Password = NULL; static char *Reinitialize_Password = NULL;
static bool Error_Detected = false; static bool Error_Detected = false;
static void MyErrorHandler( static void MyErrorHandler(BACNET_ADDRESS * src,
BACNET_ADDRESS *src, uint8_t invoke_id,
uint8_t invoke_id, BACNET_ERROR_CLASS error_class, BACNET_ERROR_CODE error_code)
BACNET_ERROR_CLASS error_class,
BACNET_ERROR_CODE error_code)
{ {
/* FIXME: verify src and invoke id */ /* FIXME: verify src and invoke id */
(void)src; (void) src;
(void)invoke_id; (void) invoke_id;
printf("BACnet Error: %s: %s\r\n", printf("BACnet Error: %s: %s\r\n",
bactext_error_class_name(error_class), bactext_error_class_name(error_class),
bactext_error_code_name(error_code)); bactext_error_code_name(error_code));
Error_Detected = true; Error_Detected = true;
} }
void MyAbortHandler( void MyAbortHandler(BACNET_ADDRESS * src,
BACNET_ADDRESS *src, uint8_t invoke_id, uint8_t abort_reason)
uint8_t invoke_id,
uint8_t abort_reason)
{ {
/* FIXME: verify src and invoke id */ /* FIXME: verify src and invoke id */
(void)src; (void) src;
(void)invoke_id; (void) invoke_id;
printf("BACnet Abort: %s\r\n", printf("BACnet Abort: %s\r\n",
bactext_abort_reason_name(abort_reason)); bactext_abort_reason_name(abort_reason));
Error_Detected = true; Error_Detected = true;
} }
void MyRejectHandler( void MyRejectHandler(BACNET_ADDRESS * src,
BACNET_ADDRESS *src, uint8_t invoke_id, uint8_t reject_reason)
uint8_t invoke_id,
uint8_t reject_reason)
{ {
/* FIXME: verify src and invoke id */ /* FIXME: verify src and invoke id */
(void)src; (void) src;
(void)invoke_id; (void) invoke_id;
printf("BACnet Reject: %s\r\n", printf("BACnet Reject: %s\r\n",
bactext_reject_reason_name(reject_reason)); bactext_reject_reason_name(reject_reason));
Error_Detected = true; Error_Detected = true;
} }
void MyReinitializeDeviceSimpleAckHandler( void MyReinitializeDeviceSimpleAckHandler(BACNET_ADDRESS * src,
BACNET_ADDRESS *src, uint8_t invoke_id)
uint8_t invoke_id)
{ {
(void)src; (void) src;
(void)invoke_id; (void) invoke_id;
printf("ReinitializeDevice Acknowledged!\r\n"); printf("ReinitializeDevice Acknowledged!\r\n");
} }
static void Init_Service_Handlers(void) static void Init_Service_Handlers(void)
{ {
/* we need to handle who-is /* we need to handle who-is
to support dynamic device binding to us */ to support dynamic device binding to us */
apdu_set_unconfirmed_handler( apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS,
SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
handler_who_is); /* handle i-am to support binding to other devices */
/* handle i-am to support binding to other devices */ apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_I_AM,
apdu_set_unconfirmed_handler( handler_i_am_bind);
SERVICE_UNCONFIRMED_I_AM, /* set the handler for all the services we don't implement
handler_i_am_bind); It is required to send the proper reject message... */
/* set the handler for all the services we don't implement apdu_set_unrecognized_service_handler_handler
It is required to send the proper reject message... */ (handler_unrecognized_service);
apdu_set_unrecognized_service_handler_handler( /* we must implement read property - it's required! */
handler_unrecognized_service); apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY,
/* we must implement read property - it's required! */ handler_read_property);
apdu_set_confirmed_handler( /* handle the ack coming back */
SERVICE_CONFIRMED_READ_PROPERTY, apdu_set_confirmed_simple_ack_handler
handler_read_property); (SERVICE_CONFIRMED_REINITIALIZE_DEVICE,
/* handle the ack coming back */ MyReinitializeDeviceSimpleAckHandler);
apdu_set_confirmed_simple_ack_handler( /* handle any errors coming back */
SERVICE_CONFIRMED_REINITIALIZE_DEVICE, apdu_set_error_handler(SERVICE_CONFIRMED_REINITIALIZE_DEVICE,
MyReinitializeDeviceSimpleAckHandler); MyErrorHandler);
/* handle any errors coming back */ apdu_set_abort_handler(MyAbortHandler);
apdu_set_error_handler( apdu_set_reject_handler(MyRejectHandler);
SERVICE_CONFIRMED_REINITIALIZE_DEVICE,
MyErrorHandler);
apdu_set_abort_handler(
MyAbortHandler);
apdu_set_reject_handler(
MyRejectHandler);
} }
#ifdef BIP_DEBUG #ifdef BIP_DEBUG
static void print_address( static void print_address(char *name, BACNET_ADDRESS * dest) // destination address
char *name,
BACNET_ADDRESS *dest) // destination address
{ {
int i = 0; // counter int i = 0; // counter
if (dest) if (dest) {
{ printf("%s: ", name);
printf("%s: ",name); for (i = 0; i < dest->mac_len; i++) {
for (i = 0; i < dest->mac_len; i++) printf("%02X", dest->mac[i]);
{ }
printf("%02X",dest->mac[i]); printf("\n");
} }
printf("\n");
}
} }
#endif #endif
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
BACNET_ADDRESS src = {0}; // address where message came from BACNET_ADDRESS src = { 0 }; // address where message came from
uint16_t pdu_len = 0; uint16_t pdu_len = 0;
unsigned timeout = 100; // milliseconds unsigned timeout = 100; // milliseconds
unsigned max_apdu = 0; unsigned max_apdu = 0;
time_t elapsed_seconds = 0; time_t elapsed_seconds = 0;
time_t last_seconds = 0; time_t last_seconds = 0;
time_t current_seconds = 0; time_t current_seconds = 0;
time_t timeout_seconds = 0; time_t timeout_seconds = 0;
uint8_t invoke_id = 0; uint8_t invoke_id = 0;
bool found = false; bool found = false;
#ifdef BIP_DEBUG #ifdef BIP_DEBUG
BACNET_ADDRESS my_address, broadcast_address; BACNET_ADDRESS my_address, broadcast_address;
#endif #endif
if (argc < 3) if (argc < 3) {
{ /* note: priority 16 and 0 should produce the same end results... */
/* note: priority 16 and 0 should produce the same end results... */ printf("Usage: %s device-instance state [password]\r\n"
printf( "Send BACnet ReinitializeDevice service to device.\r\n"
"Usage: %s device-instance state [password]\r\n" "\r\n"
"Send BACnet ReinitializeDevice service to device.\r\n" "The device-instance can be 0 to %d.\r\n"
"\r\n" "Possible state values:\r\n"
"The device-instance can be 0 to %d.\r\n" " 0=coldstart\r\n"
"Possible state values:\r\n" " 1=warmstart\r\n"
" 0=coldstart\r\n" " 2=startbackup\r\n"
" 1=warmstart\r\n" " 3=endbackup\r\n"
" 2=startbackup\r\n" " 4=startrestore\r\n"
" 3=endbackup\r\n" " 5=endrestore\r\n"
" 4=startrestore\r\n" " 6=abortrestore\r\n"
" 5=endrestore\r\n" "The optional password is a character string of 1 to 20 characters.\r\n",
" 6=abortrestore\r\n" filename_remove_path(argv[0]), BACNET_MAX_INSTANCE - 1);
"The optional password is a character string of 1 to 20 characters.\r\n", return 0;
filename_remove_path(argv[0]),
BACNET_MAX_INSTANCE-1);
return 0;
}
/* decode the command line parameters */
Target_Device_Object_Instance = strtol(argv[1],NULL,0);
Reinitialize_State = strtol(argv[2],NULL,0);
/* optional password */
if (argc > 3)
Reinitialize_Password = argv[3];
if (Target_Device_Object_Instance >= BACNET_MAX_INSTANCE)
{
fprintf(stderr,"device-instance=%u - it must be less than %u\r\n",
Target_Device_Object_Instance,BACNET_MAX_INSTANCE);
return 1;
}
/* setup my info */
Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE);
address_init();
Init_Service_Handlers();
/* configure standard BACnet/IP port */
bip_set_interface("eth0"); /* for linux */
bip_set_port(0xBAC0);
if (!bip_init())
return 1;
#ifdef BIP_DEBUG
datalink_get_broadcast_address(&broadcast_address);
print_address("Broadcast",&broadcast_address);
datalink_get_my_address(&my_address);
print_address("Address",&my_address);
#endif
/* configure the timeout values */
last_seconds = time(NULL);
timeout_seconds = (Device_APDU_Timeout() / 1000) *
Device_Number_Of_APDU_Retries();
/* don't send an I-Am unless asked */
I_Am_Request = false;
/* try to bind with the device */
Send_WhoIs(Target_Device_Object_Instance,Target_Device_Object_Instance);
/* loop forever */
for (;;)
{
/* increment timer - exit if timed out */
current_seconds = time(NULL);
/* returns 0 bytes on timeout */
pdu_len = bip_receive(
&src,
&Rx_Buf[0],
MAX_MPDU,
timeout);
/* process */
if (pdu_len)
{
npdu_handler(
&src,
&Rx_Buf[0],
pdu_len);
} }
/* at least one second has passed */ /* decode the command line parameters */
if (current_seconds != last_seconds) Target_Device_Object_Instance = strtol(argv[1], NULL, 0);
tsm_timer_milliseconds(((current_seconds - last_seconds) * 1000)); Reinitialize_State = strtol(argv[2], NULL, 0);
if (Error_Detected) /* optional password */
break; if (argc > 3)
if (I_Am_Request) Reinitialize_Password = argv[3];
{
I_Am_Request = false; if (Target_Device_Object_Instance >= BACNET_MAX_INSTANCE) {
iam_send(&Handler_Transmit_Buffer[0]); fprintf(stderr, "device-instance=%u - it must be less than %u\r\n",
Target_Device_Object_Instance, BACNET_MAX_INSTANCE);
return 1;
} }
else
{ /* setup my info */
/* wait until the device is bound, or timeout and quit */ Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE);
found = address_bind_request( address_init();
Target_Device_Object_Instance, Init_Service_Handlers();
&max_apdu, /* configure standard BACnet/IP port */
&Target_Address); bip_set_interface("eth0"); /* for linux */
if (found) bip_set_port(0xBAC0);
{ if (!bip_init())
if (invoke_id == 0) return 1;
{ #ifdef BIP_DEBUG
invoke_id = Send_Reinitialize_Device_Request( datalink_get_broadcast_address(&broadcast_address);
Target_Device_Object_Instance, print_address("Broadcast", &broadcast_address);
Reinitialize_State, datalink_get_my_address(&my_address);
Reinitialize_Password); print_address("Address", &my_address);
} #endif
else if (tsm_invoke_id_free(invoke_id)) /* configure the timeout values */
break; last_seconds = time(NULL);
} timeout_seconds = (Device_APDU_Timeout() / 1000) *
else Device_Number_Of_APDU_Retries();
{ /* don't send an I-Am unless asked */
I_Am_Request = false;
/* try to bind with the device */
Send_WhoIs(Target_Device_Object_Instance,
Target_Device_Object_Instance);
/* loop forever */
for (;;) {
/* increment timer - exit if timed out */ /* increment timer - exit if timed out */
elapsed_seconds += (current_seconds - last_seconds); current_seconds = time(NULL);
if (elapsed_seconds > timeout_seconds)
break;
}
}
/* keep track of time for next check */
last_seconds = current_seconds;
}
return 0; /* returns 0 bytes on timeout */
pdu_len = bip_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout);
/* process */
if (pdu_len) {
npdu_handler(&src, &Rx_Buf[0], pdu_len);
}
/* at least one second has passed */
if (current_seconds != last_seconds)
tsm_timer_milliseconds(((current_seconds -
last_seconds) * 1000));
if (Error_Detected)
break;
if (I_Am_Request) {
I_Am_Request = false;
iam_send(&Handler_Transmit_Buffer[0]);
} else {
/* wait until the device is bound, or timeout and quit */
found = address_bind_request(Target_Device_Object_Instance,
&max_apdu, &Target_Address);
if (found) {
if (invoke_id == 0) {
invoke_id =
Send_Reinitialize_Device_Request
(Target_Device_Object_Instance, Reinitialize_State,
Reinitialize_Password);
} else if (tsm_invoke_id_free(invoke_id))
break;
} else {
/* increment timer - exit if timed out */
elapsed_seconds += (current_seconds - last_seconds);
if (elapsed_seconds > timeout_seconds)
break;
}
}
/* keep track of time for next check */
last_seconds = current_seconds;
}
return 0;
} }
+92 -112
View File
@@ -48,136 +48,116 @@
/* This is an example application using the BACnet Stack */ /* This is an example application using the BACnet Stack */
/* buffers used for receiving */ /* buffers used for receiving */
static uint8_t Rx_Buf[MAX_MPDU] = {0}; 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 */ /* we need to handle who-is to support dynamic device binding */
apdu_set_unconfirmed_handler( apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS,
SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
handler_who_is); apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_HAS,
apdu_set_unconfirmed_handler( handler_who_has);
SERVICE_UNCONFIRMED_WHO_HAS, /* set the handler for all the services we don't implement */
handler_who_has); /* It is required to send the proper reject message... */
/* set the handler for all the services we don't implement */ apdu_set_unrecognized_service_handler_handler
/* It is required to send the proper reject message... */ (handler_unrecognized_service);
apdu_set_unrecognized_service_handler_handler( /* Set the handlers for any confirmed services that we support. */
handler_unrecognized_service); /* We must implement read property - it's required! */
/* Set the handlers for any confirmed services that we support. */ apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY,
/* We must implement read property - it's required! */ handler_read_property);
apdu_set_confirmed_handler( apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROPERTY,
SERVICE_CONFIRMED_READ_PROPERTY, handler_write_property);
handler_read_property); apdu_set_confirmed_handler(SERVICE_CONFIRMED_ATOMIC_READ_FILE,
apdu_set_confirmed_handler( handler_atomic_read_file);
SERVICE_CONFIRMED_WRITE_PROPERTY, apdu_set_confirmed_handler(SERVICE_CONFIRMED_REINITIALIZE_DEVICE,
handler_write_property); handler_reinitialize_device);
apdu_set_confirmed_handler( /* handle communication so we can shutup when asked */
SERVICE_CONFIRMED_ATOMIC_READ_FILE, apdu_set_confirmed_handler
handler_atomic_read_file); (SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL,
apdu_set_confirmed_handler( handler_device_communication_control);
SERVICE_CONFIRMED_REINITIALIZE_DEVICE,
handler_reinitialize_device);
/* handle communication so we can shutup when asked */
apdu_set_confirmed_handler(
SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL,
handler_device_communication_control);
} }
static void cleanup(void) static void cleanup(void)
{ {
datalink_cleanup(); datalink_cleanup();
} }
static void print_address( static void print_address(char *name, BACNET_ADDRESS * dest) // destination address
char *name,
BACNET_ADDRESS *dest) // destination address
{ {
int i = 0; // counter int i = 0; // counter
if (dest) if (dest) {
{ printf("%s: ", name);
printf("%s: ",name); for (i = 0; i < dest->mac_len; i++) {
for (i = 0; i < dest->mac_len; i++) printf("%02X", dest->mac[i]);
{ }
printf("%02X",dest->mac[i]); printf("\n");
} }
printf("\n");
}
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
BACNET_ADDRESS src = {0}; // address where message came from BACNET_ADDRESS src = { 0 }; // address where message came from
uint16_t pdu_len = 0; uint16_t pdu_len = 0;
unsigned timeout = 100; // milliseconds unsigned timeout = 100; // milliseconds
BACNET_ADDRESS my_address, broadcast_address; BACNET_ADDRESS my_address, broadcast_address;
time_t last_seconds = 0; time_t last_seconds = 0;
time_t current_seconds = 0; time_t current_seconds = 0;
/* allow the device ID to be set */ /* allow the device ID to be set */
if (argc > 1) if (argc > 1)
Device_Set_Object_Instance_Number(strtol(argv[1],NULL,0)); Device_Set_Object_Instance_Number(strtol(argv[1], NULL, 0));
if (argc > 2) if (argc > 2)
bip_set_port(strtol(argv[2],NULL,0)); bip_set_port(strtol(argv[2], NULL, 0));
printf("BACnet Server Demo - Device #%u\r\n", printf("BACnet Server Demo - Device #%u\r\n",
Device_Object_Instance_Number()); Device_Object_Instance_Number());
Init_Service_Handlers(); Init_Service_Handlers();
#ifdef BACDL_ETHERNET #ifdef BACDL_ETHERNET
// init the physical layer // init the physical layer
if (!ethernet_init("eth0")) if (!ethernet_init("eth0"))
return 1; return 1;
#endif #endif
#ifdef BACDL_BIP #ifdef BACDL_BIP
bip_set_interface("eth0"); bip_set_interface("eth0");
if (!bip_init()) if (!bip_init())
return 1; return 1;
printf("bip: using port %hu\r\n",bip_get_port()); printf("bip: using port %hu\r\n", bip_get_port());
#endif #endif
#ifdef BACDL_ARCNET #ifdef BACDL_ARCNET
if (!arcnet_init("arc0")) if (!arcnet_init("arc0"))
return 1; return 1;
#endif #endif
datalink_get_broadcast_address(&broadcast_address); datalink_get_broadcast_address(&broadcast_address);
print_address("Broadcast",&broadcast_address); print_address("Broadcast", &broadcast_address);
datalink_get_my_address(&my_address); datalink_get_my_address(&my_address);
print_address("Address",&my_address); print_address("Address", &my_address);
atexit(cleanup); atexit(cleanup);
/* configure the timeout values */ /* configure the timeout values */
last_seconds = time(NULL); last_seconds = time(NULL);
/* broadcast an I-Am on startup */ /* broadcast an I-Am on startup */
I_Am_Request = true; I_Am_Request = true;
// loop forever // loop forever
for (;;) for (;;) {
{ // input
// input current_seconds = time(NULL);
current_seconds = time(NULL);
// returns 0 bytes on timeout // returns 0 bytes on timeout
pdu_len = datalink_receive( pdu_len = datalink_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout);
&src,
&Rx_Buf[0],
MAX_MPDU,
timeout);
// process // process
if (pdu_len) if (pdu_len) {
{ npdu_handler(&src, &Rx_Buf[0], pdu_len);
npdu_handler( }
&src, /* at least one second has passed */
&Rx_Buf[0], if (current_seconds != last_seconds)
pdu_len); dcc_timer_seconds(current_seconds - last_seconds);
/* send out the I-Am if requested */
if (I_Am_Request) {
I_Am_Request = false;
iam_send(&Handler_Transmit_Buffer[0]);
}
// output
// blink LEDs, Turn on or off outputs, etc
} }
/* at least one second has passed */
if (current_seconds != last_seconds)
dcc_timer_seconds(current_seconds - last_seconds);
/* send out the I-Am if requested */
if (I_Am_Request)
{
I_Am_Request = false;
iam_send(&Handler_Transmit_Buffer[0]);
}
// output
// blink LEDs, Turn on or off outputs, etc
}
} }
+131 -164
View File
@@ -28,7 +28,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h> /* for time */ #include <time.h> /* for time */
#include <errno.h> #include <errno.h>
#include "bactext.h" #include "bactext.h"
#include "iam.h" #include "iam.h"
@@ -50,7 +50,7 @@
#include "txbuf.h" #include "txbuf.h"
// buffer used for receive // buffer used for receive
static uint8_t Rx_Buf[MAX_MPDU] = {0}; static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
/* global variables used in this file */ /* global variables used in this file */
static BACNET_OBJECT_TYPE Target_Object_Type = MAX_BACNET_OBJECT_TYPE; static BACNET_OBJECT_TYPE Target_Object_Type = MAX_BACNET_OBJECT_TYPE;
@@ -59,191 +59,158 @@ static char *Target_Object_Name = NULL;
static bool Error_Detected = false; static bool Error_Detected = false;
void MyAbortHandler( void MyAbortHandler(BACNET_ADDRESS * src,
BACNET_ADDRESS *src, uint8_t invoke_id, uint8_t abort_reason)
uint8_t invoke_id,
uint8_t abort_reason)
{ {
/* FIXME: verify src and invoke id */ /* FIXME: verify src and invoke id */
(void)src; (void) src;
(void)invoke_id; (void) invoke_id;
printf("BACnet Abort: %s\r\n", printf("BACnet Abort: %s\r\n",
bactext_abort_reason_name(abort_reason)); bactext_abort_reason_name(abort_reason));
Error_Detected = true; Error_Detected = true;
} }
void MyRejectHandler( void MyRejectHandler(BACNET_ADDRESS * src,
BACNET_ADDRESS *src, uint8_t invoke_id, uint8_t reject_reason)
uint8_t invoke_id,
uint8_t reject_reason)
{ {
/* FIXME: verify src and invoke id */ /* FIXME: verify src and invoke id */
(void)src; (void) src;
(void)invoke_id; (void) invoke_id;
printf("BACnet Reject: %s\r\n", printf("BACnet Reject: %s\r\n",
bactext_reject_reason_name(reject_reason)); bactext_reject_reason_name(reject_reason));
Error_Detected = true; Error_Detected = true;
} }
static void Init_Service_Handlers(void) static void Init_Service_Handlers(void)
{ {
/* we need to handle who-is /* we need to handle who-is
to support dynamic device binding to us */ to support dynamic device binding to us */
apdu_set_unconfirmed_handler( apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS,
SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
handler_who_is); /* set the handler for all the services we don't implement
/* set the handler for all the services we don't implement It is required to send the proper reject message... */
It is required to send the proper reject message... */ apdu_set_unrecognized_service_handler_handler
apdu_set_unrecognized_service_handler_handler( (handler_unrecognized_service);
handler_unrecognized_service); /* we must implement read property - it's required! */
/* we must implement read property - it's required! */ apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY,
apdu_set_confirmed_handler( handler_read_property);
SERVICE_CONFIRMED_READ_PROPERTY, /* handle the reply (request) coming back */
handler_read_property); apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_I_HAVE,
/* handle the reply (request) coming back */ handler_i_have);
apdu_set_unconfirmed_handler( /* handle any errors coming back */
SERVICE_UNCONFIRMED_I_HAVE, apdu_set_abort_handler(MyAbortHandler);
handler_i_have); apdu_set_reject_handler(MyRejectHandler);
/* handle any errors coming back */
apdu_set_abort_handler(
MyAbortHandler);
apdu_set_reject_handler(
MyRejectHandler);
} }
#ifdef BIP_DEBUG #ifdef BIP_DEBUG
static void print_address( static void print_address(char *name, BACNET_ADDRESS * dest) // destination address
char *name,
BACNET_ADDRESS *dest) // destination address
{ {
int i = 0; // counter int i = 0; // counter
if (dest) if (dest) {
{ printf("%s: ", name);
printf("%s: ",name); for (i = 0; i < dest->mac_len; i++) {
for (i = 0; i < dest->mac_len; i++) printf("%02X", dest->mac[i]);
{ }
printf("%02X",dest->mac[i]); printf("\n");
} }
printf("\n");
}
} }
#endif #endif
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
BACNET_ADDRESS src = {0}; // address where message came from BACNET_ADDRESS src = { 0 }; // address where message came from
uint16_t pdu_len = 0; uint16_t pdu_len = 0;
unsigned timeout = 100; // milliseconds unsigned timeout = 100; // milliseconds
time_t elapsed_seconds = 0; time_t elapsed_seconds = 0;
time_t last_seconds = 0; time_t last_seconds = 0;
time_t current_seconds = 0; time_t current_seconds = 0;
time_t timeout_seconds = 0; time_t timeout_seconds = 0;
#ifdef BIP_DEBUG #ifdef BIP_DEBUG
BACNET_ADDRESS my_address, broadcast_address; BACNET_ADDRESS my_address, broadcast_address;
#endif #endif
if (argc < 2) if (argc < 2) {
{ /* note: priority 16 and 0 should produce the same end results... */
/* note: priority 16 and 0 should produce the same end results... */ printf("Usage: %s <object-type object-instance | object-name>\r\n"
printf( "Send BACnet WhoHas request to devices, and wait for responses.\r\n"
"Usage: %s <object-type object-instance | object-name>\r\n" "\r\n"
"Send BACnet WhoHas request to devices, and wait for responses.\r\n" "Use either:\r\n"
"\r\n" "The object-type can be 0 to %d.\r\n"
"Use either:\r\n" "The object-instance can be 0 to %d.\r\n"
"The object-type can be 0 to %d.\r\n" "or:\r\n"
"The object-instance can be 0 to %d.\r\n" "The object-name can be any string of characters.\r\n",
"or:\r\n" filename_remove_path(argv[0]),
"The object-name can be any string of characters.\r\n", MAX_BACNET_OBJECT_TYPE - 1, BACNET_MAX_INSTANCE);
filename_remove_path(argv[0]), return 0;
MAX_BACNET_OBJECT_TYPE-1,
BACNET_MAX_INSTANCE);
return 0;
}
/* decode the command line parameters */
if (argc < 3)
{
Target_Object_Name = argv[1];
}
else
{
Target_Object_Type = strtol(argv[1],NULL,0);
Target_Object_Instance = strtol(argv[2],NULL,0);
if (Target_Object_Instance > BACNET_MAX_INSTANCE)
{
fprintf(stderr,"object-instance=%u - it must be less than %u\r\n",
Target_Object_Instance,BACNET_MAX_INSTANCE+1);
return 1;
} }
if (Target_Object_Type > MAX_BACNET_OBJECT_TYPE) /* decode the command line parameters */
{ if (argc < 3) {
fprintf(stderr,"object-type=%u - it must be less than %u\r\n", Target_Object_Name = argv[1];
Target_Object_Type,MAX_BACNET_OBJECT_TYPE+1); } else {
return 1; Target_Object_Type = strtol(argv[1], NULL, 0);
} Target_Object_Instance = strtol(argv[2], NULL, 0);
} if (Target_Object_Instance > BACNET_MAX_INSTANCE) {
/* setup my info */ fprintf(stderr,
Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE); "object-instance=%u - it must be less than %u\r\n",
Init_Service_Handlers(); Target_Object_Instance, BACNET_MAX_INSTANCE + 1);
/* configure standard BACnet/IP port */ return 1;
bip_set_interface("eth0"); /* for linux */ }
bip_set_port(0xBAC0); if (Target_Object_Type > MAX_BACNET_OBJECT_TYPE) {
if (!bip_init()) fprintf(stderr, "object-type=%u - it must be less than %u\r\n",
return 1; Target_Object_Type, MAX_BACNET_OBJECT_TYPE + 1);
#ifdef BIP_DEBUG return 1;
datalink_get_broadcast_address(&broadcast_address); }
print_address("Broadcast",&broadcast_address);
datalink_get_my_address(&my_address);
print_address("Address",&my_address);
#endif
/* configure the timeout values */
last_seconds = time(NULL);
timeout_seconds = Device_APDU_Timeout() / 1000;
/* don't send an I-Am unless asked */
I_Am_Request = false;
/* send the request */
if (argc < 3)
Send_WhoHas_Name(-1, -1, Target_Object_Name);
else
Send_WhoHas_Object(-1, -1,
Target_Object_Type,
Target_Object_Instance);
/* loop forever */
for (;;)
{
/* increment timer - exit if timed out */
current_seconds = time(NULL);
/* returns 0 bytes on timeout */
pdu_len = bip_receive(
&src,
&Rx_Buf[0],
MAX_MPDU,
timeout);
/* process */
if (pdu_len)
{
npdu_handler(
&src,
&Rx_Buf[0],
pdu_len);
}
if (Error_Detected)
break;
if (I_Am_Request)
{
I_Am_Request = false;
iam_send(&Handler_Transmit_Buffer[0]);
} }
/* setup my info */
Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE);
Init_Service_Handlers();
/* configure standard BACnet/IP port */
bip_set_interface("eth0"); /* for linux */
bip_set_port(0xBAC0);
if (!bip_init())
return 1;
#ifdef BIP_DEBUG
datalink_get_broadcast_address(&broadcast_address);
print_address("Broadcast", &broadcast_address);
datalink_get_my_address(&my_address);
print_address("Address", &my_address);
#endif
/* configure the timeout values */
last_seconds = time(NULL);
timeout_seconds = Device_APDU_Timeout() / 1000;
/* don't send an I-Am unless asked */
I_Am_Request = false;
/* send the request */
if (argc < 3)
Send_WhoHas_Name(-1, -1, Target_Object_Name);
else else
{ Send_WhoHas_Object(-1, -1,
/* increment timer - exit if timed out */ Target_Object_Type, Target_Object_Instance);
elapsed_seconds += (current_seconds - last_seconds); /* loop forever */
if (elapsed_seconds > timeout_seconds) for (;;) {
break; /* increment timer - exit if timed out */
current_seconds = time(NULL);
/* returns 0 bytes on timeout */
pdu_len = bip_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout);
/* process */
if (pdu_len) {
npdu_handler(&src, &Rx_Buf[0], pdu_len);
}
if (Error_Detected)
break;
if (I_Am_Request) {
I_Am_Request = false;
iam_send(&Handler_Transmit_Buffer[0]);
} else {
/* increment timer - exit if timed out */
elapsed_seconds += (current_seconds - last_seconds);
if (elapsed_seconds > timeout_seconds)
break;
}
/* keep track of time for next check */
last_seconds = current_seconds;
} }
/* keep track of time for next check */
last_seconds = current_seconds;
}
return 0; return 0;
} }
+265 -336
View File
@@ -28,7 +28,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h> /* for time */ #include <time.h> /* for time */
#include <errno.h> #include <errno.h>
#include "bactext.h" #include "bactext.h"
#include "iam.h" #include "iam.h"
@@ -49,7 +49,7 @@
#include "txbuf.h" #include "txbuf.h"
// buffer used for receive // buffer used for receive
static uint8_t Rx_Buf[MAX_MPDU] = {0}; static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
/* global variables used in this file */ /* global variables used in this file */
static uint32_t Target_File_Object_Instance = 4194303; static uint32_t Target_File_Object_Instance = 4194303;
@@ -60,378 +60,307 @@ static bool End_Of_File_Detected = false;
static bool Error_Detected = false; static bool Error_Detected = false;
static uint8_t Current_Invoke_ID = 0; static uint8_t Current_Invoke_ID = 0;
static void Atomic_Read_File_Error_Handler( static void Atomic_Read_File_Error_Handler(BACNET_ADDRESS * src,
BACNET_ADDRESS *src, uint8_t invoke_id,
uint8_t invoke_id, BACNET_ERROR_CLASS error_class, BACNET_ERROR_CODE error_code)
BACNET_ERROR_CLASS error_class,
BACNET_ERROR_CODE error_code)
{ {
/* FIXME: verify src and invoke id */ /* FIXME: verify src and invoke id */
(void)src; (void) src;
(void)invoke_id; (void) invoke_id;
printf("\r\nBACnet Error!\r\n"); printf("\r\nBACnet Error!\r\n");
printf("Error Class: %s\r\n", printf("Error Class: %s\r\n", bactext_error_class_name(error_class));
bactext_error_class_name(error_class)); printf("Error Code: %s\r\n", bactext_error_code_name(error_code));
printf("Error Code: %s\r\n", Error_Detected = true;
bactext_error_code_name(error_code));
Error_Detected = true;
} }
void MyAbortHandler( void MyAbortHandler(BACNET_ADDRESS * src,
BACNET_ADDRESS *src, uint8_t invoke_id, uint8_t abort_reason)
uint8_t invoke_id,
uint8_t abort_reason)
{ {
/* FIXME: verify src and invoke id */ /* FIXME: verify src and invoke id */
(void)src; (void) src;
(void)invoke_id; (void) invoke_id;
printf("\r\nBACnet Abort!\r\n"); printf("\r\nBACnet Abort!\r\n");
printf("Abort Reason: %s\r\n", printf("Abort Reason: %s\r\n",
bactext_abort_reason_name(abort_reason)); bactext_abort_reason_name(abort_reason));
Error_Detected = true; Error_Detected = true;
} }
void MyRejectHandler( void MyRejectHandler(BACNET_ADDRESS * src,
BACNET_ADDRESS *src, uint8_t invoke_id, uint8_t reject_reason)
uint8_t invoke_id,
uint8_t reject_reason)
{ {
/* FIXME: verify src and invoke id */ /* FIXME: verify src and invoke id */
(void)src; (void) src;
(void)invoke_id; (void) invoke_id;
printf("\r\nBACnet Reject!\r\n"); printf("\r\nBACnet Reject!\r\n");
printf("Reject Reason: %s\r\n", printf("Reject Reason: %s\r\n",
bactext_reject_reason_name(reject_reason)); bactext_reject_reason_name(reject_reason));
Error_Detected = true; Error_Detected = true;
} }
static uint8_t Send_Atomic_Write_File_Stream( static uint8_t Send_Atomic_Write_File_Stream(uint32_t device_id,
uint32_t device_id, uint32_t file_instance,
uint32_t file_instance, int fileStartPosition, BACNET_OCTET_STRING * fileData)
int fileStartPosition,
BACNET_OCTET_STRING *fileData)
{ {
BACNET_ADDRESS dest; BACNET_ADDRESS dest;
BACNET_ADDRESS my_address; BACNET_ADDRESS my_address;
unsigned max_apdu = 0; unsigned max_apdu = 0;
uint8_t invoke_id = 0; uint8_t invoke_id = 0;
bool status = false; bool status = false;
int pdu_len = 0; int pdu_len = 0;
int bytes_sent = 0; int bytes_sent = 0;
BACNET_ATOMIC_WRITE_FILE_DATA data; BACNET_ATOMIC_WRITE_FILE_DATA data;
/* is the device bound? */ /* is the device bound? */
status = address_get_by_device(device_id, &max_apdu, &dest); status = address_get_by_device(device_id, &max_apdu, &dest);
/* is there a tsm available? */ /* is there a tsm available? */
if (status)
status = tsm_transaction_available();
if (status)
{
datalink_get_my_address(&my_address);
pdu_len = npdu_encode_apdu(
&Handler_Transmit_Buffer[0],
&dest,
&my_address,
true, // true for confirmed messages
MESSAGE_PRIORITY_NORMAL);
invoke_id = tsm_next_free_invokeID();
// load the data for the encoding
data.object_type = OBJECT_FILE;
data.object_instance = file_instance;
data.access = FILE_STREAM_ACCESS;
data.type.stream.fileStartPosition = fileStartPosition;
status = octetstring_copy(&data.fileData, fileData);
if (status) if (status)
{ status = tsm_transaction_available();
pdu_len += awf_encode_apdu( if (status) {
&Handler_Transmit_Buffer[pdu_len], datalink_get_my_address(&my_address);
invoke_id, pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], &dest, &my_address, true, // true for confirmed messages
&data); MESSAGE_PRIORITY_NORMAL);
/* will the APDU fit the target device?
note: if there is a bottleneck router in between
us and the destination, we won't know unless
we have a way to check for that and update the
max_apdu in the address binding table. */
if ((unsigned)pdu_len <= max_apdu)
{
tsm_set_confirmed_unsegmented_transaction(
invoke_id,
&dest,
&Handler_Transmit_Buffer[0],
pdu_len);
bytes_sent = datalink_send_pdu(
&dest, // destination address
&Handler_Transmit_Buffer[0],
pdu_len); // number of bytes of data
if (bytes_sent <= 0)
fprintf(stderr,"Failed to Send AtomicWriteFile Request (%s)!\n",
strerror(errno));
}
else
fprintf(stderr,"Failed to Send AtomicWriteFile Request "
"(payload [%d] exceeds destination maximum APDU [%u])!\n",
pdu_len,max_apdu);
}
else
fprintf(stderr,"Failed to Send AtomicWriteFile Request "
"(payload [%d] exceeds octet string capacity)!\n",pdu_len);
}
return invoke_id; invoke_id = tsm_next_free_invokeID();
// load the data for the encoding
data.object_type = OBJECT_FILE;
data.object_instance = file_instance;
data.access = FILE_STREAM_ACCESS;
data.type.stream.fileStartPosition = fileStartPosition;
status = octetstring_copy(&data.fileData, fileData);
if (status) {
pdu_len += awf_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
invoke_id, &data);
/* will the APDU fit the target device?
note: if there is a bottleneck router in between
us and the destination, we won't know unless
we have a way to check for that and update the
max_apdu in the address binding table. */
if ((unsigned) pdu_len <= max_apdu) {
tsm_set_confirmed_unsegmented_transaction(invoke_id,
&dest, &Handler_Transmit_Buffer[0], pdu_len);
bytes_sent = datalink_send_pdu(&dest, // destination address
&Handler_Transmit_Buffer[0], pdu_len); // number of bytes of data
if (bytes_sent <= 0)
fprintf(stderr,
"Failed to Send AtomicWriteFile Request (%s)!\n",
strerror(errno));
} else
fprintf(stderr, "Failed to Send AtomicWriteFile Request "
"(payload [%d] exceeds destination maximum APDU [%u])!\n",
pdu_len, max_apdu);
} else
fprintf(stderr, "Failed to Send AtomicWriteFile Request "
"(payload [%d] exceeds octet string capacity)!\n",
pdu_len);
}
return invoke_id;
} }
static void Send_WhoIs(uint32_t device_id) static void Send_WhoIs(uint32_t device_id)
{ {
int pdu_len = 0; int pdu_len = 0;
BACNET_ADDRESS dest; BACNET_ADDRESS dest;
int bytes_sent = 0; int bytes_sent = 0;
/* Who-Is is a global broadcast */ /* Who-Is is a global broadcast */
datalink_get_broadcast_address(&dest); datalink_get_broadcast_address(&dest);
/* encode the NPDU portion of the packet */ /* encode the NPDU portion of the packet */
pdu_len = npdu_encode_apdu( pdu_len = npdu_encode_apdu(&Handler_Transmit_Buffer[0], &dest, NULL, false, // true for confirmed messages
&Handler_Transmit_Buffer[0], MESSAGE_PRIORITY_NORMAL);
&dest,
NULL,
false, // true for confirmed messages
MESSAGE_PRIORITY_NORMAL);
/* encode the APDU portion of the packet */ /* encode the APDU portion of the packet */
pdu_len += whois_encode_apdu( pdu_len += whois_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
&Handler_Transmit_Buffer[pdu_len], device_id, device_id);
device_id,
device_id);
bytes_sent = datalink_send_pdu( bytes_sent = datalink_send_pdu(&dest, /* destination address */
&dest, /* destination address */ &Handler_Transmit_Buffer[0], pdu_len); /* number of bytes of data */
&Handler_Transmit_Buffer[0], if (bytes_sent <= 0)
pdu_len); /* number of bytes of data */ fprintf(stderr, "Failed to Send Who-Is Request (%s)!\n",
if (bytes_sent <= 0) strerror(errno));
fprintf(stderr,"Failed to Send Who-Is Request (%s)!\n", strerror(errno));
} }
static void LocalIAmHandler( static void LocalIAmHandler(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len, BACNET_ADDRESS * src)
uint16_t service_len,
BACNET_ADDRESS *src)
{ {
int len = 0; int len = 0;
uint32_t device_id = 0; uint32_t device_id = 0;
unsigned max_apdu = 0; unsigned max_apdu = 0;
int segmentation = 0; int segmentation = 0;
uint16_t vendor_id = 0; uint16_t vendor_id = 0;
(void)src; (void) src;
(void)service_len; (void) service_len;
len = iam_decode_service_request( len = iam_decode_service_request(service_request,
service_request, &device_id, &max_apdu, &segmentation, &vendor_id);
&device_id, if (len != -1) {
&max_apdu, address_add(device_id, max_apdu, src);
&segmentation, } else
&vendor_id); fprintf(stderr, "!\n");
if (len != -1)
{
address_add(device_id,
max_apdu,
src);
}
else
fprintf(stderr,"!\n");
return; return;
} }
static void Init_Service_Handlers(void) static void Init_Service_Handlers(void)
{ {
/* we need to handle who-is /* we need to handle who-is
to support dynamic device binding to us */ to support dynamic device binding to us */
apdu_set_unconfirmed_handler( apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS,
SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
handler_who_is); /* handle i-am to support binding to other devices */
/* handle i-am to support binding to other devices */ apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_I_AM,
apdu_set_unconfirmed_handler( LocalIAmHandler);
SERVICE_UNCONFIRMED_I_AM, /* set the handler for all the services we don't implement
LocalIAmHandler); It is required to send the proper reject message... */
/* set the handler for all the services we don't implement apdu_set_unrecognized_service_handler_handler
It is required to send the proper reject message... */ (handler_unrecognized_service);
apdu_set_unrecognized_service_handler_handler( /* we must implement read property - it's required! */
handler_unrecognized_service); apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY,
/* we must implement read property - it's required! */ handler_read_property);
apdu_set_confirmed_handler( /* handle any errors coming back */
SERVICE_CONFIRMED_READ_PROPERTY, apdu_set_error_handler(SERVICE_CONFIRMED_ATOMIC_READ_FILE,
handler_read_property); Atomic_Read_File_Error_Handler);
/* handle any errors coming back */ apdu_set_abort_handler(MyAbortHandler);
apdu_set_error_handler( apdu_set_reject_handler(MyRejectHandler);
SERVICE_CONFIRMED_ATOMIC_READ_FILE,
Atomic_Read_File_Error_Handler);
apdu_set_abort_handler(
MyAbortHandler);
apdu_set_reject_handler(
MyRejectHandler);
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
BACNET_ADDRESS src = {0}; // address where message came from BACNET_ADDRESS src = { 0 }; // address where message came from
uint16_t pdu_len = 0; uint16_t pdu_len = 0;
unsigned timeout = 100; // milliseconds unsigned timeout = 100; // milliseconds
unsigned max_apdu = 0; unsigned max_apdu = 0;
time_t elapsed_seconds = 0; time_t elapsed_seconds = 0;
time_t last_seconds = 0; time_t last_seconds = 0;
time_t current_seconds = 0; time_t current_seconds = 0;
time_t timeout_seconds = 0; time_t timeout_seconds = 0;
int fileStartPosition = 0; int fileStartPosition = 0;
unsigned requestedOctetCount = 0; unsigned requestedOctetCount = 0;
uint8_t invoke_id = 0; uint8_t invoke_id = 0;
bool found = false; bool found = false;
uint16_t my_max_apdu = 0; uint16_t my_max_apdu = 0;
FILE *pFile = NULL; FILE *pFile = NULL;
static BACNET_OCTET_STRING fileData; static BACNET_OCTET_STRING fileData;
size_t len = 0; size_t len = 0;
if (argc < 4) if (argc < 4) {
{ /* FIXME: what about access method - record or stream? */
/* FIXME: what about access method - record or stream? */ printf("%s device-instance file-instance local-name\r\n",
printf("%s device-instance file-instance local-name\r\n", filename_remove_path(argv[0]));
filename_remove_path(argv[0])); return 0;
return 0;
}
/* decode the command line parameters */
Target_Device_Object_Instance = strtol(argv[1],NULL,0);
Target_File_Object_Instance = strtol(argv[2],NULL,0);
Local_File_Name = argv[3];
if (Target_Device_Object_Instance >= BACNET_MAX_INSTANCE)
{
fprintf(stderr,"device-instance=%u - it must be less than %u\r\n",
Target_Device_Object_Instance,BACNET_MAX_INSTANCE);
return 1;
}
if (Target_File_Object_Instance >= BACNET_MAX_INSTANCE)
{
fprintf(stderr,"file-instance=%u - it must be less than %u\r\n",
Target_File_Object_Instance,BACNET_MAX_INSTANCE+1);
return 1;
}
/* setup my info */
Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE);
address_init();
Init_Service_Handlers();
/* configure standard BACnet/IP port */
bip_set_interface("eth0"); /* for linux */
bip_set_port(0xBAC0);
if (!bip_init())
return 1;
/* configure the timeout values */
last_seconds = time(NULL);
timeout_seconds = (Device_APDU_Timeout() / 1000) *
Device_Number_Of_APDU_Retries();
/* try to bind with the device */
Send_WhoIs(Target_Device_Object_Instance);
/* loop forever */
for (;;)
{
/* increment timer - exit if timed out */
current_seconds = time(NULL);
/* returns 0 bytes on timeout */
pdu_len = bip_receive(
&src,
&Rx_Buf[0],
MAX_MPDU,
timeout);
/* process */
if (pdu_len)
{
npdu_handler(
&src,
&Rx_Buf[0],
pdu_len);
} }
/* at least one second has passed */ /* decode the command line parameters */
if (current_seconds != last_seconds) Target_Device_Object_Instance = strtol(argv[1], NULL, 0);
tsm_timer_milliseconds(((current_seconds - last_seconds) * 1000)); Target_File_Object_Instance = strtol(argv[2], NULL, 0);
if (End_Of_File_Detected || Error_Detected) Local_File_Name = argv[3];
{ if (Target_Device_Object_Instance >= BACNET_MAX_INSTANCE) {
printf("\r\n"); fprintf(stderr, "device-instance=%u - it must be less than %u\r\n",
break; Target_Device_Object_Instance, BACNET_MAX_INSTANCE);
return 1;
} }
if (I_Am_Request) if (Target_File_Object_Instance >= BACNET_MAX_INSTANCE) {
{ fprintf(stderr, "file-instance=%u - it must be less than %u\r\n",
I_Am_Request = false; Target_File_Object_Instance, BACNET_MAX_INSTANCE + 1);
iam_send(&Handler_Transmit_Buffer[0]); return 1;
} }
else /* setup my info */
{ Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE);
/* wait until the device is bound, or timeout and quit */ address_init();
found = address_bind_request( Init_Service_Handlers();
Target_Device_Object_Instance, /* configure standard BACnet/IP port */
&max_apdu, bip_set_interface("eth0"); /* for linux */
&Target_Address); bip_set_port(0xBAC0);
if (found) if (!bip_init())
{ return 1;
/* calculate the smaller of our APDU size or theirs /* configure the timeout values */
and remove the overhead of the APDU (varies depending on size). last_seconds = time(NULL);
note: we could fail if there is a bottle neck (router) timeout_seconds = (Device_APDU_Timeout() / 1000) *
and smaller MPDU in betweeen. */ Device_Number_Of_APDU_Retries();
if (max_apdu < MAX_APDU) /* try to bind with the device */
my_max_apdu = max_apdu; Send_WhoIs(Target_Device_Object_Instance);
else /* loop forever */
my_max_apdu = MAX_APDU; for (;;) {
/* Typical sizes are 50, 128, 206, 480, 1024, and 1476 octets */
if (my_max_apdu <= 50)
requestedOctetCount = my_max_apdu - 16;
else if (my_max_apdu <= 480)
requestedOctetCount = my_max_apdu - 32;
else if (my_max_apdu <= 1476)
requestedOctetCount = my_max_apdu - 64;
else
requestedOctetCount = my_max_apdu / 2;
/* has the previous invoke id expired or returned?
note: invoke ID = 0 is invalid, so it will be idle */
if ((invoke_id == 0) || tsm_invoke_id_free(invoke_id))
{
if (invoke_id != 0)
fileStartPosition += requestedOctetCount;
/* we'll read the file in chunks
less than max_apdu to keep unsegmented */
pFile = fopen(Local_File_Name,"rb");
if (pFile)
{
(void)fseek(pFile,
fileStartPosition,
SEEK_SET);
len = fread(octetstring_value(&fileData), 1,
requestedOctetCount, pFile);
if (len < requestedOctetCount)
End_Of_File_Detected = true;
octetstring_truncate(&fileData,len);
fclose(pFile);
}
else
End_Of_File_Detected = true;
printf("\rSending %d bytes",(fileStartPosition+len));
invoke_id = Send_Atomic_Write_File_Stream(
Target_Device_Object_Instance,
Target_File_Object_Instance,
fileStartPosition,
&fileData);
Current_Invoke_ID = invoke_id;
}
}
else
{
/* increment timer - exit if timed out */ /* increment timer - exit if timed out */
elapsed_seconds += (current_seconds - last_seconds); current_seconds = time(NULL);
if (elapsed_seconds > timeout_seconds)
break;
}
}
/* keep track of time for next check */
last_seconds = current_seconds;
}
return 0; /* returns 0 bytes on timeout */
pdu_len = bip_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout);
/* process */
if (pdu_len) {
npdu_handler(&src, &Rx_Buf[0], pdu_len);
}
/* at least one second has passed */
if (current_seconds != last_seconds)
tsm_timer_milliseconds(((current_seconds -
last_seconds) * 1000));
if (End_Of_File_Detected || Error_Detected) {
printf("\r\n");
break;
}
if (I_Am_Request) {
I_Am_Request = false;
iam_send(&Handler_Transmit_Buffer[0]);
} else {
/* wait until the device is bound, or timeout and quit */
found = address_bind_request(Target_Device_Object_Instance,
&max_apdu, &Target_Address);
if (found) {
/* calculate the smaller of our APDU size or theirs
and remove the overhead of the APDU (varies depending on size).
note: we could fail if there is a bottle neck (router)
and smaller MPDU in betweeen. */
if (max_apdu < MAX_APDU)
my_max_apdu = max_apdu;
else
my_max_apdu = MAX_APDU;
/* Typical sizes are 50, 128, 206, 480, 1024, and 1476 octets */
if (my_max_apdu <= 50)
requestedOctetCount = my_max_apdu - 16;
else if (my_max_apdu <= 480)
requestedOctetCount = my_max_apdu - 32;
else if (my_max_apdu <= 1476)
requestedOctetCount = my_max_apdu - 64;
else
requestedOctetCount = my_max_apdu / 2;
/* has the previous invoke id expired or returned?
note: invoke ID = 0 is invalid, so it will be idle */
if ((invoke_id == 0) || tsm_invoke_id_free(invoke_id)) {
if (invoke_id != 0)
fileStartPosition += requestedOctetCount;
/* we'll read the file in chunks
less than max_apdu to keep unsegmented */
pFile = fopen(Local_File_Name, "rb");
if (pFile) {
(void) fseek(pFile, fileStartPosition, SEEK_SET);
len = fread(octetstring_value(&fileData), 1,
requestedOctetCount, pFile);
if (len < requestedOctetCount)
End_Of_File_Detected = true;
octetstring_truncate(&fileData, len);
fclose(pFile);
} else
End_Of_File_Detected = true;
printf("\rSending %d bytes",
(fileStartPosition + len));
invoke_id =
Send_Atomic_Write_File_Stream
(Target_Device_Object_Instance,
Target_File_Object_Instance, fileStartPosition,
&fileData);
Current_Invoke_ID = invoke_id;
}
} else {
/* increment timer - exit if timed out */
elapsed_seconds += (current_seconds - last_seconds);
if (elapsed_seconds > timeout_seconds)
break;
}
}
/* keep track of time for next check */
last_seconds = current_seconds;
}
return 0;
} }
+253 -295
View File
@@ -28,7 +28,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h> /* for time */ #include <time.h> /* for time */
#include <errno.h> #include <errno.h>
#include "bactext.h" #include "bactext.h"
#include "iam.h" #include "iam.h"
@@ -50,7 +50,7 @@
#include "txbuf.h" #include "txbuf.h"
// buffer used for receive // buffer used for receive
static uint8_t Rx_Buf[MAX_MPDU] = {0}; static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
/* global variables used in this file */ /* global variables used in this file */
static uint32_t Target_Device_Object_Instance = BACNET_MAX_INSTANCE; static uint32_t Target_Device_Object_Instance = BACNET_MAX_INSTANCE;
@@ -59,326 +59,284 @@ static BACNET_OBJECT_TYPE Target_Object_Type = OBJECT_ANALOG_INPUT;
static BACNET_PROPERTY_ID Target_Object_Property = PROP_ACKED_TRANSITIONS; static BACNET_PROPERTY_ID Target_Object_Property = PROP_ACKED_TRANSITIONS;
/* array index value or BACNET_ARRAY_ALL */ /* array index value or BACNET_ARRAY_ALL */
static int32_t Target_Object_Property_Index = BACNET_ARRAY_ALL; static int32_t Target_Object_Property_Index = BACNET_ARRAY_ALL;
static BACNET_APPLICATION_TAG Target_Object_Property_Tag = BACNET_APPLICATION_TAG_NULL; static BACNET_APPLICATION_TAG Target_Object_Property_Tag =
static BACNET_APPLICATION_DATA_VALUE Target_Object_Property_Value = {0}; BACNET_APPLICATION_TAG_NULL;
static BACNET_APPLICATION_DATA_VALUE Target_Object_Property_Value = { 0 };
/* 0 if not set, 1..16 if set */ /* 0 if not set, 1..16 if set */
static uint8_t Target_Object_Property_Priority = 0; static uint8_t Target_Object_Property_Priority = 0;
static BACNET_ADDRESS Target_Address; static BACNET_ADDRESS Target_Address;
static bool Error_Detected = false; static bool Error_Detected = false;
static void MyErrorHandler( static void MyErrorHandler(BACNET_ADDRESS * src,
BACNET_ADDRESS *src, uint8_t invoke_id,
uint8_t invoke_id, BACNET_ERROR_CLASS error_class, BACNET_ERROR_CODE error_code)
BACNET_ERROR_CLASS error_class,
BACNET_ERROR_CODE error_code)
{ {
/* FIXME: verify src and invoke id */ /* FIXME: verify src and invoke id */
(void)src; (void) src;
(void)invoke_id; (void) invoke_id;
printf("\r\nBACnet Error!\r\n"); printf("\r\nBACnet Error!\r\n");
printf("Error Class: %s\r\n", printf("Error Class: %s\r\n", bactext_error_class_name(error_class));
bactext_error_class_name(error_class)); printf("Error Code: %s\r\n", bactext_error_code_name(error_code));
printf("Error Code: %s\r\n", Error_Detected = true;
bactext_error_code_name(error_code));
Error_Detected = true;
} }
void MyAbortHandler( void MyAbortHandler(BACNET_ADDRESS * src,
BACNET_ADDRESS *src, uint8_t invoke_id, uint8_t abort_reason)
uint8_t invoke_id,
uint8_t abort_reason)
{ {
/* FIXME: verify src and invoke id */ /* FIXME: verify src and invoke id */
(void)src; (void) src;
(void)invoke_id; (void) invoke_id;
printf("\r\nBACnet Abort!\r\n"); printf("\r\nBACnet Abort!\r\n");
printf("Abort Reason: %s\r\n", printf("Abort Reason: %s\r\n",
bactext_abort_reason_name(abort_reason)); bactext_abort_reason_name(abort_reason));
Error_Detected = true; Error_Detected = true;
} }
void MyRejectHandler( void MyRejectHandler(BACNET_ADDRESS * src,
BACNET_ADDRESS *src, uint8_t invoke_id, uint8_t reject_reason)
uint8_t invoke_id,
uint8_t reject_reason)
{ {
/* FIXME: verify src and invoke id */ /* FIXME: verify src and invoke id */
(void)src; (void) src;
(void)invoke_id; (void) invoke_id;
printf("\r\nBACnet Reject!\r\n"); printf("\r\nBACnet Reject!\r\n");
printf("Reject Reason: %s\r\n", printf("Reject Reason: %s\r\n",
bactext_reject_reason_name(reject_reason)); bactext_reject_reason_name(reject_reason));
Error_Detected = true; Error_Detected = true;
} }
void MyWritePropertySimpleAckHandler( void MyWritePropertySimpleAckHandler(BACNET_ADDRESS * src,
BACNET_ADDRESS *src, uint8_t invoke_id)
uint8_t invoke_id)
{ {
(void)src; (void) src;
(void)invoke_id; (void) invoke_id;
printf("\r\nWriteProperty Acknowledged!\r\n"); printf("\r\nWriteProperty Acknowledged!\r\n");
} }
static void Init_Service_Handlers(void) static void Init_Service_Handlers(void)
{ {
/* we need to handle who-is /* we need to handle who-is
to support dynamic device binding to us */ to support dynamic device binding to us */
apdu_set_unconfirmed_handler( apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS,
SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
handler_who_is); /* handle i-am to support binding to other devices */
/* handle i-am to support binding to other devices */ apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_I_AM,
apdu_set_unconfirmed_handler( handler_i_am_bind);
SERVICE_UNCONFIRMED_I_AM, /* set the handler for all the services we don't implement
handler_i_am_bind); It is required to send the proper reject message... */
/* set the handler for all the services we don't implement apdu_set_unrecognized_service_handler_handler
It is required to send the proper reject message... */ (handler_unrecognized_service);
apdu_set_unrecognized_service_handler_handler( /* we must implement read property - it's required! */
handler_unrecognized_service); apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY,
/* we must implement read property - it's required! */ handler_read_property);
apdu_set_confirmed_handler( /* handle the ack coming back */
SERVICE_CONFIRMED_READ_PROPERTY, apdu_set_confirmed_simple_ack_handler(SERVICE_CONFIRMED_WRITE_PROPERTY,
handler_read_property); MyWritePropertySimpleAckHandler);
/* handle the ack coming back */ /* handle any errors coming back */
apdu_set_confirmed_simple_ack_handler( apdu_set_error_handler(SERVICE_CONFIRMED_WRITE_PROPERTY,
SERVICE_CONFIRMED_WRITE_PROPERTY, MyErrorHandler);
MyWritePropertySimpleAckHandler); apdu_set_abort_handler(MyAbortHandler);
/* handle any errors coming back */ apdu_set_reject_handler(MyRejectHandler);
apdu_set_error_handler(
SERVICE_CONFIRMED_WRITE_PROPERTY,
MyErrorHandler);
apdu_set_abort_handler(
MyAbortHandler);
apdu_set_reject_handler(
MyRejectHandler);
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
BACNET_ADDRESS src = {0}; // address where message came from BACNET_ADDRESS src = { 0 }; // address where message came from
uint16_t pdu_len = 0; uint16_t pdu_len = 0;
unsigned timeout = 100; // milliseconds unsigned timeout = 100; // milliseconds
unsigned max_apdu = 0; unsigned max_apdu = 0;
time_t elapsed_seconds = 0; time_t elapsed_seconds = 0;
time_t last_seconds = 0; time_t last_seconds = 0;
time_t current_seconds = 0; time_t current_seconds = 0;
time_t timeout_seconds = 0; time_t timeout_seconds = 0;
uint8_t invoke_id = 0; uint8_t invoke_id = 0;
bool found = false; bool found = false;
char *value_string = NULL; char *value_string = NULL;
bool status = false; bool status = false;
if (argc < 7) if (argc < 7) {
{ /* note: priority 16 and 0 should produce the same end results... */
/* note: priority 16 and 0 should produce the same end results... */ printf("Usage: %s device-instance object-type object-instance "
printf("Usage: %s device-instance object-type object-instance " "property tag value [priority] [index]\r\n"
"property tag value [priority] [index]\r\n" "\r\n"
"\r\n" "device-instance:\r\n"
"device-instance:\r\n" "BACnet Device Object Instance number that you are trying to\r\n"
"BACnet Device Object Instance number that you are trying to\r\n" "communicate to. This number will be used to try and bind with\r\n"
"communicate to. This number will be used to try and bind with\r\n" "the device using Who-Is and I-Am services. For example, if you were\r\n"
"the device using Who-Is and I-Am services. For example, if you were\r\n" "writing to Device Object 123, the device-instance would be 123.\r\n"
"writing to Device Object 123, the device-instance would be 123.\r\n" "\r\n"
"\r\n" "object-type:\r\n"
"object-type:\r\n" "The object type is the integer value of the enumeration\r\n"
"The object type is the integer value of the enumeration\r\n" "BACNET_OBJECT_TYPE in bacenum.h. It is the object that you are\r\n"
"BACNET_OBJECT_TYPE in bacenum.h. It is the object that you are\r\n" "writing to. For example if you were writing to Analog Output 2, \r\n"
"writing to. For example if you were writing to Analog Output 2, \r\n" "the object-type would be 1.\r\n"
"the object-type would be 1.\r\n" "\r\n"
"\r\n" "object-instance:\r\n"
"object-instance:\r\n" "This is the object instance number of the object that you are \r\n"
"This is the object instance number of the object that you are \r\n" "writing to. For example, if you were writing to Analog Output 2, \r\n"
"writing to. For example, if you were writing to Analog Output 2, \r\n" "the object-instance would be 2.\r\n"
"the object-instance would be 2.\r\n" "\r\n"
"\r\n" "property:\r\n"
"property:\r\n" "The property is an integer value of the enumeration \r\n"
"The property is an integer value of the enumeration \r\n" "BACNET_PROPERTY_ID in bacenum.h. It is the property you are \r\n"
"BACNET_PROPERTY_ID in bacenum.h. It is the property you are \r\n" "writing to. For example, if you were writing to the Present Value\r\n"
"writing to. For example, if you were writing to the Present Value\r\n" "property, you would use 85 as the property.\r\n"
"property, you would use 85 as the property.\r\n" "\r\n"
"\r\n" "tag:\r\n"
"tag:\r\n" "Tag is the integer value of the enumeration BACNET_APPLICATION_TAG \r\n"
"Tag is the integer value of the enumeration BACNET_APPLICATION_TAG \r\n" "in bacenum.h. It is the data type of the value that you are\r\n"
"in bacenum.h. It is the data type of the value that you are\r\n" "writing. For example, if you were writing a REAL value, you would \r\n"
"writing. For example, if you were writing a REAL value, you would \r\n" "use a tag of 4."
"use a tag of 4." "\r\n"
"\r\n" "value:\r\n"
"value:\r\n" "The value is an ASCII representation of some type of data that you\r\n"
"The value is an ASCII representation of some type of data that you\r\n" "are writing. It is encoded using the tag information provided. For\r\n"
"are writing. It is encoded using the tag information provided. For\r\n" "example, if you were writing a REAL value of 100.0, you would use \r\n"
"example, if you were writing a REAL value of 100.0, you would use \r\n" "100.0 as the value.\r\n"
"100.0 as the value.\r\n" "\r\n"
"\r\n" "[priority]:\r\n"
"[priority]:\r\n" "This optional parameter is used for setting the priority of the\r\n"
"This optional parameter is used for setting the priority of the\r\n" "write. If no priority is given, none is sent, and the BACnet \r\n"
"write. If no priority is given, none is sent, and the BACnet \r\n" "standard requires that the value is written at the lowest \r\n"
"standard requires that the value is written at the lowest \r\n" "priority (16) if the object property supports priorities.\r\n"
"priority (16) if the object property supports priorities.\r\n" "\r\n"
"\r\n" "[index]\r\n"
"[index]\r\n" "This optional integer parameter is the index number of an array.\r\n"
"This optional integer parameter is the index number of an array.\r\n" "If the property is an array, individual elements can be written\r\n"
"If the property is an array, individual elements can be written\r\n" "to if supported.\r\n"
"to if supported.\r\n" "\r\n"
"\r\n" "Here is a brief overview of BACnet property and tags:\r\n"
"Here is a brief overview of BACnet property and tags:\r\n" "Certain properties are expected to be written with certain \r\n"
"Certain properties are expected to be written with certain \r\n" "application tags, so you probably need to know which ones to use\r\n"
"application tags, so you probably need to know which ones to use\r\n" "with each property of each object. It is almost safe to say that\r\n"
"with each property of each object. It is almost safe to say that\r\n" "given a property and an object and a table, the tag could be looked\r\n"
"given a property and an object and a table, the tag could be looked\r\n" "up automatically. There may be a few exceptions to this, such as\r\n"
"up automatically. There may be a few exceptions to this, such as\r\n" "the Any property type in the schedule object and the Present Value\r\n"
"the Any property type in the schedule object and the Present Value\r\n" "accepting REAL, BOOLEAN, NULL, etc. Perhaps it would be simpler for\r\n"
"accepting REAL, BOOLEAN, NULL, etc. Perhaps it would be simpler for\r\n" "the demo to use this kind of table - but I also wanted to be able\r\n"
"the demo to use this kind of table - but I also wanted to be able\r\n" "to do negative testing by passing the wrong tag and have the server\r\n"
"to do negative testing by passing the wrong tag and have the server\r\n" "return a reject message.\r\n"
"return a reject message.\r\n" "\r\n"
"\r\n" "Example:\r\n"
"Example:\r\n" "If you want send a 100 to the Present-Value in the Analog Output\r\n"
"If you want send a 100 to the Present-Value in the Analog Output\r\n" "at priority 16, you could send the following command:\r\n"
"at priority 16, you could send the following command:\r\n" "%s 123 1 0 85 4 100\r\n"
"%s 123 1 0 85 4 100\r\n" "You could also send a relinquish command:\r\n"
"You could also send a relinquish command:\r\n" "%s 123 1 0 85 0 0\r\n",
"%s 123 1 0 85 0 0\r\n", filename_remove_path(argv[0]),
filename_remove_path(argv[0]), filename_remove_path(argv[0]), filename_remove_path(argv[0]));
filename_remove_path(argv[0]), return 0;
filename_remove_path(argv[0]));
return 0;
}
/* decode the command line parameters */
Target_Device_Object_Instance = strtol(argv[1],NULL,0);
Target_Object_Type = strtol(argv[2],NULL,0);
Target_Object_Instance = strtol(argv[3],NULL,0);
Target_Object_Property = strtol(argv[4],NULL,0);
Target_Object_Property_Tag = strtol(argv[5],NULL,0);
value_string = argv[6];
/* optional priority */
if (argc > 7)
Target_Object_Property_Priority = strtol(argv[7],NULL,0);
/* optional index */
if (argc > 8)
Target_Object_Property_Index = strtol(argv[8],NULL,0);
if (Target_Device_Object_Instance >= BACNET_MAX_INSTANCE)
{
fprintf(stderr,"device-instance=%u - it must be less than %u\r\n",
Target_Device_Object_Instance,BACNET_MAX_INSTANCE);
return 1;
}
if (Target_Object_Type > MAX_BACNET_OBJECT_TYPE)
{
fprintf(stderr,"object-type=%u - it must be less than %u\r\n",
Target_Object_Type,MAX_BACNET_OBJECT_TYPE+1);
return 1;
}
if (Target_Object_Instance > BACNET_MAX_INSTANCE)
{
fprintf(stderr,"object-instance=%u - it must be less than %u\r\n",
Target_Object_Instance,BACNET_MAX_INSTANCE+1);
return 1;
}
if (Target_Object_Property > MAX_BACNET_PROPERTY_ID)
{
fprintf(stderr,"object-type=%u - it must be less than %u\r\n",
Target_Object_Property,MAX_BACNET_PROPERTY_ID+1);
return 1;
}
if (Target_Object_Property_Tag >= MAX_BACNET_APPLICATION_TAG)
{
fprintf(stderr,"tag=%u - it must be less than %u\r\n",
Target_Object_Property_Tag,MAX_BACNET_APPLICATION_TAG);
return 1;
}
status = bacapp_parse_application_data(
Target_Object_Property_Tag,
value_string,
&Target_Object_Property_Value);
if (!status)
{
/* FIXME: show the expected entry format for the tag */
fprintf(stderr,"unable to parse the tag value\r\n");
return 1;
}
/* setup my info */
Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE);
address_init();
Init_Service_Handlers();
/* configure standard BACnet/IP port */
bip_set_interface("eth0"); /* for linux */
bip_set_port(0xBAC0);
if (!bip_init())
return 1;
/* configure the timeout values */
last_seconds = time(NULL);
timeout_seconds = (Device_APDU_Timeout() / 1000) *
Device_Number_Of_APDU_Retries();
/* try to bind with the device */
Send_WhoIs(Target_Device_Object_Instance,Target_Device_Object_Instance);
/* loop forever */
for (;;)
{
/* increment timer - exit if timed out */
current_seconds = time(NULL);
/* returns 0 bytes on timeout */
pdu_len = bip_receive(
&src,
&Rx_Buf[0],
MAX_MPDU,
timeout);
/* process */
if (pdu_len)
{
npdu_handler(
&src,
&Rx_Buf[0],
pdu_len);
} }
/* at least one second has passed */ /* decode the command line parameters */
if (current_seconds != last_seconds) Target_Device_Object_Instance = strtol(argv[1], NULL, 0);
tsm_timer_milliseconds(((current_seconds - last_seconds) * 1000)); Target_Object_Type = strtol(argv[2], NULL, 0);
if (Error_Detected) Target_Object_Instance = strtol(argv[3], NULL, 0);
break; Target_Object_Property = strtol(argv[4], NULL, 0);
if (I_Am_Request) Target_Object_Property_Tag = strtol(argv[5], NULL, 0);
{ value_string = argv[6];
I_Am_Request = false; /* optional priority */
iam_send(&Handler_Transmit_Buffer[0]); if (argc > 7)
Target_Object_Property_Priority = strtol(argv[7], NULL, 0);
/* optional index */
if (argc > 8)
Target_Object_Property_Index = strtol(argv[8], NULL, 0);
if (Target_Device_Object_Instance >= BACNET_MAX_INSTANCE) {
fprintf(stderr, "device-instance=%u - it must be less than %u\r\n",
Target_Device_Object_Instance, BACNET_MAX_INSTANCE);
return 1;
} }
else if (Target_Object_Type > MAX_BACNET_OBJECT_TYPE) {
{ fprintf(stderr, "object-type=%u - it must be less than %u\r\n",
/* wait until the device is bound, or timeout and quit */ Target_Object_Type, MAX_BACNET_OBJECT_TYPE + 1);
found = address_bind_request( return 1;
Target_Device_Object_Instance, }
&max_apdu, if (Target_Object_Instance > BACNET_MAX_INSTANCE) {
&Target_Address); fprintf(stderr, "object-instance=%u - it must be less than %u\r\n",
if (found) Target_Object_Instance, BACNET_MAX_INSTANCE + 1);
{ return 1;
if (invoke_id == 0) }
{ if (Target_Object_Property > MAX_BACNET_PROPERTY_ID) {
invoke_id = Send_Write_Property_Request( fprintf(stderr, "object-type=%u - it must be less than %u\r\n",
Target_Device_Object_Instance, Target_Object_Property, MAX_BACNET_PROPERTY_ID + 1);
Target_Object_Type, return 1;
Target_Object_Instance, }
Target_Object_Property, if (Target_Object_Property_Tag >= MAX_BACNET_APPLICATION_TAG) {
&Target_Object_Property_Value, fprintf(stderr, "tag=%u - it must be less than %u\r\n",
Target_Object_Property_Priority, Target_Object_Property_Tag, MAX_BACNET_APPLICATION_TAG);
Target_Object_Property_Index); return 1;
} }
else if (tsm_invoke_id_free(invoke_id)) status = bacapp_parse_application_data(Target_Object_Property_Tag,
break; value_string, &Target_Object_Property_Value);
} if (!status) {
else /* FIXME: show the expected entry format for the tag */
{ fprintf(stderr, "unable to parse the tag value\r\n");
return 1;
}
/* setup my info */
Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE);
address_init();
Init_Service_Handlers();
/* configure standard BACnet/IP port */
bip_set_interface("eth0"); /* for linux */
bip_set_port(0xBAC0);
if (!bip_init())
return 1;
/* configure the timeout values */
last_seconds = time(NULL);
timeout_seconds = (Device_APDU_Timeout() / 1000) *
Device_Number_Of_APDU_Retries();
/* try to bind with the device */
Send_WhoIs(Target_Device_Object_Instance,
Target_Device_Object_Instance);
/* loop forever */
for (;;) {
/* increment timer - exit if timed out */ /* increment timer - exit if timed out */
elapsed_seconds += (current_seconds - last_seconds); current_seconds = time(NULL);
if (elapsed_seconds > timeout_seconds)
break;
}
}
/* keep track of time for next check */
last_seconds = current_seconds;
}
return 0; /* returns 0 bytes on timeout */
pdu_len = bip_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout);
/* process */
if (pdu_len) {
npdu_handler(&src, &Rx_Buf[0], pdu_len);
}
/* at least one second has passed */
if (current_seconds != last_seconds)
tsm_timer_milliseconds(((current_seconds -
last_seconds) * 1000));
if (Error_Detected)
break;
if (I_Am_Request) {
I_Am_Request = false;
iam_send(&Handler_Transmit_Buffer[0]);
} else {
/* wait until the device is bound, or timeout and quit */
found = address_bind_request(Target_Device_Object_Instance,
&max_apdu, &Target_Address);
if (found) {
if (invoke_id == 0) {
invoke_id =
Send_Write_Property_Request
(Target_Device_Object_Instance, Target_Object_Type,
Target_Object_Instance, Target_Object_Property,
&Target_Object_Property_Value,
Target_Object_Property_Priority,
Target_Object_Property_Index);
} else if (tsm_invoke_id_free(invoke_id))
break;
} else {
/* increment timer - exit if timed out */
elapsed_seconds += (current_seconds - last_seconds);
if (elapsed_seconds > timeout_seconds)
break;
}
}
/* keep track of time for next check */
last_seconds = current_seconds;
}
return 0;
} }
+3 -1
View File
@@ -6,7 +6,9 @@ Don't use C++-style comments (comments beginning with "//" and running
to the end of the line) for modules that are written in C. The module to the end of the line) for modules that are written in C. The module
may run through C rather than C++ compilers, and not all C compilers may run through C rather than C++ compilers, and not all C compilers
support C++-style comments (GCC does, but IBM's C compiler for AIX, for support C++-style comments (GCC does, but IBM's C compiler for AIX, for
example, doesn't do so by default). example, doesn't do so by default). Note: there is a program
called usr/bin/ccmtcnvt in the liwc package that converts the C++
comments to C comments.
Don't initialize variables in their declaration with non-constant Don't initialize variables in their declaration with non-constant
values. Not all compilers support this. E.g. don't use values. Not all compilers support this. E.g. don't use
+1 -2
View File
@@ -576,8 +576,7 @@ void MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port)
// that is not known to this node. // that is not known to this node.
// FIXME: change this if you add a proprietary type // FIXME: change this if you add a proprietary type
else if /*( */ (mstp_port->FrameType >= else if /*( */ (mstp_port->FrameType >=
FRAME_TYPE_PROPRIETARY_MIN) FRAME_TYPE_PROPRIETARY_MIN) { /*&& */
{ /*&& */
/*(FrameType <= FRAME_TYPE_PROPRIETARY_MAX)) */ /*(FrameType <= FRAME_TYPE_PROPRIETARY_MAX)) */
/* unnecessary if FrameType is uint8_t with max of 255 */ /* unnecessary if FrameType is uint8_t with max of 255 */
// an unexpected or unwanted frame was received. // an unexpected or unwanted frame was received.
+158 -182
View File
@@ -81,206 +81,192 @@ clockp Clock Prescaler DataRate
bool arcnet_valid(void) bool arcnet_valid(void)
{ {
return (ARCNET_Sock_FD >= 0); return (ARCNET_Sock_FD >= 0);
} }
void arcnet_cleanup(void) void arcnet_cleanup(void)
{ {
if (arcnet_valid()) if (arcnet_valid())
close(ARCNET_Sock_FD); close(ARCNET_Sock_FD);
ARCNET_Sock_FD = -1; ARCNET_Sock_FD = -1;
return; 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; 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; int uid = 0;
/* check to see if we are being run as root */ /* check to see if we are being run as root */
uid = getuid(); uid = getuid();
if (uid != 0) { if (uid != 0) {
fprintf(stderr, fprintf(stderr,
"arcnet: Unable to open an af_packet socket. " "arcnet: Unable to open an af_packet socket. "
"Try running with root priveleges.\n"); "Try running with root priveleges.\n");
return sock_fd; return sock_fd;
} }
fprintf(stderr,"arcnet: opening \"%s\"\n",interface_name); fprintf(stderr, "arcnet: opening \"%s\"\n", interface_name);
// note: on some systems you may have to add or enable in // note: on some systems you may have to add or enable in
// modules.conf (or in modutils/alias on Debian with update-modules) // modules.conf (or in modutils/alias on Debian with update-modules)
// alias net-pf-17 af_packet // alias net-pf-17 af_packet
// Then follow it by: # modprobe af_packet // Then follow it by: # modprobe af_packet
if ((sock_fd = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ALL))) < 0) if ((sock_fd = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ALL))) < 0) {
{ /* Error occured */
/* Error occured */ fprintf(stderr,
fprintf(stderr, "arcnet: Error opening socket: %s\n", strerror(errno));
"arcnet: Error opening socket: %s\n", fprintf(stderr,
strerror(errno)); "You might need to add the following to modules.conf\n"
fprintf(stderr, "(or in /etc/modutils/alias on Debian with update-modules):\n"
"You might need to add the following to modules.conf\n" "alias net-pf-17 af_packet\n"
"(or in /etc/modutils/alias on Debian with update-modules):\n" "Also, add af_packet to /etc/modules.\n"
"alias net-pf-17 af_packet\n" "Then follow it by:\n" "# modprobe af_packet\n");
"Also, add af_packet to /etc/modules.\n" exit(-1);
"Then follow it by:\n" }
"# modprobe af_packet\n");
exit(-1);
}
if (ARCNET_Sock_FD >= 0) if (ARCNET_Sock_FD >= 0) {
{ /* Bind the socket to an interface name so we only get packets from it */
/* Bind the socket to an interface name so we only get packets from it */ ARCNET_Socket_Address.sa_family = ARPHRD_ARCNET;
//ARCNET_Socket_Address.sa_family = PF_INET;
/* Clear the memory before copying */
memset(ARCNET_Socket_Address.sa_data, '\0',
sizeof(ARCNET_Socket_Address.sa_data));
/* Strcpy the interface name into the address */
strncpy(ARCNET_Socket_Address.sa_data, interface_name,
sizeof(ARCNET_Socket_Address.sa_data) - 1);
fprintf(stderr, "arcnet: binding \"%s\"\n",
ARCNET_Socket_Address.sa_data);
if (bind(sock_fd, &ARCNET_Socket_Address,
sizeof(ARCNET_Socket_Address)) != 0) {
/* Bind problem, close socket and return */
fprintf(stderr,
"arcnet: Unable to bind 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"
"alias net-pf-17 af_packet\n"
"Also, add af_packet to /etc/modules.\n"
"Then follow it by:\n" "# modprobe af_packet\n");
/* Close the socket */
close(sock_fd);
exit(-1);
}
}
strncpy(ifr.ifr_name, interface_name, sizeof(ifr.ifr_name));
rv = ioctl(sock_fd, SIOCGIFHWADDR, &ifr);
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; ARCNET_Socket_Address.sa_family = ARPHRD_ARCNET;
//ARCNET_Socket_Address.sa_family = PF_INET; //ARCNET_Socket_Address.sa_family = PF_INET;
/* Clear the memory before copying */ /* Clear the memory before copying */
memset(ARCNET_Socket_Address.sa_data, '\0', memset(ARCNET_Socket_Address.sa_data, '\0',
sizeof(ARCNET_Socket_Address.sa_data)); sizeof(ARCNET_Socket_Address.sa_data));
/* Strcpy the interface name into the address */ /* Strcpy the interface name into the address */
strncpy(ARCNET_Socket_Address.sa_data, interface_name, strncpy(ARCNET_Socket_Address.sa_data, interface_name,
sizeof(ARCNET_Socket_Address.sa_data)-1); sizeof(ARCNET_Socket_Address.sa_data) - 1);
fprintf(stderr,"arcnet: binding \"%s\"\n",ARCNET_Socket_Address.sa_data); fprintf(stderr, "arcnet: MAC=%02Xh iface=\"%s\"\n",
if (bind(sock_fd, &ARCNET_Socket_Address, ARCNET_MAC_Address, ARCNET_Socket_Address.sa_data);
sizeof(ARCNET_Socket_Address)) != 0)
{
/* Bind problem, close socket and return */
fprintf(stderr,
"arcnet: Unable to bind 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"
"alias net-pf-17 af_packet\n"
"Also, add af_packet to /etc/modules.\n"
"Then follow it by:\n"
"# modprobe af_packet\n");
/* Close the socket */
close(sock_fd);
exit(-1);
}
}
strncpy(ifr.ifr_name, interface_name, sizeof(ifr.ifr_name));
rv = ioctl(sock_fd, SIOCGIFHWADDR, &ifr);
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;
//ARCNET_Socket_Address.sa_family = PF_INET;
/* Clear the memory before copying */
memset(ARCNET_Socket_Address.sa_data, '\0',
sizeof(ARCNET_Socket_Address.sa_data));
/* Strcpy the interface name into the address */
strncpy(ARCNET_Socket_Address.sa_data, interface_name,
sizeof(ARCNET_Socket_Address.sa_data)-1);
fprintf(stderr,"arcnet: MAC=%02Xh iface=\"%s\"\n",
ARCNET_MAC_Address,
ARCNET_Socket_Address.sa_data);
atexit(arcnet_cleanup); atexit(arcnet_cleanup);
return sock_fd; return sock_fd;
} }
bool arcnet_init(char *interface_name) bool arcnet_init(char *interface_name)
{ {
ARCNET_Sock_FD = arcnet_bind(interface_name); ARCNET_Sock_FD = arcnet_bind(interface_name);
return arcnet_valid(); return arcnet_valid();
} }
/* function to send a packet out the socket */ /* function to send a packet out the socket */
/* returns number of bytes sent on success, negative on failure */ /* returns number of bytes sent on success, negative on failure */
int arcnet_send( int arcnet_send(BACNET_ADDRESS * dest, // destination address
BACNET_ADDRESS *dest, // destination address BACNET_ADDRESS * src, // source address
BACNET_ADDRESS *src, // source address 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
unsigned pdu_len) // number of bytes of data
{ {
int bytes = 0; int bytes = 0;
uint8_t mtu[512] = { 0 }; uint8_t mtu[512] = { 0 };
int mtu_len = 0; int mtu_len = 0;
struct archdr *pkt = (struct archdr *)mtu; struct archdr *pkt = (struct archdr *) mtu;
// don't waste time if the socket is not valid // don't waste time if the socket is not valid
if (ARCNET_Sock_FD < 0) if (ARCNET_Sock_FD < 0) {
{
fprintf(stderr, "arcnet: socket is invalid!\n"); fprintf(stderr, "arcnet: socket is invalid!\n");
return -1; return -1;
} }
/* load destination MAC address */ /* load destination MAC address */
if (dest->mac_len == 1) if (dest->mac_len == 1)
pkt->hard.dest = dest->mac[0]; pkt->hard.dest = dest->mac[0];
else else {
{
fprintf(stderr, "arcnet: invalid destination MAC address!\n"); fprintf(stderr, "arcnet: invalid destination MAC address!\n");
return -2; return -2;
} }
if (src->mac_len == 1) if (src->mac_len == 1)
pkt->hard.source = src->mac[0]; pkt->hard.source = src->mac[0];
else else {
{
fprintf(stderr, "arcnet: invalid source MAC address!\n"); fprintf(stderr, "arcnet: invalid source MAC address!\n");
return -3; return -3;
} }
if ((ARC_HDR_SIZE + pdu_len) > 512) if ((ARC_HDR_SIZE + pdu_len) > 512) {
{
fprintf(stderr, "arcnet: PDU is too big to send!\n"); fprintf(stderr, "arcnet: PDU is too big to send!\n");
return -4; return -4;
} }
/* Logical PDU portion */ /* Logical PDU portion */
pkt->soft.raw[0] = 0xCD; /* SC for BACnet */ pkt->soft.raw[0] = 0xCD; /* SC for BACnet */
pkt->soft.raw[1] = 0x82; /* DSAP for BACnet */ pkt->soft.raw[1] = 0x82; /* DSAP for BACnet */
pkt->soft.raw[2] = 0x82; /* SSAP for BACnet */ pkt->soft.raw[2] = 0x82; /* SSAP for BACnet */
pkt->soft.raw[3] = 0x03; /* Control byte in header */ pkt->soft.raw[3] = 0x03; /* Control byte in header */
memcpy(&pkt->soft.raw[4], pdu, pdu_len); memcpy(&pkt->soft.raw[4], pdu, pdu_len);
/* packet length */ /* packet length */
mtu_len = ARC_HDR_SIZE + 4 /*SC,DSAP,SSAP,LLC*/ + pdu_len; mtu_len = ARC_HDR_SIZE + 4 /*SC,DSAP,SSAP,LLC */ + pdu_len;
/* Send the packet */ /* Send the packet */
bytes = bytes =
sendto(ARCNET_Sock_FD, &mtu, mtu_len, 0, sendto(ARCNET_Sock_FD, &mtu, mtu_len, 0,
(struct sockaddr *) &ARCNET_Socket_Address, (struct sockaddr *) &ARCNET_Socket_Address,
sizeof(ARCNET_Socket_Address)); sizeof(ARCNET_Socket_Address));
/* did it get sent? */ /* did it get sent? */
if (bytes < 0) if (bytes < 0)
fprintf(stderr,"arcnet: Error sending packet: %s\n", fprintf(stderr, "arcnet: Error sending packet: %s\n",
strerror(errno)); strerror(errno));
return bytes; return bytes;
} }
/* function to send a PDU out the socket */ /* function to send a PDU out the socket */
/* returns number of bytes sent on success, negative on failure */ /* returns number of bytes sent on success, negative on failure */
int arcnet_send_pdu( int arcnet_send_pdu(BACNET_ADDRESS * dest, // destination address
BACNET_ADDRESS *dest, // destination address 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
unsigned pdu_len) // number of bytes of data
{ {
BACNET_ADDRESS src = {0}; // source address BACNET_ADDRESS src = { 0 }; // source address
src.mac[0] = ARCNET_MAC_Address; src.mac[0] = ARCNET_MAC_Address;
src.mac_len = 1; src.mac_len = 1;
return arcnet_send(dest, // destination address return arcnet_send(dest, // destination address
&src, // source address &src, // source address
pdu, // any data to be sent - may be null pdu, // any data to be sent - may be null
pdu_len); // number of bytes of data pdu_len); // number of bytes of data
} }
// receives an framed packet // receives an framed packet
// returns the number of octets in the PDU, or zero on failure // returns the number of octets in the PDU, or zero on failure
uint16_t arcnet_receive( uint16_t arcnet_receive(BACNET_ADDRESS * src, // source address
BACNET_ADDRESS *src, // source address uint8_t * pdu, // PDU data
uint8_t *pdu, // PDU data uint16_t max_pdu, // amount of space available in the PDU
uint16_t max_pdu, // amount of space available in the PDU unsigned timeout) // milliseconds to wait for a packet
unsigned timeout) // milliseconds to wait for a packet
{ {
int received_bytes; int received_bytes;
uint8_t buf[512] = {0}; // data uint8_t buf[512] = { 0 }; // data
uint16_t pdu_len = 0; // return value uint16_t pdu_len = 0; // return value
fd_set read_fds; fd_set read_fds;
int max; int max;
struct timeval select_timeout; struct timeval select_timeout;
struct archdr *pkt = (struct archdr *)buf; struct archdr *pkt = (struct archdr *) buf;
/* Make sure the socket is open */ /* Make sure the socket is open */
if (ARCNET_Sock_FD <= 0) if (ARCNET_Sock_FD <= 0)
@@ -289,14 +275,11 @@ uint16_t arcnet_receive(
/* we could just use a non-blocking socket, but that consumes all /* we could just use a non-blocking socket, but that consumes all
the CPU time. We can use a timeout; it is only supported as the CPU time. We can use a timeout; it is only supported as
a select. */ a select. */
if (timeout >= 1000) if (timeout >= 1000) {
{
select_timeout.tv_sec = timeout / 1000; select_timeout.tv_sec = timeout / 1000;
select_timeout.tv_usec = select_timeout.tv_usec =
1000 * (timeout - select_timeout.tv_sec * 1000); 1000 * (timeout - select_timeout.tv_sec * 1000);
} } else {
else
{
select_timeout.tv_sec = 0; select_timeout.tv_sec = 0;
select_timeout.tv_usec = 1000 * timeout; select_timeout.tv_usec = 1000 * timeout;
} }
@@ -315,22 +298,23 @@ uint16_t arcnet_receive(
// using O_NONBLOCK and no data // using O_NONBLOCK and no data
// was immediately available for reading. // was immediately available for reading.
if (errno != EAGAIN) if (errno != EAGAIN)
fprintf(stderr,"ethernet: Read error in receiving packet: %s\n", fprintf(stderr,
"ethernet: Read error in receiving packet: %s\n",
strerror(errno)); strerror(errno));
return 0; return 0;
} }
if (received_bytes == 0) if (received_bytes == 0)
return 0; return 0;
/* printf("arcnet: received %u bytes (offset=%02Xh %02Xh) " /* printf("arcnet: received %u bytes (offset=%02Xh %02Xh) "
"from %02Xh (proto==%02Xh)\n", "from %02Xh (proto==%02Xh)\n",
received_bytes, pkt->offset[0], pkt->offset[1], received_bytes, pkt->offset[0], pkt->offset[1],
pkt->hard.source, pkt->soft.raw[0]); pkt->hard.source, pkt->soft.raw[0]);
*/ */
if (pkt->hard.source == ARCNET_MAC_Address) { if (pkt->hard.source == ARCNET_MAC_Address) {
fprintf(stderr,"arcnet: self sent packet?\n"); fprintf(stderr, "arcnet: self sent packet?\n");
return 0; return 0;
} }
if (pkt->soft.raw[0] != 0xCD) { if (pkt->soft.raw[0] != 0xCD) {
@@ -338,23 +322,20 @@ uint16_t arcnet_receive(
return 0; return 0;
} }
if ((pkt->hard.dest != ARCNET_MAC_Address) && if ((pkt->hard.dest != ARCNET_MAC_Address) &&
(pkt->hard.dest != ARCNET_BROADCAST)) (pkt->hard.dest != ARCNET_BROADCAST)) {
{ fprintf(stderr, "arcnet: This packet is not for us.\n");
fprintf(stderr,"arcnet: This packet is not for us.\n");
return 0; return 0;
} }
if ((pkt->soft.raw[1] != 0x82) || /* DSAP */ if ((pkt->soft.raw[1] != 0x82) || /* DSAP */
(pkt->soft.raw[2] != 0x82) || /* LSAP */ (pkt->soft.raw[2] != 0x82) || /* LSAP */
(pkt->soft.raw[3] != 0x03)) /* LLC Control */ (pkt->soft.raw[3] != 0x03)) { /* LLC Control */
{ fprintf(stderr, "arcnet: BACnet packet has invalid LLC.\n");
fprintf(stderr,"arcnet: BACnet packet has invalid LLC.\n");
return 0; return 0;
} }
/* It must be addressed to us or be a Broadcast */ /* It must be addressed to us or be a Broadcast */
if ((pkt->hard.dest != ARCNET_MAC_Address) && if ((pkt->hard.dest != ARCNET_MAC_Address) &&
(pkt->hard.dest != ARCNET_BROADCAST)) (pkt->hard.dest != ARCNET_BROADCAST)) {
{ fprintf(stderr, "arcnet: This packet is not for us.\n");
fprintf(stderr,"arcnet: This packet is not for us.\n");
return 0; return 0;
} }
/* copy the source address */ /* copy the source address */
@@ -365,47 +346,42 @@ uint16_t arcnet_receive(
pdu_len -= 4 /* SC, DSAP, SSAP, LLC Control */ ; pdu_len -= 4 /* SC, DSAP, SSAP, LLC Control */ ;
// copy the buffer into the PDU // copy the buffer into the PDU
if (pdu_len < max_pdu) if (pdu_len < max_pdu)
memmove(&pdu[0],&pkt->soft.raw[4],pdu_len); memmove(&pdu[0], &pkt->soft.raw[4], pdu_len);
// silently ignore packets that are too large // silently ignore packets that are too large
else else
pdu_len = 0; pdu_len = 0;
return pdu_len; return pdu_len;
} }
void arcnet_get_my_address(BACNET_ADDRESS *my_address) void arcnet_get_my_address(BACNET_ADDRESS * my_address)
{ {
int i = 0; int i = 0;
my_address->mac_len = 1; my_address->mac_len = 1;
my_address->mac[0] = ARCNET_MAC_Address; my_address->mac[0] = ARCNET_MAC_Address;
my_address->net = 0; // local only, no routing my_address->net = 0; // local only, no routing
my_address->len = 0; my_address->len = 0;
for (i = 0; i < MAX_MAC_LEN; i++) for (i = 0; i < MAX_MAC_LEN; i++) {
{ my_address->adr[i] = 0;
my_address->adr[i] = 0;
}
return;
}
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; // len=0 denotes broadcast address
for (i = 0; i < MAX_MAC_LEN; i++)
{
dest->adr[i] = 0;
} }
}
return; return;
} }
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; // len=0 denotes broadcast address
for (i = 0; i < MAX_MAC_LEN; i++) {
dest->adr[i] = 0;
}
}
return;
}
+17 -21
View File
@@ -39,7 +39,8 @@
#include "net.h" #include "net.h"
static int get_local_ifr_ioctl(char *ifname, struct ifreq *ifr, int request) static int get_local_ifr_ioctl(char *ifname, struct ifreq *ifr,
int request)
{ {
int fd; int fd;
int rv; // return value int rv; // return value
@@ -54,16 +55,14 @@ static int get_local_ifr_ioctl(char *ifname, struct ifreq *ifr, int request)
return rv; return rv;
} }
static int get_local_address_ioctl( static int get_local_address_ioctl(char *ifname,
char *ifname, struct in_addr *addr, int request)
struct in_addr *addr,
int request)
{ {
struct ifreq ifr = { {{0}} }; struct ifreq ifr = { {{0}} };
struct sockaddr_in *tcpip_address; struct sockaddr_in *tcpip_address;
int rv; // return value int rv; // return value
rv = get_local_ifr_ioctl(ifname,&ifr,request); rv = get_local_ifr_ioctl(ifname, &ifr, request);
if (rv >= 0) { if (rv >= 0) {
tcpip_address = (struct sockaddr_in *) &ifr.ifr_addr; tcpip_address = (struct sockaddr_in *) &ifr.ifr_addr;
memcpy(addr, &tcpip_address->sin_addr, sizeof(struct in_addr)); memcpy(addr, &tcpip_address->sin_addr, sizeof(struct in_addr));
@@ -80,20 +79,21 @@ void bip_set_interface(char *ifname)
/* setup local address */ /* setup local address */
get_local_address_ioctl(ifname, &local_address, SIOCGIFADDR); get_local_address_ioctl(ifname, &local_address, SIOCGIFADDR);
bip_set_addr(local_address.s_addr); bip_set_addr(local_address.s_addr);
#ifdef BIP_DEBUG #ifdef BIP_DEBUG
fprintf(stderr,"IP Address: %s\n",inet_ntoa(local_address)); fprintf(stderr, "IP Address: %s\n", inet_ntoa(local_address));
#endif #endif
/* setup local broadcast address */ /* setup local broadcast address */
get_local_address_ioctl(ifname, &broadcast_address, SIOCGIFBRDADDR); get_local_address_ioctl(ifname, &broadcast_address, SIOCGIFBRDADDR);
bip_set_broadcast_addr(broadcast_address.s_addr); bip_set_broadcast_addr(broadcast_address.s_addr);
#ifdef BIP_DEBUG #ifdef BIP_DEBUG
fprintf(stderr,"Broadcast Address: %s\n",inet_ntoa(broadcast_address)); fprintf(stderr, "Broadcast Address: %s\n",
#endif inet_ntoa(broadcast_address));
#endif
} }
bool bip_init(void) bool bip_init(void)
{ {
int status = 0; // return from socket lib calls int status = 0; // return from socket lib calls
struct sockaddr_in sin; struct sockaddr_in sin;
int sockopt = 0; int sockopt = 0;
int sock_fd = -1; int sock_fd = -1;
@@ -108,8 +108,7 @@ bool bip_init(void)
sockopt = 1; sockopt = 1;
status = setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, status = setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
&sockopt, sizeof(sockopt)); &sockopt, sizeof(sockopt));
if (status < 0) if (status < 0) {
{
close(sock_fd); close(sock_fd);
bip_set_socket(-1); bip_set_socket(-1);
return status; return status;
@@ -117,22 +116,19 @@ bool bip_init(void)
// allow us to send a broadcast // allow us to send a broadcast
status = setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, status = setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST,
&sockopt, sizeof(sockopt)); &sockopt, sizeof(sockopt));
if (status < 0) if (status < 0) {
{
close(sock_fd); close(sock_fd);
bip_set_socket(-1); bip_set_socket(-1);
return status; return status;
} }
// bind the socket to the local port number and IP address // bind the socket to the local port number and IP address
sin.sin_family = AF_INET; sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY); sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_port = htons(bip_get_port()); sin.sin_port = htons(bip_get_port());
memset(&(sin.sin_zero), '\0', sizeof(sin.sin_zero)); memset(&(sin.sin_zero), '\0', sizeof(sin.sin_zero));
status = bind(sock_fd, status = bind(sock_fd,
(const struct sockaddr*)&sin, sizeof(struct sockaddr)); (const struct sockaddr *) &sin, sizeof(struct sockaddr));
if (status < 0) if (status < 0) {
{
close(sock_fd); close(sock_fd);
bip_set_socket(-1); bip_set_socket(-1);
return false; return false;
+132 -166
View File
@@ -45,24 +45,25 @@ uint8_t Ethernet_Broadcast[MAX_MAC_LEN] =
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
// commonly used empty address for ethernet quick compare // commonly used empty address for ethernet quick compare
uint8_t Ethernet_Empty_MAC[MAX_MAC_LEN] = { 0, 0, 0, 0, 0, 0 }; uint8_t Ethernet_Empty_MAC[MAX_MAC_LEN] = { 0, 0, 0, 0, 0, 0 };
// my local device data - MAC address // my local device data - MAC address
uint8_t Ethernet_MAC_Address[MAX_MAC_LEN] = { 0 }; uint8_t Ethernet_MAC_Address[MAX_MAC_LEN] = { 0 };
static int eth802_sockfd = -1; /* 802.2 file handle */ static int eth802_sockfd = -1; /* 802.2 file handle */
static struct sockaddr eth_addr = { 0 }; // used for binding 802.2 static struct sockaddr eth_addr = { 0 }; // used for binding 802.2
bool ethernet_valid(void) bool ethernet_valid(void)
{ {
return (eth802_sockfd >= 0); return (eth802_sockfd >= 0);
} }
void ethernet_cleanup(void) void ethernet_cleanup(void)
{ {
if (ethernet_valid()) if (ethernet_valid())
close(eth802_sockfd); close(eth802_sockfd);
eth802_sockfd = -1; eth802_sockfd = -1;
return; return;
} }
/*---------------------------------------------------------------------- /*----------------------------------------------------------------------
@@ -76,20 +77,20 @@ void ethernet_cleanup(void)
----------------------------------------------------------------------*/ ----------------------------------------------------------------------*/
int setNonblocking(int fd) int setNonblocking(int fd)
{ {
int flags; int flags;
if (-1 == (flags = fcntl(fd, F_GETFL, 0))) if (-1 == (flags = fcntl(fd, F_GETFL, 0)))
flags = 0; flags = 0;
return fcntl(fd, F_SETFL, flags | O_NONBLOCK); return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
} }
/* opens an 802.2 socket to receive and send packets */ /* 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; int uid = 0;
fprintf(stderr,"ethernet: opening \"%s\"\n",interface_name); fprintf(stderr, "ethernet: opening \"%s\"\n", interface_name);
/* check to see if we are being run as root */ /* check to see if we are being run as root */
uid = getuid(); uid = getuid();
if (uid != 0) { if (uid != 0) {
@@ -104,19 +105,16 @@ static int ethernet_bind(struct sockaddr *eth_addr, char *interface_name)
// Then follow it by: # modprobe af_packet // Then follow it by: # modprobe af_packet
/* Attempt to open the socket for 802.2 ethernet frames */ /* Attempt to open the socket for 802.2 ethernet frames */
if ((sock_fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_802_2))) < 0) if ((sock_fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_802_2))) < 0) {
{
/* Error occured */ /* Error occured */
fprintf(stderr, fprintf(stderr,
"ethernet: Error opening socket: %s\n", "ethernet: Error opening socket: %s\n", strerror(errno));
strerror(errno));
fprintf(stderr, fprintf(stderr,
"You might need to add the following to modules.conf\n" "You might need to add the following to modules.conf\n"
"(or in /etc/modutils/alias on Debian with update-modules):\n" "(or in /etc/modutils/alias on Debian with update-modules):\n"
"alias net-pf-17 af_packet\n" "alias net-pf-17 af_packet\n"
"Also, add af_packet to /etc/modules.\n" "Also, add af_packet to /etc/modules.\n"
"Then follow it by:\n" "Then follow it by:\n" "# modprobe af_packet\n");
"# modprobe af_packet\n");
exit(-1); exit(-1);
} }
/* Bind the socket to an address */ /* Bind the socket to an address */
@@ -124,11 +122,11 @@ static int ethernet_bind(struct sockaddr *eth_addr, char *interface_name)
/* Clear the memory before copying */ /* Clear the memory before copying */
memset(eth_addr->sa_data, '\0', sizeof(eth_addr->sa_data)); memset(eth_addr->sa_data, '\0', sizeof(eth_addr->sa_data));
/* Strcpy the interface name into the address */ /* 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,
fprintf(stderr,"ethernet: binding \"%s\"\n",eth_addr->sa_data); sizeof(eth_addr->sa_data) - 1);
fprintf(stderr, "ethernet: binding \"%s\"\n", eth_addr->sa_data);
/* Attempt to bind the socket to the interface */ /* Attempt to bind the socket to the interface */
if (bind(sock_fd, eth_addr, sizeof(struct sockaddr)) != 0) if (bind(sock_fd, eth_addr, sizeof(struct sockaddr)) != 0) {
{
/* Bind problem, close socket and return */ /* Bind problem, close socket and return */
fprintf(stderr, fprintf(stderr,
"ethernet: Unable to bind 802.2 socket : %s\n", "ethernet: Unable to bind 802.2 socket : %s\n",
@@ -138,8 +136,7 @@ static int ethernet_bind(struct sockaddr *eth_addr, char *interface_name)
"(or in /etc/modutils/alias on Debian with update-modules):\n" "(or in /etc/modutils/alias on Debian with update-modules):\n"
"alias net-pf-17 af_packet\n" "alias net-pf-17 af_packet\n"
"Also, add af_packet to /etc/modules.\n" "Also, add af_packet to /etc/modules.\n"
"Then follow it by:\n" "Then follow it by:\n" "# modprobe af_packet\n");
"# modprobe af_packet\n");
/* Close the socket */ /* Close the socket */
close(sock_fd); close(sock_fd);
exit(-1); exit(-1);
@@ -155,7 +152,7 @@ static int get_local_hwaddr(const char *ifname, unsigned char *mac)
{ {
struct ifreq ifr; struct ifreq ifr;
int fd; 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 */ /* determine the local MAC address */
strcpy(ifr.ifr_name, ifname); strcpy(ifr.ifr_name, ifname);
@@ -174,19 +171,17 @@ static int get_local_hwaddr(const char *ifname, unsigned char *mac)
bool ethernet_init(char *interface_name) bool ethernet_init(char *interface_name)
{ {
get_local_hwaddr(interface_name, Ethernet_MAC_Address); get_local_hwaddr(interface_name, Ethernet_MAC_Address);
eth802_sockfd = eth802_sockfd = ethernet_bind(&eth_addr, interface_name);
ethernet_bind(&eth_addr, interface_name);
return ethernet_valid(); return ethernet_valid();
} }
/* function to send a packet out the 802.2 socket */ /* function to send a packet out the 802.2 socket */
/* returns bytes sent success, negative on failure */ /* returns bytes sent success, negative on failure */
int ethernet_send( int ethernet_send(BACNET_ADDRESS * dest, // destination address
BACNET_ADDRESS *dest, // destination address BACNET_ADDRESS * src, // source address
BACNET_ADDRESS *src, // source address 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
unsigned pdu_len) // number of bytes of data
{ {
int bytes = 0; int bytes = 0;
uint8_t mtu[MAX_MPDU] = { 0 }; uint8_t mtu[MAX_MPDU] = { 0 };
@@ -194,52 +189,42 @@ int ethernet_send(
int i = 0; int i = 0;
// don't waste time if the socket is not valid // don't waste time if the socket is not valid
if (eth802_sockfd < 0) if (eth802_sockfd < 0) {
{
fprintf(stderr, "ethernet: 802.2 socket is invalid!\n"); fprintf(stderr, "ethernet: 802.2 socket is invalid!\n");
return -1; return -1;
} }
/* load destination ethernet MAC address */ /* load destination ethernet MAC address */
if (dest->mac_len == 6) if (dest->mac_len == 6) {
{ for (i = 0; i < 6; i++) {
for (i = 0; i < 6; i++) mtu[mtu_len] = dest->mac[i];
{ mtu_len++;
mtu[mtu_len] = dest->mac[i]; }
mtu_len++; } else {
}
}
else
{
fprintf(stderr, "ethernet: invalid destination MAC address!\n"); fprintf(stderr, "ethernet: invalid destination MAC address!\n");
return -2; return -2;
} }
/* load source ethernet MAC address */ /* load source ethernet MAC address */
if (src->mac_len == 6) if (src->mac_len == 6) {
{ for (i = 0; i < 6; i++) {
for (i = 0; i < 6; i++) mtu[mtu_len] = src->mac[i];
{ mtu_len++;
mtu[mtu_len] = src->mac[i]; }
mtu_len++; } else {
}
}
else
{
fprintf(stderr, "ethernet: invalid source MAC address!\n"); fprintf(stderr, "ethernet: invalid source MAC address!\n");
return -3; return -3;
} }
if ((14 + 3 + pdu_len) > MAX_MPDU) if ((14 + 3 + pdu_len) > MAX_MPDU) {
{
fprintf(stderr, "ethernet: PDU is too big to send!\n"); fprintf(stderr, "ethernet: PDU is too big to send!\n");
return -4; return -4;
} }
/* packet length */ /* packet length */
mtu_len += encode_unsigned16(&mtu[12], mtu_len += encode_unsigned16(&mtu[12],
3 /*DSAP,SSAP,LLC*/ + pdu_len); 3 /*DSAP,SSAP,LLC */ + pdu_len);
// Logical PDU portion // Logical PDU portion
mtu[mtu_len++] = 0x82; /* DSAP for BACnet */ mtu[mtu_len++] = 0x82; /* DSAP for BACnet */
mtu[mtu_len++] = 0x82; /* SSAP for BACnet */ mtu[mtu_len++] = 0x82; /* SSAP for BACnet */
mtu[mtu_len++] = 0x03; /* Control byte in header */ mtu[mtu_len++] = 0x03; /* Control byte in header */
memcpy(&mtu[mtu_len], pdu, pdu_len); memcpy(&mtu[mtu_len], pdu, pdu_len);
mtu_len += pdu_len; mtu_len += pdu_len;
@@ -249,46 +234,43 @@ int ethernet_send(
(struct sockaddr *) &eth_addr, sizeof(struct sockaddr)); (struct sockaddr *) &eth_addr, sizeof(struct sockaddr));
/* did it get sent? */ /* did it get sent? */
if (bytes < 0) if (bytes < 0)
fprintf(stderr,"ethernet: Error sending packet: %s\n", fprintf(stderr, "ethernet: Error sending packet: %s\n",
strerror(errno)); strerror(errno));
return bytes; return bytes;
} }
/* function to send a packet out the 802.2 socket */ /* function to send a packet out the 802.2 socket */
/* returns number of bytes sent on success, negative on failure */ /* returns number of bytes sent on success, negative on failure */
int ethernet_send_pdu( int ethernet_send_pdu(BACNET_ADDRESS * dest, // destination address
BACNET_ADDRESS *dest, // destination address 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
unsigned pdu_len) // number of bytes of data
{ {
int i = 0; // counter int i = 0; // counter
BACNET_ADDRESS src = {0}; // source address BACNET_ADDRESS src = { 0 }; // source address
for (i = 0; i < 6; i++) for (i = 0; i < 6; i++) {
{ src.mac[i] = Ethernet_MAC_Address[i];
src.mac[i] = Ethernet_MAC_Address[i]; src.mac_len++;
src.mac_len++; }
} /* function to send a packet out the 802.2 socket */
/* function to send a packet out the 802.2 socket */ /* returns 1 on success, 0 on failure */
/* returns 1 on success, 0 on failure */ return ethernet_send(dest, // destination address
return ethernet_send(dest, // destination address &src, // source address
&src, // source address pdu, // any data to be sent - may be null
pdu, // any data to be sent - may be null pdu_len); // number of bytes of data
pdu_len); // number of bytes of data
} }
// receives an 802.2 framed packet // receives an 802.2 framed packet
// returns the number of octets in the PDU, or zero on failure // returns the number of octets in the PDU, or zero on failure
uint16_t ethernet_receive( uint16_t ethernet_receive(BACNET_ADDRESS * src, // source address
BACNET_ADDRESS *src, // source address uint8_t * pdu, // PDU data
uint8_t *pdu, // PDU data uint16_t max_pdu, // amount of space available in the PDU
uint16_t max_pdu, // amount of space available in the PDU unsigned timeout) // number of milliseconds to wait for a packet
unsigned timeout) // number of milliseconds to wait for a packet
{ {
int received_bytes; int received_bytes;
uint8_t buf[MAX_MPDU] = {0}; // data uint8_t buf[MAX_MPDU] = { 0 }; // data
uint16_t pdu_len = 0; // return value uint16_t pdu_len = 0; // return value
fd_set read_fds; fd_set read_fds;
int max; int max;
struct timeval select_timeout; struct timeval select_timeout;
@@ -300,14 +282,11 @@ uint16_t ethernet_receive(
/* we could just use a non-blocking socket, but that consumes all /* we could just use a non-blocking socket, but that consumes all
the CPU time. We can use a timeout; it is only supported as the CPU time. We can use a timeout; it is only supported as
a select. */ a select. */
if (timeout >= 1000) if (timeout >= 1000) {
{
select_timeout.tv_sec = timeout / 1000; select_timeout.tv_sec = timeout / 1000;
select_timeout.tv_usec = select_timeout.tv_usec =
1000 * (timeout - select_timeout.tv_sec * 1000); 1000 * (timeout - select_timeout.tv_sec * 1000);
} } else {
else
{
select_timeout.tv_sec = 0; select_timeout.tv_sec = 0;
select_timeout.tv_usec = 1000 * timeout; select_timeout.tv_usec = 1000 * timeout;
} }
@@ -326,13 +305,14 @@ uint16_t ethernet_receive(
// using O_NONBLOCK and no data // using O_NONBLOCK and no data
// was immediately available for reading. // was immediately available for reading.
if (errno != EAGAIN) if (errno != EAGAIN)
fprintf(stderr,"ethernet: Read error in receiving packet: %s\n", fprintf(stderr,
"ethernet: Read error in receiving packet: %s\n",
strerror(errno)); strerror(errno));
return 0; return 0;
} }
if (received_bytes == 0) if (received_bytes == 0)
return 0; return 0;
/* the signature of an 802.2 BACnet packet */ /* the signature of an 802.2 BACnet packet */
if ((buf[14] != 0x82) && (buf[15] != 0x82)) { if ((buf[14] != 0x82) && (buf[15] != 0x82)) {
@@ -345,109 +325,95 @@ uint16_t ethernet_receive(
// check destination address for when // check destination address for when
// the Ethernet card is in promiscious mode // the Ethernet card is in promiscious mode
if ((memcmp(&buf[0], Ethernet_MAC_Address,6) != 0) if ((memcmp(&buf[0], Ethernet_MAC_Address, 6) != 0)
&& (memcmp(&buf[0], Ethernet_Broadcast, 6) != 0)) && (memcmp(&buf[0], Ethernet_Broadcast, 6) != 0)) {
{
//fprintf(stderr, "ethernet: This packet isn't for us\n"); //fprintf(stderr, "ethernet: This packet isn't for us\n");
return 0; return 0;
} }
(void)decode_unsigned16(&buf[12],&pdu_len); (void) decode_unsigned16(&buf[12], &pdu_len);
pdu_len -= 3 /* DSAP, SSAP, LLC Control */ ; pdu_len -= 3 /* DSAP, SSAP, LLC Control */ ;
// copy the buffer into the PDU // copy the buffer into the PDU
if (pdu_len < max_pdu) if (pdu_len < max_pdu)
memmove(&pdu[0],&buf[17],pdu_len); memmove(&pdu[0], &buf[17], pdu_len);
// ignore packets that are too large // ignore packets that are too large
else else
pdu_len = 0; pdu_len = 0;
return pdu_len; return pdu_len;
} }
void ethernet_set_my_address(BACNET_ADDRESS *my_address) void ethernet_set_my_address(BACNET_ADDRESS * my_address)
{ {
int i = 0; int i = 0;
for (i = 0; i < 6; i++) for (i = 0; i < 6; i++) {
{ Ethernet_MAC_Address[i] = my_address->mac[i];
Ethernet_MAC_Address[i] = my_address->mac[i]; }
}
return; return;
} }
void ethernet_get_my_address(BACNET_ADDRESS *my_address) void ethernet_get_my_address(BACNET_ADDRESS * my_address)
{ {
int i = 0; int i = 0;
my_address->mac_len = 0; my_address->mac_len = 0;
for (i = 0; i < 6; i++) for (i = 0; i < 6; i++) {
{ my_address->mac[i] = Ethernet_MAC_Address[i];
my_address->mac[i] = Ethernet_MAC_Address[i]; my_address->mac_len++;
my_address->mac_len++; }
} my_address->net = 0; // local only, no routing
my_address->net = 0; // local only, no routing my_address->len = 0;
my_address->len = 0; for (i = 0; i < MAX_MAC_LEN; i++) {
for (i = 0; i < MAX_MAC_LEN; i++) my_address->adr[i] = 0;
{ }
my_address->adr[i] = 0;
}
return; return;
} }
void ethernet_get_broadcast_address( void ethernet_get_broadcast_address(BACNET_ADDRESS * dest) // destination address
BACNET_ADDRESS *dest) // destination address
{ {
int i = 0; // counter int i = 0; // counter
if (dest) if (dest) {
{ for (i = 0; i < 6; i++) {
for (i = 0; i < 6; i++) dest->mac[i] = Ethernet_Broadcast[i];
{ }
dest->mac[i] = Ethernet_Broadcast[i]; dest->mac_len = 6;
dest->net = BACNET_BROADCAST_NETWORK;
dest->len = 0; // denotes broadcast address
for (i = 0; i < MAX_MAC_LEN; i++) {
dest->adr[i] = 0;
}
} }
dest->mac_len = 6;
dest->net = BACNET_BROADCAST_NETWORK;
dest->len = 0; // denotes broadcast address
for (i = 0; i < MAX_MAC_LEN; i++)
{
dest->adr[i] = 0;
}
}
return; return;
} }
void ethernet_debug_address( void ethernet_debug_address(const char *info, BACNET_ADDRESS * dest)
const char *info,
BACNET_ADDRESS *dest)
{ {
int i = 0; // counter int i = 0; // counter
if (info) if (info)
fprintf(stderr,"%s",info); fprintf(stderr, "%s", info);
if (dest) if (dest) {
{ fprintf(stderr, "Address:\n");
fprintf(stderr,"Address:\n"); fprintf(stderr, " MAC Length=%d\n", dest->mac_len);
fprintf(stderr," MAC Length=%d\n",dest->mac_len); fprintf(stderr, " MAC Address=");
fprintf(stderr," MAC Address="); for (i = 0; i < MAX_MAC_LEN; i++) {
for (i = 0; i < MAX_MAC_LEN; i++) fprintf(stderr, "%02X ", (unsigned) dest->mac[i]);
{ }
fprintf(stderr,"%02X ",(unsigned)dest->mac[i]); fprintf(stderr, "\n");
fprintf(stderr, " Net=%hu\n", dest->net);
fprintf(stderr, " Len=%d\n", dest->len);
fprintf(stderr, " Adr=");
for (i = 0; i < MAX_MAC_LEN; i++) {
fprintf(stderr, "%02X ", (unsigned) dest->adr[i]);
}
fprintf(stderr, "\n");
} }
fprintf(stderr,"\n");
fprintf(stderr," Net=%hu\n",dest->net);
fprintf(stderr," Len=%d\n",dest->len);
fprintf(stderr," Adr=");
for (i = 0; i < MAX_MAC_LEN; i++)
{
fprintf(stderr,"%02X ",(unsigned)dest->adr[i]);
}
fprintf(stderr,"\n");
}
return; return;
} }
+206 -248
View File
@@ -48,293 +48,251 @@
bool Who_Is_Request = true; bool Who_Is_Request = true;
// buffers used for receiving // buffers used for receiving
static uint8_t Rx_Buf[MAX_MPDU] = {0}; static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
static void LocalIAmHandler( static void LocalIAmHandler(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len, BACNET_ADDRESS * src)
uint16_t service_len,
BACNET_ADDRESS *src)
{ {
int len = 0; int len = 0;
uint32_t device_id = 0; uint32_t device_id = 0;
unsigned max_apdu = 0; unsigned max_apdu = 0;
int segmentation = 0; int segmentation = 0;
uint16_t vendor_id = 0; uint16_t vendor_id = 0;
(void)src; (void) src;
(void)service_len; (void) service_len;
len = iam_decode_service_request( len = iam_decode_service_request(service_request,
service_request, &device_id, &max_apdu, &segmentation, &vendor_id);
&device_id, fprintf(stderr, "Received I-Am Request");
&max_apdu, if (len != -1) {
&segmentation, fprintf(stderr, " from %u!\n", device_id);
&vendor_id); address_add(device_id, max_apdu, src);
fprintf(stderr,"Received I-Am Request"); } else
if (len != -1) fprintf(stderr, "!\n");
{
fprintf(stderr," from %u!\n",device_id);
address_add(device_id,
max_apdu,
src);
}
else
fprintf(stderr,"!\n");
return; return;
} }
static void Read_Properties(void) static void Read_Properties(void)
{ {
uint32_t device_id = 0; uint32_t device_id = 0;
bool status = false; bool status = false;
unsigned max_apdu = 0; unsigned max_apdu = 0;
BACNET_ADDRESS src; BACNET_ADDRESS src;
bool next_device = false; bool next_device = false;
static unsigned index = 0; static unsigned index = 0;
static unsigned property = 0; static unsigned property = 0;
/* list of required (and some optional and proprietary) /* list of required (and some optional and proprietary)
properties in the Device Object. Note that this demo properties in the Device Object. Note that this demo
tests for error messages so that the device doesn't have tests for error messages so that the device doesn't have
to have all the properties listed here. */ to have all the properties listed here. */
const int object_props[] = const int object_props[] = {
{ PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME,
PROP_OBJECT_NAME, PROP_OBJECT_TYPE,
PROP_OBJECT_TYPE, PROP_SYSTEM_STATUS,
PROP_SYSTEM_STATUS, PROP_VENDOR_NAME,
PROP_VENDOR_NAME, PROP_VENDOR_IDENTIFIER,
PROP_VENDOR_IDENTIFIER, PROP_MODEL_NAME,
PROP_MODEL_NAME, PROP_FIRMWARE_REVISION,
PROP_FIRMWARE_REVISION, PROP_APPLICATION_SOFTWARE_VERSION,
PROP_APPLICATION_SOFTWARE_VERSION, PROP_PROTOCOL_VERSION,
PROP_PROTOCOL_VERSION, PROP_PROTOCOL_CONFORMANCE_CLASS,
PROP_PROTOCOL_CONFORMANCE_CLASS, PROP_PROTOCOL_SERVICES_SUPPORTED,
PROP_PROTOCOL_SERVICES_SUPPORTED, PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED,
PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED, PROP_MAX_APDU_LENGTH_ACCEPTED,
PROP_MAX_APDU_LENGTH_ACCEPTED, PROP_SEGMENTATION_SUPPORTED,
PROP_SEGMENTATION_SUPPORTED, PROP_LOCAL_TIME,
PROP_LOCAL_TIME, PROP_LOCAL_DATE,
PROP_LOCAL_DATE, PROP_UTC_OFFSET,
PROP_UTC_OFFSET, PROP_DAYLIGHT_SAVINGS_STATUS,
PROP_DAYLIGHT_SAVINGS_STATUS, PROP_APDU_SEGMENT_TIMEOUT,
PROP_APDU_SEGMENT_TIMEOUT, PROP_APDU_TIMEOUT,
PROP_APDU_TIMEOUT, PROP_NUMBER_OF_APDU_RETRIES,
PROP_NUMBER_OF_APDU_RETRIES, PROP_TIME_SYNCHRONIZATION_RECIPIENTS,
PROP_TIME_SYNCHRONIZATION_RECIPIENTS, PROP_MAX_MASTER,
PROP_MAX_MASTER, PROP_MAX_INFO_FRAMES,
PROP_MAX_INFO_FRAMES, PROP_DEVICE_ADDRESS_BINDING,
PROP_DEVICE_ADDRESS_BINDING, /* note: PROP_OBJECT_LIST is missing because
/* note: PROP_OBJECT_LIST is missing because the result can be very large. Read index 0
the result can be very large. Read index 0 which gives us the number of objects in the list,
which gives us the number of objects in the list, and then we can read index 1, 2.. n one by one,
and then we can read index 1, 2.. n one by one, rather than trying to read the entire object
rather than trying to read the entire object list in one message. */
list in one message. */ /* some proprietary properties */
/* some proprietary properties */ 514, 515,
514,515, /* end of list */
/* end of list */ -1
-1 };
};
if (address_count()) if (address_count()) {
{ if (address_get_by_index(index, &device_id, &max_apdu, &src)) {
if (address_get_by_index(index, &device_id, &max_apdu, &src)) if (object_props[property] < 0)
{ next_device = true;
if (object_props[property] < 0) else {
next_device = true; /* note: if we wanted to do this synchronously, we would get the
else invoke ID from the sending of the request, and wait until we
{ got the reply with matching invoke ID or the TSM of the
/* note: if we wanted to do this synchronously, we would get the invoke ID expired. This demo is doing things asynchronously. */
invoke ID from the sending of the request, and wait until we status = Send_Read_Property_Request(device_id, // destination device
got the reply with matching invoke ID or the TSM of the OBJECT_DEVICE,
invoke ID expired. This demo is doing things asynchronously. */ device_id, object_props[property], BACNET_ARRAY_ALL);
status = Send_Read_Property_Request( if (status)
device_id, // destination device property++;
OBJECT_DEVICE, }
device_id, } else
object_props[property], next_device = true;
BACNET_ARRAY_ALL); if (next_device) {
if (status) next_device = false;
property++; index++;
} if (index >= MAX_ADDRESS_CACHE)
index = 0;
property = 0;
}
} }
else
next_device = true;
if (next_device)
{
next_device = false;
index++;
if (index >= MAX_ADDRESS_CACHE)
index = 0;
property = 0;
}
}
return; return;
} }
static void Init_Service_Handlers(void) static void Init_Service_Handlers(void)
{ {
// we need to handle who-is to support dynamic device binding // we need to handle who-is to support dynamic device binding
apdu_set_unconfirmed_handler( apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS,
SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
handler_who_is); apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_I_AM,
apdu_set_unconfirmed_handler( LocalIAmHandler);
SERVICE_UNCONFIRMED_I_AM,
LocalIAmHandler);
// set the handler for all the services we don't implement // set the handler for all the services we don't implement
// It is required to send the proper reject message... // It is required to send the proper reject message...
apdu_set_unrecognized_service_handler_handler( apdu_set_unrecognized_service_handler_handler
handler_unrecognized_service); (handler_unrecognized_service);
// Set the handlers for any confirmed services that we support. // Set the handlers for any confirmed services that we support.
// We must implement read property - it's required! // We must implement read property - it's required!
apdu_set_confirmed_handler( apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY,
SERVICE_CONFIRMED_READ_PROPERTY, handler_read_property);
handler_read_property); apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROPERTY,
apdu_set_confirmed_handler( handler_write_property);
SERVICE_CONFIRMED_WRITE_PROPERTY, apdu_set_confirmed_handler(SERVICE_CONFIRMED_ATOMIC_READ_FILE,
handler_write_property); handler_atomic_read_file);
apdu_set_confirmed_handler( // handle the data coming back from confirmed requests
SERVICE_CONFIRMED_ATOMIC_READ_FILE, apdu_set_confirmed_ack_handler(SERVICE_CONFIRMED_READ_PROPERTY,
handler_atomic_read_file); handler_read_property_ack);
// handle the data coming back from confirmed requests apdu_set_confirmed_ack_handler(SERVICE_CONFIRMED_ATOMIC_READ_FILE,
apdu_set_confirmed_ack_handler( handler_atomic_read_file_ack);
SERVICE_CONFIRMED_READ_PROPERTY,
handler_read_property_ack);
apdu_set_confirmed_ack_handler(
SERVICE_CONFIRMED_ATOMIC_READ_FILE,
handler_atomic_read_file_ack);
} }
static void print_address_cache(void) static void print_address_cache(void)
{ {
unsigned i,j; unsigned i, j;
BACNET_ADDRESS address; BACNET_ADDRESS address;
uint32_t device_id = 0; uint32_t device_id = 0;
unsigned max_apdu = 0; unsigned max_apdu = 0;
fprintf(stderr,"Device\tMAC\tMaxAPDU\tNet\n"); fprintf(stderr, "Device\tMAC\tMaxAPDU\tNet\n");
for (i = 0; i < MAX_ADDRESS_CACHE; i++) for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
{ if (address_get_by_index(i, &device_id, &max_apdu, &address)) {
if (address_get_by_index(i,&device_id, &max_apdu, &address)) fprintf(stderr, "%u\t", device_id);
{ for (j = 0; j < address.mac_len; j++) {
fprintf(stderr,"%u\t",device_id); fprintf(stderr, "%02X", address.mac[j]);
for (j = 0; j < address.mac_len; j++) }
{ fprintf(stderr, "\t");
fprintf(stderr,"%02X",address.mac[j]); fprintf(stderr, "%hu\t", max_apdu);
} fprintf(stderr, "%hu\n", address.net);
fprintf(stderr,"\t"); }
fprintf(stderr,"%hu\t",max_apdu);
fprintf(stderr,"%hu\n",address.net);
} }
}
} }
static void print_tsm_stats(void) static void print_tsm_stats(void)
{ {
int idle = 0; int idle = 0;
int total = 0; int total = 0;
idle = tsm_transaction_idle_count(); idle = tsm_transaction_idle_count();
total = MAX_TSM_TRANSACTIONS; total = MAX_TSM_TRANSACTIONS;
fprintf(stderr,"TSM: %d idle of %d transactions\n",idle,total); 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(); datalink_cleanup();
print_address_cache(); print_address_cache();
print_tsm_stats(); print_tsm_stats();
exit(0); exit(0);
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
BACNET_ADDRESS src = {0}; // address where message came from BACNET_ADDRESS src = { 0 }; // address where message came from
uint16_t pdu_len = 0; uint16_t pdu_len = 0;
unsigned timeout = 100; // milliseconds unsigned timeout = 100; // milliseconds
unsigned count = 0; // milliseconds unsigned count = 0; // milliseconds
time_t start_time; time_t start_time;
time_t new_time = 0; time_t new_time = 0;
start_time = time(NULL); /* get current time */ start_time = time(NULL); /* get current time */
// Linux specials // Linux specials
signal(SIGINT, sig_handler); signal(SIGINT, sig_handler);
signal(SIGHUP, sig_handler); signal(SIGHUP, sig_handler);
signal(SIGTERM, sig_handler); signal(SIGTERM, sig_handler);
// setup this BACnet Server device // setup this BACnet Server device
Device_Set_Object_Instance_Number(111); Device_Set_Object_Instance_Number(111);
Init_Service_Handlers(); Init_Service_Handlers();
#ifdef BACDL_ETHERNET #ifdef BACDL_ETHERNET
// init the physical layer // init the physical layer
if (!ethernet_init("eth0")) if (!ethernet_init("eth0"))
return 1; return 1;
#endif #endif
#ifdef BACDL_BIP #ifdef BACDL_BIP
bip_set_interface("eth0"); bip_set_interface("eth0");
bip_set_port(0xBAC0); bip_set_port(0xBAC0);
if (!bip_init()) if (!bip_init())
return 1; return 1;
#endif #endif
#ifdef BACDL_ARCNET #ifdef BACDL_ARCNET
if (!arcnet_init("arc0")) if (!arcnet_init("arc0"))
return 1; return 1;
#endif #endif
// loop forever // loop forever
for (;;) for (;;) {
{ // input
// input new_time = time(NULL);
new_time = time(NULL); // returns 0 bytes on timeout
// returns 0 bytes on timeout pdu_len = datalink_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout);
pdu_len = datalink_receive(
&src,
&Rx_Buf[0],
MAX_MPDU,
timeout);
// process // process
if (pdu_len) if (pdu_len) {
{ npdu_handler(&src, &Rx_Buf[0], pdu_len);
npdu_handler( }
&src, if (new_time > start_time) {
&Rx_Buf[0], tsm_timer_milliseconds(new_time - start_time * 1000);
pdu_len); start_time = new_time;
} }
if (new_time > start_time) if (I_Am_Request) {
{ I_Am_Request = false;
tsm_timer_milliseconds(new_time - start_time * 1000); iam_send(&Handler_Transmit_Buffer[0]);
start_time = new_time; } else if (Who_Is_Request) {
} Who_Is_Request = false;
if (I_Am_Request) Send_WhoIs(-1, -1);
{ }
I_Am_Request = false; // output
iam_send(&Handler_Transmit_Buffer[0]); // some round robin task switching
} else if (Who_Is_Request) count++;
{ switch (count) {
Who_Is_Request = false; case 1:
Send_WhoIs(-1,-1); // used for testing, but kind of noisy on the network
} //Read_Properties();
// output break;
// some round robin task switching case 2:
count++; break;
switch (count) default:
{ count = 0;
case 1: break;
// used for testing, but kind of noisy on the network }
//Read_Properties();
break; // blink LEDs, Turn on or off outputs, etc
case 2:
break;
default:
count = 0;
break;
} }
// blink LEDs, Turn on or off outputs, etc return 0;
}
return 0;
} }
+12 -12
View File
@@ -27,34 +27,34 @@
#define NET_H #define NET_H
/* common unix sockets headers needed */ /* common unix sockets headers needed */
#include <sys/types.h> /* basic system data types */ #include <sys/types.h> /* basic system data types */
#include <sys/time.h> /* timeval{} for select() */ #include <sys/time.h> /* timeval{} for select() */
#include <time.h> /* timespec{} for pselect() */ #include <time.h> /* timespec{} for pselect() */
#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */ #include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#include <arpa/inet.h> /* inet(3) functions */ #include <arpa/inet.h> /* inet(3) functions */
#include <fcntl.h> /* for nonblocking */ #include <fcntl.h> /* for nonblocking */
#include <netdb.h> #include <netdb.h>
#include <errno.h> #include <errno.h>
#include <signal.h> #include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/stat.h> /* for S_xxx file mode constants */ #include <sys/stat.h> /* for S_xxx file mode constants */
#include <sys/uio.h> /* for iovec{} and readv/writev */ #include <sys/uio.h> /* for iovec{} and readv/writev */
#include <unistd.h> #include <unistd.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/un.h> /* for Unix domain sockets */ #include <sys/un.h> /* for Unix domain sockets */
#ifdef HAVE_SYS_SELECT_H #ifdef HAVE_SYS_SELECT_H
# include <sys/select.h> /* for convenience */ # include <sys/select.h> /* for convenience */
#endif #endif
#ifdef HAVE_POLL_H #ifdef HAVE_POLL_H
# include <poll.h> /* for convenience */ # include <poll.h> /* for convenience */
#endif #endif
#ifdef HAVE_STRINGS_H #ifdef HAVE_STRINGS_H
# include <strings.h> /* for convenience */ # include <strings.h> /* for convenience */
#endif #endif
/* Three headers are normally needed for socket/file ioctl's: /* Three headers are normally needed for socket/file ioctl's:
+31 -37
View File
@@ -44,56 +44,50 @@
#include "mstp.h" #include "mstp.h"
// Transmits a Frame on the wire // Transmits a Frame on the wire
void RS485_Send_Frame( void RS485_Send_Frame(struct mstp_port_struct_t *mstp_port, // port specific data
struct mstp_port_struct_t *mstp_port, // port specific data uint8_t * buffer, // frame to send (up to 501 bytes of 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 nbytes) // number of bytes of data (up to 501)
{ {
// in order to avoid line contention // in order to avoid line contention
while (mstp_port->Turn_Around_Waiting) while (mstp_port->Turn_Around_Waiting) {
{ // wait, yield, or whatever
// wait, yield, or whatever }
}
// Disable the receiver, and enable the transmit line driver. // Disable the receiver, and enable the transmit line driver.
while (nbytes) while (nbytes) {
{ putc(*buffer, stderr);
putc(*buffer,stderr); buffer++;
buffer++; nbytes--;
nbytes--; }
}
// Wait until the final stop bit of the most significant CRC octet // Wait until the final stop bit of the most significant CRC octet
// has been transmitted but not more than Tpostdrive. // has been transmitted but not more than Tpostdrive.
// Disable the transmit line driver. // Disable the transmit line driver.
return; return;
} }
// called by timer, interrupt(?) or other thread // 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)
{ {
if (mstp_port->ReceiveError == true) if (mstp_port->ReceiveError == true) {
{ // wait for state machine to clear this
// wait for state machine to clear this }
} // wait for state machine to read from the DataRegister
// wait for state machine to read from the DataRegister else if (mstp_port->DataAvailable == false) {
else if (mstp_port->DataAvailable == false) // check for data
{
// check for data
// if error, // if error,
// ReceiveError = TRUE; // ReceiveError = TRUE;
// return; // return;
mstp_port->DataRegister = 0; // FIXME: Get this data from UART or buffer mstp_port->DataRegister = 0; // FIXME: Get this data from UART or buffer
// if data is ready, // if data is ready,
// DataAvailable = TRUE; // DataAvailable = TRUE;
// return; // return;
} }
} }
+114 -109
View File
@@ -37,174 +37,180 @@
#include "bip.h" #include "bip.h"
#if (defined(BACDL_ETHERNET) || defined(BACDL_BIP)) #if (defined(BACDL_ETHERNET) || defined(BACDL_BIP))
static int interface = SOCKET_ERROR; // SOCKET_ERROR means no open interface static int interface = SOCKET_ERROR; // SOCKET_ERROR means no open interface
#endif #endif
void bip_set_interface(char *ifname) void bip_set_interface(char *ifname)
{ {
/*dummy function - to make the demos compile easier */ /*dummy function - to make the demos compile easier */
} }
#if (defined(BACDL_ETHERNET) || defined(BACDL_BIP)) #if (defined(BACDL_ETHERNET) || defined(BACDL_BIP))
/*-----------------------------------*/ /*-----------------------------------*/
static void Error(const char * Msg) static void Error(const char *Msg)
{ {
int Code = WSAGetLastError(); int Code = WSAGetLastError();
#ifdef HOST #ifdef HOST
printf("%s, error code: %i\n", Msg, Code); printf("%s, error code: %i\n", Msg, Code);
#else #else
printf("%s, error code: %s\n", Msg, xn_geterror_string(Code)); printf("%s, error code: %s\n", Msg, xn_geterror_string(Code));
#endif #endif
exit(1); exit(1);
} }
#ifndef HOST #ifndef HOST
/*-----------------------------------*/ /*-----------------------------------*/
void InterfaceCleanup(void) void InterfaceCleanup(void)
{ {
if (interface != SOCKET_ERROR) if (interface != SOCKET_ERROR) {
{ xn_interface_close(interface);
xn_interface_close(interface); interface = SOCKET_ERROR;
interface = SOCKET_ERROR;
#if DEVICE_ID == PRISM_PCMCIA_DEVICE #if DEVICE_ID == PRISM_PCMCIA_DEVICE
RTPCShutDown(); RTPCShutDown();
#endif #endif
} }
} }
#endif #endif
static void NetInitialize(void) static void NetInitialize(void)
// initialize the TCP/IP stack // initialize the TCP/IP stack
{ {
int Result; int Result;
#ifndef HOST #ifndef HOST
RTKernelInit(0); // get the kernel going RTKernelInit(0); // get the kernel going
if (!RTKDebugVersion()) // switch of all diagnostics and error messages of RTIP-32 if (!RTKDebugVersion()) // switch of all diagnostics and error messages of RTIP-32
xn_callbacks()->cb_wr_screen_string_fnc = NULL; xn_callbacks()->cb_wr_screen_string_fnc = NULL;
CLKSetTimerIntVal(10*1000); // 10 millisecond tick CLKSetTimerIntVal(10 * 1000); // 10 millisecond tick
RTKDelay(1); RTKDelay(1);
RTCMOSSetSystemTime(); // get the right time-of-day RTCMOSSetSystemTime(); // get the right time-of-day
#ifdef RTUSB_VER #ifdef RTUSB_VER
RTURegisterCallback(USBAX172); // ax172 and ax772 drivers RTURegisterCallback(USBAX172); // ax172 and ax772 drivers
RTURegisterCallback(USBAX772); RTURegisterCallback(USBAX772);
RTURegisterCallback(USBKeyboard); // support USB keyboards RTURegisterCallback(USBKeyboard); // support USB keyboards
FindUSBControllers(); // install USB host controllers 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 #endif
#ifdef DHCP #ifdef DHCP
XN_REGISTER_DHCP_CLI() // and optionally the DHCP client XN_REGISTER_DHCP_CLI() // and optionally the DHCP client
#endif #endif
Result = xn_rtip_init(); // Initialize the RTIP stack
if (Result != 0)
Error("xn_rtip_init failed");
Result = xn_rtip_init(); // Initialize the RTIP stack atexit(InterfaceCleanup); // make sure the driver is shut down properly
if (Result != 0) RTCallDebugger(RT_DBG_CALLRESET, (DWORD) exit, 0); // even if we get restarted by the debugger
Error("xn_rtip_init failed");
atexit(InterfaceCleanup); // make sure the driver is shut down properly Result = BIND_DRIVER(MINOR_0); // tell RTIP what Ethernet driver we want (see netcfg.h)
RTCallDebugger(RT_DBG_CALLRESET, (DWORD)exit, 0); // even if we get restarted by the debugger if (Result != 0)
Error("driver initialization failed");
Result = BIND_DRIVER(MINOR_0); // tell RTIP what Ethernet driver we want (see netcfg.h)
if (Result != 0)
Error("driver initialization failed");
#if DEVICE_ID == PRISM_PCMCIA_DEVICE #if DEVICE_ID == PRISM_PCMCIA_DEVICE
// if this is a PCMCIA device, start the PCMCIA driver // if this is a PCMCIA device, start the PCMCIA driver
if (RTPCInit(-1, 0, 2, NULL) == 0) if (RTPCInit(-1, 0, 2, NULL) == 0)
Error("No PCMCIA controller found"); Error("No PCMCIA controller found");
#endif #endif
// Open the interface // Open the interface
interface = xn_interface_open_config(DEVICE_ID, MINOR_0, ED_IO_ADD, ED_IRQ, ED_MEM_ADD); interface =
if (interface == SOCKET_ERROR) xn_interface_open_config(DEVICE_ID, MINOR_0, ED_IO_ADD, ED_IRQ,
Error("xn_interface_open_config failed"); ED_MEM_ADD);
else if (interface == SOCKET_ERROR)
{ Error("xn_interface_open_config failed");
struct _iface_info ii; else {
struct _iface_info ii;
#ifdef BACDL_ETHERNET #ifdef BACDL_ETHERNET
BACNET_ADDRESS my_address; BACNET_ADDRESS my_address;
unsigned i; unsigned i;
#endif #endif
xn_interface_info(interface, &ii); xn_interface_info(interface, &ii);
printf("Interface opened, MAC address: %02x-%02x-%02x-%02x-%02x-%02x\n", printf
ii.my_ethernet_address[0], ii.my_ethernet_address[1], ii.my_ethernet_address[2], ("Interface opened, MAC address: %02x-%02x-%02x-%02x-%02x-%02x\n",
ii.my_ethernet_address[3], ii.my_ethernet_address[4], ii.my_ethernet_address[5]); ii.my_ethernet_address[0], ii.my_ethernet_address[1],
ii.my_ethernet_address[2], ii.my_ethernet_address[3],
ii.my_ethernet_address[4], ii.my_ethernet_address[5]);
#ifdef BACDL_ETHERNET #ifdef BACDL_ETHERNET
for (i = 0; i < 6; i++) for (i = 0; i < 6; i++) {
{ my_address.mac[i] = ii.my_ethernet_address[i];
my_address.mac[i] = ii.my_ethernet_address[i]; }
} ethernet_set_my_address(&my_address);
ethernet_set_my_address(&my_address);
#endif #endif
} }
#if DEVICE_ID == PRISM_PCMCIA_DEVICE || DEVICE_ID == PRISM_DEVICE #if DEVICE_ID == PRISM_PCMCIA_DEVICE || DEVICE_ID == PRISM_DEVICE
xn_wlan_setup(interface, // iface_no: value returned by xn_interface_open_config() xn_wlan_setup(interface, // iface_no: value returned by xn_interface_open_config()
"network name", // SSID : network name set in the access point "network name", // SSID : network name set in the access point
"station name", // Name : name of this node "station name", // Name : name of this node
0, // Channel : 0 for access points, 1..14 for ad-hoc 0, // Channel : 0 for access points, 1..14 for ad-hoc
0, // KeyIndex: 0 .. 3 0, // KeyIndex: 0 .. 3
"12345", // WEP Key : key to use (5 or 13 bytes) "12345", // WEP Key : key to use (5 or 13 bytes)
0); // Flags : see manual and Wlanapi.h for details 0); // Flags : see manual and Wlanapi.h for details
Sleep(1000); // wireless devices need a little time before they can be used Sleep(1000); // wireless devices need a little time before they can be used
#endif // WLAN device #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); Result = xn_autoip(interface, MinIP, MaxIP, NetMask, TargetIP);
if (Result == SOCKET_ERROR) if (Result == SOCKET_ERROR)
Error("xn_autoip failed"); Error("xn_autoip failed");
else else {
{ printf("Auto-assigned IP address %i.%i.%i.%i\n", TargetIP[0],
printf("Auto-assigned IP address %i.%i.%i.%i\n", TargetIP[0], TargetIP[1], TargetIP[2], TargetIP[3]); TargetIP[1], TargetIP[2], TargetIP[3]);
// define default gateway and DNS server // 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,
xn_set_server_list((DWORD*)DNSServer, 1); 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}, {ROUTER_OPTION, 1}}; {
DHCP_session DS; DHCP_param param[] = { {SUBNET_MASK, 1}
DHCP_conf DC; , {DNS_OP, 1}
, {ROUTER_OPTION, 1}
};
DHCP_session DS;
DHCP_conf DC;
xn_init_dhcp_conf(&DC); // load default DHCP options xn_init_dhcp_conf(&DC); // load default DHCP options
DC.plist = param; // add MASK, DNS, and gateway options DC.plist = param; // add MASK, DNS, and gateway options
DC.plist_entries = sizeof(param) / sizeof(param[0]); DC.plist_entries = sizeof(param) / sizeof(param[0]);
printf("Contacting DHCP server, please wait...\n"); printf("Contacting DHCP server, please wait...\n");
Result = xn_dhcp(interface, &DS, &DC); // contact DHCP server Result = xn_dhcp(interface, &DS, &DC); // contact DHCP server
if (Result == SOCKET_ERROR) if (Result == SOCKET_ERROR)
Error("xn_dhcp failed"); Error("xn_dhcp failed");
memcpy(TargetIP, DS.client_ip, 4); memcpy(TargetIP, DS.client_ip, 4);
printf("My IP address is: %i.%i.%i.%i\n", TargetIP[0], TargetIP[1], TargetIP[2], TargetIP[3]); printf("My IP address is: %i.%i.%i.%i\n", TargetIP[0], TargetIP[1],
} TargetIP[2], TargetIP[3]);
}
#else #else
// Set the IP address and interface // Set the IP address and interface
printf("Using static IP address %i.%i.%i.%i\n", TargetIP[0], TargetIP[1], TargetIP[2], TargetIP[3]); printf("Using static IP address %i.%i.%i.%i\n", TargetIP[0],
Result = xn_set_ip(interface, TargetIP, NetMask); TargetIP[1], TargetIP[2], TargetIP[3]);
// define default gateway and DNS server Result = xn_set_ip(interface, TargetIP, NetMask);
xn_rt_add(RT_DEFAULT, ip_ffaddr, DefaultGateway, 1, interface, RT_INF); // define default gateway and DNS server
xn_set_server_list((DWORD*)DNSServer, 1); xn_rt_add(RT_DEFAULT, ip_ffaddr, DefaultGateway, 1, interface, RT_INF);
xn_set_server_list((DWORD *) DNSServer, 1);
#endif #endif
#else // HOST defined, run on Windows #else // HOST defined, run on Windows
WSADATA wd; WSADATA wd;
Result = WSAStartup(0x0101, &wd); Result = WSAStartup(0x0101, &wd);
#endif #endif
if (Result != 0) if (Result != 0)
Error("TCP/IP stack initialization failed"); Error("TCP/IP stack initialization failed");
} }
#endif #endif
bool bip_init(void) bool bip_init(void)
{ {
int rv = 0; // return from socket lib calls int rv = 0; // return from socket lib calls
struct sockaddr_in sin = {-1}; struct sockaddr_in sin = { -1 };
int value = 1; int value = 1;
int sock_fd = -1; int sock_fd = -1;
@@ -212,7 +218,7 @@ bool bip_init(void)
bip_set_address(TargetIP[0], TargetIP[1], TargetIP[2], TargetIP[3]); bip_set_address(TargetIP[0], TargetIP[1], TargetIP[2], TargetIP[3]);
// FIXME: // FIXME:
#if 0 #if 0
bip_set_address(NetMask[0], NetMask[1], NetMask[2], NetMask[3]); bip_set_address(NetMask[0], NetMask[1], NetMask[2], NetMask[3]);
extern unsigned long bip_get_addr(void); extern unsigned long bip_get_addr(void);
@@ -238,9 +244,8 @@ bool bip_init(void)
sin.sin_port = htons(bip_get_port()); sin.sin_port = htons(bip_get_port());
memset(&(sin.sin_zero), '\0', 8); memset(&(sin.sin_zero), '\0', 8);
rv = bind(sock_fd, rv = bind(sock_fd,
(const struct sockaddr*)&sin, sizeof(struct sockaddr)); (const struct sockaddr *) &sin, sizeof(struct sockaddr));
if (rv < 0) if (rv < 0) {
{
close(sock_fd); close(sock_fd);
bip_set_socket(-1); bip_set_socket(-1);
return false; return false;
+124 -152
View File
@@ -25,8 +25,8 @@
#include <stdint.h> // for standard integer types uint8_t etc. #include <stdint.h> // for standard integer types uint8_t etc.
#include <stdbool.h> // for the standard bool type. #include <stdbool.h> // for the standard bool type.
#include <stdio.h> // for the standard bool type. #include <stdio.h> // for the standard bool type.
#include <stdlib.h> // for the standard bool type. #include <stdlib.h> // for the standard bool type.
#include <rttarget.h> #include <rttarget.h>
#include <rtk32.h> #include <rtk32.h>
#include <clock.h> #include <clock.h>
@@ -40,6 +40,7 @@ uint8_t Ethernet_Broadcast[MAX_MAC_LEN] =
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
// commonly used empty address for ethernet quick compare // commonly used empty address for ethernet quick compare
uint8_t Ethernet_Empty_MAC[MAX_MAC_LEN] = { 0, 0, 0, 0, 0, 0 }; uint8_t Ethernet_Empty_MAC[MAX_MAC_LEN] = { 0, 0, 0, 0, 0, 0 };
// my local device data - MAC address // my local device data - MAC address
uint8_t Ethernet_MAC_Address[MAX_MAC_LEN] = { 0, 0, 0, 0, 0, 0 }; uint8_t Ethernet_MAC_Address[MAX_MAC_LEN] = { 0, 0, 0, 0, 0, 0 };
@@ -49,33 +50,33 @@ static struct sockaddr Ethernet_Address = { 0 };
bool ethernet_valid(void) bool ethernet_valid(void)
{ {
return (Ethernet_Socket != -1); return (Ethernet_Socket != -1);
} }
void ethernet_cleanup(void) void ethernet_cleanup(void)
{ {
if (ethernet_valid()) if (ethernet_valid())
closesocket(Ethernet_Socket); closesocket(Ethernet_Socket);
Ethernet_Socket = -1; Ethernet_Socket = -1;
return; return;
} }
bool ethernet_init(char *interface_name) bool ethernet_init(char *interface_name)
{ {
int value = 1; int value = 1;
(void)interface_name; (void) interface_name;
// setup the socket // setup the socket
Ethernet_Socket = socket(AF_INET, SOCK_RAW, 0); Ethernet_Socket = socket(AF_INET, SOCK_RAW, 0);
//Ethernet_Socket = socket(AF_INET, SOCK_STREAM, 0); //Ethernet_Socket = socket(AF_INET, SOCK_STREAM, 0);
if (Ethernet_Socket < 0) if (Ethernet_Socket < 0)
fprintf(stderr,"ethernet: failed to bind to socket!\r\n"); fprintf(stderr, "ethernet: failed to bind to socket!\r\n");
Ethernet_Address.sa_family = AF_INET; Ethernet_Address.sa_family = AF_INET;
memset(Ethernet_Address.sa_data,0,sizeof(Ethernet_Address.sa_data)); memset(Ethernet_Address.sa_data, 0, sizeof(Ethernet_Address.sa_data));
if (bind(Ethernet_Socket, if (bind(Ethernet_Socket,
&Ethernet_Address, sizeof(Ethernet_Address)) == SOCKET_ERROR) &Ethernet_Address, sizeof(Ethernet_Address)) == SOCKET_ERROR)
fprintf(stderr,"ethernet: failed to bind to socket!\r\n"); fprintf(stderr, "ethernet: failed to bind to socket!\r\n");
//setsockopt(Ethernet_Socket,SOL_SOCKET,SO_802_2,(char *)&value,sizeof(value)); //setsockopt(Ethernet_Socket,SOL_SOCKET,SO_802_2,(char *)&value,sizeof(value));
return ethernet_valid(); return ethernet_valid();
@@ -83,11 +84,10 @@ bool ethernet_init(char *interface_name)
/* function to send a packet out the 802.2 socket */ /* function to send a packet out the 802.2 socket */
/* returns bytes sent on success, negative number on failure */ /* returns bytes sent on success, negative number on failure */
int ethernet_send( int ethernet_send(BACNET_ADDRESS * dest, // destination address
BACNET_ADDRESS *dest, // destination address BACNET_ADDRESS * src, // source address
BACNET_ADDRESS *src, // source address 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
unsigned pdu_len) // number of bytes of data
{ {
int bytes = 0; int bytes = 0;
uint8_t mtu[MAX_MPDU] = { 0 }; uint8_t mtu[MAX_MPDU] = { 0 };
@@ -95,100 +95,86 @@ int ethernet_send(
int i = 0; int i = 0;
// don't waste time if the socket is not valid // don't waste time if the socket is not valid
if (Ethernet_Socket < 0) if (Ethernet_Socket < 0) {
{
fprintf(stderr, "ethernet: 802.2 socket is invalid!\n"); fprintf(stderr, "ethernet: 802.2 socket is invalid!\n");
return -1; return -1;
} }
/* load destination ethernet MAC address */ /* load destination ethernet MAC address */
if (dest->mac_len == 6) if (dest->mac_len == 6) {
{ for (i = 0; i < 6; i++) {
for (i = 0; i < 6; i++) mtu[mtu_len] = dest->mac[i];
{ mtu_len++;
mtu[mtu_len] = dest->mac[i]; }
mtu_len++; } else {
}
}
else
{
fprintf(stderr, "ethernet: invalid destination MAC address!\n"); fprintf(stderr, "ethernet: invalid destination MAC address!\n");
return -2; return -2;
} }
/* load source ethernet MAC address */ /* load source ethernet MAC address */
if (src->mac_len == 6) if (src->mac_len == 6) {
{ for (i = 0; i < 6; i++) {
for (i = 0; i < 6; i++) mtu[mtu_len] = src->mac[i];
{ mtu_len++;
mtu[mtu_len] = src->mac[i]; }
mtu_len++; } else {
}
}
else
{
fprintf(stderr, "ethernet: invalid source MAC address!\n"); fprintf(stderr, "ethernet: invalid source MAC address!\n");
return -3; return -3;
} }
if ((14 + 3 + pdu_len) > MAX_MPDU) if ((14 + 3 + pdu_len) > MAX_MPDU) {
{
fprintf(stderr, "ethernet: PDU is too big to send!\n"); fprintf(stderr, "ethernet: PDU is too big to send!\n");
return -4; return -4;
} }
/* packet length */ /* packet length */
mtu_len += encode_unsigned16(&mtu[12], mtu_len += encode_unsigned16(&mtu[12],
3 /*DSAP,SSAP,LLC*/ + pdu_len); 3 /*DSAP,SSAP,LLC */ + pdu_len);
// Logical PDU portion // Logical PDU portion
mtu[mtu_len++] = 0x82; /* DSAP for BACnet */ mtu[mtu_len++] = 0x82; /* DSAP for BACnet */
mtu[mtu_len++] = 0x82; /* SSAP for BACnet */ mtu[mtu_len++] = 0x82; /* SSAP for BACnet */
mtu[mtu_len++] = 0x03; /* Control byte in header */ mtu[mtu_len++] = 0x03; /* Control byte in header */
memcpy(&mtu[mtu_len], pdu, pdu_len); memcpy(&mtu[mtu_len], pdu, pdu_len);
mtu_len += pdu_len; mtu_len += pdu_len;
/* Send the packet */ /* Send the packet */
bytes = bytes = send(Ethernet_Socket, (const char *) &mtu, mtu_len, 0);
send(Ethernet_Socket, (const char *)&mtu, mtu_len, 0);
/* did it get sent? */ /* did it get sent? */
if (bytes < 0) if (bytes < 0)
fprintf(stderr,"ethernet: Error sending packet: %s\n", fprintf(stderr, "ethernet: Error sending packet: %s\n",
strerror(errno)); strerror(errno));
return bytes; return bytes;
} }
/* function to send a packet out the 802.2 socket */ /* function to send a packet out the 802.2 socket */
/* returns bytes sent on success, negative number on failure */ /* returns bytes sent on success, negative number on failure */
int ethernet_send_pdu( int ethernet_send_pdu(BACNET_ADDRESS * dest, // destination address
BACNET_ADDRESS *dest, // destination address 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
unsigned pdu_len) // number of bytes of data
{ {
int i = 0; // counter int i = 0; // counter
BACNET_ADDRESS src = {0}; // source address BACNET_ADDRESS src = { 0 }; // source address
for (i = 0; i < 6; i++) for (i = 0; i < 6; i++) {
{ src.mac[i] = Ethernet_MAC_Address[i];
src.mac[i] = Ethernet_MAC_Address[i]; src.mac_len++;
src.mac_len++; }
} /* function to send a packet out the 802.2 socket */
/* function to send a packet out the 802.2 socket */ /* returns 1 on success, 0 on failure */
/* returns 1 on success, 0 on failure */ return ethernet_send(dest, // destination address
return ethernet_send(dest, // destination address &src, // source address
&src, // source address pdu, // any data to be sent - may be null
pdu, // any data to be sent - may be null pdu_len); // number of bytes of data
pdu_len); // number of bytes of data
} }
// receives an 802.2 framed packet // receives an 802.2 framed packet
// returns the number of octets in the PDU, or zero on failure // returns the number of octets in the PDU, or zero on failure
uint16_t ethernet_receive( uint16_t ethernet_receive(BACNET_ADDRESS * src, // source address
BACNET_ADDRESS *src, // source address uint8_t * pdu, // PDU data
uint8_t *pdu, // PDU data uint16_t max_pdu, // amount of space available in the PDU
uint16_t max_pdu, // amount of space available in the PDU unsigned timeout) // number of milliseconds to wait for a packet
unsigned timeout) // number of milliseconds to wait for a packet
{ {
int received_bytes; int received_bytes;
uint8_t buf[MAX_MPDU] = {0}; // data uint8_t buf[MAX_MPDU] = { 0 }; // data
uint16_t pdu_len = 0; // return value uint16_t pdu_len = 0; // return value
fd_set read_fds; fd_set read_fds;
int max; int max;
struct timeval select_timeout; struct timeval select_timeout;
@@ -200,14 +186,11 @@ uint16_t ethernet_receive(
/* we could just use a non-blocking socket, but that consumes all /* we could just use a non-blocking socket, but that consumes all
the CPU time. We can use a timeout; it is only supported as the CPU time. We can use a timeout; it is only supported as
a select. */ a select. */
if (timeout >= 1000) if (timeout >= 1000) {
{
select_timeout.tv_sec = timeout / 1000; select_timeout.tv_sec = timeout / 1000;
select_timeout.tv_usec = select_timeout.tv_usec =
1000 * (timeout - select_timeout.tv_sec * 1000); 1000 * (timeout - select_timeout.tv_sec * 1000);
} } else {
else
{
select_timeout.tv_sec = 0; select_timeout.tv_sec = 0;
select_timeout.tv_usec = 1000 * timeout; select_timeout.tv_usec = 1000 * timeout;
} }
@@ -216,7 +199,8 @@ uint16_t ethernet_receive(
max = Ethernet_Socket; max = Ethernet_Socket;
if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0) 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 else
return 0; return 0;
@@ -226,13 +210,14 @@ uint16_t ethernet_receive(
// using O_NONBLOCK and no data // using O_NONBLOCK and no data
// was immediately available for reading. // was immediately available for reading.
if (errno != EAGAIN) if (errno != EAGAIN)
fprintf(stderr,"ethernet: Read error in receiving packet: %s\n", fprintf(stderr,
"ethernet: Read error in receiving packet: %s\n",
strerror(errno)); strerror(errno));
return 0; return 0;
} }
if (received_bytes == 0) if (received_bytes == 0)
return 0; return 0;
/* the signature of an 802.2 BACnet packet */ /* the signature of an 802.2 BACnet packet */
if ((buf[14] != 0x82) && (buf[15] != 0x82)) { if ((buf[14] != 0x82) && (buf[15] != 0x82)) {
@@ -245,108 +230,95 @@ uint16_t ethernet_receive(
// check destination address for when // check destination address for when
// the Ethernet card is in promiscious mode // the Ethernet card is in promiscious mode
if ((memcmp(&buf[0], Ethernet_MAC_Address,6) != 0) if ((memcmp(&buf[0], Ethernet_MAC_Address, 6) != 0)
&& (memcmp(&buf[0], Ethernet_Broadcast, 6) != 0)) && (memcmp(&buf[0], Ethernet_Broadcast, 6) != 0)) {
{
//fprintf(stderr, "ethernet: This packet isn't for us\n"); //fprintf(stderr, "ethernet: This packet isn't for us\n");
return 0; return 0;
} }
(void)decode_unsigned16(&buf[12],&pdu_len); (void) decode_unsigned16(&buf[12], &pdu_len);
pdu_len -= 3 /* DSAP, SSAP, LLC Control */ ; pdu_len -= 3 /* DSAP, SSAP, LLC Control */ ;
// copy the buffer into the PDU // copy the buffer into the PDU
if (pdu_len < max_pdu) if (pdu_len < max_pdu)
memmove(&pdu[0],&buf[17],pdu_len); memmove(&pdu[0], &buf[17], pdu_len);
// ignore packets that are too large // ignore packets that are too large
// client should check my max apdu first // client should check my max apdu first
else else
pdu_len = 0; pdu_len = 0;
return pdu_len; return pdu_len;
} }
void ethernet_get_my_address(BACNET_ADDRESS *my_address) void ethernet_get_my_address(BACNET_ADDRESS * my_address)
{ {
int i = 0; int i = 0;
my_address->mac_len = 0; my_address->mac_len = 0;
for (i = 0; i < 6; i++) for (i = 0; i < 6; i++) {
{ my_address->mac[i] = Ethernet_MAC_Address[i];
my_address->mac[i] = Ethernet_MAC_Address[i]; my_address->mac_len++;
my_address->mac_len++; }
} my_address->net = 0; // local only, no routing
my_address->net = 0; // local only, no routing my_address->len = 0;
my_address->len = 0; for (i = 0; i < MAX_MAC_LEN; i++) {
for (i = 0; i < MAX_MAC_LEN; i++) my_address->adr[i] = 0;
{ }
my_address->adr[i] = 0;
}
return; return;
} }
void ethernet_set_my_address(BACNET_ADDRESS *my_address) void ethernet_set_my_address(BACNET_ADDRESS * my_address)
{ {
int i = 0; int i = 0;
for (i = 0; i < 6; i++) for (i = 0; i < 6; i++) {
{ Ethernet_MAC_Address[i] = my_address->mac[i];
Ethernet_MAC_Address[i] = my_address->mac[i]; }
}
return; return;
} }
void ethernet_get_broadcast_address( void ethernet_get_broadcast_address(BACNET_ADDRESS * dest) // destination address
BACNET_ADDRESS *dest) // destination address
{ {
int i = 0; // counter int i = 0; // counter
if (dest) if (dest) {
{ for (i = 0; i < 6; i++) {
for (i = 0; i < 6; i++) dest->mac[i] = Ethernet_Broadcast[i];
{ }
dest->mac[i] = Ethernet_Broadcast[i]; dest->mac_len = 6;
dest->net = BACNET_BROADCAST_NETWORK;
dest->len = 0; // denotes broadcast address
for (i = 0; i < MAX_MAC_LEN; i++) {
dest->adr[i] = 0;
}
} }
dest->mac_len = 6;
dest->net = BACNET_BROADCAST_NETWORK;
dest->len = 0; // denotes broadcast address
for (i = 0; i < MAX_MAC_LEN; i++)
{
dest->adr[i] = 0;
}
}
return; return;
} }
void ethernet_debug_address( void ethernet_debug_address(const char *info, BACNET_ADDRESS * dest)
const char *info,
BACNET_ADDRESS *dest)
{ {
int i = 0; // counter int i = 0; // counter
if (info) if (info)
fprintf(stderr,"%s",info); fprintf(stderr, "%s", info);
if (dest) if (dest) {
{ fprintf(stderr, "Address:\n");
fprintf(stderr,"Address:\n"); fprintf(stderr, " MAC Length=%d\n", dest->mac_len);
fprintf(stderr," MAC Length=%d\n",dest->mac_len); fprintf(stderr, " MAC Address=");
fprintf(stderr," MAC Address="); for (i = 0; i < MAX_MAC_LEN; i++) {
for (i = 0; i < MAX_MAC_LEN; i++) fprintf(stderr, "%02X ", (unsigned) dest->mac[i]);
{ }
fprintf(stderr,"%02X ",(unsigned)dest->mac[i]); fprintf(stderr, "\n");
fprintf(stderr, " Net=%hu\n", dest->net);
fprintf(stderr, " Len=%d\n", dest->len);
fprintf(stderr, " Adr=");
for (i = 0; i < MAX_MAC_LEN; i++) {
fprintf(stderr, "%02X ", (unsigned) dest->adr[i]);
}
fprintf(stderr, "\n");
} }
fprintf(stderr,"\n");
fprintf(stderr," Net=%hu\n",dest->net);
fprintf(stderr," Len=%d\n",dest->len);
fprintf(stderr," Adr=");
for (i = 0; i < MAX_MAC_LEN; i++)
{
fprintf(stderr,"%02X ",(unsigned)dest->adr[i]);
}
fprintf(stderr,"\n");
}
return; return;
} }
+45 -49
View File
@@ -30,34 +30,33 @@
extern void RTEmuInit(void); extern void RTEmuInit(void);
#ifdef _MSC_VER #ifdef _MSC_VER
#define VOIDEXPORT _declspec(dllexport) void __cdecl #define VOIDEXPORT _declspec(dllexport) void __cdecl
#else #else
#define VOIDEXPORT void __export __cdecl #define VOIDEXPORT void __export __cdecl
#endif #endif
/* DISK SYSTEM */ /* DISK SYSTEM */
#ifdef DOC // include DiskOnChip driver #ifdef DOC // include DiskOnChip driver
#include <rtfiles.h> #include <rtfiles.h>
#define RTF_MAX_FILES 16 // support for more open files (default is 8) #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 #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 //#define READ_HEAD_BUFFER_SIZE 2048+4
//static BYTE ReadAheadBuffer[READ_HEAD_BUFFER_SIZE]; //static BYTE ReadAheadBuffer[READ_HEAD_BUFFER_SIZE];
static RTFDrvFLPYData FLPYDriveAData = {0}; static RTFDrvFLPYData FLPYDriveAData = { 0 };
static RTFDrvDOCData DOCDriveData = {0}; static RTFDrvDOCData DOCDriveData = { 0 };
static RTFDrvIDEData IDEDriveData = {0}; static RTFDrvIDEData IDEDriveData = { 0 };
RTFDevice RTFDeviceList[] = RTFDevice RTFDeviceList[] = {
{
/* type,number,flags,driver,driverdata */ /* type,number,flags,driver,driverdata */
{ RTF_DEVICE_FLOPPY, 0, 0, &RTFDrvFloppy, &FLPYDriveAData}, {RTF_DEVICE_FLOPPY, 0, 0, &RTFDrvFloppy, &FLPYDriveAData},
{ RTF_DEVICE_FDISK , 0, 0, &RTFDrvDOC, &DOCDriveData}, {RTF_DEVICE_FDISK, 0, 0, &RTFDrvDOC, &DOCDriveData},
{ RTF_DEVICE_FDISK , 0, 0, &RTFDrvIDE, &IDEDriveData}, {RTF_DEVICE_FDISK, 0, 0, &RTFDrvIDE, &IDEDriveData},
{ 0 , 0, 0, NULL, NULL} {0, 0, 0, NULL, NULL}
}; };
#endif #endif
/* END OF DISK SYSTEM */ /* END OF DISK SYSTEM */
@@ -67,14 +66,14 @@ extern void RTEmuInit(void);
#define MAXOBJECTS 1024 #define MAXOBJECTS 1024
#define MAXTYPES 32 #define MAXTYPES 32
RTW32Handle RTHandleTable[MAXHANDLES] = {{0}}; RTW32Handle RTHandleTable[MAXHANDLES] = { {0} };
int RTHandleCount = MAXHANDLES; int RTHandleCount = MAXHANDLES;
RTW32Object RTObjectTable[MAXOBJECTS] = {{0}}; RTW32Object RTObjectTable[MAXOBJECTS] = { {0} };
int RTObjectCount = MAXOBJECTS; int RTObjectCount = MAXOBJECTS;
RTW32Types RTTypeTable[MAXTYPES] = {{0}}; RTW32Types RTTypeTable[MAXTYPES] = { {0} };
int RTTypeCount = MAXTYPES; int RTTypeCount = MAXTYPES;
#if 0 #if 0
/* We can embed some files in the RTB file, like a binary /* We can embed some files in the RTB file, like a binary
@@ -85,44 +84,41 @@ int RTTypeCount = MAXTYPES;
that here, as well as the LPT, console, and FAT. that here, as well as the LPT, console, and FAT.
From RTFiles-32 manual, ch. 7, "Using RTFiles-32 with From RTFiles-32 manual, ch. 7, "Using RTFiles-32 with
RTTarget-32" */ RTTarget-32" */
RTFileSystem Console = RTFileSystem Console = { RT_FS_CONSOLE, 0, 0, &RTConsoleFileSystem };
{ RT_FS_CONSOLE, 0, 0, &RTConsoleFileSystem };
RTFileSystem LPTFiles = RTFileSystem LPTFiles = { RT_FS_LPT_DEVICE, 0, 0, &RTLPTFileSystem };
{ RT_FS_LPT_DEVICE, 0, 0, &RTLPTFileSystem };
/* logical drive Z: can be used to access the RAM drive */ /* logical drive Z: can be used to access the RAM drive */
RTFileSystem RAMFiles = RTFileSystem RAMFiles =
{ RT_FS_FILE,1 << ('Z'-'A'), 0, &RTRAMFileSystem }; { RT_FS_FILE, 1 << ('Z' - 'A'), 0, &RTRAMFileSystem };
/* logical drive A: through D: are reserved for FAT */ /* logical drive A: through D: are reserved for FAT */
RTFileSystem FATFiles = RTFileSystem FATFiles =
{ RT_FS_FILE | RT_FS_IS_DEFAULT, 0x0F, 0x03, &RTFilesFileSystem }; { RT_FS_FILE | RT_FS_IS_DEFAULT, 0x0F, 0x03, &RTFilesFileSystem };
RTFileSystem *RTFileSystemList[] = RTFileSystem *RTFileSystemList[] = {
{ &Console,
&Console, &LPTFiles,
&LPTFiles, &RAMFiles,
&RAMFiles, &FATFiles,
&FATFiles, NULL,
NULL,
}; };
#endif #endif
/*-----------------------------------*/ /*-----------------------------------*/
VOIDEXPORT Init(void) VOIDEXPORT Init(void)
{ {
(void)RTSetFlags(RT_MM_VIRTUAL, 1); // this is the better method (void) RTSetFlags(RT_MM_VIRTUAL, 1); // this is the better method
(void)RTCMOSExtendHeap(); // get as much memory as we can (void) RTCMOSExtendHeap(); // get as much memory as we can
RTCMOSSetSystemTime(); // get the right date and time 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 // pizza - RTHaltCPL3 appears to cause problems with file handling
//RTIdleHandler = (void RTTAPI *)RTHaltCPL3; // low power when idle //RTIdleHandler = (void RTTAPI *)RTHaltCPL3; // low power when idle
// not needed with pre-emptive // not needed with pre-emptive
//RTKTimeSlice(2); // allow same priority task switch //RTKTimeSlice(2); // allow same priority task switch
RTKConfig.Flags |= RF_PREEMPTIVE; // preemptive multitasking RTKConfig.Flags |= RF_PREEMPTIVE; // preemptive multitasking
RTKConfig.Flags |= RF_WIN32MUTEX_MUTEX; // Win32 mutexes are RTK32 mutexes RTKConfig.Flags |= RF_WIN32MUTEX_MUTEX; // Win32 mutexes are RTK32 mutexes
RTKConfig.Flags |= RF_FPCONTEXT; // saves floating point context for tasks RTKConfig.Flags |= RF_FPCONTEXT; // saves floating point context for tasks
RTKConfig.HookedIRQs |= 1 << 1; // hook the keyboard IRQ RTKConfig.HookedIRQs |= 1 << 1; // hook the keyboard IRQ
RTKConfig.DefaultTaskStackSize = 1024*8; // for Win32 task stacks req = 0 RTKConfig.DefaultTaskStackSize = 1024 * 8; // for Win32 task stacks req = 0
} }
+61 -74
View File
@@ -37,95 +37,82 @@
#include "net.h" #include "net.h"
// buffers used for transmit and receive // buffers used for transmit and receive
static uint8_t Rx_Buf[MAX_MPDU] = {0}; static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
#ifdef BACDL_MSTP #ifdef BACDL_MSTP
volatile struct mstp_port_struct_t MSTP_Port; // port data volatile struct mstp_port_struct_t MSTP_Port; // port data
static uint8_t MSTP_MAC_Address = 0x05; // local MAC address static uint8_t MSTP_MAC_Address = 0x05; // local MAC address
#endif #endif
static void Init_Service_Handlers(void) static void Init_Service_Handlers(void)
{ {
// we need to handle who-is to support dynamic device binding // we need to handle who-is to support dynamic device binding
apdu_set_unconfirmed_handler( apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, WhoIsHandler);
SERVICE_UNCONFIRMED_WHO_IS, // set the handler for all the services we don't implement
WhoIsHandler); // It is required to send the proper reject message...
// set the handler for all the services we don't implement apdu_set_unrecognized_service_handler_handler
// It is required to send the proper reject message... (UnrecognizedServiceHandler);
apdu_set_unrecognized_service_handler_handler( // we must implement read property - it's required!
UnrecognizedServiceHandler); apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY,
// we must implement read property - it's required! ReadPropertyHandler);
apdu_set_confirmed_handler( apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROPERTY,
SERVICE_CONFIRMED_READ_PROPERTY, WritePropertyHandler);
ReadPropertyHandler);
apdu_set_confirmed_handler(
SERVICE_CONFIRMED_WRITE_PROPERTY,
WritePropertyHandler);
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
BACNET_ADDRESS src = {0}; // address where message came from BACNET_ADDRESS src = { 0 }; // address where message came from
uint16_t pdu_len = 0; uint16_t pdu_len = 0;
unsigned timeout = 100; // milliseconds unsigned timeout = 100; // milliseconds
(void)argc; (void) argc;
(void)argv; (void) argv;
Device_Set_Object_Instance_Number(126); Device_Set_Object_Instance_Number(126);
Init_Service_Handlers(); Init_Service_Handlers();
// init the physical layer // init the physical layer
#ifdef BACDL_BIP #ifdef BACDL_BIP
if (!bip_init()) if (!bip_init())
return 1; return 1;
#endif #endif
#ifdef BACDL_ETHERNET #ifdef BACDL_ETHERNET
if (!ethernet_init(NULL)) if (!ethernet_init(NULL))
return 1; return 1;
#endif #endif
#ifdef BACDL_MSTP #ifdef BACDL_MSTP
RS485_Initialize(); RS485_Initialize();
MSTP_Init(&MSTP_Port,MSTP_MAC_Address); MSTP_Init(&MSTP_Port, MSTP_MAC_Address);
#endif #endif
// loop forever // loop forever
for (;;) for (;;) {
{ // input
// input #ifdef BACDL_MSTP
#ifdef BACDL_MSTP MSTP_Millisecond_Timer(&MSTP_Port);
MSTP_Millisecond_Timer(&MSTP_Port); // note: also called by RS-485 Receive ISR
// note: also called by RS-485 Receive ISR RS485_Check_UART_Data(&MSTP_Port);
RS485_Check_UART_Data(&MSTP_Port); MSTP_Receive_Frame_FSM(&MSTP_Port);
MSTP_Receive_Frame_FSM(&MSTP_Port); #endif
#endif
#if (defined(BACDL_ETHERNET) || defined(BACDL_BIP)) #if (defined(BACDL_ETHERNET) || defined(BACDL_BIP))
// returns 0 bytes on timeout // returns 0 bytes on timeout
pdu_len = bacdl_receive( pdu_len = bacdl_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout);
&src, #endif
&Rx_Buf[0],
MAX_MPDU,
timeout);
#endif
// process // process
if (pdu_len) if (pdu_len) {
{ npdu_handler(&src, &Rx_Buf[0], pdu_len);
npdu_handler( }
&src, if (I_Am_Request) {
&Rx_Buf[0], I_Am_Request = false;
pdu_len); Send_IAm();
}
// output
#ifdef BACDL_MSTP
MSTP_Master_Node_FSM(&MSTP_Port);
#endif
// blink LEDs, Turn on or off outputs, etc
} }
if (I_Am_Request)
{
I_Am_Request = false;
Send_IAm();
}
// output
#ifdef BACDL_MSTP
MSTP_Master_Node_FSM(&MSTP_Port);
#endif
// blink LEDs, Turn on or off outputs, etc
}
} }
+11 -11
View File
@@ -35,17 +35,17 @@
#include <process.h> #include <process.h>
#ifdef BACDL_BIP #ifdef BACDL_BIP
#include "bip.h" #include "bip.h"
#ifndef HOST #ifndef HOST
#include "netcfg.h" #include "netcfg.h"
#include <rttarget.h> #include <rttarget.h>
#include <rtk32.h> #include <rtk32.h>
#include <clock.h> #include <clock.h>
#include <socket.h> #include <socket.h>
#else #else
#include <winsock.h> #include <winsock.h>
#endif #endif
#define close closesocket #define close closesocket
#endif #endif
#endif #endif
+41 -41
View File
@@ -31,74 +31,74 @@
// #define AUTO_IP // use xn_autoip() to get an IP address // #define AUTO_IP // use xn_autoip() to get an IP address
// #define DHCP // if you enable this, you must also link library dhcpc.lib // #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 TargetIP[] = { 0, 0, 0, 0 }; // will be filled at run-time
static BYTE NetMask[] = {255, 255, 255, 0}; static BYTE NetMask[] = { 255, 255, 255, 0 };
static BYTE MinIP[] = {192, 168, 1, 128}; static BYTE MinIP[] = { 192, 168, 1, 128 };
static BYTE MaxIP[] = {192, 168, 1, 255}; static BYTE MaxIP[] = { 192, 168, 1, 255 };
static BYTE DefaultGateway[] = {192, 168, 1, 1}; // set to zero if not available or required static BYTE DefaultGateway[] = { 192, 168, 1, 1 }; // set to zero if not available or required
static BYTE DNSServer[] = {192, 168, 1, 1}; // ditto static BYTE DNSServer[] = { 192, 168, 1, 1 }; // ditto
#elif defined(DHCP) // use DHCP #elif defined(DHCP) // use DHCP
#include <dhcpcapi.h> #include <dhcpcapi.h>
static BYTE TargetIP[] = { 0, 0, 0, 0}; // will be filled at run-time 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 TargetIP[] = { 192, 168, 0, 50 };
static BYTE NetMask[] = {255, 255, 255, 0}; static BYTE NetMask[] = { 255, 255, 255, 0 };
static BYTE DefaultGateway[] = {192, 168, 0, 1}; // set to zero if not available or required static BYTE DefaultGateway[] = { 192, 168, 0, 1 }; // set to zero if not available or required
static BYTE DNSServer[] = {192, 168, 0, 1}; // ditto static BYTE DNSServer[] = { 192, 168, 0, 1 }; // ditto
#endif #endif
#define DEVICE_ID DAVICOM_DEVICE // define your device type here #define DEVICE_ID DAVICOM_DEVICE // define your device type here
#ifndef DEVICE_ID #ifndef DEVICE_ID
#error You must define Ethernet driver/resources and IP address/net mask here #error You must define Ethernet driver/resources and IP address/net mask here
#endif #endif
// The following values are ignored for PCI devices (the BIOS supplies // The following values are ignored for PCI devices (the BIOS supplies
// them), but they must be set correctly for ISA/PCMCIA systems and for // them), but they must be set correctly for ISA/PCMCIA systems and for
// PCI devices if you do not have a BIOS // PCI devices if you do not have a BIOS
#define ED_IO_ADD 0x300 // I/O address of the device #define ED_IO_ADD 0x300 // I/O address of the device
#define ED_IRQ 5 // IRQ of the device #define ED_IRQ 5 // IRQ of the device
#define ED_MEM_ADD 0 // Memory Window (only some devices) #define ED_MEM_ADD 0 // Memory Window (only some devices)
// Define function to pull in the required driver // Define function to pull in the required driver
#if DEVICE_ID == NE2000_DEVICE #if DEVICE_ID == NE2000_DEVICE
#define BIND_DRIVER xn_bind_ne2000 #define BIND_DRIVER xn_bind_ne2000
#elif DEVICE_ID == N83815_DEVICE #elif DEVICE_ID == N83815_DEVICE
#define BIND_DRIVER xn_bind_n83815 #define BIND_DRIVER xn_bind_n83815
#elif DEVICE_ID == TC90X_DEVICE #elif DEVICE_ID == TC90X_DEVICE
#define BIND_DRIVER xn_bind_tc90x #define BIND_DRIVER xn_bind_tc90x
#elif DEVICE_ID == SMC91C9X_DEVICE #elif DEVICE_ID == SMC91C9X_DEVICE
#define BIND_DRIVER xn_bind_smc91c9x #define BIND_DRIVER xn_bind_smc91c9x
#elif DEVICE_ID == LANCE_DEVICE #elif DEVICE_ID == LANCE_DEVICE
#define BIND_DRIVER xn_bind_rtlance #define BIND_DRIVER xn_bind_rtlance
#elif DEVICE_ID == LANCE_ISA_DEVICE #elif DEVICE_ID == LANCE_ISA_DEVICE
#define BIND_DRIVER xn_bind_lance_isa #define BIND_DRIVER xn_bind_lance_isa
#elif DEVICE_ID == LAN_CS89X0_DEVICE #elif DEVICE_ID == LAN_CS89X0_DEVICE
#define BIND_DRIVER xn_bind_cs #define BIND_DRIVER xn_bind_cs
#elif DEVICE_ID == I82559_DEVICE #elif DEVICE_ID == I82559_DEVICE
#define BIND_DRIVER xn_bind_i82559 #define BIND_DRIVER xn_bind_i82559
#elif DEVICE_ID == R8139_DEVICE #elif DEVICE_ID == R8139_DEVICE
#define BIND_DRIVER xn_bind_r8139 #define BIND_DRIVER xn_bind_r8139
#elif DEVICE_ID == DAVICOM_DEVICE #elif DEVICE_ID == DAVICOM_DEVICE
#define BIND_DRIVER xn_bind_davicom #define BIND_DRIVER xn_bind_davicom
#elif DEVICE_ID == RHINE_DEVICE #elif DEVICE_ID == RHINE_DEVICE
#define BIND_DRIVER xn_bind_rhine #define BIND_DRIVER xn_bind_rhine
#elif DEVICE_ID == AX172_DEVICE #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 #define BIND_DRIVER xn_bind_ax172
#elif DEVICE_ID == AX772_DEVICE #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 #define BIND_DRIVER xn_bind_ax772
#elif DEVICE_ID == PRISM_DEVICE #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 #define BIND_DRIVER xn_bind_prism
#elif DEVICE_ID == PRISM_PCMCIA_DEVICE #elif DEVICE_ID == PRISM_PCMCIA_DEVICE
#include <rtpcmcia.h> #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 #define BIND_DRIVER xn_bind_prism_pcmcia
#else #else
#error Invalid DEVICE_ID value #error Invalid DEVICE_ID value
#endif #endif
+75 -82
View File
@@ -44,118 +44,111 @@ static long RS485_Base = 0;
/* hardware IRQ number */ /* hardware IRQ number */
static long RS485_IRQ_Number = 0; static long RS485_IRQ_Number = 0;
static void RS485_Standard_Port_Settings(long port, long *pIRQ, long *pBase) static void RS485_Standard_Port_Settings(long port, long *pIRQ,
long *pBase)
{ {
switch (port) switch (port) {
{
case COM1: case COM1:
*pBase = (long)0x3F8; *pBase = (long) 0x3F8;
*pIRQ = 4L; *pIRQ = 4L;
break; break;
case COM2: case COM2:
*pBase = (long)0x2F8; *pBase = (long) 0x2F8;
*pIRQ = 3L; *pIRQ = 3L;
break; break;
case COM3: case COM3:
*pBase = (long)0x3E8; *pBase = (long) 0x3E8;
*pIRQ = 4L; *pIRQ = 4L;
break; break;
case COM4: case COM4:
*pBase = (long)0x2E8; *pBase = (long) 0x2E8;
*pIRQ = 3L; *pIRQ = 3L;
break; break;
default: default:
break; break;
} }
} }
static RS485_Open_Port( static RS485_Open_Port(int port, /* COM port number - COM1 = 0 */
int port, /* COM port number - COM1 = 0 */ long baud, /* baud rate */
long baud, /* baud rate */ unsigned base, /* io base address */
unsigned base, /* io base address */ int irq)
int irq) /* hardware IRQ number */ { /* hardware IRQ number */
{ /* setup the COM IO */
/* setup the COM IO */ SetIOBase(port, base);
SetIOBase(port, base); SetIRQ(port, irq);
SetIRQ(port, irq);
if (irq < 8) if (irq < 8)
RTKIRQTopPriority(irq,9); RTKIRQTopPriority(irq, 9);
InitPort(port, baud, PARITY_NONE, 1, 8); InitPort(port, baud, PARITY_NONE, 1, 8);
if (HasFIFO(port)) if (HasFIFO(port))
EnableFIFO(port,8); EnableFIFO(port, 8);
EnableCOMInterrupt(port, 1024*4); EnableCOMInterrupt(port, 1024 * 4);
/* enable the 485 via the DTR pin */ /* enable the 485 via the DTR pin */
RS485_IO_ENABLE(port); RS485_IO_ENABLE(port);
RS485_RECEIVE_ENABLE(port); RS485_RECEIVE_ENABLE(port);
return; return;
} }
void RS485_Initialize(void) void RS485_Initialize(void)
{ {
RS485_Standard_Port_Settings(RS485_Port, &RS485_IRQ_Number, &RS485_Base); RS485_Standard_Port_Settings(RS485_Port, &RS485_IRQ_Number,
RS485_Open_Port(RS485_Port, RS485_Baud, RS485_Base, RS485_IRQ_Number); &RS485_Base);
RS485_Open_Port(RS485_Port, RS485_Baud, RS485_Base, RS485_IRQ_Number);
} }
void RS485_Send_Frame( void RS485_Send_Frame(volatile struct mstp_port_struct_t *mstp_port, // port specific data
volatile struct mstp_port_struct_t *mstp_port, // port specific data uint8_t * buffer, // frame to send (up to 501 bytes of 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 nbytes) // number of bytes of data (up to 501)
{ {
bool status = true; // return value bool status = true; // return value
(void)mstp_port; (void) mstp_port;
RS485_TRANSMIT_ENABLE(RS485_Port); RS485_TRANSMIT_ENABLE(RS485_Port);
SendBlock(RS485_Port, (char *)buffer, nbytes); SendBlock(RS485_Port, (char *) buffer, nbytes);
/* need to wait at least 9600 baud * 512 bytes = 54mS */ /* need to wait at least 9600 baud * 512 bytes = 54mS */
(void)WaitSendBufferEmpty(RS485_Port,MilliSecsToTicks(200)); (void) WaitSendBufferEmpty(RS485_Port, MilliSecsToTicks(200));
while (!(LineStatus(RS485_Port) & TX_SHIFT_EMPTY)) while (!(LineStatus(RS485_Port) & TX_SHIFT_EMPTY))
RTKScheduler(); RTKScheduler();
RS485_RECEIVE_ENABLE(RS485_Port); RS485_RECEIVE_ENABLE(RS485_Port);
return; return;
} }
void RS485_Check_UART_Data( void RS485_Check_UART_Data(volatile struct mstp_port_struct_t *mstp_port) // port specific data
volatile struct mstp_port_struct_t *mstp_port) // port specific data
{ {
COMData com_data = 0; /* byte from COM driver */ COMData com_data = 0; /* byte from COM driver */
unsigned timeout = 10; // milliseconds to wait for a character unsigned timeout = 10; // milliseconds to wait for a character
Duration ticks; /* duration to wait for data */ Duration ticks; /* duration to wait for data */
if (mstp_port->ReceiveError) if (mstp_port->ReceiveError) {
{ // wait for state machine to clear this
// wait for state machine to clear this }
} // wait for state machine to read from the DataRegister
// wait for state machine to read from the DataRegister else if (!mstp_port->DataAvailable) {
else if (!mstp_port->DataAvailable) // check for data
{ ticks = MilliSecsToTicks(timeout);
// check for data if (!ticks)
ticks = MilliSecsToTicks(timeout); ticks = 1;
if (!ticks) if (RTKGetTimed(ReceiveBuffer[RS485_Port], &com_data, ticks)) {
ticks = 1; // if error,
if (RTKGetTimed(ReceiveBuffer[RS485_Port],&com_data,ticks)) if (com_data & (COM_OVERRUN << 8))
{ mstp_port->ReceiveError = true;
// if error, else if (com_data & (COM_FRAME << 8))
if (com_data & (COM_OVERRUN << 8)) mstp_port->ReceiveError = true;
mstp_port->ReceiveError = true; else {
else if (com_data & (COM_FRAME << 8)) mstp_port->DataRegister = com_data & 0x00FF;
mstp_port->ReceiveError = true; mstp_port->DataAvailable = true;
else }
{ }
mstp_port->DataRegister = com_data & 0x00FF;
mstp_port->DataAvailable = true;
}
} }
}
} }
void RS485_Process_Tx_Message(void) void RS485_Process_Tx_Message(void)
{ {
// nothing to do // nothing to do
} }
+13 -13
View File
@@ -4,25 +4,25 @@
// C99 Boolean types for compilers without C99 support // C99 Boolean types for compilers without C99 support
#ifndef __cplusplus #ifndef __cplusplus
typedef int _Bool; typedef int _Bool;
#ifndef bool #ifndef bool
#define bool _Bool #define bool _Bool
#endif #endif
#ifndef true #ifndef true
#define true 1 #define true 1
#endif #endif
#ifndef false #ifndef false
#define false 0 #define false 0
#endif #endif
#define __bool_true_false_are_defined 1 #define __bool_true_false_are_defined 1
#endif #endif
#ifndef FALSE #ifndef FALSE
#define FALSE 0 #define FALSE 0
#endif #endif
#ifndef TRUE #ifndef TRUE
#define TRUE 1 #define TRUE 1
#endif #endif
#endif #endif
+7 -7
View File
@@ -6,14 +6,14 @@
#include <stddef.h> #include <stddef.h>
typedef unsigned char uint8_t; // 1 byte 0 to 255 typedef unsigned char uint8_t; // 1 byte 0 to 255
typedef signed char int8_t; // 1 byte -127 to 127 typedef signed char int8_t; // 1 byte -127 to 127
typedef unsigned short uint16_t; // 2 bytes 0 to 65535 typedef unsigned short uint16_t; // 2 bytes 0 to 65535
typedef signed short int16_t; // 2 bytes -32767 to 32767 typedef signed short int16_t; // 2 bytes -32767 to 32767
//typedef unsigned short long uint24_t; // 3 bytes 0 to 16777215 //typedef unsigned short long uint24_t; // 3 bytes 0 to 16777215
typedef unsigned long uint32_t; // 4 bytes 0 to 4294967295 typedef unsigned long uint32_t; // 4 bytes 0 to 4294967295
typedef signed long int32_t; // 4 bytes -2147483647 to 2147483647 typedef signed long int32_t; // 4 bytes -2147483647 to 2147483647
// typedef signed long long int64_t; // typedef signed long long int64_t;
// typedef unsigned long long uint64_t; // typedef unsigned long long uint64_t;
#endif // STDINT_H #endif // STDINT_H
+74 -81
View File
@@ -37,8 +37,8 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> // for standard integer types uint8_t etc. #include <stdint.h> // for standard integer types uint8_t etc.
#include <stdbool.h> // for the standard bool type. #include <stdbool.h> // for the standard bool type.
#include "bacdcode.h" #include "bacdcode.h"
#include "bip.h" #include "bip.h"
#include "net.h" #include "net.h"
@@ -46,60 +46,64 @@
/* To fill a need, we invent the gethostaddr() function. */ /* To fill a need, we invent the gethostaddr() function. */
static long gethostaddr(void) static long gethostaddr(void)
{ {
struct hostent *host_ent; struct hostent *host_ent;
char host_name[255]; char host_name[255];
if (gethostname(host_name, sizeof(host_name)) != 0) if (gethostname(host_name, sizeof(host_name)) != 0)
return -1; return -1;
#ifdef BIP_DEBUG #ifdef BIP_DEBUG
printf("host name: %s\n",host_name); printf("host name: %s\n", host_name);
#endif #endif
if ((host_ent = gethostbyname(host_name)) == NULL) if ((host_ent = gethostbyname(host_name)) == NULL)
return -1; return -1;
return *(long *)host_ent->h_addr; return *(long *) host_ent->h_addr;
} }
static void set_broadcast_address(uint32_t net_address) static void set_broadcast_address(uint32_t net_address)
{ {
long broadcast_address = 0; long broadcast_address = 0;
long mask = 0; long mask = 0;
/* Note: sometimes INADDR_BROADCAST does not let me get /* Note: sometimes INADDR_BROADCAST does not let me get
any unicast messages. Not sure why... */ any unicast messages. Not sure why... */
#if USE_INADDR #if USE_INADDR
(void)net_address; (void) net_address;
bip_set_broadcast_addr(INADDR_BROADCAST); bip_set_broadcast_addr(INADDR_BROADCAST);
#else #else
if (IN_CLASSA(ntohl(net_address))) if (IN_CLASSA(ntohl(net_address)))
broadcast_address = (ntohl(net_address) & ~IN_CLASSA_HOST) | IN_CLASSA_HOST; broadcast_address =
else if (IN_CLASSB(ntohl(net_address))) (ntohl(net_address) & ~IN_CLASSA_HOST) | IN_CLASSA_HOST;
broadcast_address = (ntohl(net_address) & ~IN_CLASSB_HOST) | IN_CLASSB_HOST; else if (IN_CLASSB(ntohl(net_address)))
else if (IN_CLASSC(ntohl(net_address))) broadcast_address =
broadcast_address = (ntohl(net_address) & ~IN_CLASSC_HOST) | IN_CLASSC_HOST; (ntohl(net_address) & ~IN_CLASSB_HOST) | IN_CLASSB_HOST;
else if (IN_CLASSD(ntohl(net_address))) else if (IN_CLASSC(ntohl(net_address)))
broadcast_address = (ntohl(net_address) & ~IN_CLASSD_HOST) | IN_CLASSD_HOST; broadcast_address =
else (ntohl(net_address) & ~IN_CLASSC_HOST) | IN_CLASSC_HOST;
broadcast_address = INADDR_BROADCAST; else if (IN_CLASSD(ntohl(net_address)))
bip_set_broadcast_addr(htonl(broadcast_address)); broadcast_address =
#endif (ntohl(net_address) & ~IN_CLASSD_HOST) | IN_CLASSD_HOST;
else
broadcast_address = INADDR_BROADCAST;
bip_set_broadcast_addr(htonl(broadcast_address));
#endif
} }
static void cleanup(void) static void cleanup(void)
{ {
WSACleanup(); WSACleanup();
} }
void bip_set_interface(char *ifname) void bip_set_interface(char *ifname)
{ {
(void)ifname; (void) ifname;
/* dummy function */ /* dummy function */
} }
bool bip_init(void) bool bip_init(void)
{ {
int rv = 0; // return from socket lib calls int rv = 0; // return from socket lib calls
struct sockaddr_in sin = {-1}; struct sockaddr_in sin = { -1 };
int value = 1; int value = 1;
int sock_fd = -1; int sock_fd = -1;
int Result; int Result;
@@ -109,63 +113,55 @@ bool bip_init(void)
Result = WSAStartup((1 << 8) | 1, &wd); Result = WSAStartup((1 << 8) | 1, &wd);
//Result = WSAStartup(MAKEWORD(2,2), &wd); //Result = WSAStartup(MAKEWORD(2,2), &wd);
if (Result != 0) if (Result != 0) {
{ Code = WSAGetLastError();
Code = WSAGetLastError(); printf("TCP/IP stack initialization failed, error code: %i\n",
printf("TCP/IP stack initialization failed, error code: %i\n", Code);
Code); exit(1);
exit(1);
} }
atexit(cleanup); atexit(cleanup);
address.s_addr = gethostaddr(); address.s_addr = gethostaddr();
if (address.s_addr == (unsigned)-1) if (address.s_addr == (unsigned) -1) {
{ Code = WSAGetLastError();
Code = WSAGetLastError(); printf("Get host address failed, error code: %i\n", Code);
printf("Get host address failed, error code: %i\n", exit(1);
Code);
exit(1);
} }
#ifdef BIP_DEBUG #ifdef BIP_DEBUG
printf("host address: %s\n",inet_ntoa(address)); printf("host address: %s\n", inet_ntoa(address));
#endif #endif
bip_set_addr(address.s_addr); bip_set_addr(address.s_addr);
set_broadcast_address(address.s_addr); set_broadcast_address(address.s_addr);
/* assumes that the driver has already been initialized */ /* assumes that the driver has already been initialized */
sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
bip_set_socket(sock_fd); bip_set_socket(sock_fd);
if (sock_fd < 0) if (sock_fd < 0) {
{ fprintf(stderr, "bip: failed to allocate a socket.\n");
fprintf(stderr,"bip: failed to allocate a socket.\n"); return false;
return false;
} }
// Allow us to use the same socket for sending and receiving // Allow us to use the same socket for sending and receiving
// This makes sure that the src port is correct when sending // This makes sure that the src port is correct when sending
rv = setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, rv = setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
(char *)&value, sizeof(value)); (char *) &value, sizeof(value));
if (rv < 0) if (rv < 0) {
{ fprintf(stderr, "bip: failed to set REUSEADDR socket option.\n");
fprintf(stderr,"bip: failed to set REUSEADDR socket option.\n"); close(sock_fd);
close(sock_fd); bip_set_socket(-1);
bip_set_socket(-1); return false;
return false;
} }
// allow us to send a broadcast // allow us to send a broadcast
rv = setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, rv = setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST,
(char *)&value, sizeof(value)); (char *) &value, sizeof(value));
if (rv < 0) if (rv < 0) {
{ fprintf(stderr, "bip: failed to set BROADCAST socket option.\n");
fprintf(stderr,"bip: failed to set BROADCAST socket option.\n"); close(sock_fd);
close(sock_fd); bip_set_socket(-1);
bip_set_socket(-1); return false;
return false;
} }
// bind the socket to the local port number and IP address // bind the socket to the local port number and IP address
sin.sin_family = AF_INET; sin.sin_family = AF_INET;
#if USE_INADDR #if USE_INADDR
/* by setting sin.sin_addr.s_addr to INADDR_ANY, /* by setting sin.sin_addr.s_addr to INADDR_ANY,
I am telling the IP stack to automatically fill I am telling the IP stack to automatically fill
in the IP address of the machine the process in the IP address of the machine the process
@@ -182,20 +178,18 @@ bool bip_init(void)
Note: sometimes INADDR_ANY does not let me get Note: sometimes INADDR_ANY does not let me get
any unicast messages. Not sure why... */ any unicast messages. Not sure why... */
sin.sin_addr.s_addr = htonl(INADDR_ANY); sin.sin_addr.s_addr = htonl(INADDR_ANY);
#else #else
/* or we could use the specific adapter address /* or we could use the specific adapter address
note: already in network byte order */ note: already in network byte order */
sin.sin_addr.s_addr = address.s_addr; sin.sin_addr.s_addr = address.s_addr;
#endif #endif
sin.sin_port = htons(bip_get_port()); sin.sin_port = htons(bip_get_port());
memset(&(sin.sin_zero), '\0', sizeof(sin.sin_zero)); memset(&(sin.sin_zero), '\0', sizeof(sin.sin_zero));
rv = bind(sock_fd, rv = bind(sock_fd,
(const struct sockaddr*)&sin, sizeof(struct sockaddr)); (const struct sockaddr *) &sin, sizeof(struct sockaddr));
if (rv < 0) if (rv < 0) {
{ fprintf(stderr, "bip: failed to bind to %s port %hd\n",
fprintf(stderr,"bip: failed to bind to %s port %hd\n", inet_ntoa(sin.sin_addr), bip_get_port());
inet_ntoa(sin.sin_addr),
bip_get_port());
close(sock_fd); close(sock_fd);
bip_set_socket(-1); bip_set_socket(-1);
return false; return false;
@@ -203,4 +197,3 @@ bool bip_init(void)
return true; return true;
} }
+174 -217
View File
@@ -29,7 +29,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <conio.h> /* for kbhit and getch */ #include <conio.h> /* for kbhit and getch */
#include "iam.h" #include "iam.h"
#include "address.h" #include "address.h"
#include "config.h" #include "config.h"
@@ -43,262 +43,219 @@
#include "txbuf.h" #include "txbuf.h"
// buffer used for receive // buffer used for receive
static uint8_t Rx_Buf[MAX_MPDU] = {0}; static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
/* send a whois to see who is on the network */ /* send a whois to see who is on the network */
static bool Who_Is_Request = true; static bool Who_Is_Request = true;
static void Read_Properties(void) static void Read_Properties(void)
{ {
uint32_t device_id = 0; uint32_t device_id = 0;
bool status = false; bool status = false;
unsigned max_apdu = 0; unsigned max_apdu = 0;
BACNET_ADDRESS src; BACNET_ADDRESS src;
bool next_device = false; bool next_device = false;
static unsigned index = 0; static unsigned index = 0;
static unsigned property = 0; static unsigned property = 0;
/* list of required (and some optional) properties in the /* list of required (and some optional) properties in the
Device Object Device Object
note: you could just loop through note: you could just loop through
all the properties in all the objects. */ all the properties in all the objects. */
const int object_props[] = const int object_props[] = {
{ PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME,
PROP_OBJECT_NAME, PROP_OBJECT_TYPE,
PROP_OBJECT_TYPE, PROP_SYSTEM_STATUS,
PROP_SYSTEM_STATUS, PROP_VENDOR_NAME,
PROP_VENDOR_NAME, PROP_VENDOR_IDENTIFIER,
PROP_VENDOR_IDENTIFIER, PROP_MODEL_NAME,
PROP_MODEL_NAME, PROP_FIRMWARE_REVISION,
PROP_FIRMWARE_REVISION, PROP_APPLICATION_SOFTWARE_VERSION,
PROP_APPLICATION_SOFTWARE_VERSION, PROP_PROTOCOL_VERSION,
PROP_PROTOCOL_VERSION, PROP_PROTOCOL_CONFORMANCE_CLASS,
PROP_PROTOCOL_CONFORMANCE_CLASS, PROP_PROTOCOL_SERVICES_SUPPORTED,
PROP_PROTOCOL_SERVICES_SUPPORTED, PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED,
PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED, PROP_MAX_APDU_LENGTH_ACCEPTED,
PROP_MAX_APDU_LENGTH_ACCEPTED, PROP_SEGMENTATION_SUPPORTED,
PROP_SEGMENTATION_SUPPORTED, PROP_LOCAL_TIME,
PROP_LOCAL_TIME, PROP_LOCAL_DATE,
PROP_LOCAL_DATE, PROP_UTC_OFFSET,
PROP_UTC_OFFSET, PROP_DAYLIGHT_SAVINGS_STATUS,
PROP_DAYLIGHT_SAVINGS_STATUS, PROP_APDU_SEGMENT_TIMEOUT,
PROP_APDU_SEGMENT_TIMEOUT, PROP_APDU_TIMEOUT,
PROP_APDU_TIMEOUT, PROP_NUMBER_OF_APDU_RETRIES,
PROP_NUMBER_OF_APDU_RETRIES, PROP_TIME_SYNCHRONIZATION_RECIPIENTS,
PROP_TIME_SYNCHRONIZATION_RECIPIENTS, PROP_MAX_MASTER,
PROP_MAX_MASTER, PROP_MAX_INFO_FRAMES,
PROP_MAX_INFO_FRAMES, PROP_DEVICE_ADDRESS_BINDING,
PROP_DEVICE_ADDRESS_BINDING, /* note: PROP_OBJECT_LIST is missing cause
/* note: PROP_OBJECT_LIST is missing cause we need to get it with an index method since
we need to get it with an index method since the list could be very large */
the list could be very large */ /* some proprietary properties */
/* some proprietary properties */ 514, 515,
514,515, /* end of list */
/* end of list */ -1
-1 };
};
if (address_count()) if (address_count()) {
{ if (address_get_by_index(index, &device_id, &max_apdu, &src)) {
if (address_get_by_index(index, &device_id, &max_apdu, &src)) if (object_props[property] < 0)
{ next_device = true;
if (object_props[property] < 0) else {
next_device = true; status = Send_Read_Property_Request(device_id, // destination device
else OBJECT_DEVICE,
{ device_id, object_props[property], BACNET_ARRAY_ALL);
status = Send_Read_Property_Request( if (status)
device_id, // destination device property++;
OBJECT_DEVICE, }
device_id, } else
object_props[property], next_device = true;
BACNET_ARRAY_ALL); if (next_device) {
if (status) next_device = false;
property++; index++;
} if (index >= MAX_ADDRESS_CACHE)
index = 0;
property = 0;
}
} }
else
next_device = true;
if (next_device)
{
next_device = false;
index++;
if (index >= MAX_ADDRESS_CACHE)
index = 0;
property = 0;
}
}
return; return;
} }
static void LocalIAmHandler( static void LocalIAmHandler(uint8_t * service_request,
uint8_t *service_request, uint16_t service_len, BACNET_ADDRESS * src)
uint16_t service_len,
BACNET_ADDRESS *src)
{ {
int len = 0; int len = 0;
uint32_t device_id = 0; uint32_t device_id = 0;
unsigned max_apdu = 0; unsigned max_apdu = 0;
int segmentation = 0; int segmentation = 0;
uint16_t vendor_id = 0; uint16_t vendor_id = 0;
(void)src; (void) src;
(void)service_len; (void) service_len;
len = iam_decode_service_request( len = iam_decode_service_request(service_request,
service_request, &device_id, &max_apdu, &segmentation, &vendor_id);
&device_id, fprintf(stderr, "Received I-Am Request");
&max_apdu, if (len != -1) {
&segmentation, fprintf(stderr, " from %u!\n", device_id);
&vendor_id); address_add(device_id, max_apdu, src);
fprintf(stderr,"Received I-Am Request"); } else
if (len != -1) fprintf(stderr, "!\n");
{
fprintf(stderr," from %u!\n",device_id);
address_add(device_id,
max_apdu,
src);
}
else
fprintf(stderr,"!\n");
return; return;
} }
static void Init_Service_Handlers(void) static void Init_Service_Handlers(void)
{ {
// we need to handle who-is to support dynamic device binding // we need to handle who-is to support dynamic device binding
apdu_set_unconfirmed_handler( apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS,
SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
handler_who_is); apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_I_AM,
apdu_set_unconfirmed_handler( LocalIAmHandler);
SERVICE_UNCONFIRMED_I_AM,
LocalIAmHandler);
// set the handler for all the services we don't implement // set the handler for all the services we don't implement
// It is required to send the proper reject message... // It is required to send the proper reject message...
apdu_set_unrecognized_service_handler_handler( apdu_set_unrecognized_service_handler_handler
handler_unrecognized_service); (handler_unrecognized_service);
// we must implement read property - it's required! // we must implement read property - it's required!
apdu_set_confirmed_handler( apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY,
SERVICE_CONFIRMED_READ_PROPERTY, handler_read_property);
handler_read_property); apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROPERTY,
apdu_set_confirmed_handler( handler_write_property);
SERVICE_CONFIRMED_WRITE_PROPERTY, // handle the data coming back from confirmed requests
handler_write_property); apdu_set_confirmed_ack_handler(SERVICE_CONFIRMED_READ_PROPERTY,
// handle the data coming back from confirmed requests handler_read_property_ack);
apdu_set_confirmed_ack_handler(
SERVICE_CONFIRMED_READ_PROPERTY,
handler_read_property_ack);
} }
static void print_address( static void print_address(char *name, BACNET_ADDRESS * dest) // destination address
char *name,
BACNET_ADDRESS *dest) // destination address
{ {
int i = 0; // counter int i = 0; // counter
if (dest) if (dest) {
{ printf("%s: ", name);
printf("%s: ",name); for (i = 0; i < dest->mac_len; i++) {
for (i = 0; i < dest->mac_len; i++) printf("%02X", dest->mac[i]);
{ }
printf("%02X",dest->mac[i]); printf("\n");
} }
printf("\n");
}
} }
static void print_address_cache(void) static void print_address_cache(void)
{ {
int i,j; int i, j;
BACNET_ADDRESS address; BACNET_ADDRESS address;
uint32_t device_id = 0; uint32_t device_id = 0;
unsigned max_apdu = 0; unsigned max_apdu = 0;
fprintf(stderr,"Device\tMAC\tMaxAPDU\tNet\n"); fprintf(stderr, "Device\tMAC\tMaxAPDU\tNet\n");
for (i = 0; i < MAX_ADDRESS_CACHE; i++) for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
{ if (address_get_by_index(i, &device_id, &max_apdu, &address)) {
if (address_get_by_index(i,&device_id, &max_apdu, &address)) fprintf(stderr, "%u\t", device_id);
{ for (j = 0; j < address.mac_len; j++) {
fprintf(stderr,"%u\t",device_id); fprintf(stderr, "%02X", address.mac[j]);
for (j = 0; j < address.mac_len; j++) }
{ fprintf(stderr, "\t");
fprintf(stderr,"%02X",address.mac[j]); fprintf(stderr, "%hu\t", max_apdu);
} fprintf(stderr, "%hu\n", address.net);
fprintf(stderr,"\t"); }
fprintf(stderr,"%hu\t",max_apdu);
fprintf(stderr,"%hu\n",address.net);
} }
}
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
BACNET_ADDRESS src = {0}; // address where message came from BACNET_ADDRESS src = { 0 }; // address where message came from
uint16_t pdu_len = 0; uint16_t pdu_len = 0;
unsigned timeout = 100; // milliseconds unsigned timeout = 100; // milliseconds
BACNET_ADDRESS my_address, broadcast_address; BACNET_ADDRESS my_address, broadcast_address;
(void)argc; (void) argc;
(void)argv; (void) argv;
Device_Set_Object_Instance_Number(124); Device_Set_Object_Instance_Number(124);
Init_Service_Handlers(); Init_Service_Handlers();
// init the data link layer // init the data link layer
/* configure standard BACnet/IP port */ /* configure standard BACnet/IP port */
bip_set_port(0xBAC0); bip_set_port(0xBAC0);
if (!bip_init()) if (!bip_init())
return 1; return 1;
datalink_get_broadcast_address(&broadcast_address); datalink_get_broadcast_address(&broadcast_address);
print_address("Broadcast",&broadcast_address); print_address("Broadcast", &broadcast_address);
datalink_get_my_address(&my_address); datalink_get_my_address(&my_address);
print_address("Address",&my_address); print_address("Address", &my_address);
printf("BACnet stack running...\n"); printf("BACnet stack running...\n");
// loop forever // loop forever
for (;;) for (;;) {
{ // input
// input
// returns 0 bytes on timeout // returns 0 bytes on timeout
pdu_len = bip_receive( pdu_len = bip_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout);
&src,
&Rx_Buf[0],
MAX_MPDU,
timeout);
// process // process
if (pdu_len) if (pdu_len) {
{ npdu_handler(&src, &Rx_Buf[0], pdu_len);
npdu_handler( }
&src, if (I_Am_Request) {
&Rx_Buf[0], I_Am_Request = false;
pdu_len); iam_send(&Handler_Transmit_Buffer[0]);
} } else if (Who_Is_Request) {
if (I_Am_Request) Who_Is_Request = false;
{ Send_WhoIs(-1, -1);
I_Am_Request = false; } else {
iam_send(&Handler_Transmit_Buffer[0]); Read_Properties();
} else if (Who_Is_Request) }
{
Who_Is_Request = false; // output
Send_WhoIs(-1,-1);
} // blink LEDs, Turn on or off outputs, etc
else
{ /* wait for ESC from keyboard before quitting */
Read_Properties(); if (kbhit() && (getch() == 0x1B))
break;
} }
// output print_address_cache();
// blink LEDs, Turn on or off outputs, etc return 0;
/* wait for ESC from keyboard before quitting */
if (kbhit() && (getch() == 0x1B))
break;
}
print_address_cache();
return 0;
} }
+13 -13
View File
@@ -4,25 +4,25 @@
// C99 Boolean types for compilers without C99 support // C99 Boolean types for compilers without C99 support
#ifndef __cplusplus #ifndef __cplusplus
typedef int _Bool; typedef int _Bool;
#ifndef bool #ifndef bool
#define bool _Bool #define bool _Bool
#endif #endif
#ifndef true #ifndef true
#define true 1 #define true 1
#endif #endif
#ifndef false #ifndef false
#define false 0 #define false 0
#endif #endif
#define __bool_true_false_are_defined 1 #define __bool_true_false_are_defined 1
#endif #endif
#ifndef FALSE #ifndef FALSE
#define FALSE 0 #define FALSE 0
#endif #endif
#ifndef TRUE #ifndef TRUE
#define TRUE 1 #define TRUE 1
#endif #endif
#endif #endif
+7 -7
View File
@@ -6,14 +6,14 @@
#include <stddef.h> #include <stddef.h>
typedef unsigned char uint8_t; // 1 byte 0 to 255 typedef unsigned char uint8_t; // 1 byte 0 to 255
typedef signed char int8_t; // 1 byte -127 to 127 typedef signed char int8_t; // 1 byte -127 to 127
typedef unsigned short uint16_t; // 2 bytes 0 to 65535 typedef unsigned short uint16_t; // 2 bytes 0 to 65535
typedef signed short int16_t; // 2 bytes -32767 to 32767 typedef signed short int16_t; // 2 bytes -32767 to 32767
//typedef unsigned short long uint24_t; // 3 bytes 0 to 16777215 //typedef unsigned short long uint24_t; // 3 bytes 0 to 16777215
typedef unsigned long uint32_t; // 4 bytes 0 to 4294967295 typedef unsigned long uint32_t; // 4 bytes 0 to 4294967295
typedef signed long int32_t; // 4 bytes -2147483647 to 2147483647 typedef signed long int32_t; // 4 bytes -2147483647 to 2147483647
// typedef signed long long int64_t; // typedef signed long long int64_t;
// typedef unsigned long long uint64_t; // typedef unsigned long long uint64_t;
#endif // STDINT_H #endif // STDINT_H