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:
@@ -396,3 +396,7 @@ clean: ports-clean
|
||||
test:
|
||||
$(MAKE) -s -C test clean
|
||||
$(MAKE) -s -j -C test all
|
||||
|
||||
.PHONY: retest
|
||||
retest:
|
||||
$(MAKE) -s -j -C test retest
|
||||
|
||||
+13
-24
@@ -68,7 +68,7 @@
|
||||
#define MSTP_HEADER_MAX (2 + 1 + 1 + 1 + 2 + 1)
|
||||
|
||||
/* 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 */
|
||||
static MSTP_RECEIVE_STATE MSTP_Receive_State = MSTP_RECEIVE_STATE_IDLE;
|
||||
/* 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(
|
||||
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 uint8_t old_frame = 255;
|
||||
@@ -286,8 +286,7 @@ static void packet_statistics(
|
||||
MSTP_Statistics[src].der_reply = delta;
|
||||
}
|
||||
}
|
||||
if ((mstp_port->ReceivedValidFrame) ||
|
||||
(mstp_port->ReceivedValidFrameNotForUs)) {
|
||||
if (mstp_port->ReceivedValidFrame) {
|
||||
if ((mstp_port->DataLength <= mstp_port->InputBufferSize) &&
|
||||
(mstp_port->DataLength > 0)) {
|
||||
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 */
|
||||
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;
|
||||
|
||||
@@ -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 */
|
||||
/* Return: amount of PDU data */
|
||||
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 */
|
||||
(void)mstp_port;
|
||||
(void)timeout;
|
||||
@@ -437,7 +436,7 @@ uint16_t MSTP_Get_Send(
|
||||
* @param nbytes - number of bytes of data to send
|
||||
*/
|
||||
void MSTP_Send_Frame(
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
struct mstp_port_struct_t *mstp_port,
|
||||
uint8_t * buffer,
|
||||
uint16_t nbytes)
|
||||
{
|
||||
@@ -447,7 +446,7 @@ void MSTP_Send_Frame(
|
||||
}
|
||||
|
||||
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 */
|
||||
(void)mstp_port;
|
||||
(void)timeout;
|
||||
@@ -623,7 +622,7 @@ static void write_global_header(void)
|
||||
}
|
||||
|
||||
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_usec = 0; /* timestamp microseconds */
|
||||
@@ -637,8 +636,7 @@ static void write_received_packet(
|
||||
gettimeofday(&tv, NULL);
|
||||
ts_sec = tv.tv_sec;
|
||||
ts_usec = tv.tv_usec;
|
||||
if ((mstp_port->ReceivedValidFrame) ||
|
||||
(mstp_port->ReceivedValidFrameNotForUs)) {
|
||||
if (mstp_port->ReceivedValidFrame) {
|
||||
packet_statistics(&tv, mstp_port);
|
||||
}
|
||||
(void)data_write(&ts_sec, sizeof(ts_sec), 1);
|
||||
@@ -765,7 +763,7 @@ static bool test_global_header(const char *filename)
|
||||
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_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;
|
||||
if (mstp_port->DataLength == 0) {
|
||||
mstp_port->ReceivedValidFrame = true;
|
||||
mstp_port->ReceivedValidFrameNotForUs = true;
|
||||
}
|
||||
} else {
|
||||
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) {
|
||||
mstp_port->ReceivedInvalidFrame = false;
|
||||
mstp_port->ReceivedValidFrame = true;
|
||||
mstp_port->ReceivedValidFrameNotForUs = true;
|
||||
} else {
|
||||
mstp_port->ReceivedInvalidFrame = true;
|
||||
mstp_port->ReceivedValidFrame = false;
|
||||
mstp_port->ReceivedValidFrameNotForUs = false;
|
||||
}
|
||||
} else {
|
||||
mstp_port->DataLength = 0;
|
||||
}
|
||||
if (mstp_port->ReceivedInvalidFrame) {
|
||||
Invalid_Frame_Count++;
|
||||
} else if ((mstp_port->ReceivedValidFrame) ||
|
||||
(mstp_port->ReceivedValidFrameNotForUs)) {
|
||||
} else if (mstp_port->ReceivedValidFrame) {
|
||||
packet_statistics(&tv, mstp_port);
|
||||
}
|
||||
} else {
|
||||
@@ -984,7 +978,7 @@ static void print_help(char *filename)
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
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->ReceivedInvalidFrame = false;
|
||||
mstp_port->ReceivedValidFrame = false;
|
||||
mstp_port->ReceivedValidFrameNotForUs = false;
|
||||
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 */
|
||||
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;
|
||||
uint32_t packet_count = 0;
|
||||
uint32_t header_len = 0;
|
||||
@@ -1177,10 +1170,6 @@ int main(int argc, char *argv[])
|
||||
write_received_packet(mstp_port, MSTP_HEADER_MAX);
|
||||
mstp_structure_init(mstp_port);
|
||||
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) {
|
||||
if (MSTP_Receive_State == MSTP_RECEIVE_STATE_HEADER) {
|
||||
mstp_port->Index = 0;
|
||||
|
||||
@@ -50,9 +50,7 @@ void *dl_mstp_thread(void *pArgs)
|
||||
uint16_t pdu_len;
|
||||
uint8_t shutdown = 0;
|
||||
|
||||
shared_port_data.Treply_timeout = 260;
|
||||
shared_port_data.MSTP_Packets = 0;
|
||||
shared_port_data.Tusage_timeout = 30;
|
||||
shared_port_data.RS485_Handle = -1;
|
||||
shared_port_data.RS485_Baud = B38400;
|
||||
shared_port_data.RS485MOD = 0;
|
||||
@@ -95,6 +93,8 @@ void *dl_mstp_thread(void *pArgs)
|
||||
if (!dlmstp_init(&mstp_port, 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();
|
||||
if (port->port_id == INVALID_MSGBOX_ID) {
|
||||
|
||||
@@ -75,7 +75,7 @@ static bool run_thread;
|
||||
|
||||
/*RT_TASK Receive_Task, Fsm_Task;*/
|
||||
/* 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 */
|
||||
static uint8_t TxBuffer[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) {
|
||||
run_master = true;
|
||||
} else {
|
||||
silence = MSTP_Port.SilenceTimer(NULL);
|
||||
silence = MSTP_Port.SilenceTimer(&MSTP_Port);
|
||||
switch (MSTP_Port.master_state) {
|
||||
case MSTP_MASTER_STATE_IDLE:
|
||||
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 */
|
||||
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;
|
||||
|
||||
@@ -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 */
|
||||
/* Return: amount of PDU data */
|
||||
uint16_t MSTP_Get_Send(
|
||||
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
||||
uint16_t MSTP_Get_Send(struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
||||
{ /* milliseconds to wait for a packet */
|
||||
uint16_t pdu_len = 0;
|
||||
uint8_t frame_type = 0;
|
||||
@@ -421,7 +420,7 @@ uint16_t MSTP_Get_Send(
|
||||
* @param nbytes - number of bytes of data to send
|
||||
*/
|
||||
void MSTP_Send_Frame(
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
struct mstp_port_struct_t *mstp_port,
|
||||
uint8_t * buffer,
|
||||
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 */
|
||||
uint16_t MSTP_Get_Reply(
|
||||
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
||||
uint16_t MSTP_Get_Reply(struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
||||
{ /* milliseconds to wait for a packet */
|
||||
uint16_t pdu_len = 0; /* return value */
|
||||
bool matched = false;
|
||||
|
||||
@@ -228,7 +228,7 @@ void *dlmstp_receive_fsm_task(void *pArg)
|
||||
do {
|
||||
RS485_Check_UART_Data(mstp_port);
|
||||
MSTP_Receive_Frame_FSM(
|
||||
(volatile struct mstp_port_struct_t *)pArg);
|
||||
(struct mstp_port_struct_t *)pArg);
|
||||
received_frame = mstp_port->ReceivedValidFrame ||
|
||||
mstp_port->ReceivedInvalidFrame;
|
||||
if (received_frame) {
|
||||
@@ -274,11 +274,11 @@ void *dlmstp_master_fsm_task(void *pArg)
|
||||
run_master = true;
|
||||
break;
|
||||
case MSTP_MASTER_STATE_WAIT_FOR_REPLY:
|
||||
if (silence >= poSharedData->Treply_timeout)
|
||||
if (silence >= mstp_port->Treply_timeout)
|
||||
run_master = true;
|
||||
break;
|
||||
case MSTP_MASTER_STATE_POLL_FOR_MASTER:
|
||||
if (silence >= poSharedData->Tusage_timeout)
|
||||
if (silence >= mstp_port->Tusage_timeout)
|
||||
run_master = true;
|
||||
break;
|
||||
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 */
|
||||
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;
|
||||
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 */
|
||||
/* Return: amount of PDU data */
|
||||
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 */
|
||||
uint16_t pdu_len = 0;
|
||||
uint8_t frame_type = 0;
|
||||
@@ -391,7 +391,7 @@ uint16_t MSTP_Get_Send(
|
||||
* @param nbytes - number of bytes of data to send
|
||||
*/
|
||||
void MSTP_Send_Frame(
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
struct mstp_port_struct_t *mstp_port,
|
||||
uint8_t * buffer,
|
||||
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 */
|
||||
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 */
|
||||
uint16_t pdu_len = 0; /* return value */
|
||||
bool matched = false;
|
||||
|
||||
@@ -87,16 +87,6 @@ typedef struct shared_mstp_data {
|
||||
/* buffers needed by mstp port struct */
|
||||
uint8_t TxBuffer[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 */
|
||||
uint16_t SilenceTime;
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
#endif
|
||||
|
||||
/* 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 */
|
||||
static uint8_t RxBuffer[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 */
|
||||
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;
|
||||
|
||||
@@ -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 */
|
||||
/* Return: amount of PDU data */
|
||||
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 */
|
||||
(void)mstp_port;
|
||||
(void)timeout;
|
||||
@@ -107,7 +107,7 @@ uint16_t MSTP_Get_Send(
|
||||
* @param nbytes - number of bytes of data to send
|
||||
*/
|
||||
void MSTP_Send_Frame(
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
struct mstp_port_struct_t *mstp_port,
|
||||
uint8_t * buffer,
|
||||
uint16_t nbytes)
|
||||
{
|
||||
@@ -117,7 +117,7 @@ void MSTP_Send_Frame(
|
||||
}
|
||||
|
||||
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 */
|
||||
(void)mstp_port;
|
||||
(void)timeout;
|
||||
@@ -165,7 +165,7 @@ static int network_init(const char *name, int protocol)
|
||||
}
|
||||
|
||||
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 */
|
||||
unsigned i = 0; /* counter */
|
||||
@@ -241,7 +241,7 @@ void signal_init(void)
|
||||
/* simple test to packetize the data and print it */
|
||||
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;
|
||||
uint32_t packet_count = 0;
|
||||
int sockfd = -1;
|
||||
|
||||
+4
-4
@@ -217,7 +217,7 @@ uint32_t RS485_Get_Baud_Rate(void)
|
||||
* ALGORITHM: 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;
|
||||
SHARED_MSTP_DATA *poSharedData = (SHARED_MSTP_DATA *)mstp_port->UserData;
|
||||
@@ -382,7 +382,7 @@ bool RS485_Set_Baud_Rate(uint32_t baud)
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
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) */
|
||||
uint16_t nbytes)
|
||||
{ /* number of bytes of data (up to 501) */
|
||||
@@ -458,7 +458,7 @@ void RS485_Send_Frame(
|
||||
* ALGORITHM: 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;
|
||||
struct timeval waiter;
|
||||
@@ -694,7 +694,7 @@ void RS485_Print_Ports(void)
|
||||
#include <string.h>
|
||||
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 pfm_buf[8] = { 0x55, 0xFF, 0x01, 0x67, 0x07, 0x00, 0x00, 0x3E };
|
||||
long baud = 38400;
|
||||
|
||||
+3
-3
@@ -57,16 +57,16 @@ extern "C" {
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
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) */
|
||||
uint16_t nbytes); /* number of bytes of data (up to 501) */
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
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
|
||||
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
|
||||
uint32_t RS485_Get_Baud_Rate(
|
||||
void);
|
||||
|
||||
Vendored
+4
@@ -17,6 +17,10 @@
|
||||
"searchDir": [],
|
||||
"svdFile":"${workspaceRoot}/stm32f429.svd",
|
||||
"runToEntryPoint": "main",
|
||||
"liveWatch": {
|
||||
"enabled": true,
|
||||
"samplesPerSecond": 1
|
||||
},
|
||||
"swoConfig": {
|
||||
"enabled": true,
|
||||
"cpuFrequency": 8000000,
|
||||
|
||||
@@ -77,7 +77,7 @@ static struct my_object_functions {
|
||||
properties that are writable or that may change.
|
||||
The properties that are constant can be hard coded
|
||||
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_CHARACTER_STRING My_Object_Name;
|
||||
static const char *Device_Name_Default = "stm32f4xx";
|
||||
@@ -1131,9 +1131,8 @@ void Device_Init(object_functions_t *object_table)
|
||||
pObject++;
|
||||
}
|
||||
dcc_set_status_duration(COMMUNICATION_ENABLE, 0);
|
||||
if (Object_Instance_Number >= BACNET_MAX_INSTANCE) {
|
||||
Object_Instance_Number = 103;
|
||||
srand(Object_Instance_Number);
|
||||
if (Object_Instance_Number > BACNET_MAX_INSTANCE) {
|
||||
Object_Instance_Number = BACNET_MAX_INSTANCE;
|
||||
}
|
||||
characterstring_init_ansi(&My_Object_Name, Device_Name_Default);
|
||||
}
|
||||
|
||||
+27
-2
@@ -22,7 +22,7 @@
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
@@ -30,7 +30,9 @@
|
||||
#include "stm32f4xx.h"
|
||||
#include "stm32f4xx_pwr.h"
|
||||
#include "stm32f4xx_rcc.h"
|
||||
#include "stm32f4xx_rng.h"
|
||||
#include "system_stm32f4xx.h"
|
||||
#include "bacnet/basic/object/device.h"
|
||||
#include "bacnet/basic/sys/mstimer.h"
|
||||
#include "bacnet/basic/sys/ringbuf.h"
|
||||
#include "bacnet/datalink/datalink.h"
|
||||
@@ -96,13 +98,36 @@ int main(void)
|
||||
MSTP_Port.OutputBuffer = Output_Buffer;
|
||||
MSTP_Port.OutputBufferSize = sizeof(Output_Buffer);
|
||||
/* user data */
|
||||
MSTP_Port.ZeroConfigEnabled = true;
|
||||
MSTP_Port.SlaveNodeEnabled = false;
|
||||
MSTP_User_Data.RS485_Driver = &RS485_Driver;
|
||||
MSTP_Port.UserData = &MSTP_User_Data;
|
||||
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);
|
||||
/* initialize application layer*/
|
||||
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 (;;) {
|
||||
if (mstimer_expired(&Blink_Timer)) {
|
||||
mstimer_reset(&Blink_Timer);
|
||||
|
||||
@@ -52,7 +52,7 @@ static HANDLE Receive_Packet_Flag;
|
||||
HANDLE Received_Frame_Flag;
|
||||
static DLMSTP_PACKET Transmit_Packet;
|
||||
/* 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 */
|
||||
static uint8_t TxBuffer[DLMSTP_MPDU_MAX];
|
||||
static uint8_t RxBuffer[DLMSTP_MPDU_MAX];
|
||||
@@ -62,11 +62,12 @@ static uint32_t TimeBeginPeriod;
|
||||
/* 1-millisecond target resolution */
|
||||
#define TARGET_RESOLUTION 1
|
||||
|
||||
static uint16_t Timer_Silence(void)
|
||||
static uint16_t Timer_Silence(void *arg)
|
||||
{
|
||||
uint32_t now = timeGetTime();
|
||||
uint32_t delta_time = 0;
|
||||
|
||||
(void)arg;
|
||||
if (SilenceStartTime < now) {
|
||||
delta_time = now - SilenceStartTime;
|
||||
} else {
|
||||
@@ -79,8 +80,9 @@ static uint16_t Timer_Silence(void)
|
||||
return (uint16_t)delta_time;
|
||||
}
|
||||
|
||||
static void Timer_Silence_Reset(void)
|
||||
static void Timer_Silence_Reset(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
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 */
|
||||
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;
|
||||
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 */
|
||||
/* Return: amount of PDU data */
|
||||
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 */
|
||||
uint16_t pdu_len = 0;
|
||||
uint8_t destination = 0; /* destination address */
|
||||
@@ -303,7 +305,7 @@ uint16_t MSTP_Get_Send(
|
||||
* @param nbytes - number of bytes of data to send
|
||||
*/
|
||||
void MSTP_Send_Frame(
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
struct mstp_port_struct_t *mstp_port,
|
||||
uint8_t * buffer,
|
||||
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 */
|
||||
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 */
|
||||
uint16_t pdu_len = 0; /* return value */
|
||||
uint8_t destination = 0; /* destination address */
|
||||
|
||||
@@ -51,7 +51,7 @@ static HANDLE Receive_Packet_Flag;
|
||||
HANDLE Received_Frame_Flag;
|
||||
static DLMSTP_PACKET Transmit_Packet;
|
||||
/* 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 */
|
||||
static uint8_t TxBuffer[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 */
|
||||
static uint32_t Timer_Silence(void *pArg)
|
||||
{
|
||||
(void)pArg;
|
||||
return mstimer_elapsed(&Silence_Timer);
|
||||
}
|
||||
|
||||
static void Timer_Silence_Reset(void *pArg)
|
||||
{
|
||||
(void)pArg;
|
||||
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 */
|
||||
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;
|
||||
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 */
|
||||
/* Return: amount of PDU data */
|
||||
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 */
|
||||
uint16_t pdu_len = 0;
|
||||
uint8_t destination = 0; /* destination address */
|
||||
@@ -288,7 +290,7 @@ uint16_t MSTP_Get_Send(
|
||||
* @param nbytes - number of bytes of data to send
|
||||
*/
|
||||
void MSTP_Send_Frame(
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
struct mstp_port_struct_t *mstp_port,
|
||||
uint8_t * buffer,
|
||||
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 */
|
||||
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 */
|
||||
uint16_t pdu_len = 0; /* return value */
|
||||
uint8_t destination = 0; /* destination address */
|
||||
|
||||
+2
-2
@@ -421,7 +421,7 @@ bool RS485_Set_Baud_Rate(uint32_t baud)
|
||||
|
||||
/* Transmits a Frame on the wire */
|
||||
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) */
|
||||
uint16_t nbytes)
|
||||
{ /* number of bytes of data (up to 501) */
|
||||
@@ -453,7 +453,7 @@ void RS485_Send_Frame(
|
||||
}
|
||||
|
||||
/* 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];
|
||||
DWORD dwRead = 0;
|
||||
|
||||
+2
-2
@@ -58,13 +58,13 @@ extern "C" {
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
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) */
|
||||
uint16_t nbytes); /* number of bytes of data (up to 501) */
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
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
|
||||
uint32_t RS485_Get_Baud_Rate(
|
||||
|
||||
@@ -2631,6 +2631,7 @@ bool Network_Port_Read_Range(
|
||||
(void)pInfo;
|
||||
pRequest->error_class = ERROR_CLASS_PROPERTY;
|
||||
pRequest->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
(void)pInfo;
|
||||
#endif
|
||||
break;
|
||||
case PROP_BBMD_FOREIGN_DEVICE_TABLE:
|
||||
@@ -2642,6 +2643,7 @@ bool Network_Port_Read_Range(
|
||||
(void)pInfo;
|
||||
pRequest->error_class = ERROR_CLASS_PROPERTY;
|
||||
pRequest->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
(void)pInfo;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
|
||||
+89
-114
@@ -41,7 +41,7 @@ int dlmstp_send_pdu(BACNET_ADDRESS *dest,
|
||||
{
|
||||
int bytes_sent = 0;
|
||||
unsigned i = 0; /* loop counter */
|
||||
struct dlmstp_user_data_t *port = NULL;
|
||||
struct dlmstp_user_data_t *user = NULL;
|
||||
struct dlmstp_packet *pkt;
|
||||
|
||||
if (!MSTP_Port) {
|
||||
@@ -50,8 +50,8 @@ int dlmstp_send_pdu(BACNET_ADDRESS *dest,
|
||||
if (!MSTP_Port->UserData) {
|
||||
return 0;
|
||||
}
|
||||
port = MSTP_Port->UserData;
|
||||
pkt = (struct dlmstp_packet *)(void *)Ringbuf_Data_Peek(&port->PDU_Queue);
|
||||
user = MSTP_Port->UserData;
|
||||
pkt = (struct dlmstp_packet *)(void *)Ringbuf_Data_Peek(&user->PDU_Queue);
|
||||
if (pkt && (pdu_len <= DLMSTP_MPDU_MAX)) {
|
||||
if (npdu_data->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.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;
|
||||
}
|
||||
}
|
||||
@@ -86,30 +86,30 @@ int dlmstp_send_pdu(BACNET_ADDRESS *dest,
|
||||
* @return amount of PDU data
|
||||
*/
|
||||
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;
|
||||
struct dlmstp_packet *pkt;
|
||||
struct dlmstp_user_data_t *port;
|
||||
struct dlmstp_user_data_t *user;
|
||||
|
||||
if (!mstp_port) {
|
||||
return 0;
|
||||
}
|
||||
port = (struct dlmstp_user_data_t *)mstp_port->UserData;
|
||||
if (!port) {
|
||||
user = (struct dlmstp_user_data_t *)mstp_port->UserData;
|
||||
if (!user) {
|
||||
return 0;
|
||||
}
|
||||
if (Ringbuf_Empty(&port->PDU_Queue)) {
|
||||
if (Ringbuf_Empty(&user->PDU_Queue)) {
|
||||
return 0;
|
||||
}
|
||||
/* 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 */
|
||||
pdu_len = MSTP_Create_Frame(&mstp_port->OutputBuffer[0],
|
||||
mstp_port->OutputBufferSize, pkt->frame_type, pkt->address.mac[0],
|
||||
mstp_port->This_Station, &pkt->pdu[0], pkt->pdu_len);
|
||||
port->Statistics.transmit_pdu_counter++;
|
||||
(void)Ringbuf_Pop(&port->PDU_Queue, NULL);
|
||||
user->Statistics.transmit_pdu_counter++;
|
||||
(void)Ringbuf_Pop(&user->PDU_Queue, NULL);
|
||||
|
||||
return pdu_len;
|
||||
}
|
||||
@@ -148,15 +148,12 @@ static bool MSTP_Compare_Data_Expecting_Reply(
|
||||
request_pdu = &mstp_port->InputBuffer[0];
|
||||
request_pdu_len = mstp_port->DataLength;
|
||||
src_address = mstp_port->SourceAddress;
|
||||
|
||||
/* unused parameters */
|
||||
request_pdu_len = request_pdu_len;
|
||||
reply_pdu_len = reply_pdu_len;
|
||||
/* decode the request data */
|
||||
request.address.mac[0] = src_address;
|
||||
request.address.mac_len = 1;
|
||||
offset = (uint16_t)npdu_decode(
|
||||
&request_pdu[0], NULL, &request.address, &request.npdu_data);
|
||||
offset = bacnet_npdu_decode(
|
||||
&request_pdu[0], request_pdu_len, NULL, &request.address,
|
||||
&request.npdu_data);
|
||||
if (request.npdu_data.network_layer_message) {
|
||||
return false;
|
||||
}
|
||||
@@ -172,8 +169,9 @@ static bool MSTP_Compare_Data_Expecting_Reply(
|
||||
request.service_choice = request_pdu[offset + 3];
|
||||
/* decode the reply data */
|
||||
bacnet_address_copy(&reply.address, dest_address);
|
||||
offset = (uint16_t)npdu_decode(
|
||||
&reply_pdu[0], &reply.address, NULL, &reply.npdu_data);
|
||||
offset = bacnet_npdu_decode(
|
||||
&reply_pdu[0], reply_pdu_len, &reply.address, NULL,
|
||||
&reply.npdu_data);
|
||||
if (reply.npdu_data.network_layer_message) {
|
||||
return false;
|
||||
}
|
||||
@@ -244,26 +242,26 @@ static bool MSTP_Compare_Data_Expecting_Reply(
|
||||
* @return number of bytes, or 0 if no reply is available
|
||||
*/
|
||||
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;
|
||||
bool matched = false;
|
||||
struct dlmstp_packet packet = { 0 };
|
||||
struct dlmstp_user_data_t *port = NULL;
|
||||
struct dlmstp_user_data_t *user = NULL;
|
||||
struct dlmstp_packet *pkt;
|
||||
|
||||
if (!mstp_port) {
|
||||
return 0;
|
||||
}
|
||||
port = mstp_port->UserData;
|
||||
if (!port) {
|
||||
user = mstp_port->UserData;
|
||||
if (!user) {
|
||||
return 0;
|
||||
}
|
||||
if (Ringbuf_Empty(&port->PDU_Queue)) {
|
||||
if (Ringbuf_Empty(&user->PDU_Queue)) {
|
||||
return 0;
|
||||
}
|
||||
/* 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? */
|
||||
matched = MSTP_Compare_Data_Expecting_Reply(
|
||||
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],
|
||||
mstp_port->OutputBufferSize, pkt->frame_type, packet.address.mac[0],
|
||||
mstp_port->This_Station, &pkt->pdu[0], pkt->pdu_len);
|
||||
port->Statistics.transmit_pdu_counter++;
|
||||
(void)Ringbuf_Pop(&port->PDU_Queue, NULL);
|
||||
user->Statistics.transmit_pdu_counter++;
|
||||
(void)Ringbuf_Pop(&user->PDU_Queue, NULL);
|
||||
|
||||
return pdu_len;
|
||||
}
|
||||
@@ -286,70 +284,48 @@ uint16_t MSTP_Get_Reply(
|
||||
* @param buffer - buffer 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,
|
||||
uint16_t nbytes)
|
||||
{
|
||||
struct dlmstp_user_data_t *port;
|
||||
struct dlmstp_user_data_t *user;
|
||||
struct dlmstp_rs485_driver *driver;
|
||||
|
||||
if (!mstp_port) {
|
||||
return;
|
||||
}
|
||||
port = mstp_port->UserData;
|
||||
if (!port) {
|
||||
user = mstp_port->UserData;
|
||||
if (!user) {
|
||||
return;
|
||||
}
|
||||
driver = port->RS485_Driver;
|
||||
driver = user->RS485_Driver;
|
||||
if (!driver) {
|
||||
return;
|
||||
}
|
||||
driver->send(buffer, nbytes);
|
||||
port->Statistics.transmit_frame_counter++;
|
||||
user->Statistics.transmit_frame_counter++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief MS/TP state machine received a frame
|
||||
* @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) {
|
||||
return 0;
|
||||
}
|
||||
port = mstp_port->UserData;
|
||||
if (!port) {
|
||||
user = mstp_port->UserData;
|
||||
if (!user) {
|
||||
return 0;
|
||||
}
|
||||
port->ReceivePacketPending = true;
|
||||
user->ReceivePacketPending = true;
|
||||
|
||||
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
|
||||
* @param pdu - place to put PDU data for the caller
|
||||
@@ -363,11 +339,10 @@ uint16_t dlmstp_receive(
|
||||
{
|
||||
uint16_t pdu_len = 0;
|
||||
uint8_t data_register = 0;
|
||||
struct dlmstp_user_data_t *port;
|
||||
struct dlmstp_user_data_t *user;
|
||||
struct dlmstp_rs485_driver *driver;
|
||||
uint16_t i;
|
||||
uint32_t milliseconds;
|
||||
uint32_t turnaround_milliseconds;
|
||||
|
||||
if (!MSTP_Port) {
|
||||
return 0;
|
||||
@@ -375,11 +350,11 @@ uint16_t dlmstp_receive(
|
||||
if (!MSTP_Port->UserData) {
|
||||
return 0;
|
||||
}
|
||||
port = MSTP_Port->UserData;
|
||||
if (!port) {
|
||||
user = MSTP_Port->UserData;
|
||||
if (!user) {
|
||||
return 0;
|
||||
}
|
||||
driver = port->RS485_Driver;
|
||||
driver = user->RS485_Driver;
|
||||
if (!driver) {
|
||||
return 0;
|
||||
}
|
||||
@@ -392,7 +367,6 @@ uint16_t dlmstp_receive(
|
||||
}
|
||||
/* only do receive state machine while we don't have a frame */
|
||||
while ((MSTP_Port->ReceivedValidFrame == false) &&
|
||||
(MSTP_Port->ReceivedValidFrameNotForUs == false) &&
|
||||
(MSTP_Port->ReceivedInvalidFrame == false)) {
|
||||
MSTP_Port->DataAvailable = driver->read(&data_register);
|
||||
if (MSTP_Port->DataAvailable) {
|
||||
@@ -404,39 +378,35 @@ uint16_t dlmstp_receive(
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (MSTP_Port->ReceivedValidFrameNotForUs ||
|
||||
MSTP_Port->ReceivedValidFrame || MSTP_Port->ReceivedInvalidFrame) {
|
||||
if (MSTP_Port->ReceivedValidFrame || MSTP_Port->ReceivedInvalidFrame) {
|
||||
/* delay after reception before transmitting - per MS/TP spec */
|
||||
turnaround_milliseconds =
|
||||
dlmstp_receive_turnaround_time(driver->baud_rate());
|
||||
milliseconds = MSTP_Port->SilenceTimer(MSTP_Port);
|
||||
if (milliseconds < turnaround_milliseconds) {
|
||||
if (milliseconds < MSTP_Port->Tturnaround_timeout) {
|
||||
/* we're waiting; do nothing else */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (MSTP_Port->ReceivedValidFrameNotForUs) {
|
||||
MSTP_Port->ReceivedValidFrameNotForUs = false;
|
||||
port->Statistics.receive_valid_frame_counter++;
|
||||
}
|
||||
if (MSTP_Port->ReceivedValidFrame) {
|
||||
port->Statistics.receive_valid_frame_counter++;
|
||||
user->Statistics.receive_valid_frame_counter++;
|
||||
}
|
||||
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) {
|
||||
/* only do master state machine while rx is idle */
|
||||
if (MSTP_Port->This_Station <= DEFAULT_MAX_MASTER) {
|
||||
/* only node state machines while rx is idle */
|
||||
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)) {
|
||||
/* do nothing while some states fast transition */
|
||||
};
|
||||
}
|
||||
}
|
||||
/* see if there is a packet available */
|
||||
if (port->ReceivePacketPending) {
|
||||
port->ReceivePacketPending = false;
|
||||
port->Statistics.receive_pdu_counter++;
|
||||
if (user->ReceivePacketPending) {
|
||||
user->ReceivePacketPending = false;
|
||||
user->Statistics.receive_pdu_counter++;
|
||||
pdu_len = MSTP_Port->DataLength;
|
||||
if (pdu_len > max_pdu) {
|
||||
/* 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)
|
||||
{
|
||||
/* Master Nodes can only have address 0-127 */
|
||||
if (mac_address <= 127) {
|
||||
if (MSTP_Port) {
|
||||
MSTP_Port->This_Station = mac_address;
|
||||
}
|
||||
if (MSTP_Port) {
|
||||
MSTP_Port->This_Station = mac_address;
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -648,12 +615,12 @@ void dlmstp_get_broadcast_address(BACNET_ADDRESS *dest)
|
||||
bool dlmstp_send_pdu_queue_empty(void)
|
||||
{
|
||||
bool status = false;
|
||||
struct dlmstp_user_data_t *port;
|
||||
struct dlmstp_user_data_t *user;
|
||||
|
||||
if (MSTP_Port) {
|
||||
port = MSTP_Port->UserData;
|
||||
if (port) {
|
||||
status = Ringbuf_Empty(&port->PDU_Queue);
|
||||
user = MSTP_Port->UserData;
|
||||
if (user) {
|
||||
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 status = false;
|
||||
struct dlmstp_user_data_t *port;
|
||||
struct dlmstp_user_data_t *user;
|
||||
|
||||
if (MSTP_Port) {
|
||||
port = MSTP_Port->UserData;
|
||||
if (port) {
|
||||
status = Ringbuf_Full(&port->PDU_Queue);
|
||||
user = MSTP_Port->UserData;
|
||||
if (user) {
|
||||
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)
|
||||
{
|
||||
struct dlmstp_user_data_t *port;
|
||||
struct dlmstp_user_data_t *user;
|
||||
struct dlmstp_rs485_driver *driver;
|
||||
|
||||
if (!MSTP_Port) {
|
||||
@@ -695,12 +662,20 @@ void dlmstp_set_baud_rate(uint32_t baud)
|
||||
if (!MSTP_Port->UserData) {
|
||||
return;
|
||||
}
|
||||
port = MSTP_Port->UserData;
|
||||
driver = port->RS485_Driver;
|
||||
user = MSTP_Port->UserData;
|
||||
driver = user->RS485_Driver;
|
||||
if (!driver) {
|
||||
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)
|
||||
{
|
||||
struct dlmstp_user_data_t *port;
|
||||
struct dlmstp_user_data_t *user;
|
||||
struct dlmstp_rs485_driver *driver;
|
||||
|
||||
if (!MSTP_Port) {
|
||||
@@ -718,8 +693,8 @@ uint32_t dlmstp_baud_rate(void)
|
||||
if (!MSTP_Port->UserData) {
|
||||
return 0;
|
||||
}
|
||||
port = MSTP_Port->UserData;
|
||||
driver = port->RS485_Driver;
|
||||
user = MSTP_Port->UserData;
|
||||
driver = user->RS485_Driver;
|
||||
if (!driver) {
|
||||
return 0;
|
||||
}
|
||||
@@ -733,7 +708,7 @@ uint32_t dlmstp_baud_rate(void)
|
||||
*/
|
||||
void dlmstp_fill_statistics(struct dlmstp_statistics *statistics)
|
||||
{
|
||||
struct dlmstp_user_data_t *port;
|
||||
struct dlmstp_user_data_t *user;
|
||||
|
||||
if (!MSTP_Port) {
|
||||
return;
|
||||
@@ -741,12 +716,12 @@ void dlmstp_fill_statistics(struct dlmstp_statistics *statistics)
|
||||
if (!MSTP_Port->UserData) {
|
||||
return;
|
||||
}
|
||||
port = MSTP_Port->UserData;
|
||||
if (!port) {
|
||||
user = MSTP_Port->UserData;
|
||||
if (!user) {
|
||||
return;
|
||||
}
|
||||
if (statistics) {
|
||||
*statistics = port->Statistics;
|
||||
*statistics = user->Statistics;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -821,18 +796,18 @@ void dlmstp_silence_reset(void *arg)
|
||||
*/
|
||||
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;
|
||||
if (MSTP_Port) {
|
||||
MSTP_Port->SilenceTimer = dlmstp_silence_milliseconds;
|
||||
MSTP_Port->SilenceTimerReset = dlmstp_silence_reset;
|
||||
user_data = (struct dlmstp_user_data_t *)MSTP_Port->UserData;
|
||||
if (user_data && !user_data->Initialized) {
|
||||
Ringbuf_Init(&user_data->PDU_Queue,
|
||||
(volatile uint8_t *)user_data->PDU_Buffer,
|
||||
sizeof(user_data->PDU_Buffer), DLMSTP_MAX_INFO_FRAMES);
|
||||
user = (struct dlmstp_user_data_t *)MSTP_Port->UserData;
|
||||
if (user && !user->Initialized) {
|
||||
Ringbuf_Init(&user->PDU_Queue,
|
||||
(volatile uint8_t *)user->PDU_Buffer,
|
||||
sizeof(user->PDU_Buffer), DLMSTP_MAX_INFO_FRAMES);
|
||||
MSTP_Init(MSTP_Port);
|
||||
user_data->Initialized = true;
|
||||
user->Initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+528
-215
File diff suppressed because it is too large
Load Diff
+209
-156
@@ -1,27 +1,27 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2004 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
*
|
||||
* Copyright (C) 2004 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef MSTP_H
|
||||
#define MSTP_H
|
||||
|
||||
@@ -30,6 +30,17 @@
|
||||
#include <stdbool.h>
|
||||
#include "bacnet/bacnet_stack_exports.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 {
|
||||
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 */
|
||||
/* if an error is detected during the reception of a frame. */
|
||||
/* Set to FALSE by the Master or Slave Node state machine. */
|
||||
unsigned ReceiveError:1;
|
||||
unsigned ReceiveError : 1;
|
||||
/* There is data in the buffer */
|
||||
unsigned DataAvailable:1;
|
||||
unsigned ReceivedInvalidFrame:1;
|
||||
unsigned DataAvailable : 1;
|
||||
unsigned ReceivedInvalidFrame : 1;
|
||||
/* A Boolean flag set to TRUE by the Receive State Machine */
|
||||
/* if a valid frame is received. */
|
||||
/* Set to FALSE by the Master or Slave Node state machine. */
|
||||
unsigned ReceivedValidFrame:1;
|
||||
/* A Boolean flag set to TRUE by the Receive State Machine */
|
||||
/* if a valid frame is received but it is not addressed to us. */
|
||||
/* Set to FALSE by the Master or Slave Node state machine. */
|
||||
unsigned ReceivedValidFrameNotForUs:1;
|
||||
/* A Boolean flag set to TRUE by the master machine if this node is the */
|
||||
/* only known master node. */
|
||||
unsigned SoleMaster:1;
|
||||
unsigned ReceivedValidFrame : 1;
|
||||
/* A Boolean flag set to TRUE by the master machine if this node is the
|
||||
only known master node. */
|
||||
unsigned SoleMaster : 1;
|
||||
/* A Boolean flag set to TRUE if this node is a slave node */
|
||||
unsigned SlaveNodeEnabled : 1;
|
||||
/* A Boolean flag set to TRUE if this node is using a ZeroConfig address */
|
||||
unsigned ZeroConfigEnabled : 1;
|
||||
/* stores the latest received data */
|
||||
uint8_t DataRegister;
|
||||
/* Used to accumulate the CRC on the data field of a frame. */
|
||||
@@ -65,185 +76,227 @@ struct mstp_port_struct_t {
|
||||
uint16_t DataLength;
|
||||
/* Used to store the destination address of a received frame. */
|
||||
uint8_t DestinationAddress;
|
||||
/* Used to count the number of received octets or errors. */
|
||||
/* This is used in the detection of link activity. */
|
||||
/* Compared to Nmin_octets */
|
||||
/* Used to count the number of received octets or errors.
|
||||
This is used in the detection of link activity.
|
||||
Compared to Nmin_octets */
|
||||
uint8_t EventCount;
|
||||
/* Used to store the frame type of a received frame. */
|
||||
uint8_t FrameType;
|
||||
/* 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 */
|
||||
/* 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 */
|
||||
/* pass the token. */
|
||||
uint8_t FrameCount;
|
||||
/* Used to accumulate the CRC on the header of a frame. */
|
||||
uint8_t HeaderCRC;
|
||||
/* Used to store the actual CRC from the header. */
|
||||
uint8_t HeaderCRCActual;
|
||||
/* Used as an index by the Receive State Machine, up to a maximum value of */
|
||||
/* InputBufferSize. */
|
||||
/* Used as an index by the Receive State Machine,
|
||||
up to a maximum value of InputBufferSize. */
|
||||
uint32_t Index;
|
||||
/* An array of octets, used to store octets as they are received. */
|
||||
/* InputBuffer is indexed from 0 to InputBufferSize-1. */
|
||||
/* The maximum size of a frame is 501 octets. */
|
||||
/* FIXME: assign this to an actual array of bytes! */
|
||||
/* An array of octets, used to store octets as they are received.
|
||||
InputBuffer is indexed from 0 to InputBufferSize-1. */
|
||||
/* Note: assign this to an actual array of bytes! */
|
||||
/* Note: the buffer is designed as a pointer since some compilers
|
||||
and microcontroller architectures have limits as to places to
|
||||
hold contiguous memory. */
|
||||
uint8_t *InputBuffer;
|
||||
uint16_t InputBufferSize;
|
||||
/* "Next Station," the MAC address of the node to which This Station passes */
|
||||
/* the token. If the Next_Station is unknown, Next_Station shall be equal to */
|
||||
/* "Next Station," the MAC address of the node to which
|
||||
This Station passes */
|
||||
/* the token. If the Next_Station is unknown, Next_Station
|
||||
shall be equal to */
|
||||
/* This_Station. */
|
||||
uint8_t Next_Station;
|
||||
/* "Poll Station," the MAC address of the node to which This Station last */
|
||||
/* sent a Poll For Master. This is used during token maintenance. */
|
||||
/* "Poll Station," the MAC address of the node to which This Station last
|
||||
sent a Poll For Master. This is used during token maintenance. */
|
||||
uint8_t Poll_Station;
|
||||
/* A counter of transmission retries used for Token and Poll For Master */
|
||||
/* transmission. */
|
||||
/* A counter of transmission retries used for Token and Poll For Master
|
||||
transmission. */
|
||||
unsigned RetryCount;
|
||||
/* A timer with nominal 5 millisecond resolution used to measure and */
|
||||
/* generate silence on the medium between octets. It is incremented by a */
|
||||
/* timer process and is cleared by the Receive State Machine when activity */
|
||||
/* is detected and by the SendFrame procedure as each octet is transmitted. */
|
||||
/* Since the timer resolution is limited and the timer is not necessarily */
|
||||
/* synchronized to other machine events, a timer value of N will actually */
|
||||
/* denote intervals between N-1 and N */
|
||||
/* A timer with nominal 5 millisecond resolution used to measure
|
||||
and generate silence on the medium between octets. It is
|
||||
incremented by a timer process and is cleared by the Receive
|
||||
State Machine when activity is detected and by the SendFrame
|
||||
procedure as each octet is transmitted. */
|
||||
/* Since the timer resolution is limited and the timer is not necessarily
|
||||
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
|
||||
so that you can be atomic on 8 bit microcontrollers */
|
||||
uint32_t(
|
||||
*SilenceTimer) (
|
||||
void *pArg);
|
||||
void (
|
||||
*SilenceTimerReset) (
|
||||
void *pArg);
|
||||
uint32_t (*SilenceTimer)(void *pArg);
|
||||
void (*SilenceTimerReset)(void *pArg);
|
||||
|
||||
/* 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 */
|
||||
/* Machine when a Data Expecting Reply Answer activity is completed. */
|
||||
/* note: we always send a reply postponed since a message other than
|
||||
/* 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
|
||||
Machine when a Data Expecting Reply Answer activity is completed.
|
||||
note: we always send a reply postponed since a message other than
|
||||
the reply may be in the transmit queue */
|
||||
/* uint16_t ReplyPostponedTimer; */
|
||||
|
||||
/* Used to store the Source Address of a received frame. */
|
||||
uint8_t SourceAddress;
|
||||
|
||||
/* The number of tokens received by this node. When this counter reaches the */
|
||||
/* value Npoll, the node polls the address range between TS and NS for */
|
||||
/* additional master nodes. TokenCount is set to zero at the end of the */
|
||||
/* polling process. */
|
||||
/* The number of tokens received by this node. When this counter
|
||||
reaches the value Npoll, the node polls the address range between
|
||||
TS and NS for additional master nodes. TokenCount is set to zero
|
||||
at the end of the polling process. */
|
||||
unsigned TokenCount;
|
||||
|
||||
/* "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 */
|
||||
/* 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. */
|
||||
/* "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
|
||||
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. */
|
||||
uint8_t This_Station;
|
||||
|
||||
/* 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. */
|
||||
/* 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.*/
|
||||
uint8_t 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. */
|
||||
/* 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. */
|
||||
uint8_t Nmax_master;
|
||||
|
||||
/* An array of octets, used to store octets for transmitting */
|
||||
/* 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! */
|
||||
/* Note: the buffer is designed as a pointer since some compilers
|
||||
/* An array of octets, used to store octets for transmitting
|
||||
OutputBuffer is indexed from 0 to OutputBufferSize-1.
|
||||
FIXME: assign this to an actual array of bytes!
|
||||
Note: the buffer is designed as a pointer since some compilers
|
||||
and microcontroller architectures have limits as to places to
|
||||
hold contiguous memory. */
|
||||
uint8_t *OutputBuffer;
|
||||
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 */
|
||||
void *UserData;
|
||||
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void MSTP_Init(
|
||||
volatile struct mstp_port_struct_t *mstp_port);
|
||||
BACNET_STACK_EXPORT
|
||||
void MSTP_Receive_Frame_FSM(
|
||||
volatile struct mstp_port_struct_t
|
||||
*mstp_port);
|
||||
BACNET_STACK_EXPORT
|
||||
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);
|
||||
BACNET_STACK_EXPORT
|
||||
void MSTP_Init(struct mstp_port_struct_t *mstp_port);
|
||||
BACNET_STACK_EXPORT
|
||||
void MSTP_Receive_Frame_FSM(struct mstp_port_struct_t *mstp_port);
|
||||
BACNET_STACK_EXPORT
|
||||
bool MSTP_Master_Node_FSM(struct mstp_port_struct_t *mstp_port);
|
||||
BACNET_STACK_EXPORT
|
||||
void MSTP_Slave_Node_FSM(struct mstp_port_struct_t *mstp_port);
|
||||
|
||||
/* returns true if line is active */
|
||||
BACNET_STACK_EXPORT
|
||||
bool MSTP_Line_Active(
|
||||
volatile struct mstp_port_struct_t *mstp_port);
|
||||
/* returns true if line is active */
|
||||
BACNET_STACK_EXPORT
|
||||
bool MSTP_Line_Active(struct mstp_port_struct_t *mstp_port);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
uint16_t MSTP_Create_Frame(
|
||||
uint8_t * buffer, /* where frame is loaded */
|
||||
uint16_t 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 */
|
||||
uint16_t data_len); /* number of bytes of data (up to 501) */
|
||||
BACNET_STACK_EXPORT
|
||||
uint16_t MSTP_Create_Frame(uint8_t *buffer,
|
||||
uint16_t buffer_len,
|
||||
uint8_t frame_type,
|
||||
uint8_t destination,
|
||||
uint8_t source,
|
||||
uint8_t *data,
|
||||
uint16_t data_len);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void MSTP_Create_And_Send_Frame(
|
||||
volatile struct mstp_port_struct_t *mstp_port, /* port to send from */
|
||||
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 */
|
||||
uint16_t data_len);
|
||||
BACNET_STACK_EXPORT
|
||||
void MSTP_Create_And_Send_Frame(
|
||||
struct mstp_port_struct_t *mstp_port,
|
||||
uint8_t frame_type,
|
||||
uint8_t destination,
|
||||
uint8_t source,
|
||||
uint8_t *data,
|
||||
uint16_t data_len);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void MSTP_Fill_BACnet_Address(
|
||||
BACNET_ADDRESS * src,
|
||||
uint8_t mstp_address);
|
||||
BACNET_STACK_EXPORT
|
||||
void MSTP_Fill_BACnet_Address(BACNET_ADDRESS *src, uint8_t mstp_address);
|
||||
|
||||
/* functions used by the MS/TP state machine to put or get data */
|
||||
/* FIXME: developer must implement these in their DLMSTP module */
|
||||
BACNET_STACK_EXPORT
|
||||
void MSTP_Zero_Config_UUID_Init(struct mstp_port_struct_t *mstp_port);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
uint16_t MSTP_Put_Receive(
|
||||
volatile struct mstp_port_struct_t *mstp_port);
|
||||
BACNET_STACK_EXPORT
|
||||
void MSTP_Zero_Config_FSM(struct mstp_port_struct_t *mstp_port);
|
||||
|
||||
/* 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(
|
||||
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 */
|
||||
/* functions used by the MS/TP state machine to put or get data */
|
||||
/* FIXME: developer must implement these in their DLMSTP module */
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void MSTP_Send_Frame(
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
uint8_t * buffer,
|
||||
uint16_t nbytes);
|
||||
BACNET_STACK_EXPORT
|
||||
uint16_t MSTP_Put_Receive(
|
||||
struct mstp_port_struct_t *mstp_port);
|
||||
|
||||
/* 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
|
||||
}
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*********************************************************************/
|
||||
*
|
||||
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*********************************************************************/
|
||||
#ifndef MSTPDEF_H
|
||||
#define MSTPDEF_H
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
/* The value 255 is used to denote broadcast when used as a */
|
||||
/* destination address but is not allowed as a value for a station. */
|
||||
/* 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
|
||||
|
||||
/* MS/TP Frame Type */
|
||||
@@ -52,15 +52,23 @@
|
||||
/* These frames are available to vendors as proprietary (non-BACnet) frames. */
|
||||
/* The first two octets of the Data field shall specify the unique vendor */
|
||||
/* identification code, most significant octet first, for the type of */
|
||||
/* vendor-proprietary frame to be conveyed. The length of the data portion */
|
||||
/* of a Proprietary frame shall be in the range of 2 to 501 octets. */
|
||||
/* vendor-proprietary frame to be conveyed. */
|
||||
#define FRAME_TYPE_PROPRIETARY_MIN 128
|
||||
#define FRAME_TYPE_PROPRIETARY_MAX 255
|
||||
/* The initial CRC16 checksum value */
|
||||
#define CRC16_INITIAL_VALUE (0xFFFF)
|
||||
#define CRC32K_INITIAL_VALUE (0xFFFFFFFF)
|
||||
#define CRC32K_RESIDUE (0x0843323B)
|
||||
/* frame specific data */
|
||||
#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
|
||||
|
||||
/* receive FSM states */
|
||||
@@ -85,6 +93,16 @@ typedef enum {
|
||||
MSTP_MASTER_STATE_ANSWER_DATA_REQUEST = 8
|
||||
} 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 */
|
||||
/* of loss of token: 500 milliseconds. */
|
||||
#define Tno_token 500
|
||||
@@ -98,13 +116,29 @@ typedef enum {
|
||||
/* 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 */
|
||||
#define Tturnaround (40UL)
|
||||
#define Tturnaround (40UL)
|
||||
/* turnaround_time_milliseconds = (Tturnaround*1000UL)/RS485_Baud; */
|
||||
|
||||
/* The number of tokens received or used before a Poll For Master cycle */
|
||||
/* is executed: 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. */
|
||||
#define Nretry_token 1
|
||||
|
||||
@@ -126,6 +160,15 @@ typedef enum {
|
||||
/* 15 milliseconds. */
|
||||
#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_MASTER 127
|
||||
#define DEFAULT_MAC_ADDRESS 127
|
||||
@@ -134,7 +177,6 @@ typedef enum {
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@@ -87,3 +87,18 @@ const char *mstptext_frame_type(unsigned index)
|
||||
return indtext_by_index_split_default(mstp_frame_type_text, index,
|
||||
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");
|
||||
}
|
||||
|
||||
@@ -39,6 +39,9 @@ extern "C" {
|
||||
BACNET_STACK_EXPORT
|
||||
const char *mstptext_frame_type(
|
||||
unsigned index);
|
||||
BACNET_STACK_EXPORT
|
||||
const char *mstptext_zero_config_state(
|
||||
unsigned index);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -158,6 +158,7 @@ list(APPEND testdirs
|
||||
bacnet/datalink/cobs
|
||||
bacnet/datalink/crc
|
||||
bacnet/datalink/bvlc
|
||||
bacnet/datalink/mstp
|
||||
)
|
||||
|
||||
enable_testing()
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user