Skip to content

Commit a4f6a90

Browse files
committed
MCU8MASS-2405 Add provisioning option to switch between LTE-M and NB-IoT
1 parent f38d322 commit a4f6a90

File tree

2 files changed

+190
-2
lines changed

2 files changed

+190
-2
lines changed

examples/provision/provision.ino

Lines changed: 177 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#include "security_profile.h"
1313
#include "sequans_controller.h"
1414

15+
#include "types.h"
16+
1517
#include "cryptoauthlib/lib/atcacert/atcacert_client.h"
1618
#include "cryptoauthlib/lib/atcacert/atcacert_def.h"
1719
#include "cryptoauthlib/lib/cryptoauthlib.h"
@@ -2046,6 +2048,170 @@ void provisionHttp() {
20462048
askInputQuestion(F("Press enter to return to the main menu"), nullptr, 0);
20472049
}
20482050

2051+
bool queryOperatingMode(OperatingMode* operating_mode) {
2052+
2053+
char mode_buffer[32] = "";
2054+
2055+
const ResponseResult result = SequansController.writeCommand(
2056+
F("AT+SQNMODEACTIVE?"),
2057+
mode_buffer,
2058+
sizeof(mode_buffer));
2059+
2060+
if (result != ResponseResult::OK) {
2061+
SerialModule.println(F("Failed to query operating mode"));
2062+
return false;
2063+
}
2064+
2065+
char raw_mode_buffer[8] = "";
2066+
2067+
const bool extracted = SequansController.extractValueFromCommandResponse(
2068+
mode_buffer,
2069+
0,
2070+
raw_mode_buffer,
2071+
sizeof(raw_mode_buffer));
2072+
2073+
if (!extracted) {
2074+
SerialModule.println(
2075+
F("Failed to extract operating mode from command response"));
2076+
return false;
2077+
}
2078+
2079+
char* endptr = NULL;
2080+
const int mode = strtol(raw_mode_buffer, &endptr, 10);
2081+
2082+
if (*endptr != '\0') {
2083+
SerialModule.printf(F("Conversion error, non-convertible part: %s\n"),
2084+
endptr);
2085+
return false;
2086+
}
2087+
2088+
*operating_mode = static_cast<OperatingMode>(mode);
2089+
2090+
return true;
2091+
}
2092+
2093+
void provisionOperatingMode() {
2094+
2095+
SerialModule.println("\r\n");
2096+
2097+
// ------------------------------------------------------------------------
2098+
// Step 1: Check modem version
2099+
// ------------------------------------------------------------------------
2100+
2101+
char version_result_buffer[64] = "";
2102+
ResponseResult result = SequansController.writeCommand(
2103+
"ATI1",
2104+
version_result_buffer,
2105+
sizeof(version_result_buffer));
2106+
2107+
if (result != ResponseResult::OK) {
2108+
SerialModule.printf(
2109+
F("Failed to retrieve modem firmware version.\r\n"));
2110+
return;
2111+
}
2112+
2113+
// Dual mode FW is version 8.2, whereas single mode is 8.0. We expect output
2114+
// on the following form:
2115+
//
2116+
// UE8.x.x.x
2117+
// LR8.x.x.x-xxxxx
2118+
//
2119+
const char* prefix = "UE";
2120+
const char* start = strstr(version_result_buffer, prefix);
2121+
2122+
if (start == NULL) {
2123+
SerialModule.printf(
2124+
F("Failed to retrieve modem firmware version.\r\n"));
2125+
return;
2126+
}
2127+
2128+
start += strlen(prefix);
2129+
2130+
int major = 0;
2131+
int minor = 0;
2132+
int patch = 0;
2133+
int build = 0;
2134+
const size_t items_parsed =
2135+
sscanf(start, "%d.%d.%d.%d", &major, &minor, &patch, &build);
2136+
2137+
if (items_parsed != 4) {
2138+
SerialModule.printf(
2139+
F("Failed to retrieve modem firmware version.\r\n"));
2140+
return;
2141+
}
2142+
2143+
if (!(major == 8 && minor == 2)) {
2144+
SerialModule.printf(
2145+
F("Current modem version %d.%d.%d.%d does not "
2146+
"support dual mode (NB-IoT + LTE-M). You need to upgrade the "
2147+
"modem firmware.\r\nHead "
2148+
"to iot.microchip.com/docs/arduino/userguide/sequans_modem for "
2149+
"instructions.\r\n"),
2150+
major,
2151+
minor,
2152+
patch,
2153+
build);
2154+
return;
2155+
}
2156+
2157+
// ------------------------------------------------------------------------
2158+
// Step 2: Change mode
2159+
// ------------------------------------------------------------------------
2160+
2161+
const uint8_t mode = askNumberedQuestion(
2162+
F("Select mode:\r\n1: LTE-M\r\n2: NB-IoT\r\nPlease choose (press "
2163+
"enter "
2164+
"when done): "),
2165+
1,
2166+
2);
2167+
2168+
SerialModule.println("\r\n");
2169+
SerialModule.println(F("Writing configuration..."));
2170+
2171+
result =
2172+
SequansController.writeCommand(F("AT+SQNMODEACTIVE=%d"), NULL, 0, mode);
2173+
2174+
if (result != ResponseResult::OK) {
2175+
SerialModule.println(F("Failed to change operating mode"));
2176+
return;
2177+
}
2178+
2179+
// ------------------------------------------------------------------------
2180+
// Step 3: Reset and validate
2181+
// ------------------------------------------------------------------------
2182+
2183+
SequansController.writeCommand(F("AT^RESET"));
2184+
2185+
if (!SequansController.waitForURC("SYSSTART", NULL, 0, 6000)) {
2186+
SerialModule.println(F("Modem did not wake up after reset!"));
2187+
return;
2188+
}
2189+
2190+
OperatingMode operating_mode = OperatingMode::Unknown;
2191+
const bool success = queryOperatingMode(&operating_mode);
2192+
2193+
if (!success) {
2194+
SerialModule.println(F("Failed to query operating mode after reset"));
2195+
return;
2196+
}
2197+
2198+
SerialModule.printf(F("Operating mode is now: "));
2199+
2200+
switch (operating_mode) {
2201+
case OperatingMode::LteM:
2202+
SerialModule.printf(F("LTE-M\r\n"));
2203+
break;
2204+
2205+
case OperatingMode::NbIoT:
2206+
SerialModule.printf(F("NB-IoT\r\n"));
2207+
break;
2208+
2209+
default:
2210+
SerialModule.printf(F("Unknown. This should not happen!\r\n"));
2211+
break;
2212+
}
2213+
}
2214+
20492215
void setup() {
20502216
LedCtrl.begin();
20512217
LedCtrl.startupCycle();
@@ -2068,12 +2234,13 @@ void loop() {
20682234
"strings well.\r\n"));
20692235

