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:
@@ -81,6 +81,7 @@ static uint32_t Database_Revision;
|
||||
static BACNET_REINITIALIZED_STATE Reinitialize_State = BACNET_REINIT_IDLE;
|
||||
static const char *Reinit_Password = "stm32f4xx";
|
||||
static const char *BACnet_Version = BACNET_VERSION_TEXT;
|
||||
static uint8_t Device_UUID[16];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Device_Properties_Required[] = { PROP_OBJECT_IDENTIFIER,
|
||||
@@ -94,7 +95,8 @@ static const int Device_Properties_Required[] = { PROP_OBJECT_IDENTIFIER,
|
||||
PROP_DATABASE_REVISION, -1 };
|
||||
|
||||
static const int Device_Properties_Optional[] = { PROP_DESCRIPTION,
|
||||
PROP_LOCATION, PROP_MAX_MASTER, PROP_MAX_INFO_FRAMES, -1 };
|
||||
PROP_LOCATION, PROP_MAX_MASTER, PROP_MAX_INFO_FRAMES, PROP_DEVICE_UUID,
|
||||
-1 };
|
||||
|
||||
static const int Device_Properties_Proprietary[] = { -1 };
|
||||
|
||||
@@ -398,6 +400,71 @@ void Device_Inc_Database_Revision(void)
|
||||
Database_Revision++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize a UUID for storing the unique identifier of this device
|
||||
* @note A Universally Unique IDentifier (UUID) - also called a
|
||||
* Global Unique IDentifier (GUID) - is a 128-bit value, see RFC 4122.
|
||||
*
|
||||
* 4.4. Algorithms for Creating a UUID from Truly Random or
|
||||
* Pseudo-Random Numbers
|
||||
*
|
||||
* The version 4 UUID is meant for generating UUIDs from truly-random or
|
||||
* pseudo-random numbers.
|
||||
*
|
||||
* The algorithm is as follows:
|
||||
*
|
||||
* o Set the two most significant bits (bits 6 and 7) of the
|
||||
* clock_seq_hi_and_reserved to zero and one, respectively.
|
||||
*
|
||||
* o Set the four most significant bits (bits 12 through 15) of the
|
||||
* time_hi_and_version field to the 4-bit version number from
|
||||
* Section 4.1.3.
|
||||
*
|
||||
* o Set all the other bits to randomly (or pseudo-randomly) chosen
|
||||
* values.
|
||||
*/
|
||||
void Device_UUID_Init(void)
|
||||
{
|
||||
unsigned i = 0;
|
||||
|
||||
/* 1. Generate 16 random bytes = 128 bits */
|
||||
for (i = 0; i < sizeof(Device_UUID); i++) {
|
||||
Device_UUID[i] = rand() % 255;
|
||||
}
|
||||
/* 2. Adjust certain bits according to RFC 4122 section 4.4.
|
||||
This just means do the following
|
||||
(a) set the high nibble of the 7th byte equal to 4 and
|
||||
(b) set the two most significant bits of the 9th byte to 10'B,
|
||||
so the high nibble will be one of {8,9,A,B}.
|
||||
From http://www.cryptosys.net/pki/Uuid.c.html */
|
||||
Device_UUID[6] = 0x40 | (Device_UUID[6] & 0x0f);
|
||||
Device_UUID[8] = 0x80 | (Device_UUID[8] & 0x3f);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the UUID for this device
|
||||
* @param new_uuid [in] The new UUID to set
|
||||
* @param length [in] The length of the new UUID
|
||||
*/
|
||||
void Device_UUID_Set(uint8_t *new_uuid, size_t length)
|
||||
{
|
||||
if (new_uuid && (length == sizeof(Device_UUID))) {
|
||||
memcpy(Device_UUID, new_uuid, sizeof(Device_UUID));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the UUID for this device
|
||||
* @param uuid [out] The UUID of this device
|
||||
* @param length [in] The length of the UUID
|
||||
*/
|
||||
void Device_UUID_Get(uint8_t *uuid, size_t length)
|
||||
{
|
||||
if (uuid && (length == sizeof(Device_UUID))) {
|
||||
memcpy(uuid, Device_UUID, sizeof(Device_UUID));
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the total count of objects supported by this Device Object.
|
||||
* @note Since many network clients depend on the object list
|
||||
* for discovery, it must be consistent!
|
||||
@@ -586,6 +653,7 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string = { 0 };
|
||||
BACNET_CHARACTER_STRING char_string = { 0 };
|
||||
BACNET_OCTET_STRING octet_string = { 0 };
|
||||
uint32_t i = 0;
|
||||
uint32_t count = 0;
|
||||
uint8_t *apdu = NULL;
|
||||
@@ -713,6 +781,10 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], dlmstp_max_master());
|
||||
break;
|
||||
case PROP_DEVICE_UUID:
|
||||
octetstring_init(&octet_string, Device_UUID, sizeof(Device_UUID));
|
||||
apdu_len = encode_application_octet_string(&apdu[0], &octet_string);
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
|
||||
+21
-17
@@ -44,7 +44,7 @@
|
||||
|
||||
/* MS/TP port */
|
||||
static struct mstp_port_struct_t MSTP_Port;
|
||||
static struct dlmstp_rs485_driver RS485_Driver = {
|
||||
static struct dlmstp_rs485_driver RS485_Driver = {
|
||||
.init = rs485_init,
|
||||
.send = rs485_bytes_send,
|
||||
.read = rs485_byte_available,
|
||||
@@ -52,7 +52,7 @@ static struct dlmstp_rs485_driver RS485_Driver = {
|
||||
.baud_rate = rs485_baud_rate,
|
||||
.baud_rate_set = rs485_baud_rate_set,
|
||||
.silence_milliseconds = rs485_silence_milliseconds,
|
||||
.silence_reset = rs485_silence_reset
|
||||
.silence_reset = rs485_silence_reset
|
||||
};
|
||||
static struct dlmstp_user_data_t MSTP_User_Data;
|
||||
static uint8_t Input_Buffer[DLMSTP_MPDU_MAX];
|
||||
@@ -90,6 +90,24 @@ int main(void)
|
||||
led_init();
|
||||
rs485_init();
|
||||
mstimer_set(&Blink_Timer, 500);
|
||||
/* FIXME: get the device ID from EEPROM */
|
||||
Device_Set_Object_Instance_Number(103);
|
||||
/* seed stdlib rand() with device-id to get pseudo consistent
|
||||
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
|
||||
/* initialize the Device UUID from rand() */
|
||||
Device_UUID_Init();
|
||||
Device_UUID_Get(MSTP_Port.UUID, sizeof(MSTP_Port.UUID));
|
||||
/* initialize MSTP datalink layer */
|
||||
MSTP_Port.Nmax_info_frames = DLMSTP_MAX_INFO_FRAMES;
|
||||
MSTP_Port.Nmax_master = DLMSTP_MAX_MASTER;
|
||||
@@ -104,6 +122,7 @@ int main(void)
|
||||
MSTP_Port.UserData = &MSTP_User_Data;
|
||||
dlmstp_init((char *)&MSTP_Port);
|
||||
if (MSTP_Port.ZeroConfigEnabled) {
|
||||
/* set node to monitor address */
|
||||
dlmstp_set_mac_address(255);
|
||||
} else {
|
||||
/* FIXME: get the address from hardware DIP or from EEPROM */
|
||||
@@ -113,21 +132,6 @@ int main(void)
|
||||
dlmstp_set_baud_rate(DLMSTP_BAUD_RATE_DEFAULT);
|
||||
/* initialize application layer*/
|
||||
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 (;;) {
|
||||
if (mstimer_expired(&Blink_Timer)) {
|
||||
mstimer_reset(&Blink_Timer);
|
||||
|
||||
Reference in New Issue
Block a user