Fixed line endings, and set EOL properties.

This commit is contained in:
skarg
2008-12-05 21:26:24 +00:00
parent fa1d2b4fdc
commit 980f0145be
13 changed files with 2035 additions and 2030 deletions
+3 -3
View File
@@ -50,7 +50,7 @@ void npdu_handler(
/*FIXME: network layer message received! Handle it! */ /*FIXME: network layer message received! Handle it! */
#if PRINT_ENABLED #if PRINT_ENABLED
printf("NPDU: Network Layer Message discarded!\n"); printf("NPDU: Network Layer Message discarded!\n");
#endif #endif
} else if ((apdu_offset > 0) && (apdu_offset <= pdu_len)) { } else if ((apdu_offset > 0) && (apdu_offset <= pdu_len)) {
if ((npdu_data.protocol_version == BACNET_PROTOCOL_VERSION) && if ((npdu_data.protocol_version == BACNET_PROTOCOL_VERSION) &&
((dest.net == 0) || (dest.net == BACNET_BROADCAST_NETWORK))) { ((dest.net == 0) || (dest.net == BACNET_BROADCAST_NETWORK))) {
@@ -62,12 +62,12 @@ void npdu_handler(
} else { } else {
if (dest.net) { if (dest.net) {
#if PRINT_ENABLED #if PRINT_ENABLED
printf("NPDU: DNET=%d. Discarded!\n", dest.net); printf("NPDU: DNET=%d. Discarded!\n", dest.net);
#endif #endif
} else { } else {
#if PRINT_ENABLED #if PRINT_ENABLED
printf("NPDU: BACnet Protocol Version=%d. Discarded!\n", printf("NPDU: BACnet Protocol Version=%d. Discarded!\n",
npdu_data.protocol_version); npdu_data.protocol_version);
#endif #endif
} }
} }
+55 -55
View File
@@ -23,7 +23,7 @@
* *
*********************************************************************/ *********************************************************************/
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include "config.h" #include "config.h"
#include "config.h" #include "config.h"
@@ -51,14 +51,14 @@ static int rpm_ack_decode_service_request(
{ {
int decoded_len = 0; /* return value */ int decoded_len = 0; /* return value */
int len = 0; /* number of bytes returned from decoding */ int len = 0; /* number of bytes returned from decoding */
uint8_t tag_number = 0; /* decoded tag number */ uint8_t tag_number = 0; /* decoded tag number */
uint32_t len_value = 0; /* decoded length value */ uint32_t len_value = 0; /* decoded length value */
BACNET_READ_ACCESS_DATA *rpm_object; BACNET_READ_ACCESS_DATA *rpm_object;
BACNET_READ_ACCESS_DATA *old_rpm_object; BACNET_READ_ACCESS_DATA *old_rpm_object;
BACNET_PROPERTY_REFERENCE *rpm_property; BACNET_PROPERTY_REFERENCE *rpm_property;
BACNET_PROPERTY_REFERENCE *old_rpm_property; BACNET_PROPERTY_REFERENCE *old_rpm_property;
BACNET_APPLICATION_DATA_VALUE *value; BACNET_APPLICATION_DATA_VALUE *value;
BACNET_APPLICATION_DATA_VALUE *old_value; BACNET_APPLICATION_DATA_VALUE *old_value;
rpm_object = read_access_data; rpm_object = read_access_data;
old_rpm_object = rpm_object; old_rpm_object = rpm_object;
@@ -90,11 +90,11 @@ static int rpm_ack_decode_service_request(
decoded_len += len; decoded_len += len;
apdu_len -= len; apdu_len -= len;
apdu += len; apdu += len;
if (apdu_len && decode_is_opening_tag_number(apdu, 4)) { if (apdu_len && decode_is_opening_tag_number(apdu, 4)) {
/* propertyValue */ /* propertyValue */
decoded_len++; decoded_len++;
apdu_len--; apdu_len--;
apdu++; apdu++;
/* note: if this is an array, there will be /* note: if this is an array, there will be
more than one element to decode */ more than one element to decode */
value = calloc(1, sizeof(BACNET_APPLICATION_DATA_VALUE)); value = calloc(1, sizeof(BACNET_APPLICATION_DATA_VALUE));
@@ -102,7 +102,7 @@ static int rpm_ack_decode_service_request(
old_value = value; old_value = value;
while (value && (apdu_len > 0)) { while (value && (apdu_len > 0)) {
len = len =
bacapp_decode_application_data(apdu, apdu_len, value); bacapp_decode_application_data(apdu, apdu_len, value);
decoded_len += len; decoded_len += len;
apdu_len -= len; apdu_len -= len;
apdu += len; apdu += len;
@@ -118,42 +118,42 @@ static int rpm_ack_decode_service_request(
old_value->next = value; old_value->next = value;
} }
} }
} else if (apdu_len && decode_is_opening_tag_number(apdu, 5)) { } else if (apdu_len && decode_is_opening_tag_number(apdu, 5)) {
/* propertyAccessError */ /* propertyAccessError */
decoded_len++; decoded_len++;
apdu_len--; apdu_len--;
apdu++; apdu++;
/* decode the class and code sequence */ /* decode the class and code sequence */
len = len =
decode_tag_number_and_value(apdu, &tag_number, decode_tag_number_and_value(apdu, &tag_number,
&len_value); &len_value);
decoded_len += len; decoded_len += len;
apdu_len -= len; apdu_len -= len;
apdu += len; apdu += len;
/* FIXME: we could validate that the tag is enumerated... */ /* FIXME: we could validate that the tag is enumerated... */
len = decode_enumerated(apdu, len_value, len = decode_enumerated(apdu, len_value,
(int *)&rpm_property->error.error_class); (int *)&rpm_property->error.error_class);
decoded_len += len; decoded_len += len;
apdu_len -= len; apdu_len -= len;
apdu += len; apdu += len;
len = len =
decode_tag_number_and_value(apdu, &tag_number, decode_tag_number_and_value(apdu, &tag_number,
&len_value); &len_value);
decoded_len += len; decoded_len += len;
apdu_len -= len; apdu_len -= len;
apdu += len; apdu += len;
/* FIXME: we could validate that the tag is enumerated... */ /* FIXME: we could validate that the tag is enumerated... */
len = decode_enumerated(apdu, len_value, len = decode_enumerated(apdu, len_value,
(int *)&rpm_property->error.error_code); (int *)&rpm_property->error.error_code);
decoded_len += len; decoded_len += len;
apdu_len -= len; apdu_len -= len;
apdu += len; apdu += len;
if (apdu_len && decode_is_closing_tag_number(apdu, 5)) { if (apdu_len && decode_is_closing_tag_number(apdu, 5)) {
decoded_len++; decoded_len++;
apdu_len--; apdu_len--;
apdu++; apdu++;
} }
} }
old_rpm_property = rpm_property; old_rpm_property = rpm_property;
rpm_property = calloc(1, sizeof(BACNET_PROPERTY_REFERENCE)); rpm_property = calloc(1, sizeof(BACNET_PROPERTY_REFERENCE));
old_rpm_property->next = rpm_property; old_rpm_property->next = rpm_property;
@@ -200,8 +200,8 @@ static void PrintReadPropertyMultipleData(
fprintf(stdout, "[%d]", listOfProperties->propertyArrayIndex); fprintf(stdout, "[%d]", listOfProperties->propertyArrayIndex);
#endif #endif
} }
value = listOfProperties->value; value = listOfProperties->value;
if (value) { if (value) {
#if PRINT_ENABLED #if PRINT_ENABLED
if (value->next) { if (value->next) {
fprintf(stdout, "{"); fprintf(stdout, "{");
@@ -226,16 +226,16 @@ static void PrintReadPropertyMultipleData(
#endif #endif
value = value->next; value = value->next;
} }
} else { } else {
#if PRINT_ENABLED #if PRINT_ENABLED
/* AccessError */ /* AccessError */
fprintf(stdout, "BACnet Error: %s: %s\r\n", fprintf(stdout, "BACnet Error: %s: %s\r\n",
bactext_error_class_name( bactext_error_class_name(
(int)listOfProperties->error.error_class), (int)listOfProperties->error.error_class),
bactext_error_code_name( bactext_error_code_name(
(int)listOfProperties->error.error_code)); (int)listOfProperties->error.error_code));
#endif #endif
} }
listOfProperties = listOfProperties->next; listOfProperties = listOfProperties->next;
} }
#if PRINT_ENABLED #if PRINT_ENABLED
+36 -36
View File
@@ -39,39 +39,39 @@
#include "cov.h" #include "cov.h"
/* some demo stuff needed */ /* some demo stuff needed */
#include "handlers.h" #include "handlers.h"
int ucov_notify_encode_pdu( int ucov_notify_encode_pdu(
uint8_t * buffer, uint8_t * buffer,
BACNET_ADDRESS * dest, BACNET_ADDRESS * dest,
BACNET_NPDU_DATA * npdu_data, BACNET_NPDU_DATA * npdu_data,
BACNET_COV_DATA * cov_data) BACNET_COV_DATA * cov_data)
{ {
int len = 0; int len = 0;
int pdu_len = 0; int pdu_len = 0;
/* unconfirmed is a broadcast */ /* unconfirmed is a 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 */
npdu_encode_npdu_data(npdu_data, false, MESSAGE_PRIORITY_NORMAL); npdu_encode_npdu_data(npdu_data, false, MESSAGE_PRIORITY_NORMAL);
pdu_len = npdu_encode_pdu(&buffer[0], dest, NULL, npdu_data); pdu_len = npdu_encode_pdu(&buffer[0], dest, NULL, npdu_data);
/* encode the APDU portion of the packet */ /* encode the APDU portion of the packet */
len = ucov_notify_encode_apdu(&buffer[pdu_len], cov_data); len = ucov_notify_encode_apdu(&buffer[pdu_len], cov_data);
pdu_len += len; pdu_len += len;
return pdu_len; return pdu_len;
} }
int Send_UCOV_Notify( int Send_UCOV_Notify(
uint8_t * buffer, uint8_t * buffer,
BACNET_COV_DATA * cov_data) BACNET_COV_DATA * cov_data)
{ {
int pdu_len = 0; int pdu_len = 0;
BACNET_ADDRESS dest; BACNET_ADDRESS dest;
int bytes_sent = 0; int bytes_sent = 0;
BACNET_NPDU_DATA npdu_data; BACNET_NPDU_DATA npdu_data;
pdu_len = ucov_notify_encode_pdu(buffer, &dest, &npdu_data, cov_data); pdu_len = ucov_notify_encode_pdu(buffer, &dest, &npdu_data, cov_data);
bytes_sent = datalink_send_pdu(&dest, &npdu_data, &buffer[0], pdu_len); bytes_sent = datalink_send_pdu(&dest, &npdu_data, &buffer[0], pdu_len);
return bytes_sent; return bytes_sent;
} }
+6 -1
View File
@@ -1,20 +1,25 @@
#!/bin/sh #!/bin/sh
# fix DOS/Unix names, and remove backup files # fix DOS/Unix names and Subversion EOL-Style, and remove backup files
# exit silently if utility is not installed # exit silently if utility is not installed
[ -x /usr/bin/dos2unix ] || exit 0 [ -x /usr/bin/dos2unix ] || exit 0
[ -x /usr/bin/svn ] || exit 0
directory=${1-`pwd`} directory=${1-`pwd`}
for filename in $( find ${directory} -name '*.c' ) for filename in $( find ${directory} -name '*.c' )
do do
echo Fixing DOS/Unix ${filename} echo Fixing DOS/Unix ${filename}
/usr/bin/dos2unix ${filename} /usr/bin/dos2unix ${filename}
echo Setting Subversion EOL Style for ${filename}
/usr/bin/svn propset svn:eol-style native ${filename}
done done
for filename in $( find ${directory} -name '*.h' ) for filename in $( find ${directory} -name '*.h' )
do do
echo Fixing DOS/Unix ${filename} echo Fixing DOS/Unix ${filename}
/usr/bin/dos2unix ${filename} /usr/bin/dos2unix ${filename}
echo Setting Subversion EOL Style for ${filename}
/usr/bin/svn propset svn:eol-style native ${filename}
done done
for filename in $( find ${directory} -name '*~' ) for filename in $( find ${directory} -name '*~' )
+90 -90
View File
@@ -1,90 +1,90 @@
/*####COPYRIGHTBEGIN#### /*####COPYRIGHTBEGIN####
------------------------------------------- -------------------------------------------
Copyright (C) 2008 by Steve Karg Copyright (C) 2008 by Steve Karg
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2 as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version. of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program; if not, write to: along with this program; if not, write to:
The Free Software Foundation, Inc. The Free Software Foundation, Inc.
59 Temple Place - Suite 330 59 Temple Place - Suite 330
Boston, MA 02111-1307 Boston, MA 02111-1307
USA. USA.
As a special exception, if other files instantiate templates or As a special exception, if other files instantiate templates or
use macros or inline functions from this file, or you compile use macros or inline functions from this file, or you compile
this file and link it with other works to produce a work based this file and link it with other works to produce a work based
on this file, this file does not by itself cause the resulting on this file, this file does not by itself cause the resulting
work to be covered by the GNU General Public License. However work to be covered by the GNU General Public License. However
the source code for this file must still be made available in the source code for this file must still be made available in
accordance with section (3) of the GNU General Public License. accordance with section (3) of the GNU General Public License.
This exception does not invalidate any other reasons why a work This exception does not invalidate any other reasons why a work
based on this file might be covered by the GNU General Public based on this file might be covered by the GNU General Public
License. License.
------------------------------------------- -------------------------------------------
####COPYRIGHTEND####*/ ####COPYRIGHTEND####*/
/* Functional Description: Generic FIFO library for deeply /* Functional Description: Generic FIFO library for deeply
embedded system. See the unit tests for usage examples. embedded system. See the unit tests for usage examples.
This library only uses a byte sized chunk. This library only uses a byte sized chunk.
This library is designed for use in Interrupt Service Routines This library is designed for use in Interrupt Service Routines
and so is declared as "static inline" */ and so is declared as "static inline" */
#ifndef FIFO_H #ifndef FIFO_H
#define FIFO_H #define FIFO_H
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
struct fifo_buffer_t { struct fifo_buffer_t {
volatile unsigned head; /* first byte of data */ volatile unsigned head; /* first byte of data */
volatile unsigned tail; /* last byte of data */ volatile unsigned tail; /* last byte of data */
volatile uint8_t *buffer; /* block of memory or array of data */ volatile uint8_t *buffer; /* block of memory or array of data */
unsigned buffer_len; /* length of the data */ unsigned buffer_len; /* length of the data */
}; };
typedef struct fifo_buffer_t FIFO_BUFFER; typedef struct fifo_buffer_t FIFO_BUFFER;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
bool FIFO_Empty( bool FIFO_Empty(
FIFO_BUFFER const *b); FIFO_BUFFER const *b);
uint8_t FIFO_Peek( uint8_t FIFO_Peek(
FIFO_BUFFER const *b); FIFO_BUFFER const *b);
uint8_t FIFO_Get( uint8_t FIFO_Get(
FIFO_BUFFER * b); FIFO_BUFFER * b);
bool FIFO_Put( bool FIFO_Put(
FIFO_BUFFER * b, FIFO_BUFFER * b,
uint8_t data_byte); uint8_t data_byte);
bool FIFO_Add( bool FIFO_Add(
FIFO_BUFFER * b, FIFO_BUFFER * b,
uint8_t *data_bytes, uint8_t *data_bytes,
unsigned count); unsigned count);
void FIFO_Flush( void FIFO_Flush(
FIFO_BUFFER * b); FIFO_BUFFER * b);
/* note: buffer_len must be a power of two */ /* note: buffer_len must be a power of two */
void FIFO_Init( void FIFO_Init(
FIFO_BUFFER * b, FIFO_BUFFER * b,
volatile uint8_t *buffer, volatile uint8_t *buffer,
unsigned buffer_len); unsigned buffer_len);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif #endif
+160 -160
View File
@@ -1,160 +1,160 @@
/*####COPYRIGHTBEGIN#### /*####COPYRIGHTBEGIN####
------------------------------------------- -------------------------------------------
Copyright (C) 2007 Steve Karg Copyright (C) 2007 Steve Karg
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2 as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version. of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program; if not, write to: along with this program; if not, write to:
The Free Software Foundation, Inc. The Free Software Foundation, Inc.
59 Temple Place - Suite 330 59 Temple Place - Suite 330
Boston, MA 02111-1307, USA. Boston, MA 02111-1307, USA.
As a special exception, if other files instantiate templates or As a special exception, if other files instantiate templates or
use macros or inline functions from this file, or you compile use macros or inline functions from this file, or you compile
this file and link it with other works to produce a work based this file and link it with other works to produce a work based
on this file, this file does not by itself cause the resulting on this file, this file does not by itself cause the resulting
work to be covered by the GNU General Public License. However work to be covered by the GNU General Public License. However
the source code for this file must still be made available in the source code for this file must still be made available in
accordance with section (3) of the GNU General Public License. accordance with section (3) of the GNU General Public License.
This exception does not invalidate any other reasons why a work This exception does not invalidate any other reasons why a work
based on this file might be covered by the GNU General Public based on this file might be covered by the GNU General Public
License. License.
------------------------------------------- -------------------------------------------
####COPYRIGHTEND####*/ ####COPYRIGHTEND####*/
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include "bits.h" #include "bits.h"
#include "apdu.h" #include "apdu.h"
#include "bacdef.h" #include "bacdef.h"
#include "bacdcode.h" #include "bacdcode.h"
#include "bacenum.h" #include "bacenum.h"
#include "handlers.h" #include "handlers.h"
uint16_t apdu_timeout( uint16_t apdu_timeout(
void) void)
{ {
return 3000; return 3000;
} }
uint8_t apdu_retries( uint8_t apdu_retries(
void) void)
{ {
return 3; return 3;
} }
bool apdu_service_supported( bool apdu_service_supported(
BACNET_SERVICES_SUPPORTED service_supported) BACNET_SERVICES_SUPPORTED service_supported)
{ {
bool status = false; bool status = false;
switch (service_supported) { switch (service_supported) {
case SERVICE_SUPPORTED_READ_PROPERTY: case SERVICE_SUPPORTED_READ_PROPERTY:
case SERVICE_SUPPORTED_WHO_IS: case SERVICE_SUPPORTED_WHO_IS:
case SERVICE_CONFIRMED_REINITIALIZE_DEVICE: case SERVICE_CONFIRMED_REINITIALIZE_DEVICE:
case SERVICE_SUPPORTED_WRITE_PROPERTY: case SERVICE_SUPPORTED_WRITE_PROPERTY:
case SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL: case SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL:
status = true; status = true;
break; break;
default: default:
break; break;
} }
return status; return status;
} }
uint16_t apdu_decode_confirmed_service_request( uint16_t apdu_decode_confirmed_service_request(
uint8_t * apdu, /* APDU data */ uint8_t * apdu, /* APDU data */
uint16_t apdu_len, uint16_t apdu_len,
BACNET_CONFIRMED_SERVICE_DATA * service_data, BACNET_CONFIRMED_SERVICE_DATA * service_data,
uint8_t * service_choice, uint8_t * service_choice,
uint8_t ** service_request, uint8_t ** service_request,
uint16_t * service_request_len) uint16_t * service_request_len)
{ {
uint16_t len = 0; /* counts where we are in PDU */ uint16_t len = 0; /* counts where we are in PDU */
service_data->segmented_message = (apdu[0] & BIT3) ? true : false; service_data->segmented_message = (apdu[0] & BIT3) ? true : false;
service_data->more_follows = (apdu[0] & BIT2) ? true : false; service_data->more_follows = (apdu[0] & BIT2) ? true : false;
service_data->segmented_response_accepted = service_data->segmented_response_accepted =
(apdu[0] & BIT1) ? true : false; (apdu[0] & BIT1) ? true : false;
service_data->max_segs = decode_max_segs(apdu[1]); service_data->max_segs = decode_max_segs(apdu[1]);
service_data->max_resp = decode_max_apdu(apdu[1]); service_data->max_resp = decode_max_apdu(apdu[1]);
service_data->invoke_id = apdu[2]; service_data->invoke_id = apdu[2];
len = 3; len = 3;
if (service_data->segmented_message) { if (service_data->segmented_message) {
service_data->sequence_number = apdu[len++]; service_data->sequence_number = apdu[len++];
service_data->proposed_window_number = apdu[len++]; service_data->proposed_window_number = apdu[len++];
} }
*service_choice = apdu[len++]; *service_choice = apdu[len++];
*service_request = &apdu[len]; *service_request = &apdu[len];
*service_request_len = apdu_len - len; *service_request_len = apdu_len - len;
return len; return len;
} }
void apdu_handler( void apdu_handler(
BACNET_ADDRESS * src, BACNET_ADDRESS * src,
uint8_t * apdu, /* APDU data */ uint8_t * apdu, /* APDU data */
uint16_t apdu_len) uint16_t apdu_len)
{ {
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;
uint16_t len = 0; /* counts where we are in PDU */ uint16_t len = 0; /* counts where we are in PDU */
if (apdu) { if (apdu) {
/* PDU Type */ /* PDU Type */
switch (apdu[0] & 0xF0) { switch (apdu[0] & 0xF0) {
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST: case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
len = apdu_decode_confirmed_service_request(&apdu[0], /* APDU data */ len = apdu_decode_confirmed_service_request(&apdu[0], /* APDU data */
apdu_len, &service_data, &service_choice, &service_request, apdu_len, &service_data, &service_choice, &service_request,
&service_request_len); &service_request_len);
if (service_choice == SERVICE_CONFIRMED_READ_PROPERTY) { if (service_choice == SERVICE_CONFIRMED_READ_PROPERTY) {
handler_read_property(service_request, service_request_len, handler_read_property(service_request, service_request_len,
src, &service_data); src, &service_data);
} }
else if (service_choice == SERVICE_CONFIRMED_WRITE_PROPERTY) { else if (service_choice == SERVICE_CONFIRMED_WRITE_PROPERTY) {
handler_write_property(service_request, handler_write_property(service_request,
service_request_len, src, &service_data); service_request_len, src, &service_data);
} else if (service_choice == SERVICE_CONFIRMED_REINITIALIZE_DEVICE) { } else if (service_choice == SERVICE_CONFIRMED_REINITIALIZE_DEVICE) {
handler_reinitialize_device(service_request, handler_reinitialize_device(service_request,
service_request_len, src, &service_data); service_request_len, src, &service_data);
} else if (service_choice == SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL) { } else if (service_choice == SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL) {
handler_device_communication_control(service_request, handler_device_communication_control(service_request,
service_request_len, src, &service_data); service_request_len, src, &service_data);
} else { } else {
handler_unrecognized_service(service_request, handler_unrecognized_service(service_request,
service_request_len, src, &service_data); service_request_len, src, &service_data);
} }
break; break;
case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST: case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
service_choice = apdu[1]; service_choice = apdu[1];
service_request = &apdu[2]; service_request = &apdu[2];
service_request_len = apdu_len - 2; service_request_len = apdu_len - 2;
if (service_choice == SERVICE_UNCONFIRMED_WHO_IS) { if (service_choice == SERVICE_UNCONFIRMED_WHO_IS) {
handler_who_is(service_request, service_request_len, src); handler_who_is(service_request, service_request_len, src);
} }
break; break;
case PDU_TYPE_SIMPLE_ACK: case PDU_TYPE_SIMPLE_ACK:
case PDU_TYPE_COMPLEX_ACK: case PDU_TYPE_COMPLEX_ACK:
case PDU_TYPE_SEGMENT_ACK: case PDU_TYPE_SEGMENT_ACK:
case PDU_TYPE_ERROR: case PDU_TYPE_ERROR:
case PDU_TYPE_REJECT: case PDU_TYPE_REJECT:
case PDU_TYPE_ABORT: case PDU_TYPE_ABORT:
default: default:
break; break;
} }
} }
return; return;
} }
+440 -440
View File
@@ -1,440 +1,440 @@
/*####COPYRIGHTBEGIN#### /*####COPYRIGHTBEGIN####
------------------------------------------- -------------------------------------------
Copyright (C) 2005 Steve Karg Copyright (C) 2005 Steve Karg
Contributions by Thomas Neumann in 2008. Contributions by Thomas Neumann in 2008.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2 as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version. of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program; if not, write to: along with this program; if not, write to:
The Free Software Foundation, Inc. The Free Software Foundation, Inc.
59 Temple Place - Suite 330 59 Temple Place - Suite 330
Boston, MA 02111-1307, USA. Boston, MA 02111-1307, USA.
As a special exception, if other files instantiate templates or As a special exception, if other files instantiate templates or
use macros or inline functions from this file, or you compile use macros or inline functions from this file, or you compile
this file and link it with other works to produce a work based this file and link it with other works to produce a work based
on this file, this file does not by itself cause the resulting on this file, this file does not by itself cause the resulting
work to be covered by the GNU General Public License. However work to be covered by the GNU General Public License. However
the source code for this file must still be made available in the source code for this file must still be made available in
accordance with section (3) of the GNU General Public License. accordance with section (3) of the GNU General Public License.
This exception does not invalidate any other reasons why a work This exception does not invalidate any other reasons why a work
based on this file might be covered by the GNU General Public based on this file might be covered by the GNU General Public
License. License.
------------------------------------------- -------------------------------------------
####COPYRIGHTEND####*/ ####COPYRIGHTEND####*/
#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 "config.h" #include "config.h"
#include "bip.h" #include "bip.h"
#include "net.h" #include "net.h"
bool BIP_Debug = false; bool BIP_Debug = false;
/* gets an IP address by name, where name can be a /* gets an IP address by name, where name can be a
string that is an IP address in dotted form, or string that is an IP address in dotted form, or
a name that is a domain name a name that is a domain name
returns 0 if not found, or returns 0 if not found, or
an IP address in network byte order */ an IP address in network byte order */
long bip_getaddrbyname( long bip_getaddrbyname(
const char *host_name) const char *host_name)
{ {
struct hostent *host_ent; struct hostent *host_ent;
if ((host_ent = gethostbyname(host_name)) == NULL) if ((host_ent = gethostbyname(host_name)) == NULL)
return 0; return 0;
return *(long *) host_ent->h_addr; return *(long *) host_ent->h_addr;
} }
/* To fill a need, we invent the gethostaddr() function. */ /* To fill a need, we invent the gethostaddr() function. */
static long gethostaddr( static long gethostaddr(
void) 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;
if ((host_ent = gethostbyname(host_name)) == NULL) if ((host_ent = gethostbyname(host_name)) == NULL)
return -1; return -1;
if (BIP_Debug) { if (BIP_Debug) {
printf("host: %s at %u.%u.%u.%u\n", host_name, printf("host: %s at %u.%u.%u.%u\n", host_name,
((uint8_t *) host_ent->h_addr)[0], ((uint8_t *) host_ent->h_addr)[0],
((uint8_t *) host_ent->h_addr)[1], ((uint8_t *) host_ent->h_addr)[1],
((uint8_t *) host_ent->h_addr)[2], ((uint8_t *) host_ent->h_addr)[2],
((uint8_t *) host_ent->h_addr)[3]); ((uint8_t *) host_ent->h_addr)[3]);
} }
/* note: network byte order */ /* note: network byte order */
return *(long *) host_ent->h_addr; return *(long *) host_ent->h_addr;
} }
#if (!defined(USE_INADDR) || (USE_INADDR == 0)) && \ #if (!defined(USE_INADDR) || (USE_INADDR == 0)) && \
(!defined(USE_CLASSADDR) || (USE_CLASSADDR == 0)) (!defined(USE_CLASSADDR) || (USE_CLASSADDR == 0))
/* returns the subnet mask in network byte order */ /* returns the subnet mask in network byte order */
static uint32_t getIpMaskForIpAddress( static uint32_t getIpMaskForIpAddress(
uint32_t ipAddress) uint32_t ipAddress)
{ {
/* Allocate information for up to 16 NICs */ /* Allocate information for up to 16 NICs */
IP_ADAPTER_INFO AdapterInfo[16]; IP_ADAPTER_INFO AdapterInfo[16];
/* Save memory size of buffer */ /* Save memory size of buffer */
DWORD dwBufLen = sizeof(AdapterInfo); DWORD dwBufLen = sizeof(AdapterInfo);
uint32_t ipMask = INADDR_BROADCAST; uint32_t ipMask = INADDR_BROADCAST;
bool found = false; bool found = false;
PIP_ADAPTER_INFO pAdapterInfo; PIP_ADAPTER_INFO pAdapterInfo;
/* GetAdapterInfo: /* GetAdapterInfo:
[out] buffer to receive data [out] buffer to receive data
[in] size of receive data buffer */ [in] size of receive data buffer */
DWORD dwStatus = GetAdaptersInfo(AdapterInfo, DWORD dwStatus = GetAdaptersInfo(AdapterInfo,
&dwBufLen); &dwBufLen);
if (dwStatus == ERROR_SUCCESS) { if (dwStatus == ERROR_SUCCESS) {
/* Verify return value is valid, no buffer overflow /* Verify return value is valid, no buffer overflow
Contains pointer to current adapter info */ Contains pointer to current adapter info */
pAdapterInfo = AdapterInfo; pAdapterInfo = AdapterInfo;
do { do {
IP_ADDR_STRING *pIpAddressInfo = &pAdapterInfo->IpAddressList; IP_ADDR_STRING *pIpAddressInfo = &pAdapterInfo->IpAddressList;
do { do {
unsigned long adapterAddress = unsigned long adapterAddress =
inet_addr(pIpAddressInfo->IpAddress.String); inet_addr(pIpAddressInfo->IpAddress.String);
unsigned long adapterMask = unsigned long adapterMask =
inet_addr(pIpAddressInfo->IpMask.String); inet_addr(pIpAddressInfo->IpMask.String);
if (adapterAddress == ipAddress) { if (adapterAddress == ipAddress) {
ipMask = adapterMask; ipMask = adapterMask;
found = true; found = true;
} }
pIpAddressInfo = pIpAddressInfo->Next; pIpAddressInfo = pIpAddressInfo->Next;
} while (pIpAddressInfo && !found); } while (pIpAddressInfo && !found);
/* Progress through linked list */ /* Progress through linked list */
pAdapterInfo = pAdapterInfo->Next; pAdapterInfo = pAdapterInfo->Next;
/* Terminate on last adapter */ /* Terminate on last adapter */
} while (pAdapterInfo && !found); } while (pAdapterInfo && !found);
} }
return ipMask; return ipMask;
} }
#endif #endif
static void set_broadcast_address( static void set_broadcast_address(
uint32_t net_address) uint32_t net_address)
{ {
#if defined(USE_INADDR) && USE_INADDR #if defined(USE_INADDR) && USE_INADDR
/* 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... */
net_address = net_address; net_address = net_address;
bip_set_broadcast_addr(INADDR_BROADCAST); bip_set_broadcast_addr(INADDR_BROADCAST);
#elif defined(USE_CLASSADDR) && USE_CLASSADDR #elif defined(USE_CLASSADDR) && USE_CLASSADDR
long broadcast_address = 0; long broadcast_address = 0;
if (IN_CLASSA(ntohl(net_address))) if (IN_CLASSA(ntohl(net_address)))
broadcast_address = broadcast_address =
(ntohl(net_address) & ~IN_CLASSA_HOST) | IN_CLASSA_HOST; (ntohl(net_address) & ~IN_CLASSA_HOST) | IN_CLASSA_HOST;
else if (IN_CLASSB(ntohl(net_address))) else if (IN_CLASSB(ntohl(net_address)))
broadcast_address = broadcast_address =
(ntohl(net_address) & ~IN_CLASSB_HOST) | IN_CLASSB_HOST; (ntohl(net_address) & ~IN_CLASSB_HOST) | IN_CLASSB_HOST;
else if (IN_CLASSC(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_CLASSC_HOST) | IN_CLASSC_HOST;
else if (IN_CLASSD(ntohl(net_address))) else if (IN_CLASSD(ntohl(net_address)))
broadcast_address = broadcast_address =
(ntohl(net_address) & ~IN_CLASSD_HOST) | IN_CLASSD_HOST; (ntohl(net_address) & ~IN_CLASSD_HOST) | IN_CLASSD_HOST;
else else
broadcast_address = INADDR_BROADCAST; broadcast_address = INADDR_BROADCAST;
bip_set_broadcast_addr(htonl(broadcast_address)); bip_set_broadcast_addr(htonl(broadcast_address));
#else #else
/* these are network byte order variables */ /* these are network byte order variables */
long broadcast_address = 0; long broadcast_address = 0;
long net_mask = 0; long net_mask = 0;
net_mask = getIpMaskForIpAddress(net_address); net_mask = getIpMaskForIpAddress(net_address);
if (BIP_Debug) { if (BIP_Debug) {
struct in_addr address; struct in_addr address;
address.s_addr = net_mask; address.s_addr = net_mask;
printf("IP Mask: %s\n", inet_ntoa(address)); printf("IP Mask: %s\n", inet_ntoa(address));
} }
broadcast_address = (net_address & net_mask) | (~net_mask); broadcast_address = (net_address & net_mask) | (~net_mask);
bip_set_broadcast_addr(broadcast_address); bip_set_broadcast_addr(broadcast_address);
#endif #endif
} }
static void cleanup( static void cleanup(
void) void)
{ {
WSACleanup(); WSACleanup();
} }
/* on Windows, ifname is the dotted ip address of the interface */ /* on Windows, ifname is the dotted ip address of the interface */
void bip_set_interface( void bip_set_interface(
char *ifname) char *ifname)
{ {
struct in_addr address; struct in_addr address;
/* setup local address */ /* setup local address */
if (bip_get_addr() == 0) { if (bip_get_addr() == 0) {
bip_set_addr(inet_addr(ifname)); bip_set_addr(inet_addr(ifname));
} }
if (BIP_Debug) { if (BIP_Debug) {
address.s_addr = htonl(bip_get_addr()); address.s_addr = htonl(bip_get_addr());
fprintf(stderr, "Interface: %s\n", ifname); fprintf(stderr, "Interface: %s\n", ifname);
} }
/* setup local broadcast address */ /* setup local broadcast address */
if (bip_get_broadcast_addr() == 0) { if (bip_get_broadcast_addr() == 0) {
address.s_addr = htonl(bip_get_addr()); address.s_addr = htonl(bip_get_addr());
set_broadcast_address(address.s_addr); set_broadcast_address(address.s_addr);
} }
} }
static char *winsock_error_code_text( static char *winsock_error_code_text(
int code) int code)
{ {
switch (code) { switch (code) {
case WSAEACCES: case WSAEACCES:
return "Permission denied."; return "Permission denied.";
case WSAEINTR: case WSAEINTR:
return "Interrupted system call."; return "Interrupted system call.";
case WSAEBADF: case WSAEBADF:
return "Bad file number."; return "Bad file number.";
case WSAEFAULT: case WSAEFAULT:
return "Bad address."; return "Bad address.";
case WSAEINVAL: case WSAEINVAL:
return "Invalid argument."; return "Invalid argument.";
case WSAEMFILE: case WSAEMFILE:
return "Too many open files."; return "Too many open files.";
case WSAEWOULDBLOCK: case WSAEWOULDBLOCK:
return "Operation would block."; return "Operation would block.";
case WSAEINPROGRESS: case WSAEINPROGRESS:
return return
"Operation now in progress. This error is returned if any Windows Sockets API function is called while a blocking function is in progress."; "Operation now in progress. This error is returned if any Windows Sockets API function is called while a blocking function is in progress.";
case WSAENOTSOCK: case WSAENOTSOCK:
return "Socket operation on nonsocket."; return "Socket operation on nonsocket.";
case WSAEDESTADDRREQ: case WSAEDESTADDRREQ:
return "Destination address required."; return "Destination address required.";
case WSAEMSGSIZE: case WSAEMSGSIZE:
return "Message too long."; return "Message too long.";
case WSAEPROTOTYPE: case WSAEPROTOTYPE:
return "Protocol wrong type for socket."; return "Protocol wrong type for socket.";
case WSAENOPROTOOPT: case WSAENOPROTOOPT:
return "Protocol not available."; return "Protocol not available.";
case WSAEPROTONOSUPPORT: case WSAEPROTONOSUPPORT:
return "Protocol not supported."; return "Protocol not supported.";
case WSAESOCKTNOSUPPORT: case WSAESOCKTNOSUPPORT:
return "Socket type not supported."; return "Socket type not supported.";
case WSAEOPNOTSUPP: case WSAEOPNOTSUPP:
return "Operation not supported on socket."; return "Operation not supported on socket.";
case WSAEPFNOSUPPORT: case WSAEPFNOSUPPORT:
return "Protocol family not supported."; return "Protocol family not supported.";
case WSAEAFNOSUPPORT: case WSAEAFNOSUPPORT:
return "Address family not supported by protocol family."; return "Address family not supported by protocol family.";
case WSAEADDRINUSE: case WSAEADDRINUSE:
return "Address already in use."; return "Address already in use.";
case WSAEADDRNOTAVAIL: case WSAEADDRNOTAVAIL:
return "Cannot assign requested address."; return "Cannot assign requested address.";
case WSAENETDOWN: case WSAENETDOWN:
return return
"Network is down. This error may be reported at any time if the Windows Sockets implementation detects an underlying failure."; "Network is down. This error may be reported at any time if the Windows Sockets implementation detects an underlying failure.";
case WSAENETUNREACH: case WSAENETUNREACH:
return "Network is unreachable."; return "Network is unreachable.";
case WSAENETRESET: case WSAENETRESET:
return "Network dropped connection on reset."; return "Network dropped connection on reset.";
case WSAECONNABORTED: case WSAECONNABORTED:
return "Software caused connection abort."; return "Software caused connection abort.";
case WSAECONNRESET: case WSAECONNRESET:
return "Connection reset by peer."; return "Connection reset by peer.";
case WSAENOBUFS: case WSAENOBUFS:
return "No buffer space available."; return "No buffer space available.";
case WSAEISCONN: case WSAEISCONN:
return "Socket is already connected."; return "Socket is already connected.";
case WSAENOTCONN: case WSAENOTCONN:
return "Socket is not connected."; return "Socket is not connected.";
case WSAESHUTDOWN: case WSAESHUTDOWN:
return "Cannot send after socket shutdown."; return "Cannot send after socket shutdown.";
case WSAETOOMANYREFS: case WSAETOOMANYREFS:
return "Too many references: cannot splice."; return "Too many references: cannot splice.";
case WSAETIMEDOUT: case WSAETIMEDOUT:
return "Connection timed out."; return "Connection timed out.";
case WSAECONNREFUSED: case WSAECONNREFUSED:
return "Connection refused."; return "Connection refused.";
case WSAELOOP: case WSAELOOP:
return "Too many levels of symbolic links."; return "Too many levels of symbolic links.";
case WSAENAMETOOLONG: case WSAENAMETOOLONG:
return "File name too long."; return "File name too long.";
case WSAEHOSTDOWN: case WSAEHOSTDOWN:
return "Host is down."; return "Host is down.";
case WSAEHOSTUNREACH: case WSAEHOSTUNREACH:
return "No route to host."; return "No route to host.";
case WSASYSNOTREADY: case WSASYSNOTREADY:
return "Returned by WSAStartup(), " return "Returned by WSAStartup(), "
"indicating that the network subsystem is unusable."; "indicating that the network subsystem is unusable.";
case WSAVERNOTSUPPORTED: case WSAVERNOTSUPPORTED:
return "Returned by WSAStartup(), " return "Returned by WSAStartup(), "
"indicating that the Windows Sockets DLL cannot support " "indicating that the Windows Sockets DLL cannot support "
"this application."; "this application.";
case WSANOTINITIALISED: case WSANOTINITIALISED:
return "Winsock not initialized. " return "Winsock not initialized. "
"This message is returned by any function except WSAStartup(), " "This message is returned by any function except WSAStartup(), "
"indicating that a successful WSAStartup() has not yet " "indicating that a successful WSAStartup() has not yet "
"been performed."; "been performed.";
case WSAEDISCON: case WSAEDISCON:
return "Disconnect."; return "Disconnect.";
case WSAHOST_NOT_FOUND: case WSAHOST_NOT_FOUND:
return "Host not found. " "This message indicates that the key " return "Host not found. " "This message indicates that the key "
"(name, address, and so on) was not found."; "(name, address, and so on) was not found.";
case WSATRY_AGAIN: case WSATRY_AGAIN:
return "Nonauthoritative host not found. " return "Nonauthoritative host not found. "
"This error may suggest that the name service itself " "This error may suggest that the name service itself "
"is not functioning."; "is not functioning.";
case WSANO_RECOVERY: case WSANO_RECOVERY:
return "Nonrecoverable error. " return "Nonrecoverable error. "
"This error may suggest that the name service itself " "This error may suggest that the name service itself "
"is not functioning."; "is not functioning.";
case WSANO_DATA: case WSANO_DATA:
return "Valid name, no data record of requested type. " return "Valid name, no data record of requested type. "
"This error indicates that the key " "This error indicates that the key "
"(name, address, and so on) was not found."; "(name, address, and so on) was not found.";
default: default:
return "unknown"; return "unknown";
} }
} }
bool bip_init( bool bip_init(
char *ifname) char *ifname)
{ {
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;
int Code; int Code;
WSADATA wd; WSADATA wd;
struct in_addr address; struct in_addr address;
struct in_addr broadcast_address; struct in_addr broadcast_address;
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\n" " error code: %i %s\n", printf("TCP/IP stack initialization failed\n" " error code: %i %s\n",
Code, winsock_error_code_text(Code)); Code, winsock_error_code_text(Code));
exit(1); exit(1);
} }
atexit(cleanup); atexit(cleanup);
if (ifname) if (ifname)
bip_set_interface(ifname); bip_set_interface(ifname);
/* has address been set? */ /* has address been set? */
address.s_addr = htonl(bip_get_addr()); address.s_addr = htonl(bip_get_addr());
if (address.s_addr == 0) { if (address.s_addr == 0) {
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\n" " error code: %i %s\n", Code, printf("Get host address failed\n" " error code: %i %s\n", Code,
winsock_error_code_text(Code)); winsock_error_code_text(Code));
exit(1); exit(1);
} }
bip_set_addr(address.s_addr); bip_set_addr(address.s_addr);
} }
if (BIP_Debug) { if (BIP_Debug) {
fprintf(stderr, "IP Address: %s\n", inet_ntoa(address)); fprintf(stderr, "IP Address: %s\n", inet_ntoa(address));
} }
/* has broadcast address been set? */ /* has broadcast address been set? */
if (bip_get_broadcast_addr() == 0) { if (bip_get_broadcast_addr() == 0) {
set_broadcast_address(address.s_addr); set_broadcast_address(address.s_addr);
} }
if (BIP_Debug) { if (BIP_Debug) {
broadcast_address.s_addr = htonl(bip_get_broadcast_addr()); broadcast_address.s_addr = htonl(bip_get_broadcast_addr());
fprintf(stderr, "IP Broadcast Address: %s\n", fprintf(stderr, "IP Broadcast Address: %s\n",
inet_ntoa(broadcast_address)); inet_ntoa(broadcast_address));
fprintf(stderr, "UDP Port: 0x%04X [%hu]\n", bip_get_port(), fprintf(stderr, "UDP Port: 0x%04X [%hu]\n", bip_get_port(),
bip_get_port()); bip_get_port());
} }
/* 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, (char *) &value, rv = setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &value,
sizeof(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;
} }
/* Enables transmission and receipt of broadcast messages on the socket. */ /* Enables transmission and receipt of broadcast messages on the socket. */
rv = setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, (char *) &value, rv = setsockopt(sock_fd, SOL_SOCKET, SO_BROADCAST, (char *) &value,
sizeof(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;
} }
#if 0 #if 0
/* probably only for Apple... */ /* probably only for Apple... */
/* rebind a port that is already in use. /* rebind a port that is already in use.
Note: all users of the port must specify this flag */ Note: all users of the port must specify this flag */
rv = setsockopt(sock_fd, SOL_SOCKET, SO_REUSEPORT, (char *) &value, rv = setsockopt(sock_fd, SOL_SOCKET, SO_REUSEPORT, (char *) &value,
sizeof(value)); sizeof(value));
if (rv < 0) { if (rv < 0) {
fprintf(stderr, "bip: failed to set REUSEPORT socket option.\n"); fprintf(stderr, "bip: failed to set REUSEPORT socket option.\n");
close(sock_fd); close(sock_fd);
bip_set_socket(-1); bip_set_socket(-1);
return false; return false;
} }
#endif #endif
/* 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 defined(USE_INADDR) && USE_INADDR #if defined(USE_INADDR) && 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
is running on. is running on.
Some server computers have multiple IP addresses. Some server computers have multiple IP addresses.
A socket bound to one of these will not accept A socket bound to one of these will not accept
connections to another address. Frequently you prefer connections to another address. Frequently you prefer
to allow any one of the computer's IP addresses to allow any one of the computer's IP addresses
to be used for connections. Use INADDR_ANY (0L) to to be used for connections. Use INADDR_ANY (0L) to
allow clients to connect using any one of the host's allow clients to connect using any one of the host's
IP addresses. */ IP addresses. */
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, (const struct sockaddr *) &sin, rv = bind(sock_fd, (const struct sockaddr *) &sin,
sizeof(struct sockaddr)); 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;
} }
return true; return true;
} }
+464 -464
View File
@@ -1,464 +1,464 @@
/*####COPYRIGHTBEGIN#### /*####COPYRIGHTBEGIN####
------------------------------------------- -------------------------------------------
Copyright (C) 2005 Steve Karg, modified by Kevin Liao Copyright (C) 2005 Steve Karg, modified by Kevin Liao
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2 as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version. of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program; if not, write to: along with this program; if not, write to:
The Free Software Foundation, Inc. The Free Software Foundation, Inc.
59 Temple Place - Suite 330 59 Temple Place - Suite 330
Boston, MA 02111-1307, USA. Boston, MA 02111-1307, USA.
As a special exception, if other files instantiate templates or As a special exception, if other files instantiate templates or
use macros or inline functions from this file, or you compile use macros or inline functions from this file, or you compile
this file and link it with other works to produce a work based this file and link it with other works to produce a work based
on this file, this file does not by itself cause the resulting on this file, this file does not by itself cause the resulting
work to be covered by the GNU General Public License. However work to be covered by the GNU General Public License. However
the source code for this file must still be made available in the source code for this file must still be made available in
accordance with section (3) of the GNU General Public License. accordance with section (3) of the GNU General Public License.
This exception does not invalidate any other reasons why a work This exception does not invalidate any other reasons why a work
based on this file might be covered by the GNU General Public based on this file might be covered by the GNU General Public
License. License.
------------------------------------------- -------------------------------------------
####COPYRIGHTEND####*/ ####COPYRIGHTEND####*/
#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 <assert.h> #include <assert.h>
#include <direct.h> #include <direct.h>
#include <io.h> #include <io.h>
#include "bacdef.h" #include "bacdef.h"
#include "ethernet.h" #include "ethernet.h"
#include "bacdcode.h" #include "bacdcode.h"
/* Uses WinPCap to access raw ethernet */ /* Uses WinPCap to access raw ethernet */
/* Notes: */ /* Notes: */
/* To make ethernet.c work under win32, you have to: */ /* To make ethernet.c work under win32, you have to: */
/* 1. install winpcap 3.1 development pack; */ /* 1. install winpcap 3.1 development pack; */
/* 2. install Microsoft Platform SDK Feb 2003. */ /* 2. install Microsoft Platform SDK Feb 2003. */
/* 3. remove or modify functions used for log such as */ /* 3. remove or modify functions used for log such as */
/* "LogError()", "LogInfo()", which were implemented */ /* "LogError()", "LogInfo()", which were implemented */
/* as a wrapper of Log4cpp. */ /* as a wrapper of Log4cpp. */
/* -- Kevin Liao */ /* -- Kevin Liao */
/* includes for accessing ethernet by using winpcap */ /* includes for accessing ethernet by using winpcap */
#include "pcap.h" #include "pcap.h"
#include "packet32.h" #include "packet32.h"
#include "ntddndis.h" #include "ntddndis.h"
#include "remote-ext.h" #include "remote-ext.h"
/* commonly used comparison address for ethernet */ /* commonly used comparison address for ethernet */
uint8_t Ethernet_Broadcast[MAX_MAC_LEN] = 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 };
/* couple of var for using winpcap */ /* couple of var for using winpcap */
static char pcap_errbuf[PCAP_ERRBUF_SIZE + 1]; static char pcap_errbuf[PCAP_ERRBUF_SIZE + 1];
static pcap_t *pcap_eth802_fp = NULL; /* 802.2 file handle, from winpcap */ static pcap_t *pcap_eth802_fp = NULL; /* 802.2 file handle, from winpcap */
static unsigned eth_timeout = 100; static unsigned eth_timeout = 100;
/* couple of external func for runtime error logging, you can simply */ /* couple of external func for runtime error logging, you can simply */
/* replace them with standard "printf(...)" */ /* replace them with standard "printf(...)" */
/* Logging extern functions: Info level */ /* Logging extern functions: Info level */
extern void LogInfo( extern void LogInfo(
const char *msg); const char *msg);
/* Logging extern functions: Error level*/ /* Logging extern functions: Error level*/
extern void LogError( extern void LogError(
const char *msg); const char *msg);
/* Logging extern functions: Debug level*/ /* Logging extern functions: Debug level*/
extern void LogDebug( extern void LogDebug(
const char *msg); const char *msg);
bool ethernet_valid( bool ethernet_valid(
void) void)
{ {
return (pcap_eth802_fp != NULL); return (pcap_eth802_fp != NULL);
} }
void ethernet_cleanup( void ethernet_cleanup(
void) void)
{ {
if (pcap_eth802_fp) { if (pcap_eth802_fp) {
pcap_close(pcap_eth802_fp); pcap_close(pcap_eth802_fp);
pcap_eth802_fp = NULL; pcap_eth802_fp = NULL;
} }
LogInfo("ethernet.c: ethernet_cleanup() ok.\n"); LogInfo("ethernet.c: ethernet_cleanup() ok.\n");
} }
void ethernet_set_timeout( void ethernet_set_timeout(
unsigned timeout) unsigned timeout)
{ {
eth_timeout = timeout; eth_timeout = timeout;
} }
/*---------------------------------------------------------------------- /*----------------------------------------------------------------------
Portable function to set a socket into nonblocking mode. Portable function to set a socket into nonblocking mode.
Calling this on a socket causes all future read() and write() calls on Calling this on a socket causes all future read() and write() calls on
that socket to do only as much as they can immediately, and return that socket to do only as much as they can immediately, and return
without waiting. without waiting.
If no data can be read or written, they return -1 and set errno If no data can be read or written, they return -1 and set errno
to EAGAIN (or EWOULDBLOCK). to EAGAIN (or EWOULDBLOCK).
Thanks to Bjorn Reese for this code. Thanks to Bjorn Reese for this code.
----------------------------------------------------------------------*/ ----------------------------------------------------------------------*/
/** /**
* We don't need to use this function since WinPCap has provided one * We don't need to use this function since WinPCap has provided one
* named "pcap_setnonblock()". * named "pcap_setnonblock()".
* Kevin, 2006.08.15 * Kevin, 2006.08.15
*/ */
/* /*
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);
} }
*/ */
bool ethernet_init( bool ethernet_init(
char *if_name) char *if_name)
{ {
PPACKET_OID_DATA pOidData; PPACKET_OID_DATA pOidData;
LPADAPTER lpAdapter; LPADAPTER lpAdapter;
pcap_if_t *pcap_all_if; pcap_if_t *pcap_all_if;
pcap_if_t *dev; pcap_if_t *dev;
BOOLEAN result; BOOLEAN result;
CHAR str[sizeof(PACKET_OID_DATA) + 128]; CHAR str[sizeof(PACKET_OID_DATA) + 128];
int i; int i;
char msgBuf[200]; char msgBuf[200];
if (ethernet_valid()) if (ethernet_valid())
ethernet_cleanup(); ethernet_cleanup();
/** /**
* Find the interface user specified * Find the interface user specified
*/ */
/* Retrieve the device list */ /* Retrieve the device list */
if (pcap_findalldevs(&pcap_all_if, pcap_errbuf) == -1) { if (pcap_findalldevs(&pcap_all_if, pcap_errbuf) == -1) {
sprintf(msgBuf, "ethernet.c: error in pcap_findalldevs: %s\n", sprintf(msgBuf, "ethernet.c: error in pcap_findalldevs: %s\n",
pcap_errbuf); pcap_errbuf);
LogError(msgBuf); LogError(msgBuf);
return false; return false;
} }
/* Scan the list printing every entry */ /* Scan the list printing every entry */
for (dev = pcap_all_if; dev; dev = dev->next) { for (dev = pcap_all_if; dev; dev = dev->next) {
if (strcmp(if_name, dev->name) == 0) if (strcmp(if_name, dev->name) == 0)
break; break;
} }
pcap_freealldevs(pcap_all_if); /* we don't need it anymore */ pcap_freealldevs(pcap_all_if); /* we don't need it anymore */
if (dev == NULL) { if (dev == NULL) {
sprintf(msgBuf, "ethernet.c: specified interface not found: %s\n", sprintf(msgBuf, "ethernet.c: specified interface not found: %s\n",
if_name); if_name);
LogError(msgBuf); LogError(msgBuf);
return false; return false;
} }
/** /**
* Get local MAC address * Get local MAC address
*/ */
ZeroMemory(str, sizeof(PACKET_OID_DATA) + 128); ZeroMemory(str, sizeof(PACKET_OID_DATA) + 128);
lpAdapter = PacketOpenAdapter(if_name); lpAdapter = PacketOpenAdapter(if_name);
if (lpAdapter == NULL) { if (lpAdapter == NULL) {
ethernet_cleanup(); ethernet_cleanup();
sprintf(msgBuf, "ethernet.c: error in PacketOpenAdapter(\"%s\")\n", sprintf(msgBuf, "ethernet.c: error in PacketOpenAdapter(\"%s\")\n",
if_name); if_name);
LogError(msgBuf); LogError(msgBuf);
return false; return false;
} }
pOidData = (PPACKET_OID_DATA) str; pOidData = (PPACKET_OID_DATA) str;
pOidData->Oid = OID_802_3_CURRENT_ADDRESS; pOidData->Oid = OID_802_3_CURRENT_ADDRESS;
pOidData->Length = 6; pOidData->Length = 6;
result = PacketRequest(lpAdapter, FALSE, pOidData); result = PacketRequest(lpAdapter, FALSE, pOidData);
if (!result) { if (!result) {
PacketCloseAdapter(lpAdapter); PacketCloseAdapter(lpAdapter);
ethernet_cleanup(); ethernet_cleanup();
LogError("ethernet.c: error in PacketRequest()\n"); LogError("ethernet.c: error in PacketRequest()\n");
return false; return false;
} }
for (i = 0; i < 6; ++i) for (i = 0; i < 6; ++i)
Ethernet_MAC_Address[i] = pOidData->Data[i]; Ethernet_MAC_Address[i] = pOidData->Data[i];
PacketCloseAdapter(lpAdapter); PacketCloseAdapter(lpAdapter);
/** /**
* Open interface for subsequent sending and receiving * Open interface for subsequent sending and receiving
*/ */
/* Open the output device */ /* Open the output device */
pcap_eth802_fp = pcap_open(if_name, /* name of the device */ pcap_eth802_fp = pcap_open(if_name, /* name of the device */
MAX_MPDU, /* portion of the packet to capture */ MAX_MPDU, /* portion of the packet to capture */
PCAP_OPENFLAG_PROMISCUOUS, /* promiscuous mode */ PCAP_OPENFLAG_PROMISCUOUS, /* promiscuous mode */
eth_timeout, /* read timeout */ eth_timeout, /* read timeout */
NULL, /* authentication on the remote machine */ NULL, /* authentication on the remote machine */
pcap_errbuf /* error buffer */ pcap_errbuf /* error buffer */
); );
if (pcap_eth802_fp == NULL) { if (pcap_eth802_fp == NULL) {
PacketCloseAdapter(lpAdapter); PacketCloseAdapter(lpAdapter);
ethernet_cleanup(); ethernet_cleanup();
sprintf(msgBuf, sprintf(msgBuf,
"ethernet.c: unable to open the adapter. %s is not supported by WinPcap\n", "ethernet.c: unable to open the adapter. %s is not supported by WinPcap\n",
if_name); if_name);
LogError(msgBuf); LogError(msgBuf);
return false; return false;
} }
LogInfo("ethernet.c: ethernet_init() ok.\n"); LogInfo("ethernet.c: ethernet_init() ok.\n");
atexit(ethernet_cleanup); atexit(ethernet_cleanup);
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 };
int mtu_len = 0; int mtu_len = 0;
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_valid()) { if (!ethernet_valid()) {
LogError("ethernet.c: invalid 802.2 ethernet interface descriptor!\n"); LogError("ethernet.c: invalid 802.2 ethernet interface descriptor!\n");
return -1; 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[mtu_len] = dest->mac[i];
mtu_len++; mtu_len++;
} }
} else { } else {
LogError("ethernet.c: invalid destination MAC address!\n"); LogError("ethernet.c: 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[mtu_len] = src->mac[i];
mtu_len++; mtu_len++;
} }
} else { } else {
LogError("ethernet.c: invalid source MAC address!\n"); LogError("ethernet.c: invalid source MAC address!\n");
return -3; return -3;
} }
if ((14 + 3 + pdu_len) > MAX_MPDU) { if ((14 + 3 + pdu_len) > MAX_MPDU) {
LogError("ethernet.c: PDU is too big to send!\n"); LogError("ethernet.c: PDU is too big to send!\n");
return -4; return -4;
} }
/* packet length */ /* packet length */
mtu_len += encode_unsigned16(&mtu[12], 3 /*DSAP,SSAP,LLC */ + pdu_len); mtu_len += encode_unsigned16(&mtu[12], 3 /*DSAP,SSAP,LLC */ + pdu_len);
/* Logical PDU portion */ /* 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 */
if (pcap_sendpacket(pcap_eth802_fp, mtu, mtu_len) != 0) { if (pcap_sendpacket(pcap_eth802_fp, mtu, mtu_len) != 0) {
/* did it get sent? */ /* did it get sent? */
char msgBuf[200]; char msgBuf[200];
sprintf(msgBuf, "ethernet.c: error sending packet: %s\n", sprintf(msgBuf, "ethernet.c: error sending packet: %s\n",
pcap_geterr(pcap_eth802_fp)); pcap_geterr(pcap_eth802_fp));
LogError(msgBuf); LogError(msgBuf);
return -5; return -5;
} }
return mtu_len; return mtu_len;
} }
/* 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. we ommit it due to winpcap API. */ unsigned timeout /* number of milliseconds to wait for a packet. we ommit it due to winpcap API. */
) )
{ {
struct pcap_pkthdr *header; struct pcap_pkthdr *header;
int res; int res;
u_char *pkt_data; u_char *pkt_data;
uint16_t pdu_len = 0; /* return value */ uint16_t pdu_len = 0; /* return value */
/* Make sure the socket is open */ /* Make sure the socket is open */
if (!ethernet_valid()) { if (!ethernet_valid()) {
LogError("ethernet.c: invalid 802.2 ethernet interface descriptor!\n"); LogError("ethernet.c: invalid 802.2 ethernet interface descriptor!\n");
return 0; return 0;
} }
/* Capture a packet */ /* Capture a packet */
res = pcap_next_ex(pcap_eth802_fp, &header, &pkt_data); res = pcap_next_ex(pcap_eth802_fp, &header, &pkt_data);
if (res < 0) { if (res < 0) {
char msgBuf[200]; char msgBuf[200];
sprintf(msgBuf, "ethernet.c: error in receiving packet: %s\n", sprintf(msgBuf, "ethernet.c: error in receiving packet: %s\n",
pcap_geterr(pcap_eth802_fp)); pcap_geterr(pcap_eth802_fp));
return 0; return 0;
} else if (res == 0) } else if (res == 0)
return 0; return 0;
if (header->len == 0 || header->caplen == 0) if (header->len == 0 || header->caplen == 0)
return 0; return 0;
/* the signature of an 802.2 BACnet packet */ /* the signature of an 802.2 BACnet packet */
if ((pkt_data[14] != 0x82) && (pkt_data[15] != 0x82)) { if ((pkt_data[14] != 0x82) && (pkt_data[15] != 0x82)) {
/*eth_log_error("ethernet.c: Non-BACnet packet\n"); */ /*eth_log_error("ethernet.c: Non-BACnet packet\n"); */
return 0; return 0;
} }
/* copy the source address */ /* copy the source address */
src->mac_len = 6; src->mac_len = 6;
memmove(src->mac, &pkt_data[6], 6); memmove(src->mac, &pkt_data[6], 6);
/* 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(&pkt_data[0], Ethernet_MAC_Address, 6) != 0) if ((memcmp(&pkt_data[0], Ethernet_MAC_Address, 6) != 0)
&& (memcmp(&pkt_data[0], Ethernet_Broadcast, 6) != 0)) { && (memcmp(&pkt_data[0], Ethernet_Broadcast, 6) != 0)) {
/*eth_log_error( "ethernet.c: This packet isn't for us\n"); */ /*eth_log_error( "ethernet.c: This packet isn't for us\n"); */
return 0; return 0;
} }
(void) decode_unsigned16(&pkt_data[12], &pdu_len); (void) decode_unsigned16(&pkt_data[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], &pkt_data[17], pdu_len); memmove(&pdu[0], &pkt_data[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( void ethernet_set_my_address(
BACNET_ADDRESS * 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( void ethernet_get_my_address(
BACNET_ADDRESS * 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) BACNET_ADDRESS * dest)
{ /* destination address */ { /* 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->mac_len = 6;
dest->net = BACNET_BROADCAST_NETWORK; dest->net = BACNET_BROADCAST_NETWORK;
dest->len = 0; /* denotes broadcast address */ dest->len = 0; /* denotes broadcast address */
for (i = 0; i < MAX_MAC_LEN; i++) { for (i = 0; i < MAX_MAC_LEN; i++) {
dest->adr[i] = 0; dest->adr[i] = 0;
} }
} }
return; return;
} }
void ethernet_debug_address( void ethernet_debug_address(
const char *info, const char *info,
BACNET_ADDRESS * dest) BACNET_ADDRESS * dest)
{ {
int i = 0; /* counter */ int i = 0; /* counter */
char msgBuf[200]; char msgBuf[200];
if (info) { if (info) {
sprintf(msgBuf, "%s", info); sprintf(msgBuf, "%s", info);
LogError(msgBuf); LogError(msgBuf);
} }
/* if */ /* if */
if (dest) { if (dest) {
sprintf(msgBuf, "Address:\n MAC Length=%d\n MAC Address=", sprintf(msgBuf, "Address:\n MAC Length=%d\n MAC Address=",
dest->mac_len); dest->mac_len);
LogInfo(msgBuf); LogInfo(msgBuf);
for (i = 0; i < MAX_MAC_LEN; i++) { for (i = 0; i < MAX_MAC_LEN; i++) {
sprintf(msgBuf, "%02X ", (unsigned) dest->mac[i]); sprintf(msgBuf, "%02X ", (unsigned) dest->mac[i]);
LogInfo(msgBuf); LogInfo(msgBuf);
} /* for */ } /* for */
LogInfo("\n"); LogInfo("\n");
sprintf(msgBuf, " Net=%hu\n Len=%d\n Adr=", dest->net, dest->len); sprintf(msgBuf, " Net=%hu\n Len=%d\n Adr=", dest->net, dest->len);
LogInfo(msgBuf); LogInfo(msgBuf);
for (i = 0; i < MAX_MAC_LEN; i++) { for (i = 0; i < MAX_MAC_LEN; i++) {
sprintf(msgBuf, "%02X ", (unsigned) dest->adr[i]); sprintf(msgBuf, "%02X ", (unsigned) dest->adr[i]);
LogInfo(msgBuf); LogInfo(msgBuf);
} /* for */ } /* for */
LogInfo("\n"); LogInfo("\n");
} }
/* if ( dest ) */ /* if ( dest ) */
return; return;
} }
+347 -347
View File
@@ -1,347 +1,347 @@
/************************************************************************** /**************************************************************************
* *
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net> * Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including * "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, * without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to * distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to * permit persons to whom the Software is furnished to do so, subject to
* the following conditions: * the following conditions:
* *
* The above copyright notice and this permission notice shall be included * The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software. * in all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* *
*********************************************************************/ *********************************************************************/
/* This is one way to use the embedded BACnet stack under Win32 */ /* This is one way to use the embedded BACnet stack under Win32 */
/* compiled with Borland C++ 5.02 or Visual C++ 6.0 */ /* compiled with Borland C++ 5.02 or Visual C++ 6.0 */
#include <winsock2.h> #include <winsock2.h>
#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"
#include "bacdef.h" #include "bacdef.h"
#include "npdu.h" #include "npdu.h"
#include "apdu.h" #include "apdu.h"
#include "device.h" #include "device.h"
#include "handlers.h" #include "handlers.h"
#include "client.h" #include "client.h"
#include "datalink.h" #include "datalink.h"
#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;
bool I_Am_Request = true; bool I_Am_Request = true;
static void Read_Properties( static void Read_Properties(
void) 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) if (object_props[property] < 0)
next_device = true; next_device = true;
else { else {
status = Send_Read_Property_Request(device_id, /* destination device */ status = Send_Read_Property_Request(device_id, /* destination device */
OBJECT_DEVICE, device_id, object_props[property], OBJECT_DEVICE, device_id, object_props[property],
BACNET_ARRAY_ALL); BACNET_ARRAY_ALL);
if (status) if (status)
property++; property++;
} }
} else } else
next_device = true; next_device = true;
if (next_device) { if (next_device) {
next_device = false; next_device = false;
index++; index++;
if (index >= MAX_ADDRESS_CACHE) if (index >= MAX_ADDRESS_CACHE)
index = 0; index = 0;
property = 0; property = 0;
} }
} }
return; return;
} }
static void LocalIAmHandler( static void LocalIAmHandler(
uint8_t * service_request, uint8_t * service_request,
uint16_t service_len, uint16_t service_len,
BACNET_ADDRESS * src) 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 = len =
iam_decode_service_request(service_request, &device_id, &max_apdu, iam_decode_service_request(service_request, &device_id, &max_apdu,
&segmentation, &vendor_id); &segmentation, &vendor_id);
fprintf(stderr, "Received I-Am Request"); fprintf(stderr, "Received I-Am Request");
if (len != -1) { if (len != -1) {
fprintf(stderr, " from %u!\n", device_id); fprintf(stderr, " from %u!\n", device_id);
address_add(device_id, max_apdu, src); address_add(device_id, max_apdu, src);
} else } else
fprintf(stderr, "!\n"); fprintf(stderr, "!\n");
return; return;
} }
static void Init_Service_Handlers( static void Init_Service_Handlers(
void) 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(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_I_AM, LocalIAmHandler); apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_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(SERVICE_CONFIRMED_READ_PROPERTY, apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY,
handler_read_property); handler_read_property);
apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROPERTY, apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROPERTY,
handler_write_property); handler_write_property);
/* handle the data coming back from confirmed requests */ /* handle the data coming back from confirmed requests */
apdu_set_confirmed_ack_handler(SERVICE_CONFIRMED_READ_PROPERTY, apdu_set_confirmed_ack_handler(SERVICE_CONFIRMED_READ_PROPERTY,
handler_read_property_ack); handler_read_property_ack);
} }
static void print_address( static void print_address(
char *name, char *name,
BACNET_ADDRESS * dest) BACNET_ADDRESS * dest)
{ /* destination address */ { /* 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( static void print_address_cache(
void) 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); fprintf(stderr, "%u\t", device_id);
for (j = 0; j < address.mac_len; j++) { for (j = 0; j < address.mac_len; j++) {
fprintf(stderr, "%02X", address.mac[j]); fprintf(stderr, "%02X", address.mac[j]);
} }
fprintf(stderr, "\t"); fprintf(stderr, "\t");
fprintf(stderr, "%hu\t", max_apdu); fprintf(stderr, "%hu\t", max_apdu);
fprintf(stderr, "%hu\n", address.net); fprintf(stderr, "%hu\n", address.net);
} }
} }
} }
static void Init_DataLink( static void Init_DataLink(
void) void)
{ {
char *pEnv = NULL; char *pEnv = NULL;
#if defined(BACDL_BIP) && BBMD_ENABLED #if defined(BACDL_BIP) && BBMD_ENABLED
long bbmd_port = 0xBAC0; long bbmd_port = 0xBAC0;
long bbmd_address = 0; long bbmd_address = 0;
long bbmd_timetolive_seconds = 60000; long bbmd_timetolive_seconds = 60000;
#endif #endif
#if defined(BACDL_ALL) #if defined(BACDL_ALL)
pEnv = getenv("BACNET_DATALINK"); pEnv = getenv("BACNET_DATALINK");
if (pEnv) { if (pEnv) {
datalink_set(pEnv)); datalink_set(pEnv));
} else { } else {
datalink_set(NULL); datalink_set(NULL);
} }
#endif #endif
#if defined(BACDL_BIP) #if defined(BACDL_BIP)
pEnv = getenv("BACNET_IP_PORT"); pEnv = getenv("BACNET_IP_PORT");
if (pEnv) { if (pEnv) {
bip_set_port(strtol(pEnv, NULL, 0)); bip_set_port(strtol(pEnv, NULL, 0));
} else { } else {
bip_set_port(0xBAC0); bip_set_port(0xBAC0);
} }
BIP_Debug = true; BIP_Debug = true;
#elif defined(BACDL_MSTP) #elif defined(BACDL_MSTP)
pEnv = getenv("BACNET_MAX_INFO_FRAMES"); pEnv = getenv("BACNET_MAX_INFO_FRAMES");
if (pEnv) { if (pEnv) {
dlmstp_set_max_info_frames(strtol(pEnv, NULL, 0)); dlmstp_set_max_info_frames(strtol(pEnv, NULL, 0));
} else { } else {
dlmstp_set_max_info_frames(1); dlmstp_set_max_info_frames(1);
} }
pEnv = getenv("BACNET_MAX_MASTER"); pEnv = getenv("BACNET_MAX_MASTER");
if (pEnv) { if (pEnv) {
dlmstp_set_max_master(strtol(pEnv, NULL, 0)); dlmstp_set_max_master(strtol(pEnv, NULL, 0));
} else { } else {
dlmstp_set_max_master(127); dlmstp_set_max_master(127);
} }
pEnv = getenv("BACNET_MSTP_BAUD"); pEnv = getenv("BACNET_MSTP_BAUD");
if (pEnv) { if (pEnv) {
RS485_Set_Baud_Rate(strtol(pEnv, NULL, 0)); RS485_Set_Baud_Rate(strtol(pEnv, NULL, 0));
} else { } else {
RS485_Set_Baud_Rate(38400); RS485_Set_Baud_Rate(38400);
} }
pEnv = getenv("BACNET_MSTP_MAC"); pEnv = getenv("BACNET_MSTP_MAC");
if (pEnv) { if (pEnv) {
dlmstp_set_mac_address(strtol(pEnv, NULL, 0)); dlmstp_set_mac_address(strtol(pEnv, NULL, 0));
} else { } else {
dlmstp_set_mac_address(127); dlmstp_set_mac_address(127);
} }
#endif #endif
if (!datalink_init(getenv("BACNET_IFACE"))) { if (!datalink_init(getenv("BACNET_IFACE"))) {
exit(1); exit(1);
} }
#if defined(BACDL_BIP) && BBMD_ENABLED #if defined(BACDL_BIP) && BBMD_ENABLED
pEnv = getenv("BACNET_BBMD_PORT"); pEnv = getenv("BACNET_BBMD_PORT");
if (pEnv) { if (pEnv) {
bbmd_port = strtol(pEnv, NULL, 0); bbmd_port = strtol(pEnv, NULL, 0);
if (bbmd_port > 0xFFFF) { if (bbmd_port > 0xFFFF) {
bbmd_port = 0xBAC0; bbmd_port = 0xBAC0;
} }
} }
pEnv = getenv("BACNET_BBMD_TIMETOLIVE"); pEnv = getenv("BACNET_BBMD_TIMETOLIVE");
if (pEnv) { if (pEnv) {
bbmd_timetolive_seconds = strtol(pEnv, NULL, 0); bbmd_timetolive_seconds = strtol(pEnv, NULL, 0);
if (bbmd_timetolive_seconds > 0xFFFF) { if (bbmd_timetolive_seconds > 0xFFFF) {
bbmd_timetolive_seconds = 0xFFFF; bbmd_timetolive_seconds = 0xFFFF;
} }
} }
pEnv = getenv("BACNET_BBMD_ADDRESS"); pEnv = getenv("BACNET_BBMD_ADDRESS");
if (pEnv) { if (pEnv) {
bbmd_address = bip_getaddrbyname(pEnv); bbmd_address = bip_getaddrbyname(pEnv);
if (bbmd_address) { if (bbmd_address) {
struct in_addr addr; struct in_addr addr;
addr.s_addr = bbmd_address; addr.s_addr = bbmd_address;
printf("Server: Registering with BBMD at %s:%ld for %ld seconds\n", printf("Server: Registering with BBMD at %s:%ld for %ld seconds\n",
inet_ntoa(addr), bbmd_port, bbmd_timetolive_seconds); inet_ntoa(addr), bbmd_port, bbmd_timetolive_seconds);
bvlc_register_with_bbmd(bbmd_address, bbmd_port, bvlc_register_with_bbmd(bbmd_address, bbmd_port,
bbmd_timetolive_seconds); bbmd_timetolive_seconds);
} }
} }
#endif #endif
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
BACNET_ADDRESS src = { BACNET_ADDRESS src = {
0}; /* address where message came from */ 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, BACNET_ADDRESS my_address,
broadcast_address; broadcast_address;
(void) argc; (void) argc;
(void) argv; (void) argv;
Device_Set_Object_Instance_Number(4194303); Device_Set_Object_Instance_Number(4194303);
Init_Service_Handlers(); Init_Service_Handlers();
Init_DataLink(); Init_DataLink();
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 = 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, &Rx_Buf[0], pdu_len);
} }
if (I_Am_Request) { if (I_Am_Request) {
I_Am_Request = false; I_Am_Request = false;
Send_I_Am(&Handler_Transmit_Buffer[0]); Send_I_Am(&Handler_Transmit_Buffer[0]);
} else if (Who_Is_Request) { } else if (Who_Is_Request) {
Who_Is_Request = false; Who_Is_Request = false;
Send_WhoIs(-1, -1); Send_WhoIs(-1, -1);
} else { } else {
Read_Properties(); Read_Properties();
} }
/* output */ /* output */
/* blink LEDs, Turn on or off outputs, etc */ /* blink LEDs, Turn on or off outputs, etc */
/* wait for ESC from keyboard before quitting */ /* wait for ESC from keyboard before quitting */
if (kbhit() && (getch() == 0x1B)) if (kbhit() && (getch() == 0x1B))
break; break;
} }
print_address_cache(); print_address_cache();
return 0; return 0;
} }
+53 -53
View File
@@ -1,53 +1,53 @@
/************************************************************************** /**************************************************************************
* *
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net> * Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including * "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, * without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to * distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to * permit persons to whom the Software is furnished to do so, subject to
* the following conditions: * the following conditions:
* *
* The above copyright notice and this permission notice shall be included * The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software. * in all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* *
*********************************************************************/ *********************************************************************/
#ifndef NET_H #ifndef NET_H
#define NET_H #define NET_H
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#define STRICT 1 #define STRICT 1
#include <windows.h> #include <windows.h>
#if (!defined(USE_INADDR) || (USE_INADDR == 0)) && \ #if (!defined(USE_INADDR) || (USE_INADDR == 0)) && \
(!defined(USE_CLASSADDR) || (USE_CLASSADDR == 0)) (!defined(USE_CLASSADDR) || (USE_CLASSADDR == 0))
#include <iphlpapi.h> #include <iphlpapi.h>
#endif #endif
#include <winsock2.h> #include <winsock2.h>
#include <sys/timeb.h> #include <sys/timeb.h>
#include <process.h> #include <process.h>
#ifdef _MSC_VER #ifdef _MSC_VER
#define inline __inline #define inline __inline
#endif #endif
#ifdef __BORLANDC__ #ifdef __BORLANDC__
#define inline __inline #define inline __inline
#endif #endif
#define close closesocket #define close closesocket
typedef int socklen_t; typedef int socklen_t;
#endif #endif
+28 -28
View File
@@ -1,28 +1,28 @@
#ifndef _STDBOOL_H #ifndef _STDBOOL_H
#define _STDBOOL_H #define _STDBOOL_H
#include <stdint.h> #include <stdint.h>
/* C99 Boolean types for compilers without C99 support */ /* C99 Boolean types for compilers without C99 support */
/* http://www.opengroup.org/onlinepubs/009695399/basedefs/stdbool.h.html */ /* http://www.opengroup.org/onlinepubs/009695399/basedefs/stdbool.h.html */
#if !defined(__cplusplus) #if !defined(__cplusplus)
#if !defined(__GNUC__) #if !defined(__GNUC__)
/* _Bool builtin type is included in GCC */ /* _Bool builtin type is included in GCC */
/* ISO C Standard: 5.2.5 An object declared as /* ISO C Standard: 5.2.5 An object declared as
type _Bool is large enough to store type _Bool is large enough to store
the values 0 and 1. */ the values 0 and 1. */
/* We choose 8 bit to match C++ */ /* We choose 8 bit to match C++ */
/* It must also promote to integer */ /* It must also promote to integer */
typedef int8_t _Bool; typedef int8_t _Bool;
#endif #endif
/* ISO C Standard: 7.16 Boolean type */ /* ISO C Standard: 7.16 Boolean type */
#define bool _Bool #define bool _Bool
#define true 1 #define true 1
#define false 0 #define false 0
#define __bool_true_false_are_defined 1 #define __bool_true_false_are_defined 1
#endif #endif
#endif #endif
+31 -31
View File
@@ -1,31 +1,31 @@
/* Defines the standard integer types that are used in code */ /* Defines the standard integer types that are used in code */
/* for the x86 processor and Borland Compiler */ /* for the x86 processor and Borland Compiler */
#ifndef _STDINT_H #ifndef _STDINT_H
#define _STDINT_H #define _STDINT_H
#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 uint32_t; /* 4 bytes 0 to 4294967295 */ typedef unsigned uint32_t; /* 4 bytes 0 to 4294967295 */
typedef int int32_t; /* 4 bytes -2147483647 to 2147483647 */ typedef int 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; */
#define INT8_MIN (-128) #define INT8_MIN (-128)
#define INT16_MIN (-32768) #define INT16_MIN (-32768)
#define INT32_MIN (-2147483647 - 1) #define INT32_MIN (-2147483647 - 1)
#define INT8_MAX 127 #define INT8_MAX 127
#define INT16_MAX 32767 #define INT16_MAX 32767
#define INT32_MAX 2147483647 #define INT32_MAX 2147483647
#define UINT8_MAX 0xff /* 255U */ #define UINT8_MAX 0xff /* 255U */
#define UINT16_MAX 0xffff /* 65535U */ #define UINT16_MAX 0xffff /* 65535U */
#define UINT32_MAX 0xffffffff /* 4294967295U */ #define UINT32_MAX 0xffffffff /* 4294967295U */
#endif /* STDINT_H */ #endif /* STDINT_H */
+322 -322
View File
@@ -1,322 +1,322 @@
/*####COPYRIGHTBEGIN#### /*####COPYRIGHTBEGIN####
------------------------------------------- -------------------------------------------
Copyright (C) 2004 by Steve Karg Copyright (C) 2004 by Steve Karg
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2 as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version. of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program; if not, write to: along with this program; if not, write to:
The Free Software Foundation, Inc. The Free Software Foundation, Inc.
59 Temple Place - Suite 330 59 Temple Place - Suite 330
Boston, MA 02111-1307 Boston, MA 02111-1307
USA. USA.
As a special exception, if other files instantiate templates or As a special exception, if other files instantiate templates or
use macros or inline functions from this file, or you compile use macros or inline functions from this file, or you compile
this file and link it with other works to produce a work based this file and link it with other works to produce a work based
on this file, this file does not by itself cause the resulting on this file, this file does not by itself cause the resulting
work to be covered by the GNU General Public License. However work to be covered by the GNU General Public License. However
the source code for this file must still be made available in the source code for this file must still be made available in
accordance with section (3) of the GNU General Public License. accordance with section (3) of the GNU General Public License.
This exception does not invalidate any other reasons why a work This exception does not invalidate any other reasons why a work
based on this file might be covered by the GNU General Public based on this file might be covered by the GNU General Public
License. License.
------------------------------------------- -------------------------------------------
####COPYRIGHTEND####*/ ####COPYRIGHTEND####*/
/* Functional Description: Generic FIFO library for deeply /* Functional Description: Generic FIFO library for deeply
embedded system. See the unit tests for usage examples. */ embedded system. See the unit tests for usage examples. */
#include <stddef.h> #include <stddef.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "fifo.h" #include "fifo.h"
/**************************************************************************** /****************************************************************************
* DESCRIPTION: Returns the number of elements in the ring buffer * DESCRIPTION: Returns the number of elements in the ring buffer
* RETURN: Number of elements in the ring buffer * RETURN: Number of elements in the ring buffer
* ALGORITHM: none * ALGORITHM: none
* NOTES: none * NOTES: none
*****************************************************************************/ *****************************************************************************/
static unsigned FIFO_Count ( static unsigned FIFO_Count (
FIFO_BUFFER const *b) FIFO_BUFFER const *b)
{ {
return (b ? (b->head - b->tail) : 0); return (b ? (b->head - b->tail) : 0);
} }
/**************************************************************************** /****************************************************************************
* DESCRIPTION: Returns the empty/full status of the ring buffer * DESCRIPTION: Returns the empty/full status of the ring buffer
* RETURN: true if the ring buffer is full, false if it is not. * RETURN: true if the ring buffer is full, false if it is not.
* ALGORITHM: none * ALGORITHM: none
* NOTES: none * NOTES: none
*****************************************************************************/ *****************************************************************************/
static bool FIFO_Full ( static bool FIFO_Full (
FIFO_BUFFER const *b) FIFO_BUFFER const *b)
{ {
return (b ? (FIFO_Count(b) == b->buffer_len) : true); return (b ? (FIFO_Count(b) == b->buffer_len) : true);
} }
/**************************************************************************** /****************************************************************************
* DESCRIPTION: Tests to see if space is available * DESCRIPTION: Tests to see if space is available
* RETURN: true if the number of bytes is available * RETURN: true if the number of bytes is available
* ALGORITHM: none * ALGORITHM: none
* NOTES: none * NOTES: none
*****************************************************************************/ *****************************************************************************/
static bool FIFO_Available ( static bool FIFO_Available (
FIFO_BUFFER const *b, FIFO_BUFFER const *b,
unsigned count) unsigned count)
{ {
return (b ? (count < (b->buffer_len - FIFO_Count(b))) : false); return (b ? (count < (b->buffer_len - FIFO_Count(b))) : false);
} }
/**************************************************************************** /****************************************************************************
* DESCRIPTION: Returns the empty/full status of the ring buffer * DESCRIPTION: Returns the empty/full status of the ring buffer
* RETURN: true if the ring buffer is empty, false if it is not. * RETURN: true if the ring buffer is empty, false if it is not.
* ALGORITHM: none * ALGORITHM: none
* NOTES: none * NOTES: none
*****************************************************************************/ *****************************************************************************/
bool FIFO_Empty( bool FIFO_Empty(
FIFO_BUFFER const *b) FIFO_BUFFER const *b)
{ {
return (b ? (FIFO_Count(b) == 0) : true); return (b ? (FIFO_Count(b) == 0) : true);
} }
/**************************************************************************** /****************************************************************************
* DESCRIPTION: Looks at the data from the head of the list without removing it * DESCRIPTION: Looks at the data from the head of the list without removing it
* RETURN: byte of data, or zero if nothing in the list * RETURN: byte of data, or zero if nothing in the list
* ALGORITHM: none * ALGORITHM: none
* NOTES: Use Empty function to see if there is data to retrieve * NOTES: Use Empty function to see if there is data to retrieve
*****************************************************************************/ *****************************************************************************/
uint8_t FIFO_Peek( uint8_t FIFO_Peek(
FIFO_BUFFER const *b) FIFO_BUFFER const *b)
{ {
if (b) { if (b) {
return (b->buffer[b->tail % b->buffer_len]); return (b->buffer[b->tail % b->buffer_len]);
} }
return 0; return 0;
} }
/**************************************************************************** /****************************************************************************
* DESCRIPTION: Gets the data from the front of the list, and removes it * DESCRIPTION: Gets the data from the front of the list, and removes it
* RETURN: the data, or zero if nothing in the list * RETURN: the data, or zero if nothing in the list
* ALGORITHM: none * ALGORITHM: none
* NOTES: Use Empty function to see if there is data to retrieve * NOTES: Use Empty function to see if there is data to retrieve
*****************************************************************************/ *****************************************************************************/
uint8_t FIFO_Get( uint8_t FIFO_Get(
FIFO_BUFFER * b) FIFO_BUFFER * b)
{ {
uint8_t data_byte = 0; uint8_t data_byte = 0;
if (!FIFO_Empty(b)) { if (!FIFO_Empty(b)) {
data_byte = b->buffer[b->tail % b->buffer_len]; data_byte = b->buffer[b->tail % b->buffer_len];
b->tail++; b->tail++;
} }
return data_byte; return data_byte;
} }
/**************************************************************************** /****************************************************************************
* DESCRIPTION: Adds an element of data to the FIFO * DESCRIPTION: Adds an element of data to the FIFO
* RETURN: true on succesful add, false if not added * RETURN: true on succesful add, false if not added
* ALGORITHM: none * ALGORITHM: none
* NOTES: none * NOTES: none
*****************************************************************************/ *****************************************************************************/
bool FIFO_Put( bool FIFO_Put(
FIFO_BUFFER * b, FIFO_BUFFER * b,
uint8_t data_byte) uint8_t data_byte)
{ {
bool status = false; /* return value */ bool status = false; /* return value */
if (b) { if (b) {
/* limit the ring to prevent overwriting */ /* limit the ring to prevent overwriting */
if (!FIFO_Full(b)) { if (!FIFO_Full(b)) {
b->buffer[b->head % b->buffer_len] = data_byte; b->buffer[b->head % b->buffer_len] = data_byte;
b->head++; b->head++;
status = true; status = true;
} }
} }
return status; return status;
} }
/**************************************************************************** /****************************************************************************
* DESCRIPTION: Adds one or more elements of data to the FIFO * DESCRIPTION: Adds one or more elements of data to the FIFO
* RETURN: true if space available and added, false if not added * RETURN: true if space available and added, false if not added
* ALGORITHM: none * ALGORITHM: none
* NOTES: none * NOTES: none
*****************************************************************************/ *****************************************************************************/
bool FIFO_Add( bool FIFO_Add(
FIFO_BUFFER * b, FIFO_BUFFER * b,
uint8_t *data_bytes, uint8_t *data_bytes,
unsigned count) unsigned count)
{ {
bool status = false; /* return value */ bool status = false; /* return value */
/* limit the ring to prevent overwriting */ /* limit the ring to prevent overwriting */
if (FIFO_Available (b, count)) { if (FIFO_Available (b, count)) {
while (count) { while (count) {
b->buffer[b->head % b->buffer_len] = *data_bytes; b->buffer[b->head % b->buffer_len] = *data_bytes;
b->head++; b->head++;
data_bytes++; data_bytes++;
count--; count--;
} }
status = true; status = true;
} }
return status; return status;
} }
/**************************************************************************** /****************************************************************************
* DESCRIPTION: Flushes any data in the buffer * DESCRIPTION: Flushes any data in the buffer
* RETURN: none * RETURN: none
* ALGORITHM: none * ALGORITHM: none
* NOTES: none * NOTES: none
*****************************************************************************/ *****************************************************************************/
void FIFO_Flush( void FIFO_Flush(
FIFO_BUFFER * b) FIFO_BUFFER * b)
{ {
if (b) { if (b) {
b->tail = b->head; b->tail = b->head;
} }
} }
/**************************************************************************** /****************************************************************************
* DESCRIPTION: Configures the ring buffer * DESCRIPTION: Configures the ring buffer
* RETURN: none * RETURN: none
* ALGORITHM: none * ALGORITHM: none
* NOTES: buffer_len must be a power of two * NOTES: buffer_len must be a power of two
*****************************************************************************/ *****************************************************************************/
void FIFO_Init( void FIFO_Init(
FIFO_BUFFER * b, FIFO_BUFFER * b,
volatile uint8_t *buffer, volatile uint8_t *buffer,
unsigned buffer_len) unsigned buffer_len)
{ {
if (b) { if (b) {
b->head = 0; b->head = 0;
b->tail = 0; b->tail = 0;
b->buffer = buffer; b->buffer = buffer;
b->buffer_len = buffer_len; b->buffer_len = buffer_len;
} }
return; return;
} }
#ifdef TEST #ifdef TEST
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include "ctest.h" #include "ctest.h"
/* test the FIFO */ /* test the FIFO */
/* note: must be a power of two! */ /* note: must be a power of two! */
#define FIFO_BUFFER_SIZE 64 #define FIFO_BUFFER_SIZE 64
void testFIFOBuffer( void testFIFOBuffer(
Test * pTest) Test * pTest)
{ {
FIFO_BUFFER test_buffer; FIFO_BUFFER test_buffer;
volatile uint8_t data_store[FIFO_BUFFER_SIZE]; volatile uint8_t data_store[FIFO_BUFFER_SIZE];
uint8_t test_add_data[40] = {"RoseSteveLouPatRachelJessicaDaniAmyHerb"}; uint8_t test_add_data[40] = {"RoseSteveLouPatRachelJessicaDaniAmyHerb"};
uint8_t test_data; uint8_t test_data;
uint8_t index; uint8_t index;
uint8_t count; uint8_t count;
bool status; bool status;
FIFO_Init(&test_buffer, data_store, sizeof(data_store)); FIFO_Init(&test_buffer, data_store, sizeof(data_store));
ct_test(pTest, FIFO_Empty(&test_buffer)); ct_test(pTest, FIFO_Empty(&test_buffer));
/* load the buffer */ /* load the buffer */
for (test_data = 0; test_data < FIFO_BUFFER_SIZE; test_data++) { for (test_data = 0; test_data < FIFO_BUFFER_SIZE; test_data++) {
status = FIFO_Put(&test_buffer, test_data); status = FIFO_Put(&test_buffer, test_data);
ct_test(pTest, status == true); ct_test(pTest, status == true);
ct_test(pTest, !FIFO_Empty(&test_buffer)); ct_test(pTest, !FIFO_Empty(&test_buffer));
} }
/* not able to put any more */ /* not able to put any more */
status = FIFO_Put(&test_buffer, 42); status = FIFO_Put(&test_buffer, 42);
ct_test(pTest, status == false); ct_test(pTest, status == false);
/* unload the buffer */ /* unload the buffer */
for (index = 0; index < FIFO_BUFFER_SIZE; index++) { for (index = 0; index < FIFO_BUFFER_SIZE; index++) {
ct_test(pTest, !FIFO_Empty(&test_buffer)); ct_test(pTest, !FIFO_Empty(&test_buffer));
test_data = FIFO_Peek(&test_buffer); test_data = FIFO_Peek(&test_buffer);
ct_test(pTest, test_data == index); ct_test(pTest, test_data == index);
test_data = FIFO_Get(&test_buffer); test_data = FIFO_Get(&test_buffer);
ct_test(pTest, test_data == index); ct_test(pTest, test_data == index);
} }
ct_test(pTest, FIFO_Empty(&test_buffer)); ct_test(pTest, FIFO_Empty(&test_buffer));
test_data = FIFO_Get(&test_buffer); test_data = FIFO_Get(&test_buffer);
ct_test(pTest, test_data == 0); ct_test(pTest, test_data == 0);
test_data = FIFO_Peek(&test_buffer); test_data = FIFO_Peek(&test_buffer);
ct_test(pTest, test_data == 0); ct_test(pTest, test_data == 0);
ct_test(pTest, FIFO_Empty(&test_buffer)); ct_test(pTest, FIFO_Empty(&test_buffer));
/* test the ring around the buffer */ /* test the ring around the buffer */
for (index = 0; index < FIFO_BUFFER_SIZE; index++) { for (index = 0; index < FIFO_BUFFER_SIZE; index++) {
ct_test(pTest, FIFO_Empty(&test_buffer)); ct_test(pTest, FIFO_Empty(&test_buffer));
for (count = 1; count < 4; count++) { for (count = 1; count < 4; count++) {
test_data = count; test_data = count;
status = FIFO_Put(&test_buffer, test_data); status = FIFO_Put(&test_buffer, test_data);
ct_test(pTest, status == true); ct_test(pTest, status == true);
ct_test(pTest, !FIFO_Empty(&test_buffer)); ct_test(pTest, !FIFO_Empty(&test_buffer));
} }
for (count = 1; count < 4; count++) { for (count = 1; count < 4; count++) {
ct_test(pTest, !FIFO_Empty(&test_buffer)); ct_test(pTest, !FIFO_Empty(&test_buffer));
test_data = FIFO_Peek(&test_buffer); test_data = FIFO_Peek(&test_buffer);
ct_test(pTest, test_data == count); ct_test(pTest, test_data == count);
test_data = FIFO_Get(&test_buffer); test_data = FIFO_Get(&test_buffer);
ct_test(pTest, test_data == count); ct_test(pTest, test_data == count);
} }
} }
ct_test(pTest, FIFO_Empty(&test_buffer)); ct_test(pTest, FIFO_Empty(&test_buffer));
/* test Add */ /* test Add */
status = FIFO_Add(&test_buffer, test_add_data, sizeof(test_add_data)); status = FIFO_Add(&test_buffer, test_add_data, sizeof(test_add_data));
ct_test(pTest, status == true); ct_test(pTest, status == true);
ct_test(pTest, !FIFO_Empty(&test_buffer)); ct_test(pTest, !FIFO_Empty(&test_buffer));
for (index = 0; index < sizeof(test_add_data); index++) { for (index = 0; index < sizeof(test_add_data); index++) {
/* unload the buffer */ /* unload the buffer */
ct_test(pTest, !FIFO_Empty(&test_buffer)); ct_test(pTest, !FIFO_Empty(&test_buffer));
test_data = FIFO_Peek(&test_buffer); test_data = FIFO_Peek(&test_buffer);
ct_test(pTest, test_data == test_add_data[index]); ct_test(pTest, test_data == test_add_data[index]);
test_data = FIFO_Get(&test_buffer); test_data = FIFO_Get(&test_buffer);
ct_test(pTest, test_data == test_add_data[index]); ct_test(pTest, test_data == test_add_data[index]);
} }
ct_test(pTest, FIFO_Empty(&test_buffer)); ct_test(pTest, FIFO_Empty(&test_buffer));
/* test flush */ /* test flush */
status = FIFO_Add(&test_buffer, test_add_data, sizeof(test_add_data)); status = FIFO_Add(&test_buffer, test_add_data, sizeof(test_add_data));
ct_test(pTest, status == true); ct_test(pTest, status == true);
ct_test(pTest, !FIFO_Empty(&test_buffer)); ct_test(pTest, !FIFO_Empty(&test_buffer));
FIFO_Flush(&test_buffer); FIFO_Flush(&test_buffer);
ct_test(pTest, FIFO_Empty(&test_buffer)); ct_test(pTest, FIFO_Empty(&test_buffer));
return; return;
} }
#ifdef TEST_FIFO_BUFFER #ifdef TEST_FIFO_BUFFER
int main( int main(
void) void)
{ {
Test *pTest; Test *pTest;
bool rc; bool rc;
pTest = ct_create("FIFO Buffer", NULL); pTest = ct_create("FIFO Buffer", NULL);
/* individual tests */ /* individual tests */
rc = ct_addTestFunction(pTest, testFIFOBuffer); rc = ct_addTestFunction(pTest, testFIFOBuffer);
assert(rc); assert(rc);
ct_setStream(pTest, stdout); ct_setStream(pTest, stdout);
ct_run(pTest); ct_run(pTest);
(void) ct_report(pTest); (void) ct_report(pTest);
ct_destroy(pTest); ct_destroy(pTest);
return 0; return 0;
} }
#endif #endif
#endif #endif