When you plan to deploy / sell sigfox based solution to consumer, you have to manage you device park. The sigfox network have a restricted radio medium to ensure you will not emit more than what you payed for you will be charged by them if a device you own is emitting, even if it is emitting out of your control. There is no network subscription like in 3G before being able to emit so anyone can emit. That is why, to ensure every one is clear, you have an extra cost if you emit more than you are allowed or if you emit from a non registered device.
When you are designing end-user system you have no control on the device and if you propose a monthly fee to use your solution you will never sure the end user will unplug it once he stop to pay for your service. It means you could have a consumer stopping to pay for your service but a device continuing to emit and sigfox request you to pay for it.
Since the network allow you to have downlink message, now you have the capability to send order to your device and as a consequence allowing you to kill the device remotely. This is a good solution !
Next you have a new scenario where your end user finally decide to reuse your service and want to reactivate the device. At this step you won’t be able to communicate with it and you will have to find another way to reset its state to normal. You can eventually add a “factory reset” button or request to reflash it. There is another funny when : playing with the reboot time.
This post will describe how to lock a device to stop emit on network and how to play with the startup sequence to reset it. Read more !
So basically, the idea is to be able to lock a device on startup ; for this we can define a running mode and a locked mode :
#define CONF_VERSION 0 #define CONF_STATE_NORMAL 0 #define CONF_STATE_LOCK 1 struct s_storedConfig { uint8_t state; } storedConfig;
This state will be stored in the flash and on startup we are going to check this mode:
// Get the right version of stored config TD_FLASH_SetVariablesVersion(CONF_VERSION); // Load status if (!TD_FLASH_DeclareVariable((uint8_t *) &storedConfig, sizeof(storedConfig), 0)) { // when not found = first run - init storedConfig.state = CONF_STATE_NORMAL; TD_FLASH_WriteVariables(); } // in anycase, now, the config is loader if ( storedConfig.state == CONF_STATE_NORMAL ) { // Here we are on the normal case // so you will write your custom code } else if ( storedConfig.state == CONF_STATE_LOCK ) { // this case will be the one to manage Locked devices // lock state }
Now we can add in the code a processing to lock the device when receiving a lock order from the downlink communication. So as an example we can modify the “normal case” to lock the device when receiving 0xAA as acknowledgment.
// Normal state // emit any message and wait for eventual acknowledgment value from // the downlink channel TD_SIGFOX_DOWNLINK_SetUserCallback(downlink_callback); TD_SIGFOX_SendV1(MODE_FRAME, false, message, 12, 2, true, false); static int downlink_callback(uint8_t *rx_frame, uint8_t length) { if (rx_frame == 0) { // end of reception process TD_SIGFOX_DOWNLINK_SetUserCallback(0); return 1; } else { if (length == 0) { // start of reception process return 1; } else { // an ack has been received 0xAA = LOCK if ( rx_frame[0] == 0xAA ){ storedConfig.state = CONF_STATE_LOCK; TD_FLASH_WriteVariables(); // update config TD_RTC_Delay(300 * DELAY_1MS); // for fun NVIC_SystemReset(); // reboot ! } return 1; } } }
At this point, the device is updating it own configuration and restart on the reception of a specific code. On restart, the device will reach the “lock state” instead of the “normal state”
Now in the lock state we are going to create an infinite loop but as we want to be able to unlock the device, we will have a specific time when the device will change its configuration and you shut it down / reset it during this time frame, on reboot, the device will restart in the “normal state”
// lock state TD_RTC_Delay(10000 * DELAY_1MS); // wait for 10 seconds storedConfig.state = CONF_STATE_NORMAL; TD_FLASH_WriteVariables(); TD_RTC_Delay(5000 * DELAY_1MS); // here we have a 5 seconds periode // where we can reset the device and // bring it back to normal state storedConfig.state = CONF_STATE_LOCK; TD_FLASH_WriteVariables(); while(1); // Then we relock the device and // loop for a while ...
You can change the system to get a more difficult way to unlock the device to avoid a risk of undesired reset during the unlock period as when running out of battery.
Hi Paul,
great post!
Should we use the ack frame to change back to the normal mode during the state lock mode?
if ( rx_frame[0] == 0xAB ) {
storedConfig.state = CONF_STATE_NORMAL;
TD_FLASH_WriteVariables();
TD_RTC_Delay(5000 * DELAY_1MS);
NVIC_SystemReset();
}
If you unactivate the device, it will never transmit anymore (this is the objective) so it will be never able to receive a new order to reactivate. That is why the reactivation have to be manual.
So unfortunately, it is not working.
Hi paul, fantastic post, i just have a question, i’m traying to do it but, i don’t know where i must put de this sentences:
– TD_SIGFOX_DOWNLINK_SetUserCallback(downlink_callback);
– TD_SIGFOX_SendV1(MODE_FRAME, false, message, 12, 2, true, false);
thanks in advance
In the “normal state” if you have in the previous paragraph