Skip to content
Version 6.1.0
Contact Us

ReinitializeDevice

ReinitializeDevice is how a BACnet client activates the Network Port changes it wrote, so read that chapter’s Writable properties and Changes_Pending first if your device has writable Network Port properties.

ReinitializeDevice asks a device to restart, activate pending changes, or step through backup and restore. To answer it, register the callback and enable the service (service number 20):

DllExport void BACnetStack_RegisterCallbackReinitializeDevice(bool(*FPCallbackReinitializeDevice) (const uint32_t deviceInstance, const uint32_t reinitializedState, const char* password, const uint32_t passwordLength, uint32_t* errorCode));
DllExport bool BACnetStack_SetServiceEnabled(const uint32_t deviceInstance, const uint32_t service, const bool enabled);

The callback is mandatory. Without it the stack answers every ReinitializeDevice with Error SERVICES / SERVICE_REQUEST_DENIED.

Value State What to do
0 COLDSTART Restart. What a cold start means is your product’s decision; often the same as a warm start. Pending Network Port values are not activated.
1 WARMSTART Restart, keeping the data a short power cut would keep. Pending Network Port values are activated first.
2–6 STARTBACKUP, ENDBACKUP, STARTRESTORE, ENDRESTORE, ABORTRESTORE Backup and restore. The stack drives these through the backup and restore callbacks after the SimpleAck.
7 ACTIVATE_CHANGES Nothing beyond accepting: the stack activates the pending values.

A state above 7 is rejected by the stack before your callback is called.

Six steps: 1 the stack checks the request, 2 the stack checks the pending values can be activated, 3 your ReinitializeDevice callback checks the password, the only step that is yours, 4 the stack activates the pending values through your Set callbacks, 5 communication is re-enabled after a restart state, 6 the stack sends the SimpleAck.

When a ReinitializeDevice arrives, the stack:

  1. checks the request, the backup/restore preconditions and the DeviceCommunicationControl rules;
  2. checks that every pending Network Port value can be activated (for ACTIVATE_CHANGES and WARMSTART). If not, it answers Error(PROPERTY, INVALID_CONFIGURATION_DATA) and does not call you;
  3. calls your CallbackReinitializeDevice. If you return false, it answers with your error and activates nothing;
  4. activates the pending values, calling your Set callbacks. If one is refused it answers Error(PROPERTY, INVALID_CONFIGURATION_DATA), even though your callback returned true;
  5. re-enables communication if a WARMSTART or COLDSTART ended a DeviceCommunicationControl disable;
  6. sends the SimpleAck.

So the stack does the password relay, the pending-change checks, the activation and the reply. Your application does the password check, the restart, and the persistence of the values it receives in step 4.

The stack does not check the password against anything; it passes it to you. password is NULL with passwordLength 0 when the request carried none. The stack rejects a password that is empty, longer than 20 characters, or not well-formed UTF-8 before calling you. A password is optional in BACnet, but a device that ships with one should check it here.

Return true to accept. Return false and set *errorCode to refuse. The stack sends these codes with these classes:

*errorCode Value Sent as
PASSWORD_FAILURE 26 SECURITY, PASSWORD_FAILURE
MISSING_REQUIRED_PARAMETER 16 SERVICES, MISSING_REQUIRED_PARAMETER (a password is required and none was sent)
CONFIGURATION_IN_PROGRESS 2 DEVICE, CONFIGURATION_IN_PROGRESS
COMMUNICATION_DISABLED 83 SERVICES, COMMUNICATION_DISABLED
OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED 45 SERVICES, OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED (a state you do not support)
INVALID_CONFIGURATION_DATA 46 PROPERTY, INVALID_CONFIGURATION_DATA

Any other code is sent with its own error class, as the other service callbacks send it. No code (the preset SUCCESS), OTHER, a value above 65535, or an abort-type or reject-type code is sent as SERVICES, SERVICE_REQUEST_DENIED. ABORT_OTHER (56) asks for an Abort(other) instead. A refusal is never answered with an Abort otherwise.

Do not restart inside the callback. The stack still has to activate the pending values and send the SimpleAck after you return. Set a flag, and restart after BACnetStack_Tick() returns. If one of your Set callbacks refused a value during activation, the client received an error, and you may choose not to restart.

Chipkin keeps its examples on GitHub up to date with the stack, so this manual does not copy their code. BACnetProfileExample-B-BC-CPP, a BACnet Building Controller, handles ReinitializeDevice in main.cpp. Its ReinitializeDevice() callback checks the password, accepts ACTIVATE_CHANGES, COLDSTART, WARMSTART and the backup and restore states, and only arms the restart. Its main loop restarts the device later, after the SimpleAck has had time to go out. The password is the DCC_PASSWORD constant, and the same check guards DeviceCommunicationControl.

An MS/TP port follows the same pattern as an IPv4 port, with Max_Master and Max_Info_Frames served and activated through the unsigned-integer callbacks. Store them in the Set callback. In byte mode the stack’s own MS/TP engine reads them again from your Get callback after the activation, so there is nothing more to do; in packet mode, apply them to your own MS/TP engine as well. See the MS/TP Network Port.

  • Persist in the Set callback, not in CallbackReinitializeDevice. The values are not handed to you until after your ReinitializeDevice callback returns.
  • COLDSTART does not activate pending values. If your product wants a cold start to apply them, call BACnetStack_ActivateNetworkPortPendingChanges() before restarting.
  • Sending ReinitializeDevice to another device is BACnetStack_SendReinitializeDevice(); see its doc comment in source/CASBACnetStackDLL.h.