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:
|
||||||
|
|||||||
+89
-114
@@ -41,7 +41,7 @@ int dlmstp_send_pdu(BACNET_ADDRESS *dest,
|
|||||||
{
|
{
|
||||||
int bytes_sent = 0;
|
int bytes_sent = 0;
|
||||||
unsigned i = 0; /* loop counter */
|
unsigned i = 0; /* loop counter */
|
||||||
struct dlmstp_user_data_t *port = NULL;
|
struct dlmstp_user_data_t *user = NULL;
|
||||||
struct dlmstp_packet *pkt;
|
struct dlmstp_packet *pkt;
|
||||||
|
|
||||||
if (!MSTP_Port) {
|
if (!MSTP_Port) {
|
||||||
@@ -50,8 +50,8 @@ int dlmstp_send_pdu(BACNET_ADDRESS *dest,
|
|||||||
if (!MSTP_Port->UserData) {
|
if (!MSTP_Port->UserData) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
port = MSTP_Port->UserData;
|
user = MSTP_Port->UserData;
|
||||||
pkt = (struct dlmstp_packet *)(void *)Ringbuf_Data_Peek(&port->PDU_Queue);
|
pkt = (struct dlmstp_packet *)(void *)Ringbuf_Data_Peek(&user->PDU_Queue);
|
||||||
if (pkt && (pdu_len <= DLMSTP_MPDU_MAX)) {
|
if (pkt && (pdu_len <= DLMSTP_MPDU_MAX)) {
|
||||||
if (npdu_data->data_expecting_reply) {
|
if (npdu_data->data_expecting_reply) {
|
||||||
pkt->frame_type = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY;
|
pkt->frame_type = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY;
|
||||||
@@ -71,7 +71,7 @@ int dlmstp_send_pdu(BACNET_ADDRESS *dest,
|
|||||||
pkt->address.mac[0] = MSTP_BROADCAST_ADDRESS;
|
pkt->address.mac[0] = MSTP_BROADCAST_ADDRESS;
|
||||||
pkt->address.len = 0;
|
pkt->address.len = 0;
|
||||||
}
|
}
|
||||||
if (Ringbuf_Data_Put(&port->PDU_Queue, (uint8_t *)pkt)) {
|
if (Ringbuf_Data_Put(&user->PDU_Queue, (uint8_t *)pkt)) {
|
||||||
bytes_sent = pdu_len;
|
bytes_sent = pdu_len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -86,30 +86,30 @@ int dlmstp_send_pdu(BACNET_ADDRESS *dest,
|
|||||||
* @return amount of PDU data
|
* @return amount of PDU data
|
||||||
*/
|
*/
|
||||||
uint16_t MSTP_Get_Send(
|
uint16_t MSTP_Get_Send(
|
||||||
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
||||||
{
|
{
|
||||||
uint16_t pdu_len = 0;
|
uint16_t pdu_len = 0;
|
||||||
struct dlmstp_packet *pkt;
|
struct dlmstp_packet *pkt;
|
||||||
struct dlmstp_user_data_t *port;
|
struct dlmstp_user_data_t *user;
|
||||||
|
|
||||||
if (!mstp_port) {
|
if (!mstp_port) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
port = (struct dlmstp_user_data_t *)mstp_port->UserData;
|
user = (struct dlmstp_user_data_t *)mstp_port->UserData;
|
||||||
if (!port) {
|
if (!user) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (Ringbuf_Empty(&port->PDU_Queue)) {
|
if (Ringbuf_Empty(&user->PDU_Queue)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* look at next PDU in queue without removing it */
|
/* look at next PDU in queue without removing it */
|
||||||
pkt = (struct dlmstp_packet *)(void *)Ringbuf_Peek(&port->PDU_Queue);
|
pkt = (struct dlmstp_packet *)(void *)Ringbuf_Peek(&user->PDU_Queue);
|
||||||
/* convert the PDU into the MSTP Frame */
|
/* convert the PDU into the MSTP Frame */
|
||||||
pdu_len = MSTP_Create_Frame(&mstp_port->OutputBuffer[0],
|
pdu_len = MSTP_Create_Frame(&mstp_port->OutputBuffer[0],
|
||||||
mstp_port->OutputBufferSize, pkt->frame_type, pkt->address.mac[0],
|
mstp_port->OutputBufferSize, pkt->frame_type, pkt->address.mac[0],
|
||||||
mstp_port->This_Station, &pkt->pdu[0], pkt->pdu_len);
|
mstp_port->This_Station, &pkt->pdu[0], pkt->pdu_len);
|
||||||
port->Statistics.transmit_pdu_counter++;
|
user->Statistics.transmit_pdu_counter++;
|
||||||
(void)Ringbuf_Pop(&port->PDU_Queue, NULL);
|
(void)Ringbuf_Pop(&user->PDU_Queue, NULL);
|
||||||
|
|
||||||
return pdu_len;
|
return pdu_len;
|
||||||
}
|
}
|
||||||
@@ -148,15 +148,12 @@ static bool MSTP_Compare_Data_Expecting_Reply(
|
|||||||
request_pdu = &mstp_port->InputBuffer[0];
|
request_pdu = &mstp_port->InputBuffer[0];
|
||||||
request_pdu_len = mstp_port->DataLength;
|
request_pdu_len = mstp_port->DataLength;
|
||||||
src_address = mstp_port->SourceAddress;
|
src_address = mstp_port->SourceAddress;
|
||||||
|
|
||||||
/* unused parameters */
|
|
||||||
request_pdu_len = request_pdu_len;
|
|
||||||
reply_pdu_len = reply_pdu_len;
|
|
||||||
/* decode the request data */
|
/* decode the request data */
|
||||||
request.address.mac[0] = src_address;
|
request.address.mac[0] = src_address;
|
||||||
request.address.mac_len = 1;
|
request.address.mac_len = 1;
|
||||||
offset = (uint16_t)npdu_decode(
|
offset = bacnet_npdu_decode(
|
||||||
&request_pdu[0], NULL, &request.address, &request.npdu_data);
|
&request_pdu[0], request_pdu_len, NULL, &request.address,
|
||||||
|
&request.npdu_data);
|
||||||
if (request.npdu_data.network_layer_message) {
|
if (request.npdu_data.network_layer_message) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -172,8 +169,9 @@ static bool MSTP_Compare_Data_Expecting_Reply(
|
|||||||
request.service_choice = request_pdu[offset + 3];
|
request.service_choice = request_pdu[offset + 3];
|
||||||
/* decode the reply data */
|
/* decode the reply data */
|
||||||
bacnet_address_copy(&reply.address, dest_address);
|
bacnet_address_copy(&reply.address, dest_address);
|
||||||
offset = (uint16_t)npdu_decode(
|
offset = bacnet_npdu_decode(
|
||||||
&reply_pdu[0], &reply.address, NULL, &reply.npdu_data);
|
&reply_pdu[0], reply_pdu_len, &reply.address, NULL,
|
||||||
|
&reply.npdu_data);
|
||||||
if (reply.npdu_data.network_layer_message) {
|
if (reply.npdu_data.network_layer_message) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -244,26 +242,26 @@ static bool MSTP_Compare_Data_Expecting_Reply(
|
|||||||
* @return number of bytes, or 0 if no reply is available
|
* @return number of bytes, or 0 if no reply is available
|
||||||
*/
|
*/
|
||||||
uint16_t MSTP_Get_Reply(
|
uint16_t MSTP_Get_Reply(
|
||||||
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
struct mstp_port_struct_t *mstp_port, unsigned timeout)
|
||||||
{
|
{
|
||||||
uint16_t pdu_len = 0;
|
uint16_t pdu_len = 0;
|
||||||
bool matched = false;
|
bool matched = false;
|
||||||
struct dlmstp_packet packet = { 0 };
|
struct dlmstp_packet packet = { 0 };
|
||||||
struct dlmstp_user_data_t *port = NULL;
|
struct dlmstp_user_data_t *user = NULL;
|
||||||
struct dlmstp_packet *pkt;
|
struct dlmstp_packet *pkt;
|
||||||
|
|
||||||
if (!mstp_port) {
|
if (!mstp_port) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
port = mstp_port->UserData;
|
user = mstp_port->UserData;
|
||||||
if (!port) {
|
if (!user) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (Ringbuf_Empty(&port->PDU_Queue)) {
|
if (Ringbuf_Empty(&user->PDU_Queue)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* look at next PDU in queue without removing it */
|
/* look at next PDU in queue without removing it */
|
||||||
pkt = (struct dlmstp_packet *)(void *)Ringbuf_Peek(&port->PDU_Queue);
|
pkt = (struct dlmstp_packet *)(void *)Ringbuf_Peek(&user->PDU_Queue);
|
||||||
/* is this the reply to the DER? */
|
/* is this the reply to the DER? */
|
||||||
matched = MSTP_Compare_Data_Expecting_Reply(
|
matched = MSTP_Compare_Data_Expecting_Reply(
|
||||||
mstp_port, pkt->pdu, pkt->pdu_len, &pkt->address);
|
mstp_port, pkt->pdu, pkt->pdu_len, &pkt->address);
|
||||||
@@ -274,8 +272,8 @@ uint16_t MSTP_Get_Reply(
|
|||||||
pdu_len = MSTP_Create_Frame(&mstp_port->OutputBuffer[0],
|
pdu_len = MSTP_Create_Frame(&mstp_port->OutputBuffer[0],
|
||||||
mstp_port->OutputBufferSize, pkt->frame_type, packet.address.mac[0],
|
mstp_port->OutputBufferSize, pkt->frame_type, packet.address.mac[0],
|
||||||
mstp_port->This_Station, &pkt->pdu[0], pkt->pdu_len);
|
mstp_port->This_Station, &pkt->pdu[0], pkt->pdu_len);
|
||||||
port->Statistics.transmit_pdu_counter++;
|
user->Statistics.transmit_pdu_counter++;
|
||||||
(void)Ringbuf_Pop(&port->PDU_Queue, NULL);
|
(void)Ringbuf_Pop(&user->PDU_Queue, NULL);
|
||||||
|
|
||||||
return pdu_len;
|
return pdu_len;
|
||||||
}
|
}
|
||||||
@@ -286,70 +284,48 @@ uint16_t MSTP_Get_Reply(
|
|||||||
* @param buffer - buffer to send
|
* @param buffer - buffer to send
|
||||||
* @param nbytes - number of bytes of data to send
|
* @param nbytes - number of bytes of data to send
|
||||||
*/
|
*/
|
||||||
void MSTP_Send_Frame(volatile struct mstp_port_struct_t *mstp_port,
|
void MSTP_Send_Frame(struct mstp_port_struct_t *mstp_port,
|
||||||
uint8_t *buffer,
|
uint8_t *buffer,
|
||||||
uint16_t nbytes)
|
uint16_t nbytes)
|
||||||
{
|
{
|
||||||
struct dlmstp_user_data_t *port;
|
struct dlmstp_user_data_t *user;
|
||||||
struct dlmstp_rs485_driver *driver;
|
struct dlmstp_rs485_driver *driver;
|
||||||
|
|
||||||
if (!mstp_port) {
|
if (!mstp_port) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
port = mstp_port->UserData;
|
user = mstp_port->UserData;
|
||||||
if (!port) {
|
if (!user) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
driver = port->RS485_Driver;
|
driver = user->RS485_Driver;
|
||||||
if (!driver) {
|
if (!driver) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
driver->send(buffer, nbytes);
|
driver->send(buffer, nbytes);
|
||||||
port->Statistics.transmit_frame_counter++;
|
user->Statistics.transmit_frame_counter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief MS/TP state machine received a frame
|
* @brief MS/TP state machine received a frame
|
||||||
* @return number of bytes queued, or 0 if unable to be queued
|
* @return number of bytes queued, or 0 if unable to be queued
|
||||||
*/
|
*/
|
||||||
uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port)
|
uint16_t MSTP_Put_Receive(struct mstp_port_struct_t *mstp_port)
|
||||||
{
|
{
|
||||||
struct dlmstp_user_data_t *port = NULL;
|
struct dlmstp_user_data_t *user = NULL;
|
||||||
|
|
||||||
if (!mstp_port) {
|
if (!mstp_port) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
port = mstp_port->UserData;
|
user = mstp_port->UserData;
|
||||||
if (!port) {
|
if (!user) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
port->ReceivePacketPending = true;
|
user->ReceivePacketPending = true;
|
||||||
|
|
||||||
return mstp_port->DataLength;
|
return mstp_port->DataLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Baud rate determines turnaround time.
|
|
||||||
* The minimum time after the end of the stop bit of the final octet of a
|
|
||||||
* received frame before a node may enable its EIA-485 driver: 40 bit times.
|
|
||||||
* At 9600 baud, 40 bit times would be about 4.166 milliseconds
|
|
||||||
* At 19200 baud, 40 bit times would be about 2.083 milliseconds
|
|
||||||
* At 38400 baud, 40 bit times would be about 1.041 milliseconds
|
|
||||||
* At 57600 baud, 40 bit times would be about 0.694 milliseconds
|
|
||||||
* At 76800 baud, 40 bit times would be about 0.520 milliseconds
|
|
||||||
* At 115200 baud, 40 bit times would be about 0.347 milliseconds
|
|
||||||
* 40 bits is 4 octets including a start and stop bit with each octet
|
|
||||||
* @param baud_rate - baud rate in bits per second
|
|
||||||
* @return: amount of whole milliseconds to wait 1..5
|
|
||||||
*/
|
|
||||||
static uint32_t dlmstp_receive_turnaround_time(uint32_t baud_rate)
|
|
||||||
{
|
|
||||||
if (baud_rate == 0) {
|
|
||||||
baud_rate = 9600;
|
|
||||||
}
|
|
||||||
return (1 + ((Tturnaround * 1000) / baud_rate));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Run the MS/TP state machines, and get packet if available
|
* @brief Run the MS/TP state machines, and get packet if available
|
||||||
* @param pdu - place to put PDU data for the caller
|
* @param pdu - place to put PDU data for the caller
|
||||||
@@ -363,11 +339,10 @@ uint16_t dlmstp_receive(
|
|||||||
{
|
{
|
||||||
uint16_t pdu_len = 0;
|
uint16_t pdu_len = 0;
|
||||||
uint8_t data_register = 0;
|
uint8_t data_register = 0;
|
||||||
struct dlmstp_user_data_t *port;
|
struct dlmstp_user_data_t *user;
|
||||||
struct dlmstp_rs485_driver *driver;
|
struct dlmstp_rs485_driver *driver;
|
||||||
uint16_t i;
|
uint16_t i;
|
||||||
uint32_t milliseconds;
|
uint32_t milliseconds;
|
||||||
uint32_t turnaround_milliseconds;
|
|
||||||
|
|
||||||
if (!MSTP_Port) {
|
if (!MSTP_Port) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -375,11 +350,11 @@ uint16_t dlmstp_receive(
|
|||||||
if (!MSTP_Port->UserData) {
|
if (!MSTP_Port->UserData) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
port = MSTP_Port->UserData;
|
user = MSTP_Port->UserData;
|
||||||
if (!port) {
|
if (!user) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
driver = port->RS485_Driver;
|
driver = user->RS485_Driver;
|
||||||
if (!driver) {
|
if (!driver) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -392,7 +367,6 @@ uint16_t dlmstp_receive(
|
|||||||
}
|
}
|
||||||
/* only do receive state machine while we don't have a frame */
|
/* only do receive state machine while we don't have a frame */
|
||||||
while ((MSTP_Port->ReceivedValidFrame == false) &&
|
while ((MSTP_Port->ReceivedValidFrame == false) &&
|
||||||
(MSTP_Port->ReceivedValidFrameNotForUs == false) &&
|
|
||||||
(MSTP_Port->ReceivedInvalidFrame == false)) {
|
(MSTP_Port->ReceivedInvalidFrame == false)) {
|
||||||
MSTP_Port->DataAvailable = driver->read(&data_register);
|
MSTP_Port->DataAvailable = driver->read(&data_register);
|
||||||
if (MSTP_Port->DataAvailable) {
|
if (MSTP_Port->DataAvailable) {
|
||||||
@@ -404,39 +378,35 @@ uint16_t dlmstp_receive(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (MSTP_Port->ReceivedValidFrameNotForUs ||
|
if (MSTP_Port->ReceivedValidFrame || MSTP_Port->ReceivedInvalidFrame) {
|
||||||
MSTP_Port->ReceivedValidFrame || MSTP_Port->ReceivedInvalidFrame) {
|
|
||||||
/* delay after reception before transmitting - per MS/TP spec */
|
/* delay after reception before transmitting - per MS/TP spec */
|
||||||
turnaround_milliseconds =
|
|
||||||
dlmstp_receive_turnaround_time(driver->baud_rate());
|
|
||||||
milliseconds = MSTP_Port->SilenceTimer(MSTP_Port);
|
milliseconds = MSTP_Port->SilenceTimer(MSTP_Port);
|
||||||
if (milliseconds < turnaround_milliseconds) {
|
if (milliseconds < MSTP_Port->Tturnaround_timeout) {
|
||||||
/* we're waiting; do nothing else */
|
/* we're waiting; do nothing else */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (MSTP_Port->ReceivedValidFrameNotForUs) {
|
|
||||||
MSTP_Port->ReceivedValidFrameNotForUs = false;
|
|
||||||
port->Statistics.receive_valid_frame_counter++;
|
|
||||||
}
|
|
||||||
if (MSTP_Port->ReceivedValidFrame) {
|
if (MSTP_Port->ReceivedValidFrame) {
|
||||||
port->Statistics.receive_valid_frame_counter++;
|
user->Statistics.receive_valid_frame_counter++;
|
||||||
}
|
}
|
||||||
if (MSTP_Port->ReceivedInvalidFrame) {
|
if (MSTP_Port->ReceivedInvalidFrame) {
|
||||||
port->Statistics.receive_invalid_frame_counter++;
|
user->Statistics.receive_invalid_frame_counter++;
|
||||||
}
|
}
|
||||||
if (MSTP_Port->receive_state == MSTP_RECEIVE_STATE_IDLE) {
|
if (MSTP_Port->receive_state == MSTP_RECEIVE_STATE_IDLE) {
|
||||||
/* only do master state machine while rx is idle */
|
/* only node state machines while rx is idle */
|
||||||
if (MSTP_Port->This_Station <= DEFAULT_MAX_MASTER) {
|
if (MSTP_Port->SlaveNodeEnabled) {
|
||||||
|
MSTP_Slave_Node_FSM(MSTP_Port);
|
||||||
|
} else if ((MSTP_Port->This_Station <= DEFAULT_MAX_MASTER) ||
|
||||||
|
MSTP_Port->ZeroConfigEnabled) {
|
||||||
while (MSTP_Master_Node_FSM(MSTP_Port)) {
|
while (MSTP_Master_Node_FSM(MSTP_Port)) {
|
||||||
/* do nothing while some states fast transition */
|
/* do nothing while some states fast transition */
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* see if there is a packet available */
|
/* see if there is a packet available */
|
||||||
if (port->ReceivePacketPending) {
|
if (user->ReceivePacketPending) {
|
||||||
port->ReceivePacketPending = false;
|
user->ReceivePacketPending = false;
|
||||||
port->Statistics.receive_pdu_counter++;
|
user->Statistics.receive_pdu_counter++;
|
||||||
pdu_len = MSTP_Port->DataLength;
|
pdu_len = MSTP_Port->DataLength;
|
||||||
if (pdu_len > max_pdu) {
|
if (pdu_len > max_pdu) {
|
||||||
/* PDU is too large */
|
/* PDU is too large */
|
||||||
@@ -498,11 +468,8 @@ void dlmstp_fill_bacnet_address(BACNET_ADDRESS *src, uint8_t mstp_address)
|
|||||||
*/
|
*/
|
||||||
void dlmstp_set_mac_address(uint8_t mac_address)
|
void dlmstp_set_mac_address(uint8_t mac_address)
|
||||||
{
|
{
|
||||||
/* Master Nodes can only have address 0-127 */
|
if (MSTP_Port) {
|
||||||
if (mac_address <= 127) {
|
MSTP_Port->This_Station = mac_address;
|
||||||
if (MSTP_Port) {
|
|
||||||
MSTP_Port->This_Station = mac_address;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -648,12 +615,12 @@ void dlmstp_get_broadcast_address(BACNET_ADDRESS *dest)
|
|||||||
bool dlmstp_send_pdu_queue_empty(void)
|
bool dlmstp_send_pdu_queue_empty(void)
|
||||||
{
|
{
|
||||||
bool status = false;
|
bool status = false;
|
||||||
struct dlmstp_user_data_t *port;
|
struct dlmstp_user_data_t *user;
|
||||||
|
|
||||||
if (MSTP_Port) {
|
if (MSTP_Port) {
|
||||||
port = MSTP_Port->UserData;
|
user = MSTP_Port->UserData;
|
||||||
if (port) {
|
if (user) {
|
||||||
status = Ringbuf_Empty(&port->PDU_Queue);
|
status = Ringbuf_Empty(&user->PDU_Queue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -667,12 +634,12 @@ bool dlmstp_send_pdu_queue_empty(void)
|
|||||||
bool dlmstp_send_pdu_queue_full(void)
|
bool dlmstp_send_pdu_queue_full(void)
|
||||||
{
|
{
|
||||||
bool status = false;
|
bool status = false;
|
||||||
struct dlmstp_user_data_t *port;
|
struct dlmstp_user_data_t *user;
|
||||||
|
|
||||||
if (MSTP_Port) {
|
if (MSTP_Port) {
|
||||||
port = MSTP_Port->UserData;
|
user = MSTP_Port->UserData;
|
||||||
if (port) {
|
if (user) {
|
||||||
status = Ringbuf_Full(&port->PDU_Queue);
|
status = Ringbuf_Full(&user->PDU_Queue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -686,7 +653,7 @@ bool dlmstp_send_pdu_queue_full(void)
|
|||||||
*/
|
*/
|
||||||
void dlmstp_set_baud_rate(uint32_t baud)
|
void dlmstp_set_baud_rate(uint32_t baud)
|
||||||
{
|
{
|
||||||
struct dlmstp_user_data_t *port;
|
struct dlmstp_user_data_t *user;
|
||||||
struct dlmstp_rs485_driver *driver;
|
struct dlmstp_rs485_driver *driver;
|
||||||
|
|
||||||
if (!MSTP_Port) {
|
if (!MSTP_Port) {
|
||||||
@@ -695,12 +662,20 @@ void dlmstp_set_baud_rate(uint32_t baud)
|
|||||||
if (!MSTP_Port->UserData) {
|
if (!MSTP_Port->UserData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
port = MSTP_Port->UserData;
|
user = MSTP_Port->UserData;
|
||||||
driver = port->RS485_Driver;
|
driver = user->RS485_Driver;
|
||||||
if (!driver) {
|
if (!driver) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
driver->baud_rate_set(baud);
|
if (driver->baud_rate_set(baud)) {
|
||||||
|
/* Tframe_abort=60 bit times, not to exceed 100 milliseconds.*/
|
||||||
|
if (MSTP_Port->Tframe_abort <= 7) {
|
||||||
|
/* within baud range, so auto-calculate range based on baud */
|
||||||
|
MSTP_Port->Tframe_abort = 1+((60*1000UL)/baud);
|
||||||
|
}
|
||||||
|
/* Tturnaround=40 bit times */
|
||||||
|
MSTP_Port->Tturnaround_timeout = 1 + ((Tturnaround * 1000) / baud);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -709,7 +684,7 @@ void dlmstp_set_baud_rate(uint32_t baud)
|
|||||||
*/
|
*/
|
||||||
uint32_t dlmstp_baud_rate(void)
|
uint32_t dlmstp_baud_rate(void)
|
||||||
{
|
{
|
||||||
struct dlmstp_user_data_t *port;
|
struct dlmstp_user_data_t *user;
|
||||||
struct dlmstp_rs485_driver *driver;
|
struct dlmstp_rs485_driver *driver;
|
||||||
|
|
||||||
if (!MSTP_Port) {
|
if (!MSTP_Port) {
|
||||||
@@ -718,8 +693,8 @@ uint32_t dlmstp_baud_rate(void)
|
|||||||
if (!MSTP_Port->UserData) {
|
if (!MSTP_Port->UserData) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
port = MSTP_Port->UserData;
|
user = MSTP_Port->UserData;
|
||||||
driver = port->RS485_Driver;
|
driver = user->RS485_Driver;
|
||||||
if (!driver) {
|
if (!driver) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -733,7 +708,7 @@ uint32_t dlmstp_baud_rate(void)
|
|||||||
*/
|
*/
|
||||||
void dlmstp_fill_statistics(struct dlmstp_statistics *statistics)
|
void dlmstp_fill_statistics(struct dlmstp_statistics *statistics)
|
||||||
{
|
{
|
||||||
struct dlmstp_user_data_t *port;
|
struct dlmstp_user_data_t *user;
|
||||||
|
|
||||||
if (!MSTP_Port) {
|
if (!MSTP_Port) {
|
||||||
return;
|
return;
|
||||||
@@ -741,12 +716,12 @@ void dlmstp_fill_statistics(struct dlmstp_statistics *statistics)
|
|||||||
if (!MSTP_Port->UserData) {
|
if (!MSTP_Port->UserData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
port = MSTP_Port->UserData;
|
user = MSTP_Port->UserData;
|
||||||
if (!port) {
|
if (!user) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (statistics) {
|
if (statistics) {
|
||||||
*statistics = port->Statistics;
|
*statistics = user->Statistics;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -821,18 +796,18 @@ void dlmstp_silence_reset(void *arg)
|
|||||||
*/
|
*/
|
||||||
bool dlmstp_init(char *ifname)
|
bool dlmstp_init(char *ifname)
|
||||||
{
|
{
|
||||||
struct dlmstp_user_data_t *user_data;
|
struct dlmstp_user_data_t *user;
|
||||||
MSTP_Port = (struct mstp_port_struct_t *)ifname;
|
MSTP_Port = (struct mstp_port_struct_t *)ifname;
|
||||||
if (MSTP_Port) {
|
if (MSTP_Port) {
|
||||||
MSTP_Port->SilenceTimer = dlmstp_silence_milliseconds;
|
MSTP_Port->SilenceTimer = dlmstp_silence_milliseconds;
|
||||||
MSTP_Port->SilenceTimerReset = dlmstp_silence_reset;
|
MSTP_Port->SilenceTimerReset = dlmstp_silence_reset;
|
||||||
user_data = (struct dlmstp_user_data_t *)MSTP_Port->UserData;
|
user = (struct dlmstp_user_data_t *)MSTP_Port->UserData;
|
||||||
if (user_data && !user_data->Initialized) {
|
if (user && !user->Initialized) {
|
||||||
Ringbuf_Init(&user_data->PDU_Queue,
|
Ringbuf_Init(&user->PDU_Queue,
|
||||||
(volatile uint8_t *)user_data->PDU_Buffer,
|
(volatile uint8_t *)user->PDU_Buffer,
|
||||||
sizeof(user_data->PDU_Buffer), DLMSTP_MAX_INFO_FRAMES);
|
sizeof(user->PDU_Buffer), DLMSTP_MAX_INFO_FRAMES);
|
||||||
MSTP_Init(MSTP_Port);
|
MSTP_Init(MSTP_Port);
|
||||||
user_data->Initialized = true;
|
user->Initialized = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+528
-215
File diff suppressed because it is too large
Load Diff
+209
-156
@@ -1,27 +1,27 @@
|
|||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
*
|
*
|
||||||
* Copyright (C) 2004 Steve Karg <skarg@users.sourceforge.net>
|
* Copyright (C) 2004 Steve Karg <skarg@users.sourceforge.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
* a copy of this software and associated documentation files (the
|
* a copy of this software and associated documentation files (the
|
||||||
* "Software"), to deal in the Software without restriction, including
|
* "Software"), to deal in the Software without restriction, including
|
||||||
* without limitation the rights to use, copy, modify, merge, publish,
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
* permit persons to whom the Software is furnished to do so, subject to
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
* the following conditions:
|
* the following conditions:
|
||||||
*
|
*
|
||||||
* The above copyright notice and this permission notice shall be included
|
* The above copyright notice and this permission notice shall be included
|
||||||
* in all copies or substantial portions of the Software.
|
* in all copies or substantial portions of the Software.
|
||||||
*
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*
|
*
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
#ifndef MSTP_H
|
#ifndef MSTP_H
|
||||||
#define MSTP_H
|
#define MSTP_H
|
||||||
|
|
||||||
@@ -30,6 +30,17 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "bacnet/bacnet_stack_exports.h"
|
#include "bacnet/bacnet_stack_exports.h"
|
||||||
#include "bacnet/datalink/mstpdef.h"
|
#include "bacnet/datalink/mstpdef.h"
|
||||||
|
#include "bacnet/config.h"
|
||||||
|
|
||||||
|
/* Repeater turnoff delay. The duration of a continuous logical one state */
|
||||||
|
/* at the active input port of an MS/TP repeater after which the repeater */
|
||||||
|
/* will enter the IDLE state: 29 bit times < Troff < 40 bit times. */
|
||||||
|
#ifndef Troff
|
||||||
|
#define Troff 30
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* size of the buffer used to send and validate a unique test request */
|
||||||
|
#define MSTP_UUID_SIZE 16
|
||||||
|
|
||||||
struct mstp_port_struct_t {
|
struct mstp_port_struct_t {
|
||||||
MSTP_RECEIVE_STATE receive_state;
|
MSTP_RECEIVE_STATE receive_state;
|
||||||
@@ -39,21 +50,21 @@ struct mstp_port_struct_t {
|
|||||||
/* A Boolean flag set to TRUE by the Receive State Machine */
|
/* A Boolean flag set to TRUE by the Receive State Machine */
|
||||||
/* if an error is detected during the reception of a frame. */
|
/* if an error is detected during the reception of a frame. */
|
||||||
/* Set to FALSE by the Master or Slave Node state machine. */
|
/* Set to FALSE by the Master or Slave Node state machine. */
|
||||||
unsigned ReceiveError:1;
|
unsigned ReceiveError : 1;
|
||||||
/* There is data in the buffer */
|
/* There is data in the buffer */
|
||||||
unsigned DataAvailable:1;
|
unsigned DataAvailable : 1;
|
||||||
unsigned ReceivedInvalidFrame:1;
|
unsigned ReceivedInvalidFrame : 1;
|
||||||
/* A Boolean flag set to TRUE by the Receive State Machine */
|
/* A Boolean flag set to TRUE by the Receive State Machine */
|
||||||
/* if a valid frame is received. */
|
/* if a valid frame is received. */
|
||||||
/* Set to FALSE by the Master or Slave Node state machine. */
|
/* Set to FALSE by the Master or Slave Node state machine. */
|
||||||
unsigned ReceivedValidFrame:1;
|
unsigned ReceivedValidFrame : 1;
|
||||||
/* A Boolean flag set to TRUE by the Receive State Machine */
|
/* A Boolean flag set to TRUE by the master machine if this node is the
|
||||||
/* if a valid frame is received but it is not addressed to us. */
|
only known master node. */
|
||||||
/* Set to FALSE by the Master or Slave Node state machine. */
|
unsigned SoleMaster : 1;
|
||||||
unsigned ReceivedValidFrameNotForUs:1;
|
/* A Boolean flag set to TRUE if this node is a slave node */
|
||||||
/* A Boolean flag set to TRUE by the master machine if this node is the */
|
unsigned SlaveNodeEnabled : 1;
|
||||||
/* only known master node. */
|
/* A Boolean flag set to TRUE if this node is using a ZeroConfig address */
|
||||||
unsigned SoleMaster:1;
|
unsigned ZeroConfigEnabled : 1;
|
||||||
/* stores the latest received data */
|
/* stores the latest received data */
|
||||||
uint8_t DataRegister;
|
uint8_t DataRegister;
|
||||||
/* Used to accumulate the CRC on the data field of a frame. */
|
/* Used to accumulate the CRC on the data field of a frame. */
|
||||||
@@ -65,185 +76,227 @@ struct mstp_port_struct_t {
|
|||||||
uint16_t DataLength;
|
uint16_t DataLength;
|
||||||
/* Used to store the destination address of a received frame. */
|
/* Used to store the destination address of a received frame. */
|
||||||
uint8_t DestinationAddress;
|
uint8_t DestinationAddress;
|
||||||
/* Used to count the number of received octets or errors. */
|
/* Used to count the number of received octets or errors.
|
||||||
/* This is used in the detection of link activity. */
|
This is used in the detection of link activity.
|
||||||
/* Compared to Nmin_octets */
|
Compared to Nmin_octets */
|
||||||
uint8_t EventCount;
|
uint8_t EventCount;
|
||||||
/* Used to store the frame type of a received frame. */
|
/* Used to store the frame type of a received frame. */
|
||||||
uint8_t FrameType;
|
uint8_t FrameType;
|
||||||
/* The number of frames sent by this node during a single token hold. */
|
/* The number of frames sent by this node during a single token hold.
|
||||||
/* When this counter reaches the value Nmax_info_frames, the node must */
|
When this counter reaches the value Nmax_info_frames, the node must */
|
||||||
/* pass the token. */
|
/* pass the token. */
|
||||||
uint8_t FrameCount;
|
uint8_t FrameCount;
|
||||||
/* Used to accumulate the CRC on the header of a frame. */
|
/* Used to accumulate the CRC on the header of a frame. */
|
||||||
uint8_t HeaderCRC;
|
uint8_t HeaderCRC;
|
||||||
/* Used to store the actual CRC from the header. */
|
/* Used to store the actual CRC from the header. */
|
||||||
uint8_t HeaderCRCActual;
|
uint8_t HeaderCRCActual;
|
||||||
/* Used as an index by the Receive State Machine, up to a maximum value of */
|
/* Used as an index by the Receive State Machine,
|
||||||
/* InputBufferSize. */
|
up to a maximum value of InputBufferSize. */
|
||||||
uint32_t Index;
|
uint32_t Index;
|
||||||
/* An array of octets, used to store octets as they are received. */
|
/* An array of octets, used to store octets as they are received.
|
||||||
/* InputBuffer is indexed from 0 to InputBufferSize-1. */
|
InputBuffer is indexed from 0 to InputBufferSize-1. */
|
||||||
/* The maximum size of a frame is 501 octets. */
|
/* Note: assign this to an actual array of bytes! */
|
||||||
/* FIXME: assign this to an actual array of bytes! */
|
|
||||||
/* Note: the buffer is designed as a pointer since some compilers
|
/* Note: the buffer is designed as a pointer since some compilers
|
||||||
and microcontroller architectures have limits as to places to
|
and microcontroller architectures have limits as to places to
|
||||||
hold contiguous memory. */
|
hold contiguous memory. */
|
||||||
uint8_t *InputBuffer;
|
uint8_t *InputBuffer;
|
||||||
uint16_t InputBufferSize;
|
uint16_t InputBufferSize;
|
||||||
/* "Next Station," the MAC address of the node to which This Station passes */
|
/* "Next Station," the MAC address of the node to which
|
||||||
/* the token. If the Next_Station is unknown, Next_Station shall be equal to */
|
This Station passes */
|
||||||
|
/* the token. If the Next_Station is unknown, Next_Station
|
||||||
|
shall be equal to */
|
||||||
/* This_Station. */
|
/* This_Station. */
|
||||||
uint8_t Next_Station;
|
uint8_t Next_Station;
|
||||||
/* "Poll Station," the MAC address of the node to which This Station last */
|
/* "Poll Station," the MAC address of the node to which This Station last
|
||||||
/* sent a Poll For Master. This is used during token maintenance. */
|
sent a Poll For Master. This is used during token maintenance. */
|
||||||
uint8_t Poll_Station;
|
uint8_t Poll_Station;
|
||||||
/* A counter of transmission retries used for Token and Poll For Master */
|
/* A counter of transmission retries used for Token and Poll For Master
|
||||||
/* transmission. */
|
transmission. */
|
||||||
unsigned RetryCount;
|
unsigned RetryCount;
|
||||||
/* A timer with nominal 5 millisecond resolution used to measure and */
|
/* A timer with nominal 5 millisecond resolution used to measure
|
||||||
/* generate silence on the medium between octets. It is incremented by a */
|
and generate silence on the medium between octets. It is
|
||||||
/* timer process and is cleared by the Receive State Machine when activity */
|
incremented by a timer process and is cleared by the Receive
|
||||||
/* is detected and by the SendFrame procedure as each octet is transmitted. */
|
State Machine when activity is detected and by the SendFrame
|
||||||
/* Since the timer resolution is limited and the timer is not necessarily */
|
procedure as each octet is transmitted. */
|
||||||
/* synchronized to other machine events, a timer value of N will actually */
|
/* Since the timer resolution is limited and the timer is not necessarily
|
||||||
/* denote intervals between N-1 and N */
|
synchronized to other machine events, a timer value of N will actually
|
||||||
|
denote intervals between N-1 and N */
|
||||||
/* Note: done here as functions - put into timer task or ISR
|
/* Note: done here as functions - put into timer task or ISR
|
||||||
so that you can be atomic on 8 bit microcontrollers */
|
so that you can be atomic on 8 bit microcontrollers */
|
||||||
uint32_t(
|
uint32_t (*SilenceTimer)(void *pArg);
|
||||||
*SilenceTimer) (
|
void (*SilenceTimerReset)(void *pArg);
|
||||||
void *pArg);
|
|
||||||
void (
|
|
||||||
*SilenceTimerReset) (
|
|
||||||
void *pArg);
|
|
||||||
|
|
||||||
/* A timer used to measure and generate Reply Postponed frames. It is */
|
/* A timer used to measure and generate Reply Postponed frames. It is
|
||||||
/* incremented by a timer process and is cleared by the Master Node State */
|
incremented by a timer process and is cleared by the Master Node State
|
||||||
/* Machine when a Data Expecting Reply Answer activity is completed. */
|
Machine when a Data Expecting Reply Answer activity is completed.
|
||||||
/* note: we always send a reply postponed since a message other than
|
note: we always send a reply postponed since a message other than
|
||||||
the reply may be in the transmit queue */
|
the reply may be in the transmit queue */
|
||||||
/* uint16_t ReplyPostponedTimer; */
|
/* uint16_t ReplyPostponedTimer; */
|
||||||
|
|
||||||
/* Used to store the Source Address of a received frame. */
|
/* Used to store the Source Address of a received frame. */
|
||||||
uint8_t SourceAddress;
|
uint8_t SourceAddress;
|
||||||
|
|
||||||
/* The number of tokens received by this node. When this counter reaches the */
|
/* The number of tokens received by this node. When this counter
|
||||||
/* value Npoll, the node polls the address range between TS and NS for */
|
reaches the value Npoll, the node polls the address range between
|
||||||
/* additional master nodes. TokenCount is set to zero at the end of the */
|
TS and NS for additional master nodes. TokenCount is set to zero
|
||||||
/* polling process. */
|
at the end of the polling process. */
|
||||||
unsigned TokenCount;
|
unsigned TokenCount;
|
||||||
|
|
||||||
/* "This Station," the MAC address of this node. TS is generally read from a */
|
/* "This Station," the MAC address of this node. TS is generally read from a
|
||||||
/* hardware DIP switch, or from nonvolatile memory. Valid values for TS are */
|
hardware DIP switch, or from nonvolatile memory. Valid values for TS are
|
||||||
/* 0 to 254. The value 255 is used to denote broadcast when used as a */
|
0 to 254. The value 255 is used to denote broadcast when used as a
|
||||||
/* destination address but is not allowed as a value for TS. */
|
destination address but is not allowed as a value for TS. */
|
||||||
uint8_t This_Station;
|
uint8_t This_Station;
|
||||||
|
|
||||||
/* This parameter represents the value of the Max_Info_Frames property of */
|
/* This parameter represents the value of the Max_Info_Frames property of
|
||||||
/* the node's Device object. The value of Max_Info_Frames specifies the */
|
the node's Device object. The value of Max_Info_Frames specifies the
|
||||||
/* maximum number of information frames the node may send before it must */
|
maximum number of information frames the node may send before it must
|
||||||
/* pass the token. Max_Info_Frames may have different values on different */
|
pass the token. Max_Info_Frames may have different values on different
|
||||||
/* nodes. This may be used to allocate more or less of the available link */
|
nodes. This may be used to allocate more or less of the available link
|
||||||
/* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */
|
bandwidth to particular nodes. If Max_Info_Frames is not writable in a
|
||||||
/* node, its value shall be 1. */
|
node, its value shall be 1.*/
|
||||||
uint8_t Nmax_info_frames;
|
uint8_t Nmax_info_frames;
|
||||||
|
|
||||||
/* This parameter represents the value of the Max_Master property of the */
|
/* This parameter represents the value of the Max_Master property of the
|
||||||
/* node's Device object. The value of Max_Master specifies the highest */
|
node's Device object. The value of Max_Master specifies the highest
|
||||||
/* allowable address for master nodes. The value of Max_Master shall be */
|
allowable address for master nodes. The value of Max_Master shall be
|
||||||
/* less than or equal to 127. If Max_Master is not writable in a node, */
|
less than or equal to 127. If Max_Master is not writable in a node,
|
||||||
/* its value shall be 127. */
|
its value shall be 127. */
|
||||||
uint8_t Nmax_master;
|
uint8_t Nmax_master;
|
||||||
|
|
||||||
/* An array of octets, used to store octets for transmitting */
|
/* An array of octets, used to store octets for transmitting
|
||||||
/* OutputBuffer is indexed from 0 to OutputBufferSize-1. */
|
OutputBuffer is indexed from 0 to OutputBufferSize-1.
|
||||||
/* The maximum size of a frame is 501 octets. */
|
FIXME: assign this to an actual array of bytes!
|
||||||
/* FIXME: assign this to an actual array of bytes! */
|
Note: the buffer is designed as a pointer since some compilers
|
||||||
/* Note: the buffer is designed as a pointer since some compilers
|
|
||||||
and microcontroller architectures have limits as to places to
|
and microcontroller architectures have limits as to places to
|
||||||
hold contiguous memory. */
|
hold contiguous memory. */
|
||||||
uint8_t *OutputBuffer;
|
uint8_t *OutputBuffer;
|
||||||
uint16_t OutputBufferSize;
|
uint16_t OutputBufferSize;
|
||||||
|
|
||||||
|
/* orderly transition tracking for zero-configuration node startup */
|
||||||
|
MSTP_ZERO_CONFIG_STATE Zero_Config_State;
|
||||||
|
/* the MAC address that this node is testing for MAC addresses
|
||||||
|
that are not in-use.*/
|
||||||
|
uint8_t Zero_Config_Station;
|
||||||
|
/* Used to count the number of received poll-for-master frames
|
||||||
|
This is used in the detection of addresses not in-use. */
|
||||||
|
uint8_t Poll_Count;
|
||||||
|
/* This parameter is random value 1..64, used to choose the poll slot */
|
||||||
|
uint8_t Npoll_slot;
|
||||||
|
/* UUID for storing the unique identifier for this node
|
||||||
|
used to send and validate a unique test request and response */
|
||||||
|
uint8_t UUID[MSTP_UUID_SIZE];
|
||||||
|
/* amount of silence time to wait, in milliseconds */
|
||||||
|
uint32_t Zero_Config_Silence;
|
||||||
|
/* This parameter tracks the highest polled station address.
|
||||||
|
The value of this parameter shall be less than or equal to 127.
|
||||||
|
In the absence of other fixed address nodes, this value shall be 127. */
|
||||||
|
uint8_t Zero_Config_Max_Master;
|
||||||
|
|
||||||
|
/* The minimum time without a DataAvailable or ReceiveError event within
|
||||||
|
a frame before a receiving node may discard the frame: 60 bit times.
|
||||||
|
Implementations may use larger values for this timeout,
|
||||||
|
not to exceed 100 milliseconds.
|
||||||
|
Tframe_abort = 1 + ((60*1000UL)/RS485_Baud); */
|
||||||
|
uint8_t Tframe_abort;
|
||||||
|
|
||||||
|
/* The maximum time a node may wait after reception of a frame that
|
||||||
|
expects a reply before sending the first octet of a reply or
|
||||||
|
Reply Postponed frame: 250 milliseconds. */
|
||||||
|
uint8_t Treply_delay;
|
||||||
|
|
||||||
|
/* The minimum time without a DataAvailable or ReceiveError event
|
||||||
|
that a node must wait for a station to begin replying to a
|
||||||
|
confirmed request: 255 milliseconds. (Implementations may use
|
||||||
|
larger values for this timeout, not to exceed 300 milliseconds.) */
|
||||||
|
uint16_t Treply_timeout;
|
||||||
|
|
||||||
|
/* The minimum time without a DataAvailable or ReceiveError event
|
||||||
|
that a node must wait for a remote node to begin using a token
|
||||||
|
or replying to a Poll For Master frame: 20 milliseconds.
|
||||||
|
(Implementations may use larger values for this timeout,
|
||||||
|
not to exceed 35 milliseconds.) */
|
||||||
|
uint8_t Tusage_timeout;
|
||||||
|
|
||||||
|
/* The minimum time after the end of the stop bit of the final
|
||||||
|
octet of a received frame before a node may enable its
|
||||||
|
EIA-485 driver: 40 bit times.
|
||||||
|
40 bits is 4 octets including a start and stop bit with each octet.
|
||||||
|
turnaround_time_milliseconds = (Tturnaround*1000UL)/RS485_Baud; */
|
||||||
|
uint8_t Tturnaround_timeout;
|
||||||
|
|
||||||
/*Platform-specific port data */
|
/*Platform-specific port data */
|
||||||
void *UserData;
|
void *UserData;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
void MSTP_Init(
|
void MSTP_Init(struct mstp_port_struct_t *mstp_port);
|
||||||
volatile struct mstp_port_struct_t *mstp_port);
|
BACNET_STACK_EXPORT
|
||||||
BACNET_STACK_EXPORT
|
void MSTP_Receive_Frame_FSM(struct mstp_port_struct_t *mstp_port);
|
||||||
void MSTP_Receive_Frame_FSM(
|
BACNET_STACK_EXPORT
|
||||||
volatile struct mstp_port_struct_t
|
bool MSTP_Master_Node_FSM(struct mstp_port_struct_t *mstp_port);
|
||||||
*mstp_port);
|
BACNET_STACK_EXPORT
|
||||||
BACNET_STACK_EXPORT
|
void MSTP_Slave_Node_FSM(struct mstp_port_struct_t *mstp_port);
|
||||||
bool MSTP_Master_Node_FSM(
|
|
||||||
volatile struct mstp_port_struct_t
|
|
||||||
*mstp_port);
|
|
||||||
BACNET_STACK_EXPORT
|
|
||||||
void MSTP_Slave_Node_FSM(
|
|
||||||
volatile struct mstp_port_struct_t *mstp_port);
|
|
||||||
|
|
||||||
/* returns true if line is active */
|
/* returns true if line is active */
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
bool MSTP_Line_Active(
|
bool MSTP_Line_Active(struct mstp_port_struct_t *mstp_port);
|
||||||
volatile struct mstp_port_struct_t *mstp_port);
|
|
||||||
|
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
uint16_t MSTP_Create_Frame(
|
uint16_t MSTP_Create_Frame(uint8_t *buffer,
|
||||||
uint8_t * buffer, /* where frame is loaded */
|
uint16_t buffer_len,
|
||||||
uint16_t buffer_len, /* amount of space available */
|
uint8_t frame_type,
|
||||||
uint8_t frame_type, /* type of frame to send - see defines */
|
uint8_t destination,
|
||||||
uint8_t destination, /* destination address */
|
uint8_t source,
|
||||||
uint8_t source, /* source address */
|
uint8_t *data,
|
||||||
uint8_t * data, /* any data to be sent - may be null */
|
uint16_t data_len);
|
||||||
uint16_t data_len); /* number of bytes of data (up to 501) */
|
|
||||||
|
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
void MSTP_Create_And_Send_Frame(
|
void MSTP_Create_And_Send_Frame(
|
||||||
volatile struct mstp_port_struct_t *mstp_port, /* port to send from */
|
struct mstp_port_struct_t *mstp_port,
|
||||||
uint8_t frame_type, /* type of frame to send - see defines */
|
uint8_t frame_type,
|
||||||
uint8_t destination, /* destination address */
|
uint8_t destination,
|
||||||
uint8_t source, /* source address */
|
uint8_t source,
|
||||||
uint8_t * data, /* any data to be sent - may be null */
|
uint8_t *data,
|
||||||
uint16_t data_len);
|
uint16_t data_len);
|
||||||
|
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
void MSTP_Fill_BACnet_Address(
|
void MSTP_Fill_BACnet_Address(BACNET_ADDRESS *src, uint8_t mstp_address);
|
||||||
BACNET_ADDRESS * src,
|
|
||||||
uint8_t mstp_address);
|
|
||||||
|
|
||||||
/* functions used by the MS/TP state machine to put or get data */
|
BACNET_STACK_EXPORT
|
||||||
/* FIXME: developer must implement these in their DLMSTP module */
|
void MSTP_Zero_Config_UUID_Init(struct mstp_port_struct_t *mstp_port);
|
||||||
|
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
uint16_t MSTP_Put_Receive(
|
void MSTP_Zero_Config_FSM(struct mstp_port_struct_t *mstp_port);
|
||||||
volatile struct mstp_port_struct_t *mstp_port);
|
|
||||||
|
|
||||||
/* for the MS/TP state machine to use for getting data to send */
|
/* functions used by the MS/TP state machine to put or get data */
|
||||||
/* Return: amount of PDU data */
|
/* FIXME: developer must implement these in their DLMSTP module */
|
||||||
BACNET_STACK_EXPORT
|
|
||||||
uint16_t MSTP_Get_Send(
|
|
||||||
volatile struct mstp_port_struct_t *mstp_port,
|
|
||||||
unsigned timeout); /* milliseconds to wait for a packet */
|
|
||||||
/* for the MS/TP state machine to use for getting the reply for
|
|
||||||
Data-Expecting-Reply Frame */
|
|
||||||
/* Return: amount of PDU data */
|
|
||||||
BACNET_STACK_EXPORT
|
|
||||||
uint16_t MSTP_Get_Reply(
|
|
||||||
volatile struct mstp_port_struct_t *mstp_port,
|
|
||||||
unsigned timeout); /* milliseconds to wait for a packet */
|
|
||||||
|
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
void MSTP_Send_Frame(
|
uint16_t MSTP_Put_Receive(
|
||||||
volatile struct mstp_port_struct_t *mstp_port,
|
struct mstp_port_struct_t *mstp_port);
|
||||||
uint8_t * buffer,
|
|
||||||
uint16_t nbytes);
|
/* for the MS/TP state machine to use for getting data to send */
|
||||||
|
/* Return: amount of PDU data */
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
uint16_t MSTP_Get_Send(struct mstp_port_struct_t *mstp_port,
|
||||||
|
unsigned timeout); /* milliseconds to wait for a packet */
|
||||||
|
/* for the MS/TP state machine to use for getting the reply for
|
||||||
|
Data-Expecting-Reply Frame */
|
||||||
|
/* Return: amount of PDU data */
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
uint16_t MSTP_Get_Reply(struct mstp_port_struct_t *mstp_port,
|
||||||
|
unsigned timeout); /* milliseconds to wait for a packet */
|
||||||
|
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
void MSTP_Send_Frame(
|
||||||
|
struct mstp_port_struct_t *mstp_port,
|
||||||
|
uint8_t * buffer,
|
||||||
|
uint16_t nbytes);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,26 @@
|
|||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
|
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
* a copy of this software and associated documentation files (the
|
* a copy of this software and associated documentation files (the
|
||||||
* "Software"), to deal in the Software without restriction, including
|
* "Software"), to deal in the Software without restriction, including
|
||||||
* without limitation the rights to use, copy, modify, merge, publish,
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
* permit persons to whom the Software is furnished to do so, subject to
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
* the following conditions:
|
* the following conditions:
|
||||||
*
|
*
|
||||||
* The above copyright notice and this permission notice shall be included
|
* The above copyright notice and this permission notice shall be included
|
||||||
* in all copies or substantial portions of the Software.
|
* in all copies or substantial portions of the Software.
|
||||||
*
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
#ifndef MSTPDEF_H
|
#ifndef MSTPDEF_H
|
||||||
#define MSTPDEF_H
|
#define MSTPDEF_H
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
/* The value 255 is used to denote broadcast when used as a */
|
/* The value 255 is used to denote broadcast when used as a */
|
||||||
/* destination address but is not allowed as a value for a station. */
|
/* destination address but is not allowed as a value for a station. */
|
||||||
/* Station addresses for master nodes can be 0-127. */
|
/* Station addresses for master nodes can be 0-127. */
|
||||||
/* Station addresses for slave nodes can be 127-254. */
|
/* Station addresses for slave nodes can be 0-254. */
|
||||||
#define MSTP_BROADCAST_ADDRESS 255
|
#define MSTP_BROADCAST_ADDRESS 255
|
||||||
|
|
||||||
/* MS/TP Frame Type */
|
/* MS/TP Frame Type */
|
||||||
@@ -52,15 +52,23 @@
|
|||||||
/* These frames are available to vendors as proprietary (non-BACnet) frames. */
|
/* These frames are available to vendors as proprietary (non-BACnet) frames. */
|
||||||
/* The first two octets of the Data field shall specify the unique vendor */
|
/* The first two octets of the Data field shall specify the unique vendor */
|
||||||
/* identification code, most significant octet first, for the type of */
|
/* identification code, most significant octet first, for the type of */
|
||||||
/* vendor-proprietary frame to be conveyed. The length of the data portion */
|
/* vendor-proprietary frame to be conveyed. */
|
||||||
/* of a Proprietary frame shall be in the range of 2 to 501 octets. */
|
|
||||||
#define FRAME_TYPE_PROPRIETARY_MIN 128
|
#define FRAME_TYPE_PROPRIETARY_MIN 128
|
||||||
#define FRAME_TYPE_PROPRIETARY_MAX 255
|
#define FRAME_TYPE_PROPRIETARY_MAX 255
|
||||||
/* The initial CRC16 checksum value */
|
/* The initial CRC16 checksum value */
|
||||||
#define CRC16_INITIAL_VALUE (0xFFFF)
|
#define CRC16_INITIAL_VALUE (0xFFFF)
|
||||||
#define CRC32K_INITIAL_VALUE (0xFFFFFFFF)
|
#define CRC32K_INITIAL_VALUE (0xFFFFFFFF)
|
||||||
#define CRC32K_RESIDUE (0x0843323B)
|
#define CRC32K_RESIDUE (0x0843323B)
|
||||||
|
/* frame specific data */
|
||||||
#define MSTP_PREAMBLE_X55 (0x55)
|
#define MSTP_PREAMBLE_X55 (0x55)
|
||||||
|
/* The length of the data portion of a Test_Request, Test_Response,
|
||||||
|
BACnet Data Expecting Reply, or BACnet Data Not Expecting Reply frame
|
||||||
|
may range from 0 to 501 octets.
|
||||||
|
The length of the data portion of a proprietary frame shall
|
||||||
|
be in the range of 2 to 501 octets.*/
|
||||||
|
#define MSTP_FRAME_NPDU_MAX 501
|
||||||
|
/* COBS-encoded frames data parameter length is between
|
||||||
|
502 and 1497 octets, inclusive */
|
||||||
#define MSTP_EXTENDED_FRAME_NPDU_MAX 1497
|
#define MSTP_EXTENDED_FRAME_NPDU_MAX 1497
|
||||||
|
|
||||||
/* receive FSM states */
|
/* receive FSM states */
|
||||||
@@ -85,6 +93,16 @@ typedef enum {
|
|||||||
MSTP_MASTER_STATE_ANSWER_DATA_REQUEST = 8
|
MSTP_MASTER_STATE_ANSWER_DATA_REQUEST = 8
|
||||||
} MSTP_MASTER_STATE;
|
} MSTP_MASTER_STATE;
|
||||||
|
|
||||||
|
/* MSTP zero config FSM states */
|
||||||
|
typedef enum MSTP_Zero_Config_State {
|
||||||
|
MSTP_ZERO_CONFIG_STATE_INIT = 0,
|
||||||
|
MSTP_ZERO_CONFIG_STATE_IDLE = 1,
|
||||||
|
MSTP_ZERO_CONFIG_STATE_LURK = 2,
|
||||||
|
MSTP_ZERO_CONFIG_STATE_CLAIM = 3,
|
||||||
|
MSTP_ZERO_CONFIG_STATE_CONFIRM = 4,
|
||||||
|
MSTP_ZERO_CONFIG_STATE_USE = 5
|
||||||
|
} MSTP_ZERO_CONFIG_STATE;
|
||||||
|
|
||||||
/* The time without a DataAvailable or ReceiveError event before declaration */
|
/* The time without a DataAvailable or ReceiveError event before declaration */
|
||||||
/* of loss of token: 500 milliseconds. */
|
/* of loss of token: 500 milliseconds. */
|
||||||
#define Tno_token 500
|
#define Tno_token 500
|
||||||
@@ -98,13 +116,29 @@ typedef enum {
|
|||||||
/* At 76800 baud, 40 bit times would be about 0.520 milliseconds */
|
/* At 76800 baud, 40 bit times would be about 0.520 milliseconds */
|
||||||
/* At 115200 baud, 40 bit times would be about 0.347 milliseconds */
|
/* At 115200 baud, 40 bit times would be about 0.347 milliseconds */
|
||||||
/* 40 bits is 4 octets including a start and stop bit with each octet */
|
/* 40 bits is 4 octets including a start and stop bit with each octet */
|
||||||
#define Tturnaround (40UL)
|
#define Tturnaround (40UL)
|
||||||
/* turnaround_time_milliseconds = (Tturnaround*1000UL)/RS485_Baud; */
|
/* turnaround_time_milliseconds = (Tturnaround*1000UL)/RS485_Baud; */
|
||||||
|
|
||||||
/* The number of tokens received or used before a Poll For Master cycle */
|
/* The number of tokens received or used before a Poll For Master cycle */
|
||||||
/* is executed: 50. */
|
/* is executed: 50. */
|
||||||
#define Npoll 50
|
#define Npoll 50
|
||||||
|
|
||||||
|
/* The minimum number of polls received before a zero-config address */
|
||||||
|
/* is claimed: 8. */
|
||||||
|
#define Nmin_poll 8
|
||||||
|
|
||||||
|
/* The first zero-config address: 64 */
|
||||||
|
#define Nmin_poll_station 64
|
||||||
|
|
||||||
|
/* The last zero-config address: 127 */
|
||||||
|
#define Nmax_poll_station 127
|
||||||
|
|
||||||
|
/* The number of zero-config station poll slots: 64 */
|
||||||
|
#define Nmax_poll_slot 64
|
||||||
|
|
||||||
|
/* The last master node address: 127 */
|
||||||
|
#define Nmax_master_station 127
|
||||||
|
|
||||||
/* The number of retries on sending Token: 1. */
|
/* The number of retries on sending Token: 1. */
|
||||||
#define Nretry_token 1
|
#define Nretry_token 1
|
||||||
|
|
||||||
@@ -126,6 +160,15 @@ typedef enum {
|
|||||||
/* 15 milliseconds. */
|
/* 15 milliseconds. */
|
||||||
#define Tusage_delay 15
|
#define Tusage_delay 15
|
||||||
|
|
||||||
|
/* The minimum number of DataAvailable or ReceiveError events that must be */
|
||||||
|
/* seen by a receiving node in order to declare the line "active": 4. */
|
||||||
|
#define Nmin_octets 4
|
||||||
|
|
||||||
|
#define DEFAULT_Tframe_abort 95
|
||||||
|
#define DEFAULT_Treply_delay 245
|
||||||
|
#define DEFAULT_Treply_timeout 250
|
||||||
|
#define DEFAULT_Tusage_timeout 35
|
||||||
|
|
||||||
#define DEFAULT_MAX_INFO_FRAMES 1
|
#define DEFAULT_MAX_INFO_FRAMES 1
|
||||||
#define DEFAULT_MAX_MASTER 127
|
#define DEFAULT_MAX_MASTER 127
|
||||||
#define DEFAULT_MAC_ADDRESS 127
|
#define DEFAULT_MAC_ADDRESS 127
|
||||||
@@ -134,7 +177,6 @@ typedef enum {
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|||||||
@@ -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