Zero Touch Provisioning Based on TLS 1.3
Device configuration from the cloud with TLS 1.3 security.
Components and supplies
1
LED 10mm
1
Resistor 220 Ohm
1
Arduino MKR GSM 1400
1
Luner IoT SIM
Tools and machines
1
Arduino IDE
Apps and platforms
1
Luner IoT Suite
Project description
Code
ZeroTouchProvisioning
c_cpp
Automatic device configuration based on TLS 1.3 authentisity and security
1#include <MKRGSM.h> 2#include <ArduinoUniqueID.h> 3#include <ArduinoJson.h> 4 5// LED (Config) 6#define PIN_LED 7 7 8// number of loops to wait for the end of initialization 9#define TECHNOLOGY_INIT_WAITING 7 10 11#define LEN_MODEM_AT 4 12const unsigned char MODEM_AT[LEN_MODEM_AT] = {'a', 't', '\r', '\n'}; 13 14 15#define LEN_MODEM_AT_CREG 10 16const unsigned char MODEM_AT_CREG[LEN_MODEM_AT_CREG] = {'a', 't', '+', 'c', 'r', 'e', 'g', '?', '\r', '\n'}; 17 18#define LEN_MODEM_CREG 8 19const char MODEM_CREG[LEN_MODEM_CREG] = {'+', 'C', 'R', 'E', 'G', ':', ' ', '\\0'}; 20 21#define LEN_MODEM_AT_CSIM 8 22const unsigned char MODEM_AT_CSIM[LEN_MODEM_AT_CSIM] = {'a', 't', '+', 'c', 's', 'i', 'm', '='}; 23 24#define LEN_MODEM_CSIM 8 25const char MODEM_CSIM[LEN_MODEM_CSIM] = {'+', 'C', 'S', 'I', 'M', ':', ' ', '\\0'}; 26 27#define LEN_APDU_HEADER 5 28 29const char APDU_MANAGE_CHANNEL[LEN_APDU_HEADER] = { 0x00, 0x70, 0x00, 0x00, 0x00 }; 30 31const char APDU_SELECT[LEN_APDU_HEADER] = { 0x00, (char)0xA4, 0x04, 0x0C, 0x00 }; 32 33#define APDU_ISO_CLA 0x00 34 35#define APDU_PUT_DATA_INS 0xda 36#define APDU_PUT_DATA_P1 0x02 37 38#define APDU_GET_DATA_INS 0xca 39#define APDU_GET_DATA_MODE_REQUEST 0x00 40#define APDU_GET_DATA_MODE_DATA 0x01 41 42#define APDU_GET_STATUS_INS 0xcc 43#define APDU_GET_STATUS_MODE_GET 0x02 44#define APDU_GET_STATUS_LEN_GET 0x04 45 46#define APDU_GET_RESPONSE_INS 0xc0 47 48 49#define STATUS_RECEIVE_DONE 0x0003 50#define STATUS_RECEIVE_DATA 0x0007 51#define STATUS_RECEIVE_ERROR 0x000f 52#define LEN_AID_SAFE2 12 53const char AID_SAFE2[LEN_AID_SAFE2] = {(char)0xf0, 0x70, 0x6F, 0x64, 0x67, 0x73, 0x61, 0x66, 0x65, 0x32, 0x01, 0x01 }; 54 55#define LEN_MODEM_OK 4 56const char MODEM_OK[LEN_MODEM_OK] = {'O', 'K', '\r', '\\0'}; 57 58#define LEN_MODEM_ERROR 7 59const char MODEM_ERROR[LEN_MODEM_ERROR] = {'E', 'R', 'R', 'O', 'R', '\r', '\\0'}; 60 61#define LEN_1_CHAR_MAX 10 62#define LEN_2_CHARS_MAX 100 63 64#define CR '\r' 65#define EOL '\n' 66 67// IO buffer used for AT commands proceeding, size = header + 256 * 2 68#define LEN_IO_BUFFER 600 69char buf[LEN_IO_BUFFER]; 70 71#define LEN_DATA_BUF 4 72unsigned char dataBuf[LEN_DATA_BUF]; 73 74unsigned char apdu_header[LEN_APDU_HEADER]; 75 76unsigned char regFlag; 77 78#define STATE_READY 0x00 79#define STATE_REQUEST_SENT 0x01 80#define STATE_REQUEST_DATA 0x02 81#define STATE_DONE 0x03 82 83#define LEN_DEVICE_ID_MAX 16 84unsigned char id[LEN_DEVICE_ID_MAX]; 85 86char gState; 87char gChan; 88 89#define JSON_CONFIG_CAPACITY 384 90 91 92//DynamicJsonDocument cfg(JSON_CONFIG_CAPACITY); 93StaticJsonDocument<192> cfg; 94 95 96char registered(char * resp) { 97 char b = *resp; 98 b &= 0x0f; 99 resp++; 100 if (*resp != CR) { 101 // 2-chars <stat> value 102 b *= 10; 103 b += *resp - 0x30; 104 } 105 switch (b) { 106 case 1: // 1: registered, home network 107 case 5: // 5: registered, roaming 108 return true; 109 110 default: 111 return false; 112 } 113} 114 115void logData(char * dataBuf, char len) { 116 int dataLen = (unsigned char)len; 117 int blockLen; 118 int ofs = 0; 119 while (dataLen > 0) { 120 blockLen = Serial.availableForWrite(); 121 if (blockLen < 1) { 122 delay(1); 123 continue; 124 } 125 if (blockLen > dataLen) { 126 blockLen = dataLen; 127 } 128 Serial.write(&dataBuf[ofs], blockLen); 129 ofs += blockLen; 130 dataLen -= blockLen; 131 } 132 Serial.flush(); 133} 134 135 136void atCommand(char * cmdBuf, short len) { 137 short cmdLen = len; 138 short blockLen; 139 short ofs = 0; 140 while (cmdLen > 0) { 141 blockLen = SerialGSM.availableForWrite(); 142 if (blockLen < 1) { 143 delay(1); 144 continue; 145 } 146 if (blockLen > cmdLen) { 147 blockLen = cmdLen; 148 } 149 SerialGSM.write(&cmdBuf[ofs], blockLen); 150 ofs += blockLen; 151 cmdLen -= blockLen; 152 } 153 SerialGSM.flush(); 154} 155 156#define CNTR_MAX 10000 157 158short atResponse(char * respBuf) { 159 // read AT response 160 short cntr = 0; 161 char * ptr; 162 short len = 0; 163 short blockLen; 164 165 // initialize for timeout 166 respBuf[0] = 0; 167 do { 168 blockLen = SerialGSM.readBytesUntil(EOL, &respBuf[len], (int)(LEN_IO_BUFFER - len)); 169 if (blockLen > 0) { 170 len += blockLen; 171 respBuf[len++] = EOL; 172 respBuf[len] = 0; 173 } 174 175 ptr = strstr(respBuf, MODEM_OK); 176 if (ptr == NULL) { 177 ptr = strstr(respBuf, MODEM_ERROR); 178 } 179 180 } while (ptr == NULL); 181 return len; 182} 183 184char decimalPut(int v, char * dst) { 185 char ofs = 0; 186 // number of chars populated 187 char cnt = 1; 188 char b; 189 // safety check - shall be redesigned for negative numbers 190 if (v < 0) { 191 v = 0; 192 } 193 if (v >= LEN_1_CHAR_MAX) { 194 ofs++; 195 cnt++; 196 } 197 if (v >= LEN_2_CHARS_MAX) { 198 ofs++; 199 cnt++; 200 } 201 // at least 1 digit shall be populated 202 do { 203 b = (char)(v % 10); 204 dst[ofs--] = '0' + b; 205 v -= b; 206 v /= 10; 207 } while (v > 0); 208 return cnt; 209} 210 211#define LEN_HEX 16 212const char HEX_CONVERSION[LEN_HEX] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; 213 214void hexPut(char b, char * dst) { 215 dst[0] = HEX_CONVERSION[(b >> 4) & 0x0f]; 216 dst[1] = HEX_CONVERSION[b & 0x0f]; 217} 218 219#define LEN_BYTE_HEX 2 220 221short buildAtCsim(char * cmdBuf, char cla, char * apduBuf, char * dataBuf, short dataLen) { 222 short len = LEN_APDU_HEADER; 223 short ofs = 0; 224 if (dataBuf != NULL) { 225 len += dataLen; 226 } 227 memcpy(cmdBuf, MODEM_AT_CSIM, LEN_MODEM_AT_CSIM); 228 ofs = LEN_MODEM_AT_CSIM; 229 ofs += decimalPut(len << 1, &cmdBuf[ofs]); 230 cmdBuf[ofs++] = ','; 231 cmdBuf[ofs++] = '"'; 232 233 // put CLA 234 hexPut(apduBuf[0] | cla, &cmdBuf[ofs]); 235 ofs += LEN_BYTE_HEX; 236 // put INS, P1, P2 237 for (char i=1; i<4; i++) { 238 hexPut(apduBuf[i], &cmdBuf[ofs]); 239 ofs += LEN_BYTE_HEX; 240 } 241 // put LEN 242 hexPut(dataLen, &cmdBuf[ofs]); 243 ofs += LEN_BYTE_HEX; 244 if ((dataLen > 0) && (dataBuf != NULL)) { 245 // put Data 246 for (short i=0; i<dataLen; i++) { 247 hexPut(dataBuf[i], &cmdBuf[ofs]); 248 ofs += LEN_BYTE_HEX; 249 } 250 } 251 252 cmdBuf[ofs++] = '"'; 253 cmdBuf[ofs++] = '\r'; 254 cmdBuf[ofs++] = '\n'; 255 cmdBuf[ofs] = 0; 256 return ofs; 257} 258 259#define RES_OK 0x00 260#define RES_INVALID_CSIM_RESPONSE 0x01 261#define RES_INVALID_OPEN_CHANNEL_RESPONSE 0x02 262#define RES_INVALID_CHANNEL_ID 0x03 263#define RES_UNEXPECTED_GET_STATUS_RESPONSE 0x04 264#define RES_INVALID_GET_STATUS_RESPONSE 0x05 265#define RES_UNEXPECTED_GET_DATA_RESPONSE 0x06 266#define RES_INVALID_GET_DATA_RESPONSE 0x07 267#define RES_JSON_DESERIALIZATION_FAILED 0x08 268 269#define OFS_APDU_CLA 0x00 270#define OFS_APDU_INS 0x01 271#define OFS_APDU_P1 0x02 272#define OFS_APDU_P2 0x03 273#define OFS_APDU_LEN 0x05 274 275#define MODE_CHANNEL_CLOSE 0x80 276 277#define TAG_DEVICE_ID 0xc0 278#define TAG_DEVICE_DATA 0xc1 279 280char simChannelOpen(char * chan) { 281 // put AT SIM command: Open Supplementary Logical Channel 282 short cmdLen = buildAtCsim(buf, 0, (char *)APDU_MANAGE_CHANNEL, (char *)NULL, 1); 283 atCommand(buf, cmdLen); 284 short respLen = atResponse(buf); 285 logData(buf, respLen); 286 // analyze response 287 char * ptr; 288 ptr = strstr(buf, MODEM_CSIM); 289 if (ptr == NULL) { 290 Serial.println("CSIM not detected in the response"); 291 return RES_INVALID_CSIM_RESPONSE; 292 } 293 294 if ((ptr[LEN_MODEM_CSIM - 1] != '6') || 295 (ptr[LEN_MODEM_CSIM + 0] != ',') || 296 (ptr[LEN_MODEM_CSIM + 1] != '"') || 297 (ptr[LEN_MODEM_CSIM + 2] != '0')) { 298 299 Serial.println("Unexpected response for MANAGE CHANNEL"); 300 return RES_INVALID_OPEN_CHANNEL_RESPONSE; 301 } 302 303 // extract channel ID 304 char ch = ptr[LEN_MODEM_CSIM + 3] - '0'; 305 if ((ch <= 0) || (ch >= 4)) { 306 Serial.print("Unexpected response (chan ID) for MANAGE CHANNEL: "); 307 Serial.println(ch); 308 return RES_INVALID_CHANNEL_ID; 309 } 310 *chan = ch; 311 return RES_OK; 312} 313 314char simChannelClose(char chan) { 315 // close supplementary logical channel 316 memcpy(apdu_header, APDU_MANAGE_CHANNEL, LEN_APDU_HEADER); 317 apdu_header[OFS_APDU_P1] = MODE_CHANNEL_CLOSE; 318 apdu_header[OFS_APDU_P2] = chan; 319 short cmdLen = buildAtCsim(buf, 0, (char *)apdu_header, (char *)NULL, 0); 320 atCommand(buf, cmdLen); 321 short respLen = atResponse(buf); 322 logData(buf, respLen); 323 return RES_OK; 324} 325 326char simSelectSafe2(char chan) { 327 // SELECT (by AID) SAFE2 328 short cmdLen = buildAtCsim(buf, chan, (char *)APDU_SELECT, (char *)AID_SAFE2, LEN_AID_SAFE2); 329 atCommand(buf, cmdLen); 330 short respLen = atResponse(buf); 331 logData(buf, respLen); 332 return RES_OK; 333} 334 335char simGetData(char chan, char mode, unsigned char * buf, short * len) { 336 // PUT DATA (from dataBuffer) 337 338 char bh, bl; 339 340 apdu_header[OFS_APDU_CLA] = APDU_ISO_CLA; 341 apdu_header[OFS_APDU_INS] = APDU_GET_DATA_INS; 342 apdu_header[OFS_APDU_P1] = mode; 343 apdu_header[OFS_APDU_P2] = 0x00; 344 apdu_header[OFS_APDU_LEN] = 0x00; 345 short cmdLen = buildAtCsim((char *)buf, chan, (char *)apdu_header, NULL, 0); 346 atCommand((char *)buf, cmdLen); 347 short respLen = atResponse((char *)buf); 348 349 if (mode == APDU_GET_DATA_MODE_DATA) { 350 // analyze response 351 char * ptr; 352 ptr = strstr((const char *)buf, MODEM_CSIM); 353 if (ptr == NULL) { 354 Serial.println("CSIM not detected in the response"); 355 return RES_INVALID_CSIM_RESPONSE; 356 } 357 358 // expected response: 4,"61xx" 359 if ((ptr[LEN_MODEM_CSIM - 1] == '4') && 360 (ptr[LEN_MODEM_CSIM + 0] == ',') && 361 (ptr[LEN_MODEM_CSIM + 1] == '"') && 362 (ptr[LEN_MODEM_CSIM + 2] == '6') && 363 (ptr[LEN_MODEM_CSIM + 3] == '1')) { 364 365 bh = hex2val(ptr[LEN_MODEM_CSIM + 4]); 366 bl = hex2val(ptr[LEN_MODEM_CSIM + 5]); 367 if ((bh == -1) || (bl == -1)) { 368 Serial.println("Invalid response for GET DATA (Data)"); 369 return RES_INVALID_GET_DATA_RESPONSE; 370 } 371 unsigned char len = (unsigned char)((bh << 4) | bl); 372 Serial.print("expected data length: "); 373 Serial.println(len, HEX); 374 375 apdu_header[OFS_APDU_CLA] = APDU_ISO_CLA; 376 apdu_header[OFS_APDU_INS] = APDU_GET_RESPONSE_INS; 377 apdu_header[OFS_APDU_P1] = 0x00; 378 apdu_header[OFS_APDU_P2] = 0x00; 379 apdu_header[OFS_APDU_LEN] = len; 380 cmdLen = buildAtCsim((char *)buf, chan, (char *)apdu_header, NULL, len); 381 atCommand((char *)buf, cmdLen); 382 respLen = atResponse((char *)buf); 383 logData((char *)buf, respLen); 384 385 ptr = strstr((const char *)buf, MODEM_CSIM); 386 if (ptr == NULL) { 387 Serial.println("CSIM not detected in the response (GR)"); 388 return RES_INVALID_CSIM_RESPONSE; 389 } 390 } 391 short hlen = 0; 392 short ofs = LEN_MODEM_CSIM - 1; 393 char b; 394 do { 395 b = ptr[ofs++] - 0x30; 396 if ((b < 0) || (b > 9)) { 397 Serial.println("CSIM not detected in the response (GR)"); 398 return RES_INVALID_CSIM_RESPONSE; 399 } 400 hlen *= 10; // shift left for 1 tetrade 401 hlen += b; 402 } while (ptr[ofs] != ','); 403 // skip ',' and '"' 404 ofs += 2; 405 hlen >>= 1; // number of bytes 406 hlen -= 2; // exclude SW 407 Serial.print("received:"); 408 Serial.println(hlen); 409 for (short ii=0; ii<hlen; ii++) { 410 bh = hex2val(ptr[ofs]); 411 bl = hex2val(ptr[ofs + 1]); 412 if ((bh == -1) || (bl == -1)) { 413 Serial.print("Invalid charcters in the response (GR): "); 414 return RES_INVALID_CSIM_RESPONSE; 415 } 416 ofs += 2; 417 buf[ii] = (unsigned char)((bh << 4) | bl); 418 } 419 buf[hlen] = 0; 420 // re-assign response length 421 respLen = hlen; 422 } 423 logData((char *)buf, respLen); 424 Serial.println(); 425 *len = respLen; 426 return RES_OK; 427} 428 429char hex2val(char h) { 430 for (char i=0; i<LEN_HEX; i++) { 431 if (HEX_CONVERSION[i] == h) { 432 return i; 433 } 434 } 435 return -1; 436} 437 438unsigned short chars2short(char * buf) { 439 unsigned char b; 440 unsigned short w = 0; 441 for (char i=0; i<4; i++) { 442 b = hex2val(buf[i]); 443 //Serial.print(b); 444 if (b < 0) { 445 return -1; 446 } 447 w <<= 4; 448 w += b; 449 } 450 return w; 451} 452 453char simGetStatus(char chan, char mode, unsigned char * buf, short * stat, short * data_len) { 454 // PUT DATA (from dataBuffer) 455 456 apdu_header[OFS_APDU_CLA] = APDU_ISO_CLA; 457 apdu_header[OFS_APDU_INS] = APDU_GET_STATUS_INS; 458 apdu_header[OFS_APDU_P1] = mode; 459 apdu_header[OFS_APDU_P2] = 0x00; 460 apdu_header[OFS_APDU_LEN] = 0x00; 461 short cmdLen = buildAtCsim((char *)buf, chan, (char *)apdu_header, NULL, 0); 462 atCommand((char *)buf, cmdLen); 463 short respLen = atResponse((char *)buf); 464 logData((char *)buf, respLen); 465 466 // analyze response 467 char * ptr; 468 ptr = strstr((const char *)buf, MODEM_CSIM); 469 if (ptr == NULL) { 470 Serial.println("CSIM not detected in the response (GS)"); 471 return RES_INVALID_CSIM_RESPONSE; 472 } 473 474 // expected response: 4,"6104" 475 if ((ptr[LEN_MODEM_CSIM - 1] == '4') && 476 (ptr[LEN_MODEM_CSIM + 0] == ',') && 477 (ptr[LEN_MODEM_CSIM + 1] == '"') && 478 (ptr[LEN_MODEM_CSIM + 2] == '6') && 479 (ptr[LEN_MODEM_CSIM + 3] == '1') && 480 (ptr[LEN_MODEM_CSIM + 4] == '0') && 481 (ptr[LEN_MODEM_CSIM + 5] == '4')) { 482 483 apdu_header[OFS_APDU_CLA] = APDU_ISO_CLA; 484 apdu_header[OFS_APDU_INS] = APDU_GET_RESPONSE_INS; 485 apdu_header[OFS_APDU_P1] = 0x00; 486 apdu_header[OFS_APDU_P2] = 0x00; 487 apdu_header[OFS_APDU_LEN] = APDU_GET_STATUS_LEN_GET; 488 cmdLen = buildAtCsim((char *)buf, chan, (char *)apdu_header, NULL, APDU_GET_STATUS_LEN_GET); 489 atCommand((char *)buf, cmdLen); 490 respLen = atResponse((char *)buf); 491 logData((char *)buf, respLen); 492 493 ptr = strstr((const char *)buf, MODEM_CSIM); 494 if (ptr == NULL) { 495 Serial.println("CSIM not detected in the response (GR)"); 496 return RES_INVALID_CSIM_RESPONSE; 497 } 498 } 499 500 // expected response: [receiveStatus:2][receiveLength:2][SW:2] => 12 chars 501 if ((ptr[LEN_MODEM_CSIM - 1] != '1') || 502 (ptr[LEN_MODEM_CSIM + 0] != '2') || 503 (ptr[LEN_MODEM_CSIM + 1] != ',') || 504 (ptr[LEN_MODEM_CSIM + 2] != '"')) { 505 506 Serial.println("Unexpected response for GET STATUS (Receive)"); 507 return RES_UNEXPECTED_GET_STATUS_RESPONSE; 508 } 509 510 // extract status & length 511 //Serial.println("status"); 512 short wStatus = chars2short(&ptr[LEN_MODEM_CSIM + 3]); 513 if (wStatus < 0) { 514 Serial.println("Invalid response for GET STATUS (Receive)"); 515 return RES_INVALID_GET_STATUS_RESPONSE; 516 } 517 //Serial.println("length"); 518 short wLength = chars2short(&ptr[LEN_MODEM_CSIM + 3 + 4]); 519 if (wLength < 0) { 520 Serial.println("Invalid response for GET STATUS (Receive)"); 521 return RES_INVALID_GET_STATUS_RESPONSE; 522 } 523 //Serial.println(); 524 *stat = wStatus; 525 *data_len = wLength; 526 return RES_OK; 527} 528 529 530char send(unsigned char tag, unsigned char * dataPtr, short dataLen) { 531 532 short cmdLen = 0; 533 short respLen = 0; 534 char chan = 0; 535 // put AT SIM command: Open Supplementary Logical Channel 536 cmdLen = buildAtCsim((char *)buf, 0, (char *)APDU_MANAGE_CHANNEL, NULL, 1); 537 atCommand((char *)buf, cmdLen); 538 respLen = atResponse((char *)buf); 539 logData((char *)buf, respLen); 540 // analyze response 541 char * ptr; 542 ptr = strstr((const char *)buf, MODEM_CSIM); 543 if (ptr == NULL) { 544 Serial.println("CSIM not detected in the response"); 545 return RES_INVALID_CSIM_RESPONSE; 546 } 547 548 if ((ptr[LEN_MODEM_CSIM - 1] != '6') || 549 (ptr[LEN_MODEM_CSIM + 0] != ',') || 550 (ptr[LEN_MODEM_CSIM + 1] != '"') || 551 (ptr[LEN_MODEM_CSIM + 2] != '0')) { 552 553 Serial.println("Unexpected response for MANAGE CHANNEL"); 554 return RES_INVALID_OPEN_CHANNEL_RESPONSE; 555 } 556 557 // extract channel ID 558 chan = ptr[LEN_MODEM_CSIM + 3] - '0'; 559 if ((chan <= 0) || (chan >= 4)) { 560 Serial.print("Unexpected response (chan ID) for MANAGE CHANNEL: "); 561 Serial.println(chan); 562 return RES_INVALID_CHANNEL_ID; 563 } 564 // SELECT (by AID) SAFE2 565 cmdLen = buildAtCsim((char *)buf, chan, (char *)APDU_SELECT, (char *)AID_SAFE2, LEN_AID_SAFE2); 566 atCommand((char *)buf, cmdLen); 567 respLen = atResponse((char *)buf); 568 logData((char *)buf, respLen); 569 570 // PUT DATA (from dataBuffer) 571 char apdu_header[LEN_APDU_HEADER]; 572 apdu_header[OFS_APDU_CLA] = APDU_ISO_CLA; 573 apdu_header[OFS_APDU_INS] = APDU_PUT_DATA_INS; 574 apdu_header[OFS_APDU_P1] = APDU_PUT_DATA_P1; 575 apdu_header[OFS_APDU_P2] = tag; 576 apdu_header[OFS_APDU_LEN] = 0x00; 577 cmdLen = buildAtCsim(buf, chan, (char *)apdu_header, (char *)dataPtr, dataLen); 578 atCommand(buf, cmdLen); 579 respLen = atResponse(buf); 580 logData(buf, respLen); 581 582 // close supplementary logical channel 583 memcpy(apdu_header, APDU_MANAGE_CHANNEL, LEN_APDU_HEADER); 584 apdu_header[OFS_APDU_P1] = MODE_CHANNEL_CLOSE; 585 apdu_header[OFS_APDU_P2] = chan; 586 cmdLen = buildAtCsim(buf, 0, apdu_header, NULL, 0); 587 atCommand(buf, cmdLen); 588 respLen = atResponse(buf); 589 logData(buf, respLen); 590 return RES_OK; 591} 592 593#define LEN_NAME_CONTROL_LED 9 594const char NAME_CONTROL_LED[LEN_NAME_CONTROL_LED] = { 'i', 'o', 't', ':', 'A', 'l', 'a', 'r', 'm' }; 595 596#define LEN_NAME_EFFECT_ON 2 597const char NAME_EFFECT_ON[LEN_NAME_EFFECT_ON] = { 'O', 'n' }; 598 599char configParseApply(const char * buf, short dataLen) { 600 601 DeserializationError error = deserializeJson(cfg, buf, dataLen); 602 603 if (error) { 604 Serial.print(F("deserializeJson() failed: ")); 605 Serial.println(error.f_str()); 606 return RES_JSON_DESERIALIZATION_FAILED; 607 } 608 609 const char* cfg_version = cfg["configuration"]["version"]; // "2020-10-13" 610 Serial.print("configuration version: "); 611 Serial.println(cfg_version); 612 613 const char* cfg_config_0_action = cfg["configuration"]["config"][0]["action"]; // "iot:Alarm" 614 const char* cfg_config_0_effect = cfg["configuration"]["config"][0]["effect"]; // "On" 615 616 if (memcmp(cfg_config_0_action, NAME_CONTROL_LED, LEN_NAME_CONTROL_LED) == 0) { 617 if (memcmp(cfg_config_0_effect, NAME_EFFECT_ON, LEN_NAME_EFFECT_ON) == 0) { 618 Serial.println("iot:Alarm configured as ON"); 619 digitalWrite(PIN_LED, HIGH); 620 } else { 621 Serial.println("iot:Alarm configured as OFF"); 622 digitalWrite(PIN_LED, LOW); 623 } 624 } 625 626} 627 628void setup() { 629 // initialize digital pin LED (#7) as an output 630 pinMode(PIN_LED, OUTPUT); 631 632 // reset the ublox module 633 pinMode(GSM_RESETN, OUTPUT); 634 digitalWrite(GSM_RESETN, HIGH); 635 delay(100); 636 digitalWrite(GSM_RESETN, LOW); 637 delay(300); 638 639 // Open serial communications and wait for port to open: 640 Serial.begin(9600); 641 while (!Serial) { 642 ; // wait for serial port to connect 643 } 644 Serial.println("MKR AT"); 645 // put Device ID 646 short sz = 0; 647 for (short i=0; i<UniqueIDsize; i++) { 648 hexPut(UniqueID[i], &buf[sz]); 649 sz += 2; 650 } 651 logData(buf, sz); 652 Serial.println(); 653 // initialize modem AT interface 654 SerialGSM.begin(9600); 655 656 regFlag = false; 657 char ready = 0; 658 unsigned char b = 0; 659 unsigned char pos = 0; 660 do { 661 // put AT command 662 logData((char *)MODEM_AT, LEN_MODEM_AT); 663 SerialGSM.write(MODEM_AT, LEN_MODEM_AT); 664 delay(100); 665 // modem could not respond during initialization 666 if (SerialGSM.available()) { 667 ready = 1; 668 while (SerialGSM.available()) { 669 b = SerialGSM.read(); 670 Serial.write(b); 671 delay(10); 672 } 673 } 674 delay(300); 675 } while (ready == 0); 676 677 unsigned char cntr = 0; 678 while (cntr < TECHNOLOGY_INIT_WAITING) { 679 // wait for a half of a second 680 delay(500); 681 682 // put AT command 683 logData((char *)MODEM_AT_CREG, LEN_MODEM_AT_CREG); 684 atCommand((char *)MODEM_AT_CREG, LEN_MODEM_AT_CREG); 685 // read AT response 686 pos = atResponse(buf); 687 688 // analyze response 689 char * ptr; 690 ptr = strstr(buf, MODEM_CREG); 691 if (ptr != NULL) { 692 regFlag = registered(&ptr[LEN_MODEM_CREG + 1]); 693 Serial.write(ptr[LEN_MODEM_CREG - 1]); 694 Serial.write(':'); 695 Serial.write(ptr[LEN_MODEM_CREG + 1]); 696 Serial.println(); 697 } else { 698 Serial.println("not found `+CREG`"); 699 } 700 if (regFlag) { 701 cntr++; 702 } 703 Serial.print("cntr: "); 704 Serial.println(cntr); 705 // wait 1 sec before repeat 706 delay(1000); 707 } 708 Serial.println("setup finished"); 709 710 711 // put Device ID 712 short idLen = UniqueIDsize; 713 if (idLen > LEN_DEVICE_ID_MAX) { 714 idLen = LEN_DEVICE_ID_MAX; 715 } 716 memcpy(id, (void *)UniqueID, idLen); 717 char res = send(TAG_DEVICE_ID, &id[0], idLen); 718 if (res == RES_OK) { 719 Serial.println("Set Device ID: OK"); 720 } else { 721 Serial.println("Set Device ID: ERROR"); 722 } 723 724 gState = STATE_READY; 725} 726 727void loop() { 728 729 unsigned char secs; 730 short dataLen = 0; 731 short receiveState, receiveRes; 732 char rv; 733 734 735 if (gState == STATE_READY) { 736 rv = simChannelOpen(&gChan); 737 if (rv == RES_OK) { 738 rv = simSelectSafe2(gChan); 739 } 740 if (rv == RES_OK) { 741 rv = simGetData(gChan, (char)APDU_GET_DATA_MODE_REQUEST, (unsigned char *)buf, &dataLen); 742 } 743 if (rv == RES_OK) { 744 gState = STATE_REQUEST_SENT; 745 } else { 746 gState = STATE_DONE; 747 } 748 } 749 if (gState == STATE_REQUEST_SENT) { 750 751 for (secs=0; secs < 15; secs++) { 752 delay(1000); 753 } 754 rv = simGetStatus(gChan, APDU_GET_STATUS_MODE_GET, (unsigned char *)buf, &receiveState, &receiveRes); 755 Serial.print("receiving state: "); 756 Serial.println(receiveState, HEX); 757 if (receiveState == STATUS_RECEIVE_DATA) { 758 gState = STATE_REQUEST_DATA; 759 return; 760 } 761 if (receiveState == STATUS_RECEIVE_DONE) { 762 if (receiveRes != 0) { 763 Serial.print("receiving error: "); 764 Serial.println(receiveRes, HEX); 765 gState = STATE_DONE; 766 return; 767 } 768 } 769 if (rv != RES_OK) { 770 gState = STATE_DONE; 771 } 772 return; 773 } 774 if (gState == STATE_REQUEST_DATA) { 775 rv = simGetData(gChan, APDU_GET_DATA_MODE_DATA, (unsigned char *)buf, &dataLen); 776 if (rv == RES_OK) { 777 rv = configParseApply(buf, dataLen); 778 } 779 gState = STATE_DONE; 780 } 781 if (gState == STATE_DONE) { 782 simChannelClose(gChan); 783 gState = STATE_READY; 784 785 Serial.print("waiting"); 786 unsigned char minutes = 5; 787 788 while (minutes > 0) { 789 for (secs=0; secs < 60; secs++) { 790 delay(1000); 791 } 792 minutes -= 1; 793 Serial.print('.'); 794 } 795 Serial.println(); 796 return; 797 } 798}
Downloadable files
Connection schema
Connection schema

Connection schema
Connection schema

Comments
Only logged in users can leave comments