20702236
const uint8_t provision_type = askNumberedQuestion(
2071-
F("Method to provision\r\n"
2237+
F("Method to provision:\r\n"
20722238
"1: MQTT\r\n"
20732239
"2: HTTP\r\n"
2240+
"3: Operating mode (NB-IoT or LTE-M)\r\n"
20742241
"Please choose (press enter when done): "),
20752242
1,
2076-
2);
2243+
3);
20772244

20782245
switch (provision_type) {
20792246
case 1:
@@ -2084,6 +2251,14 @@ void loop() {
20842251
provisionHttp();
20852252
break;
20862253

2254+
case 3:
2255+
provisionOperatingMode();
2256+
// Dummy question to make sure user reads error messages (if any)
2257+
askInputQuestion(F("\r\nPress enter to return to the main menu"),
2258+
nullptr,
2259+
0);
2260+
break;
2261+
20872262
default:
20882263
break;
20892264
}

examples/provision/types.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* @file types.h
3+
4+
* @brief We need to place this in a separate file due to how Arduino compiles.
5+
Placing this enum in the .ino file ends up in compilation errors.
6+
*/
7+
8+
#ifndef TYPES_H
9+
#define TYPES_H
10+
11+
enum class OperatingMode { LteM = 1, NbIoT, Unknown };
12+
13+
#endif

0 commit comments

Comments
 (0)