From dafc55bf9fc45fa5f79ff68d42e4398f8a40e081 Mon Sep 17 00:00:00 2001 From: skarg Date: Mon, 14 Aug 2006 13:59:07 +0000 Subject: [PATCH] Working on the Datalink MS/TP layer - no working yet. --- bacnet-stack/dlmstp.h | 30 ++++++++-- bacnet-stack/mstp.c | 72 +++++++++++++++------- bacnet-stack/mstp.h | 15 +++++ bacnet-stack/ports/pic18/dlmstp.c | 99 +++++++++++++++++++++++++++---- 4 files changed, 174 insertions(+), 42 deletions(-) diff --git a/bacnet-stack/dlmstp.h b/bacnet-stack/dlmstp.h index a85f199d..10f1d1ce 100644 --- a/bacnet-stack/dlmstp.h +++ b/bacnet-stack/dlmstp.h @@ -39,6 +39,7 @@ #include #include #include "bacdef.h" +#include "npdu.h" /* defines specific to MS/TP */ #define MAX_HEADER (2+1+1+1+2+1+2+1) @@ -46,7 +47,6 @@ typedef struct dlmstp_packet { bool ready; /* true if ready to be sent or received */ - bool data_expecting_reply; BACNET_ADDRESS address; /* src or dest address */ unsigned pdu_len; /* packet length */ uint8_t pdu[MAX_MPDU]; /* packet */ @@ -61,23 +61,41 @@ extern "C" { void dlmstp_task(void); void dlmstp_millisecond_timer(void); -/* returns number of bytes sent on success, negative on failure */ + /* returns number of bytes sent on success, negative on failure */ int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */ + BACNET_NPDU_DATA * npdu_data, /* network information */ uint8_t * pdu, /* any data to be sent - may be null */ unsigned pdu_len); /* number of bytes of data */ -/* returns the number of octets in the PDU, or zero on failure */ + /* returns the number of octets in the PDU, or zero on failure */ uint16_t dlmstp_receive(BACNET_ADDRESS * src, /* source address */ uint8_t * pdu, /* PDU data */ uint16_t max_pdu, /* amount of space available in the PDU */ unsigned timeout); /* milliseconds to wait for a packet */ -/* function for MS/TP state machine to use to get a packet - to transmit. It returns the number of bytes in the - packet, or 0 if none. */ + /* function for MS/TP state machine to use to get a packet + to transmit. It returns the number of bytes in the + packet, or 0 if none. */ int dlmstp_get_transmit_pdu(BACNET_ADDRESS * dest, /* destination address */ uint8_t * pdu); /* any data to be sent - may be null */ + /* This parameter represents the value of the Max_Info_Frames property of */ + /* the node's Device object. The value of Max_Info_Frames specifies the */ + /* maximum number of information frames the node may send before it must */ + /* pass the token. Max_Info_Frames may have different values on different */ + /* nodes. This may be used to allocate more or less of the available link */ + /* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */ + /* node, its value shall be 1. */ + void dlmstp_set_max_info_frames(unsigned max_info_frames); + unsigned dlmstp_max_info_frames(void); + + /* This parameter represents the value of the Max_Master property of the */ + /* node's Device object. The value of Max_Master specifies the highest */ + /* allowable address for master nodes. The value of Max_Master shall be */ + /* less than or equal to 127. If Max_Master is not writable in a node, */ + /* its value shall be 127. */ + void dlmstp_set_max_info_frames(uint8_t max_master); + uint8_t dlmstp_max_master(void); void dlmstp_set_my_address(uint8_t my_address); void dlmstp_get_my_address(BACNET_ADDRESS * my_address); diff --git a/bacnet-stack/mstp.c b/bacnet-stack/mstp.c index 599319ff..b5aa758e 100644 --- a/bacnet-stack/mstp.c +++ b/bacnet-stack/mstp.c @@ -128,17 +128,14 @@ const unsigned Tusage_delay = 15; /* larger values for this timeout, not to exceed 100 milliseconds.) */ const unsigned Tusage_timeout = 20; -unsigned MSTP_Create_Frame(uint8_t * buffer, /* where frame is loaded */ +/* creates the 8 octet frame header */ +unsigned MSTP_Create_Frame_Header(uint8_t * buffer, /* where frame is loaded */ unsigned buffer_len, /* amount of space available */ uint8_t frame_type, /* type of frame to send - see defines */ uint8_t destination, /* destination address */ - uint8_t source, /* source address */ - uint8_t * data, /* any data to be sent - may be null */ - unsigned data_len) + uint8_t source) /* source address */ { /* number of bytes of data (up to 501) */ uint8_t crc8 = 0xFF; /* used to calculate the crc value */ - uint16_t crc16 = 0xFFFF; /* used to calculate the crc value */ - unsigned index = 0; /* used to load the data portion of the frame */ /* not enough to do a header */ if (buffer_len < 8) @@ -158,24 +155,53 @@ unsigned MSTP_Create_Frame(uint8_t * buffer, /* where frame is loaded */ crc8 = CRC_Calc_Header(buffer[6], crc8); buffer[7] = ~crc8; - index = 8; - while (data_len && data && (index < buffer_len)) { - buffer[index] = *data; - crc16 = CRC_Calc_Data(buffer[index], crc16); - data++; - index++; - data_len--; + return 8; /* returns the frame length */ +} + +/* copies the PDU to a buffer while calculating its CRC checksum + The CRC checksum is appended to the last two octets. */ +unsigned MSTP_Copy_PDU_CRC(uint8_t * buffer, /* where frame is loaded */ + unsigned buffer_len, /* amount of space available */ + uint16_t crc16, /* used to calculate the crc value */ + uint8_t * data, /* any data to be sent - may be null */ + unsigned data_len) +{ + unsigned index = 0; /* offset into the buffer */ + + if (buffer && data && data_len && ((data_len + 2) < buffer_len)) + { + for (index = 0; index < data_len; index++) + { + buffer[index] = data[index]; + crc16 = CRC_Calc_Data(buffer[index], crc16); + } + + crc16 = ~crc16; + buffer[data_len] = LO_BYTE(crc16); + buffer[data_len + 1] = HI_BYTE(crc16); + index = data_len + 2; } - /* append the data CRC if necessary */ - if (index > 8) { - if ((index + 2) <= buffer_len) { - crc16 = ~crc16; - buffer[index] = LO_BYTE(crc16); - index++; - buffer[index] = HI_BYTE(crc16); - index++; - } else - return 0; + + return index; +} + +unsigned MSTP_Create_Frame(uint8_t * buffer, /* where frame is loaded */ + unsigned buffer_len, /* amount of space available */ + uint8_t frame_type, /* type of frame to send - see defines */ + uint8_t destination, /* destination address */ + uint8_t source, /* source address */ + uint8_t * data, /* any data to be sent - may be null */ + unsigned data_len) +{ /* number of bytes of data (up to 501) */ + uint16_t crc16 = 0xFFFF; /* used to calculate the crc value */ + unsigned index = 0; /* used to load the data portion of the frame */ + + index = MSTP_Create_Frame_Header(buffer, buffer_len, frame_type, + destination, source); + if (data && data_len) + { + index += MSTP_Copy_PDU_CRC(&buffer[index], buffer_len - index, + crc16, data, data_len); } return index; /* returns the frame length */ diff --git a/bacnet-stack/mstp.h b/bacnet-stack/mstp.h index a2e62834..7db177cc 100644 --- a/bacnet-stack/mstp.h +++ b/bacnet-stack/mstp.h @@ -214,6 +214,21 @@ extern "C" { void MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port); +/* creates the 8 octet frame header */ +unsigned MSTP_Create_Frame_Header(uint8_t * buffer, /* where frame is loaded */ + unsigned buffer_len, /* amount of space available */ + uint8_t frame_type, /* type of frame to send - see defines */ + uint8_t destination, /* destination address */ + uint8_t source); /* source address */ +/* copies the PDU to a buffer while calculating its CRC checksum + The CRC checksum is appended to the last two octets. */ +unsigned MSTP_Copy_PDU_CRC(uint8_t * buffer, /* where frame is loaded */ + unsigned buffer_len, /* amount of space available */ + uint16_t crc16, /* used to calculate the crc value */ + uint8_t * data, /* any data to be sent - may be null */ + unsigned data_len); + + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/bacnet-stack/ports/pic18/dlmstp.c b/bacnet-stack/ports/pic18/dlmstp.c index ef3fc7fd..14576b86 100644 --- a/bacnet-stack/ports/pic18/dlmstp.c +++ b/bacnet-stack/ports/pic18/dlmstp.c @@ -30,11 +30,13 @@ #include "mstp.h" #include "dlmstp.h" #include "rs485.h" +#include "npdu.h" static DLMSTP_PACKET Receive_Buffer; static DLMSTP_PACKET Transmit_Buffer; +static uint8_t PDU_Buffer[MAX_MPDU]; +/* local MS/TP port data */ volatile struct mstp_port_struct_t MSTP_Port; /* port data */ -static uint8_t MSTP_MAC_Address = 0x05; /* local MAC address */ void dlmstp_init(void) { @@ -48,7 +50,7 @@ void dlmstp_init(void) Transmit_Buffer.pdu_len = 0; /* initialize hardware */ RS485_Initialize(); - MSTP_Init(&MSTP_Port, MSTP_MAC_Address); + MSTP_Init(&MSTP_Port, MSTP_Port.This_Station); } void dlmstp_cleanup(void) @@ -58,22 +60,57 @@ void dlmstp_cleanup(void) /* returns number of bytes sent on success, zero on failure */ int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */ + BACNET_NPDU_DATA * npdu_data, /* network information */ uint8_t * pdu, /* any data to be sent - may be null */ unsigned pdu_len) { /* number of bytes of data */ bool status; int bytes_sent = 0; + int npdu_len = 0; + uint8_t frame_type = 0; + uint8_t destination = 0; /* destination address */ + BACNET_ADDRESS src; if (Transmit_Buffer.ready == false) { - /* FIXME: how do we get data_expecting_reply? */ - Transmit_Buffer.data_expecting_reply = false; - Receive_Buffer.pdu_len = 0; - memmove(&Transmit_Buffer.address, dest, - sizeof(Transmit_Buffer.address)); - Transmit_Buffer.pdu_len = pdu_len; - /* FIXME: copy the whole PDU or just the pdu_len? */ - memmove(Transmit_Buffer.pdu, pdu, sizeof(Transmit_Buffer.pdu)); - bytes_sent = pdu_len; + if (npdu_data->confirmed_message) + frame_type = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY; + else + frame_type = FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY; + + /* load destination MAC address */ + if (dest && dest->mac_len == 1) { + destination = dest->mac[0]; + } else { + #if PRINT_ENABLED + fprintf(stderr, "mstp: invalid destination MAC address!\n"); + #endif + return -2; + } + dlmstp_get_my_address(&src); + npdu_len = npdu_encode_pdu(&PDU_Buffer[0], dest, &src, npdu_data); + if ((8 + npdu_len + pdu_len) > MAX_MPDU) { + #if PRINT_ENABLED + fprintf(stderr, "mstp: PDU is too big to send!\n"); + #endif + return -4; + } + memcpy(&PDU_Buffer[npdu_len], pdu, pdu_len); +/* copies the PDU to a buffer while calculating its CRC checksum + The CRC checksum is appended to the last two octets. */ +unsigned MSTP_Copy_PDU_CRC(uint8_t * buffer, /* where frame is loaded */ + unsigned buffer_len, /* amount of space available */ + uint16_t crc16, /* used to calculate the crc value */ + uint8_t * data, /* any data to be sent - may be null */ + unsigned data_len); + + bytes_sent = MSTP_Create_Frame( + &Transmit_Buffer.pdu[0], + sizeof(Transmit_Buffer.pdu), + frame_type, + destination, + MSTP_Port.This_Station, + &PDU_Buffer[0], + npdu_len + pdu_len); Transmit_Buffer.ready = true; } @@ -160,15 +197,51 @@ uint16_t dlmstp_put_receive(BACNET_ADDRESS * src, /* source address */ void dlmstp_set_my_address(uint8_t mac_address) { /* FIXME: Master Nodes can only have address 1-127 */ - MSTP_MAC_Address = mac_address; + MSTP_Port.This_Station = mac_address; return; } +/* This parameter represents the value of the Max_Info_Frames property of */ +/* the node's Device object. The value of Max_Info_Frames specifies the */ +/* maximum number of information frames the node may send before it must */ +/* pass the token. Max_Info_Frames may have different values on different */ +/* nodes. This may be used to allocate more or less of the available link */ +/* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */ +/* node, its value shall be 1. */ +void dlmstp_set_max_info_frames(unsigned max_info_frames) +{ + MSTP_Port.Nmax_info_frames = max_info_frames; + + return; +} + +unsigned dlmstp_max_info_frames(void) +{ + return MSTP_Port.Nmax_info_frames; +} + +/* This parameter represents the value of the Max_Master property of the */ +/* node's Device object. The value of Max_Master specifies the highest */ +/* allowable address for master nodes. The value of Max_Master shall be */ +/* less than or equal to 127. If Max_Master is not writable in a node, */ +/* its value shall be 127. */ +void dlmstp_set_max_info_frames(uint8_t max_master) +{ + MSTP_Port.Nmax_master = max_master; + + return; +} + +uint8_t dlmstp_max_master(void) +{ + return MSTP_Port.Nmax_master; +} + void dlmstp_get_my_address(BACNET_ADDRESS * my_address) { my_address->mac_len = 1; - my_address->mac[0] = MSTP_MAC_Address; + my_address->mac[0] = MSTP_Port.This_Station; my_address->net = 0; /* local only, no routing */ my_address->len = 0; for (i = 0; i < MAX_MAC_LEN; i++) {