diff --git a/.github/workflows/compile-provisioning.yml b/.github/workflows/compile-provisioning.yml new file mode 100644 index 000000000..f291859ac --- /dev/null +++ b/.github/workflows/compile-provisioning.yml @@ -0,0 +1,262 @@ +name: Compile Provisioning + +on: + pull_request: + paths: + - ".github/workflows/compile-provisioning.yml" + - "examples/**" + - "src/**" + push: + paths: + - ".github/workflows/compile-provisioning.yml" + - "examples/**" + - "src/**" + +jobs: + build: + runs-on: ubuntu-latest + + env: + # libraries to install for all boards + UNIVERSAL_LIBRARIES: | + # Install the ArduinoIoTCloud library from the repository + - source-path: ./ + - name: ArduinoHttpClient + version: 0.6.1 + - name: Arduino_DebugUtils + version: 1.4.0 + - name: ArduinoMqttClient + version: 0.1.8 + - name: Arduino_KVStore + version: 1.0.0 + - source-url: https://github.com/pennam/Arduino_ConnectionHandler.git + version: 0f0f4a4ce718fcf2066a092a92cc2fdcd4d8bedd + - name: Arduino_SecureElement + version: 0.4.0 + - name: Arduino_CloudUtils + version: 1.1.1 + - source-url: https://github.com/arduino-libraries/Arduino_UniqueHWId.git + version: 7e1bfeb586cac00f043c39997a1e9937ed8152b0 + - source-url: https://github.com/arduino-libraries/Arduino_NetworkConfigurator.git + version: 3499628000f2b652e856db406e4e02140bf267a6 + # sketch paths to compile (recursive) for all boards + UNIVERSAL_SKETCH_PATHS: | + - examples/utility/Provisioning_2.0 + SKETCHES_REPORTS_PATH: sketches-reports + + strategy: + fail-fast: false + + matrix: + board: + - fqbn: arduino:samd:mkrwifi1010 + type: nina + artifact-name-suffix: arduino-samd-mkrwifi1010 + - fqbn: arduino:samd:nano_33_iot + type: nina + artifact-name-suffix: arduino-samd-nano_33_iot + - fqbn: arduino:mbed_portenta:envie_m7:split=100_0 + type: mbed_portenta + artifact-name-suffix: arduino-mbed_portenta-envie_m7 + - fqbn: arduino:mbed_nano:nanorp2040connect + type: nina + artifact-name-suffix: arduino-mbed_nano-nanorp2040connect + - fqbn: arduino:mbed_nicla:nicla_vision + type: mbed_nicla + artifact-name-suffix: arduino-mbed_nicla-nicla_vision + - fqbn: arduino:mbed_opta:opta + type: mbed_opta + artifact-name-suffix: arduino-mbed_opta-opta + - fqbn: arduino:mbed_giga:giga + type: mbed_giga + artifact-name-suffix: arduino-mbed_giga-giga + - fqbn: arduino:renesas_portenta:portenta_c33 + type: renesas_portenta + artifact-name-suffix: arduino-renesas_portenta-portenta_c33 + - fqbn: arduino:renesas_uno:unor4wifi + type: renesas_uno + artifact-name-suffix: arduino-renesas_uno-unor4wifi + + # make board type-specific customizations to the matrix jobs + include: + # MKR WiFi 1010, Nano 33 IoT, Nano RP2040 Connect + - board: + type: nina + platforms: | + # Install samd and mbed_nano platform via Boards Manager + - name: arduino:samd + version: 1.8.14 + - name: arduino:mbed_nano + version: 4.3.1 + libraries: | + - name: RTCZero + version: 1.6.0 + - name: ArduinoECCX08 + version: 1.3.9 + - name: Adafruit SleepyDog Library + version: 1.6.5 + - name: ArduinoBearSSL + version: 1.7.6 + - source-url: https://github.com/pennam/WiFiNINA.git + version: b9a8d705f85fef8c19862c32e314367d4bba5734 + - source-url: https://github.com/arduino-libraries/SpiNINA.git + version: 4c8f2956b1b9cd421583393421c6c9276ba27614 + - source-url: https://github.com/pennam/ArduinoBLE.git + version: 5915fa2df776e6eb7e9e5afd896ed3d1c048c9c0 + # Portenta + - board: + type: mbed_portenta + platforms: | + # Install mbed_portenta platform via Boards Manager + - name: arduino:mbed_portenta + version: 4.3.1 + libraries: | + - source-url: https://github.com/pennam/Arduino_Cellular.git + version: bfbd25791d200b113d640e16eed43ce547ab0b0c + - name: ArduinoECCX08 + version: 1.3.9 + - name: StreamDebugger + version: 1.0.1 + - name: TinyGsm + version: 0.12.0 + - name: ArduinoBearSSL + version: 1.7.6 + - name: ArduinoBLE + version: 1.4.0 + # Nicla Vision + - board: + type: mbed_nicla + platforms: | + # Install mbed_nicla platform via Boards Manager + - name: arduino:mbed_nicla + version: 4.3.1 + libraries: | + - name: ArduinoBLE + version: 1.4.0 + # Opta + - board: + type: mbed_opta + platforms: | + # Install mbed_opta platform via Boards Manager + - name: arduino:mbed_opta + version: 4.3.1 + libraries: | + - name: ArduinoECCX08 + version: 1.3.9 + - name: ArduinoBearSSL + version: 1.7.6 + - name: ArduinoBLE + version: 1.4.0 + # GIGA + - board: + type: mbed_giga + platforms: | + # Install mbed_giga platform via Boards Manager + - name: arduino:mbed_giga + version: 4.3.1 + libraries: | + - name: ArduinoECCX08 + version: 1.3.9 + - name: ArduinoBearSSL + version: 1.7.6 + - name: ArduinoBLE + version: 1.4.0 + # Portenta C33 + - board: + type: renesas_portenta + platforms: | + # Install renesas_portenta platform via Boards Manager + - name: arduino:renesas_portenta + version: 1.4.1 + libraries: | + - source-url: https://github.com/pennam/Arduino_Cellular.git + version: bfbd25791d200b113d640e16eed43ce547ab0b0c + - name: StreamDebugger + version: 1.0.1 + - name: TinyGsm + version: 0.12.0 + - name: ArduinoBLE + version: 1.4.0 + # UNO R4 WiFi + - board: + type: renesas_uno + platforms: | + # Install renesas_uno platform via Boards Manager + - name: arduino:renesas_uno + version: 1.4.1 + libraries: | + - name: ArduinoBLE + version: 1.4.0 + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Clear cache + run: | + rm -rf ~/.cache + - name: Compile production provisioning sketch + uses: arduino/compile-sketches@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + platforms: ${{ matrix.platforms }} + fqbn: ${{ matrix.board.fqbn }} + libraries: | + ${{ env.UNIVERSAL_LIBRARIES }} + ${{ matrix.libraries }} + sketch-paths: | + ${{ env.UNIVERSAL_SKETCH_PATHS }} + ${{ matrix.sketch-paths }} + enable-deltas-report: "false" + sketches-report-path: ${{ env.SKETCHES_REPORTS_PATH }} + cli-compile-flags: | + - --clean + - --verbose + - --output-dir + - ${{ runner.temp }}/provisioning-prod + - name: Compile staging provisioning sketch + uses: arduino/compile-sketches@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + platforms: ${{ matrix.platforms }} + fqbn: ${{ matrix.board.fqbn }} + libraries: | + ${{ env.UNIVERSAL_LIBRARIES }} + ${{ matrix.libraries }} + sketch-paths: | + ${{ env.UNIVERSAL_SKETCH_PATHS }} + ${{ matrix.sketch-paths }} + enable-deltas-report: "false" + sketches-report-path: ${{ env.SKETCHES_REPORTS_PATH }} + cli-compile-flags: | + - --clean + - --verbose + - --build-property + - "compiler.cpp.extra_flags=-DCOMPILE_TEST=1" + - --output-dir + - ${{ runner.temp }}/provisioning-staging + - name: Write data to size trends report spreadsheet + # Update report on every push to the master branch + if: github.event_name == 'push' && github.ref == 'refs/heads/master' + uses: arduino/report-size-trends@main + with: + sketches-report-path: ${{ env.SKETCHES_REPORTS_PATH }} + google-key-file: ${{ secrets.GOOGLE_KEY_FILE }} + spreadsheet-id: 1I6NZkpZpf8KugBkE92adB1Z3_b7ZepOpCdYTOigJpN4 + + - name: Save memory usage change report as artifact + if: github.event_name == 'pull_request' + uses: actions/upload-artifact@v4 + with: + name: sketches-report-${{ matrix.board.artifact-name-suffix }} + path: ${{ env.SKETCHES_REPORTS_PATH }} + + - name: Save production artifact + uses: actions/upload-artifact@v4 + with: + name: provisioning-prod-${{ matrix.board.artifact-name-suffix }} + path: ${{ runner.temp }}/provisioning-prod/ + + - name: Save staging artifact + uses: actions/upload-artifact@v4 + with: + name: provisioning-staging-${{ matrix.board.artifact-name-suffix }} + path: ${{ runner.temp }}/provisioning-staging/ diff --git a/examples/utility/Provisioning_2.0/CSRHandler.cpp b/examples/utility/Provisioning_2.0/CSRHandler.cpp index 1a6101e4b..8235db14a 100644 --- a/examples/utility/Provisioning_2.0/CSRHandler.cpp +++ b/examples/utility/Provisioning_2.0/CSRHandler.cpp @@ -193,6 +193,42 @@ uint32_t CSRHandlerClass::getTimestamp() { return ts; } +bool CSRHandlerClass::parseDateFromStr(char *str) { + char *tok[3]; + int i = 1; + tok[0] = strtok(str, "-"); + for (; i < 3; i++) { + char *t = strtok(NULL, "-"); + if(t == NULL){ + break; + } + tok[i] = t; + } + if (i < 3) { + return false; + } + + char *day = strtok(tok[2], "T"); + char *time = strtok(NULL, "T"); + + if(time == NULL){ + return false; + } + + char *hour = strtok(time, ":"); + + if(strlen(tok[0]) != 4 || strlen(tok[1]) != 2 || strlen(day) != 2 || strlen(hour) != 2){ + return false; + } + + _issueYear = atoi(tok[0]); + _issueMonth = atoi(tok[1]); + _issueDay = atoi(day); + _issueHour = atoi(hour); + + return true; +} + CSRHandlerClass::CSRHandlerStates CSRHandlerClass::handleBuildCSR() { if (!_certForCSR) { _certForCSR = new ECP256Certificate(); @@ -296,7 +332,7 @@ CSRHandlerClass::CSRHandlerStates CSRHandlerClass::handleParseResponse() { if(i < 6 || strlen(token[0]) != 36 || strlen(token[1]) != 40 || strlen(token[2]) < 10 || strlen(token[3]) != 32 || strlen(token[4]) != 64 || strlen(token[5]) != 64 - || sscanf(token[2], "%4d-%2d-%2dT%2d", &_issueYear, &_issueMonth, &_issueDay, &_issueHour) != 4){ + || !parseDateFromStr(token[2])){ updateNextRequestAt(); DEBUG_ERROR("CSRH::%s Error parsing response, retrying in %d ms", __FUNCTION__, _nextRequestAt - millis()); return CSRHandlerStates::REQUEST_SIGNATURE; diff --git a/examples/utility/Provisioning_2.0/CSRHandler.h b/examples/utility/Provisioning_2.0/CSRHandler.h index ae5956b7e..dcc2bc479 100644 --- a/examples/utility/Provisioning_2.0/CSRHandler.h +++ b/examples/utility/Provisioning_2.0/CSRHandler.h @@ -63,6 +63,7 @@ class CSRHandlerClass { uint32_t jitter(uint32_t base = JITTER_BASE, uint32_t max = JITTER_MAX); bool postRequest(const char *url, String &postData); uint32_t getTimestamp(); + bool parseDateFromStr(char *str); CSRHandlerStates handleBuildCSR(); CSRHandlerStates handleRequestSignature(); CSRHandlerStates handleWaitingResponse(); diff --git a/examples/utility/Provisioning_2.0/FactoryTester.h b/examples/utility/Provisioning_2.0/FactoryTester.h new file mode 100644 index 000000000..c29e152ba --- /dev/null +++ b/examples/utility/Provisioning_2.0/FactoryTester.h @@ -0,0 +1,80 @@ +/* + Copyright (c) 2025 Arduino SA + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +#pragma once +#include +#include + +#ifdef BOARD_USE_NINA +#include "WiFiNINA.h" +#include "utility/wifi_drv.h" +#endif + +inline void LedFactoryTest() { +#if defined(BOARD_HAS_RGB) +#if defined(BOARD_USE_NINA) + // MKR WiFi 1010, RP2040 Connect + WiFiDrv::pinMode(GREEN_LED, OUTPUT); + WiFiDrv::digitalWrite(GREEN_LED, LED_OFF); + WiFiDrv::pinMode(BLUE_LED, OUTPUT); + WiFiDrv::digitalWrite(BLUE_LED, LED_OFF); + WiFiDrv::pinMode(RED_LED, OUTPUT); + WiFiDrv::digitalWrite(RED_LED, LED_OFF); + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, LED_OFF); + + for(uint8_t i = 0; i<2; i++){ + digitalWrite(LED_BUILTIN, LED_ON); + WiFiDrv::digitalWrite(RED_LED, LED_ON); + delay(300); + digitalWrite(LED_BUILTIN, LED_OFF); + WiFiDrv::digitalWrite(RED_LED, LED_OFF); + WiFiDrv::digitalWrite(GREEN_LED, LED_ON); + delay(300); + digitalWrite(LED_BUILTIN, LED_ON); + WiFiDrv::digitalWrite(GREEN_LED, LED_OFF); + WiFiDrv::digitalWrite(BLUE_LED, LED_ON); + delay(300); + digitalWrite(LED_BUILTIN, LED_OFF); + WiFiDrv::digitalWrite(BLUE_LED, LED_OFF); + delay(200); + } +#else + // Portenta H7, Giga, Nicla Vision, Portenta C33 + pinMode(GREEN_LED, OUTPUT); + digitalWrite(GREEN_LED, LED_OFF); + pinMode(RED_LED, OUTPUT); + digitalWrite(RED_LED, LED_OFF); + pinMode(BLUE_LED, OUTPUT); + digitalWrite(BLUE_LED, LED_OFF); + for(uint8_t i = 0; i<2; i++){ + digitalWrite(RED_LED, LED_ON); + delay(300); + digitalWrite(RED_LED, LED_OFF); + digitalWrite(GREEN_LED, LED_ON); + delay(300); + digitalWrite(GREEN_LED, LED_OFF); + digitalWrite(BLUE_LED, LED_ON); + delay(300); + digitalWrite(BLUE_LED, LED_OFF); + delay(200); + } +#endif +#else // Nano 33 IoT + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, LED_OFF); + uint32_t start = millis(); + while(millis() - start < 2000) { + digitalWrite(LED_BUILTIN, LED_ON); + delay(300); + digitalWrite(LED_BUILTIN, LED_OFF); + delay(300); + } +#endif + +} diff --git a/examples/utility/Provisioning_2.0/OptaFactoryTest.cpp b/examples/utility/Provisioning_2.0/OptaFactoryTest.cpp new file mode 100644 index 000000000..636633c56 --- /dev/null +++ b/examples/utility/Provisioning_2.0/OptaFactoryTest.cpp @@ -0,0 +1,493 @@ +/* + Copyright (c) 2025 Arduino SA + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +#ifdef ARDUINO_OPTA +#include "OptaFactoryTest.h" + + +#define VID_FINDER 0x35D1 +#define VID_ARDUINO 0x2341 + +#define PID_BASIC 0x0064 +#define PID_PLUS 0x0164 +#define PID_ADVANCED 0x0264 + +#define LED1_SYS PI_0 // 154u +#define LED2_SYS PI_1 // 155u +#define LED3_SYS PI_3 // 157u +#define LED4_SYS PH_15 // 153u + +#define RL1 D0 +#define RL2 D1 +#define RL3 D2 +#define RL4 D3 + +#define N_ANALOG_INPUTS 8 +#define N_LED 7 + +#define ANALOG_THS 2.0 + +#define MY_RS485_TX_PIN PB_10 +#define MY_RS485_RX_PIN PB_11 +#define MY_RS485_DE_PIN PB_14 +#define MY_RS485_RE_PIN PB_13 + +#define N_PULSE 54 + +/* Constants */ +const uint8_t n_input[N_ANALOG_INPUTS] = {A0, A1, A2, A3, A4, A5, A6, A7}; +const uint8_t n_led[N_LED] = {LEDR, LEDG, LEDB, 154u, 155u, 157u, 153u}; +float v_input[N_ANALOG_INPUTS]; + +OptaBoardInfo* boardInfo(); + +void OptaFactoryTestClass::begin() { + pinMode(LED1_SYS, OUTPUT); + pinMode(LED2_SYS, OUTPUT); + pinMode(LED3_SYS, OUTPUT); + pinMode(LED4_SYS, OUTPUT); + + pinMode(RL1, OUTPUT); + pinMode(RL2, OUTPUT); + pinMode(RL3, OUTPUT); + pinMode(RL4, OUTPUT); + + /* Set ADC resolution to 12 bits */ + analogReadResolution(12); + SCB_DisableDCache(); + +} +void OptaFactoryTestClass::optaIDTest() { + _info = boardInfo(); + if(_info->magic == 0xB5) + { + if(_info->vid == VID_FINDER) + { + if(_info->pid == PID_BASIC) + { + digitalWrite(RL4, HIGH); + digitalWrite(LED4_SYS, HIGH); + } + else + { + if(_info->pid == PID_PLUS) + { + digitalWrite(RL3, HIGH); + digitalWrite(LED3_SYS, HIGH); + } + else + { + if(_info->pid == PID_ADVANCED) + { + digitalWrite(RL4, HIGH); + digitalWrite(LED4_SYS, HIGH); + digitalWrite(RL3, HIGH); + digitalWrite(LED3_SYS, HIGH); + } + } + } + } + else + { + if(_info->vid == VID_ARDUINO) + { + if(_info->pid == PID_BASIC) + { + digitalWrite(RL2, HIGH); + digitalWrite(LED2_SYS, HIGH); + } + else + { + if(_info->pid == PID_PLUS) + { + digitalWrite(RL2, HIGH); + digitalWrite(LED2_SYS, HIGH); + digitalWrite(RL4, HIGH); + digitalWrite(LED4_SYS, HIGH); + } + else + { + if(_info->pid == PID_ADVANCED) + { + digitalWrite(RL2, HIGH); + digitalWrite(LED2_SYS, HIGH); + digitalWrite(RL3, HIGH); + digitalWrite(LED3_SYS, HIGH); + } + } + } + } + } + delay(1000); + digitalWrite(RL1, LOW); + digitalWrite(LED1_SYS, LOW); + digitalWrite(RL2, LOW); + digitalWrite(LED2_SYS, LOW); + digitalWrite(RL3, LOW); + digitalWrite(LED3_SYS, LOW); + digitalWrite(RL4, LOW); + digitalWrite(LED4_SYS, LOW); + } + + /* Turn ON all LED */ + for(uint8_t i = 0; i < N_LED; i++) + { + digitalWrite(n_led[i], HIGH); + delay(50); + } + /* Turn OFF all LED */ + for(uint8_t i = 0; i < N_LED; i++) + { + digitalWrite(n_led[i], LOW); + delay(50); + } + + + printInfo(); + + if(_info->_board_functionalities.rs485 == 1) { + pinMode(MY_RS485_TX_PIN, OUTPUT); + digitalWrite(MY_RS485_TX_PIN, LOW); + + pinMode(MY_RS485_DE_PIN, OUTPUT); + digitalWrite(MY_RS485_DE_PIN, LOW); + + pinMode(MY_RS485_RE_PIN, OUTPUT); + digitalWrite(MY_RS485_RE_PIN, LOW); + + pinMode(MY_RS485_RX_PIN, INPUT); + attachInterrupt(digitalPinToInterrupt(MY_RS485_RX_PIN), rs485Rcv, FALLING); + _nextBoardInfoPrint = millis(); + _nextRS485Run = millis() + 2000; + } + +} + +bool OptaFactoryTestClass::poll() { + if(_ms10 < millis()) + { + _ms10 = millis() + 10; + ledManage(); + } + if(_ms100 < millis()) + { + _ms100 = millis() + 100; + + inputManage(); + + } + + if (_nextBoardInfoPrint < millis()) + { + _nextBoardInfoPrint = millis() + 3000; + Serial.print(millis()); + Serial.println("ms"); + printModel(); + } + + if(_nextRS485Run < millis() && _info->_board_functionalities.rs485 == 1 && _rs485_test_done == false) + { + _nextRS485Run = millis() + 1000; + rs485Manage(); + } + return _test_running; +} + +void OptaFactoryTestClass::ledManage(void) +{ + /* Run every 10ms */ + if(_all_on) + { + digitalWrite(LEDR, HIGH); + digitalWrite(LEDG, HIGH); + digitalWrite(LEDB, HIGH); + } +} + +void OptaFactoryTestClass::inputManage(void) +{ + /* Read all analog input values */ + for(uint8_t i = 0; i < N_ANALOG_INPUTS; i++) + { + v_input[i] = analogRead(n_input[i]) * (3.3 / 4095.0); + } + if(v_input[0] >= ANALOG_THS) + { + _test_running = true; + digitalWrite(RL1, HIGH); + digitalWrite(LED1_SYS, HIGH); + } + if(v_input[1] >= ANALOG_THS) + { + digitalWrite(RL2, HIGH); + digitalWrite(LED2_SYS, HIGH); + } + if(v_input[2] >= ANALOG_THS) + { + digitalWrite(RL3, HIGH); + digitalWrite(LED3_SYS, HIGH); + } + if(v_input[3] >= ANALOG_THS) + { + digitalWrite(RL4, HIGH); + digitalWrite(LED4_SYS, HIGH); + } + if(v_input[4] >= ANALOG_THS) + { + digitalWrite(RL1, HIGH); + digitalWrite(LED1_SYS, HIGH); + digitalWrite(RL2, HIGH); + digitalWrite(LED2_SYS, HIGH); + } + if(v_input[5] >= ANALOG_THS) + { + digitalWrite(RL3, HIGH); + digitalWrite(LED3_SYS, HIGH); + digitalWrite(RL4, HIGH); + digitalWrite(LED4_SYS, HIGH); + } + if(v_input[6] >= ANALOG_THS) + { + digitalWrite(RL1, HIGH); + digitalWrite(LED1_SYS, HIGH); + digitalWrite(RL3, HIGH); + digitalWrite(LED3_SYS, HIGH); + } + if(v_input[7] >= ANALOG_THS) + { + digitalWrite(RL2, HIGH); + digitalWrite(LED2_SYS, HIGH); + digitalWrite(RL4, HIGH); + digitalWrite(LED4_SYS, HIGH); + } + + if((v_input[0] < ANALOG_THS) && (v_input[4] < ANALOG_THS) && (v_input[6] < ANALOG_THS)) + { + digitalWrite(RL1, LOW); + digitalWrite(LED1_SYS, LOW); + } + if((v_input[1] < ANALOG_THS) && (v_input[4] < ANALOG_THS) && (v_input[7] < ANALOG_THS)) + { + digitalWrite(RL2, LOW); + digitalWrite(LED2_SYS, LOW); + } + if((v_input[2] < ANALOG_THS) && (v_input[5] < ANALOG_THS) && (v_input[6] < ANALOG_THS)) + { + digitalWrite(RL3, LOW); + digitalWrite(LED3_SYS, LOW); + } + if((v_input[3] < ANALOG_THS) && (v_input[5] < ANALOG_THS) && (v_input[7] < ANALOG_THS)) + { + digitalWrite(RL4, LOW); + digitalWrite(LED4_SYS, LOW); + } + if((v_input[0] >= ANALOG_THS) && (v_input[1] >= ANALOG_THS) && (v_input[2] >= ANALOG_THS) && (v_input[3] >= ANALOG_THS) && (v_input[4] >= ANALOG_THS) && (v_input[5] >= ANALOG_THS) && (v_input[6] >= ANALOG_THS) && (v_input[7] >= ANALOG_THS)) + { + digitalWrite(LEDR, HIGH); + digitalWrite(LEDG, HIGH); + digitalWrite(LEDB, HIGH); + _all_on = true; + } + else if( _all_on == true ) + { + digitalWrite(LEDR, LOW); + digitalWrite(LEDG, LOW); + digitalWrite(LEDB, LOW); + _all_on = false; + } +} + +void OptaFactoryTestClass::rs485Manage() { + bool rs485_ok = false; + uint32_t t_rs485_pulse = 0; + digitalWrite(MY_RS485_RE_PIN, HIGH); + digitalWrite(MY_RS485_DE_PIN, HIGH); + delay(10); + + for(uint32_t i = 0; i < N_PULSE; i++) + { + digitalWrite(MY_RS485_TX_PIN, HIGH); + delay(1); + digitalWrite(MY_RS485_TX_PIN, LOW); + delay(1); + } + delay(10); + digitalWrite(MY_RS485_DE_PIN, LOW); + digitalWrite(MY_RS485_RE_PIN, LOW); + + /* Search start of incoming transmission */ + _rs485_pulse = 0; + while((_rs485_pulse == 0) && (t_rs485_pulse < 200)) + { + t_rs485_pulse++; + delay(1); + } + + _rs485_pulse = 0; + + if(t_rs485_pulse < 200) + { + /* Receive data */ + t_rs485_pulse = 0; + uint32_t rs485_pulse_old = 0; + for(t_rs485_pulse = 0; t_rs485_pulse < 20; t_rs485_pulse++) + { + if(rs485_pulse_old != _rs485_pulse) + { + rs485_pulse_old = _rs485_pulse; + t_rs485_pulse = 0; + } + delay(10); + } + + /* End of receiving */ + if(_rs485_pulse > 0) + { + if((_rs485_pulse == N_PULSE) || (_rs485_pulse == N_PULSE + 1)) + { + Serial.println("RS485 check OK"); + rs485_ok = true; + } + } + } + + if(rs485_ok == true) + { + digitalWrite(RL1, HIGH); + digitalWrite(LED1_SYS, HIGH); + delay(1000); + digitalWrite(RL1, LOW); + digitalWrite(LED1_SYS, LOW); + _rs485_test_done = true; + _test_running = false; + } +} + + +void OptaFactoryTestClass::printInfo() { + Serial.print("\n"); + Serial.print("**********************************\n"); + Serial.print(">>> OPTA - 2023-07-13 15:38:21 <<<\n"); + Serial.print("**********************************\n"); + Serial.print("\n"); + + if(_info->magic == 0xB5) + { + printModel(); + + Serial.println("VID: 0x" + String(_info->vid, HEX)); + Serial.println("PID: 0x" + String(_info->pid, HEX)); + + char mac_address_char[18]; + uint8_t idx_mac_address_char = 0; + uint8_t a; + for(uint8_t i = 0; i < 6; i++) + { + a = _info->mac_address[i] >> 4; + for(uint8_t b = 0; b < 2; b++) + { + if(a <= 9) + { + mac_address_char[idx_mac_address_char] = a + 0x30; + } + else + { + mac_address_char[idx_mac_address_char] = a + 0x37; + } + idx_mac_address_char++; + a = _info->mac_address[i] & 0x0F; + } + if(i < 5) + { + mac_address_char[idx_mac_address_char++] = ':'; + } + } + mac_address_char[idx_mac_address_char] = 0; + Serial.println("MAC: " + String(mac_address_char)); + + Serial.println("Has Ethernet: " + String(_info->_board_functionalities.ethernet == 1 ? "Yes" : "No")); + Serial.println("Has WiFi module: " + String(_info->_board_functionalities.wifi == 1 ? "Yes" : "No")); + Serial.println("Has RS485: " + String(_info->_board_functionalities.rs485 == 1 ? "Yes" : "No")); + } + + +} + +void OptaFactoryTestClass::printModel(void) +{ + switch(_info->vid) + { + case VID_FINDER: + { + Serial.print(">>> Finder OPTA "); + switch(_info->pid) + { + case PID_BASIC: + { + Serial.print("Basic"); + } break; + + case PID_PLUS: + { + Serial.print("Plus"); + } break; + + case PID_ADVANCED: + { + Serial.print("Advanced"); + } break; + + default: + { + Serial.print("Unknown"); + } break; + } + } break; + + case VID_ARDUINO: + { + Serial.print(">>> Arduino OPTA "); + switch(_info->pid) + { + case PID_BASIC: + { + Serial.print("Lite - AFX00003"); + } break; + + case PID_PLUS: + { + Serial.print("RS485 - AFX00001"); + } break; + + case PID_ADVANCED: + { + Serial.print("WiFi - AFX00002"); + } break; + + default: + { + Serial.print("Unknown"); + } break; + } + } break; + + default: + { + Serial.print("Unknown "); + } break; + } + Serial.println(" <<<\n"); +} + +void OptaFactoryTestClass::rs485Rcv() { + _rs485_pulse++; +} + +OptaFactoryTestClass OptaFactoryTest; + +#endif diff --git a/examples/utility/Provisioning_2.0/OptaFactoryTest.h b/examples/utility/Provisioning_2.0/OptaFactoryTest.h new file mode 100644 index 000000000..16649840c --- /dev/null +++ b/examples/utility/Provisioning_2.0/OptaFactoryTest.h @@ -0,0 +1,34 @@ +/* + Copyright (c) 2025 Arduino SA + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ +#pragma once +#include +#include "opta_info.h" +class OptaFactoryTestClass { +public: + void begin(); + void optaIDTest(); + bool poll(); +private: + void ledManage(); + void inputManage(); + void rs485Manage(); + void printInfo(); + void printModel(); + static void rs485Rcv(); + static inline uint32_t _rs485_pulse = 0; + bool _all_on = false; + bool _rs485_test_done = false; + bool _test_running = false; + OptaBoardInfo *_info; + uint32_t _ms10 = 0; + uint32_t _ms100 = 0; + uint32_t _nextBoardInfoPrint = 0; + uint32_t _nextRS485Run = 0; +}; + +extern OptaFactoryTestClass OptaFactoryTest; diff --git a/examples/utility/Provisioning_2.0/Provisioning_2.0.ino b/examples/utility/Provisioning_2.0/Provisioning_2.0.ino index 7f8f44ceb..b644529ff 100644 --- a/examples/utility/Provisioning_2.0/Provisioning_2.0.ino +++ b/examples/utility/Provisioning_2.0/Provisioning_2.0.ino @@ -14,10 +14,17 @@ #include #include #include "utility/LEDFeedback.h" +#include "FactoryTester.h" +#if defined(ARDUINO_OPTA) +#include "OptaFactoryTest.h" +#endif -const char *SKETCH_VERSION = "0.3.3"; +const char *SKETCH_VERSION = "0.5.0"; enum class DeviceState { + #if defined(ARDUINO_OPTA) + OPTA_TEST, + #endif HARDWARE_CHECK, BEGIN, NETWORK_CONFIG, @@ -57,6 +64,25 @@ void setup() { setDebugMessageLevel(4); initProperties(); + + #if !defined(ARDUINO_OPTA) && !defined(ARDUINO_UNOR4_WIFI) + LedFactoryTest(); + #endif + + #if defined(ARDUINO_OPTA) + OptaFactoryTest.begin(); + OptaFactoryTest.optaIDTest(); + uint32_t start = millis(); + while(millis() - start < 500){ + if(OptaFactoryTest.poll() == true){ + pinMode(LEDG, OUTPUT); + ResetInput::getInstance().begin(); + _state = DeviceState::OPTA_TEST; + return; + } + } + #endif + AgentsManagerClass::getInstance().begin(); LEDFeedbackClass::getInstance().begin(); DEBUG_INFO("Starting Provisioning version %s", SKETCH_VERSION); @@ -67,6 +93,26 @@ void sendStatus(StatusMessage msg) { AgentsManagerClass::getInstance().sendMsg(outMsg); } +#if defined(ARDUINO_OPTA) +uint32_t lastLedStatusChanged = 0; +bool ledactive = false; +DeviceState handleOptaTest() { + bool running = OptaFactoryTest.poll(); + if(!running){ + digitalWrite(LEDG, LOW); + digitalWrite(LEDR, HIGH); + } else { + if(millis() - lastLedStatusChanged > 250){ + lastLedStatusChanged = millis(); + ledactive = !ledactive; + digitalWrite(LEDG, ledactive); + } + } + + return DeviceState::OPTA_TEST; +} +#endif + DeviceState handleHardwareCheck() { // Init the secure element if(!secureElement.begin()) { @@ -216,6 +262,9 @@ DeviceState handleError() { void loop() { switch (_state) { + #if defined(ARDUINO_OPTA) + case DeviceState::OPTA_TEST: _state = handleOptaTest (); break; + #endif case DeviceState::HARDWARE_CHECK: _state = handleHardwareCheck(); break; case DeviceState::BEGIN: _state = handleBegin (); break; case DeviceState::NETWORK_CONFIG : _state = handleNetworkConfig(); break; @@ -225,4 +274,11 @@ void loop() { case DeviceState::ERROR: _state = handleError (); break; default: break; } + + #if defined(ARDUINO_OPTA) + if(_state == DeviceState::NETWORK_CONFIG || _state == DeviceState::RUN){ + OptaFactoryTest.poll(); + } + #endif + } diff --git a/examples/utility/Provisioning_2.0/SecretsHelper.h b/examples/utility/Provisioning_2.0/SecretsHelper.h index bdb6354d1..fba33e25b 100644 --- a/examples/utility/Provisioning_2.0/SecretsHelper.h +++ b/examples/utility/Provisioning_2.0/SecretsHelper.h @@ -14,6 +14,11 @@ inline String GetUHWID() { UniqueHWId Id; if (Id.begin()) { +#ifdef ARDUINO_NANO_RP2040_CONNECT + /*Delay added for avoiding device crashes + on Nano RP2040 Connect when reading the UHWID */ + delay(100); +#endif return Id.get(); } return ""; diff --git a/examples/utility/Provisioning_2.0/thingProperties.h b/examples/utility/Provisioning_2.0/thingProperties.h index 7f51fa6ca..9d2a6cdd7 100644 --- a/examples/utility/Provisioning_2.0/thingProperties.h +++ b/examples/utility/Provisioning_2.0/thingProperties.h @@ -12,6 +12,7 @@ #include #include #include +#include "Arduino_NetworkConfigurator.h" #include "configuratorAgents/agents/BLEAgent.h" #include "configuratorAgents/agents/SerialAgent.h" diff --git a/src/AIoTC_Config.h b/src/AIoTC_Config.h index b0fba96a3..bd1187765 100644 --- a/src/AIoTC_Config.h +++ b/src/AIoTC_Config.h @@ -155,7 +155,8 @@ #endif #if defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_NICLA_VISION) || defined(ARDUINO_OPTA) || defined(ARDUINO_GIGA) \ - || defined(ARDUINO_UNOR4_WIFI) || defined(ARDUINO_PORTENTA_C33) + || defined(ARDUINO_UNOR4_WIFI) || defined(ARDUINO_PORTENTA_C33) || defined(ARDUINO_NANO_RP2040_CONNECT) \ + || defined(ARDUINO_SAMD_MKRWIFI1010) || defined(ARDUINO_SAMD_NANO_33_IOT) #define NETWORK_CONFIGURATOR_ENABLED (1) #else #define NETWORK_CONFIGURATOR_ENABLED (0)