Feature/mstp zero config option (#564)

* Added a MS/TP zero-config (automatically choose an unused MAC address) using an algorithm that starts with MAC=64 and waits for a random number of PFM (minimum of 8 plus modulo 64) before attempting to choose a MAC sequentially from 64..127. The confirmation uses a 128-bit UUID with the MSTP Test Request frame. The modifications are in src/bacnet/datalink/mstp.c and src/bacnet/datalink/dlmstp.c modules enabling any device to use zero-config if enabled. A working demonstration is in the ports/stm32f4xx for the NUCLEO board. Complete unit testing is included.  Options include lurking forever (wait for a router or another master node before joining) or lurking for a minimum time (enables self forming automatic MAC addressing device nodes).
This commit is contained in:
Steve Karg
2024-02-02 11:18:20 -06:00
committed by GitHub
parent 8f576461a8
commit 1f591db6e7
26 changed files with 2138 additions and 599 deletions
+4
View File
@@ -396,3 +396,7 @@ clean: ports-clean
test: test:
$(MAKE) -s -C test clean $(MAKE) -s -C test clean
$(MAKE) -s -j -C test all $(MAKE) -s -j -C test all
.PHONY: retest
retest:
$(MAKE) -s -j -C test retest
+13 -24
View File
@@ -68,7 +68,7 @@
#define MSTP_HEADER_MAX (2 + 1 + 1 + 1 + 2 + 1) #define MSTP_HEADER_MAX (2 + 1 + 1 + 1 + 2 + 1)
/* local port data - shared with RS-485 */ /* local port data - shared with RS-485 */
static volatile struct mstp_port_struct_t MSTP_Port; static struct mstp_port_struct_t MSTP_Port;
/* track the receive state to know when there is a broken packet */ /* track the receive state to know when there is a broken packet */
static MSTP_RECEIVE_STATE MSTP_Receive_State = MSTP_RECEIVE_STATE_IDLE; static MSTP_RECEIVE_STATE MSTP_Receive_State = MSTP_RECEIVE_STATE_IDLE;
/* buffers needed by mstp port struct */ /* buffers needed by mstp port struct */
@@ -185,7 +185,7 @@ static void mstp_monitor_i_am(uint8_t mac, uint8_t *pdu, uint16_t pdu_len)
} }
static void packet_statistics( static void packet_statistics(
struct timeval *tv, volatile struct mstp_port_struct_t *mstp_port) struct timeval *tv, struct mstp_port_struct_t *mstp_port)
{ {
static struct timeval old_tv = { 0 }; static struct timeval old_tv = { 0 };
static uint8_t old_frame = 255; static uint8_t old_frame = 255;
@@ -286,8 +286,7 @@ static void packet_statistics(
MSTP_Statistics[src].der_reply = delta; MSTP_Statistics[src].der_reply = delta;
} }
} }
if ((mstp_port->ReceivedValidFrame) || if (mstp_port->ReceivedValidFrame) {
(mstp_port->ReceivedValidFrameNotForUs)) {
if ((mstp_port->DataLength <= mstp_port->InputBufferSize) && if ((mstp_port->DataLength <= mstp_port->InputBufferSize) &&
(mstp_port->DataLength > 0)) { (mstp_port->DataLength > 0)) {
mstp_monitor_i_am( mstp_monitor_i_am(
@@ -413,7 +412,7 @@ static void Timer_Silence_Reset(void *pArg)
} }
/* functions used by the MS/TP state machine to put or get data */ /* functions used by the MS/TP state machine to put or get data */
uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port) uint16_t MSTP_Put_Receive(struct mstp_port_struct_t *mstp_port)
{ {
(void)mstp_port; (void)mstp_port;
@@ -423,7 +422,7 @@ uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port)
/* for the MS/TP state machine to use for getting data to send */ /* for the MS/TP state machine to use for getting data to send */
/* Return: amount of PDU data */ /* Return: amount of PDU data */
uint16_t MSTP_Get_Send( uint16_t MSTP_Get_Send(
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout) struct mstp_port_struct_t *mstp_port, unsigned timeout)
{ /* milliseconds to wait for a packet */ { /* milliseconds to wait for a packet */
(void)mstp_port; (void)mstp_port;
(void)timeout; (void)timeout;
@@ -437,7 +436,7 @@ uint16_t MSTP_Get_Send(
* @param nbytes - number of bytes of data to send * @param nbytes - number of bytes of data to send
*/ */
void MSTP_Send_Frame( void MSTP_Send_Frame(
volatile struct mstp_port_struct_t *mstp_port, struct mstp_port_struct_t *mstp_port,
uint8_t * buffer, uint8_t * buffer,
uint16_t nbytes) uint16_t nbytes)
{ {
@@ -447,7 +446,7 @@ void MSTP_Send_Frame(
} }
uint16_t MSTP_Get_Reply( uint16_t MSTP_Get_Reply(
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout) struct mstp_port_struct_t *mstp_port, unsigned timeout)
{ /* milliseconds to wait for a packet */ { /* milliseconds to wait for a packet */
(void)mstp_port; (void)mstp_port;
(void)timeout; (void)timeout;
@@ -623,7 +622,7 @@ static void write_global_header(void)
} }
static void write_received_packet( static void write_received_packet(
volatile struct mstp_port_struct_t *mstp_port, size_t header_len) struct mstp_port_struct_t *mstp_port, size_t header_len)
{ {
uint32_t ts_sec = 0; /* timestamp seconds */ uint32_t ts_sec = 0; /* timestamp seconds */
uint32_t ts_usec = 0; /* timestamp microseconds */ uint32_t ts_usec = 0; /* timestamp microseconds */
@@ -637,8 +636,7 @@ static void write_received_packet(
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
ts_sec = tv.tv_sec; ts_sec = tv.tv_sec;
ts_usec = tv.tv_usec; ts_usec = tv.tv_usec;
if ((mstp_port->ReceivedValidFrame) || if (mstp_port->ReceivedValidFrame) {
(mstp_port->ReceivedValidFrameNotForUs)) {
packet_statistics(&tv, mstp_port); packet_statistics(&tv, mstp_port);
} }
(void)data_write(&ts_sec, sizeof(ts_sec), 1); (void)data_write(&ts_sec, sizeof(ts_sec), 1);
@@ -765,7 +763,7 @@ static bool test_global_header(const char *filename)
return true; return true;
} }
static bool read_received_packet(volatile struct mstp_port_struct_t *mstp_port) static bool read_received_packet(struct mstp_port_struct_t *mstp_port)
{ {
uint32_t ts_sec = 0; /* timestamp seconds */ uint32_t ts_sec = 0; /* timestamp seconds */
uint32_t ts_usec = 0; /* timestamp microseconds */ uint32_t ts_usec = 0; /* timestamp microseconds */
@@ -824,7 +822,6 @@ static bool read_received_packet(volatile struct mstp_port_struct_t *mstp_port)
mstp_port->ReceivedInvalidFrame = false; mstp_port->ReceivedInvalidFrame = false;
if (mstp_port->DataLength == 0) { if (mstp_port->DataLength == 0) {
mstp_port->ReceivedValidFrame = true; mstp_port->ReceivedValidFrame = true;
mstp_port->ReceivedValidFrameNotForUs = true;
} }
} else { } else {
mstp_port->ReceivedValidFrame = false; mstp_port->ReceivedValidFrame = false;
@@ -864,19 +861,16 @@ static bool read_received_packet(volatile struct mstp_port_struct_t *mstp_port)
if (mstp_port->DataCRC == 0xF0B8) { if (mstp_port->DataCRC == 0xF0B8) {
mstp_port->ReceivedInvalidFrame = false; mstp_port->ReceivedInvalidFrame = false;
mstp_port->ReceivedValidFrame = true; mstp_port->ReceivedValidFrame = true;
mstp_port->ReceivedValidFrameNotForUs = true;
} else { } else {
mstp_port->ReceivedInvalidFrame = true; mstp_port->ReceivedInvalidFrame = true;
mstp_port->ReceivedValidFrame = false; mstp_port->ReceivedValidFrame = false;
mstp_port->ReceivedValidFrameNotForUs = false;
} }
} else { } else {
mstp_port->DataLength = 0; mstp_port->DataLength = 0;
} }
if (mstp_port->ReceivedInvalidFrame) { if (mstp_port->ReceivedInvalidFrame) {
Invalid_Frame_Count++; Invalid_Frame_Count++;
} else if ((mstp_port->ReceivedValidFrame) || } else if (mstp_port->ReceivedValidFrame) {
(mstp_port->ReceivedValidFrameNotForUs)) {
packet_statistics(&tv, mstp_port); packet_statistics(&tv, mstp_port);
} }
} else { } else {
@@ -984,7 +978,7 @@ static void print_help(char *filename)
} }
/* initialize some of the variables in the MS/TP Receive structure */ /* initialize some of the variables in the MS/TP Receive structure */
static void mstp_structure_init(volatile struct mstp_port_struct_t *mstp_port) static void mstp_structure_init(struct mstp_port_struct_t *mstp_port)
{ {
if (mstp_port) { if (mstp_port) {
mstp_port->FrameType = FRAME_TYPE_PROPRIETARY_MAX; mstp_port->FrameType = FRAME_TYPE_PROPRIETARY_MAX;
@@ -996,7 +990,6 @@ static void mstp_structure_init(volatile struct mstp_port_struct_t *mstp_port)
mstp_port->EventCount = 0; mstp_port->EventCount = 0;
mstp_port->ReceivedInvalidFrame = false; mstp_port->ReceivedInvalidFrame = false;
mstp_port->ReceivedValidFrame = false; mstp_port->ReceivedValidFrame = false;
mstp_port->ReceivedValidFrameNotForUs = false;
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
} }
} }
@@ -1004,7 +997,7 @@ static void mstp_structure_init(volatile struct mstp_port_struct_t *mstp_port)
/* simple test to packetize the data and print it */ /* simple test to packetize the data and print it */
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
volatile struct mstp_port_struct_t *mstp_port; struct mstp_port_struct_t *mstp_port;
long my_baud = 38400; long my_baud = 38400;
uint32_t packet_count = 0; uint32_t packet_count = 0;
uint32_t header_len = 0; uint32_t header_len = 0;
@@ -1177,10 +1170,6 @@ int main(int argc, char *argv[])
write_received_packet(mstp_port, MSTP_HEADER_MAX); write_received_packet(mstp_port, MSTP_HEADER_MAX);
mstp_structure_init(mstp_port); mstp_structure_init(mstp_port);
packet_count++; packet_count++;
} else if (mstp_port->ReceivedValidFrameNotForUs) {
write_received_packet(mstp_port, MSTP_HEADER_MAX);
mstp_structure_init(mstp_port);
packet_count++;
} else if (mstp_port->ReceivedInvalidFrame) { } else if (mstp_port->ReceivedInvalidFrame) {
if (MSTP_Receive_State == MSTP_RECEIVE_STATE_HEADER) { if (MSTP_Receive_State == MSTP_RECEIVE_STATE_HEADER) {
mstp_port->Index = 0; mstp_port->Index = 0;
+2 -2
View File
@@ -50,9 +50,7 @@ void *dl_mstp_thread(void *pArgs)
uint16_t pdu_len; uint16_t pdu_len;
uint8_t shutdown = 0; uint8_t shutdown = 0;
shared_port_data.Treply_timeout = 260;
shared_port_data.MSTP_Packets = 0; shared_port_data.MSTP_Packets = 0;
shared_port_data.Tusage_timeout = 30;
shared_port_data.RS485_Handle = -1; shared_port_data.RS485_Handle = -1;
shared_port_data.RS485_Baud = B38400; shared_port_data.RS485_Baud = B38400;
shared_port_data.RS485MOD = 0; shared_port_data.RS485MOD = 0;
@@ -95,6 +93,8 @@ void *dl_mstp_thread(void *pArgs)
if (!dlmstp_init(&mstp_port, port->iface)) { if (!dlmstp_init(&mstp_port, port->iface)) {
printf("MSTP %s init failed. Stop.\n", port->iface); printf("MSTP %s init failed. Stop.\n", port->iface);
} }
mstp_port.Treply_timeout = 260;
mstp_port.Tusage_timeout = 30;
port->port_id = create_msgbox(); port->port_id = create_msgbox();
if (port->port_id == INVALID_MSGBOX_ID) { if (port->port_id == INVALID_MSGBOX_ID) {
+6 -8
View File
@@ -75,7 +75,7 @@ static bool run_thread;
/*RT_TASK Receive_Task, Fsm_Task;*/ /*RT_TASK Receive_Task, Fsm_Task;*/
/* local MS/TP port data - shared with RS-485 */ /* local MS/TP port data - shared with RS-485 */
static volatile struct mstp_port_struct_t MSTP_Port; static struct mstp_port_struct_t MSTP_Port;
/* buffers needed by mstp port struct */ /* buffers needed by mstp port struct */
static uint8_t TxBuffer[DLMSTP_MPDU_MAX]; static uint8_t TxBuffer[DLMSTP_MPDU_MAX];
static uint8_t RxBuffer[DLMSTP_MPDU_MAX]; static uint8_t RxBuffer[DLMSTP_MPDU_MAX];
@@ -287,7 +287,7 @@ static void *dlmstp_master_fsm_task(void *pArg)
if (MSTP_Port.ReceivedValidFrame || MSTP_Port.ReceivedInvalidFrame) { if (MSTP_Port.ReceivedValidFrame || MSTP_Port.ReceivedInvalidFrame) {
run_master = true; run_master = true;
} else { } else {
silence = MSTP_Port.SilenceTimer(NULL); silence = MSTP_Port.SilenceTimer(&MSTP_Port);
switch (MSTP_Port.master_state) { switch (MSTP_Port.master_state) {
case MSTP_MASTER_STATE_IDLE: case MSTP_MASTER_STATE_IDLE:
if (silence >= Tno_token) if (silence >= Tno_token)
@@ -353,7 +353,7 @@ void dlmstp_fill_bacnet_address(BACNET_ADDRESS *src, uint8_t mstp_address)
} }
/* for the MS/TP state machine to use for putting received data */ /* for the MS/TP state machine to use for putting received data */
uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port) uint16_t MSTP_Put_Receive(struct mstp_port_struct_t *mstp_port)
{ {
uint16_t pdu_len = 0; uint16_t pdu_len = 0;
@@ -384,8 +384,7 @@ uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port)
/* for the MS/TP state machine to use for getting data to send */ /* for the MS/TP state machine to use for getting data to send */
/* Return: amount of PDU data */ /* Return: amount of PDU data */
uint16_t MSTP_Get_Send( uint16_t MSTP_Get_Send(struct mstp_port_struct_t *mstp_port, unsigned timeout)
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout)
{ /* milliseconds to wait for a packet */ { /* milliseconds to wait for a packet */
uint16_t pdu_len = 0; uint16_t pdu_len = 0;
uint8_t frame_type = 0; uint8_t frame_type = 0;
@@ -421,7 +420,7 @@ uint16_t MSTP_Get_Send(
* @param nbytes - number of bytes of data to send * @param nbytes - number of bytes of data to send
*/ */
void MSTP_Send_Frame( void MSTP_Send_Frame(
volatile struct mstp_port_struct_t *mstp_port, struct mstp_port_struct_t *mstp_port,
uint8_t * buffer, uint8_t * buffer,
uint16_t nbytes) uint16_t nbytes)
{ {
@@ -584,8 +583,7 @@ static bool dlmstp_compare_data_expecting_reply(uint8_t *request_pdu,
} }
/* Get the reply to a DATA_EXPECTING_REPLY frame, or nothing */ /* Get the reply to a DATA_EXPECTING_REPLY frame, or nothing */
uint16_t MSTP_Get_Reply( uint16_t MSTP_Get_Reply(struct mstp_port_struct_t *mstp_port, unsigned timeout)
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout)
{ /* milliseconds to wait for a packet */ { /* milliseconds to wait for a packet */
uint16_t pdu_len = 0; /* return value */ uint16_t pdu_len = 0; /* return value */
bool matched = false; bool matched = false;
+7 -7
View File
@@ -228,7 +228,7 @@ void *dlmstp_receive_fsm_task(void *pArg)
do { do {
RS485_Check_UART_Data(mstp_port); RS485_Check_UART_Data(mstp_port);
MSTP_Receive_Frame_FSM( MSTP_Receive_Frame_FSM(
(volatile struct mstp_port_struct_t *)pArg); (struct mstp_port_struct_t *)pArg);
received_frame = mstp_port->ReceivedValidFrame || received_frame = mstp_port->ReceivedValidFrame ||
mstp_port->ReceivedInvalidFrame; mstp_port->ReceivedInvalidFrame;
if (received_frame) { if (received_frame) {
@@ -274,11 +274,11 @@ void *dlmstp_master_fsm_task(void *pArg)
run_master = true; run_master = true;
break; break;
case MSTP_MASTER_STATE_WAIT_FOR_REPLY: case MSTP_MASTER_STATE_WAIT_FOR_REPLY:
if (silence >= poSharedData->Treply_timeout) if (silence >= mstp_port->Treply_timeout)
run_master = true; run_master = true;
break; break;
case MSTP_MASTER_STATE_POLL_FOR_MASTER: case MSTP_MASTER_STATE_POLL_FOR_MASTER:
if (silence >= poSharedData->Tusage_timeout) if (silence >= mstp_port->Tusage_timeout)
run_master = true; run_master = true;
break; break;
default: default:
@@ -324,7 +324,7 @@ void dlmstp_fill_bacnet_address(BACNET_ADDRESS *src, uint8_t mstp_address)
} }
/* for the MS/TP state machine to use for putting received data */ /* for the MS/TP state machine to use for putting received data */
uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port) uint16_t MSTP_Put_Receive(struct mstp_port_struct_t *mstp_port)
{ {
uint16_t pdu_len = 0; uint16_t pdu_len = 0;
SHARED_MSTP_DATA *poSharedData = (SHARED_MSTP_DATA *)mstp_port->UserData; SHARED_MSTP_DATA *poSharedData = (SHARED_MSTP_DATA *)mstp_port->UserData;
@@ -353,7 +353,7 @@ uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port)
/* for the MS/TP state machine to use for getting data to send */ /* for the MS/TP state machine to use for getting data to send */
/* Return: amount of PDU data */ /* Return: amount of PDU data */
uint16_t MSTP_Get_Send( uint16_t MSTP_Get_Send(
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout) struct mstp_port_struct_t *mstp_port, unsigned timeout)
{ /* milliseconds to wait for a packet */ { /* milliseconds to wait for a packet */
uint16_t pdu_len = 0; uint16_t pdu_len = 0;
uint8_t frame_type = 0; uint8_t frame_type = 0;
@@ -391,7 +391,7 @@ uint16_t MSTP_Get_Send(
* @param nbytes - number of bytes of data to send * @param nbytes - number of bytes of data to send
*/ */
void MSTP_Send_Frame( void MSTP_Send_Frame(
volatile struct mstp_port_struct_t *mstp_port, struct mstp_port_struct_t *mstp_port,
uint8_t * buffer, uint8_t * buffer,
uint16_t nbytes) uint16_t nbytes)
{ {
@@ -555,7 +555,7 @@ bool dlmstp_compare_data_expecting_reply(uint8_t *request_pdu,
/* Get the reply to a DATA_EXPECTING_REPLY frame, or nothing */ /* Get the reply to a DATA_EXPECTING_REPLY frame, or nothing */
uint16_t MSTP_Get_Reply( uint16_t MSTP_Get_Reply(
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout) struct mstp_port_struct_t *mstp_port, unsigned timeout)
{ /* milliseconds to wait for a packet */ { /* milliseconds to wait for a packet */
uint16_t pdu_len = 0; /* return value */ uint16_t pdu_len = 0; /* return value */
bool matched = false; bool matched = false;
-10
View File
@@ -87,16 +87,6 @@ typedef struct shared_mstp_data {
/* buffers needed by mstp port struct */ /* buffers needed by mstp port struct */
uint8_t TxBuffer[DLMSTP_MPDU_MAX]; uint8_t TxBuffer[DLMSTP_MPDU_MAX];
uint8_t RxBuffer[DLMSTP_MPDU_MAX]; uint8_t RxBuffer[DLMSTP_MPDU_MAX];
/* The minimum time without a DataAvailable or ReceiveError event */
/* that a node must wait for a station to begin replying to a */
/* confirmed request: 255 milliseconds. (Implementations may use */
/* larger values for this timeout, not to exceed 300 milliseconds.) */
uint16_t Treply_timeout;
/* The minimum time without a DataAvailable or ReceiveError event that a */
/* node must wait for a remote node to begin using a token or replying to */
/* a Poll For Master frame: 20 milliseconds. (Implementations may use */
/* larger values for this timeout, not to exceed 100 milliseconds.) */
uint8_t Tusage_timeout;
/* Timer that indicates line silence - and functions */ /* Timer that indicates line silence - and functions */
uint16_t SilenceTime; uint16_t SilenceTime;
+7 -7
View File
@@ -59,7 +59,7 @@
#endif #endif
/* local port data - shared with RS-485 */ /* local port data - shared with RS-485 */
static volatile struct mstp_port_struct_t MSTP_Port; static struct mstp_port_struct_t MSTP_Port;
/* buffers needed by mstp port struct */ /* buffers needed by mstp port struct */
static uint8_t RxBuffer[DLMSTP_MPDU_MAX]; static uint8_t RxBuffer[DLMSTP_MPDU_MAX];
static uint8_t TxBuffer[DLMSTP_MPDU_MAX]; static uint8_t TxBuffer[DLMSTP_MPDU_MAX];
@@ -83,7 +83,7 @@ static void Timer_Silence_Reset(void *pArg)
} }
/* functions used by the MS/TP state machine to put or get data */ /* functions used by the MS/TP state machine to put or get data */
uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port) uint16_t MSTP_Put_Receive(struct mstp_port_struct_t *mstp_port)
{ {
(void)mstp_port; (void)mstp_port;
@@ -93,7 +93,7 @@ uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port)
/* for the MS/TP state machine to use for getting data to send */ /* for the MS/TP state machine to use for getting data to send */
/* Return: amount of PDU data */ /* Return: amount of PDU data */
uint16_t MSTP_Get_Send( uint16_t MSTP_Get_Send(
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout) struct mstp_port_struct_t *mstp_port, unsigned timeout)
{ /* milliseconds to wait for a packet */ { /* milliseconds to wait for a packet */
(void)mstp_port; (void)mstp_port;
(void)timeout; (void)timeout;
@@ -107,7 +107,7 @@ uint16_t MSTP_Get_Send(
* @param nbytes - number of bytes of data to send * @param nbytes - number of bytes of data to send
*/ */
void MSTP_Send_Frame( void MSTP_Send_Frame(
volatile struct mstp_port_struct_t *mstp_port, struct mstp_port_struct_t *mstp_port,
uint8_t * buffer, uint8_t * buffer,
uint16_t nbytes) uint16_t nbytes)
{ {
@@ -117,7 +117,7 @@ void MSTP_Send_Frame(
} }
uint16_t MSTP_Get_Reply( uint16_t MSTP_Get_Reply(
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout) struct mstp_port_struct_t *mstp_port, unsigned timeout)
{ /* milliseconds to wait for a packet */ { /* milliseconds to wait for a packet */
(void)mstp_port; (void)mstp_port;
(void)timeout; (void)timeout;
@@ -165,7 +165,7 @@ static int network_init(const char *name, int protocol)
} }
static void snap_received_packet( static void snap_received_packet(
volatile struct mstp_port_struct_t *mstp_port, int sockfd) struct mstp_port_struct_t *mstp_port, int sockfd)
{ {
uint16_t mtu_len = 0; /* number of octets of packet saved in file */ uint16_t mtu_len = 0; /* number of octets of packet saved in file */
unsigned i = 0; /* counter */ unsigned i = 0; /* counter */
@@ -241,7 +241,7 @@ void signal_init(void)
/* simple test to packetize the data and print it */ /* simple test to packetize the data and print it */
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
volatile struct mstp_port_struct_t *mstp_port; struct mstp_port_struct_t *mstp_port;
long my_baud = 38400; long my_baud = 38400;
uint32_t packet_count = 0; uint32_t packet_count = 0;
int sockfd = -1; int sockfd = -1;
+4 -4
View File
@@ -217,7 +217,7 @@ uint32_t RS485_Get_Baud_Rate(void)
* ALGORITHM: none * ALGORITHM: none
* NOTES: none * NOTES: none
*****************************************************************************/ *****************************************************************************/
uint32_t RS485_Get_Port_Baud_Rate(volatile struct mstp_port_struct_t *mstp_port) uint32_t RS485_Get_Port_Baud_Rate(struct mstp_port_struct_t *mstp_port)
{ {
uint32_t baud = 0; uint32_t baud = 0;
SHARED_MSTP_DATA *poSharedData = (SHARED_MSTP_DATA *)mstp_port->UserData; SHARED_MSTP_DATA *poSharedData = (SHARED_MSTP_DATA *)mstp_port->UserData;
@@ -382,7 +382,7 @@ bool RS485_Set_Baud_Rate(uint32_t baud)
* NOTES: none * NOTES: none
*****************************************************************************/ *****************************************************************************/
void RS485_Send_Frame( void RS485_Send_Frame(
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */ struct mstp_port_struct_t *mstp_port, /* port specific data */
uint8_t *buffer, /* frame to send (up to 501 bytes of data) */ uint8_t *buffer, /* frame to send (up to 501 bytes of data) */
uint16_t nbytes) uint16_t nbytes)
{ /* number of bytes of data (up to 501) */ { /* number of bytes of data (up to 501) */
@@ -458,7 +458,7 @@ void RS485_Send_Frame(
* ALGORITHM: none * ALGORITHM: none
* NOTES: none * NOTES: none
*****************************************************************************/ *****************************************************************************/
void RS485_Check_UART_Data(volatile struct mstp_port_struct_t *mstp_port) void RS485_Check_UART_Data(struct mstp_port_struct_t *mstp_port)
{ {
fd_set input; fd_set input;
struct timeval waiter; struct timeval waiter;
@@ -694,7 +694,7 @@ void RS485_Print_Ports(void)
#include <string.h> #include <string.h>
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
volatile struct mstp_port_struct_t mstp_port = { 0 }; struct mstp_port_struct_t mstp_port = { 0 };
uint8_t token_buf[8] = { 0x55, 0xFF, 0x00, 0x7E, 0x07, 0x00, 0x00, 0xFD }; uint8_t token_buf[8] = { 0x55, 0xFF, 0x00, 0x7E, 0x07, 0x00, 0x00, 0xFD };
uint8_t pfm_buf[8] = { 0x55, 0xFF, 0x01, 0x67, 0x07, 0x00, 0x00, 0x3E }; uint8_t pfm_buf[8] = { 0x55, 0xFF, 0x01, 0x67, 0x07, 0x00, 0x00, 0x3E };
long baud = 38400; long baud = 38400;
+3 -3
View File
@@ -57,16 +57,16 @@ extern "C" {
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
void RS485_Send_Frame( void RS485_Send_Frame(
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */ struct mstp_port_struct_t *mstp_port, /* port specific data */
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */ uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
uint16_t nbytes); /* number of bytes of data (up to 501) */ uint16_t nbytes); /* number of bytes of data (up to 501) */
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
void RS485_Check_UART_Data( void RS485_Check_UART_Data(
volatile struct mstp_port_struct_t *mstp_port); /* port specific data */ struct mstp_port_struct_t *mstp_port); /* port specific data */
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
uint32_t RS485_Get_Port_Baud_Rate( uint32_t RS485_Get_Port_Baud_Rate(
volatile struct mstp_port_struct_t *mstp_port); struct mstp_port_struct_t *mstp_port);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
uint32_t RS485_Get_Baud_Rate( uint32_t RS485_Get_Baud_Rate(
void); void);
+4
View File
@@ -17,6 +17,10 @@
"searchDir": [], "searchDir": [],
"svdFile":"${workspaceRoot}/stm32f429.svd", "svdFile":"${workspaceRoot}/stm32f429.svd",
"runToEntryPoint": "main", "runToEntryPoint": "main",
"liveWatch": {
"enabled": true,
"samplesPerSecond": 1
},
"swoConfig": { "swoConfig": {
"enabled": true, "enabled": true,
"cpuFrequency": 8000000, "cpuFrequency": 8000000,
+3 -4
View File
@@ -77,7 +77,7 @@ static struct my_object_functions {
properties that are writable or that may change. properties that are writable or that may change.
The properties that are constant can be hard coded The properties that are constant can be hard coded
into the read-property encoding. */ into the read-property encoding. */
static uint32_t Object_Instance_Number = 103; static uint32_t Object_Instance_Number = BACNET_MAX_INSTANCE;
static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL; static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL;
static BACNET_CHARACTER_STRING My_Object_Name; static BACNET_CHARACTER_STRING My_Object_Name;
static const char *Device_Name_Default = "stm32f4xx"; static const char *Device_Name_Default = "stm32f4xx";
@@ -1131,9 +1131,8 @@ void Device_Init(object_functions_t *object_table)
pObject++; pObject++;
} }
dcc_set_status_duration(COMMUNICATION_ENABLE, 0); dcc_set_status_duration(COMMUNICATION_ENABLE, 0);
if (Object_Instance_Number >= BACNET_MAX_INSTANCE) { if (Object_Instance_Number > BACNET_MAX_INSTANCE) {
Object_Instance_Number = 103; Object_Instance_Number = BACNET_MAX_INSTANCE;
srand(Object_Instance_Number);
} }
characterstring_init_ansi(&My_Object_Name, Device_Name_Default); characterstring_init_ansi(&My_Object_Name, Device_Name_Default);
} }
+27 -2
View File
@@ -22,7 +22,7 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* *
*************************************************************************/ *************************************************************************/
#include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
@@ -30,7 +30,9 @@
#include "stm32f4xx.h" #include "stm32f4xx.h"
#include "stm32f4xx_pwr.h" #include "stm32f4xx_pwr.h"
#include "stm32f4xx_rcc.h" #include "stm32f4xx_rcc.h"
#include "stm32f4xx_rng.h"
#include "system_stm32f4xx.h" #include "system_stm32f4xx.h"
#include "bacnet/basic/object/device.h"
#include "bacnet/basic/sys/mstimer.h" #include "bacnet/basic/sys/mstimer.h"
#include "bacnet/basic/sys/ringbuf.h" #include "bacnet/basic/sys/ringbuf.h"
#include "bacnet/datalink/datalink.h" #include "bacnet/datalink/datalink.h"
@@ -96,13 +98,36 @@ int main(void)
MSTP_Port.OutputBuffer = Output_Buffer; MSTP_Port.OutputBuffer = Output_Buffer;
MSTP_Port.OutputBufferSize = sizeof(Output_Buffer); MSTP_Port.OutputBufferSize = sizeof(Output_Buffer);
/* user data */ /* user data */
MSTP_Port.ZeroConfigEnabled = true;
MSTP_Port.SlaveNodeEnabled = false;
MSTP_User_Data.RS485_Driver = &RS485_Driver; MSTP_User_Data.RS485_Driver = &RS485_Driver;
MSTP_Port.UserData = &MSTP_User_Data; MSTP_Port.UserData = &MSTP_User_Data;
dlmstp_init((char *)&MSTP_Port); dlmstp_init((char *)&MSTP_Port);
dlmstp_set_mac_address(2); if (MSTP_Port.ZeroConfigEnabled) {
dlmstp_set_mac_address(255);
} else {
/* FIXME: get the address from hardware DIP or from EEPROM */
dlmstp_set_mac_address(1);
}
/* FIXME: get the baud rate from hardware DIP or from EEPROM */
dlmstp_set_baud_rate(DLMSTP_BAUD_RATE_DEFAULT); dlmstp_set_baud_rate(DLMSTP_BAUD_RATE_DEFAULT);
/* initialize application layer*/ /* initialize application layer*/
bacnet_init(); bacnet_init();
/* FIXME: get the device ID from EEPROM */
Device_Set_Object_Instance_Number(103);
/* seed stdlib rand() with device-id to get pweudo consisten
zero-config poll slot, or use hardware RNG to get a more random slot */
#ifdef BACNET_ZERO_CONFIG_RNG_HARDWARE
/* enable the random number generator hardware */
RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_RNG, ENABLE);
RNG_Cmd(ENABLE);
while (RNG_GetFlagStatus(RNG_FLAG_DRDY) == RESET) {
/* wait for 32-bit random number to generate */
}
srand(RNG_GetRandomNumber());
#else
srand(Device_Object_Instance_Number());
#endif
for (;;) { for (;;) {
if (mstimer_expired(&Blink_Timer)) { if (mstimer_expired(&Blink_Timer)) {
mstimer_reset(&Blink_Timer); mstimer_reset(&Blink_Timer);
+9 -7
View File
@@ -52,7 +52,7 @@ static HANDLE Receive_Packet_Flag;
HANDLE Received_Frame_Flag; HANDLE Received_Frame_Flag;
static DLMSTP_PACKET Transmit_Packet; static DLMSTP_PACKET Transmit_Packet;
/* local MS/TP port data - shared with RS-485 */ /* local MS/TP port data - shared with RS-485 */
volatile struct mstp_port_struct_t MSTP_Port; static struct mstp_port_struct_t MSTP_Port;
/* buffers needed by mstp port struct */ /* buffers needed by mstp port struct */
static uint8_t TxBuffer[DLMSTP_MPDU_MAX]; static uint8_t TxBuffer[DLMSTP_MPDU_MAX];
static uint8_t RxBuffer[DLMSTP_MPDU_MAX]; static uint8_t RxBuffer[DLMSTP_MPDU_MAX];
@@ -62,11 +62,12 @@ static uint32_t TimeBeginPeriod;
/* 1-millisecond target resolution */ /* 1-millisecond target resolution */
#define TARGET_RESOLUTION 1 #define TARGET_RESOLUTION 1
static uint16_t Timer_Silence(void) static uint16_t Timer_Silence(void *arg)
{ {
uint32_t now = timeGetTime(); uint32_t now = timeGetTime();
uint32_t delta_time = 0; uint32_t delta_time = 0;
(void)arg;
if (SilenceStartTime < now) { if (SilenceStartTime < now) {
delta_time = now - SilenceStartTime; delta_time = now - SilenceStartTime;
} else { } else {
@@ -79,8 +80,9 @@ static uint16_t Timer_Silence(void)
return (uint16_t)delta_time; return (uint16_t)delta_time;
} }
static void Timer_Silence_Reset(void) static void Timer_Silence_Reset(void *arg)
{ {
(void)arg;
SilenceStartTime = timeGetTime(); SilenceStartTime = timeGetTime();
} }
@@ -241,7 +243,7 @@ void dlmstp_fill_bacnet_address(BACNET_ADDRESS *src, uint8_t mstp_address)
} }
/* for the MS/TP state machine to use for putting received data */ /* for the MS/TP state machine to use for putting received data */
uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port) uint16_t MSTP_Put_Receive(struct mstp_port_struct_t *mstp_port)
{ {
uint16_t pdu_len = 0; uint16_t pdu_len = 0;
BOOL rc; BOOL rc;
@@ -266,7 +268,7 @@ uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port)
/* for the MS/TP state machine to use for getting data to send */ /* for the MS/TP state machine to use for getting data to send */
/* Return: amount of PDU data */ /* Return: amount of PDU data */
uint16_t MSTP_Get_Send( uint16_t MSTP_Get_Send(
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout) struct mstp_port_struct_t *mstp_port, unsigned timeout)
{ /* milliseconds to wait for a packet */ { /* milliseconds to wait for a packet */
uint16_t pdu_len = 0; uint16_t pdu_len = 0;
uint8_t destination = 0; /* destination address */ uint8_t destination = 0; /* destination address */
@@ -303,7 +305,7 @@ uint16_t MSTP_Get_Send(
* @param nbytes - number of bytes of data to send * @param nbytes - number of bytes of data to send
*/ */
void MSTP_Send_Frame( void MSTP_Send_Frame(
volatile struct mstp_port_struct_t *mstp_port, struct mstp_port_struct_t *mstp_port,
uint8_t * buffer, uint8_t * buffer,
uint16_t nbytes) uint16_t nbytes)
{ {
@@ -420,7 +422,7 @@ bool dlmstp_compare_data_expecting_reply(uint8_t *request_pdu,
/* Get the reply to a DATA_EXPECTING_REPLY frame, or nothing */ /* Get the reply to a DATA_EXPECTING_REPLY frame, or nothing */
uint16_t MSTP_Get_Reply( uint16_t MSTP_Get_Reply(
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout) struct mstp_port_struct_t *mstp_port, unsigned timeout)
{ /* milliseconds to wait for a packet */ { /* milliseconds to wait for a packet */
uint16_t pdu_len = 0; /* return value */ uint16_t pdu_len = 0; /* return value */
uint8_t destination = 0; /* destination address */ uint8_t destination = 0; /* destination address */
+7 -5
View File
@@ -51,7 +51,7 @@ static HANDLE Receive_Packet_Flag;
HANDLE Received_Frame_Flag; HANDLE Received_Frame_Flag;
static DLMSTP_PACKET Transmit_Packet; static DLMSTP_PACKET Transmit_Packet;
/* local MS/TP port data - shared with RS-485 */ /* local MS/TP port data - shared with RS-485 */
volatile struct mstp_port_struct_t MSTP_Port; struct mstp_port_struct_t MSTP_Port;
/* buffers needed by mstp port struct */ /* buffers needed by mstp port struct */
static uint8_t TxBuffer[DLMSTP_MPDU_MAX]; static uint8_t TxBuffer[DLMSTP_MPDU_MAX];
static uint8_t RxBuffer[DLMSTP_MPDU_MAX]; static uint8_t RxBuffer[DLMSTP_MPDU_MAX];
@@ -71,11 +71,13 @@ static struct mstimer Silence_Timer;
/* Timer that indicates line silence - and functions */ /* Timer that indicates line silence - and functions */
static uint32_t Timer_Silence(void *pArg) static uint32_t Timer_Silence(void *pArg)
{ {
(void)pArg;
return mstimer_elapsed(&Silence_Timer); return mstimer_elapsed(&Silence_Timer);
} }
static void Timer_Silence_Reset(void *pArg) static void Timer_Silence_Reset(void *pArg)
{ {
(void)pArg;
mstimer_set(&Silence_Timer, 0); mstimer_set(&Silence_Timer, 0);
} }
@@ -226,7 +228,7 @@ void dlmstp_fill_bacnet_address(BACNET_ADDRESS *src, uint8_t mstp_address)
} }
/* for the MS/TP state machine to use for putting received data */ /* for the MS/TP state machine to use for putting received data */
uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port) uint16_t MSTP_Put_Receive(struct mstp_port_struct_t *mstp_port)
{ {
uint16_t pdu_len = 0; uint16_t pdu_len = 0;
BOOL rc; BOOL rc;
@@ -252,7 +254,7 @@ uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port)
/* for the MS/TP state machine to use for getting data to send */ /* for the MS/TP state machine to use for getting data to send */
/* Return: amount of PDU data */ /* Return: amount of PDU data */
uint16_t MSTP_Get_Send( uint16_t MSTP_Get_Send(
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout) struct mstp_port_struct_t *mstp_port, unsigned timeout)
{ /* milliseconds to wait for a packet */ { /* milliseconds to wait for a packet */
uint16_t pdu_len = 0; uint16_t pdu_len = 0;
uint8_t destination = 0; /* destination address */ uint8_t destination = 0; /* destination address */
@@ -288,7 +290,7 @@ uint16_t MSTP_Get_Send(
* @param nbytes - number of bytes of data to send * @param nbytes - number of bytes of data to send
*/ */
void MSTP_Send_Frame( void MSTP_Send_Frame(
volatile struct mstp_port_struct_t *mstp_port, struct mstp_port_struct_t *mstp_port,
uint8_t * buffer, uint8_t * buffer,
uint16_t nbytes) uint16_t nbytes)
{ {
@@ -405,7 +407,7 @@ static bool dlmstp_compare_data_expecting_reply(uint8_t *request_pdu,
/* Get the reply to a DATA_EXPECTING_REPLY frame, or nothing */ /* Get the reply to a DATA_EXPECTING_REPLY frame, or nothing */
uint16_t MSTP_Get_Reply( uint16_t MSTP_Get_Reply(
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout) struct mstp_port_struct_t *mstp_port, unsigned timeout)
{ /* milliseconds to wait for a packet */ { /* milliseconds to wait for a packet */
uint16_t pdu_len = 0; /* return value */ uint16_t pdu_len = 0; /* return value */
uint8_t destination = 0; /* destination address */ uint8_t destination = 0; /* destination address */
+2 -2
View File
@@ -421,7 +421,7 @@ bool RS485_Set_Baud_Rate(uint32_t baud)
/* Transmits a Frame on the wire */ /* Transmits a Frame on the wire */
void RS485_Send_Frame( void RS485_Send_Frame(
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */ struct mstp_port_struct_t *mstp_port, /* port specific data */
uint8_t *buffer, /* frame to send (up to 501 bytes of data) */ uint8_t *buffer, /* frame to send (up to 501 bytes of data) */
uint16_t nbytes) uint16_t nbytes)
{ /* number of bytes of data (up to 501) */ { /* number of bytes of data (up to 501) */
@@ -453,7 +453,7 @@ void RS485_Send_Frame(
} }
/* called by timer, interrupt(?) or other thread */ /* called by timer, interrupt(?) or other thread */
void RS485_Check_UART_Data(volatile struct mstp_port_struct_t *mstp_port) void RS485_Check_UART_Data(struct mstp_port_struct_t *mstp_port)
{ {
char lpBuf[1]; char lpBuf[1];
DWORD dwRead = 0; DWORD dwRead = 0;
+2 -2
View File
@@ -58,13 +58,13 @@ extern "C" {
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
void RS485_Send_Frame( void RS485_Send_Frame(
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */ struct mstp_port_struct_t *mstp_port, /* port specific data */
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */ uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
uint16_t nbytes); /* number of bytes of data (up to 501) */ uint16_t nbytes); /* number of bytes of data (up to 501) */
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
void RS485_Check_UART_Data( void RS485_Check_UART_Data(
volatile struct mstp_port_struct_t *mstp_port); /* port specific data */ struct mstp_port_struct_t *mstp_port); /* port specific data */
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
uint32_t RS485_Get_Baud_Rate( uint32_t RS485_Get_Baud_Rate(
+2
View File
@@ -2631,6 +2631,7 @@ bool Network_Port_Read_Range(
(void)pInfo; (void)pInfo;
pRequest->error_class = ERROR_CLASS_PROPERTY; pRequest->error_class = ERROR_CLASS_PROPERTY;
pRequest->error_code = ERROR_CODE_UNKNOWN_PROPERTY; pRequest->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
(void)pInfo;
#endif #endif
break; break;
case PROP_BBMD_FOREIGN_DEVICE_TABLE: case PROP_BBMD_FOREIGN_DEVICE_TABLE:
@@ -2642,6 +2643,7 @@ bool Network_Port_Read_Range(
(void)pInfo; (void)pInfo;
pRequest->error_class = ERROR_CLASS_PROPERTY; pRequest->error_class = ERROR_CLASS_PROPERTY;
pRequest->error_code = ERROR_CODE_UNKNOWN_PROPERTY; pRequest->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
(void)pInfo;
#endif #endif
break; break;
default: default:
+89 -114
View File
@@ -41,7 +41,7 @@ int dlmstp_send_pdu(BACNET_ADDRESS *dest,
{ {
int bytes_sent = 0; int bytes_sent = 0;
unsigned i = 0; /* loop counter */ unsigned i = 0; /* loop counter */
struct dlmstp_user_data_t *port = NULL; struct dlmstp_user_data_t *user = NULL;
struct dlmstp_packet *pkt; struct dlmstp_packet *pkt;
if (!MSTP_Port) { if (!MSTP_Port) {
@@ -50,8 +50,8 @@ int dlmstp_send_pdu(BACNET_ADDRESS *dest,
if (!MSTP_Port->UserData) { if (!MSTP_Port->UserData) {
return 0; return 0;
} }
port = MSTP_Port->UserData; user = MSTP_Port->UserData;
pkt = (struct dlmstp_packet *)(void *)Ringbuf_Data_Peek(&port->PDU_Queue); pkt = (struct dlmstp_packet *)(void *)Ringbuf_Data_Peek(&user->PDU_Queue);
if (pkt && (pdu_len <= DLMSTP_MPDU_MAX)) { if (pkt && (pdu_len <= DLMSTP_MPDU_MAX)) {
if (npdu_data->data_expecting_reply) { if (npdu_data->data_expecting_reply) {
pkt->frame_type = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY; pkt->frame_type = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY;
@@ -71,7 +71,7 @@ int dlmstp_send_pdu(BACNET_ADDRESS *dest,
pkt->address.mac[0] = MSTP_BROADCAST_ADDRESS; pkt->address.mac[0] = MSTP_BROADCAST_ADDRESS;
pkt->address.len = 0; pkt->address.len = 0;
} }
if (Ringbuf_Data_Put(&port->PDU_Queue, (uint8_t *)pkt)) { if (Ringbuf_Data_Put(&user->PDU_Queue, (uint8_t *)pkt)) {
bytes_sent = pdu_len; bytes_sent = pdu_len;
} }
} }
@@ -86,30 +86,30 @@ int dlmstp_send_pdu(BACNET_ADDRESS *dest,
* @return amount of PDU data * @return amount of PDU data
*/ */
uint16_t MSTP_Get_Send( uint16_t MSTP_Get_Send(
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout) struct mstp_port_struct_t *mstp_port, unsigned timeout)
{ {
uint16_t pdu_len = 0; uint16_t pdu_len = 0;
struct dlmstp_packet *pkt; struct dlmstp_packet *pkt;
struct dlmstp_user_data_t *port; struct dlmstp_user_data_t *user;
if (!mstp_port) { if (!mstp_port) {
return 0; return 0;
} }
port = (struct dlmstp_user_data_t *)mstp_port->UserData; user = (struct dlmstp_user_data_t *)mstp_port->UserData;
if (!port) { if (!user) {
return 0; return 0;
} }
if (Ringbuf_Empty(&port->PDU_Queue)) { if (Ringbuf_Empty(&user->PDU_Queue)) {
return 0; return 0;
} }
/* look at next PDU in queue without removing it */ /* look at next PDU in queue without removing it */
pkt = (struct dlmstp_packet *)(void *)Ringbuf_Peek(&port->PDU_Queue); pkt = (struct dlmstp_packet *)(void *)Ringbuf_Peek(&user->PDU_Queue);
/* convert the PDU into the MSTP Frame */ /* convert the PDU into the MSTP Frame */
pdu_len = MSTP_Create_Frame(&mstp_port->OutputBuffer[0], pdu_len = MSTP_Create_Frame(&mstp_port->OutputBuffer[0],
mstp_port->OutputBufferSize, pkt->frame_type, pkt->address.mac[0], mstp_port->OutputBufferSize, pkt->frame_type, pkt->address.mac[0],
mstp_port->This_Station, &pkt->pdu[0], pkt->pdu_len); mstp_port->This_Station, &pkt->pdu[0], pkt->pdu_len);
port->Statistics.transmit_pdu_counter++; user->Statistics.transmit_pdu_counter++;
(void)Ringbuf_Pop(&port->PDU_Queue, NULL); (void)Ringbuf_Pop(&user->PDU_Queue, NULL);
return pdu_len; return pdu_len;
} }
@@ -148,15 +148,12 @@ static bool MSTP_Compare_Data_Expecting_Reply(
request_pdu = &mstp_port->InputBuffer[0]; request_pdu = &mstp_port->InputBuffer[0];
request_pdu_len = mstp_port->DataLength; request_pdu_len = mstp_port->DataLength;
src_address = mstp_port->SourceAddress; src_address = mstp_port->SourceAddress;
/* unused parameters */
request_pdu_len = request_pdu_len;
reply_pdu_len = reply_pdu_len;
/* decode the request data */ /* decode the request data */
request.address.mac[0] = src_address; request.address.mac[0] = src_address;
request.address.mac_len = 1; request.address.mac_len = 1;
offset = (uint16_t)npdu_decode( offset = bacnet_npdu_decode(
&request_pdu[0], NULL, &request.address, &request.npdu_data); &request_pdu[0], request_pdu_len, NULL, &request.address,
&request.npdu_data);
if (request.npdu_data.network_layer_message) { if (request.npdu_data.network_layer_message) {
return false; return false;
} }
@@ -172,8 +169,9 @@ static bool MSTP_Compare_Data_Expecting_Reply(
request.service_choice = request_pdu[offset + 3]; request.service_choice = request_pdu[offset + 3];
/* decode the reply data */ /* decode the reply data */
bacnet_address_copy(&reply.address, dest_address); bacnet_address_copy(&reply.address, dest_address);
offset = (uint16_t)npdu_decode( offset = bacnet_npdu_decode(
&reply_pdu[0], &reply.address, NULL, &reply.npdu_data); &reply_pdu[0], reply_pdu_len, &reply.address, NULL,
&reply.npdu_data);
if (reply.npdu_data.network_layer_message) { if (reply.npdu_data.network_layer_message) {
return false; return false;
} }
@@ -244,26 +242,26 @@ static bool MSTP_Compare_Data_Expecting_Reply(
* @return number of bytes, or 0 if no reply is available * @return number of bytes, or 0 if no reply is available
*/ */
uint16_t MSTP_Get_Reply( uint16_t MSTP_Get_Reply(
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout) struct mstp_port_struct_t *mstp_port, unsigned timeout)
{ {
uint16_t pdu_len = 0; uint16_t pdu_len = 0;
bool matched = false; bool matched = false;
struct dlmstp_packet packet = { 0 }; struct dlmstp_packet packet = { 0 };
struct dlmstp_user_data_t *port = NULL; struct dlmstp_user_data_t *user = NULL;
struct dlmstp_packet *pkt; struct dlmstp_packet *pkt;
if (!mstp_port) { if (!mstp_port) {
return 0; return 0;
} }
port = mstp_port->UserData; user = mstp_port->UserData;
if (!port) { if (!user) {
return 0; return 0;
} }
if (Ringbuf_Empty(&port->PDU_Queue)) { if (Ringbuf_Empty(&user->PDU_Queue)) {
return 0; return 0;
} }
/* look at next PDU in queue without removing it */ /* look at next PDU in queue without removing it */
pkt = (struct dlmstp_packet *)(void *)Ringbuf_Peek(&port->PDU_Queue); pkt = (struct dlmstp_packet *)(void *)Ringbuf_Peek(&user->PDU_Queue);
/* is this the reply to the DER? */ /* is this the reply to the DER? */
matched = MSTP_Compare_Data_Expecting_Reply( matched = MSTP_Compare_Data_Expecting_Reply(
mstp_port, pkt->pdu, pkt->pdu_len, &pkt->address); mstp_port, pkt->pdu, pkt->pdu_len, &pkt->address);
@@ -274,8 +272,8 @@ uint16_t MSTP_Get_Reply(
pdu_len = MSTP_Create_Frame(&mstp_port->OutputBuffer[0], pdu_len = MSTP_Create_Frame(&mstp_port->OutputBuffer[0],
mstp_port->OutputBufferSize, pkt->frame_type, packet.address.mac[0], mstp_port->OutputBufferSize, pkt->frame_type, packet.address.mac[0],
mstp_port->This_Station, &pkt->pdu[0], pkt->pdu_len); mstp_port->This_Station, &pkt->pdu[0], pkt->pdu_len);
port->Statistics.transmit_pdu_counter++; user->Statistics.transmit_pdu_counter++;
(void)Ringbuf_Pop(&port->PDU_Queue, NULL); (void)Ringbuf_Pop(&user->PDU_Queue, NULL);
return pdu_len; return pdu_len;
} }
@@ -286,70 +284,48 @@ uint16_t MSTP_Get_Reply(
* @param buffer - buffer to send * @param buffer - buffer to send
* @param nbytes - number of bytes of data to send * @param nbytes - number of bytes of data to send
*/ */
void MSTP_Send_Frame(volatile struct mstp_port_struct_t *mstp_port, void MSTP_Send_Frame(struct mstp_port_struct_t *mstp_port,
uint8_t *buffer, uint8_t *buffer,
uint16_t nbytes) uint16_t nbytes)
{ {
struct dlmstp_user_data_t *port; struct dlmstp_user_data_t *user;
struct dlmstp_rs485_driver *driver; struct dlmstp_rs485_driver *driver;
if (!mstp_port) { if (!mstp_port) {
return; return;
} }
port = mstp_port->UserData; user = mstp_port->UserData;
if (!port) { if (!user) {
return; return;
} }
driver = port->RS485_Driver; driver = user->RS485_Driver;
if (!driver) { if (!driver) {
return; return;
} }
driver->send(buffer, nbytes); driver->send(buffer, nbytes);
port->Statistics.transmit_frame_counter++; user->Statistics.transmit_frame_counter++;
} }
/** /**
* @brief MS/TP state machine received a frame * @brief MS/TP state machine received a frame
* @return number of bytes queued, or 0 if unable to be queued * @return number of bytes queued, or 0 if unable to be queued
*/ */
uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port) uint16_t MSTP_Put_Receive(struct mstp_port_struct_t *mstp_port)
{ {
struct dlmstp_user_data_t *port = NULL; struct dlmstp_user_data_t *user = NULL;
if (!mstp_port) { if (!mstp_port) {
return 0; return 0;
} }
port = mstp_port->UserData; user = mstp_port->UserData;
if (!port) { if (!user) {
return 0; return 0;
} }
port->ReceivePacketPending = true; user->ReceivePacketPending = true;
return mstp_port->DataLength; return mstp_port->DataLength;
} }
/**
* @brief Baud rate determines turnaround time.
* The minimum time after the end of the stop bit of the final octet of a
* received frame before a node may enable its EIA-485 driver: 40 bit times.
* At 9600 baud, 40 bit times would be about 4.166 milliseconds
* At 19200 baud, 40 bit times would be about 2.083 milliseconds
* At 38400 baud, 40 bit times would be about 1.041 milliseconds
* At 57600 baud, 40 bit times would be about 0.694 milliseconds
* At 76800 baud, 40 bit times would be about 0.520 milliseconds
* At 115200 baud, 40 bit times would be about 0.347 milliseconds
* 40 bits is 4 octets including a start and stop bit with each octet
* @param baud_rate - baud rate in bits per second
* @return: amount of whole milliseconds to wait 1..5
*/
static uint32_t dlmstp_receive_turnaround_time(uint32_t baud_rate)
{
if (baud_rate == 0) {
baud_rate = 9600;
}
return (1 + ((Tturnaround * 1000) / baud_rate));
}
/** /**
* @brief Run the MS/TP state machines, and get packet if available * @brief Run the MS/TP state machines, and get packet if available
* @param pdu - place to put PDU data for the caller * @param pdu - place to put PDU data for the caller
@@ -363,11 +339,10 @@ uint16_t dlmstp_receive(
{ {
uint16_t pdu_len = 0; uint16_t pdu_len = 0;
uint8_t data_register = 0; uint8_t data_register = 0;
struct dlmstp_user_data_t *port; struct dlmstp_user_data_t *user;
struct dlmstp_rs485_driver *driver; struct dlmstp_rs485_driver *driver;
uint16_t i; uint16_t i;
uint32_t milliseconds; uint32_t milliseconds;
uint32_t turnaround_milliseconds;
if (!MSTP_Port) { if (!MSTP_Port) {
return 0; return 0;
@@ -375,11 +350,11 @@ uint16_t dlmstp_receive(
if (!MSTP_Port->UserData) { if (!MSTP_Port->UserData) {
return 0; return 0;
} }
port = MSTP_Port->UserData; user = MSTP_Port->UserData;
if (!port) { if (!user) {
return 0; return 0;
} }
driver = port->RS485_Driver; driver = user->RS485_Driver;
if (!driver) { if (!driver) {
return 0; return 0;
} }
@@ -392,7 +367,6 @@ uint16_t dlmstp_receive(
} }
/* only do receive state machine while we don't have a frame */ /* only do receive state machine while we don't have a frame */
while ((MSTP_Port->ReceivedValidFrame == false) && while ((MSTP_Port->ReceivedValidFrame == false) &&
(MSTP_Port->ReceivedValidFrameNotForUs == false) &&
(MSTP_Port->ReceivedInvalidFrame == false)) { (MSTP_Port->ReceivedInvalidFrame == false)) {
MSTP_Port->DataAvailable = driver->read(&data_register); MSTP_Port->DataAvailable = driver->read(&data_register);
if (MSTP_Port->DataAvailable) { if (MSTP_Port->DataAvailable) {
@@ -404,39 +378,35 @@ uint16_t dlmstp_receive(
break; break;
} }
} }
if (MSTP_Port->ReceivedValidFrameNotForUs || if (MSTP_Port->ReceivedValidFrame || MSTP_Port->ReceivedInvalidFrame) {
MSTP_Port->ReceivedValidFrame || MSTP_Port->ReceivedInvalidFrame) {
/* delay after reception before transmitting - per MS/TP spec */ /* delay after reception before transmitting - per MS/TP spec */
turnaround_milliseconds =
dlmstp_receive_turnaround_time(driver->baud_rate());
milliseconds = MSTP_Port->SilenceTimer(MSTP_Port); milliseconds = MSTP_Port->SilenceTimer(MSTP_Port);
if (milliseconds < turnaround_milliseconds) { if (milliseconds < MSTP_Port->Tturnaround_timeout) {
/* we're waiting; do nothing else */ /* we're waiting; do nothing else */
return 0; return 0;
} }
} }
if (MSTP_Port->ReceivedValidFrameNotForUs) {
MSTP_Port->ReceivedValidFrameNotForUs = false;
port->Statistics.receive_valid_frame_counter++;
}
if (MSTP_Port->ReceivedValidFrame) { if (MSTP_Port->ReceivedValidFrame) {
port->Statistics.receive_valid_frame_counter++; user->Statistics.receive_valid_frame_counter++;
} }
if (MSTP_Port->ReceivedInvalidFrame) { if (MSTP_Port->ReceivedInvalidFrame) {
port->Statistics.receive_invalid_frame_counter++; user->Statistics.receive_invalid_frame_counter++;
} }
if (MSTP_Port->receive_state == MSTP_RECEIVE_STATE_IDLE) { if (MSTP_Port->receive_state == MSTP_RECEIVE_STATE_IDLE) {
/* only do master state machine while rx is idle */ /* only node state machines while rx is idle */
if (MSTP_Port->This_Station <= DEFAULT_MAX_MASTER) { if (MSTP_Port->SlaveNodeEnabled) {
MSTP_Slave_Node_FSM(MSTP_Port);
} else if ((MSTP_Port->This_Station <= DEFAULT_MAX_MASTER) ||
MSTP_Port->ZeroConfigEnabled) {
while (MSTP_Master_Node_FSM(MSTP_Port)) { while (MSTP_Master_Node_FSM(MSTP_Port)) {
/* do nothing while some states fast transition */ /* do nothing while some states fast transition */
}; };
} }
} }
/* see if there is a packet available */ /* see if there is a packet available */
if (port->ReceivePacketPending) { if (user->ReceivePacketPending) {
port->ReceivePacketPending = false; user->ReceivePacketPending = false;
port->Statistics.receive_pdu_counter++; user->Statistics.receive_pdu_counter++;
pdu_len = MSTP_Port->DataLength; pdu_len = MSTP_Port->DataLength;
if (pdu_len > max_pdu) { if (pdu_len > max_pdu) {
/* PDU is too large */ /* PDU is too large */
@@ -498,11 +468,8 @@ void dlmstp_fill_bacnet_address(BACNET_ADDRESS *src, uint8_t mstp_address)
*/ */
void dlmstp_set_mac_address(uint8_t mac_address) void dlmstp_set_mac_address(uint8_t mac_address)
{ {
/* Master Nodes can only have address 0-127 */ if (MSTP_Port) {
if (mac_address <= 127) { MSTP_Port->This_Station = mac_address;
if (MSTP_Port) {
MSTP_Port->This_Station = mac_address;
}
} }
return; return;
@@ -648,12 +615,12 @@ void dlmstp_get_broadcast_address(BACNET_ADDRESS *dest)
bool dlmstp_send_pdu_queue_empty(void) bool dlmstp_send_pdu_queue_empty(void)
{ {
bool status = false; bool status = false;
struct dlmstp_user_data_t *port; struct dlmstp_user_data_t *user;
if (MSTP_Port) { if (MSTP_Port) {
port = MSTP_Port->UserData; user = MSTP_Port->UserData;
if (port) { if (user) {
status = Ringbuf_Empty(&port->PDU_Queue); status = Ringbuf_Empty(&user->PDU_Queue);
} }
} }
@@ -667,12 +634,12 @@ bool dlmstp_send_pdu_queue_empty(void)
bool dlmstp_send_pdu_queue_full(void) bool dlmstp_send_pdu_queue_full(void)
{ {
bool status = false; bool status = false;
struct dlmstp_user_data_t *port; struct dlmstp_user_data_t *user;
if (MSTP_Port) { if (MSTP_Port) {
port = MSTP_Port->UserData; user = MSTP_Port->UserData;
if (port) { if (user) {
status = Ringbuf_Full(&port->PDU_Queue); status = Ringbuf_Full(&user->PDU_Queue);
} }
} }
@@ -686,7 +653,7 @@ bool dlmstp_send_pdu_queue_full(void)
*/ */
void dlmstp_set_baud_rate(uint32_t baud) void dlmstp_set_baud_rate(uint32_t baud)
{ {
struct dlmstp_user_data_t *port; struct dlmstp_user_data_t *user;
struct dlmstp_rs485_driver *driver; struct dlmstp_rs485_driver *driver;
if (!MSTP_Port) { if (!MSTP_Port) {
@@ -695,12 +662,20 @@ void dlmstp_set_baud_rate(uint32_t baud)
if (!MSTP_Port->UserData) { if (!MSTP_Port->UserData) {
return; return;
} }
port = MSTP_Port->UserData; user = MSTP_Port->UserData;
driver = port->RS485_Driver; driver = user->RS485_Driver;
if (!driver) { if (!driver) {
return; return;
} }
driver->baud_rate_set(baud); if (driver->baud_rate_set(baud)) {
/* Tframe_abort=60 bit times, not to exceed 100 milliseconds.*/
if (MSTP_Port->Tframe_abort <= 7) {
/* within baud range, so auto-calculate range based on baud */
MSTP_Port->Tframe_abort = 1+((60*1000UL)/baud);
}
/* Tturnaround=40 bit times */
MSTP_Port->Tturnaround_timeout = 1 + ((Tturnaround * 1000) / baud);
}
} }
/** /**
@@ -709,7 +684,7 @@ void dlmstp_set_baud_rate(uint32_t baud)
*/ */
uint32_t dlmstp_baud_rate(void) uint32_t dlmstp_baud_rate(void)
{ {
struct dlmstp_user_data_t *port; struct dlmstp_user_data_t *user;
struct dlmstp_rs485_driver *driver; struct dlmstp_rs485_driver *driver;
if (!MSTP_Port) { if (!MSTP_Port) {
@@ -718,8 +693,8 @@ uint32_t dlmstp_baud_rate(void)
if (!MSTP_Port->UserData) { if (!MSTP_Port->UserData) {
return 0; return 0;
} }
port = MSTP_Port->UserData; user = MSTP_Port->UserData;
driver = port->RS485_Driver; driver = user->RS485_Driver;
if (!driver) { if (!driver) {
return 0; return 0;
} }
@@ -733,7 +708,7 @@ uint32_t dlmstp_baud_rate(void)
*/ */
void dlmstp_fill_statistics(struct dlmstp_statistics *statistics) void dlmstp_fill_statistics(struct dlmstp_statistics *statistics)
{ {
struct dlmstp_user_data_t *port; struct dlmstp_user_data_t *user;
if (!MSTP_Port) { if (!MSTP_Port) {
return; return;
@@ -741,12 +716,12 @@ void dlmstp_fill_statistics(struct dlmstp_statistics *statistics)
if (!MSTP_Port->UserData) { if (!MSTP_Port->UserData) {
return; return;
} }
port = MSTP_Port->UserData; user = MSTP_Port->UserData;
if (!port) { if (!user) {
return; return;
} }
if (statistics) { if (statistics) {
*statistics = port->Statistics; *statistics = user->Statistics;
} }
} }
@@ -821,18 +796,18 @@ void dlmstp_silence_reset(void *arg)
*/ */
bool dlmstp_init(char *ifname) bool dlmstp_init(char *ifname)
{ {
struct dlmstp_user_data_t *user_data; struct dlmstp_user_data_t *user;
MSTP_Port = (struct mstp_port_struct_t *)ifname; MSTP_Port = (struct mstp_port_struct_t *)ifname;
if (MSTP_Port) { if (MSTP_Port) {
MSTP_Port->SilenceTimer = dlmstp_silence_milliseconds; MSTP_Port->SilenceTimer = dlmstp_silence_milliseconds;
MSTP_Port->SilenceTimerReset = dlmstp_silence_reset; MSTP_Port->SilenceTimerReset = dlmstp_silence_reset;
user_data = (struct dlmstp_user_data_t *)MSTP_Port->UserData; user = (struct dlmstp_user_data_t *)MSTP_Port->UserData;
if (user_data && !user_data->Initialized) { if (user && !user->Initialized) {
Ringbuf_Init(&user_data->PDU_Queue, Ringbuf_Init(&user->PDU_Queue,
(volatile uint8_t *)user_data->PDU_Buffer, (volatile uint8_t *)user->PDU_Buffer,
sizeof(user_data->PDU_Buffer), DLMSTP_MAX_INFO_FRAMES); sizeof(user->PDU_Buffer), DLMSTP_MAX_INFO_FRAMES);
MSTP_Init(MSTP_Port); MSTP_Init(MSTP_Port);
user_data->Initialized = true; user->Initialized = true;
} }
} }
+528 -215
View File
File diff suppressed because it is too large Load Diff
+209 -156
View File
@@ -1,27 +1,27 @@
/************************************************************************** /**************************************************************************
* *
* Copyright (C) 2004 Steve Karg <skarg@users.sourceforge.net> * Copyright (C) 2004 Steve Karg <skarg@users.sourceforge.net>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including * "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, * without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to * distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to * permit persons to whom the Software is furnished to do so, subject to
* the following conditions: * the following conditions:
* *
* The above copyright notice and this permission notice shall be included * The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software. * in all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* *
*********************************************************************/ *********************************************************************/
#ifndef MSTP_H #ifndef MSTP_H
#define MSTP_H #define MSTP_H
@@ -30,6 +30,17 @@
#include <stdbool.h> #include <stdbool.h>
#include "bacnet/bacnet_stack_exports.h" #include "bacnet/bacnet_stack_exports.h"
#include "bacnet/datalink/mstpdef.h" #include "bacnet/datalink/mstpdef.h"
#include "bacnet/config.h"
/* Repeater turnoff delay. The duration of a continuous logical one state */
/* at the active input port of an MS/TP repeater after which the repeater */
/* will enter the IDLE state: 29 bit times < Troff < 40 bit times. */
#ifndef Troff
#define Troff 30
#endif
/* size of the buffer used to send and validate a unique test request */
#define MSTP_UUID_SIZE 16
struct mstp_port_struct_t { struct mstp_port_struct_t {
MSTP_RECEIVE_STATE receive_state; MSTP_RECEIVE_STATE receive_state;
@@ -39,21 +50,21 @@ struct mstp_port_struct_t {
/* A Boolean flag set to TRUE by the Receive State Machine */ /* A Boolean flag set to TRUE by the Receive State Machine */
/* if an error is detected during the reception of a frame. */ /* if an error is detected during the reception of a frame. */
/* Set to FALSE by the Master or Slave Node state machine. */ /* Set to FALSE by the Master or Slave Node state machine. */
unsigned ReceiveError:1; unsigned ReceiveError : 1;
/* There is data in the buffer */ /* There is data in the buffer */
unsigned DataAvailable:1; unsigned DataAvailable : 1;
unsigned ReceivedInvalidFrame:1; unsigned ReceivedInvalidFrame : 1;
/* A Boolean flag set to TRUE by the Receive State Machine */ /* A Boolean flag set to TRUE by the Receive State Machine */
/* if a valid frame is received. */ /* if a valid frame is received. */
/* Set to FALSE by the Master or Slave Node state machine. */ /* Set to FALSE by the Master or Slave Node state machine. */
unsigned ReceivedValidFrame:1; unsigned ReceivedValidFrame : 1;
/* A Boolean flag set to TRUE by the Receive State Machine */ /* A Boolean flag set to TRUE by the master machine if this node is the
/* if a valid frame is received but it is not addressed to us. */ only known master node. */
/* Set to FALSE by the Master or Slave Node state machine. */ unsigned SoleMaster : 1;
unsigned ReceivedValidFrameNotForUs:1; /* A Boolean flag set to TRUE if this node is a slave node */
/* A Boolean flag set to TRUE by the master machine if this node is the */ unsigned SlaveNodeEnabled : 1;
/* only known master node. */ /* A Boolean flag set to TRUE if this node is using a ZeroConfig address */
unsigned SoleMaster:1; unsigned ZeroConfigEnabled : 1;
/* stores the latest received data */ /* stores the latest received data */
uint8_t DataRegister; uint8_t DataRegister;
/* Used to accumulate the CRC on the data field of a frame. */ /* Used to accumulate the CRC on the data field of a frame. */
@@ -65,185 +76,227 @@ struct mstp_port_struct_t {
uint16_t DataLength; uint16_t DataLength;
/* Used to store the destination address of a received frame. */ /* Used to store the destination address of a received frame. */
uint8_t DestinationAddress; uint8_t DestinationAddress;
/* Used to count the number of received octets or errors. */ /* Used to count the number of received octets or errors.
/* This is used in the detection of link activity. */ This is used in the detection of link activity.
/* Compared to Nmin_octets */ Compared to Nmin_octets */
uint8_t EventCount; uint8_t EventCount;
/* Used to store the frame type of a received frame. */ /* Used to store the frame type of a received frame. */
uint8_t FrameType; uint8_t FrameType;
/* The number of frames sent by this node during a single token hold. */ /* The number of frames sent by this node during a single token hold.
/* When this counter reaches the value Nmax_info_frames, the node must */ When this counter reaches the value Nmax_info_frames, the node must */
/* pass the token. */ /* pass the token. */
uint8_t FrameCount; uint8_t FrameCount;
/* Used to accumulate the CRC on the header of a frame. */ /* Used to accumulate the CRC on the header of a frame. */
uint8_t HeaderCRC; uint8_t HeaderCRC;
/* Used to store the actual CRC from the header. */ /* Used to store the actual CRC from the header. */
uint8_t HeaderCRCActual; uint8_t HeaderCRCActual;
/* Used as an index by the Receive State Machine, up to a maximum value of */ /* Used as an index by the Receive State Machine,
/* InputBufferSize. */ up to a maximum value of InputBufferSize. */
uint32_t Index; uint32_t Index;
/* An array of octets, used to store octets as they are received. */ /* An array of octets, used to store octets as they are received.
/* InputBuffer is indexed from 0 to InputBufferSize-1. */ InputBuffer is indexed from 0 to InputBufferSize-1. */
/* The maximum size of a frame is 501 octets. */ /* Note: assign this to an actual array of bytes! */
/* FIXME: assign this to an actual array of bytes! */
/* Note: the buffer is designed as a pointer since some compilers /* Note: the buffer is designed as a pointer since some compilers
and microcontroller architectures have limits as to places to and microcontroller architectures have limits as to places to
hold contiguous memory. */ hold contiguous memory. */
uint8_t *InputBuffer; uint8_t *InputBuffer;
uint16_t InputBufferSize; uint16_t InputBufferSize;
/* "Next Station," the MAC address of the node to which This Station passes */ /* "Next Station," the MAC address of the node to which
/* the token. If the Next_Station is unknown, Next_Station shall be equal to */ This Station passes */
/* the token. If the Next_Station is unknown, Next_Station
shall be equal to */
/* This_Station. */ /* This_Station. */
uint8_t Next_Station; uint8_t Next_Station;
/* "Poll Station," the MAC address of the node to which This Station last */ /* "Poll Station," the MAC address of the node to which This Station last
/* sent a Poll For Master. This is used during token maintenance. */ sent a Poll For Master. This is used during token maintenance. */
uint8_t Poll_Station; uint8_t Poll_Station;
/* A counter of transmission retries used for Token and Poll For Master */ /* A counter of transmission retries used for Token and Poll For Master
/* transmission. */ transmission. */
unsigned RetryCount; unsigned RetryCount;
/* A timer with nominal 5 millisecond resolution used to measure and */ /* A timer with nominal 5 millisecond resolution used to measure
/* generate silence on the medium between octets. It is incremented by a */ and generate silence on the medium between octets. It is
/* timer process and is cleared by the Receive State Machine when activity */ incremented by a timer process and is cleared by the Receive
/* is detected and by the SendFrame procedure as each octet is transmitted. */ State Machine when activity is detected and by the SendFrame
/* Since the timer resolution is limited and the timer is not necessarily */ procedure as each octet is transmitted. */
/* synchronized to other machine events, a timer value of N will actually */ /* Since the timer resolution is limited and the timer is not necessarily
/* denote intervals between N-1 and N */ synchronized to other machine events, a timer value of N will actually
denote intervals between N-1 and N */
/* Note: done here as functions - put into timer task or ISR /* Note: done here as functions - put into timer task or ISR
so that you can be atomic on 8 bit microcontrollers */ so that you can be atomic on 8 bit microcontrollers */
uint32_t( uint32_t (*SilenceTimer)(void *pArg);
*SilenceTimer) ( void (*SilenceTimerReset)(void *pArg);
void *pArg);
void (
*SilenceTimerReset) (
void *pArg);
/* A timer used to measure and generate Reply Postponed frames. It is */ /* A timer used to measure and generate Reply Postponed frames. It is
/* incremented by a timer process and is cleared by the Master Node State */ incremented by a timer process and is cleared by the Master Node State
/* Machine when a Data Expecting Reply Answer activity is completed. */ Machine when a Data Expecting Reply Answer activity is completed.
/* note: we always send a reply postponed since a message other than note: we always send a reply postponed since a message other than
the reply may be in the transmit queue */ the reply may be in the transmit queue */
/* uint16_t ReplyPostponedTimer; */ /* uint16_t ReplyPostponedTimer; */
/* Used to store the Source Address of a received frame. */ /* Used to store the Source Address of a received frame. */
uint8_t SourceAddress; uint8_t SourceAddress;
/* The number of tokens received by this node. When this counter reaches the */ /* The number of tokens received by this node. When this counter
/* value Npoll, the node polls the address range between TS and NS for */ reaches the value Npoll, the node polls the address range between
/* additional master nodes. TokenCount is set to zero at the end of the */ TS and NS for additional master nodes. TokenCount is set to zero
/* polling process. */ at the end of the polling process. */
unsigned TokenCount; unsigned TokenCount;
/* "This Station," the MAC address of this node. TS is generally read from a */ /* "This Station," the MAC address of this node. TS is generally read from a
/* hardware DIP switch, or from nonvolatile memory. Valid values for TS are */ hardware DIP switch, or from nonvolatile memory. Valid values for TS are
/* 0 to 254. The value 255 is used to denote broadcast when used as a */ 0 to 254. The value 255 is used to denote broadcast when used as a
/* destination address but is not allowed as a value for TS. */ destination address but is not allowed as a value for TS. */
uint8_t This_Station; uint8_t This_Station;
/* This parameter represents the value of the Max_Info_Frames property of */ /* 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 */ 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 */ maximum number of information frames the node may send before it must
/* pass the token. Max_Info_Frames may have different values on different */ 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 */ 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 */ bandwidth to particular nodes. If Max_Info_Frames is not writable in a
/* node, its value shall be 1. */ node, its value shall be 1.*/
uint8_t Nmax_info_frames; uint8_t Nmax_info_frames;
/* This parameter represents the value of the Max_Master property of the */ /* This parameter represents the value of the Max_Master property of the
/* node's Device object. The value of Max_Master specifies the highest */ node's Device object. The value of Max_Master specifies the highest
/* allowable address for master nodes. The value of Max_Master shall be */ 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, */ less than or equal to 127. If Max_Master is not writable in a node,
/* its value shall be 127. */ its value shall be 127. */
uint8_t Nmax_master; uint8_t Nmax_master;
/* An array of octets, used to store octets for transmitting */ /* An array of octets, used to store octets for transmitting
/* OutputBuffer is indexed from 0 to OutputBufferSize-1. */ OutputBuffer is indexed from 0 to OutputBufferSize-1.
/* The maximum size of a frame is 501 octets. */ FIXME: assign this to an actual array of bytes!
/* FIXME: assign this to an actual array of bytes! */ Note: the buffer is designed as a pointer since some compilers
/* Note: the buffer is designed as a pointer since some compilers
and microcontroller architectures have limits as to places to and microcontroller architectures have limits as to places to
hold contiguous memory. */ hold contiguous memory. */
uint8_t *OutputBuffer; uint8_t *OutputBuffer;
uint16_t OutputBufferSize; uint16_t OutputBufferSize;
/* orderly transition tracking for zero-configuration node startup */
MSTP_ZERO_CONFIG_STATE Zero_Config_State;
/* the MAC address that this node is testing for MAC addresses
that are not in-use.*/
uint8_t Zero_Config_Station;
/* Used to count the number of received poll-for-master frames
This is used in the detection of addresses not in-use. */
uint8_t Poll_Count;
/* This parameter is random value 1..64, used to choose the poll slot */
uint8_t Npoll_slot;
/* UUID for storing the unique identifier for this node
used to send and validate a unique test request and response */
uint8_t UUID[MSTP_UUID_SIZE];
/* amount of silence time to wait, in milliseconds */
uint32_t Zero_Config_Silence;
/* This parameter tracks the highest polled station address.
The value of this parameter shall be less than or equal to 127.
In the absence of other fixed address nodes, this value shall be 127. */
uint8_t Zero_Config_Max_Master;
/* The minimum time without a DataAvailable or ReceiveError event within
a frame before a receiving node may discard the frame: 60 bit times.
Implementations may use larger values for this timeout,
not to exceed 100 milliseconds.
Tframe_abort = 1 + ((60*1000UL)/RS485_Baud); */
uint8_t Tframe_abort;
/* The maximum time a node may wait after reception of a frame that
expects a reply before sending the first octet of a reply or
Reply Postponed frame: 250 milliseconds. */
uint8_t Treply_delay;
/* The minimum time without a DataAvailable or ReceiveError event
that a node must wait for a station to begin replying to a
confirmed request: 255 milliseconds. (Implementations may use
larger values for this timeout, not to exceed 300 milliseconds.) */
uint16_t Treply_timeout;
/* The minimum time without a DataAvailable or ReceiveError event
that a node must wait for a remote node to begin using a token
or replying to a Poll For Master frame: 20 milliseconds.
(Implementations may use larger values for this timeout,
not to exceed 35 milliseconds.) */
uint8_t Tusage_timeout;
/* The minimum time after the end of the stop bit of the final
octet of a received frame before a node may enable its
EIA-485 driver: 40 bit times.
40 bits is 4 octets including a start and stop bit with each octet.
turnaround_time_milliseconds = (Tturnaround*1000UL)/RS485_Baud; */
uint8_t Tturnaround_timeout;
/*Platform-specific port data */ /*Platform-specific port data */
void *UserData; void *UserData;
}; };
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
void MSTP_Init( void MSTP_Init(struct mstp_port_struct_t *mstp_port);
volatile struct mstp_port_struct_t *mstp_port); BACNET_STACK_EXPORT
BACNET_STACK_EXPORT void MSTP_Receive_Frame_FSM(struct mstp_port_struct_t *mstp_port);
void MSTP_Receive_Frame_FSM( BACNET_STACK_EXPORT
volatile struct mstp_port_struct_t bool MSTP_Master_Node_FSM(struct mstp_port_struct_t *mstp_port);
*mstp_port); BACNET_STACK_EXPORT
BACNET_STACK_EXPORT void MSTP_Slave_Node_FSM(struct mstp_port_struct_t *mstp_port);
bool MSTP_Master_Node_FSM(
volatile struct mstp_port_struct_t
*mstp_port);
BACNET_STACK_EXPORT
void MSTP_Slave_Node_FSM(
volatile struct mstp_port_struct_t *mstp_port);
/* returns true if line is active */ /* returns true if line is active */
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
bool MSTP_Line_Active( bool MSTP_Line_Active(struct mstp_port_struct_t *mstp_port);
volatile struct mstp_port_struct_t *mstp_port);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
uint16_t MSTP_Create_Frame( uint16_t MSTP_Create_Frame(uint8_t *buffer,
uint8_t * buffer, /* where frame is loaded */ uint16_t buffer_len,
uint16_t buffer_len, /* amount of space available */ uint8_t frame_type,
uint8_t frame_type, /* type of frame to send - see defines */ uint8_t destination,
uint8_t destination, /* destination address */ uint8_t source,
uint8_t source, /* source address */ uint8_t *data,
uint8_t * data, /* any data to be sent - may be null */ uint16_t data_len);
uint16_t data_len); /* number of bytes of data (up to 501) */
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
void MSTP_Create_And_Send_Frame( void MSTP_Create_And_Send_Frame(
volatile struct mstp_port_struct_t *mstp_port, /* port to send from */ struct mstp_port_struct_t *mstp_port,
uint8_t frame_type, /* type of frame to send - see defines */ uint8_t frame_type,
uint8_t destination, /* destination address */ uint8_t destination,
uint8_t source, /* source address */ uint8_t source,
uint8_t * data, /* any data to be sent - may be null */ uint8_t *data,
uint16_t data_len); uint16_t data_len);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
void MSTP_Fill_BACnet_Address( void MSTP_Fill_BACnet_Address(BACNET_ADDRESS *src, uint8_t mstp_address);
BACNET_ADDRESS * src,
uint8_t mstp_address);
/* functions used by the MS/TP state machine to put or get data */ BACNET_STACK_EXPORT
/* FIXME: developer must implement these in their DLMSTP module */ void MSTP_Zero_Config_UUID_Init(struct mstp_port_struct_t *mstp_port);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
uint16_t MSTP_Put_Receive( void MSTP_Zero_Config_FSM(struct mstp_port_struct_t *mstp_port);
volatile struct mstp_port_struct_t *mstp_port);
/* for the MS/TP state machine to use for getting data to send */ /* functions used by the MS/TP state machine to put or get data */
/* Return: amount of PDU data */ /* FIXME: developer must implement these in their DLMSTP module */
BACNET_STACK_EXPORT
uint16_t MSTP_Get_Send(
volatile struct mstp_port_struct_t *mstp_port,
unsigned timeout); /* milliseconds to wait for a packet */
/* for the MS/TP state machine to use for getting the reply for
Data-Expecting-Reply Frame */
/* Return: amount of PDU data */
BACNET_STACK_EXPORT
uint16_t MSTP_Get_Reply(
volatile struct mstp_port_struct_t *mstp_port,
unsigned timeout); /* milliseconds to wait for a packet */
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
void MSTP_Send_Frame( uint16_t MSTP_Put_Receive(
volatile struct mstp_port_struct_t *mstp_port, struct mstp_port_struct_t *mstp_port);
uint8_t * buffer,
uint16_t nbytes); /* for the MS/TP state machine to use for getting data to send */
/* Return: amount of PDU data */
BACNET_STACK_EXPORT
uint16_t MSTP_Get_Send(struct mstp_port_struct_t *mstp_port,
unsigned timeout); /* milliseconds to wait for a packet */
/* for the MS/TP state machine to use for getting the reply for
Data-Expecting-Reply Frame */
/* Return: amount of PDU data */
BACNET_STACK_EXPORT
uint16_t MSTP_Get_Reply(struct mstp_port_struct_t *mstp_port,
unsigned timeout); /* milliseconds to wait for a packet */
BACNET_STACK_EXPORT
void MSTP_Send_Frame(
struct mstp_port_struct_t *mstp_port,
uint8_t * buffer,
uint16_t nbytes);
#ifdef __cplusplus #ifdef __cplusplus
} }
+69 -27
View File
@@ -1,26 +1,26 @@
/************************************************************************** /**************************************************************************
* *
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net> * Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including * "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, * without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to * distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to * permit persons to whom the Software is furnished to do so, subject to
* the following conditions: * the following conditions:
* *
* The above copyright notice and this permission notice shall be included * The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software. * in all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*********************************************************************/ *********************************************************************/
#ifndef MSTPDEF_H #ifndef MSTPDEF_H
#define MSTPDEF_H #define MSTPDEF_H
@@ -32,7 +32,7 @@
/* The value 255 is used to denote broadcast when used as a */ /* The value 255 is used to denote broadcast when used as a */
/* destination address but is not allowed as a value for a station. */ /* destination address but is not allowed as a value for a station. */
/* Station addresses for master nodes can be 0-127. */ /* Station addresses for master nodes can be 0-127. */
/* Station addresses for slave nodes can be 127-254. */ /* Station addresses for slave nodes can be 0-254. */
#define MSTP_BROADCAST_ADDRESS 255 #define MSTP_BROADCAST_ADDRESS 255
/* MS/TP Frame Type */ /* MS/TP Frame Type */
@@ -52,15 +52,23 @@
/* These frames are available to vendors as proprietary (non-BACnet) frames. */ /* These frames are available to vendors as proprietary (non-BACnet) frames. */
/* The first two octets of the Data field shall specify the unique vendor */ /* The first two octets of the Data field shall specify the unique vendor */
/* identification code, most significant octet first, for the type of */ /* identification code, most significant octet first, for the type of */
/* vendor-proprietary frame to be conveyed. The length of the data portion */ /* vendor-proprietary frame to be conveyed. */
/* of a Proprietary frame shall be in the range of 2 to 501 octets. */
#define FRAME_TYPE_PROPRIETARY_MIN 128 #define FRAME_TYPE_PROPRIETARY_MIN 128
#define FRAME_TYPE_PROPRIETARY_MAX 255 #define FRAME_TYPE_PROPRIETARY_MAX 255
/* The initial CRC16 checksum value */ /* The initial CRC16 checksum value */
#define CRC16_INITIAL_VALUE (0xFFFF) #define CRC16_INITIAL_VALUE (0xFFFF)
#define CRC32K_INITIAL_VALUE (0xFFFFFFFF) #define CRC32K_INITIAL_VALUE (0xFFFFFFFF)
#define CRC32K_RESIDUE (0x0843323B) #define CRC32K_RESIDUE (0x0843323B)
/* frame specific data */
#define MSTP_PREAMBLE_X55 (0x55) #define MSTP_PREAMBLE_X55 (0x55)
/* The length of the data portion of a Test_Request, Test_Response,
BACnet Data Expecting Reply, or BACnet Data Not Expecting Reply frame
may range from 0 to 501 octets.
The length of the data portion of a proprietary frame shall
be in the range of 2 to 501 octets.*/
#define MSTP_FRAME_NPDU_MAX 501
/* COBS-encoded frames data parameter length is between
502 and 1497 octets, inclusive */
#define MSTP_EXTENDED_FRAME_NPDU_MAX 1497 #define MSTP_EXTENDED_FRAME_NPDU_MAX 1497
/* receive FSM states */ /* receive FSM states */
@@ -85,6 +93,16 @@ typedef enum {
MSTP_MASTER_STATE_ANSWER_DATA_REQUEST = 8 MSTP_MASTER_STATE_ANSWER_DATA_REQUEST = 8
} MSTP_MASTER_STATE; } MSTP_MASTER_STATE;
/* MSTP zero config FSM states */
typedef enum MSTP_Zero_Config_State {
MSTP_ZERO_CONFIG_STATE_INIT = 0,
MSTP_ZERO_CONFIG_STATE_IDLE = 1,
MSTP_ZERO_CONFIG_STATE_LURK = 2,
MSTP_ZERO_CONFIG_STATE_CLAIM = 3,
MSTP_ZERO_CONFIG_STATE_CONFIRM = 4,
MSTP_ZERO_CONFIG_STATE_USE = 5
} MSTP_ZERO_CONFIG_STATE;
/* The time without a DataAvailable or ReceiveError event before declaration */ /* The time without a DataAvailable or ReceiveError event before declaration */
/* of loss of token: 500 milliseconds. */ /* of loss of token: 500 milliseconds. */
#define Tno_token 500 #define Tno_token 500
@@ -98,13 +116,29 @@ typedef enum {
/* At 76800 baud, 40 bit times would be about 0.520 milliseconds */ /* At 76800 baud, 40 bit times would be about 0.520 milliseconds */
/* At 115200 baud, 40 bit times would be about 0.347 milliseconds */ /* At 115200 baud, 40 bit times would be about 0.347 milliseconds */
/* 40 bits is 4 octets including a start and stop bit with each octet */ /* 40 bits is 4 octets including a start and stop bit with each octet */
#define Tturnaround (40UL) #define Tturnaround (40UL)
/* turnaround_time_milliseconds = (Tturnaround*1000UL)/RS485_Baud; */ /* turnaround_time_milliseconds = (Tturnaround*1000UL)/RS485_Baud; */
/* The number of tokens received or used before a Poll For Master cycle */ /* The number of tokens received or used before a Poll For Master cycle */
/* is executed: 50. */ /* is executed: 50. */
#define Npoll 50 #define Npoll 50
/* The minimum number of polls received before a zero-config address */
/* is claimed: 8. */
#define Nmin_poll 8
/* The first zero-config address: 64 */
#define Nmin_poll_station 64
/* The last zero-config address: 127 */
#define Nmax_poll_station 127
/* The number of zero-config station poll slots: 64 */
#define Nmax_poll_slot 64
/* The last master node address: 127 */
#define Nmax_master_station 127
/* The number of retries on sending Token: 1. */ /* The number of retries on sending Token: 1. */
#define Nretry_token 1 #define Nretry_token 1
@@ -126,6 +160,15 @@ typedef enum {
/* 15 milliseconds. */ /* 15 milliseconds. */
#define Tusage_delay 15 #define Tusage_delay 15
/* The minimum number of DataAvailable or ReceiveError events that must be */
/* seen by a receiving node in order to declare the line "active": 4. */
#define Nmin_octets 4
#define DEFAULT_Tframe_abort 95
#define DEFAULT_Treply_delay 245
#define DEFAULT_Treply_timeout 250
#define DEFAULT_Tusage_timeout 35
#define DEFAULT_MAX_INFO_FRAMES 1 #define DEFAULT_MAX_INFO_FRAMES 1
#define DEFAULT_MAX_MASTER 127 #define DEFAULT_MAX_MASTER 127
#define DEFAULT_MAC_ADDRESS 127 #define DEFAULT_MAC_ADDRESS 127
@@ -134,7 +177,6 @@ typedef enum {
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
+15
View File
@@ -87,3 +87,18 @@ const char *mstptext_frame_type(unsigned index)
return indtext_by_index_split_default(mstp_frame_type_text, index, return indtext_by_index_split_default(mstp_frame_type_text, index,
FRAME_TYPE_PROPRIETARY_MIN, "UNKNOWN", "PROPRIETARY"); FRAME_TYPE_PROPRIETARY_MIN, "UNKNOWN", "PROPRIETARY");
} }
static INDTEXT_DATA mstp_zero_config_state_text[] = {
{ MSTP_ZERO_CONFIG_STATE_INIT, "INIT" },
{ MSTP_ZERO_CONFIG_STATE_IDLE, "IDLE" },
{ MSTP_ZERO_CONFIG_STATE_LURK, "LURK" },
{ MSTP_ZERO_CONFIG_STATE_CLAIM, "CLAIM" },
{ MSTP_ZERO_CONFIG_STATE_CONFIRM, "CONFIRM" },
{ MSTP_ZERO_CONFIG_STATE_USE, "USE" },
{ 0, NULL }
};
const char *mstptext_zero_config_state(unsigned index)
{
return indtext_by_index_default(mstp_zero_config_state_text, index, "unknown");
}
+3
View File
@@ -39,6 +39,9 @@ extern "C" {
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
const char *mstptext_frame_type( const char *mstptext_frame_type(
unsigned index); unsigned index);
BACNET_STACK_EXPORT
const char *mstptext_zero_config_state(
unsigned index);
#ifdef __cplusplus #ifdef __cplusplus
} }
+1
View File
@@ -158,6 +158,7 @@ list(APPEND testdirs
bacnet/datalink/cobs bacnet/datalink/cobs
bacnet/datalink/crc bacnet/datalink/crc
bacnet/datalink/bvlc bacnet/datalink/bvlc
bacnet/datalink/mstp
) )
enable_testing() enable_testing()
+54
View File
@@ -0,0 +1,54 @@
# SPDX-License-Identifier: MIT
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
get_filename_component(basename ${CMAKE_CURRENT_SOURCE_DIR} NAME)
project(test_${basename}
VERSION 1.0.0
LANGUAGES C)
string(REGEX REPLACE
"/test/bacnet/[a-zA-Z_/-]*$"
"/src"
SRC_DIR
${CMAKE_CURRENT_SOURCE_DIR})
string(REGEX REPLACE
"/test/bacnet/[a-zA-Z_/-]*$"
"/test"
TST_DIR
${CMAKE_CURRENT_SOURCE_DIR})
set(ZTST_DIR "${TST_DIR}/ztest/src")
add_compile_definitions(
BIG_ENDIAN=0
CONFIG_ZTEST=1
BACDL_MSTP=1
)
include_directories(
${SRC_DIR}
${TST_DIR}/ztest/include
)
add_executable(${PROJECT_NAME}
# File(s) under test
${SRC_DIR}/bacnet/datalink/mstp.c
${SRC_DIR}/bacnet/datalink/mstptext.c
${SRC_DIR}/bacnet/datalink/crc.c
${SRC_DIR}/bacnet/datalink/cobs.c
${SRC_DIR}/bacnet/basic/sys/fifo.c
${SRC_DIR}/bacnet/indtext.c
# core files needed
${SRC_DIR}/bacnet/bacdcode.c
${SRC_DIR}/bacnet/bacint.c
${SRC_DIR}/bacnet/bacstr.c
${SRC_DIR}/bacnet/bacreal.c
${SRC_DIR}/bacnet/npdu.c
${SRC_DIR}/bacnet/basic/sys/bigend.c
# Support files and stubs (pathname alphabetical)
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
${ZTST_DIR}/ztest.c
)
File diff suppressed because it is too large Load Diff