Updated MS/TP for the PIC project. Fixed some state transistions, and optimized to be able to return the token promptly.
This commit is contained in:
@@ -33,24 +33,105 @@
|
||||
#include "mstp.h"
|
||||
#include "dlmstp.h"
|
||||
#include "rs485.h"
|
||||
#include "npdu.h"
|
||||
#include "npdu.h"
|
||||
#include "eeprom.h"
|
||||
|
||||
// Number of MS/TP Packets Rx/Tx
|
||||
uint16_t MSTP_Packets = 0;
|
||||
|
||||
/* receive buffer */
|
||||
#pragma udata MSTPPortData
|
||||
#pragma udata MSTP_RxData
|
||||
static DLMSTP_PACKET Receive_Buffer;
|
||||
/* temp buffer for NPDU insertion */
|
||||
static uint8_t PDU_Buffer[MAX_MPDU];
|
||||
/* local MS/TP port data - shared with RS-485 */
|
||||
#pragma udata MSTP_PortData
|
||||
volatile struct mstp_port_struct_t MSTP_Port;
|
||||
#pragma udata
|
||||
|
||||
#define INCREMENT_AND_LIMIT_UINT16(x) {if (x < 0xFFFF) x++;}
|
||||
|
||||
// This defines the number of edit fields for this module
|
||||
#define MAX_EDIT_FIELD 1
|
||||
static uint8_t EditField = 0;
|
||||
/* *************************************************************************
|
||||
DESCRIPTION: This function handles incrementing or decrementing our
|
||||
EditField
|
||||
RETURN: none
|
||||
ALGORITHM: none
|
||||
NOTES: Pass a #>0 to increment #<0 to decrement
|
||||
*************************************************************************** */
|
||||
void dlmstp_SetEditField(
|
||||
signed char state) /* direction our editfield is moving */
|
||||
{
|
||||
if (state > 0)
|
||||
{
|
||||
if (++EditField > MAX_EDIT_FIELD)
|
||||
EditField = 0;
|
||||
}
|
||||
else if (state < 0)
|
||||
{
|
||||
if (EditField)
|
||||
EditField--;
|
||||
else
|
||||
EditField = MAX_EDIT_FIELD;
|
||||
}
|
||||
else
|
||||
EditField = 0;
|
||||
}
|
||||
|
||||
/* *************************************************************************
|
||||
DESCRIPTION: Gets the current edit field for this module
|
||||
RETURN: the current edit field
|
||||
ALGORITHM: none
|
||||
NOTES: none
|
||||
*************************************************************************** */
|
||||
uint8_t dlmstp_GetEditField(void)
|
||||
{
|
||||
return (EditField);
|
||||
}
|
||||
|
||||
void dlmstp_millisecond_timer(void)
|
||||
{
|
||||
INCREMENT_AND_LIMIT_UINT16(MSTP_Port.SilenceTimer);
|
||||
}
|
||||
|
||||
void dlmstp_reinit(void)
|
||||
{
|
||||
RS485_Reinit();
|
||||
dlmstp_set_my_address(DEFAULT_MAC_ADDRESS);
|
||||
dlmstp_set_max_info_frames(DEFAULT_MAX_INFO_FRAMES);
|
||||
dlmstp_set_max_master(DEFAULT_MAX_MASTER);
|
||||
}
|
||||
|
||||
void dlmstp_init(void)
|
||||
{
|
||||
{
|
||||
uint8_t data;
|
||||
|
||||
/* initialize buffer */
|
||||
Receive_Buffer.ready = false;
|
||||
Receive_Buffer.pdu_len = 0;
|
||||
/* initialize hardware */
|
||||
RS485_Initialize();
|
||||
MSTP_Init(&MSTP_Port, MSTP_Port.This_Station);
|
||||
RS485_Initialize();
|
||||
MSTP_Port.InputBuffer = &Receive_Buffer.pdu[0];
|
||||
MSTP_Init(&MSTP_Port);
|
||||
data = I2C_Read_Byte(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
EEPROM_MSTP_MAC_ADDR);
|
||||
if (data <= 127)
|
||||
MSTP_Port.This_Station = data;
|
||||
else
|
||||
dlmstp_set_my_address(DEFAULT_MAC_ADDRESS);
|
||||
data = I2C_Read_Byte(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
EEPROM_MSTP_MAX_MASTER_ADDR);
|
||||
if (data <= 127)
|
||||
MSTP_Port.Nmax_master = data;
|
||||
else
|
||||
dlmstp_set_max_master(DEFAULT_MAX_MASTER);
|
||||
MSTP_Port.Nmax_info_frames =
|
||||
I2C_Read_Byte(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
EEPROM_MSTP_MAX_INFO_FRAMES_ADDR);
|
||||
}
|
||||
|
||||
void dlmstp_cleanup(void)
|
||||
@@ -68,10 +149,11 @@ int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
unsigned npdu_len = 0;
|
||||
uint8_t frame_type = 0;
|
||||
uint8_t destination = 0; /* destination address */
|
||||
BACNET_ADDRESS src;
|
||||
BACNET_ADDRESS src;
|
||||
unsigned i = 0; /* loop counter */
|
||||
|
||||
if (MSTP_Port.TxReady == false) {
|
||||
if (npdu_data->confirmed_message)
|
||||
if (npdu_data->data_expecting_reply)
|
||||
MSTP_Port.TxFrameType = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY;
|
||||
else
|
||||
MSTP_Port.TxFrameType =
|
||||
@@ -81,72 +163,65 @@ int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
if (dest && dest->mac_len == 1) {
|
||||
destination = dest->mac[0];
|
||||
} else {
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "mstp: invalid destination MAC address!\n");
|
||||
#endif
|
||||
return -2;
|
||||
}
|
||||
dlmstp_get_my_address(&src);
|
||||
npdu_len = npdu_encode_pdu(&PDU_Buffer[0], dest, &src, npdu_data);
|
||||
if ((8 /* header len */ + npdu_len + pdu_len) > MAX_MPDU) {
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "mstp: PDU is too big to send!\n");
|
||||
#endif
|
||||
if ((8 /* header len */ + pdu_len) > MAX_MPDU) {
|
||||
return -4;
|
||||
}
|
||||
memmove(&PDU_Buffer[npdu_len], pdu, pdu_len);
|
||||
bytes_sent = MSTP_Create_Frame(
|
||||
(uint8_t *) & MSTP_Port.TxBuffer[0],
|
||||
sizeof(MSTP_Port.TxBuffer),
|
||||
MSTP_Port.TxFrameType,
|
||||
destination,
|
||||
MSTP_Port.This_Station, &PDU_Buffer[0], npdu_len + pdu_len);
|
||||
MSTP_Port.This_Station, pdu, pdu_len);
|
||||
MSTP_Port.TxLength = bytes_sent;
|
||||
MSTP_Port.TxReady = true;
|
||||
MSTP_Packets++;
|
||||
}
|
||||
|
||||
return bytes_sent;
|
||||
}
|
||||
|
||||
/* called about once a millisecond */
|
||||
void dlmstp_millisecond_timer(void)
|
||||
{
|
||||
MSTP_Millisecond_Timer(&MSTP_Port);
|
||||
}
|
||||
|
||||
/* returns the number of octets in the PDU, or zero on failure */
|
||||
/* This function is expecting to be polled. */
|
||||
uint16_t dlmstp_receive(BACNET_ADDRESS * src, /* source address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t max_pdu, /* amount of space available in the PDU */
|
||||
unsigned timeout)
|
||||
{
|
||||
uint16_t pdu_len = 0;
|
||||
|
||||
(void) timeout;
|
||||
|
||||
void dlmstp_task(void)
|
||||
{
|
||||
uint8_t bytes_remaining;
|
||||
bool received_frame;
|
||||
|
||||
/* only do receive state machine while we don't have a frame */
|
||||
if ((MSTP_Port.ReceivedValidFrame == false) &&
|
||||
(MSTP_Port.ReceivedInvalidFrame == false)) {
|
||||
RS485_Check_UART_Data(&MSTP_Port);
|
||||
MSTP_Receive_Frame_FSM(&MSTP_Port);
|
||||
(MSTP_Port.ReceivedInvalidFrame == false))
|
||||
{
|
||||
do {
|
||||
bytes_remaining = RS485_Check_UART_Data(&MSTP_Port);
|
||||
MSTP_Receive_Frame_FSM(&MSTP_Port);
|
||||
received_frame = MSTP_Port.ReceivedValidFrame ||
|
||||
MSTP_Port.ReceivedInvalidFrame;
|
||||
if (received_frame)
|
||||
break;
|
||||
} while (bytes_remaining);
|
||||
}
|
||||
/* only do master state machine while rx is idle */
|
||||
if (MSTP_Port.receive_state == MSTP_RECEIVE_STATE_IDLE) {
|
||||
while (MSTP_Master_Node_FSM(&MSTP_Port)) {};
|
||||
//MSTP_Master_Node_FSM(&MSTP_Port);
|
||||
}
|
||||
/* see if there is a packet available */
|
||||
if (Receive_Buffer.ready) {
|
||||
memmove(src, &Receive_Buffer.address,
|
||||
sizeof(Receive_Buffer.address));
|
||||
pdu_len = Receive_Buffer.pdu_len;
|
||||
memmove(&pdu[0], &Receive_Buffer.pdu[0], max_pdu);
|
||||
/* see if there is a packet available, and a place
|
||||
to put the reply (if necessary) and process it */
|
||||
if (Receive_Buffer.ready && !MSTP_Port.TxReady) {
|
||||
if (Receive_Buffer.pdu_len) {
|
||||
MSTP_Packets++;
|
||||
npdu_handler(
|
||||
&Receive_Buffer.address,
|
||||
&Receive_Buffer.pdu[0],
|
||||
Receive_Buffer.pdu_len);
|
||||
}
|
||||
Receive_Buffer.ready = false;
|
||||
}
|
||||
RS485_Process_Tx_Message();
|
||||
|
||||
return pdu_len;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void dlmstp_fill_bacnet_address(BACNET_ADDRESS * src, uint8_t mstp_address)
|
||||
{
|
||||
int i = 0;
|
||||
@@ -171,33 +246,30 @@ void dlmstp_fill_bacnet_address(BACNET_ADDRESS * src, uint8_t mstp_address)
|
||||
}
|
||||
|
||||
/* for the MS/TP state machine to use for putting received data */
|
||||
uint16_t dlmstp_put_receive(uint8_t src, /* source MS/TP address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t pdu_len)
|
||||
{
|
||||
if (Receive_Buffer.ready) {
|
||||
/* FIXME: what to do when we miss a message? */
|
||||
pdu_len = 0;
|
||||
} else if (pdu_len < sizeof(Receive_Buffer.pdu)) {
|
||||
dlmstp_fill_bacnet_address(&Receive_Buffer.address, src);
|
||||
Receive_Buffer.pdu_len = pdu_len;
|
||||
memmove(Receive_Buffer.pdu, pdu, pdu_len);
|
||||
Receive_Buffer.ready = true;
|
||||
} else {
|
||||
/* FIXME: message too large? */
|
||||
pdu_len = 0;
|
||||
}
|
||||
|
||||
return pdu_len;
|
||||
uint16_t dlmstp_put_receive(
|
||||
uint8_t src, /* source MS/TP address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t pdu_len) /* amount of PDU data */
|
||||
{
|
||||
/* PDU is already in the Receive_Buffer */
|
||||
dlmstp_fill_bacnet_address(&Receive_Buffer.address, src);
|
||||
Receive_Buffer.pdu_len = pdu_len;
|
||||
Receive_Buffer.ready = true;
|
||||
}
|
||||
|
||||
void dlmstp_set_my_address(uint8_t mac_address)
|
||||
{
|
||||
/* FIXME: Master Nodes can only have address 1-127 */
|
||||
MSTP_Port.This_Station = mac_address;
|
||||
/* Master Nodes can only have address 0-127 */
|
||||
if (mac_address <= 127)
|
||||
MSTP_Port.This_Station = mac_address;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t dlmstp_my_address(void)
|
||||
{
|
||||
return MSTP_Port.This_Station;
|
||||
}
|
||||
|
||||
/* This parameter represents the value of the Max_Info_Frames property of */
|
||||
/* the node's Device object. The value of Max_Info_Frames specifies the */
|
||||
@@ -224,8 +296,9 @@ unsigned dlmstp_max_info_frames(void)
|
||||
/* less than or equal to 127. If Max_Master is not writable in a node, */
|
||||
/* its value shall be 127. */
|
||||
void dlmstp_set_max_master(uint8_t max_master)
|
||||
{
|
||||
MSTP_Port.Nmax_master = max_master;
|
||||
{
|
||||
if (max_master <= 127)
|
||||
MSTP_Port.Nmax_master = max_master;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user