Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
New Factory Firmware sample for separate DUT and Fixture Device Groups
// ------------------------------------------------------------------------------
// File: factory.firmware.dut.agent.nut
// Version: 2.1.1
//
// Copyright 2020 Twilio
//
// SPDX-License-Identifier: MIT
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// ------------------------------------------------------------------------------
// ***************************************
// ***** SETUP *****
// ***************************************
// CONSTANTS
// Replace the following string with your server logging endpoint
const RESULTS_URL = "YOUR_RESULT_LOGGING_URL";
// GLOBALS
local blinkUpCount = 0;
// ***************************************
// ***** DUT AGENT FUNCTIONS *****
// ***************************************
// Set up an receiver for "test.result" messages from the device under test (DUT)
device.on("test.result", function(data) {
local body = http.jsonencode(data, {"compact":true});
local deviceID = data.device_id;
local headers = {"Content-Type": "application/json"};
// The following line is helpful for debugging factory firmware during development.
server.log(format("Posting message 'test results' for device %s: %s.", deviceID, body));
// Send the test result data to your server
http.post(RESULTS_URL, headers, body).sendasync(function(response) {
if (response.statuscode >= 300) {
// The following line will not be called in a production environment
// unless you have enabled logging for the specific device via impCentral
server.error(format("Failed posting test results for device %s with response %d:%s.", deviceID, response.statuscode, response.body));
} else {
// Success
server.log(format("Message 'test results' for device %s: %s has been received.", deviceID, body));
}
});
// Relay a message to the fixture which did BlinkUp on the DUT
http.post(imp.configparams.factory_fixture_url, headers, body).sendasync(function(response) {
if (response.statuscode >= 300) {
// The following line will not be called in a production environment
// unless you have enabled logging for the specific device via impCentral
server.error(format("Failed relaying test results for device %s with response %d:%s.", deviceID, response.statuscode, response.body));
} else {
// Success
server.log(format("Message 'test results' for device %s: %s has been relayed to the fixture.", deviceID, body));
}
});
});
// ------------------------------------------------------------------------------
// File: factory.firmware.dut.device.nut
// Version: 2.1.1
//
// Copyright 2020 Twilio
//
// SPDX-License-Identifier: MIT
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// ------------------------------------------------------------------------------
// ***************************************
// ***** SETUP *****
// ***************************************
// CONSTANTS
// Set the target WiFi Region code (see 'getRegionCode()', below, for values)
const WIFI_REGION = "US";
// ***************************************
// ** DEVICE UNDER TEST (DUT) FUNCTIONS **
// ***************************************
function blessDeviceUnderTest() {
// Run any tests you require for you DUT
local testResult = myTestFunction();
// Attempt to bless this device, and send the result to the Factory Test Results Webhook
server.bless(testResult, function(blessSuccess) {
// Send identifying info and result to the test results webhook
agent.send("test.result", { "device_id": hardware.getdeviceid(),
"success": (blessSuccess ? "SUCCEEDED" : "FAILED") });
// Clear the WiFi credentials and reboot if blessing completes successfully
if (blessSuccess) {
imp.clearconfiguration();
imp.setcountry(getRegionCode(WIFI_REGION));
// The imp will go idle at this point, allowing impOS to install
// application code and restart the Squirrel VM if the Production Device Group’s
// devices are set to receive application code immediately after blessing
// If you are installing your application upon device activation (first
// end-user BlinkUp), you can power down the device at this point
}
});
}
function getRegionCode(location = "US") {
// Pass in the region ID, eg. "UK", "US", to receive the code for that region
local type = imp.info().type;
local returnCode = 0;
// Region codes data organized by territory code
// Each region has two values: the first for imp001 through imp004m, the second for imp005
// NOTE select "OT" for all regions than those listed (US, Canada, Europe/UK, Japan)
local codes = { "US" : [0x00005355, 0x00115858],
"CA" : [0x00005355, 0x03B64143],
"EU" : [0x00004247, 0x037F3045],
"JA" : [0x00004247, 0x03B8504A],
"OT" : [0x00004247, 0x03D75658] }
if (location in codes) {
returnCode = codes[location];
returnCode = returnCode[(type == "imp005" ? 1 : 0)];
} else {
server.error("Invalid region ID supplied - choosing US");
returnCode = codes.US[(type == "imp005" ? 1 : 0)];
}
server.log(format("Region code chosen: 0x%08X", returnCode));
return returnCode;
}
// ***************************************
// ***** YOUR HARDWARE TEST CODE *****
// ***************************************
function myTestFunction() {
// Run your tests here
// Returning false will prevent blessing and pass a "FAILED" to the test results webhook
return true;
}
// ***************************************
// ***** RUNTIME START *****
// ***************************************
// Test and bless the DUT
blessDeviceUnderTest();
// ------------------------------------------------------------------------------
// File: factory.firmware.fixture.agent.nut
// Version: 2.1.1
//
// Copyright 2020 Twilio
//
// SPDX-License-Identifier: MIT
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// ------------------------------------------------------------------------------
// ***************************************
// ***** SETUP *****
// ***************************************
// IMPORTS
// Load in the Rocky library to manage messages from DUT agents
#require "rocky.agent.lib.nut:3.0.0"
// CONSTANTS
// Replace the following string with your server logging endpoint
const RESULTS_URL = "YOUR_RESULT_LOGGING_URL";
// GLOBALS
local blinkUpCount = 0;
// ***************************************
// ***** FACTORY FIXTURE AGENT CODE ****
// ***************************************
// Set up a receiver for "blinkup.sent" messages from the factory fixture
// This will NOT be called by a DUT, because our device-side firmware
// only sends this message from factory fixtures
device.on("blinkup.sent", function(value) {
// Increment the BlinkUp tally
blinkUpCount++;
// Prepare the notification
local deviceID = imp.configparams.deviceid;
local headers = {"Content-Type": "application/json"};
local data = {};
data.fixture_url <- http.agenturl();
data.fixture_id <- deviceID;
data.blinkup_count <- blinkUpCount;
data.timestamp <- time();
data.message <- format("BlinkUp #%08i triggered by fixture ID %s", blinkUpCount, deviceID);
local body = http.jsonencode(data);
// The following line is helpful for debugging factory firmware during development
server.log(format("Posting message 'blinkup sent' for fixture ID %s: %s", deviceID, body));
// Send the notification to your server
http.post(RESULTS_URL, headers, body).sendasync(function(response) {
if (response.statuscode >= 300) {
// The following line will not be called in a production environment
// unless you have enabled logging for the specific device via impCentral
server.error(format("Failed posting BlinkUp notification for fixture ID %s with response %d:%s", deviceID, response.statuscode, response.body));
}
});
});
// Set up an API to handle messages from DUT agents
local api = Rocky.init();
// Set up a POST endpoint at root to receive messages
api.post("/", function(context) {
try {
// Attempt to decode the received message
local data = http.jsondecode(context.req.rawbody);
// It's good, so log it...
server.log("DUT ID " + data.device_id + " blessing " + data.success.tolower());
// ...and return a 200
context.send(200, "OK");
} catch (err) {
// The incoming message did not decode so post an error...
server.error(err);
// ...and return a 400
context.send(400, "Bad data posted");
}
});
// ------------------------------------------------------------------------------
// File: factory.firmware.fixture.device.nut
// Version: 2.1.1
//
// Copyright 2020 Twilio
//
// SPDX-License-Identifier: MIT
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// ------------------------------------------------------------------------------
// ***************************************
// ***** SETUP *****
// ***************************************
// IMPORTS
// Load the CFAx33KL Library, which abstracts the LCD/Keypad used on the impFactory
#require "CFAx33KL.device.lib.nut:2.0.0"
// Load the Button library to provide debouncing on the footswitch (if installed) and green button
#require "Button.class.nut:1.2.1"
// CONSTANTS
// Enter your factory WiFi credentials as the values of these constants
const SSID = "SSID";
const PASSWORD = "PASSWORD";
// Sets how long to wait (seconds) after triggering BlinkUp before allowing another
const BLINKUP_TIME = 10;
// GLOBALS
// Flag used to prevent new BlinkUp triggers while BlinkUp is running
local sendingBlinkUp = false;
local blinkUpCount = 0;
// ***************************************
// ***** FACTORY FIXTURE FUNCTIONS *****
// ***************************************
function blinkupTriggered() {
// Trigger only when BlinkUp is not already running
if (!sendingBlinkUp) {
sendingBlinkUp = true;
imp.wakeup(BLINKUP_TIME, function() {
sendingBlinkUp = false;
});
// Configure factory BlinkUp
// NOTE Depending on which LED you connect to your impFactory, you may need
// to remove the 'BLINKUP_ACTIVEHIGH' option (default is BLINKUP_ACTIVELOW)
local optionFlags = BLINKUP_FAST | BLINKUP_ACTIVEHIGH;
// Send factory BlinkUp
server.factoryblinkup(SSID, PASSWORD, blinkupPin, optionFlags);
// Signal the agent that BlinkUp has been performed
agent.send("blinkup.sent", true);
// Update the fixture display
blinkUpCount++;
lcd.setLine2(format("BlinkUp #%07i ", blinkUpCount));
}
}
function configureFactoryFixture() {
// Assign pins
greenBtn <- Button(hardware.pinC, DIGITAL_IN, Button.NORMALLY_HIGH, null, blinkupTriggered.bindenv(this));
footSwitch <- Button(hardware.pinH, DIGITAL_IN, Button.NORMALLY_HIGH, null, blinkupTriggered.bindenv(this));
ledGreen <- hardware.pinE;
ledRed <- hardware.pinF;
blinkupPin <- hardware.pinM;
// Initialize front panel LEDs to Off
ledRed.configure(DIGITAL_OUT, 0);
ledGreen.configure(DIGITAL_OUT, 0);
// Print a message on the LCD and store it as default
lcd <- CFAx33KL(hardware.uart2);
lcd.clearAll();
lcd.setLine1("Electric Imp");
lcd.setLine2("impFactory");
lcd.setBrightness(100);
lcd.storeCurrentStateAsBootState();
}
// ***************************************
// ***** RUNTIME START *****
// ***************************************
// Configure the fixture for BlinkUp
configureFactoryFixture();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment