From 2350fe26a3d264acebbe2dbfa6aa2c806a650609 Mon Sep 17 00:00:00 2001 From: skarg Date: Fri, 18 Mar 2005 22:09:23 +0000 Subject: [PATCH] created --- bacnet-stack/device.c | 203 +++++++++++++++++++++++++++++++++++++++++ bacnet-stack/device.h | 77 ++++++++++++++++ bacnet-stack/tsm.c | 204 ++++++++++++++++++++++++++++++++++++++++++ bacnet-stack/tsm.h | 96 ++++++++++++++++++++ 4 files changed, 580 insertions(+) create mode 100644 bacnet-stack/device.c create mode 100644 bacnet-stack/device.h create mode 100644 bacnet-stack/tsm.c create mode 100644 bacnet-stack/tsm.h diff --git a/bacnet-stack/device.c b/bacnet-stack/device.c new file mode 100644 index 00000000..3e1db776 --- /dev/null +++ b/bacnet-stack/device.c @@ -0,0 +1,203 @@ +/*####COPYRIGHTBEGIN#### + ------------------------------------------- + Copyright (C) 2005 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 "bacdef.h" +#include "bacenum.h" +#include "config.h" // the custom stuff + +static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL; +static char *Vendor_Name = "ASHRAE"; +static uint16_t Vendor_Identifier = 0; +static char *Model_Name = "GNU"; +static char *Firmware_Revision = "1.0"; +static char *Application_Software_Version = "1.0"; +//static char *Location = "USA"; +static char *Description = "server"; +//static uint8_t Protocol_Version = 1; - constant, not settable +//static uint8_t Protocol_Revision = 4; - constant, not settable +//Protocol_Services_Supported +//Protocol_Object_Types_Supported +//Object_List +//static uint16_t Max_APDU_Length_Accepted = MAX_APDU; - constant +//static BACNET_SEGMENTATION Segmentation_Supported = SEGMENTATION_NONE; +//static uint8_t Max_Segments_Accepted = 0; +//VT_Classes_Supported +//Active_VT_Sessions +//Local_Time - rely on OS, if there is one +//Local_Date - rely on OS, if there is one +//UTC_Offset - rely on OS, if there is one +//Daylight_Savings_Status - rely on OS, if there is one +//APDU_Segment_Timeout +static uint16_t APDU_Timeout = 3000; +static uint8_t Number_Of_APDU_Retries = 3; +//List_Of_Session_Keys +//Time_Synchronization_Recipients +//Max_Master - rely on MS/TP subsystem, if there is one +//Max_Info_Frames - rely on MS/TP subsystem, if there is one +//Device_Address_Binding - required, but relies on binding cache +static uint8_t Database_Revision = 0; +//Configuration_Files +//Last_Restore_Time +//Backup_Failure_Timeout +//Active_COV_Subscriptions +//Slave_Proxy_Enable +//Manual_Slave_Address_Binding +//Auto_Slave_Discovery +//Slave_Address_Binding +//Profile_Name + +// methods to manipulate the data +// FIXME: add APDU encode methods for each? +BACNET_DEVICE_STATUS Device_System_Status(void) +{ + return System_Status; +} + +void Device_Set_System_Status(BACNET_DEVICE_STATUS status) +{ + // FIXME: bounds check? + System_Status = status; +} + +const char *Device_Vendor_Name(void) +{ + return Vendor_Name; +} + +void Device_Set_Vendor_Name(const char *name) +{ + Vendor_Name = name; +} + +uint16_t Device_Vendor_Identifier(void) +{ + return Vendor_Identifier; +} + +void Device_Set_Vendor_Identifier(uint16_t vendor_id) +{ + Vendor_Identifier = vendor_id; +} + +const char *Device_Model_Name(void) +{ + return Model_Name; +} + +void Device_Set_Model_Name(const char *name) +{ + Model_Name = name; +} + +const char *Device_Firmware_Revision(void) +{ + return Firmware_Revision; +} + +void Device_Set_Firmware_Revision(const char *name) +{ + Firmware_Revision = name; +} + +const char *Device_Application_Software_Version(void) +{ + return Application_Software_Version; +} + +void Device_Application_Software_Version(const char *name) +{ + Application_Software_Version = name; +} + +const char *Device_Description(void) +{ + return Description; +} + +void Device_Description(const char *name) +{ + Description = name; +} + +uint8_t Device_Protocol_Version(void) +{ + return 1; +} + +uint8_t Device_Protocol_Revision(void) +{ + return 4; +} + +uint16_t Device_Max_APDU_Length_Accepted(void) +{ + return MAX_APDU; +} + +BACNET_SEGMENTATION Device_Segmentation_Supported(void) +{ + return SEGMENTATION_NONE; +} + +//FIXME: This need some bit string encodings... +//Protocol_Services_Supported +//Protocol_Object_Types_Supported +//FIXME: Probably return one at a time, or be supported by +// an object module, or encode the APDU here. +//Object_List + + +uint16_t Device_APDU_Timeout(void) +{ + return APDU_Timeout; +} + +void Device_Set_APDU_Timeout(uint16_t timeout) +{ + APDU_Timeout = timeout; +} + +uint8_t Device_Number_Of_APDU_Retries(void) +{ + return Number_Of_APDU_Retries; +} + +void Device_Set_Number_Of_APDU_Retries(uint8_t retries) +{ + Number_Of_APDU_Retries = retries; +} + diff --git a/bacnet-stack/device.h b/bacnet-stack/device.h new file mode 100644 index 00000000..4a733781 --- /dev/null +++ b/bacnet-stack/device.h @@ -0,0 +1,77 @@ +/*####COPYRIGHTBEGIN#### + ------------------------------------------- + Copyright (C) 2005 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####*/ +#ifndef DEVICE_H +#define DEVICE_H + +#include +#include +#include +#include "bacdef.h" +#include "bacenum.h" + +BACNET_DEVICE_STATUS Device_System_Status(void); +void Device_Set_System_Status(BACNET_DEVICE_STATUS status); + +const char *Device_Vendor_Name(void); +void Device_Set_Vendor_Name(const char *name); + +uint16_t Device_Vendor_Identifier(void); +void Device_Set_Vendor_Identifier(uint16_t vendor_id); + +const char *Device_Model_Name(void); +void Device_Set_Model_Name(const char *name); + +const char *Device_Firmware_Revision(void); +void Device_Set_Firmware_Revision(const char *name); + +const char *Device_Application_Software_Version(void); +void Device_Application_Software_Version(const char *name); + +const char *Device_Description(void); +void Device_Description(const char *name); + +uint8_t Device_Protocol_Version(void); +uint8_t Device_Protocol_Revision(void); + +uint16_t Device_Max_APDU_Length_Accepted(void); +BACNET_SEGMENTATION Device_Segmentation_Supported(void); + +uint16_t Device_APDU_Timeout(void); +void Device_Set_APDU_Timeout(uint16_t timeout); + +uint8_t Device_Number_Of_APDU_Retries(void); +void Device_Set_Number_Of_APDU_Retries(uint8_t retries); + +#endif + diff --git a/bacnet-stack/tsm.c b/bacnet-stack/tsm.c new file mode 100644 index 00000000..4688295b --- /dev/null +++ b/bacnet-stack/tsm.c @@ -0,0 +1,204 @@ +/*####COPYRIGHTBEGIN#### + ------------------------------------------- + Copyright (C) 2005 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 +#include "bits.h" +#include "apdu.h" +#include "bacdef.h" +#include "bacdcode.h" +#include "bacenum.h" +#include "tsm.h" +#include "config.h" +#include "device.h" + +// Transaction State Machine +// Really only needed for segmented messages +// and a little for sending confirmed messages +// If we are only a server and only initiate broadcasts, +// then we don't need a TSM layer. + +// FIXME: not coded for segmentation + +static BACNET_TSM_DATA TSM_List[MAX_TSM_TRANSACTIONS] = {0}; + +// returns MAX_TSM_TRANSACTIONS if not found +uint8_t tsm_find_invokeID_index(uint8_t invokeID) +{ + unsigned i = 0; // counter + uint8_t index = MAX_TSM_TRANSACTIONS; // return value + + for (i = 0; i < MAX_TSM_TRANSACTIONS; i++) + { + if ((TSM_List[i].state != TSM_STATE_IDLE) && + (TSM_List[i].InvokeID == invokeID)) + { + index = i; + break; + } + } + + return index; +} + +bool tsm_transaction_available(void) +{ + bool status = false; // return value + unsigned i = 0; // counter + + for (i = 0; i < MAX_TSM_TRANSACTIONS; i++) + { + if (TSM_List[i].state == TSM_STATE_IDLE) + { + // one is available! + status = true; + break; + } + } + + return status; +} + +uint8_t tsm_transaction_idle_count(void) +{ + uint8_t count = 0; // return value + unsigned i = 0; // counter + + for (i = 0; i < MAX_TSM_TRANSACTIONS; i++) + { + if (TSM_List[i].state == TSM_STATE_IDLE) + { + // one is available! + count++; + } + } + + return count; +} + +uint8_t tsm_next_free_invokeID(void) +{ + static uint8_t current_invokeID = 1; // incremented... + uint8_t index = 0; + uint8_t invokeID = 0; + bool found = false; + + while (!found) + { + index = tsm_find_invokeID_index(current_invokeID); + if (index == MAX_TSM_TRANSACTIONS) + { + found = true; + invokeID = current_invokeID; + } + current_invokeID++; + // skip zero - we treat that internally as invalid or no free + if (current_invokeID == 0) + current_invokeID++; + } + + return invokeID; +} + +// returns 0 if there are no free transactions +uint8_t tsm_request_confirmed_unsegmented_transaction( + BACNET_ADDRESS *src, + BACNET_ADDRESS *dest, + uint8_t *pdu, + uint16_t pdu_len); +{ + uint8_t invokeID = 0; + unsigned i = 0, j = 0; + + // see if there is a free transaction + for (i = 0; i < MAX_TSM_TRANSACTIONS; i++) + { + if (TSM_List[i].state == TSM_STATE_IDLE) + { + // see if the current invoke id is free + invokeID = tsm_next_free_invokeID(); + if (invokeID) + { + // assign the transaction + TSM_List[i].state = TSM_STATE_AWAIT_CONFIRMATION; + TSM_List[i].RetryCount = Device_Number_Of_APDU_Retries(); + // start the timer + TSM_List[i].RequestTimer = Device_APDU_Timeout(); + // copy the data + for (j = 0; j < pdu_len; j++) + { + TSM_List[i].pdu[j] = pdu[j]; + } + } + break; + } + } + + return invokeID; +} + +#ifdef TEST +#include +#include +#include "ctest.h" + +void testTSM(Test * pTest) +{ + + + +} + +#ifdef TEST_TSM +int main(void) +{ + Test *pTest; + bool rc; + + pTest = ct_create("BACnet TSM", NULL); + /* individual tests */ + rc = ct_addTestFunction(pTest, testTSM); + assert(rc); + + ct_setStream(pTest, stdout); + ct_run(pTest); + (void) ct_report(pTest); + ct_destroy(pTest); + + return 0; +} +#endif /* TEST_TSM */ +#endif /* TEST */ + diff --git a/bacnet-stack/tsm.h b/bacnet-stack/tsm.h new file mode 100644 index 00000000..23e6a548 --- /dev/null +++ b/bacnet-stack/tsm.h @@ -0,0 +1,96 @@ +/*####COPYRIGHTBEGIN#### + ------------------------------------------- + Copyright (C) 2005 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####*/ +#ifndef TSM_H +#define TSM_H + +#include +#include +#include + +typedef enum +{ + TSM_STATE_IDLE, + TSM_STATE_AWAIT_CONFIRMATION, + TSM_STATE_AWAIT_RESPONSE, + TSM_STATE_SEGMENTED_REQUEST, + TSM_STATE_SEGMENTED_CONFIRMATION, +} BACNET_TSM_STATE; + +// 5.4.1 Variables And Parameters +// The following variables are defined for each instance of +// Transaction State Machine: +typedef struct BACnet_TSM_Data +{ + // used to count APDU retries + uint8_t RetryCount; + // used to count segment retries + //uint8_t SegmentRetryCount; + // used to control APDU retries and the acceptance of server replies + //bool SentAllSegments; + // stores the sequence number of the last segment received in order + //uint8_t LastSequenceNumber; + // stores the sequence number of the first segment of + // a sequence of segments that fill a window + //uint8_t InitialSequenceNumber; + // stores the current window size + //uint8_t ActualWindowSize; + // stores the window size proposed by the segment sender + //uint8_t ProposedWindowSize; + // used to perform timeout on PDU segments + //uint8_t SegmentTimer; + // used to perform timeout on Confirmed Requests + uint8_t RequestTimer; + // unique id + uint8_t InvokeID; + // state that the TSM is in + BACNET_TSM_STATE state; + // the address it was sent from + BACNET_ADDRESS src; + // the address we sent it to + BACNET_ADDRESS dest; + // copy of the PDU, should we need to send it again + uint8_t pdu[MAX_MPDU]; +} BACNET_TSM_DATA; + +bool tsm_transaction_available(void); +uint8_t tsm_transaction_idle_count(void); +uint8_t tsm_request_confirmed_unsegmented_transaction( + BACNET_ADDRESS *src, + BACNET_ADDRESS *dest, + uint8_t *pdu, + uint16_t pdu_len); + + +#endif +