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