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\n Head "
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\n 1: LTE-M\r\n 2: NB-IoT\r\n Please 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+
20492215void 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\n Press enter to return to the main menu" ),
2258+ nullptr ,
2259+ 0 );
2260+ break ;
2261+
20872262 default :
20882263 break ;
20892264 }
0 commit comments