Refactor/mstp zero config state machine (#676)
* Changed MS/TP master node self destination checks to be located in receive FSM * Changed MSTP zero configuration: modified comments for state transition names; modified next station increment; refactored the UUID rand() to not be required by common zero config implementation; added more unit tests. * Added another context to MS/TP user data to allow additional user data
This commit is contained in:
@@ -321,7 +321,19 @@ extern "C" {
|
||||
BACNET_STACK_EXPORT
|
||||
bool Device_Valid_Object_Instance_Number(
|
||||
uint32_t object_id);
|
||||
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void Device_UUID_Init(
|
||||
void);
|
||||
BACNET_STACK_EXPORT
|
||||
void Device_UUID_Set(
|
||||
uint8_t *new_uuid,
|
||||
size_t length);
|
||||
BACNET_STACK_EXPORT
|
||||
void Device_UUID_Get(
|
||||
uint8_t *uuid,
|
||||
size_t length);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
unsigned Device_Object_List_Count(
|
||||
void);
|
||||
@@ -332,8 +344,8 @@ extern "C" {
|
||||
uint32_t * instance);
|
||||
BACNET_STACK_EXPORT
|
||||
int Device_Object_List_Element_Encode(
|
||||
uint32_t object_instance,
|
||||
BACNET_ARRAY_INDEX array_index,
|
||||
uint32_t object_instance,
|
||||
BACNET_ARRAY_INDEX array_index,
|
||||
uint8_t *apdu);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
|
||||
@@ -97,7 +97,7 @@ struct dlmstp_rs485_driver {
|
||||
};
|
||||
|
||||
/**
|
||||
* A structure of BACnet Port Data for BACnet MS/TP
|
||||
* An example structure of user data for BACnet MS/TP
|
||||
*/
|
||||
struct dlmstp_user_data_t {
|
||||
struct dlmstp_statistics Statistics;
|
||||
@@ -107,6 +107,7 @@ struct dlmstp_user_data_t {
|
||||
struct dlmstp_packet PDU_Buffer[DLMSTP_MAX_INFO_FRAMES];
|
||||
bool Initialized;
|
||||
bool ReceivePacketPending;
|
||||
void *Context;
|
||||
};
|
||||
|
||||
/* callback to signify the receipt of a preamble */
|
||||
|
||||
+70
-31
@@ -452,12 +452,19 @@ void MSTP_Receive_Frame_FSM(struct mstp_port_struct_t *mstp_port)
|
||||
} else {
|
||||
if (mstp_port->DataLength == 0) {
|
||||
/* NoData */
|
||||
printf_receive_data("%s",
|
||||
mstptext_frame_type(
|
||||
if ((mstp_port->DestinationAddress ==
|
||||
mstp_port->This_Station) ||
|
||||
(mstp_port->DestinationAddress ==
|
||||
MSTP_BROADCAST_ADDRESS) ||
|
||||
(mstp_port->This_Station ==
|
||||
MSTP_BROADCAST_ADDRESS)) {
|
||||
printf_receive_data("%s",
|
||||
mstptext_frame_type(
|
||||
(unsigned)mstp_port->FrameType));
|
||||
/* indicate that a frame with no data has been
|
||||
* received */
|
||||
mstp_port->ReceivedValidFrame = true;
|
||||
/* indicate that a frame with no data has been
|
||||
* received */
|
||||
mstp_port->ReceivedValidFrame = true;
|
||||
}
|
||||
/* wait for the start of the next frame. */
|
||||
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
|
||||
} else {
|
||||
@@ -465,6 +472,8 @@ void MSTP_Receive_Frame_FSM(struct mstp_port_struct_t *mstp_port)
|
||||
if ((mstp_port->DestinationAddress ==
|
||||
mstp_port->This_Station) ||
|
||||
(mstp_port->DestinationAddress ==
|
||||
MSTP_BROADCAST_ADDRESS) ||
|
||||
(mstp_port->This_Station ==
|
||||
MSTP_BROADCAST_ADDRESS)) {
|
||||
if (mstp_port->DataLength <=
|
||||
mstp_port->InputBufferSize) {
|
||||
@@ -641,9 +650,12 @@ bool MSTP_Master_Node_FSM(struct mstp_port_struct_t *mstp_port)
|
||||
if (mstp_port->This_Station != 255) {
|
||||
/* indicate that the next station is unknown */
|
||||
mstp_port->Next_Station = mstp_port->This_Station;
|
||||
/* Send a Poll For Master since we just received
|
||||
the token */
|
||||
mstp_port->Poll_Station = (mstp_port->Next_Station + 1) %
|
||||
(mstp_port->Zero_Config_Max_Master + 1);
|
||||
mstp_port->TokenCount = Npoll;
|
||||
mstp_port->RetryCount = 0;
|
||||
mstp_port->EventCount = 0;
|
||||
mstp_port->SoleMaster = true;
|
||||
MSTP_Create_And_Send_Frame(mstp_port,
|
||||
@@ -689,14 +701,12 @@ bool MSTP_Master_Node_FSM(struct mstp_port_struct_t *mstp_port)
|
||||
mstp_port->master_state = MSTP_MASTER_STATE_INITIALIZE;
|
||||
}
|
||||
mstp_port->ReceivedValidFrame = false;
|
||||
} else if ((mstp_port->DestinationAddress ==
|
||||
mstp_port->This_Station) ||
|
||||
(mstp_port->DestinationAddress == MSTP_BROADCAST_ADDRESS)) {
|
||||
} else {
|
||||
/* destined for me! */
|
||||
switch (mstp_port->FrameType) {
|
||||
case FRAME_TYPE_TOKEN:
|
||||
/* ReceivedToken */
|
||||
/* tokens can't be broadcast */
|
||||
/* tokens cannot be broadcast */
|
||||
if (mstp_port->DestinationAddress ==
|
||||
MSTP_BROADCAST_ADDRESS) {
|
||||
break;
|
||||
@@ -1336,6 +1346,33 @@ void MSTP_Zero_Config_UUID_Init(struct mstp_port_struct_t *mstp_port)
|
||||
mstp_port->UUID[8] = 0x80 | (mstp_port->UUID[8] & 0x3f);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Increment the Zero Configuration Station address
|
||||
* @param station the current station address in the range of min..max
|
||||
* @return the next station address
|
||||
*/
|
||||
unsigned MSTP_Zero_Config_Station_Increment(unsigned station)
|
||||
{
|
||||
unsigned next_station;
|
||||
|
||||
if (station < Nmin_poll_station) {
|
||||
next_station = Nmin_poll_station;
|
||||
} else {
|
||||
#ifdef MSTP_ZERO_CONFIG_STATION_INCREMENT_MODULO
|
||||
/* as defined by specification language */
|
||||
next_station = Nmin_poll_station +
|
||||
((station + 1) % ((Nmax_poll_station - Nmin_poll_station) + 1));
|
||||
#else
|
||||
next_station = station + 1;
|
||||
if (next_station > Nmax_poll_station) {
|
||||
next_station = Nmin_poll_station;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return next_station;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The ZERO_CONFIGURATION_INIT state is entered when
|
||||
* ZeroConfigurationMode is TRUE
|
||||
@@ -1350,13 +1387,12 @@ static void MSTP_Zero_Config_State_Init(struct mstp_port_struct_t *mstp_port)
|
||||
}
|
||||
mstp_port->Poll_Count = 0;
|
||||
mstp_port->Zero_Config_Station = Nmin_poll_station;
|
||||
mstp_port->Npoll_slot = 1 + (rand() % Nmax_poll_slot);
|
||||
mstp_port->Npoll_slot = 1 + (mstp_port->UUID[0] % Nmax_poll_slot);
|
||||
/* basic silence timeout is the dropped token time plus
|
||||
one Tslot after the last master node. Add one Tslot of
|
||||
silence timeout per zero config priority slot */
|
||||
slots = 128 + mstp_port->Npoll_slot;
|
||||
mstp_port->Zero_Config_Silence = Tno_token + Tslot * slots;
|
||||
MSTP_Zero_Config_UUID_Init(mstp_port);
|
||||
mstp_port->Zero_Config_Max_Master = 0;
|
||||
mstp_port->Zero_Config_State = MSTP_ZERO_CONFIG_STATE_IDLE;
|
||||
}
|
||||
@@ -1426,23 +1462,23 @@ static void MSTP_Zero_Config_State_Lurk(struct mstp_port_struct_t *mstp_port)
|
||||
if (src == mstp_port->Zero_Config_Station) {
|
||||
/* AddressInUse */
|
||||
/* monitor PFM from the next address */
|
||||
mstp_port->Zero_Config_Station++;
|
||||
if (mstp_port->Zero_Config_Station > Nmax_poll_station) {
|
||||
/* start again from first */
|
||||
mstp_port->Zero_Config_Station = Nmin_poll_station;
|
||||
}
|
||||
mstp_port->Zero_Config_Station =
|
||||
MSTP_Zero_Config_Station_Increment(
|
||||
mstp_port->Zero_Config_Station);
|
||||
mstp_port->Poll_Count = 0;
|
||||
} else if ((frame == FRAME_TYPE_POLL_FOR_MASTER) &&
|
||||
(dst == mstp_port->Zero_Config_Station)) {
|
||||
mstp_port->Poll_Count++;
|
||||
/* calculate this node poll count priority */
|
||||
/* calculate this node poll count priority number */
|
||||
count = Nmin_poll + mstp_port->Npoll_slot;
|
||||
if (mstp_port->Poll_Count == count) {
|
||||
/* ClaimAddress */
|
||||
/* PollResponse */
|
||||
MSTP_Create_And_Send_Frame(mstp_port,
|
||||
FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER, src,
|
||||
mstp_port->Zero_Config_Station, NULL, 0);
|
||||
mstp_port->Zero_Config_State = MSTP_ZERO_CONFIG_STATE_CLAIM;
|
||||
} else {
|
||||
/* CountFrame */
|
||||
mstp_port->Poll_Count++;
|
||||
}
|
||||
}
|
||||
} else if (mstp_port->ReceivedInvalidFrame) {
|
||||
@@ -1470,7 +1506,6 @@ static void MSTP_Zero_Config_State_Claim(struct mstp_port_struct_t *mstp_port)
|
||||
if (!mstp_port) {
|
||||
return;
|
||||
}
|
||||
/* */
|
||||
if (mstp_port->ReceivedValidFrame) {
|
||||
mstp_port->ReceivedValidFrame = false;
|
||||
dst = mstp_port->DestinationAddress;
|
||||
@@ -1479,11 +1514,9 @@ static void MSTP_Zero_Config_State_Claim(struct mstp_port_struct_t *mstp_port)
|
||||
if (src == mstp_port->Zero_Config_Station) {
|
||||
/* ClaimAddressInUse */
|
||||
/* monitor PFM from the next address */
|
||||
mstp_port->Zero_Config_Station++;
|
||||
if (mstp_port->Zero_Config_Station > Nmax_poll_station) {
|
||||
/* start again from first */
|
||||
mstp_port->Zero_Config_Station = Nmin_poll_station;
|
||||
}
|
||||
mstp_port->Zero_Config_Station =
|
||||
MSTP_Zero_Config_Station_Increment(
|
||||
mstp_port->Zero_Config_Station);
|
||||
mstp_port->Poll_Count = 0;
|
||||
mstp_port->Zero_Config_State = MSTP_ZERO_CONFIG_STATE_LURK;
|
||||
} else if (frame == FRAME_TYPE_TOKEN) {
|
||||
@@ -1499,7 +1532,7 @@ static void MSTP_Zero_Config_State_Claim(struct mstp_port_struct_t *mstp_port)
|
||||
/* ClaimInvalidFrame */
|
||||
mstp_port->ReceivedInvalidFrame = false;
|
||||
} else if (mstp_port->Zero_Config_Silence > 0) {
|
||||
/* ClaimLostToken */
|
||||
/* ClaimTimeout */
|
||||
if (mstp_port->SilenceTimer((void *)mstp_port) >
|
||||
mstp_port->Zero_Config_Silence) {
|
||||
mstp_port->Zero_Config_State = MSTP_ZERO_CONFIG_STATE_IDLE;
|
||||
@@ -1550,13 +1583,14 @@ static void MSTP_Zero_Config_State_Confirm(struct mstp_port_struct_t *mstp_port)
|
||||
} else if (src == mstp_port->Zero_Config_Station) {
|
||||
/* ConfirmationAddressInUse */
|
||||
/* monitor PFM from the next address */
|
||||
mstp_port->Zero_Config_Station++;
|
||||
if (mstp_port->Zero_Config_Station > Nmax_poll_station) {
|
||||
/* start again from first */
|
||||
mstp_port->Zero_Config_Station = Nmin_poll_station;
|
||||
}
|
||||
mstp_port->Zero_Config_Station =
|
||||
MSTP_Zero_Config_Station_Increment(
|
||||
mstp_port->Zero_Config_Station);
|
||||
mstp_port->Zero_Config_State = MSTP_ZERO_CONFIG_STATE_LURK;
|
||||
}
|
||||
} else if (mstp_port->ReceivedInvalidFrame) {
|
||||
/* ConfirmationInvalidFrame */
|
||||
mstp_port->ReceivedInvalidFrame = false;
|
||||
} else if (mstp_port->SilenceTimer((void *)mstp_port) >=
|
||||
mstp_port->Treply_timeout) {
|
||||
/* ConfirmationTimeout */
|
||||
@@ -1625,9 +1659,14 @@ void MSTP_Init(struct mstp_port_struct_t *mstp_port)
|
||||
mstp_port->Treply_delay = DEFAULT_Treply_delay;
|
||||
mstp_port->Treply_timeout = DEFAULT_Treply_timeout;
|
||||
mstp_port->Tusage_timeout = DEFAULT_Tusage_timeout;
|
||||
mstp_port->SlaveNodeEnabled = false;
|
||||
/* FIXME: point to functions */
|
||||
mstp_port->SilenceTimer = Timer_Silence;
|
||||
mstp_port->SilenceTimerReset = Timer_Silence_Reset;
|
||||
/* FIXME: set these in your dlmstp if you are zero-config */
|
||||
mstp_port->ZeroConfigEnabled = true;
|
||||
/* use the libc srand() and rand() generated random number*/
|
||||
MSTP_Zero_Config_UUID_Init(&MSTP_Port);
|
||||
#endif
|
||||
if ((mstp_port->Tframe_abort < 6) || (mstp_port->Tframe_abort > 100)) {
|
||||
mstp_port->Tframe_abort = DEFAULT_Tframe_abort;
|
||||
|
||||
@@ -271,6 +271,9 @@ void MSTP_Fill_BACnet_Address(BACNET_ADDRESS *src, uint8_t mstp_address);
|
||||
BACNET_STACK_EXPORT
|
||||
void MSTP_Zero_Config_UUID_Init(struct mstp_port_struct_t *mstp_port);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
unsigned MSTP_Zero_Config_Station_Increment(unsigned station);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void MSTP_Zero_Config_FSM(struct mstp_port_struct_t *mstp_port);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user