Updated PIC port MS/TP to not always Reply-Postponed frame when sent Data-Expecting-Reply frame.

This commit is contained in:
skarg
2012-04-17 22:02:34 +00:00
parent bc8d262add
commit 9e96fdb62e
3 changed files with 139 additions and 26 deletions
+8 -5
View File
@@ -95,7 +95,6 @@ int dlmstp_send_pdu(
int bytes_sent = 0;
unsigned npdu_len = 0;
uint8_t frame_type = 0;
uint8_t destination = 0; /* destination address */
BACNET_ADDRESS src;
unsigned i = 0; /* loop counter */
@@ -107,7 +106,7 @@ int dlmstp_send_pdu(
/* load destination MAC address */
if (dest && dest->mac_len == 1) {
destination = dest->mac[0];
MSTP_Port.TxDestination = dest->mac[0];
} else {
return -2;
}
@@ -116,9 +115,13 @@ int dlmstp_send_pdu(
return -4;
}
bytes_sent =
MSTP_Create_Frame((uint8_t *) & MSTP_Port.TxBuffer[0],
sizeof(MSTP_Port.TxBuffer), MSTP_Port.TxFrameType, destination,
MSTP_Port.This_Station, pdu, pdu_len);
MSTP_Create_Frame(
(uint8_t *) & MSTP_Port.TxBuffer[0],
sizeof(MSTP_Port.TxBuffer),
MSTP_Port.TxFrameType,
MSTP_Port.TxDestination,
MSTP_Port.This_Station,
pdu, pdu_len);
MSTP_Port.TxLength = bytes_sent;
MSTP_Port.TxReady = true;
MSTP_Packets++;
+130 -21
View File
@@ -551,6 +551,113 @@ void MSTP_Receive_Frame_FSM(
return;
}
static bool mstp_compare_data_expecting_reply(
uint8_t * request_pdu,
uint16_t request_pdu_len,
uint8_t src_address,
uint8_t * reply_pdu,
uint16_t reply_pdu_len,
uint8_t dest_address)
{
uint16_t offset;
/* One way to check the message is to compare NPDU
src, dest, along with the APDU type, invoke id.
Seems a bit overkill */
struct DER_compare_t {
BACNET_NPDU_DATA npdu_data;
BACNET_ADDRESS address;
uint8_t pdu_type;
uint8_t invoke_id;
uint8_t service_choice;
};
struct DER_compare_t request;
struct DER_compare_t reply;
/* decode the request data */
request.address.mac[0] = src_address;
request.address.mac_len = 1;
offset =
npdu_decode(&request_pdu[0], NULL, &request.address,
&request.npdu_data);
if (request.npdu_data.network_layer_message) {
return false;
}
request.pdu_type = request_pdu[offset] & 0xF0;
if (request.pdu_type != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) {
return false;
}
request.invoke_id = request_pdu[offset + 2];
/* segmented message? */
if (request_pdu[offset] & BIT3)
request.service_choice = request_pdu[offset + 5];
else
request.service_choice = request_pdu[offset + 3];
/* decode the reply data */
reply.address.mac[0] = dest_address;
reply.address.mac_len = 1;
offset =
npdu_decode(&reply_pdu[0], &reply.address, NULL, &reply.npdu_data);
if (reply.npdu_data.network_layer_message) {
return false;
}
/* reply could be a lot of things:
confirmed, simple ack, abort, reject, error */
reply.pdu_type = reply_pdu[offset] & 0xF0;
switch (reply.pdu_type) {
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
reply.invoke_id = reply_pdu[offset + 2];
/* segmented message? */
if (reply_pdu[offset] & BIT3)
reply.service_choice = reply_pdu[offset + 5];
else
reply.service_choice = reply_pdu[offset + 3];
break;
case PDU_TYPE_SIMPLE_ACK:
reply.invoke_id = reply_pdu[offset + 1];
reply.service_choice = reply_pdu[offset + 2];
break;
case PDU_TYPE_COMPLEX_ACK:
reply.invoke_id = reply_pdu[offset + 1];
/* segmented message? */
if (reply_pdu[offset] & BIT3)
reply.service_choice = reply_pdu[offset + 4];
else
reply.service_choice = reply_pdu[offset + 2];
break;
case PDU_TYPE_ERROR:
reply.invoke_id = reply_pdu[offset + 1];
reply.service_choice = reply_pdu[offset + 2];
break;
case PDU_TYPE_REJECT:
case PDU_TYPE_ABORT:
reply.invoke_id = reply_pdu[offset + 1];
break;
default:
return false;
}
if (request.invoke_id != reply.invoke_id) {
return false;
}
/* these services don't have service choice included */
if ((reply.pdu_type != PDU_TYPE_REJECT) &&
(reply.pdu_type != PDU_TYPE_ABORT)) {
if (request.service_choice != reply.service_choice) {
return false;
}
}
if (request.npdu_data.protocol_version != reply.npdu_data.protocol_version) {
return false;
}
if (request.npdu_data.priority != reply.npdu_data.priority) {
return false;
}
if (!bacnet_address_same(&request.address, &reply.address)) {
return false;
}
return true;
}
/* returns true if we need to transition immediately */
bool MSTP_Master_Node_FSM(
volatile struct mstp_port_struct_t * mstp_port)
@@ -563,6 +670,7 @@ bool MSTP_Master_Node_FSM(
uint16_t my_timeout = 10, ns_timeout = 0;
/* transition immediately to the next state */
bool transition_now = false;
bool matched = false;
#if PRINT_ENABLED_MASTER
static MSTP_MASTER_STATE master_state = MSTP_MASTER_STATE_INITIALIZE;
#endif
@@ -1032,13 +1140,20 @@ bool MSTP_Master_Node_FSM(
/* BACnet Data Expecting Reply, a Test_Request, or */
/* a proprietary frame that expects a reply is received. */
case MSTP_MASTER_STATE_ANSWER_DATA_REQUEST:
#if 0
/* FIXME: we always defer the reply to be safe */
/* FIXME: if we knew the APDU type received, we could
see if the next message was that same APDU type
along with the matching src/dest and invoke ID */
if ((mstp_port->SilenceTimer <= Treply_delay) &&
mstp_port->TxReady) {
if (mstp_port->TxReady) {
/* Compare the APDU type received and
see if the message is that same APDU type
along with the matching src/dest and invoke ID */
matched =
mstp_compare_data_expecting_reply(
&mstp_port->InputBuffer[0],
mstp_port->DataLength,
mstp_port->SourceAddress,
&mstp_port->TxBuffer[0],
mstp_port->TxLength,
mstp_port->TxDestination);
}
if (matched && mstp_port->TxReady) {
/* Reply */
/* If a reply is available from the higher layers */
/* within Treply_delay after the reception of the */
@@ -1046,17 +1161,12 @@ bool MSTP_Master_Node_FSM(
/* (the mechanism used to determine this is a local matter), */
/* then call MSTP_Create_And_Send_Frame to transmit the reply frame */
/* and enter the IDLE state to wait for the next frame. */
if ((mstp_port->FrameType ==
FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY)
&& (mstp_port->TxReady)) {
RS485_Send_Frame(mstp_port,
(uint8_t *) & mstp_port->TxBuffer[0],
mstp_port->TxLength);
mstp_port->TxReady = false;
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
}
} else
#endif
RS485_Send_Frame(mstp_port,
(uint8_t *) & mstp_port->TxBuffer[0],
mstp_port->TxLength);
mstp_port->TxReady = false;
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
} else {
/* DeferredReply */
/* If no reply will be available from the higher layers */
/* within Treply_delay after the reception of the */
@@ -1064,9 +1174,8 @@ bool MSTP_Master_Node_FSM(
/* used to determine this is a local matter), */
/* then an immediate reply is not possible. */
/* Any reply shall wait until this node receives the token. */
/* Call MSTP_Create_And_Send_Frame to transmit a Reply Postponed frame, */
/* and enter the IDLE state. */
{
/* Call MSTP_Create_And_Send_Frame to transmit a */
/* Reply Postponed frame, and enter the IDLE state. */
MSTP_Create_And_Send_Frame(mstp_port,
FRAME_TYPE_REPLY_POSTPONED, mstp_port->SourceAddress,
mstp_port->This_Station, NULL, 0);
+1
View File
@@ -150,6 +150,7 @@ struct mstp_port_struct_t {
/* This array is only used for APDU messages */
uint8_t TxBuffer[MAX_MPDU];
unsigned TxLength;
uint8_t TxDestination;
bool TxReady; /* true if ready to be sent or received */
uint8_t TxFrameType; /* type of message - needed by MS/TP */
};