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:
|
test:
|
||||||
$(MAKE) -s -C test clean
|
$(MAKE) -s -C test clean
|
||||||
$(MAKE) -s -j -C test all
|
$(MAKE) -s -j -C test all
|
||||||
|
|
||||||
|
.PHONY: retest
|
||||||
|
retest:
|
||||||
|
$(MAKE) -s -j -C test retest
|
||||||
|
|||||||
+13
-24
@@ -68,7 +68,7 @@
|
|||||||
#define MSTP_HEADER_MAX (2 + 1 + 1 + 1 + 2 + 1)
|
#define MSTP_HEADER_MAX (2 + 1 + 1 + 1 + 2 + 1)
|
||||||
|
|
||||||
/* local port data - shared with RS-485 */
|
/* local port data - shared with RS-485 */
|
||||||
static volatile struct mstp_port_struct_t MSTP_Port;
|
static struct mstp_port_struct_t MSTP_Port;
|
||||||
/* track the receive state to know when there is a broken packet */
|
/* track the receive state to know when there is a broken packet */
|
||||||
static MSTP_RECEIVE_STATE MSTP_Receive_State = MSTP_RECEIVE_STATE_IDLE;
|
static MSTP_RECEIVE_STATE MSTP_Receive_State = MSTP_RECEIVE_STATE_IDLE;
|
||||||
/* buffers needed by mstp port struct */
|
/* buffers needed by mstp port struct */
|
||||||
@@ -185,7 +185,7 @@ static void mstp_monitor_i_am(uint8_t mac, uint8_t *pdu, uint16_t pdu_len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void packet_statistics(
|
static void packet_statistics(
|
||||||
struct timeval *tv, volatile struct mstp_port_struct_t *mstp_port)
|
struct timeval *tv, struct mstp_port_struct_t *mstp_port)
|
||||||
{
|
{
|
||||||
static struct timeval old_tv = { 0 };
|
static struct timeval old_tv = { 0 };
|
||||||
static uint8_t old_frame = 255;
|
static uint8_t old_frame = 255;
|
||||||
@@ -286,8 +286,7 @@ static void packet_statistics(
|
|||||||
MSTP_Statistics[src].der_reply = delta;
|
MSTP_Statistics[src].der_reply = delta;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((mstp_port->ReceivedValidFrame) ||
|
if (mstp_port->ReceivedValidFrame) {
|
||||||
(mstp_port->ReceivedValidFrameNotForUs)) {
|
|
||||||
if ((mstp_port->DataLength <= mstp_port->InputBufferSize) &&
|
if ((mstp_port->DataLength <= mstp_port->InputBufferSize) &&
|
||||||
(mstp_port->DataLength > 0)) {
|
(mstp_port->DataLength > 0)) {
|
||||||
mstp_monitor_i_am(
|
mstp_monitor_i_am(
|
||||||
@@ -413,7 +412,7 @@ static void Timer_Silence_Reset(void *pArg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* functions used by the MS/TP state machine to put or get data */
|
/* functions used by the MS/TP state machine to put or get data */
|
||||||
uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port)
|
uint16_t MSTP_Put_Receive(struct mstp_port_struct_t *mstp_port)
|
||||||
{
|
{
|
||||||
(void)mstp_port;
|
(void)mstp_port;
|
||||||
|
|
||||||
@@ -423,7 +422,7 @@ uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
/* for the MS/TP state machine to use for getting data to send */
|
/* for the MS/TP state machine to use for getting data to send */
|
||||||
/* Return: amount of PDU data */
|
/* Return: amount of PDU data */
|
||||||
uint16_t MSTP_Get_Send(
|
uint16_t MSTP_Get_Send(
|
||||||
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
||||||
{ /* milliseconds to wait for a packet */
|
{ /* milliseconds to wait for a packet */
|
||||||
(void)mstp_port;
|
(void)mstp_port;
|
||||||
(void)timeout;
|
(void)timeout;
|
||||||
@@ -437,7 +436,7 @@ uint16_t MSTP_Get_Send(
|
|||||||
* @param nbytes - number of bytes of data to send
|
* @param nbytes - number of bytes of data to send
|
||||||
*/
|
*/
|
||||||
void MSTP_Send_Frame(
|
void MSTP_Send_Frame(
|
||||||
volatile struct mstp_port_struct_t *mstp_port,
|
struct mstp_port_struct_t *mstp_port,
|
||||||
uint8_t * buffer,
|
uint8_t * buffer,
|
||||||
uint16_t nbytes)
|
uint16_t nbytes)
|
||||||
{
|
{
|
||||||
@@ -447,7 +446,7 @@ void MSTP_Send_Frame(
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint16_t MSTP_Get_Reply(
|
uint16_t MSTP_Get_Reply(
|
||||||
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
||||||
{ /* milliseconds to wait for a packet */
|
{ /* milliseconds to wait for a packet */
|
||||||
(void)mstp_port;
|
(void)mstp_port;
|
||||||
(void)timeout;
|
(void)timeout;
|
||||||
@@ -623,7 +622,7 @@ static void write_global_header(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void write_received_packet(
|
static void write_received_packet(
|
||||||
volatile struct mstp_port_struct_t *mstp_port, size_t header_len)
|
struct mstp_port_struct_t *mstp_port, size_t header_len)
|
||||||
{
|
{
|
||||||
uint32_t ts_sec = 0; /* timestamp seconds */
|
uint32_t ts_sec = 0; /* timestamp seconds */
|
||||||
uint32_t ts_usec = 0; /* timestamp microseconds */
|
uint32_t ts_usec = 0; /* timestamp microseconds */
|
||||||
@@ -637,8 +636,7 @@ static void write_received_packet(
|
|||||||
gettimeofday(&tv, NULL);
|
gettimeofday(&tv, NULL);
|
||||||
ts_sec = tv.tv_sec;
|
ts_sec = tv.tv_sec;
|
||||||
ts_usec = tv.tv_usec;
|
ts_usec = tv.tv_usec;
|
||||||
if ((mstp_port->ReceivedValidFrame) ||
|
if (mstp_port->ReceivedValidFrame) {
|
||||||
(mstp_port->ReceivedValidFrameNotForUs)) {
|
|
||||||
packet_statistics(&tv, mstp_port);
|
packet_statistics(&tv, mstp_port);
|
||||||
}
|
}
|
||||||
(void)data_write(&ts_sec, sizeof(ts_sec), 1);
|
(void)data_write(&ts_sec, sizeof(ts_sec), 1);
|
||||||
@@ -765,7 +763,7 @@ static bool test_global_header(const char *filename)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool read_received_packet(volatile struct mstp_port_struct_t *mstp_port)
|
static bool read_received_packet(struct mstp_port_struct_t *mstp_port)
|
||||||
{
|
{
|
||||||
uint32_t ts_sec = 0; /* timestamp seconds */
|
uint32_t ts_sec = 0; /* timestamp seconds */
|
||||||
uint32_t ts_usec = 0; /* timestamp microseconds */
|
uint32_t ts_usec = 0; /* timestamp microseconds */
|
||||||
@@ -824,7 +822,6 @@ static bool read_received_packet(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
mstp_port->ReceivedInvalidFrame = false;
|
mstp_port->ReceivedInvalidFrame = false;
|
||||||
if (mstp_port->DataLength == 0) {
|
if (mstp_port->DataLength == 0) {
|
||||||
mstp_port->ReceivedValidFrame = true;
|
mstp_port->ReceivedValidFrame = true;
|
||||||
mstp_port->ReceivedValidFrameNotForUs = true;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mstp_port->ReceivedValidFrame = false;
|
mstp_port->ReceivedValidFrame = false;
|
||||||
@@ -864,19 +861,16 @@ static bool read_received_packet(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
if (mstp_port->DataCRC == 0xF0B8) {
|
if (mstp_port->DataCRC == 0xF0B8) {
|
||||||
mstp_port->ReceivedInvalidFrame = false;
|
mstp_port->ReceivedInvalidFrame = false;
|
||||||
mstp_port->ReceivedValidFrame = true;
|
mstp_port->ReceivedValidFrame = true;
|
||||||
mstp_port->ReceivedValidFrameNotForUs = true;
|
|
||||||
} else {
|
} else {
|
||||||
mstp_port->ReceivedInvalidFrame = true;
|
mstp_port->ReceivedInvalidFrame = true;
|
||||||
mstp_port->ReceivedValidFrame = false;
|
mstp_port->ReceivedValidFrame = false;
|
||||||
mstp_port->ReceivedValidFrameNotForUs = false;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mstp_port->DataLength = 0;
|
mstp_port->DataLength = 0;
|
||||||
}
|
}
|
||||||
if (mstp_port->ReceivedInvalidFrame) {
|
if (mstp_port->ReceivedInvalidFrame) {
|
||||||
Invalid_Frame_Count++;
|
Invalid_Frame_Count++;
|
||||||
} else if ((mstp_port->ReceivedValidFrame) ||
|
} else if (mstp_port->ReceivedValidFrame) {
|
||||||
(mstp_port->ReceivedValidFrameNotForUs)) {
|
|
||||||
packet_statistics(&tv, mstp_port);
|
packet_statistics(&tv, mstp_port);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -984,7 +978,7 @@ static void print_help(char *filename)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* initialize some of the variables in the MS/TP Receive structure */
|
/* initialize some of the variables in the MS/TP Receive structure */
|
||||||
static void mstp_structure_init(volatile struct mstp_port_struct_t *mstp_port)
|
static void mstp_structure_init(struct mstp_port_struct_t *mstp_port)
|
||||||
{
|
{
|
||||||
if (mstp_port) {
|
if (mstp_port) {
|
||||||
mstp_port->FrameType = FRAME_TYPE_PROPRIETARY_MAX;
|
mstp_port->FrameType = FRAME_TYPE_PROPRIETARY_MAX;
|
||||||
@@ -996,7 +990,6 @@ static void mstp_structure_init(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
mstp_port->EventCount = 0;
|
mstp_port->EventCount = 0;
|
||||||
mstp_port->ReceivedInvalidFrame = false;
|
mstp_port->ReceivedInvalidFrame = false;
|
||||||
mstp_port->ReceivedValidFrame = false;
|
mstp_port->ReceivedValidFrame = false;
|
||||||
mstp_port->ReceivedValidFrameNotForUs = false;
|
|
||||||
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
|
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1004,7 +997,7 @@ static void mstp_structure_init(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
/* simple test to packetize the data and print it */
|
/* simple test to packetize the data and print it */
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
volatile struct mstp_port_struct_t *mstp_port;
|
struct mstp_port_struct_t *mstp_port;
|
||||||
long my_baud = 38400;
|
long my_baud = 38400;
|
||||||
uint32_t packet_count = 0;
|
uint32_t packet_count = 0;
|
||||||
uint32_t header_len = 0;
|
uint32_t header_len = 0;
|
||||||
@@ -1177,10 +1170,6 @@ int main(int argc, char *argv[])
|
|||||||
write_received_packet(mstp_port, MSTP_HEADER_MAX);
|
write_received_packet(mstp_port, MSTP_HEADER_MAX);
|
||||||
mstp_structure_init(mstp_port);
|
mstp_structure_init(mstp_port);
|
||||||
packet_count++;
|
packet_count++;
|
||||||
} else if (mstp_port->ReceivedValidFrameNotForUs) {
|
|
||||||
write_received_packet(mstp_port, MSTP_HEADER_MAX);
|
|
||||||
mstp_structure_init(mstp_port);
|
|
||||||
packet_count++;
|
|
||||||
} else if (mstp_port->ReceivedInvalidFrame) {
|
} else if (mstp_port->ReceivedInvalidFrame) {
|
||||||
if (MSTP_Receive_State == MSTP_RECEIVE_STATE_HEADER) {
|
if (MSTP_Receive_State == MSTP_RECEIVE_STATE_HEADER) {
|
||||||
mstp_port->Index = 0;
|
mstp_port->Index = 0;
|
||||||
|
|||||||
@@ -50,9 +50,7 @@ void *dl_mstp_thread(void *pArgs)
|
|||||||
uint16_t pdu_len;
|
uint16_t pdu_len;
|
||||||
uint8_t shutdown = 0;
|
uint8_t shutdown = 0;
|
||||||
|
|
||||||
shared_port_data.Treply_timeout = 260;
|
|
||||||
shared_port_data.MSTP_Packets = 0;
|
shared_port_data.MSTP_Packets = 0;
|
||||||
shared_port_data.Tusage_timeout = 30;
|
|
||||||
shared_port_data.RS485_Handle = -1;
|
shared_port_data.RS485_Handle = -1;
|
||||||
shared_port_data.RS485_Baud = B38400;
|
shared_port_data.RS485_Baud = B38400;
|
||||||
shared_port_data.RS485MOD = 0;
|
shared_port_data.RS485MOD = 0;
|
||||||
@@ -95,6 +93,8 @@ void *dl_mstp_thread(void *pArgs)
|
|||||||
if (!dlmstp_init(&mstp_port, port->iface)) {
|
if (!dlmstp_init(&mstp_port, port->iface)) {
|
||||||
printf("MSTP %s init failed. Stop.\n", port->iface);
|
printf("MSTP %s init failed. Stop.\n", port->iface);
|
||||||
}
|
}
|
||||||
|
mstp_port.Treply_timeout = 260;
|
||||||
|
mstp_port.Tusage_timeout = 30;
|
||||||
|
|
||||||
port->port_id = create_msgbox();
|
port->port_id = create_msgbox();
|
||||||
if (port->port_id == INVALID_MSGBOX_ID) {
|
if (port->port_id == INVALID_MSGBOX_ID) {
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ static bool run_thread;
|
|||||||
|
|
||||||
/*RT_TASK Receive_Task, Fsm_Task;*/
|
/*RT_TASK Receive_Task, Fsm_Task;*/
|
||||||
/* local MS/TP port data - shared with RS-485 */
|
/* local MS/TP port data - shared with RS-485 */
|
||||||
static volatile struct mstp_port_struct_t MSTP_Port;
|
static struct mstp_port_struct_t MSTP_Port;
|
||||||
/* buffers needed by mstp port struct */
|
/* buffers needed by mstp port struct */
|
||||||
static uint8_t TxBuffer[DLMSTP_MPDU_MAX];
|
static uint8_t TxBuffer[DLMSTP_MPDU_MAX];
|
||||||
static uint8_t RxBuffer[DLMSTP_MPDU_MAX];
|
static uint8_t RxBuffer[DLMSTP_MPDU_MAX];
|
||||||
@@ -287,7 +287,7 @@ static void *dlmstp_master_fsm_task(void *pArg)
|
|||||||
if (MSTP_Port.ReceivedValidFrame || MSTP_Port.ReceivedInvalidFrame) {
|
if (MSTP_Port.ReceivedValidFrame || MSTP_Port.ReceivedInvalidFrame) {
|
||||||
run_master = true;
|
run_master = true;
|
||||||
} else {
|
} else {
|
||||||
silence = MSTP_Port.SilenceTimer(NULL);
|
silence = MSTP_Port.SilenceTimer(&MSTP_Port);
|
||||||
switch (MSTP_Port.master_state) {
|
switch (MSTP_Port.master_state) {
|
||||||
case MSTP_MASTER_STATE_IDLE:
|
case MSTP_MASTER_STATE_IDLE:
|
||||||
if (silence >= Tno_token)
|
if (silence >= Tno_token)
|
||||||
@@ -353,7 +353,7 @@ void dlmstp_fill_bacnet_address(BACNET_ADDRESS *src, uint8_t mstp_address)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* for the MS/TP state machine to use for putting received data */
|
/* for the MS/TP state machine to use for putting received data */
|
||||||
uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port)
|
uint16_t MSTP_Put_Receive(struct mstp_port_struct_t *mstp_port)
|
||||||
{
|
{
|
||||||
uint16_t pdu_len = 0;
|
uint16_t pdu_len = 0;
|
||||||
|
|
||||||
@@ -384,8 +384,7 @@ uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
|
|
||||||
/* for the MS/TP state machine to use for getting data to send */
|
/* for the MS/TP state machine to use for getting data to send */
|
||||||
/* Return: amount of PDU data */
|
/* Return: amount of PDU data */
|
||||||
uint16_t MSTP_Get_Send(
|
uint16_t MSTP_Get_Send(struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
||||||
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
|
||||||
{ /* milliseconds to wait for a packet */
|
{ /* milliseconds to wait for a packet */
|
||||||
uint16_t pdu_len = 0;
|
uint16_t pdu_len = 0;
|
||||||
uint8_t frame_type = 0;
|
uint8_t frame_type = 0;
|
||||||
@@ -421,7 +420,7 @@ uint16_t MSTP_Get_Send(
|
|||||||
* @param nbytes - number of bytes of data to send
|
* @param nbytes - number of bytes of data to send
|
||||||
*/
|
*/
|
||||||
void MSTP_Send_Frame(
|
void MSTP_Send_Frame(
|
||||||
volatile struct mstp_port_struct_t *mstp_port,
|
struct mstp_port_struct_t *mstp_port,
|
||||||
uint8_t * buffer,
|
uint8_t * buffer,
|
||||||
uint16_t nbytes)
|
uint16_t nbytes)
|
||||||
{
|
{
|
||||||
@@ -584,8 +583,7 @@ static bool dlmstp_compare_data_expecting_reply(uint8_t *request_pdu,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Get the reply to a DATA_EXPECTING_REPLY frame, or nothing */
|
/* Get the reply to a DATA_EXPECTING_REPLY frame, or nothing */
|
||||||
uint16_t MSTP_Get_Reply(
|
uint16_t MSTP_Get_Reply(struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
||||||
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
|
||||||
{ /* milliseconds to wait for a packet */
|
{ /* milliseconds to wait for a packet */
|
||||||
uint16_t pdu_len = 0; /* return value */
|
uint16_t pdu_len = 0; /* return value */
|
||||||
bool matched = false;
|
bool matched = false;
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ void *dlmstp_receive_fsm_task(void *pArg)
|
|||||||
do {
|
do {
|
||||||
RS485_Check_UART_Data(mstp_port);
|
RS485_Check_UART_Data(mstp_port);
|
||||||
MSTP_Receive_Frame_FSM(
|
MSTP_Receive_Frame_FSM(
|
||||||
(volatile struct mstp_port_struct_t *)pArg);
|
(struct mstp_port_struct_t *)pArg);
|
||||||
received_frame = mstp_port->ReceivedValidFrame ||
|
received_frame = mstp_port->ReceivedValidFrame ||
|
||||||
mstp_port->ReceivedInvalidFrame;
|
mstp_port->ReceivedInvalidFrame;
|
||||||
if (received_frame) {
|
if (received_frame) {
|
||||||
@@ -274,11 +274,11 @@ void *dlmstp_master_fsm_task(void *pArg)
|
|||||||
run_master = true;
|
run_master = true;
|
||||||
break;
|
break;
|
||||||
case MSTP_MASTER_STATE_WAIT_FOR_REPLY:
|
case MSTP_MASTER_STATE_WAIT_FOR_REPLY:
|
||||||
if (silence >= poSharedData->Treply_timeout)
|
if (silence >= mstp_port->Treply_timeout)
|
||||||
run_master = true;
|
run_master = true;
|
||||||
break;
|
break;
|
||||||
case MSTP_MASTER_STATE_POLL_FOR_MASTER:
|
case MSTP_MASTER_STATE_POLL_FOR_MASTER:
|
||||||
if (silence >= poSharedData->Tusage_timeout)
|
if (silence >= mstp_port->Tusage_timeout)
|
||||||
run_master = true;
|
run_master = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -324,7 +324,7 @@ void dlmstp_fill_bacnet_address(BACNET_ADDRESS *src, uint8_t mstp_address)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* for the MS/TP state machine to use for putting received data */
|
/* for the MS/TP state machine to use for putting received data */
|
||||||
uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port)
|
uint16_t MSTP_Put_Receive(struct mstp_port_struct_t *mstp_port)
|
||||||
{
|
{
|
||||||
uint16_t pdu_len = 0;
|
uint16_t pdu_len = 0;
|
||||||
SHARED_MSTP_DATA *poSharedData = (SHARED_MSTP_DATA *)mstp_port->UserData;
|
SHARED_MSTP_DATA *poSharedData = (SHARED_MSTP_DATA *)mstp_port->UserData;
|
||||||
@@ -353,7 +353,7 @@ uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
/* for the MS/TP state machine to use for getting data to send */
|
/* for the MS/TP state machine to use for getting data to send */
|
||||||
/* Return: amount of PDU data */
|
/* Return: amount of PDU data */
|
||||||
uint16_t MSTP_Get_Send(
|
uint16_t MSTP_Get_Send(
|
||||||
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
||||||
{ /* milliseconds to wait for a packet */
|
{ /* milliseconds to wait for a packet */
|
||||||
uint16_t pdu_len = 0;
|
uint16_t pdu_len = 0;
|
||||||
uint8_t frame_type = 0;
|
uint8_t frame_type = 0;
|
||||||
@@ -391,7 +391,7 @@ uint16_t MSTP_Get_Send(
|
|||||||
* @param nbytes - number of bytes of data to send
|
* @param nbytes - number of bytes of data to send
|
||||||
*/
|
*/
|
||||||
void MSTP_Send_Frame(
|
void MSTP_Send_Frame(
|
||||||
volatile struct mstp_port_struct_t *mstp_port,
|
struct mstp_port_struct_t *mstp_port,
|
||||||
uint8_t * buffer,
|
uint8_t * buffer,
|
||||||
uint16_t nbytes)
|
uint16_t nbytes)
|
||||||
{
|
{
|
||||||
@@ -555,7 +555,7 @@ bool dlmstp_compare_data_expecting_reply(uint8_t *request_pdu,
|
|||||||
|
|
||||||
/* Get the reply to a DATA_EXPECTING_REPLY frame, or nothing */
|
/* Get the reply to a DATA_EXPECTING_REPLY frame, or nothing */
|
||||||
uint16_t MSTP_Get_Reply(
|
uint16_t MSTP_Get_Reply(
|
||||||
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
||||||
{ /* milliseconds to wait for a packet */
|
{ /* milliseconds to wait for a packet */
|
||||||
uint16_t pdu_len = 0; /* return value */
|
uint16_t pdu_len = 0; /* return value */
|
||||||
bool matched = false;
|
bool matched = false;
|
||||||
|
|||||||
@@ -87,16 +87,6 @@ typedef struct shared_mstp_data {
|
|||||||
/* buffers needed by mstp port struct */
|
/* buffers needed by mstp port struct */
|
||||||
uint8_t TxBuffer[DLMSTP_MPDU_MAX];
|
uint8_t TxBuffer[DLMSTP_MPDU_MAX];
|
||||||
uint8_t RxBuffer[DLMSTP_MPDU_MAX];
|
uint8_t RxBuffer[DLMSTP_MPDU_MAX];
|
||||||
/* The minimum time without a DataAvailable or ReceiveError event */
|
|
||||||
/* that a node must wait for a station to begin replying to a */
|
|
||||||
/* confirmed request: 255 milliseconds. (Implementations may use */
|
|
||||||
/* larger values for this timeout, not to exceed 300 milliseconds.) */
|
|
||||||
uint16_t Treply_timeout;
|
|
||||||
/* The minimum time without a DataAvailable or ReceiveError event that a */
|
|
||||||
/* node must wait for a remote node to begin using a token or replying to */
|
|
||||||
/* a Poll For Master frame: 20 milliseconds. (Implementations may use */
|
|
||||||
/* larger values for this timeout, not to exceed 100 milliseconds.) */
|
|
||||||
uint8_t Tusage_timeout;
|
|
||||||
/* Timer that indicates line silence - and functions */
|
/* Timer that indicates line silence - and functions */
|
||||||
uint16_t SilenceTime;
|
uint16_t SilenceTime;
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* local port data - shared with RS-485 */
|
/* local port data - shared with RS-485 */
|
||||||
static volatile struct mstp_port_struct_t MSTP_Port;
|
static struct mstp_port_struct_t MSTP_Port;
|
||||||
/* buffers needed by mstp port struct */
|
/* buffers needed by mstp port struct */
|
||||||
static uint8_t RxBuffer[DLMSTP_MPDU_MAX];
|
static uint8_t RxBuffer[DLMSTP_MPDU_MAX];
|
||||||
static uint8_t TxBuffer[DLMSTP_MPDU_MAX];
|
static uint8_t TxBuffer[DLMSTP_MPDU_MAX];
|
||||||
@@ -83,7 +83,7 @@ static void Timer_Silence_Reset(void *pArg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* functions used by the MS/TP state machine to put or get data */
|
/* functions used by the MS/TP state machine to put or get data */
|
||||||
uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port)
|
uint16_t MSTP_Put_Receive(struct mstp_port_struct_t *mstp_port)
|
||||||
{
|
{
|
||||||
(void)mstp_port;
|
(void)mstp_port;
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
/* for the MS/TP state machine to use for getting data to send */
|
/* for the MS/TP state machine to use for getting data to send */
|
||||||
/* Return: amount of PDU data */
|
/* Return: amount of PDU data */
|
||||||
uint16_t MSTP_Get_Send(
|
uint16_t MSTP_Get_Send(
|
||||||
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
||||||
{ /* milliseconds to wait for a packet */
|
{ /* milliseconds to wait for a packet */
|
||||||
(void)mstp_port;
|
(void)mstp_port;
|
||||||
(void)timeout;
|
(void)timeout;
|
||||||
@@ -107,7 +107,7 @@ uint16_t MSTP_Get_Send(
|
|||||||
* @param nbytes - number of bytes of data to send
|
* @param nbytes - number of bytes of data to send
|
||||||
*/
|
*/
|
||||||
void MSTP_Send_Frame(
|
void MSTP_Send_Frame(
|
||||||
volatile struct mstp_port_struct_t *mstp_port,
|
struct mstp_port_struct_t *mstp_port,
|
||||||
uint8_t * buffer,
|
uint8_t * buffer,
|
||||||
uint16_t nbytes)
|
uint16_t nbytes)
|
||||||
{
|
{
|
||||||
@@ -117,7 +117,7 @@ void MSTP_Send_Frame(
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint16_t MSTP_Get_Reply(
|
uint16_t MSTP_Get_Reply(
|
||||||
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
||||||
{ /* milliseconds to wait for a packet */
|
{ /* milliseconds to wait for a packet */
|
||||||
(void)mstp_port;
|
(void)mstp_port;
|
||||||
(void)timeout;
|
(void)timeout;
|
||||||
@@ -165,7 +165,7 @@ static int network_init(const char *name, int protocol)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void snap_received_packet(
|
static void snap_received_packet(
|
||||||
volatile struct mstp_port_struct_t *mstp_port, int sockfd)
|
struct mstp_port_struct_t *mstp_port, int sockfd)
|
||||||
{
|
{
|
||||||
uint16_t mtu_len = 0; /* number of octets of packet saved in file */
|
uint16_t mtu_len = 0; /* number of octets of packet saved in file */
|
||||||
unsigned i = 0; /* counter */
|
unsigned i = 0; /* counter */
|
||||||
@@ -241,7 +241,7 @@ void signal_init(void)
|
|||||||
/* simple test to packetize the data and print it */
|
/* simple test to packetize the data and print it */
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
volatile struct mstp_port_struct_t *mstp_port;
|
struct mstp_port_struct_t *mstp_port;
|
||||||
long my_baud = 38400;
|
long my_baud = 38400;
|
||||||
uint32_t packet_count = 0;
|
uint32_t packet_count = 0;
|
||||||
int sockfd = -1;
|
int sockfd = -1;
|
||||||
|
|||||||
+4
-4
@@ -217,7 +217,7 @@ uint32_t RS485_Get_Baud_Rate(void)
|
|||||||
* ALGORITHM: none
|
* ALGORITHM: none
|
||||||
* NOTES: none
|
* NOTES: none
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
uint32_t RS485_Get_Port_Baud_Rate(volatile struct mstp_port_struct_t *mstp_port)
|
uint32_t RS485_Get_Port_Baud_Rate(struct mstp_port_struct_t *mstp_port)
|
||||||
{
|
{
|
||||||
uint32_t baud = 0;
|
uint32_t baud = 0;
|
||||||
SHARED_MSTP_DATA *poSharedData = (SHARED_MSTP_DATA *)mstp_port->UserData;
|
SHARED_MSTP_DATA *poSharedData = (SHARED_MSTP_DATA *)mstp_port->UserData;
|
||||||
@@ -382,7 +382,7 @@ bool RS485_Set_Baud_Rate(uint32_t baud)
|
|||||||
* NOTES: none
|
* NOTES: none
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
void RS485_Send_Frame(
|
void RS485_Send_Frame(
|
||||||
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||||
uint8_t *buffer, /* frame to send (up to 501 bytes of data) */
|
uint8_t *buffer, /* frame to send (up to 501 bytes of data) */
|
||||||
uint16_t nbytes)
|
uint16_t nbytes)
|
||||||
{ /* number of bytes of data (up to 501) */
|
{ /* number of bytes of data (up to 501) */
|
||||||
@@ -458,7 +458,7 @@ void RS485_Send_Frame(
|
|||||||
* ALGORITHM: none
|
* ALGORITHM: none
|
||||||
* NOTES: none
|
* NOTES: none
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
void RS485_Check_UART_Data(volatile struct mstp_port_struct_t *mstp_port)
|
void RS485_Check_UART_Data(struct mstp_port_struct_t *mstp_port)
|
||||||
{
|
{
|
||||||
fd_set input;
|
fd_set input;
|
||||||
struct timeval waiter;
|
struct timeval waiter;
|
||||||
@@ -694,7 +694,7 @@ void RS485_Print_Ports(void)
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
volatile struct mstp_port_struct_t mstp_port = { 0 };
|
struct mstp_port_struct_t mstp_port = { 0 };
|
||||||
uint8_t token_buf[8] = { 0x55, 0xFF, 0x00, 0x7E, 0x07, 0x00, 0x00, 0xFD };
|
uint8_t token_buf[8] = { 0x55, 0xFF, 0x00, 0x7E, 0x07, 0x00, 0x00, 0xFD };
|
||||||
uint8_t pfm_buf[8] = { 0x55, 0xFF, 0x01, 0x67, 0x07, 0x00, 0x00, 0x3E };
|
uint8_t pfm_buf[8] = { 0x55, 0xFF, 0x01, 0x67, 0x07, 0x00, 0x00, 0x3E };
|
||||||
long baud = 38400;
|
long baud = 38400;
|
||||||
|
|||||||
+3
-3
@@ -57,16 +57,16 @@ extern "C" {
|
|||||||
|
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
void RS485_Send_Frame(
|
void RS485_Send_Frame(
|
||||||
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||||
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
||||||
uint16_t nbytes); /* number of bytes of data (up to 501) */
|
uint16_t nbytes); /* number of bytes of data (up to 501) */
|
||||||
|
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
void RS485_Check_UART_Data(
|
void RS485_Check_UART_Data(
|
||||||
volatile struct mstp_port_struct_t *mstp_port); /* port specific data */
|
struct mstp_port_struct_t *mstp_port); /* port specific data */
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
uint32_t RS485_Get_Port_Baud_Rate(
|
uint32_t RS485_Get_Port_Baud_Rate(
|
||||||
volatile struct mstp_port_struct_t *mstp_port);
|
struct mstp_port_struct_t *mstp_port);
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
uint32_t RS485_Get_Baud_Rate(
|
uint32_t RS485_Get_Baud_Rate(
|
||||||
void);
|
void);
|
||||||
|
|||||||
Vendored
+4
@@ -17,6 +17,10 @@
|
|||||||
"searchDir": [],
|
"searchDir": [],
|
||||||
"svdFile":"${workspaceRoot}/stm32f429.svd",
|
"svdFile":"${workspaceRoot}/stm32f429.svd",
|
||||||
"runToEntryPoint": "main",
|
"runToEntryPoint": "main",
|
||||||
|
"liveWatch": {
|
||||||
|
"enabled": true,
|
||||||
|
"samplesPerSecond": 1
|
||||||
|
},
|
||||||
"swoConfig": {
|
"swoConfig": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"cpuFrequency": 8000000,
|
"cpuFrequency": 8000000,
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ static struct my_object_functions {
|
|||||||
properties that are writable or that may change.
|
properties that are writable or that may change.
|
||||||
The properties that are constant can be hard coded
|
The properties that are constant can be hard coded
|
||||||
into the read-property encoding. */
|
into the read-property encoding. */
|
||||||
static uint32_t Object_Instance_Number = 103;
|
static uint32_t Object_Instance_Number = BACNET_MAX_INSTANCE;
|
||||||
static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL;
|
static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL;
|
||||||
static BACNET_CHARACTER_STRING My_Object_Name;
|
static BACNET_CHARACTER_STRING My_Object_Name;
|
||||||
static const char *Device_Name_Default = "stm32f4xx";
|
static const char *Device_Name_Default = "stm32f4xx";
|
||||||
@@ -1131,9 +1131,8 @@ void Device_Init(object_functions_t *object_table)
|
|||||||
pObject++;
|
pObject++;
|
||||||
}
|
}
|
||||||
dcc_set_status_duration(COMMUNICATION_ENABLE, 0);
|
dcc_set_status_duration(COMMUNICATION_ENABLE, 0);
|
||||||
if (Object_Instance_Number >= BACNET_MAX_INSTANCE) {
|
if (Object_Instance_Number > BACNET_MAX_INSTANCE) {
|
||||||
Object_Instance_Number = 103;
|
Object_Instance_Number = BACNET_MAX_INSTANCE;
|
||||||
srand(Object_Instance_Number);
|
|
||||||
}
|
}
|
||||||
characterstring_init_ansi(&My_Object_Name, Device_Name_Default);
|
characterstring_init_ansi(&My_Object_Name, Device_Name_Default);
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-2
@@ -22,7 +22,7 @@
|
|||||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*
|
*
|
||||||
*************************************************************************/
|
*************************************************************************/
|
||||||
|
#include <stdlib.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -30,7 +30,9 @@
|
|||||||
#include "stm32f4xx.h"
|
#include "stm32f4xx.h"
|
||||||
#include "stm32f4xx_pwr.h"
|
#include "stm32f4xx_pwr.h"
|
||||||
#include "stm32f4xx_rcc.h"
|
#include "stm32f4xx_rcc.h"
|
||||||
|
#include "stm32f4xx_rng.h"
|
||||||
#include "system_stm32f4xx.h"
|
#include "system_stm32f4xx.h"
|
||||||
|
#include "bacnet/basic/object/device.h"
|
||||||
#include "bacnet/basic/sys/mstimer.h"
|
#include "bacnet/basic/sys/mstimer.h"
|
||||||
#include "bacnet/basic/sys/ringbuf.h"
|
#include "bacnet/basic/sys/ringbuf.h"
|
||||||
#include "bacnet/datalink/datalink.h"
|
#include "bacnet/datalink/datalink.h"
|
||||||
@@ -96,13 +98,36 @@ int main(void)
|
|||||||
MSTP_Port.OutputBuffer = Output_Buffer;
|
MSTP_Port.OutputBuffer = Output_Buffer;
|
||||||
MSTP_Port.OutputBufferSize = sizeof(Output_Buffer);
|
MSTP_Port.OutputBufferSize = sizeof(Output_Buffer);
|
||||||
/* user data */
|
/* user data */
|
||||||
|
MSTP_Port.ZeroConfigEnabled = true;
|
||||||
|
MSTP_Port.SlaveNodeEnabled = false;
|
||||||
MSTP_User_Data.RS485_Driver = &RS485_Driver;
|
MSTP_User_Data.RS485_Driver = &RS485_Driver;
|
||||||
MSTP_Port.UserData = &MSTP_User_Data;
|
MSTP_Port.UserData = &MSTP_User_Data;
|
||||||
dlmstp_init((char *)&MSTP_Port);
|
dlmstp_init((char *)&MSTP_Port);
|
||||||
dlmstp_set_mac_address(2);
|
if (MSTP_Port.ZeroConfigEnabled) {
|
||||||
|
dlmstp_set_mac_address(255);
|
||||||
|
} else {
|
||||||
|
/* FIXME: get the address from hardware DIP or from EEPROM */
|
||||||
|
dlmstp_set_mac_address(1);
|
||||||
|
}
|
||||||
|
/* FIXME: get the baud rate from hardware DIP or from EEPROM */
|
||||||
dlmstp_set_baud_rate(DLMSTP_BAUD_RATE_DEFAULT);
|
dlmstp_set_baud_rate(DLMSTP_BAUD_RATE_DEFAULT);
|
||||||
/* initialize application layer*/
|
/* initialize application layer*/
|
||||||
bacnet_init();
|
bacnet_init();
|
||||||
|
/* FIXME: get the device ID from EEPROM */
|
||||||
|
Device_Set_Object_Instance_Number(103);
|
||||||
|
/* seed stdlib rand() with device-id to get pweudo consisten
|
||||||
|
zero-config poll slot, or use hardware RNG to get a more random slot */
|
||||||
|
#ifdef BACNET_ZERO_CONFIG_RNG_HARDWARE
|
||||||
|
/* enable the random number generator hardware */
|
||||||
|
RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_RNG, ENABLE);
|
||||||
|
RNG_Cmd(ENABLE);
|
||||||
|
while (RNG_GetFlagStatus(RNG_FLAG_DRDY) == RESET) {
|
||||||
|
/* wait for 32-bit random number to generate */
|
||||||
|
}
|
||||||
|
srand(RNG_GetRandomNumber());
|
||||||
|
#else
|
||||||
|
srand(Device_Object_Instance_Number());
|
||||||
|
#endif
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (mstimer_expired(&Blink_Timer)) {
|
if (mstimer_expired(&Blink_Timer)) {
|
||||||
mstimer_reset(&Blink_Timer);
|
mstimer_reset(&Blink_Timer);
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ static HANDLE Receive_Packet_Flag;
|
|||||||
HANDLE Received_Frame_Flag;
|
HANDLE Received_Frame_Flag;
|
||||||
static DLMSTP_PACKET Transmit_Packet;
|
static DLMSTP_PACKET Transmit_Packet;
|
||||||
/* local MS/TP port data - shared with RS-485 */
|
/* local MS/TP port data - shared with RS-485 */
|
||||||
volatile struct mstp_port_struct_t MSTP_Port;
|
static struct mstp_port_struct_t MSTP_Port;
|
||||||
/* buffers needed by mstp port struct */
|
/* buffers needed by mstp port struct */
|
||||||
static uint8_t TxBuffer[DLMSTP_MPDU_MAX];
|
static uint8_t TxBuffer[DLMSTP_MPDU_MAX];
|
||||||
static uint8_t RxBuffer[DLMSTP_MPDU_MAX];
|
static uint8_t RxBuffer[DLMSTP_MPDU_MAX];
|
||||||
@@ -62,11 +62,12 @@ static uint32_t TimeBeginPeriod;
|
|||||||
/* 1-millisecond target resolution */
|
/* 1-millisecond target resolution */
|
||||||
#define TARGET_RESOLUTION 1
|
#define TARGET_RESOLUTION 1
|
||||||
|
|
||||||
static uint16_t Timer_Silence(void)
|
static uint16_t Timer_Silence(void *arg)
|
||||||
{
|
{
|
||||||
uint32_t now = timeGetTime();
|
uint32_t now = timeGetTime();
|
||||||
uint32_t delta_time = 0;
|
uint32_t delta_time = 0;
|
||||||
|
|
||||||
|
(void)arg;
|
||||||
if (SilenceStartTime < now) {
|
if (SilenceStartTime < now) {
|
||||||
delta_time = now - SilenceStartTime;
|
delta_time = now - SilenceStartTime;
|
||||||
} else {
|
} else {
|
||||||
@@ -79,8 +80,9 @@ static uint16_t Timer_Silence(void)
|
|||||||
return (uint16_t)delta_time;
|
return (uint16_t)delta_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Timer_Silence_Reset(void)
|
static void Timer_Silence_Reset(void *arg)
|
||||||
{
|
{
|
||||||
|
(void)arg;
|
||||||
SilenceStartTime = timeGetTime();
|
SilenceStartTime = timeGetTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,7 +243,7 @@ void dlmstp_fill_bacnet_address(BACNET_ADDRESS *src, uint8_t mstp_address)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* for the MS/TP state machine to use for putting received data */
|
/* for the MS/TP state machine to use for putting received data */
|
||||||
uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port)
|
uint16_t MSTP_Put_Receive(struct mstp_port_struct_t *mstp_port)
|
||||||
{
|
{
|
||||||
uint16_t pdu_len = 0;
|
uint16_t pdu_len = 0;
|
||||||
BOOL rc;
|
BOOL rc;
|
||||||
@@ -266,7 +268,7 @@ uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
/* for the MS/TP state machine to use for getting data to send */
|
/* for the MS/TP state machine to use for getting data to send */
|
||||||
/* Return: amount of PDU data */
|
/* Return: amount of PDU data */
|
||||||
uint16_t MSTP_Get_Send(
|
uint16_t MSTP_Get_Send(
|
||||||
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
||||||
{ /* milliseconds to wait for a packet */
|
{ /* milliseconds to wait for a packet */
|
||||||
uint16_t pdu_len = 0;
|
uint16_t pdu_len = 0;
|
||||||
uint8_t destination = 0; /* destination address */
|
uint8_t destination = 0; /* destination address */
|
||||||
@@ -303,7 +305,7 @@ uint16_t MSTP_Get_Send(
|
|||||||
* @param nbytes - number of bytes of data to send
|
* @param nbytes - number of bytes of data to send
|
||||||
*/
|
*/
|
||||||
void MSTP_Send_Frame(
|
void MSTP_Send_Frame(
|
||||||
volatile struct mstp_port_struct_t *mstp_port,
|
struct mstp_port_struct_t *mstp_port,
|
||||||
uint8_t * buffer,
|
uint8_t * buffer,
|
||||||
uint16_t nbytes)
|
uint16_t nbytes)
|
||||||
{
|
{
|
||||||
@@ -420,7 +422,7 @@ bool dlmstp_compare_data_expecting_reply(uint8_t *request_pdu,
|
|||||||
|
|
||||||
/* Get the reply to a DATA_EXPECTING_REPLY frame, or nothing */
|
/* Get the reply to a DATA_EXPECTING_REPLY frame, or nothing */
|
||||||
uint16_t MSTP_Get_Reply(
|
uint16_t MSTP_Get_Reply(
|
||||||
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
||||||
{ /* milliseconds to wait for a packet */
|
{ /* milliseconds to wait for a packet */
|
||||||
uint16_t pdu_len = 0; /* return value */
|
uint16_t pdu_len = 0; /* return value */
|
||||||
uint8_t destination = 0; /* destination address */
|
uint8_t destination = 0; /* destination address */
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ static HANDLE Receive_Packet_Flag;
|
|||||||
HANDLE Received_Frame_Flag;
|
HANDLE Received_Frame_Flag;
|
||||||
static DLMSTP_PACKET Transmit_Packet;
|
static DLMSTP_PACKET Transmit_Packet;
|
||||||
/* local MS/TP port data - shared with RS-485 */
|
/* local MS/TP port data - shared with RS-485 */
|
||||||
volatile struct mstp_port_struct_t MSTP_Port;
|
struct mstp_port_struct_t MSTP_Port;
|
||||||
/* buffers needed by mstp port struct */
|
/* buffers needed by mstp port struct */
|
||||||
static uint8_t TxBuffer[DLMSTP_MPDU_MAX];
|
static uint8_t TxBuffer[DLMSTP_MPDU_MAX];
|
||||||
static uint8_t RxBuffer[DLMSTP_MPDU_MAX];
|
static uint8_t RxBuffer[DLMSTP_MPDU_MAX];
|
||||||
@@ -71,11 +71,13 @@ static struct mstimer Silence_Timer;
|
|||||||
/* Timer that indicates line silence - and functions */
|
/* Timer that indicates line silence - and functions */
|
||||||
static uint32_t Timer_Silence(void *pArg)
|
static uint32_t Timer_Silence(void *pArg)
|
||||||
{
|
{
|
||||||
|
(void)pArg;
|
||||||
return mstimer_elapsed(&Silence_Timer);
|
return mstimer_elapsed(&Silence_Timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Timer_Silence_Reset(void *pArg)
|
static void Timer_Silence_Reset(void *pArg)
|
||||||
{
|
{
|
||||||
|
(void)pArg;
|
||||||
mstimer_set(&Silence_Timer, 0);
|
mstimer_set(&Silence_Timer, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,7 +228,7 @@ void dlmstp_fill_bacnet_address(BACNET_ADDRESS *src, uint8_t mstp_address)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* for the MS/TP state machine to use for putting received data */
|
/* for the MS/TP state machine to use for putting received data */
|
||||||
uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port)
|
uint16_t MSTP_Put_Receive(struct mstp_port_struct_t *mstp_port)
|
||||||
{
|
{
|
||||||
uint16_t pdu_len = 0;
|
uint16_t pdu_len = 0;
|
||||||
BOOL rc;
|
BOOL rc;
|
||||||
@@ -252,7 +254,7 @@ uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
/* for the MS/TP state machine to use for getting data to send */
|
/* for the MS/TP state machine to use for getting data to send */
|
||||||
/* Return: amount of PDU data */
|
/* Return: amount of PDU data */
|
||||||
uint16_t MSTP_Get_Send(
|
uint16_t MSTP_Get_Send(
|
||||||
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
||||||
{ /* milliseconds to wait for a packet */
|
{ /* milliseconds to wait for a packet */
|
||||||
uint16_t pdu_len = 0;
|
uint16_t pdu_len = 0;
|
||||||
uint8_t destination = 0; /* destination address */
|
uint8_t destination = 0; /* destination address */
|
||||||
@@ -288,7 +290,7 @@ uint16_t MSTP_Get_Send(
|
|||||||
* @param nbytes - number of bytes of data to send
|
* @param nbytes - number of bytes of data to send
|
||||||
*/
|
*/
|
||||||
void MSTP_Send_Frame(
|
void MSTP_Send_Frame(
|
||||||
volatile struct mstp_port_struct_t *mstp_port,
|
struct mstp_port_struct_t *mstp_port,
|
||||||
uint8_t * buffer,
|
uint8_t * buffer,
|
||||||
uint16_t nbytes)
|
uint16_t nbytes)
|
||||||
{
|
{
|
||||||
@@ -405,7 +407,7 @@ static bool dlmstp_compare_data_expecting_reply(uint8_t *request_pdu,
|
|||||||
|
|
||||||
/* Get the reply to a DATA_EXPECTING_REPLY frame, or nothing */
|
/* Get the reply to a DATA_EXPECTING_REPLY frame, or nothing */
|
||||||
uint16_t MSTP_Get_Reply(
|
uint16_t MSTP_Get_Reply(
|
||||||
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
||||||
{ /* milliseconds to wait for a packet */
|
{ /* milliseconds to wait for a packet */
|
||||||
uint16_t pdu_len = 0; /* return value */
|
uint16_t pdu_len = 0; /* return value */
|
||||||
uint8_t destination = 0; /* destination address */
|
uint8_t destination = 0; /* destination address */
|
||||||
|
|||||||
+2
-2
@@ -421,7 +421,7 @@ bool RS485_Set_Baud_Rate(uint32_t baud)
|
|||||||
|
|
||||||
/* Transmits a Frame on the wire */
|
/* Transmits a Frame on the wire */
|
||||||
void RS485_Send_Frame(
|
void RS485_Send_Frame(
|
||||||
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||||
uint8_t *buffer, /* frame to send (up to 501 bytes of data) */
|
uint8_t *buffer, /* frame to send (up to 501 bytes of data) */
|
||||||
uint16_t nbytes)
|
uint16_t nbytes)
|
||||||
{ /* number of bytes of data (up to 501) */
|
{ /* number of bytes of data (up to 501) */
|
||||||
@@ -453,7 +453,7 @@ void RS485_Send_Frame(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* called by timer, interrupt(?) or other thread */
|
/* called by timer, interrupt(?) or other thread */
|
||||||
void RS485_Check_UART_Data(volatile struct mstp_port_struct_t *mstp_port)
|
void RS485_Check_UART_Data(struct mstp_port_struct_t *mstp_port)
|
||||||
{
|
{
|
||||||
char lpBuf[1];
|
char lpBuf[1];
|
||||||
DWORD dwRead = 0;
|
DWORD dwRead = 0;
|
||||||
|
|||||||
+2
-2
@@ -58,13 +58,13 @@ extern "C" {
|
|||||||
|
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
void RS485_Send_Frame(
|
void RS485_Send_Frame(
|
||||||
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||||
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
||||||
uint16_t nbytes); /* number of bytes of data (up to 501) */
|
uint16_t nbytes); /* number of bytes of data (up to 501) */
|
||||||
|
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
void RS485_Check_UART_Data(
|
void RS485_Check_UART_Data(
|
||||||
volatile struct mstp_port_struct_t *mstp_port); /* port specific data */
|
struct mstp_port_struct_t *mstp_port); /* port specific data */
|
||||||
|
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
uint32_t RS485_Get_Baud_Rate(
|
uint32_t RS485_Get_Baud_Rate(
|
||||||
|
|||||||
@@ -2631,6 +2631,7 @@ bool Network_Port_Read_Range(
|
|||||||
(void)pInfo;
|
(void)pInfo;
|
||||||
pRequest->error_class = ERROR_CLASS_PROPERTY;
|
pRequest->error_class = ERROR_CLASS_PROPERTY;
|
||||||
pRequest->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
pRequest->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||||
|
(void)pInfo;
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case PROP_BBMD_FOREIGN_DEVICE_TABLE:
|
case PROP_BBMD_FOREIGN_DEVICE_TABLE:
|
||||||
@@ -2642,6 +2643,7 @@ bool Network_Port_Read_Range(
|
|||||||
(void)pInfo;
|
(void)pInfo;
|
||||||
pRequest->error_class = ERROR_CLASS_PROPERTY;
|
pRequest->error_class = ERROR_CLASS_PROPERTY;
|
||||||
pRequest->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
pRequest->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||||
|
(void)pInfo;
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
+87
-112
@@ -41,7 +41,7 @@ int dlmstp_send_pdu(BACNET_ADDRESS *dest,
|
|||||||
{
|
{
|
||||||
int bytes_sent = 0;
|
int bytes_sent = 0;
|
||||||
unsigned i = 0; /* loop counter */
|
unsigned i = 0; /* loop counter */
|
||||||
struct dlmstp_user_data_t *port = NULL;
|
struct dlmstp_user_data_t *user = NULL;
|
||||||
struct dlmstp_packet *pkt;
|
struct dlmstp_packet *pkt;
|
||||||
|
|
||||||
if (!MSTP_Port) {
|
if (!MSTP_Port) {
|
||||||
@@ -50,8 +50,8 @@ int dlmstp_send_pdu(BACNET_ADDRESS *dest,
|
|||||||
if (!MSTP_Port->UserData) {
|
if (!MSTP_Port->UserData) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
port = MSTP_Port->UserData;
|
user = MSTP_Port->UserData;
|
||||||
pkt = (struct dlmstp_packet *)(void *)Ringbuf_Data_Peek(&port->PDU_Queue);
|
pkt = (struct dlmstp_packet *)(void *)Ringbuf_Data_Peek(&user->PDU_Queue);
|
||||||
if (pkt && (pdu_len <= DLMSTP_MPDU_MAX)) {
|
if (pkt && (pdu_len <= DLMSTP_MPDU_MAX)) {
|
||||||
if (npdu_data->data_expecting_reply) {
|
if (npdu_data->data_expecting_reply) {
|
||||||
pkt->frame_type = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY;
|
pkt->frame_type = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY;
|
||||||
@@ -71,7 +71,7 @@ int dlmstp_send_pdu(BACNET_ADDRESS *dest,
|
|||||||
pkt->address.mac[0] = MSTP_BROADCAST_ADDRESS;
|
pkt->address.mac[0] = MSTP_BROADCAST_ADDRESS;
|
||||||
pkt->address.len = 0;
|
pkt->address.len = 0;
|
||||||
}
|
}
|
||||||
if (Ringbuf_Data_Put(&port->PDU_Queue, (uint8_t *)pkt)) {
|
if (Ringbuf_Data_Put(&user->PDU_Queue, (uint8_t *)pkt)) {
|
||||||
bytes_sent = pdu_len;
|
bytes_sent = pdu_len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -86,30 +86,30 @@ int dlmstp_send_pdu(BACNET_ADDRESS *dest,
|
|||||||
* @return amount of PDU data
|
* @return amount of PDU data
|
||||||
*/
|
*/
|
||||||
uint16_t MSTP_Get_Send(
|
uint16_t MSTP_Get_Send(
|
||||||
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
||||||
{
|
{
|
||||||
uint16_t pdu_len = 0;
|
uint16_t pdu_len = 0;
|
||||||
struct dlmstp_packet *pkt;
|
struct dlmstp_packet *pkt;
|
||||||
struct dlmstp_user_data_t *port;
|
struct dlmstp_user_data_t *user;
|
||||||
|
|
||||||
if (!mstp_port) {
|
if (!mstp_port) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
port = (struct dlmstp_user_data_t *)mstp_port->UserData;
|
user = (struct dlmstp_user_data_t *)mstp_port->UserData;
|
||||||
if (!port) {
|
if (!user) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (Ringbuf_Empty(&port->PDU_Queue)) {
|
if (Ringbuf_Empty(&user->PDU_Queue)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* look at next PDU in queue without removing it */
|
/* look at next PDU in queue without removing it */
|
||||||
pkt = (struct dlmstp_packet *)(void *)Ringbuf_Peek(&port->PDU_Queue);
|
pkt = (struct dlmstp_packet *)(void *)Ringbuf_Peek(&user->PDU_Queue);
|
||||||
/* convert the PDU into the MSTP Frame */
|
/* convert the PDU into the MSTP Frame */
|
||||||
pdu_len = MSTP_Create_Frame(&mstp_port->OutputBuffer[0],
|
pdu_len = MSTP_Create_Frame(&mstp_port->OutputBuffer[0],
|
||||||
mstp_port->OutputBufferSize, pkt->frame_type, pkt->address.mac[0],
|
mstp_port->OutputBufferSize, pkt->frame_type, pkt->address.mac[0],
|
||||||
mstp_port->This_Station, &pkt->pdu[0], pkt->pdu_len);
|
mstp_port->This_Station, &pkt->pdu[0], pkt->pdu_len);
|
||||||
port->Statistics.transmit_pdu_counter++;
|
user->Statistics.transmit_pdu_counter++;
|
||||||
(void)Ringbuf_Pop(&port->PDU_Queue, NULL);
|
(void)Ringbuf_Pop(&user->PDU_Queue, NULL);
|
||||||
|
|
||||||
return pdu_len;
|
return pdu_len;
|
||||||
}
|
}
|
||||||
@@ -148,15 +148,12 @@ static bool MSTP_Compare_Data_Expecting_Reply(
|
|||||||
request_pdu = &mstp_port->InputBuffer[0];
|
request_pdu = &mstp_port->InputBuffer[0];
|
||||||
request_pdu_len = mstp_port->DataLength;
|
request_pdu_len = mstp_port->DataLength;
|
||||||
src_address = mstp_port->SourceAddress;
|
src_address = mstp_port->SourceAddress;
|
||||||
|
|
||||||
/* unused parameters */
|
|
||||||
request_pdu_len = request_pdu_len;
|
|
||||||
reply_pdu_len = reply_pdu_len;
|
|
||||||
/* decode the request data */
|
/* decode the request data */
|
||||||
request.address.mac[0] = src_address;
|
request.address.mac[0] = src_address;
|
||||||
request.address.mac_len = 1;
|
request.address.mac_len = 1;
|
||||||
offset = (uint16_t)npdu_decode(
|
offset = bacnet_npdu_decode(
|
||||||
&request_pdu[0], NULL, &request.address, &request.npdu_data);
|
&request_pdu[0], request_pdu_len, NULL, &request.address,
|
||||||
|
&request.npdu_data);
|
||||||
if (request.npdu_data.network_layer_message) {
|
if (request.npdu_data.network_layer_message) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -172,8 +169,9 @@ static bool MSTP_Compare_Data_Expecting_Reply(
|
|||||||
request.service_choice = request_pdu[offset + 3];
|
request.service_choice = request_pdu[offset + 3];
|
||||||
/* decode the reply data */
|
/* decode the reply data */
|
||||||
bacnet_address_copy(&reply.address, dest_address);
|
bacnet_address_copy(&reply.address, dest_address);
|
||||||
offset = (uint16_t)npdu_decode(
|
offset = bacnet_npdu_decode(
|
||||||
&reply_pdu[0], &reply.address, NULL, &reply.npdu_data);
|
&reply_pdu[0], reply_pdu_len, &reply.address, NULL,
|
||||||
|
&reply.npdu_data);
|
||||||
if (reply.npdu_data.network_layer_message) {
|
if (reply.npdu_data.network_layer_message) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -244,26 +242,26 @@ static bool MSTP_Compare_Data_Expecting_Reply(
|
|||||||
* @return number of bytes, or 0 if no reply is available
|
* @return number of bytes, or 0 if no reply is available
|
||||||
*/
|
*/
|
||||||
uint16_t MSTP_Get_Reply(
|
uint16_t MSTP_Get_Reply(
|
||||||
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
||||||
{
|
{
|
||||||
uint16_t pdu_len = 0;
|
uint16_t pdu_len = 0;
|
||||||
bool matched = false;
|
bool matched = false;
|
||||||
struct dlmstp_packet packet = { 0 };
|
struct dlmstp_packet packet = { 0 };
|
||||||
struct dlmstp_user_data_t *port = NULL;
|
struct dlmstp_user_data_t *user = NULL;
|
||||||
struct dlmstp_packet *pkt;
|
struct dlmstp_packet *pkt;
|
||||||
|
|
||||||
if (!mstp_port) {
|
if (!mstp_port) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
port = mstp_port->UserData;
|
user = mstp_port->UserData;
|
||||||
if (!port) {
|
if (!user) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (Ringbuf_Empty(&port->PDU_Queue)) {
|
if (Ringbuf_Empty(&user->PDU_Queue)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* look at next PDU in queue without removing it */
|
/* look at next PDU in queue without removing it */
|
||||||
pkt = (struct dlmstp_packet *)(void *)Ringbuf_Peek(&port->PDU_Queue);
|
pkt = (struct dlmstp_packet *)(void *)Ringbuf_Peek(&user->PDU_Queue);
|
||||||
/* is this the reply to the DER? */
|
/* is this the reply to the DER? */
|
||||||
matched = MSTP_Compare_Data_Expecting_Reply(
|
matched = MSTP_Compare_Data_Expecting_Reply(
|
||||||
mstp_port, pkt->pdu, pkt->pdu_len, &pkt->address);
|
mstp_port, pkt->pdu, pkt->pdu_len, &pkt->address);
|
||||||
@@ -274,8 +272,8 @@ uint16_t MSTP_Get_Reply(
|
|||||||
pdu_len = MSTP_Create_Frame(&mstp_port->OutputBuffer[0],
|
pdu_len = MSTP_Create_Frame(&mstp_port->OutputBuffer[0],
|
||||||
mstp_port->OutputBufferSize, pkt->frame_type, packet.address.mac[0],
|
mstp_port->OutputBufferSize, pkt->frame_type, packet.address.mac[0],
|
||||||
mstp_port->This_Station, &pkt->pdu[0], pkt->pdu_len);
|
mstp_port->This_Station, &pkt->pdu[0], pkt->pdu_len);
|
||||||
port->Statistics.transmit_pdu_counter++;
|
user->Statistics.transmit_pdu_counter++;
|
||||||
(void)Ringbuf_Pop(&port->PDU_Queue, NULL);
|
(void)Ringbuf_Pop(&user->PDU_Queue, NULL);
|
||||||
|
|
||||||
return pdu_len;
|
return pdu_len;
|
||||||
}
|
}
|
||||||
@@ -286,70 +284,48 @@ uint16_t MSTP_Get_Reply(
|
|||||||
* @param buffer - buffer to send
|
* @param buffer - buffer to send
|
||||||
* @param nbytes - number of bytes of data to send
|
* @param nbytes - number of bytes of data to send
|
||||||
*/
|
*/
|
||||||
void MSTP_Send_Frame(volatile struct mstp_port_struct_t *mstp_port,
|
void MSTP_Send_Frame(struct mstp_port_struct_t *mstp_port,
|
||||||
uint8_t *buffer,
|
uint8_t *buffer,
|
||||||
uint16_t nbytes)
|
uint16_t nbytes)
|
||||||
{
|
{
|
||||||
struct dlmstp_user_data_t *port;
|
struct dlmstp_user_data_t *user;
|
||||||
struct dlmstp_rs485_driver *driver;
|
struct dlmstp_rs485_driver *driver;
|
||||||
|
|
||||||
if (!mstp_port) {
|
if (!mstp_port) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
port = mstp_port->UserData;
|
user = mstp_port->UserData;
|
||||||
if (!port) {
|
if (!user) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
driver = port->RS485_Driver;
|
driver = user->RS485_Driver;
|
||||||
if (!driver) {
|
if (!driver) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
driver->send(buffer, nbytes);
|
driver->send(buffer, nbytes);
|
||||||
port->Statistics.transmit_frame_counter++;
|
user->Statistics.transmit_frame_counter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief MS/TP state machine received a frame
|
* @brief MS/TP state machine received a frame
|
||||||
* @return number of bytes queued, or 0 if unable to be queued
|
* @return number of bytes queued, or 0 if unable to be queued
|
||||||
*/
|
*/
|
||||||
uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port)
|
uint16_t MSTP_Put_Receive(struct mstp_port_struct_t *mstp_port)
|
||||||
{
|
{
|
||||||
struct dlmstp_user_data_t *port = NULL;
|
struct dlmstp_user_data_t *user = NULL;
|
||||||
|
|
||||||
if (!mstp_port) {
|
if (!mstp_port) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
port = mstp_port->UserData;
|
user = mstp_port->UserData;
|
||||||
if (!port) {
|
if (!user) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
port->ReceivePacketPending = true;
|
user->ReceivePacketPending = true;
|
||||||
|
|
||||||
return mstp_port->DataLength;
|
return mstp_port->DataLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Baud rate determines turnaround time.
|
|
||||||
* The minimum time after the end of the stop bit of the final octet of a
|
|
||||||
* received frame before a node may enable its EIA-485 driver: 40 bit times.
|
|
||||||
* At 9600 baud, 40 bit times would be about 4.166 milliseconds
|
|
||||||
* At 19200 baud, 40 bit times would be about 2.083 milliseconds
|
|
||||||
* At 38400 baud, 40 bit times would be about 1.041 milliseconds
|
|
||||||
* At 57600 baud, 40 bit times would be about 0.694 milliseconds
|
|
||||||
* At 76800 baud, 40 bit times would be about 0.520 milliseconds
|
|
||||||
* At 115200 baud, 40 bit times would be about 0.347 milliseconds
|
|
||||||
* 40 bits is 4 octets including a start and stop bit with each octet
|
|
||||||
* @param baud_rate - baud rate in bits per second
|
|
||||||
* @return: amount of whole milliseconds to wait 1..5
|
|
||||||
*/
|
|
||||||
static uint32_t dlmstp_receive_turnaround_time(uint32_t baud_rate)
|
|
||||||
{
|
|
||||||
if (baud_rate == 0) {
|
|
||||||
baud_rate = 9600;
|
|
||||||
}
|
|
||||||
return (1 + ((Tturnaround * 1000) / baud_rate));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Run the MS/TP state machines, and get packet if available
|
* @brief Run the MS/TP state machines, and get packet if available
|
||||||
* @param pdu - place to put PDU data for the caller
|
* @param pdu - place to put PDU data for the caller
|
||||||
@@ -363,11 +339,10 @@ uint16_t dlmstp_receive(
|
|||||||
{
|
{
|
||||||
uint16_t pdu_len = 0;
|
uint16_t pdu_len = 0;
|
||||||
uint8_t data_register = 0;
|
uint8_t data_register = 0;
|
||||||
struct dlmstp_user_data_t *port;
|
struct dlmstp_user_data_t *user;
|
||||||
struct dlmstp_rs485_driver *driver;
|
struct dlmstp_rs485_driver *driver;
|
||||||
uint16_t i;
|
uint16_t i;
|
||||||
uint32_t milliseconds;
|
uint32_t milliseconds;
|
||||||
uint32_t turnaround_milliseconds;
|
|
||||||
|
|
||||||
if (!MSTP_Port) {
|
if (!MSTP_Port) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -375,11 +350,11 @@ uint16_t dlmstp_receive(
|
|||||||
if (!MSTP_Port->UserData) {
|
if (!MSTP_Port->UserData) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
port = MSTP_Port->UserData;
|
user = MSTP_Port->UserData;
|
||||||
if (!port) {
|
if (!user) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
driver = port->RS485_Driver;
|
driver = user->RS485_Driver;
|
||||||
if (!driver) {
|
if (!driver) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -392,7 +367,6 @@ uint16_t dlmstp_receive(
|
|||||||
}
|
}
|
||||||
/* only do receive state machine while we don't have a frame */
|
/* only do receive state machine while we don't have a frame */
|
||||||
while ((MSTP_Port->ReceivedValidFrame == false) &&
|
while ((MSTP_Port->ReceivedValidFrame == false) &&
|
||||||
(MSTP_Port->ReceivedValidFrameNotForUs == false) &&
|
|
||||||
(MSTP_Port->ReceivedInvalidFrame == false)) {
|
(MSTP_Port->ReceivedInvalidFrame == false)) {
|
||||||
MSTP_Port->DataAvailable = driver->read(&data_register);
|
MSTP_Port->DataAvailable = driver->read(&data_register);
|
||||||
if (MSTP_Port->DataAvailable) {
|
if (MSTP_Port->DataAvailable) {
|
||||||
@@ -404,39 +378,35 @@ uint16_t dlmstp_receive(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (MSTP_Port->ReceivedValidFrameNotForUs ||
|
if (MSTP_Port->ReceivedValidFrame || MSTP_Port->ReceivedInvalidFrame) {
|
||||||
MSTP_Port->ReceivedValidFrame || MSTP_Port->ReceivedInvalidFrame) {
|
|
||||||
/* delay after reception before transmitting - per MS/TP spec */
|
/* delay after reception before transmitting - per MS/TP spec */
|
||||||
turnaround_milliseconds =
|
|
||||||
dlmstp_receive_turnaround_time(driver->baud_rate());
|
|
||||||
milliseconds = MSTP_Port->SilenceTimer(MSTP_Port);
|
milliseconds = MSTP_Port->SilenceTimer(MSTP_Port);
|
||||||
if (milliseconds < turnaround_milliseconds) {
|
if (milliseconds < MSTP_Port->Tturnaround_timeout) {
|
||||||
/* we're waiting; do nothing else */
|
/* we're waiting; do nothing else */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (MSTP_Port->ReceivedValidFrameNotForUs) {
|
|
||||||
MSTP_Port->ReceivedValidFrameNotForUs = false;
|
|
||||||
port->Statistics.receive_valid_frame_counter++;
|
|
||||||
}
|
|
||||||
if (MSTP_Port->ReceivedValidFrame) {
|
if (MSTP_Port->ReceivedValidFrame) {
|
||||||
port->Statistics.receive_valid_frame_counter++;
|
user->Statistics.receive_valid_frame_counter++;
|
||||||
}
|
}
|
||||||
if (MSTP_Port->ReceivedInvalidFrame) {
|
if (MSTP_Port->ReceivedInvalidFrame) {
|
||||||
port->Statistics.receive_invalid_frame_counter++;
|
user->Statistics.receive_invalid_frame_counter++;
|
||||||
}
|
}
|
||||||
if (MSTP_Port->receive_state == MSTP_RECEIVE_STATE_IDLE) {
|
if (MSTP_Port->receive_state == MSTP_RECEIVE_STATE_IDLE) {
|
||||||
/* only do master state machine while rx is idle */
|
/* only node state machines while rx is idle */
|
||||||
if (MSTP_Port->This_Station <= DEFAULT_MAX_MASTER) {
|
if (MSTP_Port->SlaveNodeEnabled) {
|
||||||
|
MSTP_Slave_Node_FSM(MSTP_Port);
|
||||||
|
} else if ((MSTP_Port->This_Station <= DEFAULT_MAX_MASTER) ||
|
||||||
|
MSTP_Port->ZeroConfigEnabled) {
|
||||||
while (MSTP_Master_Node_FSM(MSTP_Port)) {
|
while (MSTP_Master_Node_FSM(MSTP_Port)) {
|
||||||
/* do nothing while some states fast transition */
|
/* do nothing while some states fast transition */
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* see if there is a packet available */
|
/* see if there is a packet available */
|
||||||
if (port->ReceivePacketPending) {
|
if (user->ReceivePacketPending) {
|
||||||
port->ReceivePacketPending = false;
|
user->ReceivePacketPending = false;
|
||||||
port->Statistics.receive_pdu_counter++;
|
user->Statistics.receive_pdu_counter++;
|
||||||
pdu_len = MSTP_Port->DataLength;
|
pdu_len = MSTP_Port->DataLength;
|
||||||
if (pdu_len > max_pdu) {
|
if (pdu_len > max_pdu) {
|
||||||
/* PDU is too large */
|
/* PDU is too large */
|
||||||
@@ -498,12 +468,9 @@ void dlmstp_fill_bacnet_address(BACNET_ADDRESS *src, uint8_t mstp_address)
|
|||||||
*/
|
*/
|
||||||
void dlmstp_set_mac_address(uint8_t mac_address)
|
void dlmstp_set_mac_address(uint8_t mac_address)
|
||||||
{
|
{
|
||||||
/* Master Nodes can only have address 0-127 */
|
|
||||||
if (mac_address <= 127) {
|
|
||||||
if (MSTP_Port) {
|
if (MSTP_Port) {
|
||||||
MSTP_Port->This_Station = mac_address;
|
MSTP_Port->This_Station = mac_address;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -648,12 +615,12 @@ void dlmstp_get_broadcast_address(BACNET_ADDRESS *dest)
|
|||||||
bool dlmstp_send_pdu_queue_empty(void)
|
bool dlmstp_send_pdu_queue_empty(void)
|
||||||
{
|
{
|
||||||
bool status = false;
|
bool status = false;
|
||||||
struct dlmstp_user_data_t *port;
|
struct dlmstp_user_data_t *user;
|
||||||
|
|
||||||
if (MSTP_Port) {
|
if (MSTP_Port) {
|
||||||
port = MSTP_Port->UserData;
|
user = MSTP_Port->UserData;
|
||||||
if (port) {
|
if (user) {
|
||||||
status = Ringbuf_Empty(&port->PDU_Queue);
|
status = Ringbuf_Empty(&user->PDU_Queue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -667,12 +634,12 @@ bool dlmstp_send_pdu_queue_empty(void)
|
|||||||
bool dlmstp_send_pdu_queue_full(void)
|
bool dlmstp_send_pdu_queue_full(void)
|
||||||
{
|
{
|
||||||
bool status = false;
|
bool status = false;
|
||||||
struct dlmstp_user_data_t *port;
|
struct dlmstp_user_data_t *user;
|
||||||
|
|
||||||
if (MSTP_Port) {
|
if (MSTP_Port) {
|
||||||
port = MSTP_Port->UserData;
|
user = MSTP_Port->UserData;
|
||||||
if (port) {
|
if (user) {
|
||||||
status = Ringbuf_Full(&port->PDU_Queue);
|
status = Ringbuf_Full(&user->PDU_Queue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -686,7 +653,7 @@ bool dlmstp_send_pdu_queue_full(void)
|
|||||||
*/
|
*/
|
||||||
void dlmstp_set_baud_rate(uint32_t baud)
|
void dlmstp_set_baud_rate(uint32_t baud)
|
||||||
{
|
{
|
||||||
struct dlmstp_user_data_t *port;
|
struct dlmstp_user_data_t *user;
|
||||||
struct dlmstp_rs485_driver *driver;
|
struct dlmstp_rs485_driver *driver;
|
||||||
|
|
||||||
if (!MSTP_Port) {
|
if (!MSTP_Port) {
|
||||||
@@ -695,12 +662,20 @@ void dlmstp_set_baud_rate(uint32_t baud)
|
|||||||
if (!MSTP_Port->UserData) {
|
if (!MSTP_Port->UserData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
port = MSTP_Port->UserData;
|
user = MSTP_Port->UserData;
|
||||||
driver = port->RS485_Driver;
|
driver = user->RS485_Driver;
|
||||||
if (!driver) {
|
if (!driver) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
driver->baud_rate_set(baud);
|
if (driver->baud_rate_set(baud)) {
|
||||||
|
/* Tframe_abort=60 bit times, not to exceed 100 milliseconds.*/
|
||||||
|
if (MSTP_Port->Tframe_abort <= 7) {
|
||||||
|
/* within baud range, so auto-calculate range based on baud */
|
||||||
|
MSTP_Port->Tframe_abort = 1+((60*1000UL)/baud);
|
||||||
|
}
|
||||||
|
/* Tturnaround=40 bit times */
|
||||||
|
MSTP_Port->Tturnaround_timeout = 1 + ((Tturnaround * 1000) / baud);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -709,7 +684,7 @@ void dlmstp_set_baud_rate(uint32_t baud)
|
|||||||
*/
|
*/
|
||||||
uint32_t dlmstp_baud_rate(void)
|
uint32_t dlmstp_baud_rate(void)
|
||||||
{
|
{
|
||||||
struct dlmstp_user_data_t *port;
|
struct dlmstp_user_data_t *user;
|
||||||
struct dlmstp_rs485_driver *driver;
|
struct dlmstp_rs485_driver *driver;
|
||||||
|
|
||||||
if (!MSTP_Port) {
|
if (!MSTP_Port) {
|
||||||
@@ -718,8 +693,8 @@ uint32_t dlmstp_baud_rate(void)
|
|||||||
if (!MSTP_Port->UserData) {
|
if (!MSTP_Port->UserData) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
port = MSTP_Port->UserData;
|
user = MSTP_Port->UserData;
|
||||||
driver = port->RS485_Driver;
|
driver = user->RS485_Driver;
|
||||||
if (!driver) {
|
if (!driver) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -733,7 +708,7 @@ uint32_t dlmstp_baud_rate(void)
|
|||||||
*/
|
*/
|
||||||
void dlmstp_fill_statistics(struct dlmstp_statistics *statistics)
|
void dlmstp_fill_statistics(struct dlmstp_statistics *statistics)
|
||||||
{
|
{
|
||||||
struct dlmstp_user_data_t *port;
|
struct dlmstp_user_data_t *user;
|
||||||
|
|
||||||
if (!MSTP_Port) {
|
if (!MSTP_Port) {
|
||||||
return;
|
return;
|
||||||
@@ -741,12 +716,12 @@ void dlmstp_fill_statistics(struct dlmstp_statistics *statistics)
|
|||||||
if (!MSTP_Port->UserData) {
|
if (!MSTP_Port->UserData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
port = MSTP_Port->UserData;
|
user = MSTP_Port->UserData;
|
||||||
if (!port) {
|
if (!user) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (statistics) {
|
if (statistics) {
|
||||||
*statistics = port->Statistics;
|
*statistics = user->Statistics;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -821,18 +796,18 @@ void dlmstp_silence_reset(void *arg)
|
|||||||
*/
|
*/
|
||||||
bool dlmstp_init(char *ifname)
|
bool dlmstp_init(char *ifname)
|
||||||
{
|
{
|
||||||
struct dlmstp_user_data_t *user_data;
|
struct dlmstp_user_data_t *user;
|
||||||
MSTP_Port = (struct mstp_port_struct_t *)ifname;
|
MSTP_Port = (struct mstp_port_struct_t *)ifname;
|
||||||
if (MSTP_Port) {
|
if (MSTP_Port) {
|
||||||
MSTP_Port->SilenceTimer = dlmstp_silence_milliseconds;
|
MSTP_Port->SilenceTimer = dlmstp_silence_milliseconds;
|
||||||
MSTP_Port->SilenceTimerReset = dlmstp_silence_reset;
|
MSTP_Port->SilenceTimerReset = dlmstp_silence_reset;
|
||||||
user_data = (struct dlmstp_user_data_t *)MSTP_Port->UserData;
|
user = (struct dlmstp_user_data_t *)MSTP_Port->UserData;
|
||||||
if (user_data && !user_data->Initialized) {
|
if (user && !user->Initialized) {
|
||||||
Ringbuf_Init(&user_data->PDU_Queue,
|
Ringbuf_Init(&user->PDU_Queue,
|
||||||
(volatile uint8_t *)user_data->PDU_Buffer,
|
(volatile uint8_t *)user->PDU_Buffer,
|
||||||
sizeof(user_data->PDU_Buffer), DLMSTP_MAX_INFO_FRAMES);
|
sizeof(user->PDU_Buffer), DLMSTP_MAX_INFO_FRAMES);
|
||||||
MSTP_Init(MSTP_Port);
|
MSTP_Init(MSTP_Port);
|
||||||
user_data->Initialized = true;
|
user->Initialized = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+462
-149
@@ -48,12 +48,15 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#if PRINT_ENABLED
|
#if PRINT_ENABLED
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#endif
|
#endif
|
||||||
#include "bacnet/datalink/cobs.h"
|
#include "bacnet/datalink/cobs.h"
|
||||||
#include "bacnet/datalink/crc.h"
|
#include "bacnet/datalink/crc.h"
|
||||||
#include "bacnet/datalink/mstp.h"
|
#include "bacnet/datalink/mstp.h"
|
||||||
|
#include "bacnet/datalink/crc.h"
|
||||||
#include "bacnet/datalink/mstptext.h"
|
#include "bacnet/datalink/mstptext.h"
|
||||||
#include "bacnet/npdu.h"
|
#include "bacnet/npdu.h"
|
||||||
|
|
||||||
@@ -119,50 +122,6 @@ static inline void printf_master(const char *format, ...)
|
|||||||
/* least significant octet first */
|
/* least significant octet first */
|
||||||
/* (pad): (optional) at most one octet of padding: X'FF' */
|
/* (pad): (optional) at most one octet of padding: X'FF' */
|
||||||
|
|
||||||
/* 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
|
|
||||||
|
|
||||||
/* 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.) */
|
|
||||||
/* At 9600 baud, 60 bit times would be about 6.25 milliseconds */
|
|
||||||
/* const uint16_t Tframe_abort = 1 + ((1000 * 60) / 9600); */
|
|
||||||
#ifndef Tframe_abort
|
|
||||||
#define Tframe_abort 95
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* 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. */
|
|
||||||
#ifndef Treply_delay
|
|
||||||
#define Treply_delay 250
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* 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
|
|
||||||
|
|
||||||
/* 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.) */
|
|
||||||
#ifndef Treply_timeout
|
|
||||||
#define Treply_timeout 295
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* The 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.) */
|
|
||||||
#ifndef Tusage_timeout
|
|
||||||
#define Tusage_timeout 30
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* we need to be able to increment without rolling over */
|
/* we need to be able to increment without rolling over */
|
||||||
#define INCREMENT_AND_LIMIT_UINT8(x) \
|
#define INCREMENT_AND_LIMIT_UINT8(x) \
|
||||||
{ \
|
{ \
|
||||||
@@ -170,8 +129,12 @@ static inline void printf_master(const char *format, ...)
|
|||||||
x++; \
|
x++; \
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MSTP_Line_Active(volatile struct mstp_port_struct_t *mstp_port)
|
bool MSTP_Line_Active(struct mstp_port_struct_t *mstp_port)
|
||||||
{
|
{
|
||||||
|
if (!mstp_port) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return (mstp_port->EventCount > Nmin_octets);
|
return (mstp_port->EventCount > Nmin_octets);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,6 +142,9 @@ void MSTP_Fill_BACnet_Address(BACNET_ADDRESS *src, uint8_t mstp_address)
|
|||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
|
if (!src) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (mstp_address == MSTP_BROADCAST_ADDRESS) {
|
if (mstp_address == MSTP_BROADCAST_ADDRESS) {
|
||||||
/* mac_len = 0 if broadcast address */
|
/* mac_len = 0 if broadcast address */
|
||||||
src->mac_len = 0;
|
src->mac_len = 0;
|
||||||
@@ -219,7 +185,7 @@ void MSTP_Fill_BACnet_Address(BACNET_ADDRESS *src, uint8_t mstp_address)
|
|||||||
* @param destination - destination address
|
* @param destination - destination address
|
||||||
* @param source - source address
|
* @param source - source address
|
||||||
* @param data - any data to be sent - may be null
|
* @param data - any data to be sent - may be null
|
||||||
* @param data_len - number of bytes of data (up to 501)
|
* @param data_len - number of bytes of data
|
||||||
* @return number of bytes encoded, or 0 on error
|
* @return number of bytes encoded, or 0 on error
|
||||||
*/
|
*/
|
||||||
uint16_t MSTP_Create_Frame(uint8_t *buffer,
|
uint16_t MSTP_Create_Frame(uint8_t *buffer,
|
||||||
@@ -237,9 +203,7 @@ uint16_t MSTP_Create_Frame(uint8_t *buffer,
|
|||||||
bool cobs_bacnet_frame = false; /* true for COBS BACnet frames */
|
bool cobs_bacnet_frame = false; /* true for COBS BACnet frames */
|
||||||
|
|
||||||
/* not enough to do a header */
|
/* not enough to do a header */
|
||||||
if (buffer_size < 8) {
|
if (buffer && (buffer_size >= 8)) {
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
buffer[0] = 0x55;
|
buffer[0] = 0x55;
|
||||||
buffer[1] = 0xFF;
|
buffer[1] = 0xFF;
|
||||||
buffer[2] = frame_type;
|
buffer[2] = frame_type;
|
||||||
@@ -253,10 +217,11 @@ uint16_t MSTP_Create_Frame(uint8_t *buffer,
|
|||||||
buffer[6] = data_len & 0xFF;
|
buffer[6] = data_len & 0xFF;
|
||||||
crc8 = CRC_Calc_Header(buffer[6], crc8);
|
crc8 = CRC_Calc_Header(buffer[6], crc8);
|
||||||
buffer[7] = ~crc8;
|
buffer[7] = ~crc8;
|
||||||
|
}
|
||||||
index = 8;
|
index = 8;
|
||||||
|
|
||||||
if ((data_len > 501) || ((frame_type >= Nmin_COBS_type) &&
|
if ((data_len > MSTP_FRAME_NPDU_MAX) ||
|
||||||
(frame_type <= Nmax_COBS_type))) {
|
((frame_type >= Nmin_COBS_type) && (frame_type <= Nmax_COBS_type))) {
|
||||||
/* COBS encoded frame */
|
/* COBS encoded frame */
|
||||||
if (frame_type == FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY) {
|
if (frame_type == FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY) {
|
||||||
frame_type = FRAME_TYPE_BACNET_EXTENDED_DATA_EXPECTING_REPLY;
|
frame_type = FRAME_TYPE_BACNET_EXTENDED_DATA_EXPECTING_REPLY;
|
||||||
@@ -291,8 +256,10 @@ uint16_t MSTP_Create_Frame(uint8_t *buffer,
|
|||||||
index = index + cobs_len - 2;
|
index = index + cobs_len - 2;
|
||||||
} else if (data_len > 0) {
|
} else if (data_len > 0) {
|
||||||
while (data_len && data && (index < buffer_size)) {
|
while (data_len && data && (index < buffer_size)) {
|
||||||
|
if (buffer) {
|
||||||
buffer[index] = *data;
|
buffer[index] = *data;
|
||||||
crc16 = CRC_Calc_Data(buffer[index], crc16);
|
crc16 = CRC_Calc_Data(buffer[index], crc16);
|
||||||
|
}
|
||||||
data++;
|
data++;
|
||||||
index++;
|
index++;
|
||||||
data_len--;
|
data_len--;
|
||||||
@@ -301,9 +268,13 @@ uint16_t MSTP_Create_Frame(uint8_t *buffer,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
crc16 = ~crc16;
|
crc16 = ~crc16;
|
||||||
|
if (buffer) {
|
||||||
buffer[index] = crc16 & 0xFF; /* LSB first */
|
buffer[index] = crc16 & 0xFF; /* LSB first */
|
||||||
|
}
|
||||||
index++;
|
index++;
|
||||||
|
if (buffer) {
|
||||||
buffer[index] = crc16 >> 8;
|
buffer[index] = crc16 >> 8;
|
||||||
|
}
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,10 +288,9 @@ uint16_t MSTP_Create_Frame(uint8_t *buffer,
|
|||||||
* @param destination - destination address
|
* @param destination - destination address
|
||||||
* @param source - source address
|
* @param source - source address
|
||||||
* @param data - any data to be sent - may be null
|
* @param data - any data to be sent - may be null
|
||||||
* @param data_len - number of bytes of data (up to 501)
|
* @param data_len - number of bytes of data
|
||||||
*/
|
*/
|
||||||
void MSTP_Create_And_Send_Frame(
|
void MSTP_Create_And_Send_Frame(struct mstp_port_struct_t *mstp_port,
|
||||||
volatile struct mstp_port_struct_t *mstp_port,
|
|
||||||
uint8_t frame_type,
|
uint8_t frame_type,
|
||||||
uint8_t destination,
|
uint8_t destination,
|
||||||
uint8_t source,
|
uint8_t source,
|
||||||
@@ -329,17 +299,22 @@ void MSTP_Create_And_Send_Frame(
|
|||||||
{
|
{
|
||||||
uint16_t len = 0; /* number of bytes to send */
|
uint16_t len = 0; /* number of bytes to send */
|
||||||
|
|
||||||
len = MSTP_Create_Frame((uint8_t *)&mstp_port->OutputBuffer[0],
|
len =
|
||||||
mstp_port->OutputBufferSize, frame_type, destination, source, data,
|
MSTP_Create_Frame(mstp_port->OutputBuffer, mstp_port->OutputBufferSize,
|
||||||
data_len);
|
frame_type, destination, source, data, data_len);
|
||||||
|
|
||||||
MSTP_Send_Frame(mstp_port, (uint8_t *)&mstp_port->OutputBuffer[0], len);
|
MSTP_Send_Frame(mstp_port, (uint8_t *)&mstp_port->OutputBuffer[0], len);
|
||||||
/* FIXME: be sure to reset SilenceTimer() after each octet is sent! */
|
/* FIXME: be sure to reset SilenceTimer() after each octet is sent! */
|
||||||
}
|
}
|
||||||
|
|
||||||
void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port)
|
/**
|
||||||
|
* @brief Finite State Machine for receiving an MSTP frame
|
||||||
|
* @param mstp_port MSTP port context data
|
||||||
|
*/
|
||||||
|
void MSTP_Receive_Frame_FSM(struct mstp_port_struct_t *mstp_port)
|
||||||
{
|
{
|
||||||
MSTP_RECEIVE_STATE receive_state = mstp_port->receive_state;
|
MSTP_RECEIVE_STATE receive_state = mstp_port->receive_state;
|
||||||
|
|
||||||
printf_receive(
|
printf_receive(
|
||||||
"MSTP Rx: State=%s Data=%02X hCRC=%02X Index=%u EC=%u DateLen=%u "
|
"MSTP Rx: State=%s Data=%02X hCRC=%02X Index=%u EC=%u DateLen=%u "
|
||||||
"Silence=%u\n",
|
"Silence=%u\n",
|
||||||
@@ -348,24 +323,23 @@ void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
mstp_port->EventCount, mstp_port->DataLength,
|
mstp_port->EventCount, mstp_port->DataLength,
|
||||||
mstp_port->SilenceTimer((void *)mstp_port));
|
mstp_port->SilenceTimer((void *)mstp_port));
|
||||||
switch (mstp_port->receive_state) {
|
switch (mstp_port->receive_state) {
|
||||||
/* In the IDLE state, the node waits for the beginning of a frame.
|
|
||||||
*/
|
|
||||||
case MSTP_RECEIVE_STATE_IDLE:
|
case MSTP_RECEIVE_STATE_IDLE:
|
||||||
|
/* In the IDLE state, the node waits for
|
||||||
|
the beginning of a frame. */
|
||||||
/* EatAnError */
|
/* EatAnError */
|
||||||
if (mstp_port->ReceiveError == true) {
|
if (mstp_port->ReceiveError == true) {
|
||||||
mstp_port->ReceiveError = false;
|
mstp_port->ReceiveError = false;
|
||||||
mstp_port->SilenceTimerReset((void *)mstp_port);
|
mstp_port->SilenceTimerReset((void *)mstp_port);
|
||||||
INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount);
|
INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount);
|
||||||
/* wait for the start of a frame. */
|
|
||||||
} else if (mstp_port->DataAvailable == true) {
|
} else if (mstp_port->DataAvailable == true) {
|
||||||
|
/* wait for the start of a frame. */
|
||||||
printf_receive_data("MSTP Rx: %02X ", mstp_port->DataRegister);
|
printf_receive_data("MSTP Rx: %02X ", mstp_port->DataRegister);
|
||||||
/* Preamble1 */
|
|
||||||
if (mstp_port->DataRegister == 0x55) {
|
if (mstp_port->DataRegister == 0x55) {
|
||||||
|
/* Preamble1 */
|
||||||
/* receive the remainder of the frame. */
|
/* receive the remainder of the frame. */
|
||||||
mstp_port->receive_state = MSTP_RECEIVE_STATE_PREAMBLE;
|
mstp_port->receive_state = MSTP_RECEIVE_STATE_PREAMBLE;
|
||||||
}
|
} else {
|
||||||
/* EatAnOctet */
|
/* EatAnOctet */
|
||||||
else {
|
|
||||||
printf_receive_data("\n");
|
printf_receive_data("\n");
|
||||||
/* wait for the start of a frame. */
|
/* wait for the start of a frame. */
|
||||||
}
|
}
|
||||||
@@ -374,17 +348,17 @@ void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount);
|
INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
/* In the PREAMBLE state, the node waits for the second octet of the
|
|
||||||
* preamble. */
|
|
||||||
case MSTP_RECEIVE_STATE_PREAMBLE:
|
case MSTP_RECEIVE_STATE_PREAMBLE:
|
||||||
|
/* In the PREAMBLE state, the node waits for
|
||||||
|
the second octet of the preamble. */
|
||||||
/* Timeout */
|
/* Timeout */
|
||||||
if (mstp_port->SilenceTimer((void *)mstp_port) > Tframe_abort) {
|
if (mstp_port->SilenceTimer((void *)mstp_port) >
|
||||||
|
mstp_port->Tframe_abort) {
|
||||||
/* a correct preamble has not been received */
|
/* a correct preamble has not been received */
|
||||||
/* wait for the start of a frame. */
|
/* wait for the start of a frame. */
|
||||||
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
|
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
|
||||||
}
|
} else if (mstp_port->ReceiveError == true) {
|
||||||
/* Error */
|
/* Error */
|
||||||
else if (mstp_port->ReceiveError == true) {
|
|
||||||
mstp_port->ReceiveError = false;
|
mstp_port->ReceiveError = false;
|
||||||
mstp_port->SilenceTimerReset((void *)mstp_port);
|
mstp_port->SilenceTimerReset((void *)mstp_port);
|
||||||
INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount);
|
INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount);
|
||||||
@@ -392,19 +366,17 @@ void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
|
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
|
||||||
} else if (mstp_port->DataAvailable == true) {
|
} else if (mstp_port->DataAvailable == true) {
|
||||||
printf_receive_data("%02X ", mstp_port->DataRegister);
|
printf_receive_data("%02X ", mstp_port->DataRegister);
|
||||||
/* Preamble2 */
|
|
||||||
if (mstp_port->DataRegister == 0xFF) {
|
if (mstp_port->DataRegister == 0xFF) {
|
||||||
|
/* Preamble2 */
|
||||||
mstp_port->Index = 0;
|
mstp_port->Index = 0;
|
||||||
mstp_port->HeaderCRC = 0xFF;
|
mstp_port->HeaderCRC = 0xFF;
|
||||||
/* receive the remainder of the frame. */
|
/* receive the remainder of the frame. */
|
||||||
mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER;
|
mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER;
|
||||||
}
|
} else if (mstp_port->DataRegister == 0x55) {
|
||||||
/* ignore RepeatedPreamble1 */
|
/* ignore RepeatedPreamble1 */
|
||||||
else if (mstp_port->DataRegister == 0x55) {
|
|
||||||
/* wait for the second preamble octet. */
|
/* wait for the second preamble octet. */
|
||||||
}
|
} else {
|
||||||
/* NotPreamble */
|
/* NotPreamble */
|
||||||
else {
|
|
||||||
/* wait for the start of a frame. */
|
/* wait for the start of a frame. */
|
||||||
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
|
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
|
||||||
}
|
}
|
||||||
@@ -413,11 +385,12 @@ void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount);
|
INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
/* In the HEADER state, the node waits for the fixed message header.
|
|
||||||
*/
|
|
||||||
case MSTP_RECEIVE_STATE_HEADER:
|
case MSTP_RECEIVE_STATE_HEADER:
|
||||||
|
/* In the HEADER state, the node waits for
|
||||||
|
the fixed message header. */
|
||||||
/* Timeout */
|
/* Timeout */
|
||||||
if (mstp_port->SilenceTimer((void *)mstp_port) > Tframe_abort) {
|
if (mstp_port->SilenceTimer((void *)mstp_port) >
|
||||||
|
mstp_port->Tframe_abort) {
|
||||||
/* indicate that an error has occurred during the reception of a
|
/* indicate that an error has occurred during the reception of a
|
||||||
* frame */
|
* frame */
|
||||||
mstp_port->ReceivedInvalidFrame = true;
|
mstp_port->ReceivedInvalidFrame = true;
|
||||||
@@ -425,10 +398,9 @@ void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
|
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
|
||||||
printf_receive_error("MSTP: Rx Header: SilenceTimer %u > %d\n",
|
printf_receive_error("MSTP: Rx Header: SilenceTimer %u > %d\n",
|
||||||
(unsigned)mstp_port->SilenceTimer((void *)mstp_port),
|
(unsigned)mstp_port->SilenceTimer((void *)mstp_port),
|
||||||
Tframe_abort);
|
mstp_port->Tframe_abort);
|
||||||
}
|
} else if (mstp_port->ReceiveError == true) {
|
||||||
/* Error */
|
/* Error */
|
||||||
else if (mstp_port->ReceiveError == true) {
|
|
||||||
mstp_port->ReceiveError = false;
|
mstp_port->ReceiveError = false;
|
||||||
mstp_port->SilenceTimerReset((void *)mstp_port);
|
mstp_port->SilenceTimerReset((void *)mstp_port);
|
||||||
INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount);
|
INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount);
|
||||||
@@ -440,43 +412,38 @@ void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
|
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
|
||||||
} else if (mstp_port->DataAvailable == true) {
|
} else if (mstp_port->DataAvailable == true) {
|
||||||
printf_receive_data("%02X ", mstp_port->DataRegister);
|
printf_receive_data("%02X ", mstp_port->DataRegister);
|
||||||
/* FrameType */
|
|
||||||
if (mstp_port->Index == 0) {
|
if (mstp_port->Index == 0) {
|
||||||
|
/* FrameType */
|
||||||
mstp_port->HeaderCRC = CRC_Calc_Header(
|
mstp_port->HeaderCRC = CRC_Calc_Header(
|
||||||
mstp_port->DataRegister, mstp_port->HeaderCRC);
|
mstp_port->DataRegister, mstp_port->HeaderCRC);
|
||||||
mstp_port->FrameType = mstp_port->DataRegister;
|
mstp_port->FrameType = mstp_port->DataRegister;
|
||||||
mstp_port->Index = 1;
|
mstp_port->Index = 1;
|
||||||
}
|
} else if (mstp_port->Index == 1) {
|
||||||
/* Destination */
|
/* Destination */
|
||||||
else if (mstp_port->Index == 1) {
|
|
||||||
mstp_port->HeaderCRC = CRC_Calc_Header(
|
mstp_port->HeaderCRC = CRC_Calc_Header(
|
||||||
mstp_port->DataRegister, mstp_port->HeaderCRC);
|
mstp_port->DataRegister, mstp_port->HeaderCRC);
|
||||||
mstp_port->DestinationAddress = mstp_port->DataRegister;
|
mstp_port->DestinationAddress = mstp_port->DataRegister;
|
||||||
mstp_port->Index = 2;
|
mstp_port->Index = 2;
|
||||||
}
|
} else if (mstp_port->Index == 2) {
|
||||||
/* Source */
|
/* Source */
|
||||||
else if (mstp_port->Index == 2) {
|
|
||||||
mstp_port->HeaderCRC = CRC_Calc_Header(
|
mstp_port->HeaderCRC = CRC_Calc_Header(
|
||||||
mstp_port->DataRegister, mstp_port->HeaderCRC);
|
mstp_port->DataRegister, mstp_port->HeaderCRC);
|
||||||
mstp_port->SourceAddress = mstp_port->DataRegister;
|
mstp_port->SourceAddress = mstp_port->DataRegister;
|
||||||
mstp_port->Index = 3;
|
mstp_port->Index = 3;
|
||||||
}
|
} else if (mstp_port->Index == 3) {
|
||||||
/* Length1 */
|
/* Length1 */
|
||||||
else if (mstp_port->Index == 3) {
|
|
||||||
mstp_port->HeaderCRC = CRC_Calc_Header(
|
mstp_port->HeaderCRC = CRC_Calc_Header(
|
||||||
mstp_port->DataRegister, mstp_port->HeaderCRC);
|
mstp_port->DataRegister, mstp_port->HeaderCRC);
|
||||||
mstp_port->DataLength = mstp_port->DataRegister * 256;
|
mstp_port->DataLength = mstp_port->DataRegister * 256;
|
||||||
mstp_port->Index = 4;
|
mstp_port->Index = 4;
|
||||||
}
|
} else if (mstp_port->Index == 4) {
|
||||||
/* Length2 */
|
/* Length2 */
|
||||||
else if (mstp_port->Index == 4) {
|
|
||||||
mstp_port->HeaderCRC = CRC_Calc_Header(
|
mstp_port->HeaderCRC = CRC_Calc_Header(
|
||||||
mstp_port->DataRegister, mstp_port->HeaderCRC);
|
mstp_port->DataRegister, mstp_port->HeaderCRC);
|
||||||
mstp_port->DataLength += mstp_port->DataRegister;
|
mstp_port->DataLength += mstp_port->DataRegister;
|
||||||
mstp_port->Index = 5;
|
mstp_port->Index = 5;
|
||||||
}
|
} else if (mstp_port->Index == 5) {
|
||||||
/* HeaderCRC */
|
/* HeaderCRC */
|
||||||
else if (mstp_port->Index == 5) {
|
|
||||||
mstp_port->HeaderCRC = CRC_Calc_Header(
|
mstp_port->HeaderCRC = CRC_Calc_Header(
|
||||||
mstp_port->DataRegister, mstp_port->HeaderCRC);
|
mstp_port->DataRegister, mstp_port->HeaderCRC);
|
||||||
mstp_port->HeaderCRCActual = mstp_port->DataRegister;
|
mstp_port->HeaderCRCActual = mstp_port->DataRegister;
|
||||||
@@ -496,18 +463,9 @@ void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
printf_receive_data("%s",
|
printf_receive_data("%s",
|
||||||
mstptext_frame_type(
|
mstptext_frame_type(
|
||||||
(unsigned)mstp_port->FrameType));
|
(unsigned)mstp_port->FrameType));
|
||||||
if ((mstp_port->DestinationAddress ==
|
|
||||||
mstp_port->This_Station) ||
|
|
||||||
(mstp_port->DestinationAddress ==
|
|
||||||
MSTP_BROADCAST_ADDRESS)) {
|
|
||||||
/* ForUs */
|
|
||||||
/* indicate that a frame with no data has been
|
/* indicate that a frame with no data has been
|
||||||
* received */
|
* received */
|
||||||
mstp_port->ReceivedValidFrame = true;
|
mstp_port->ReceivedValidFrame = true;
|
||||||
} else {
|
|
||||||
/* NotForUs */
|
|
||||||
mstp_port->ReceivedValidFrameNotForUs = true;
|
|
||||||
}
|
|
||||||
/* wait for the start of the next frame. */
|
/* wait for the start of the next frame. */
|
||||||
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
|
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
|
||||||
} else {
|
} else {
|
||||||
@@ -538,9 +496,8 @@ void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
mstp_port->DataCRC = 0xFFFF;
|
mstp_port->DataCRC = 0xFFFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
/* not per MS/TP standard, but it is a case not covered */
|
/* not per MS/TP standard, but it is a case not covered */
|
||||||
else {
|
|
||||||
mstp_port->ReceiveError = false;
|
mstp_port->ReceiveError = false;
|
||||||
/* indicate that an error has occurred during */
|
/* indicate that an error has occurred during */
|
||||||
/* the reception of a frame */
|
/* the reception of a frame */
|
||||||
@@ -555,24 +512,24 @@ void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
mstp_port->DataAvailable = false;
|
mstp_port->DataAvailable = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
/* In the DATA state, the node waits for the data portion of a
|
|
||||||
* frame. */
|
|
||||||
case MSTP_RECEIVE_STATE_DATA:
|
case MSTP_RECEIVE_STATE_DATA:
|
||||||
case MSTP_RECEIVE_STATE_SKIP_DATA:
|
case MSTP_RECEIVE_STATE_SKIP_DATA:
|
||||||
|
/* In the DATA and SKIP DATA states, the node waits for the
|
||||||
|
data portion of a frame. */
|
||||||
|
if (mstp_port->SilenceTimer((void *)mstp_port) >
|
||||||
|
mstp_port->Tframe_abort) {
|
||||||
/* Timeout */
|
/* Timeout */
|
||||||
if (mstp_port->SilenceTimer((void *)mstp_port) > Tframe_abort) {
|
|
||||||
/* indicate that an error has occurred during the reception of a
|
/* indicate that an error has occurred during the reception of a
|
||||||
* frame */
|
* frame */
|
||||||
mstp_port->ReceivedInvalidFrame = true;
|
mstp_port->ReceivedInvalidFrame = true;
|
||||||
printf_receive_error(
|
printf_receive_error(
|
||||||
"MSTP: Rx Data: SilenceTimer %ums > %dms\n",
|
"MSTP: Rx Data: SilenceTimer %ums > %dms\n",
|
||||||
(unsigned)mstp_port->SilenceTimer((void *)mstp_port),
|
(unsigned)mstp_port->SilenceTimer((void *)mstp_port),
|
||||||
Tframe_abort);
|
mstp_port->Tframe_abort);
|
||||||
/* wait for the start of the next frame. */
|
/* wait for the start of the next frame. */
|
||||||
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
|
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
|
||||||
}
|
} else if (mstp_port->ReceiveError == true) {
|
||||||
/* Error */
|
/* Error */
|
||||||
else if (mstp_port->ReceiveError == true) {
|
|
||||||
mstp_port->ReceiveError = false;
|
mstp_port->ReceiveError = false;
|
||||||
mstp_port->SilenceTimerReset((void *)mstp_port);
|
mstp_port->SilenceTimerReset((void *)mstp_port);
|
||||||
/* indicate that an error has occurred during the reception of a
|
/* indicate that an error has occurred during the reception of a
|
||||||
@@ -615,36 +572,23 @@ void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
mstp_port->DataCRCActualLSB = mstp_port->DataRegister;
|
mstp_port->DataCRCActualLSB = mstp_port->DataRegister;
|
||||||
printf_receive_data("%s",
|
printf_receive_data("%s",
|
||||||
mstptext_frame_type((unsigned)mstp_port->FrameType));
|
mstptext_frame_type((unsigned)mstp_port->FrameType));
|
||||||
if (((mstp_port->Index+1) < mstp_port->InputBufferSize) &&
|
if (((mstp_port->Index + 1) < mstp_port->InputBufferSize) &&
|
||||||
(mstp_port->FrameType >= Nmin_COBS_type) &&
|
(mstp_port->FrameType >= Nmin_COBS_type) &&
|
||||||
(mstp_port->FrameType <= Nmax_COBS_type)) {
|
(mstp_port->FrameType <= Nmax_COBS_type)) {
|
||||||
if (cobs_frame_decode(
|
if (cobs_frame_decode(
|
||||||
&mstp_port->InputBuffer[mstp_port->Index + 1],
|
&mstp_port->InputBuffer[mstp_port->Index + 1],
|
||||||
mstp_port->InputBufferSize,
|
mstp_port->InputBufferSize,
|
||||||
mstp_port->InputBuffer, mstp_port->Index + 1)) {
|
mstp_port->InputBuffer, mstp_port->Index + 1)) {
|
||||||
if (mstp_port->receive_state ==
|
|
||||||
MSTP_RECEIVE_STATE_DATA) {
|
|
||||||
/* ForUs */
|
|
||||||
mstp_port->ReceivedValidFrame = true;
|
mstp_port->ReceivedValidFrame = true;
|
||||||
} else {
|
|
||||||
/* NotForUs */
|
|
||||||
mstp_port->ReceivedValidFrameNotForUs = true;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
mstp_port->ReceivedInvalidFrame = true;
|
mstp_port->ReceivedInvalidFrame = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* STATE DATA CRC - no need for new state */
|
/* STATE DATA CRC - no need for new state */
|
||||||
/* indicate the complete reception of a valid frame */
|
|
||||||
if (mstp_port->DataCRC == 0xF0B8) {
|
if (mstp_port->DataCRC == 0xF0B8) {
|
||||||
if (mstp_port->receive_state ==
|
/* indicate the complete reception of a
|
||||||
MSTP_RECEIVE_STATE_DATA) {
|
valid frame */
|
||||||
/* ForUs */
|
|
||||||
mstp_port->ReceivedValidFrame = true;
|
mstp_port->ReceivedValidFrame = true;
|
||||||
} else {
|
|
||||||
/* NotForUs */
|
|
||||||
mstp_port->ReceivedValidFrameNotForUs = true;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
mstp_port->ReceivedInvalidFrame = true;
|
mstp_port->ReceivedInvalidFrame = true;
|
||||||
printf_receive_error(
|
printf_receive_error(
|
||||||
@@ -674,8 +618,12 @@ void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns true if we need to transition immediately */
|
/**
|
||||||
bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port)
|
* @brief Finite State Machine for receiving an MSTP frame
|
||||||
|
* @param mstp_port MSTP port context data
|
||||||
|
* @return true if we need to transition immediately
|
||||||
|
*/
|
||||||
|
bool MSTP_Master_Node_FSM(struct mstp_port_struct_t *mstp_port)
|
||||||
{
|
{
|
||||||
unsigned length = 0;
|
unsigned length = 0;
|
||||||
uint8_t next_poll_station = 0;
|
uint8_t next_poll_station = 0;
|
||||||
@@ -695,6 +643,23 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
(mstp_port->Next_Station + 1) % (mstp_port->Nmax_master + 1);
|
(mstp_port->Next_Station + 1) % (mstp_port->Nmax_master + 1);
|
||||||
switch (mstp_port->master_state) {
|
switch (mstp_port->master_state) {
|
||||||
case MSTP_MASTER_STATE_INITIALIZE:
|
case MSTP_MASTER_STATE_INITIALIZE:
|
||||||
|
if (mstp_port->ZeroConfigEnabled) {
|
||||||
|
MSTP_Zero_Config_FSM(mstp_port);
|
||||||
|
if (mstp_port->This_Station != 255) {
|
||||||
|
/* indicate that the next station is unknown */
|
||||||
|
mstp_port->Next_Station = mstp_port->This_Station;
|
||||||
|
mstp_port->Poll_Station = (mstp_port->Next_Station + 1) %
|
||||||
|
(mstp_port->Zero_Config_Max_Master + 1);
|
||||||
|
mstp_port->TokenCount = Npoll;
|
||||||
|
mstp_port->EventCount = 0;
|
||||||
|
mstp_port->SoleMaster = true;
|
||||||
|
MSTP_Create_And_Send_Frame(mstp_port,
|
||||||
|
FRAME_TYPE_POLL_FOR_MASTER, mstp_port->Poll_Station,
|
||||||
|
mstp_port->This_Station, NULL, 0);
|
||||||
|
mstp_port->master_state = MSTP_MASTER_STATE_POLL_FOR_MASTER;
|
||||||
|
transition_now = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
/* DoneInitializing */
|
/* DoneInitializing */
|
||||||
/* indicate that the next station is unknown */
|
/* indicate that the next station is unknown */
|
||||||
mstp_port->Next_Station = mstp_port->This_Station;
|
mstp_port->Next_Station = mstp_port->This_Station;
|
||||||
@@ -705,6 +670,7 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
mstp_port->SoleMaster = false;
|
mstp_port->SoleMaster = false;
|
||||||
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
|
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
|
||||||
transition_now = true;
|
transition_now = true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case MSTP_MASTER_STATE_IDLE:
|
case MSTP_MASTER_STATE_IDLE:
|
||||||
/* In the IDLE state, the node waits for a frame. */
|
/* In the IDLE state, the node waits for a frame. */
|
||||||
@@ -721,7 +687,16 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
mstp_port->DataLength, mstp_port->FrameCount,
|
mstp_port->DataLength, mstp_port->FrameCount,
|
||||||
mstp_port->SilenceTimer((void *)mstp_port),
|
mstp_port->SilenceTimer((void *)mstp_port),
|
||||||
mstptext_frame_type((unsigned)mstp_port->FrameType));
|
mstptext_frame_type((unsigned)mstp_port->FrameType));
|
||||||
if ((mstp_port->DestinationAddress ==
|
if (mstp_port->SourceAddress == mstp_port->This_Station) {
|
||||||
|
/* DuplicateNode */
|
||||||
|
if (mstp_port->ZeroConfigEnabled) {
|
||||||
|
/* we are a zero config node - start over */
|
||||||
|
mstp_port->Zero_Config_State =
|
||||||
|
MSTP_ZERO_CONFIG_STATE_INIT;
|
||||||
|
mstp_port->master_state = MSTP_MASTER_STATE_INITIALIZE;
|
||||||
|
}
|
||||||
|
mstp_port->ReceivedValidFrame = false;
|
||||||
|
} else if ((mstp_port->DestinationAddress ==
|
||||||
mstp_port->This_Station) ||
|
mstp_port->This_Station) ||
|
||||||
(mstp_port->DestinationAddress == MSTP_BROADCAST_ADDRESS)) {
|
(mstp_port->DestinationAddress == MSTP_BROADCAST_ADDRESS)) {
|
||||||
/* destined for me! */
|
/* destined for me! */
|
||||||
@@ -857,7 +832,8 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
case MSTP_MASTER_STATE_WAIT_FOR_REPLY:
|
case MSTP_MASTER_STATE_WAIT_FOR_REPLY:
|
||||||
/* In the WAIT_FOR_REPLY state, the node waits for */
|
/* In the WAIT_FOR_REPLY state, the node waits for */
|
||||||
/* a reply from another node. */
|
/* a reply from another node. */
|
||||||
if (mstp_port->SilenceTimer((void *)mstp_port) >= Treply_timeout) {
|
if (mstp_port->SilenceTimer((void *)mstp_port) >=
|
||||||
|
mstp_port->Treply_timeout) {
|
||||||
/* ReplyTimeout */
|
/* ReplyTimeout */
|
||||||
/* assume that the request has failed */
|
/* assume that the request has failed */
|
||||||
mstp_port->FrameCount = mstp_port->Nmax_info_frames;
|
mstp_port->FrameCount = mstp_port->Nmax_info_frames;
|
||||||
@@ -1011,7 +987,8 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
case MSTP_MASTER_STATE_PASS_TOKEN:
|
case MSTP_MASTER_STATE_PASS_TOKEN:
|
||||||
/* The PASS_TOKEN state listens for a successor to begin using */
|
/* The PASS_TOKEN state listens for a successor to begin using */
|
||||||
/* the token that this node has just attempted to pass. */
|
/* the token that this node has just attempted to pass. */
|
||||||
if (mstp_port->SilenceTimer((void *)mstp_port) <= Tusage_timeout) {
|
if (mstp_port->SilenceTimer((void *)mstp_port) <=
|
||||||
|
mstp_port->Tusage_timeout) {
|
||||||
if (mstp_port->EventCount > Nmin_octets) {
|
if (mstp_port->EventCount > Nmin_octets) {
|
||||||
/* SawTokenUser */
|
/* SawTokenUser */
|
||||||
/* Assume that a frame has been sent by the new token user.
|
/* Assume that a frame has been sent by the new token user.
|
||||||
@@ -1138,7 +1115,7 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
}
|
}
|
||||||
mstp_port->ReceivedValidFrame = false;
|
mstp_port->ReceivedValidFrame = false;
|
||||||
} else if ((mstp_port->SilenceTimer((void *)mstp_port) >
|
} else if ((mstp_port->SilenceTimer((void *)mstp_port) >
|
||||||
Tusage_timeout) ||
|
mstp_port->Tusage_timeout) ||
|
||||||
(mstp_port->ReceivedInvalidFrame == true)) {
|
(mstp_port->ReceivedInvalidFrame == true)) {
|
||||||
if (mstp_port->SoleMaster == true) {
|
if (mstp_port->SoleMaster == true) {
|
||||||
/* SoleMaster */
|
/* SoleMaster */
|
||||||
@@ -1209,7 +1186,7 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
/* clear our flag we were holding for comparison */
|
/* clear our flag we were holding for comparison */
|
||||||
mstp_port->ReceivedValidFrame = false;
|
mstp_port->ReceivedValidFrame = false;
|
||||||
} else if (mstp_port->SilenceTimer((void *)mstp_port) >
|
} else if (mstp_port->SilenceTimer((void *)mstp_port) >
|
||||||
Treply_delay) {
|
mstp_port->Treply_delay) {
|
||||||
/* DeferredReply */
|
/* DeferredReply */
|
||||||
/* If no reply will be available from the higher layers */
|
/* If no reply will be available from the higher layers */
|
||||||
/* within Treply_delay after the reception of the */
|
/* within Treply_delay after the reception of the */
|
||||||
@@ -1247,7 +1224,11 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
return transition_now;
|
return transition_now;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MSTP_Slave_Node_FSM(volatile struct mstp_port_struct_t *mstp_port)
|
/**
|
||||||
|
* @brief Finite State Machine for the Slave Node process
|
||||||
|
* @param mstp_port the context of the MSTP port
|
||||||
|
*/
|
||||||
|
void MSTP_Slave_Node_FSM(struct mstp_port_struct_t *mstp_port)
|
||||||
{
|
{
|
||||||
unsigned length = 0;
|
unsigned length = 0;
|
||||||
|
|
||||||
@@ -1257,9 +1238,27 @@ void MSTP_Slave_Node_FSM(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
/* invalid frame was received */
|
/* invalid frame was received */
|
||||||
mstp_port->ReceivedInvalidFrame = false;
|
mstp_port->ReceivedInvalidFrame = false;
|
||||||
} else if (mstp_port->ReceivedValidFrame) {
|
} else if (mstp_port->ReceivedValidFrame) {
|
||||||
|
mstp_port->ReceivedValidFrame = false;
|
||||||
switch (mstp_port->FrameType) {
|
switch (mstp_port->FrameType) {
|
||||||
case FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY:
|
case FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY:
|
||||||
if (mstp_port->DestinationAddress != MSTP_BROADCAST_ADDRESS) {
|
if (mstp_port->DestinationAddress != MSTP_BROADCAST_ADDRESS) {
|
||||||
|
/* indicate successful reception to the higher layers */
|
||||||
|
(void)MSTP_Put_Receive(mstp_port);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FRAME_TYPE_TEST_REQUEST:
|
||||||
|
MSTP_Create_And_Send_Frame(mstp_port, FRAME_TYPE_TEST_RESPONSE,
|
||||||
|
mstp_port->SourceAddress, mstp_port->This_Station,
|
||||||
|
&mstp_port->InputBuffer[0], mstp_port->DataLength);
|
||||||
|
break;
|
||||||
|
case FRAME_TYPE_TOKEN:
|
||||||
|
case FRAME_TYPE_POLL_FOR_MASTER:
|
||||||
|
case FRAME_TYPE_TEST_RESPONSE:
|
||||||
|
case FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
/* The ANSWER_DATA_REQUEST state is entered when a */
|
/* The ANSWER_DATA_REQUEST state is entered when a */
|
||||||
/* BACnet Data Expecting Reply, a Test_Request, or */
|
/* BACnet Data Expecting Reply, a Test_Request, or */
|
||||||
/* a proprietary frame that expects a reply is received. */
|
/* a proprietary frame that expects a reply is received. */
|
||||||
@@ -1281,7 +1280,7 @@ void MSTP_Slave_Node_FSM(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
/* clear our flag we were holding for comparison */
|
/* clear our flag we were holding for comparison */
|
||||||
mstp_port->ReceivedValidFrame = false;
|
mstp_port->ReceivedValidFrame = false;
|
||||||
} else if (mstp_port->SilenceTimer((void *)mstp_port) >
|
} else if (mstp_port->SilenceTimer((void *)mstp_port) >
|
||||||
Treply_delay) {
|
mstp_port->Treply_delay) {
|
||||||
/* If no reply will be available from the higher layers
|
/* If no reply will be available from the higher layers
|
||||||
within Treply_delay after the reception of the final
|
within Treply_delay after the reception of the final
|
||||||
octet of the requesting frame (the mechanism used to
|
octet of the requesting frame (the mechanism used to
|
||||||
@@ -1290,25 +1289,320 @@ void MSTP_Slave_Node_FSM(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
/* clear our flag we were holding for comparison */
|
/* clear our flag we were holding for comparison */
|
||||||
mstp_port->ReceivedValidFrame = false;
|
mstp_port->ReceivedValidFrame = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize a UUID for storing the unique identifier of this node
|
||||||
|
* which is used to send and validate a test request and test response
|
||||||
|
* @note A Universally Unique IDentifier (UUID) - also called a
|
||||||
|
* Global Unique IDentifier (GUID) - is a 128-bit value.
|
||||||
|
*
|
||||||
|
* 4.4. Algorithms for Creating a UUID from Truly Random or
|
||||||
|
* Pseudo-Random Numbers
|
||||||
|
*
|
||||||
|
* The version 4 UUID is meant for generating UUIDs from truly-random or
|
||||||
|
* pseudo-random numbers.
|
||||||
|
*
|
||||||
|
* The algorithm is as follows:
|
||||||
|
*
|
||||||
|
* o Set the two most significant bits (bits 6 and 7) of the
|
||||||
|
* clock_seq_hi_and_reserved to zero and one, respectively.
|
||||||
|
*
|
||||||
|
* o Set the four most significant bits (bits 12 through 15) of the
|
||||||
|
* time_hi_and_version field to the 4-bit version number from
|
||||||
|
* Section 4.1.3.
|
||||||
|
*
|
||||||
|
* o Set all the other bits to randomly (or pseudo-randomly) chosen
|
||||||
|
* values.
|
||||||
|
*
|
||||||
|
* @param mstp_port the context of the MSTP port
|
||||||
|
*/
|
||||||
|
void MSTP_Zero_Config_UUID_Init(struct mstp_port_struct_t *mstp_port)
|
||||||
|
{
|
||||||
|
unsigned i = 0;
|
||||||
|
|
||||||
|
if (!mstp_port) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* 1. Generate 16 random bytes = 128 bits */
|
||||||
|
for (i = 0; i < MSTP_UUID_SIZE; i++) {
|
||||||
|
mstp_port->UUID[i] = rand() % 255;
|
||||||
|
}
|
||||||
|
/* 2. Adjust certain bits according to RFC 4122 section 4.4.
|
||||||
|
This just means do the following
|
||||||
|
(a) set the high nibble of the 7th byte equal to 4 and
|
||||||
|
(b) set the two most significant bits of the 9th byte to 10'B,
|
||||||
|
so the high nibble will be one of {8,9,A,B}.
|
||||||
|
From http://www.cryptosys.net/pki/Uuid.c.html */
|
||||||
|
mstp_port->UUID[6] = 0x40 | (mstp_port->UUID[6] & 0x0f);
|
||||||
|
mstp_port->UUID[8] = 0x80 | (mstp_port->UUID[8] & 0x3f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The ZERO_CONFIGURATION_INIT state is entered when
|
||||||
|
* ZeroConfigurationMode is TRUE
|
||||||
|
* @param mstp_port the context of the MSTP port
|
||||||
|
*/
|
||||||
|
static void MSTP_Zero_Config_State_Init(struct mstp_port_struct_t *mstp_port)
|
||||||
|
{
|
||||||
|
uint32_t slots;
|
||||||
|
|
||||||
|
if (!mstp_port) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mstp_port->Poll_Count = 0;
|
||||||
|
mstp_port->Zero_Config_Station = Nmin_poll_station;
|
||||||
|
mstp_port->Npoll_slot = 1 + (rand() % Nmax_poll_slot);
|
||||||
|
/* basic silence timeout is the dropped token time plus
|
||||||
|
one Tslot after the last master node. Add one Tslot of
|
||||||
|
silence timeout per zero config priority slot */
|
||||||
|
slots = 128 + mstp_port->Npoll_slot;
|
||||||
|
mstp_port->Zero_Config_Silence = Tno_token + Tslot * slots;
|
||||||
|
MSTP_Zero_Config_UUID_Init(mstp_port);
|
||||||
|
mstp_port->Zero_Config_Max_Master = 0;
|
||||||
|
mstp_port->Zero_Config_State = MSTP_ZERO_CONFIG_STATE_IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The ZERO_CONFIGURATION_IDLE state is entered when
|
||||||
|
* ZeroConfigurationMode is TRUE, and a node is
|
||||||
|
* is waiting for any frame or waiting to timeout.
|
||||||
|
* @param mstp_port the context of the MSTP port
|
||||||
|
*/
|
||||||
|
static void MSTP_Zero_Config_State_Idle(struct mstp_port_struct_t *mstp_port)
|
||||||
|
{
|
||||||
|
if (!mstp_port) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mstp_port->ReceivedValidFrame) {
|
||||||
|
/* next state will clear the frame flags */
|
||||||
|
/* MonitorPFM */
|
||||||
|
mstp_port->Poll_Count = 0;
|
||||||
|
mstp_port->Zero_Config_State = MSTP_ZERO_CONFIG_STATE_LURK;
|
||||||
|
} else if (mstp_port->ReceivedInvalidFrame) {
|
||||||
|
/* InvalidFrame */
|
||||||
|
mstp_port->ReceivedInvalidFrame = false;
|
||||||
|
} else if (mstp_port->Zero_Config_Silence > 0) {
|
||||||
|
if (mstp_port->SilenceTimer((void *)mstp_port) >
|
||||||
|
mstp_port->Zero_Config_Silence) {
|
||||||
|
/* ClaimAddress */
|
||||||
|
/* long silence indicates we are alone or
|
||||||
|
with other silent devices */
|
||||||
|
/* claim the token at the current zero-config address */
|
||||||
|
/* configure max master at maximum */
|
||||||
|
/* confirm this station with a quick test */
|
||||||
|
mstp_port->Zero_Config_Max_Master = DEFAULT_MAX_MASTER;
|
||||||
|
MSTP_Create_And_Send_Frame(mstp_port, FRAME_TYPE_TEST_REQUEST,
|
||||||
|
mstp_port->Zero_Config_Station, mstp_port->Zero_Config_Station,
|
||||||
|
mstp_port->UUID, sizeof(mstp_port->UUID));
|
||||||
|
mstp_port->Zero_Config_State = MSTP_ZERO_CONFIG_STATE_CONFIRM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The ZERO_CONFIGURATION_LURK state is entered when
|
||||||
|
* ZeroConfigurationMode is TRUE, and a node is
|
||||||
|
* counting a Poll For Master frames to Zero_Config_Station address
|
||||||
|
* @param mstp_port the context of the MSTP port
|
||||||
|
*/
|
||||||
|
static void MSTP_Zero_Config_State_Lurk(struct mstp_port_struct_t *mstp_port)
|
||||||
|
{
|
||||||
|
uint8_t count, frame, src, dst;
|
||||||
|
|
||||||
|
if (!mstp_port) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mstp_port->ReceivedValidFrame) {
|
||||||
|
mstp_port->ReceivedValidFrame = false;
|
||||||
|
dst = mstp_port->DestinationAddress;
|
||||||
|
src = mstp_port->SourceAddress;
|
||||||
|
frame = mstp_port->FrameType;
|
||||||
|
if (frame == FRAME_TYPE_POLL_FOR_MASTER) {
|
||||||
|
if ((dst > mstp_port->Zero_Config_Max_Master) &&
|
||||||
|
(dst <= DEFAULT_MAX_MASTER)) {
|
||||||
|
/* LearnMaxMaster */
|
||||||
|
mstp_port->Zero_Config_Max_Master = dst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (src == mstp_port->Zero_Config_Station) {
|
||||||
|
/* AddressInUse */
|
||||||
|
/* monitor PFM from the next address */
|
||||||
|
mstp_port->Zero_Config_Station++;
|
||||||
|
if (mstp_port->Zero_Config_Station > Nmax_poll_station) {
|
||||||
|
/* start again from first */
|
||||||
|
mstp_port->Zero_Config_Station = Nmin_poll_station;
|
||||||
|
}
|
||||||
|
mstp_port->Poll_Count = 0;
|
||||||
|
} else if ((frame == FRAME_TYPE_POLL_FOR_MASTER) &&
|
||||||
|
(dst == mstp_port->Zero_Config_Station)) {
|
||||||
|
mstp_port->Poll_Count++;
|
||||||
|
/* calculate this node poll count priority */
|
||||||
|
count = Nmin_poll + mstp_port->Npoll_slot;
|
||||||
|
if (mstp_port->Poll_Count == count) {
|
||||||
|
/* ClaimAddress */
|
||||||
|
MSTP_Create_And_Send_Frame(mstp_port,
|
||||||
|
FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER, src,
|
||||||
|
mstp_port->Zero_Config_Station, NULL, 0);
|
||||||
|
mstp_port->Zero_Config_State = MSTP_ZERO_CONFIG_STATE_CLAIM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (mstp_port->ReceivedInvalidFrame) {
|
||||||
|
/* InvalidFrame */
|
||||||
|
mstp_port->ReceivedInvalidFrame = false;
|
||||||
|
} else if (mstp_port->Zero_Config_Silence > 0) {
|
||||||
|
if (mstp_port->SilenceTimer((void *)mstp_port) >
|
||||||
|
mstp_port->Zero_Config_Silence) {
|
||||||
|
mstp_port->Zero_Config_State = MSTP_ZERO_CONFIG_STATE_IDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The ZERO_CONFIGURATION_CLAIM state is entered when a node
|
||||||
|
* is waiting for a Token frame from the master to which it
|
||||||
|
* previously sent a Reply To Poll For Master frame, and
|
||||||
|
* ZeroConfigurationMode is TRUE.
|
||||||
|
* @param mstp_port the context of the MSTP port
|
||||||
|
*/
|
||||||
|
static void MSTP_Zero_Config_State_Claim(struct mstp_port_struct_t *mstp_port)
|
||||||
|
{
|
||||||
|
uint8_t frame, src, dst;
|
||||||
|
|
||||||
|
if (!mstp_port) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* */
|
||||||
|
if (mstp_port->ReceivedValidFrame) {
|
||||||
|
mstp_port->ReceivedValidFrame = false;
|
||||||
|
dst = mstp_port->DestinationAddress;
|
||||||
|
src = mstp_port->SourceAddress;
|
||||||
|
frame = mstp_port->FrameType;
|
||||||
|
if (src == mstp_port->Zero_Config_Station) {
|
||||||
|
/* ClaimAddressInUse */
|
||||||
|
/* monitor PFM from the next address */
|
||||||
|
mstp_port->Zero_Config_Station++;
|
||||||
|
if (mstp_port->Zero_Config_Station > Nmax_poll_station) {
|
||||||
|
/* start again from first */
|
||||||
|
mstp_port->Zero_Config_Station = Nmin_poll_station;
|
||||||
|
}
|
||||||
|
mstp_port->Poll_Count = 0;
|
||||||
|
mstp_port->Zero_Config_State = MSTP_ZERO_CONFIG_STATE_LURK;
|
||||||
|
} else if (frame == FRAME_TYPE_TOKEN) {
|
||||||
|
if (dst == mstp_port->Zero_Config_Station) {
|
||||||
|
/* ClaimTokenForUs */
|
||||||
|
MSTP_Create_And_Send_Frame(mstp_port, FRAME_TYPE_TEST_REQUEST,
|
||||||
|
src, mstp_port->Zero_Config_Station, mstp_port->UUID,
|
||||||
|
MSTP_UUID_SIZE);
|
||||||
|
mstp_port->Zero_Config_State = MSTP_ZERO_CONFIG_STATE_CONFIRM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (mstp_port->ReceivedInvalidFrame) {
|
||||||
|
/* ClaimInvalidFrame */
|
||||||
|
mstp_port->ReceivedInvalidFrame = false;
|
||||||
|
} else if (mstp_port->Zero_Config_Silence > 0) {
|
||||||
|
/* ClaimLostToken */
|
||||||
|
if (mstp_port->SilenceTimer((void *)mstp_port) >
|
||||||
|
mstp_port->Zero_Config_Silence) {
|
||||||
|
mstp_port->Zero_Config_State = MSTP_ZERO_CONFIG_STATE_IDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The ZERO_CONFIGURATION_CONFIRM state is entered when
|
||||||
|
* a node is waiting for a Test Response frame and
|
||||||
|
* ZeroConfigurationMode is TRUE.
|
||||||
|
* @param mstp_port the context of the MSTP port
|
||||||
|
*/
|
||||||
|
static void MSTP_Zero_Config_State_Confirm(struct mstp_port_struct_t *mstp_port)
|
||||||
|
{
|
||||||
|
bool match = false;
|
||||||
|
uint8_t frame, src, dst;
|
||||||
|
|
||||||
|
if (!mstp_port) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mstp_port->ReceivedValidFrame) {
|
||||||
|
mstp_port->ReceivedValidFrame = false;
|
||||||
|
dst = mstp_port->DestinationAddress;
|
||||||
|
src = mstp_port->SourceAddress;
|
||||||
|
frame = mstp_port->FrameType;
|
||||||
|
/* note: test frame could be from us. Check frame type first. */
|
||||||
|
if (frame == FRAME_TYPE_TEST_RESPONSE) {
|
||||||
|
if (dst == mstp_port->Zero_Config_Station) {
|
||||||
|
match = true;
|
||||||
|
}
|
||||||
|
if (match & (mstp_port->DataLength < MSTP_UUID_SIZE)) {
|
||||||
|
match = false;
|
||||||
|
}
|
||||||
|
if (match &&
|
||||||
|
(memcmp(mstp_port->InputBuffer, mstp_port->UUID,
|
||||||
|
MSTP_UUID_SIZE) != 0)) {
|
||||||
|
match = false;
|
||||||
|
}
|
||||||
|
if (match) {
|
||||||
|
/* ConfirmationSuccessful */
|
||||||
|
mstp_port->This_Station = mstp_port->Zero_Config_Station;
|
||||||
|
mstp_port->Zero_Config_State = MSTP_ZERO_CONFIG_STATE_USE;
|
||||||
} else {
|
} else {
|
||||||
mstp_port->ReceivedValidFrame = false;
|
/* ConfirmationFailed */
|
||||||
|
mstp_port->Zero_Config_State = MSTP_ZERO_CONFIG_STATE_IDLE;
|
||||||
}
|
}
|
||||||
|
} else if (src == mstp_port->Zero_Config_Station) {
|
||||||
|
/* ConfirmationAddressInUse */
|
||||||
|
/* monitor PFM from the next address */
|
||||||
|
mstp_port->Zero_Config_Station++;
|
||||||
|
if (mstp_port->Zero_Config_Station > Nmax_poll_station) {
|
||||||
|
/* start again from first */
|
||||||
|
mstp_port->Zero_Config_Station = Nmin_poll_station;
|
||||||
|
}
|
||||||
|
mstp_port->Zero_Config_State = MSTP_ZERO_CONFIG_STATE_LURK;
|
||||||
|
}
|
||||||
|
} else if (mstp_port->SilenceTimer((void *)mstp_port) >=
|
||||||
|
mstp_port->Treply_timeout) {
|
||||||
|
/* ConfirmationTimeout */
|
||||||
|
/* In case validating device doesn't support Test Request */
|
||||||
|
/* no response and no collision */
|
||||||
|
mstp_port->This_Station = mstp_port->Zero_Config_Station;
|
||||||
|
mstp_port->Zero_Config_State = MSTP_ZERO_CONFIG_STATE_USE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Finite State Machine for the Zero Configuration process
|
||||||
|
* @param mstp_port the context of the MSTP port
|
||||||
|
*/
|
||||||
|
void MSTP_Zero_Config_FSM(struct mstp_port_struct_t *mstp_port)
|
||||||
|
{
|
||||||
|
if (!mstp_port) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!mstp_port->ZeroConfigEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (mstp_port->Zero_Config_State) {
|
||||||
|
case MSTP_ZERO_CONFIG_STATE_INIT:
|
||||||
|
MSTP_Zero_Config_State_Init(mstp_port);
|
||||||
break;
|
break;
|
||||||
case FRAME_TYPE_TEST_REQUEST:
|
case MSTP_ZERO_CONFIG_STATE_IDLE:
|
||||||
mstp_port->ReceivedValidFrame = false;
|
MSTP_Zero_Config_State_Idle(mstp_port);
|
||||||
MSTP_Create_And_Send_Frame(mstp_port, FRAME_TYPE_TEST_RESPONSE,
|
break;
|
||||||
mstp_port->SourceAddress, mstp_port->This_Station,
|
case MSTP_ZERO_CONFIG_STATE_LURK:
|
||||||
&mstp_port->InputBuffer[0], mstp_port->DataLength);
|
MSTP_Zero_Config_State_Lurk(mstp_port);
|
||||||
|
break;
|
||||||
|
case MSTP_ZERO_CONFIG_STATE_CLAIM:
|
||||||
|
MSTP_Zero_Config_State_Claim(mstp_port);
|
||||||
|
break;
|
||||||
|
case MSTP_ZERO_CONFIG_STATE_CONFIRM:
|
||||||
|
MSTP_Zero_Config_State_Confirm(mstp_port);
|
||||||
|
break;
|
||||||
|
case MSTP_ZERO_CONFIG_STATE_USE:
|
||||||
break;
|
break;
|
||||||
case FRAME_TYPE_TOKEN:
|
|
||||||
case FRAME_TYPE_POLL_FOR_MASTER:
|
|
||||||
case FRAME_TYPE_TEST_RESPONSE:
|
|
||||||
case FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY:
|
|
||||||
default:
|
default:
|
||||||
mstp_port->ReceivedValidFrame = false;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* note: This_Station assumed to be set with the MAC address */
|
/* note: This_Station assumed to be set with the MAC address */
|
||||||
@@ -1317,7 +1611,7 @@ void MSTP_Slave_Node_FSM(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
/* note: InputBuffer and InputBufferSize assumed to be set */
|
/* note: InputBuffer and InputBufferSize assumed to be set */
|
||||||
/* note: OutputBuffer and OutputBufferSize assumed to be set */
|
/* note: OutputBuffer and OutputBufferSize assumed to be set */
|
||||||
/* note: SilenceTimer and SilenceTimerReset assumed to be set */
|
/* note: SilenceTimer and SilenceTimerReset assumed to be set */
|
||||||
void MSTP_Init(volatile struct mstp_port_struct_t *mstp_port)
|
void MSTP_Init(struct mstp_port_struct_t *mstp_port)
|
||||||
{
|
{
|
||||||
if (mstp_port) {
|
if (mstp_port) {
|
||||||
#if 0
|
#if 0
|
||||||
@@ -1330,10 +1624,28 @@ void MSTP_Init(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
/* FIXME: these are adjustable, so you must set these in dlmstp */
|
/* FIXME: these are adjustable, so you must set these in dlmstp */
|
||||||
mstp_port->Nmax_info_frames = DEFAULT_MAX_INFO_FRAMES;
|
mstp_port->Nmax_info_frames = DEFAULT_MAX_INFO_FRAMES;
|
||||||
mstp_port->Nmax_master = DEFAULT_MAX_MASTER;
|
mstp_port->Nmax_master = DEFAULT_MAX_MASTER;
|
||||||
|
mstp_port->Tframe_abort = DEFAULT_Tframe_abort;
|
||||||
|
mstp_port->Treply_delay = DEFAULT_Treply_delay;
|
||||||
|
mstp_port->Treply_timeout = DEFAULT_Treply_timeout;
|
||||||
|
mstp_port->Tusage_timeout = DEFAULT_Tusage_timeout;
|
||||||
/* FIXME: point to functions */
|
/* FIXME: point to functions */
|
||||||
mstp_port->SilenceTimer = Timer_Silence;
|
mstp_port->SilenceTimer = Timer_Silence;
|
||||||
mstp_port = >SilenceTimerReset = Timer_Silence_Reset;
|
mstp_port->SilenceTimerReset = Timer_Silence_Reset;
|
||||||
#endif
|
#endif
|
||||||
|
if ((mstp_port->Tframe_abort < 6) || (mstp_port->Tframe_abort > 100)) {
|
||||||
|
mstp_port->Tframe_abort = DEFAULT_Tframe_abort;
|
||||||
|
}
|
||||||
|
if (mstp_port->Treply_delay > 250) {
|
||||||
|
mstp_port->Treply_delay = DEFAULT_Treply_delay;
|
||||||
|
}
|
||||||
|
if ((mstp_port->Treply_timeout < 20) ||
|
||||||
|
(mstp_port->Treply_timeout > 300)) {
|
||||||
|
mstp_port->Treply_timeout = DEFAULT_Treply_timeout;
|
||||||
|
}
|
||||||
|
if ((mstp_port->Tusage_timeout < 20) ||
|
||||||
|
(mstp_port->Tusage_timeout > 35)) {
|
||||||
|
mstp_port->Tusage_timeout = DEFAULT_Tusage_timeout;
|
||||||
|
}
|
||||||
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
|
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
|
||||||
mstp_port->master_state = MSTP_MASTER_STATE_INITIALIZE;
|
mstp_port->master_state = MSTP_MASTER_STATE_INITIALIZE;
|
||||||
mstp_port->ReceiveError = false;
|
mstp_port->ReceiveError = false;
|
||||||
@@ -1351,11 +1663,12 @@ void MSTP_Init(volatile struct mstp_port_struct_t *mstp_port)
|
|||||||
mstp_port->Poll_Station = mstp_port->This_Station;
|
mstp_port->Poll_Station = mstp_port->This_Station;
|
||||||
mstp_port->ReceivedInvalidFrame = false;
|
mstp_port->ReceivedInvalidFrame = false;
|
||||||
mstp_port->ReceivedValidFrame = false;
|
mstp_port->ReceivedValidFrame = false;
|
||||||
mstp_port->ReceivedValidFrameNotForUs = false;
|
|
||||||
mstp_port->RetryCount = 0;
|
mstp_port->RetryCount = 0;
|
||||||
mstp_port->SilenceTimerReset((void *)mstp_port);
|
mstp_port->SilenceTimerReset(mstp_port);
|
||||||
mstp_port->SoleMaster = false;
|
mstp_port->SoleMaster = false;
|
||||||
mstp_port->SourceAddress = 0;
|
mstp_port->SourceAddress = 0;
|
||||||
mstp_port->TokenCount = 0;
|
mstp_port->TokenCount = 0;
|
||||||
|
/* zero config */
|
||||||
|
mstp_port->Zero_Config_State = MSTP_ZERO_CONFIG_STATE_INIT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+204
-151
@@ -1,27 +1,27 @@
|
|||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
*
|
*
|
||||||
* Copyright (C) 2004 Steve Karg <skarg@users.sourceforge.net>
|
* Copyright (C) 2004 Steve Karg <skarg@users.sourceforge.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
* a copy of this software and associated documentation files (the
|
* a copy of this software and associated documentation files (the
|
||||||
* "Software"), to deal in the Software without restriction, including
|
* "Software"), to deal in the Software without restriction, including
|
||||||
* without limitation the rights to use, copy, modify, merge, publish,
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
* permit persons to whom the Software is furnished to do so, subject to
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
* the following conditions:
|
* the following conditions:
|
||||||
*
|
*
|
||||||
* The above copyright notice and this permission notice shall be included
|
* The above copyright notice and this permission notice shall be included
|
||||||
* in all copies or substantial portions of the Software.
|
* in all copies or substantial portions of the Software.
|
||||||
*
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*
|
*
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
#ifndef MSTP_H
|
#ifndef MSTP_H
|
||||||
#define MSTP_H
|
#define MSTP_H
|
||||||
|
|
||||||
@@ -30,6 +30,17 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "bacnet/bacnet_stack_exports.h"
|
#include "bacnet/bacnet_stack_exports.h"
|
||||||
#include "bacnet/datalink/mstpdef.h"
|
#include "bacnet/datalink/mstpdef.h"
|
||||||
|
#include "bacnet/config.h"
|
||||||
|
|
||||||
|
/* Repeater turnoff delay. The duration of a continuous logical one state */
|
||||||
|
/* at the active input port of an MS/TP repeater after which the repeater */
|
||||||
|
/* will enter the IDLE state: 29 bit times < Troff < 40 bit times. */
|
||||||
|
#ifndef Troff
|
||||||
|
#define Troff 30
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* size of the buffer used to send and validate a unique test request */
|
||||||
|
#define MSTP_UUID_SIZE 16
|
||||||
|
|
||||||
struct mstp_port_struct_t {
|
struct mstp_port_struct_t {
|
||||||
MSTP_RECEIVE_STATE receive_state;
|
MSTP_RECEIVE_STATE receive_state;
|
||||||
@@ -39,21 +50,21 @@ struct mstp_port_struct_t {
|
|||||||
/* A Boolean flag set to TRUE by the Receive State Machine */
|
/* A Boolean flag set to TRUE by the Receive State Machine */
|
||||||
/* if an error is detected during the reception of a frame. */
|
/* if an error is detected during the reception of a frame. */
|
||||||
/* Set to FALSE by the Master or Slave Node state machine. */
|
/* Set to FALSE by the Master or Slave Node state machine. */
|
||||||
unsigned ReceiveError:1;
|
unsigned ReceiveError : 1;
|
||||||
/* There is data in the buffer */
|
/* There is data in the buffer */
|
||||||
unsigned DataAvailable:1;
|
unsigned DataAvailable : 1;
|
||||||
unsigned ReceivedInvalidFrame:1;
|
unsigned ReceivedInvalidFrame : 1;
|
||||||
/* A Boolean flag set to TRUE by the Receive State Machine */
|
/* A Boolean flag set to TRUE by the Receive State Machine */
|
||||||
/* if a valid frame is received. */
|
/* if a valid frame is received. */
|
||||||
/* Set to FALSE by the Master or Slave Node state machine. */
|
/* Set to FALSE by the Master or Slave Node state machine. */
|
||||||
unsigned ReceivedValidFrame:1;
|
unsigned ReceivedValidFrame : 1;
|
||||||
/* A Boolean flag set to TRUE by the Receive State Machine */
|
/* A Boolean flag set to TRUE by the master machine if this node is the
|
||||||
/* if a valid frame is received but it is not addressed to us. */
|
only known master node. */
|
||||||
/* Set to FALSE by the Master or Slave Node state machine. */
|
unsigned SoleMaster : 1;
|
||||||
unsigned ReceivedValidFrameNotForUs:1;
|
/* A Boolean flag set to TRUE if this node is a slave node */
|
||||||
/* A Boolean flag set to TRUE by the master machine if this node is the */
|
unsigned SlaveNodeEnabled : 1;
|
||||||
/* only known master node. */
|
/* A Boolean flag set to TRUE if this node is using a ZeroConfig address */
|
||||||
unsigned SoleMaster:1;
|
unsigned ZeroConfigEnabled : 1;
|
||||||
/* stores the latest received data */
|
/* stores the latest received data */
|
||||||
uint8_t DataRegister;
|
uint8_t DataRegister;
|
||||||
/* Used to accumulate the CRC on the data field of a frame. */
|
/* Used to accumulate the CRC on the data field of a frame. */
|
||||||
@@ -65,183 +76,225 @@ struct mstp_port_struct_t {
|
|||||||
uint16_t DataLength;
|
uint16_t DataLength;
|
||||||
/* Used to store the destination address of a received frame. */
|
/* Used to store the destination address of a received frame. */
|
||||||
uint8_t DestinationAddress;
|
uint8_t DestinationAddress;
|
||||||
/* Used to count the number of received octets or errors. */
|
/* Used to count the number of received octets or errors.
|
||||||
/* This is used in the detection of link activity. */
|
This is used in the detection of link activity.
|
||||||
/* Compared to Nmin_octets */
|
Compared to Nmin_octets */
|
||||||
uint8_t EventCount;
|
uint8_t EventCount;
|
||||||
/* Used to store the frame type of a received frame. */
|
/* Used to store the frame type of a received frame. */
|
||||||
uint8_t FrameType;
|
uint8_t FrameType;
|
||||||
/* The number of frames sent by this node during a single token hold. */
|
/* The number of frames sent by this node during a single token hold.
|
||||||
/* When this counter reaches the value Nmax_info_frames, the node must */
|
When this counter reaches the value Nmax_info_frames, the node must */
|
||||||
/* pass the token. */
|
/* pass the token. */
|
||||||
uint8_t FrameCount;
|
uint8_t FrameCount;
|
||||||
/* Used to accumulate the CRC on the header of a frame. */
|
/* Used to accumulate the CRC on the header of a frame. */
|
||||||
uint8_t HeaderCRC;
|
uint8_t HeaderCRC;
|
||||||
/* Used to store the actual CRC from the header. */
|
/* Used to store the actual CRC from the header. */
|
||||||
uint8_t HeaderCRCActual;
|
uint8_t HeaderCRCActual;
|
||||||
/* Used as an index by the Receive State Machine, up to a maximum value of */
|
/* Used as an index by the Receive State Machine,
|
||||||
/* InputBufferSize. */
|
up to a maximum value of InputBufferSize. */
|
||||||
uint32_t Index;
|
uint32_t Index;
|
||||||
/* An array of octets, used to store octets as they are received. */
|
/* An array of octets, used to store octets as they are received.
|
||||||
/* InputBuffer is indexed from 0 to InputBufferSize-1. */
|
InputBuffer is indexed from 0 to InputBufferSize-1. */
|
||||||
/* The maximum size of a frame is 501 octets. */
|
/* Note: assign this to an actual array of bytes! */
|
||||||
/* FIXME: assign this to an actual array of bytes! */
|
|
||||||
/* Note: the buffer is designed as a pointer since some compilers
|
/* Note: the buffer is designed as a pointer since some compilers
|
||||||
and microcontroller architectures have limits as to places to
|
and microcontroller architectures have limits as to places to
|
||||||
hold contiguous memory. */
|
hold contiguous memory. */
|
||||||
uint8_t *InputBuffer;
|
uint8_t *InputBuffer;
|
||||||
uint16_t InputBufferSize;
|
uint16_t InputBufferSize;
|
||||||
/* "Next Station," the MAC address of the node to which This Station passes */
|
/* "Next Station," the MAC address of the node to which
|
||||||
/* the token. If the Next_Station is unknown, Next_Station shall be equal to */
|
This Station passes */
|
||||||
|
/* the token. If the Next_Station is unknown, Next_Station
|
||||||
|
shall be equal to */
|
||||||
/* This_Station. */
|
/* This_Station. */
|
||||||
uint8_t Next_Station;
|
uint8_t Next_Station;
|
||||||
/* "Poll Station," the MAC address of the node to which This Station last */
|
/* "Poll Station," the MAC address of the node to which This Station last
|
||||||
/* sent a Poll For Master. This is used during token maintenance. */
|
sent a Poll For Master. This is used during token maintenance. */
|
||||||
uint8_t Poll_Station;
|
uint8_t Poll_Station;
|
||||||
/* A counter of transmission retries used for Token and Poll For Master */
|
/* A counter of transmission retries used for Token and Poll For Master
|
||||||
/* transmission. */
|
transmission. */
|
||||||
unsigned RetryCount;
|
unsigned RetryCount;
|
||||||
/* A timer with nominal 5 millisecond resolution used to measure and */
|
/* A timer with nominal 5 millisecond resolution used to measure
|
||||||
/* generate silence on the medium between octets. It is incremented by a */
|
and generate silence on the medium between octets. It is
|
||||||
/* timer process and is cleared by the Receive State Machine when activity */
|
incremented by a timer process and is cleared by the Receive
|
||||||
/* is detected and by the SendFrame procedure as each octet is transmitted. */
|
State Machine when activity is detected and by the SendFrame
|
||||||
/* Since the timer resolution is limited and the timer is not necessarily */
|
procedure as each octet is transmitted. */
|
||||||
/* synchronized to other machine events, a timer value of N will actually */
|
/* Since the timer resolution is limited and the timer is not necessarily
|
||||||
/* denote intervals between N-1 and N */
|
synchronized to other machine events, a timer value of N will actually
|
||||||
|
denote intervals between N-1 and N */
|
||||||
/* Note: done here as functions - put into timer task or ISR
|
/* Note: done here as functions - put into timer task or ISR
|
||||||
so that you can be atomic on 8 bit microcontrollers */
|
so that you can be atomic on 8 bit microcontrollers */
|
||||||
uint32_t(
|
uint32_t (*SilenceTimer)(void *pArg);
|
||||||
*SilenceTimer) (
|
void (*SilenceTimerReset)(void *pArg);
|
||||||
void *pArg);
|
|
||||||
void (
|
|
||||||
*SilenceTimerReset) (
|
|
||||||
void *pArg);
|
|
||||||
|
|
||||||
/* A timer used to measure and generate Reply Postponed frames. It is */
|
/* A timer used to measure and generate Reply Postponed frames. It is
|
||||||
/* incremented by a timer process and is cleared by the Master Node State */
|
incremented by a timer process and is cleared by the Master Node State
|
||||||
/* Machine when a Data Expecting Reply Answer activity is completed. */
|
Machine when a Data Expecting Reply Answer activity is completed.
|
||||||
/* note: we always send a reply postponed since a message other than
|
note: we always send a reply postponed since a message other than
|
||||||
the reply may be in the transmit queue */
|
the reply may be in the transmit queue */
|
||||||
/* uint16_t ReplyPostponedTimer; */
|
/* uint16_t ReplyPostponedTimer; */
|
||||||
|
|
||||||
/* Used to store the Source Address of a received frame. */
|
/* Used to store the Source Address of a received frame. */
|
||||||
uint8_t SourceAddress;
|
uint8_t SourceAddress;
|
||||||
|
|
||||||
/* The number of tokens received by this node. When this counter reaches the */
|
/* The number of tokens received by this node. When this counter
|
||||||
/* value Npoll, the node polls the address range between TS and NS for */
|
reaches the value Npoll, the node polls the address range between
|
||||||
/* additional master nodes. TokenCount is set to zero at the end of the */
|
TS and NS for additional master nodes. TokenCount is set to zero
|
||||||
/* polling process. */
|
at the end of the polling process. */
|
||||||
unsigned TokenCount;
|
unsigned TokenCount;
|
||||||
|
|
||||||
/* "This Station," the MAC address of this node. TS is generally read from a */
|
/* "This Station," the MAC address of this node. TS is generally read from a
|
||||||
/* hardware DIP switch, or from nonvolatile memory. Valid values for TS are */
|
hardware DIP switch, or from nonvolatile memory. Valid values for TS are
|
||||||
/* 0 to 254. The value 255 is used to denote broadcast when used as a */
|
0 to 254. The value 255 is used to denote broadcast when used as a
|
||||||
/* destination address but is not allowed as a value for TS. */
|
destination address but is not allowed as a value for TS. */
|
||||||
uint8_t This_Station;
|
uint8_t This_Station;
|
||||||
|
|
||||||
/* This parameter represents the value of the Max_Info_Frames property of */
|
/* This parameter represents the value of the Max_Info_Frames property of
|
||||||
/* the node's Device object. The value of Max_Info_Frames specifies the */
|
the node's Device object. The value of Max_Info_Frames specifies the
|
||||||
/* maximum number of information frames the node may send before it must */
|
maximum number of information frames the node may send before it must
|
||||||
/* pass the token. Max_Info_Frames may have different values on different */
|
pass the token. Max_Info_Frames may have different values on different
|
||||||
/* nodes. This may be used to allocate more or less of the available link */
|
nodes. This may be used to allocate more or less of the available link
|
||||||
/* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */
|
bandwidth to particular nodes. If Max_Info_Frames is not writable in a
|
||||||
/* node, its value shall be 1. */
|
node, its value shall be 1.*/
|
||||||
uint8_t Nmax_info_frames;
|
uint8_t Nmax_info_frames;
|
||||||
|
|
||||||
/* This parameter represents the value of the Max_Master property of the */
|
/* This parameter represents the value of the Max_Master property of the
|
||||||
/* node's Device object. The value of Max_Master specifies the highest */
|
node's Device object. The value of Max_Master specifies the highest
|
||||||
/* allowable address for master nodes. The value of Max_Master shall be */
|
allowable address for master nodes. The value of Max_Master shall be
|
||||||
/* less than or equal to 127. If Max_Master is not writable in a node, */
|
less than or equal to 127. If Max_Master is not writable in a node,
|
||||||
/* its value shall be 127. */
|
its value shall be 127. */
|
||||||
uint8_t Nmax_master;
|
uint8_t Nmax_master;
|
||||||
|
|
||||||
/* An array of octets, used to store octets for transmitting */
|
/* An array of octets, used to store octets for transmitting
|
||||||
/* OutputBuffer is indexed from 0 to OutputBufferSize-1. */
|
OutputBuffer is indexed from 0 to OutputBufferSize-1.
|
||||||
/* The maximum size of a frame is 501 octets. */
|
FIXME: assign this to an actual array of bytes!
|
||||||
/* FIXME: assign this to an actual array of bytes! */
|
Note: the buffer is designed as a pointer since some compilers
|
||||||
/* Note: the buffer is designed as a pointer since some compilers
|
|
||||||
and microcontroller architectures have limits as to places to
|
and microcontroller architectures have limits as to places to
|
||||||
hold contiguous memory. */
|
hold contiguous memory. */
|
||||||
uint8_t *OutputBuffer;
|
uint8_t *OutputBuffer;
|
||||||
uint16_t OutputBufferSize;
|
uint16_t OutputBufferSize;
|
||||||
|
|
||||||
|
/* orderly transition tracking for zero-configuration node startup */
|
||||||
|
MSTP_ZERO_CONFIG_STATE Zero_Config_State;
|
||||||
|
/* the MAC address that this node is testing for MAC addresses
|
||||||
|
that are not in-use.*/
|
||||||
|
uint8_t Zero_Config_Station;
|
||||||
|
/* Used to count the number of received poll-for-master frames
|
||||||
|
This is used in the detection of addresses not in-use. */
|
||||||
|
uint8_t Poll_Count;
|
||||||
|
/* This parameter is random value 1..64, used to choose the poll slot */
|
||||||
|
uint8_t Npoll_slot;
|
||||||
|
/* UUID for storing the unique identifier for this node
|
||||||
|
used to send and validate a unique test request and response */
|
||||||
|
uint8_t UUID[MSTP_UUID_SIZE];
|
||||||
|
/* amount of silence time to wait, in milliseconds */
|
||||||
|
uint32_t Zero_Config_Silence;
|
||||||
|
/* This parameter tracks the highest polled station address.
|
||||||
|
The value of this parameter shall be less than or equal to 127.
|
||||||
|
In the absence of other fixed address nodes, this value shall be 127. */
|
||||||
|
uint8_t Zero_Config_Max_Master;
|
||||||
|
|
||||||
|
/* The minimum time without a DataAvailable or ReceiveError event within
|
||||||
|
a frame before a receiving node may discard the frame: 60 bit times.
|
||||||
|
Implementations may use larger values for this timeout,
|
||||||
|
not to exceed 100 milliseconds.
|
||||||
|
Tframe_abort = 1 + ((60*1000UL)/RS485_Baud); */
|
||||||
|
uint8_t Tframe_abort;
|
||||||
|
|
||||||
|
/* The maximum time a node may wait after reception of a frame that
|
||||||
|
expects a reply before sending the first octet of a reply or
|
||||||
|
Reply Postponed frame: 250 milliseconds. */
|
||||||
|
uint8_t Treply_delay;
|
||||||
|
|
||||||
|
/* The minimum time without a DataAvailable or ReceiveError event
|
||||||
|
that a node must wait for a station to begin replying to a
|
||||||
|
confirmed request: 255 milliseconds. (Implementations may use
|
||||||
|
larger values for this timeout, not to exceed 300 milliseconds.) */
|
||||||
|
uint16_t Treply_timeout;
|
||||||
|
|
||||||
|
/* The minimum time without a DataAvailable or ReceiveError event
|
||||||
|
that a node must wait for a remote node to begin using a token
|
||||||
|
or replying to a Poll For Master frame: 20 milliseconds.
|
||||||
|
(Implementations may use larger values for this timeout,
|
||||||
|
not to exceed 35 milliseconds.) */
|
||||||
|
uint8_t Tusage_timeout;
|
||||||
|
|
||||||
|
/* The minimum time after the end of the stop bit of the final
|
||||||
|
octet of a received frame before a node may enable its
|
||||||
|
EIA-485 driver: 40 bit times.
|
||||||
|
40 bits is 4 octets including a start and stop bit with each octet.
|
||||||
|
turnaround_time_milliseconds = (Tturnaround*1000UL)/RS485_Baud; */
|
||||||
|
uint8_t Tturnaround_timeout;
|
||||||
|
|
||||||
/*Platform-specific port data */
|
/*Platform-specific port data */
|
||||||
void *UserData;
|
void *UserData;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
void MSTP_Init(
|
void MSTP_Init(struct mstp_port_struct_t *mstp_port);
|
||||||
volatile struct mstp_port_struct_t *mstp_port);
|
BACNET_STACK_EXPORT
|
||||||
BACNET_STACK_EXPORT
|
void MSTP_Receive_Frame_FSM(struct mstp_port_struct_t *mstp_port);
|
||||||
void MSTP_Receive_Frame_FSM(
|
BACNET_STACK_EXPORT
|
||||||
volatile struct mstp_port_struct_t
|
bool MSTP_Master_Node_FSM(struct mstp_port_struct_t *mstp_port);
|
||||||
*mstp_port);
|
BACNET_STACK_EXPORT
|
||||||
BACNET_STACK_EXPORT
|
void MSTP_Slave_Node_FSM(struct mstp_port_struct_t *mstp_port);
|
||||||
bool MSTP_Master_Node_FSM(
|
|
||||||
volatile struct mstp_port_struct_t
|
|
||||||
*mstp_port);
|
|
||||||
BACNET_STACK_EXPORT
|
|
||||||
void MSTP_Slave_Node_FSM(
|
|
||||||
volatile struct mstp_port_struct_t *mstp_port);
|
|
||||||
|
|
||||||
/* returns true if line is active */
|
/* returns true if line is active */
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
bool MSTP_Line_Active(
|
bool MSTP_Line_Active(struct mstp_port_struct_t *mstp_port);
|
||||||
volatile struct mstp_port_struct_t *mstp_port);
|
|
||||||
|
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
uint16_t MSTP_Create_Frame(
|
uint16_t MSTP_Create_Frame(uint8_t *buffer,
|
||||||
uint8_t * buffer, /* where frame is loaded */
|
uint16_t buffer_len,
|
||||||
uint16_t buffer_len, /* amount of space available */
|
uint8_t frame_type,
|
||||||
uint8_t frame_type, /* type of frame to send - see defines */
|
uint8_t destination,
|
||||||
uint8_t destination, /* destination address */
|
uint8_t source,
|
||||||
uint8_t source, /* source address */
|
uint8_t *data,
|
||||||
uint8_t * data, /* any data to be sent - may be null */
|
|
||||||
uint16_t data_len); /* number of bytes of data (up to 501) */
|
|
||||||
|
|
||||||
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);
|
uint16_t data_len);
|
||||||
|
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
void MSTP_Fill_BACnet_Address(
|
void MSTP_Create_And_Send_Frame(
|
||||||
BACNET_ADDRESS * src,
|
struct mstp_port_struct_t *mstp_port,
|
||||||
uint8_t mstp_address);
|
uint8_t frame_type,
|
||||||
|
uint8_t destination,
|
||||||
|
uint8_t source,
|
||||||
|
uint8_t *data,
|
||||||
|
uint16_t data_len);
|
||||||
|
|
||||||
/* functions used by the MS/TP state machine to put or get data */
|
BACNET_STACK_EXPORT
|
||||||
/* FIXME: developer must implement these in their DLMSTP module */
|
void MSTP_Fill_BACnet_Address(BACNET_ADDRESS *src, uint8_t mstp_address);
|
||||||
|
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
uint16_t MSTP_Put_Receive(
|
void MSTP_Zero_Config_UUID_Init(struct mstp_port_struct_t *mstp_port);
|
||||||
volatile struct mstp_port_struct_t *mstp_port);
|
|
||||||
|
|
||||||
/* for the MS/TP state machine to use for getting data to send */
|
BACNET_STACK_EXPORT
|
||||||
/* Return: amount of PDU data */
|
void MSTP_Zero_Config_FSM(struct mstp_port_struct_t *mstp_port);
|
||||||
BACNET_STACK_EXPORT
|
|
||||||
uint16_t MSTP_Get_Send(
|
/* functions used by the MS/TP state machine to put or get data */
|
||||||
volatile struct mstp_port_struct_t *mstp_port,
|
/* FIXME: developer must implement these in their DLMSTP module */
|
||||||
|
|
||||||
|
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 */
|
unsigned timeout); /* milliseconds to wait for a packet */
|
||||||
/* for the MS/TP state machine to use for getting the reply for
|
/* for the MS/TP state machine to use for getting the reply for
|
||||||
Data-Expecting-Reply Frame */
|
Data-Expecting-Reply Frame */
|
||||||
/* Return: amount of PDU data */
|
/* Return: amount of PDU data */
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
uint16_t MSTP_Get_Reply(
|
uint16_t MSTP_Get_Reply(struct mstp_port_struct_t *mstp_port,
|
||||||
volatile struct mstp_port_struct_t *mstp_port,
|
|
||||||
unsigned timeout); /* milliseconds to wait for a packet */
|
unsigned timeout); /* milliseconds to wait for a packet */
|
||||||
|
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
void MSTP_Send_Frame(
|
void MSTP_Send_Frame(
|
||||||
volatile struct mstp_port_struct_t *mstp_port,
|
struct mstp_port_struct_t *mstp_port,
|
||||||
uint8_t * buffer,
|
uint8_t * buffer,
|
||||||
uint16_t nbytes);
|
uint16_t nbytes);
|
||||||
|
|
||||||
|
|||||||
@@ -1,26 +1,26 @@
|
|||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
|
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
* a copy of this software and associated documentation files (the
|
* a copy of this software and associated documentation files (the
|
||||||
* "Software"), to deal in the Software without restriction, including
|
* "Software"), to deal in the Software without restriction, including
|
||||||
* without limitation the rights to use, copy, modify, merge, publish,
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
* permit persons to whom the Software is furnished to do so, subject to
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
* the following conditions:
|
* the following conditions:
|
||||||
*
|
*
|
||||||
* The above copyright notice and this permission notice shall be included
|
* The above copyright notice and this permission notice shall be included
|
||||||
* in all copies or substantial portions of the Software.
|
* in all copies or substantial portions of the Software.
|
||||||
*
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
#ifndef MSTPDEF_H
|
#ifndef MSTPDEF_H
|
||||||
#define MSTPDEF_H
|
#define MSTPDEF_H
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
/* The value 255 is used to denote broadcast when used as a */
|
/* The value 255 is used to denote broadcast when used as a */
|
||||||
/* destination address but is not allowed as a value for a station. */
|
/* destination address but is not allowed as a value for a station. */
|
||||||
/* Station addresses for master nodes can be 0-127. */
|
/* Station addresses for master nodes can be 0-127. */
|
||||||
/* Station addresses for slave nodes can be 127-254. */
|
/* Station addresses for slave nodes can be 0-254. */
|
||||||
#define MSTP_BROADCAST_ADDRESS 255
|
#define MSTP_BROADCAST_ADDRESS 255
|
||||||
|
|
||||||
/* MS/TP Frame Type */
|
/* MS/TP Frame Type */
|
||||||
@@ -52,15 +52,23 @@
|
|||||||
/* These frames are available to vendors as proprietary (non-BACnet) frames. */
|
/* These frames are available to vendors as proprietary (non-BACnet) frames. */
|
||||||
/* The first two octets of the Data field shall specify the unique vendor */
|
/* The first two octets of the Data field shall specify the unique vendor */
|
||||||
/* identification code, most significant octet first, for the type of */
|
/* identification code, most significant octet first, for the type of */
|
||||||
/* vendor-proprietary frame to be conveyed. The length of the data portion */
|
/* vendor-proprietary frame to be conveyed. */
|
||||||
/* of a Proprietary frame shall be in the range of 2 to 501 octets. */
|
|
||||||
#define FRAME_TYPE_PROPRIETARY_MIN 128
|
#define FRAME_TYPE_PROPRIETARY_MIN 128
|
||||||
#define FRAME_TYPE_PROPRIETARY_MAX 255
|
#define FRAME_TYPE_PROPRIETARY_MAX 255
|
||||||
/* The initial CRC16 checksum value */
|
/* The initial CRC16 checksum value */
|
||||||
#define CRC16_INITIAL_VALUE (0xFFFF)
|
#define CRC16_INITIAL_VALUE (0xFFFF)
|
||||||
#define CRC32K_INITIAL_VALUE (0xFFFFFFFF)
|
#define CRC32K_INITIAL_VALUE (0xFFFFFFFF)
|
||||||
#define CRC32K_RESIDUE (0x0843323B)
|
#define CRC32K_RESIDUE (0x0843323B)
|
||||||
|
/* frame specific data */
|
||||||
#define MSTP_PREAMBLE_X55 (0x55)
|
#define MSTP_PREAMBLE_X55 (0x55)
|
||||||
|
/* The length of the data portion of a Test_Request, Test_Response,
|
||||||
|
BACnet Data Expecting Reply, or BACnet Data Not Expecting Reply frame
|
||||||
|
may range from 0 to 501 octets.
|
||||||
|
The length of the data portion of a proprietary frame shall
|
||||||
|
be in the range of 2 to 501 octets.*/
|
||||||
|
#define MSTP_FRAME_NPDU_MAX 501
|
||||||
|
/* COBS-encoded frames data parameter length is between
|
||||||
|
502 and 1497 octets, inclusive */
|
||||||
#define MSTP_EXTENDED_FRAME_NPDU_MAX 1497
|
#define MSTP_EXTENDED_FRAME_NPDU_MAX 1497
|
||||||
|
|
||||||
/* receive FSM states */
|
/* receive FSM states */
|
||||||
@@ -85,6 +93,16 @@ typedef enum {
|
|||||||
MSTP_MASTER_STATE_ANSWER_DATA_REQUEST = 8
|
MSTP_MASTER_STATE_ANSWER_DATA_REQUEST = 8
|
||||||
} MSTP_MASTER_STATE;
|
} MSTP_MASTER_STATE;
|
||||||
|
|
||||||
|
/* MSTP zero config FSM states */
|
||||||
|
typedef enum MSTP_Zero_Config_State {
|
||||||
|
MSTP_ZERO_CONFIG_STATE_INIT = 0,
|
||||||
|
MSTP_ZERO_CONFIG_STATE_IDLE = 1,
|
||||||
|
MSTP_ZERO_CONFIG_STATE_LURK = 2,
|
||||||
|
MSTP_ZERO_CONFIG_STATE_CLAIM = 3,
|
||||||
|
MSTP_ZERO_CONFIG_STATE_CONFIRM = 4,
|
||||||
|
MSTP_ZERO_CONFIG_STATE_USE = 5
|
||||||
|
} MSTP_ZERO_CONFIG_STATE;
|
||||||
|
|
||||||
/* The time without a DataAvailable or ReceiveError event before declaration */
|
/* The time without a DataAvailable or ReceiveError event before declaration */
|
||||||
/* of loss of token: 500 milliseconds. */
|
/* of loss of token: 500 milliseconds. */
|
||||||
#define Tno_token 500
|
#define Tno_token 500
|
||||||
@@ -105,6 +123,22 @@ typedef enum {
|
|||||||
/* is executed: 50. */
|
/* is executed: 50. */
|
||||||
#define Npoll 50
|
#define Npoll 50
|
||||||
|
|
||||||
|
/* The minimum number of polls received before a zero-config address */
|
||||||
|
/* is claimed: 8. */
|
||||||
|
#define Nmin_poll 8
|
||||||
|
|
||||||
|
/* The first zero-config address: 64 */
|
||||||
|
#define Nmin_poll_station 64
|
||||||
|
|
||||||
|
/* The last zero-config address: 127 */
|
||||||
|
#define Nmax_poll_station 127
|
||||||
|
|
||||||
|
/* The number of zero-config station poll slots: 64 */
|
||||||
|
#define Nmax_poll_slot 64
|
||||||
|
|
||||||
|
/* The last master node address: 127 */
|
||||||
|
#define Nmax_master_station 127
|
||||||
|
|
||||||
/* The number of retries on sending Token: 1. */
|
/* The number of retries on sending Token: 1. */
|
||||||
#define Nretry_token 1
|
#define Nretry_token 1
|
||||||
|
|
||||||
@@ -126,6 +160,15 @@ typedef enum {
|
|||||||
/* 15 milliseconds. */
|
/* 15 milliseconds. */
|
||||||
#define Tusage_delay 15
|
#define Tusage_delay 15
|
||||||
|
|
||||||
|
/* The minimum number of DataAvailable or ReceiveError events that must be */
|
||||||
|
/* seen by a receiving node in order to declare the line "active": 4. */
|
||||||
|
#define Nmin_octets 4
|
||||||
|
|
||||||
|
#define DEFAULT_Tframe_abort 95
|
||||||
|
#define DEFAULT_Treply_delay 245
|
||||||
|
#define DEFAULT_Treply_timeout 250
|
||||||
|
#define DEFAULT_Tusage_timeout 35
|
||||||
|
|
||||||
#define DEFAULT_MAX_INFO_FRAMES 1
|
#define DEFAULT_MAX_INFO_FRAMES 1
|
||||||
#define DEFAULT_MAX_MASTER 127
|
#define DEFAULT_MAX_MASTER 127
|
||||||
#define DEFAULT_MAC_ADDRESS 127
|
#define DEFAULT_MAC_ADDRESS 127
|
||||||
@@ -134,7 +177,6 @@ typedef enum {
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|||||||
@@ -87,3 +87,18 @@ const char *mstptext_frame_type(unsigned index)
|
|||||||
return indtext_by_index_split_default(mstp_frame_type_text, index,
|
return indtext_by_index_split_default(mstp_frame_type_text, index,
|
||||||
FRAME_TYPE_PROPRIETARY_MIN, "UNKNOWN", "PROPRIETARY");
|
FRAME_TYPE_PROPRIETARY_MIN, "UNKNOWN", "PROPRIETARY");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static INDTEXT_DATA mstp_zero_config_state_text[] = {
|
||||||
|
{ MSTP_ZERO_CONFIG_STATE_INIT, "INIT" },
|
||||||
|
{ MSTP_ZERO_CONFIG_STATE_IDLE, "IDLE" },
|
||||||
|
{ MSTP_ZERO_CONFIG_STATE_LURK, "LURK" },
|
||||||
|
{ MSTP_ZERO_CONFIG_STATE_CLAIM, "CLAIM" },
|
||||||
|
{ MSTP_ZERO_CONFIG_STATE_CONFIRM, "CONFIRM" },
|
||||||
|
{ MSTP_ZERO_CONFIG_STATE_USE, "USE" },
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *mstptext_zero_config_state(unsigned index)
|
||||||
|
{
|
||||||
|
return indtext_by_index_default(mstp_zero_config_state_text, index, "unknown");
|
||||||
|
}
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ extern "C" {
|
|||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
const char *mstptext_frame_type(
|
const char *mstptext_frame_type(
|
||||||
unsigned index);
|
unsigned index);
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
const char *mstptext_zero_config_state(
|
||||||
|
unsigned index);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,6 +158,7 @@ list(APPEND testdirs
|
|||||||
bacnet/datalink/cobs
|
bacnet/datalink/cobs
|
||||||
bacnet/datalink/crc
|
bacnet/datalink/crc
|
||||||
bacnet/datalink/bvlc
|
bacnet/datalink/bvlc
|
||||||
|
bacnet/datalink/mstp
|
||||||
)
|
)
|
||||||
|
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|||||||
@@ -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