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:
$(MAKE) -s -C test clean
$(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)
/* 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;
+2 -2
View File
@@ -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) {
+6 -8
View File
@@ -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;
+7 -7
View File
@@ -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;
-10
View File
@@ -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;
+7 -7
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+4
View File
@@ -17,6 +17,10 @@
"searchDir": [],
"svdFile":"${workspaceRoot}/stm32f429.svd",
"runToEntryPoint": "main",
"liveWatch": {
"enabled": true,
"samplesPerSecond": 1
},
"swoConfig": {
"enabled": true,
"cpuFrequency": 8000000,
+3 -4
View File
@@ -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
View File
@@ -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);
+9 -7
View File
@@ -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 */
+7 -5
View File
@@ -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
View File
@@ -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
View File
@@ -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(
+2
View File
@@ -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
View File
@@ -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
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>
*
* 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
}
+69 -27
View File
@@ -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 */
+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,
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
const char *mstptext_frame_type(
unsigned index);
BACNET_STACK_EXPORT
const char *mstptext_zero_config_state(
unsigned index);
#ifdef __cplusplus
}
+1
View File
@@ -158,6 +158,7 @@ list(APPEND testdirs
bacnet/datalink/cobs
bacnet/datalink/crc
bacnet/datalink/bvlc
bacnet/datalink/mstp
)
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