Working on the Datalink MS/TP layer - no working yet.
This commit is contained in:
+22
-4
@@ -39,6 +39,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include "bacdef.h"
|
#include "bacdef.h"
|
||||||
|
#include "npdu.h"
|
||||||
|
|
||||||
/* defines specific to MS/TP */
|
/* defines specific to MS/TP */
|
||||||
#define MAX_HEADER (2+1+1+1+2+1+2+1)
|
#define MAX_HEADER (2+1+1+1+2+1+2+1)
|
||||||
@@ -46,7 +47,6 @@
|
|||||||
|
|
||||||
typedef struct dlmstp_packet {
|
typedef struct dlmstp_packet {
|
||||||
bool ready; /* true if ready to be sent or received */
|
bool ready; /* true if ready to be sent or received */
|
||||||
bool data_expecting_reply;
|
|
||||||
BACNET_ADDRESS address; /* src or dest address */
|
BACNET_ADDRESS address; /* src or dest address */
|
||||||
unsigned pdu_len; /* packet length */
|
unsigned pdu_len; /* packet length */
|
||||||
uint8_t pdu[MAX_MPDU]; /* packet */
|
uint8_t pdu[MAX_MPDU]; /* packet */
|
||||||
@@ -61,23 +61,41 @@ extern "C" {
|
|||||||
void dlmstp_task(void);
|
void dlmstp_task(void);
|
||||||
void dlmstp_millisecond_timer(void);
|
void dlmstp_millisecond_timer(void);
|
||||||
|
|
||||||
/* returns number of bytes sent on success, negative on failure */
|
/* returns number of bytes sent on success, negative on failure */
|
||||||
int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||||
|
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||||
uint8_t * pdu, /* any data to be sent - may be null */
|
uint8_t * pdu, /* any data to be sent - may be null */
|
||||||
unsigned pdu_len); /* number of bytes of data */
|
unsigned pdu_len); /* number of bytes of data */
|
||||||
|
|
||||||
/* returns the number of octets in the PDU, or zero on failure */
|
/* returns the number of octets in the PDU, or zero on failure */
|
||||||
uint16_t dlmstp_receive(BACNET_ADDRESS * src, /* source address */
|
uint16_t dlmstp_receive(BACNET_ADDRESS * src, /* source address */
|
||||||
uint8_t * pdu, /* PDU data */
|
uint8_t * pdu, /* PDU data */
|
||||||
uint16_t max_pdu, /* amount of space available in the PDU */
|
uint16_t max_pdu, /* amount of space available in the PDU */
|
||||||
unsigned timeout); /* milliseconds to wait for a packet */
|
unsigned timeout); /* milliseconds to wait for a packet */
|
||||||
|
|
||||||
/* function for MS/TP state machine to use to get a packet
|
/* function for MS/TP state machine to use to get a packet
|
||||||
to transmit. It returns the number of bytes in the
|
to transmit. It returns the number of bytes in the
|
||||||
packet, or 0 if none. */
|
packet, or 0 if none. */
|
||||||
int dlmstp_get_transmit_pdu(BACNET_ADDRESS * dest, /* destination address */
|
int dlmstp_get_transmit_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||||
uint8_t * pdu); /* any data to be sent - may be null */
|
uint8_t * pdu); /* any data to be sent - may be null */
|
||||||
|
|
||||||
|
/* This parameter represents the value of the Max_Info_Frames property of */
|
||||||
|
/* the node's Device object. The value of Max_Info_Frames specifies the */
|
||||||
|
/* maximum number of information frames the node may send before it must */
|
||||||
|
/* pass the token. Max_Info_Frames may have different values on different */
|
||||||
|
/* nodes. This may be used to allocate more or less of the available link */
|
||||||
|
/* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */
|
||||||
|
/* node, its value shall be 1. */
|
||||||
|
void dlmstp_set_max_info_frames(unsigned max_info_frames);
|
||||||
|
unsigned dlmstp_max_info_frames(void);
|
||||||
|
|
||||||
|
/* This parameter represents the value of the Max_Master property of the */
|
||||||
|
/* node's Device object. The value of Max_Master specifies the highest */
|
||||||
|
/* allowable address for master nodes. The value of Max_Master shall be */
|
||||||
|
/* less than or equal to 127. If Max_Master is not writable in a node, */
|
||||||
|
/* its value shall be 127. */
|
||||||
|
void dlmstp_set_max_info_frames(uint8_t max_master);
|
||||||
|
uint8_t dlmstp_max_master(void);
|
||||||
|
|
||||||
void dlmstp_set_my_address(uint8_t my_address);
|
void dlmstp_set_my_address(uint8_t my_address);
|
||||||
void dlmstp_get_my_address(BACNET_ADDRESS * my_address);
|
void dlmstp_get_my_address(BACNET_ADDRESS * my_address);
|
||||||
|
|||||||
+47
-21
@@ -128,17 +128,14 @@ const unsigned Tusage_delay = 15;
|
|||||||
/* larger values for this timeout, not to exceed 100 milliseconds.) */
|
/* larger values for this timeout, not to exceed 100 milliseconds.) */
|
||||||
const unsigned Tusage_timeout = 20;
|
const unsigned Tusage_timeout = 20;
|
||||||
|
|
||||||
unsigned MSTP_Create_Frame(uint8_t * buffer, /* where frame is loaded */
|
/* creates the 8 octet frame header */
|
||||||
|
unsigned MSTP_Create_Frame_Header(uint8_t * buffer, /* where frame is loaded */
|
||||||
unsigned buffer_len, /* amount of space available */
|
unsigned buffer_len, /* amount of space available */
|
||||||
uint8_t frame_type, /* type of frame to send - see defines */
|
uint8_t frame_type, /* type of frame to send - see defines */
|
||||||
uint8_t destination, /* destination address */
|
uint8_t destination, /* destination address */
|
||||||
uint8_t source, /* source address */
|
uint8_t source) /* source address */
|
||||||
uint8_t * data, /* any data to be sent - may be null */
|
|
||||||
unsigned data_len)
|
|
||||||
{ /* number of bytes of data (up to 501) */
|
{ /* number of bytes of data (up to 501) */
|
||||||
uint8_t crc8 = 0xFF; /* used to calculate the crc value */
|
uint8_t crc8 = 0xFF; /* used to calculate the crc value */
|
||||||
uint16_t crc16 = 0xFFFF; /* used to calculate the crc value */
|
|
||||||
unsigned index = 0; /* used to load the data portion of the frame */
|
|
||||||
|
|
||||||
/* not enough to do a header */
|
/* not enough to do a header */
|
||||||
if (buffer_len < 8)
|
if (buffer_len < 8)
|
||||||
@@ -158,24 +155,53 @@ unsigned MSTP_Create_Frame(uint8_t * buffer, /* where frame is loaded */
|
|||||||
crc8 = CRC_Calc_Header(buffer[6], crc8);
|
crc8 = CRC_Calc_Header(buffer[6], crc8);
|
||||||
buffer[7] = ~crc8;
|
buffer[7] = ~crc8;
|
||||||
|
|
||||||
index = 8;
|
return 8; /* returns the frame length */
|
||||||
while (data_len && data && (index < buffer_len)) {
|
}
|
||||||
buffer[index] = *data;
|
|
||||||
|
/* copies the PDU to a buffer while calculating its CRC checksum
|
||||||
|
The CRC checksum is appended to the last two octets. */
|
||||||
|
unsigned MSTP_Copy_PDU_CRC(uint8_t * buffer, /* where frame is loaded */
|
||||||
|
unsigned buffer_len, /* amount of space available */
|
||||||
|
uint16_t crc16, /* used to calculate the crc value */
|
||||||
|
uint8_t * data, /* any data to be sent - may be null */
|
||||||
|
unsigned data_len)
|
||||||
|
{
|
||||||
|
unsigned index = 0; /* offset into the buffer */
|
||||||
|
|
||||||
|
if (buffer && data && data_len && ((data_len + 2) < buffer_len))
|
||||||
|
{
|
||||||
|
for (index = 0; index < data_len; index++)
|
||||||
|
{
|
||||||
|
buffer[index] = data[index];
|
||||||
crc16 = CRC_Calc_Data(buffer[index], crc16);
|
crc16 = CRC_Calc_Data(buffer[index], crc16);
|
||||||
data++;
|
|
||||||
index++;
|
|
||||||
data_len--;
|
|
||||||
}
|
}
|
||||||
/* append the data CRC if necessary */
|
|
||||||
if (index > 8) {
|
|
||||||
if ((index + 2) <= buffer_len) {
|
|
||||||
crc16 = ~crc16;
|
crc16 = ~crc16;
|
||||||
buffer[index] = LO_BYTE(crc16);
|
buffer[data_len] = LO_BYTE(crc16);
|
||||||
index++;
|
buffer[data_len + 1] = HI_BYTE(crc16);
|
||||||
buffer[index] = HI_BYTE(crc16);
|
index = data_len + 2;
|
||||||
index++;
|
}
|
||||||
} else
|
|
||||||
return 0;
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned MSTP_Create_Frame(uint8_t * buffer, /* where frame is loaded */
|
||||||
|
unsigned buffer_len, /* amount of space available */
|
||||||
|
uint8_t frame_type, /* type of frame to send - see defines */
|
||||||
|
uint8_t destination, /* destination address */
|
||||||
|
uint8_t source, /* source address */
|
||||||
|
uint8_t * data, /* any data to be sent - may be null */
|
||||||
|
unsigned data_len)
|
||||||
|
{ /* number of bytes of data (up to 501) */
|
||||||
|
uint16_t crc16 = 0xFFFF; /* used to calculate the crc value */
|
||||||
|
unsigned index = 0; /* used to load the data portion of the frame */
|
||||||
|
|
||||||
|
index = MSTP_Create_Frame_Header(buffer, buffer_len, frame_type,
|
||||||
|
destination, source);
|
||||||
|
if (data && data_len)
|
||||||
|
{
|
||||||
|
index += MSTP_Copy_PDU_CRC(&buffer[index], buffer_len - index,
|
||||||
|
crc16, data, data_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
return index; /* returns the frame length */
|
return index; /* returns the frame length */
|
||||||
|
|||||||
@@ -214,6 +214,21 @@ extern "C" {
|
|||||||
void MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t
|
void MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t
|
||||||
*mstp_port);
|
*mstp_port);
|
||||||
|
|
||||||
|
/* creates the 8 octet frame header */
|
||||||
|
unsigned MSTP_Create_Frame_Header(uint8_t * buffer, /* where frame is loaded */
|
||||||
|
unsigned buffer_len, /* amount of space available */
|
||||||
|
uint8_t frame_type, /* type of frame to send - see defines */
|
||||||
|
uint8_t destination, /* destination address */
|
||||||
|
uint8_t source); /* source address */
|
||||||
|
/* copies the PDU to a buffer while calculating its CRC checksum
|
||||||
|
The CRC checksum is appended to the last two octets. */
|
||||||
|
unsigned MSTP_Copy_PDU_CRC(uint8_t * buffer, /* where frame is loaded */
|
||||||
|
unsigned buffer_len, /* amount of space available */
|
||||||
|
uint16_t crc16, /* used to calculate the crc value */
|
||||||
|
uint8_t * data, /* any data to be sent - may be null */
|
||||||
|
unsigned data_len);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|||||||
@@ -30,11 +30,13 @@
|
|||||||
#include "mstp.h"
|
#include "mstp.h"
|
||||||
#include "dlmstp.h"
|
#include "dlmstp.h"
|
||||||
#include "rs485.h"
|
#include "rs485.h"
|
||||||
|
#include "npdu.h"
|
||||||
|
|
||||||
static DLMSTP_PACKET Receive_Buffer;
|
static DLMSTP_PACKET Receive_Buffer;
|
||||||
static DLMSTP_PACKET Transmit_Buffer;
|
static DLMSTP_PACKET Transmit_Buffer;
|
||||||
|
static uint8_t PDU_Buffer[MAX_MPDU];
|
||||||
|
/* local MS/TP port data */
|
||||||
volatile struct mstp_port_struct_t MSTP_Port; /* port data */
|
volatile struct mstp_port_struct_t MSTP_Port; /* port data */
|
||||||
static uint8_t MSTP_MAC_Address = 0x05; /* local MAC address */
|
|
||||||
|
|
||||||
void dlmstp_init(void)
|
void dlmstp_init(void)
|
||||||
{
|
{
|
||||||
@@ -48,7 +50,7 @@ void dlmstp_init(void)
|
|||||||
Transmit_Buffer.pdu_len = 0;
|
Transmit_Buffer.pdu_len = 0;
|
||||||
/* initialize hardware */
|
/* initialize hardware */
|
||||||
RS485_Initialize();
|
RS485_Initialize();
|
||||||
MSTP_Init(&MSTP_Port, MSTP_MAC_Address);
|
MSTP_Init(&MSTP_Port, MSTP_Port.This_Station);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dlmstp_cleanup(void)
|
void dlmstp_cleanup(void)
|
||||||
@@ -58,22 +60,57 @@ void dlmstp_cleanup(void)
|
|||||||
|
|
||||||
/* returns number of bytes sent on success, zero on failure */
|
/* returns number of bytes sent on success, zero on failure */
|
||||||
int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||||
|
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||||
uint8_t * pdu, /* any data to be sent - may be null */
|
uint8_t * pdu, /* any data to be sent - may be null */
|
||||||
unsigned pdu_len)
|
unsigned pdu_len)
|
||||||
{ /* number of bytes of data */
|
{ /* number of bytes of data */
|
||||||
bool status;
|
bool status;
|
||||||
int bytes_sent = 0;
|
int bytes_sent = 0;
|
||||||
|
int npdu_len = 0;
|
||||||
|
uint8_t frame_type = 0;
|
||||||
|
uint8_t destination = 0; /* destination address */
|
||||||
|
BACNET_ADDRESS src;
|
||||||
|
|
||||||
if (Transmit_Buffer.ready == false) {
|
if (Transmit_Buffer.ready == false) {
|
||||||
/* FIXME: how do we get data_expecting_reply? */
|
if (npdu_data->confirmed_message)
|
||||||
Transmit_Buffer.data_expecting_reply = false;
|
frame_type = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY;
|
||||||
Receive_Buffer.pdu_len = 0;
|
else
|
||||||
memmove(&Transmit_Buffer.address, dest,
|
frame_type = FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY;
|
||||||
sizeof(Transmit_Buffer.address));
|
|
||||||
Transmit_Buffer.pdu_len = pdu_len;
|
/* load destination MAC address */
|
||||||
/* FIXME: copy the whole PDU or just the pdu_len? */
|
if (dest && dest->mac_len == 1) {
|
||||||
memmove(Transmit_Buffer.pdu, pdu, sizeof(Transmit_Buffer.pdu));
|
destination = dest->mac[0];
|
||||||
bytes_sent = pdu_len;
|
} 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 + npdu_len + pdu_len) > MAX_MPDU) {
|
||||||
|
#if PRINT_ENABLED
|
||||||
|
fprintf(stderr, "mstp: PDU is too big to send!\n");
|
||||||
|
#endif
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
memcpy(&PDU_Buffer[npdu_len], pdu, pdu_len);
|
||||||
|
/* copies the PDU to a buffer while calculating its CRC checksum
|
||||||
|
The CRC checksum is appended to the last two octets. */
|
||||||
|
unsigned MSTP_Copy_PDU_CRC(uint8_t * buffer, /* where frame is loaded */
|
||||||
|
unsigned buffer_len, /* amount of space available */
|
||||||
|
uint16_t crc16, /* used to calculate the crc value */
|
||||||
|
uint8_t * data, /* any data to be sent - may be null */
|
||||||
|
unsigned data_len);
|
||||||
|
|
||||||
|
bytes_sent = MSTP_Create_Frame(
|
||||||
|
&Transmit_Buffer.pdu[0],
|
||||||
|
sizeof(Transmit_Buffer.pdu),
|
||||||
|
frame_type,
|
||||||
|
destination,
|
||||||
|
MSTP_Port.This_Station,
|
||||||
|
&PDU_Buffer[0],
|
||||||
|
npdu_len + pdu_len);
|
||||||
Transmit_Buffer.ready = true;
|
Transmit_Buffer.ready = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,15 +197,51 @@ uint16_t dlmstp_put_receive(BACNET_ADDRESS * src, /* source address */
|
|||||||
void dlmstp_set_my_address(uint8_t mac_address)
|
void dlmstp_set_my_address(uint8_t mac_address)
|
||||||
{
|
{
|
||||||
/* FIXME: Master Nodes can only have address 1-127 */
|
/* FIXME: Master Nodes can only have address 1-127 */
|
||||||
MSTP_MAC_Address = mac_address;
|
MSTP_Port.This_Station = mac_address;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This parameter represents the value of the Max_Info_Frames property of */
|
||||||
|
/* the node's Device object. The value of Max_Info_Frames specifies the */
|
||||||
|
/* maximum number of information frames the node may send before it must */
|
||||||
|
/* pass the token. Max_Info_Frames may have different values on different */
|
||||||
|
/* nodes. This may be used to allocate more or less of the available link */
|
||||||
|
/* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */
|
||||||
|
/* node, its value shall be 1. */
|
||||||
|
void dlmstp_set_max_info_frames(unsigned max_info_frames)
|
||||||
|
{
|
||||||
|
MSTP_Port.Nmax_info_frames = max_info_frames;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned dlmstp_max_info_frames(void)
|
||||||
|
{
|
||||||
|
return MSTP_Port.Nmax_info_frames;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This parameter represents the value of the Max_Master property of the */
|
||||||
|
/* node's Device object. The value of Max_Master specifies the highest */
|
||||||
|
/* allowable address for master nodes. The value of Max_Master shall be */
|
||||||
|
/* less than or equal to 127. If Max_Master is not writable in a node, */
|
||||||
|
/* its value shall be 127. */
|
||||||
|
void dlmstp_set_max_info_frames(uint8_t max_master)
|
||||||
|
{
|
||||||
|
MSTP_Port.Nmax_master = max_master;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t dlmstp_max_master(void)
|
||||||
|
{
|
||||||
|
return MSTP_Port.Nmax_master;
|
||||||
|
}
|
||||||
|
|
||||||
void dlmstp_get_my_address(BACNET_ADDRESS * my_address)
|
void dlmstp_get_my_address(BACNET_ADDRESS * my_address)
|
||||||
{
|
{
|
||||||
my_address->mac_len = 1;
|
my_address->mac_len = 1;
|
||||||
my_address->mac[0] = MSTP_MAC_Address;
|
my_address->mac[0] = MSTP_Port.This_Station;
|
||||||
my_address->net = 0; /* local only, no routing */
|
my_address->net = 0; /* local only, no routing */
|
||||||
my_address->len = 0;
|
my_address->len = 0;
|
||||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||||
|
|||||||
Reference in New Issue
Block a user