commit
c645c4981b
32
README.md
32
README.md
@ -18,13 +18,15 @@ This can all be done with a single small and cheap ESP32 board for less than $20
|
|||||||
# Hardware
|
# Hardware
|
||||||
|
|
||||||
Currently supported IoT boards:
|
Currently supported IoT boards:
|
||||||
- Heltec LoRa-32
|
- Heltec LoRa-32 {1}
|
||||||
- TTGOv1
|
- TTGOv1 {1}
|
||||||
- TTGOv2
|
- TTGOv2 {1}
|
||||||
- Pycom LoPy
|
- Pycom LoPy {2}
|
||||||
- Pycom LoPy4
|
- Pycom LoPy4 {2}
|
||||||
- LoLin32 with [LoraNode32 shield](https://github.com/hallard/LoLin32-Lora)
|
- LoLin32 with [LoraNode32 shield](https://github.com/hallard/LoLin32-Lora) {2}{3}
|
||||||
- LoLin32 Lite with [LoraNode32-Lite shield](https://github.com/hallard/LoLin32-Lite-Lora)
|
- LoLin32 Lite with [LoraNode32-Lite shield](https://github.com/hallard/LoLin32-Lite-Lora) {2}{3}
|
||||||
|
|
||||||
|
{1} on board OLED Display supported; {2} on board RGB LED supported; {3} on board Hardware unique DEVEUI supported
|
||||||
|
|
||||||
Target platform must be selected in [platformio.ini](https://github.com/cyberman54/ESP32-Paxcounter/blob/master/platformio.ini).<br>
|
Target platform must be selected in [platformio.ini](https://github.com/cyberman54/ESP32-Paxcounter/blob/master/platformio.ini).<br>
|
||||||
Hardware dependent settings (pinout etc.) are stored in board files in /hal directory.<br>
|
Hardware dependent settings (pinout etc.) are stored in board files in /hal directory.<br>
|
||||||
@ -50,6 +52,8 @@ Use <A HREF="https://platformio.org/">PlatformIO</A> with your preferred IDE for
|
|||||||
|
|
||||||
Before compiling the code, create file loraconf.h in the /src directory from the template [loraconf.sample.h](https://github.com/cyberman54/ESP32-Paxcounter/blob/master/src/loraconf.sample.h) and populate it with your personal APPEUI und APPKEY for the LoRaWAN network. Only OTAA join is supported, not ABP. The DEVEUI will be derived from the device's MAC adress during device startup and is shown as well on the device's display (if it has one) as on the serial console for copying it to your LoRaWAN network server settings. If you enter a DEVEUI in loraconf.h it will be used instead.
|
Before compiling the code, create file loraconf.h in the /src directory from the template [loraconf.sample.h](https://github.com/cyberman54/ESP32-Paxcounter/blob/master/src/loraconf.sample.h) and populate it with your personal APPEUI und APPKEY for the LoRaWAN network. Only OTAA join is supported, not ABP. The DEVEUI will be derived from the device's MAC adress during device startup and is shown as well on the device's display (if it has one) as on the serial console for copying it to your LoRaWAN network server settings. If you enter a DEVEUI in loraconf.h it will be used instead.
|
||||||
|
|
||||||
|
**If Using a board with Microchip 24AA02E64 Unique ID for deveui, it will override the one of loraconf.h**
|
||||||
|
|
||||||
# Uploading
|
# Uploading
|
||||||
|
|
||||||
To upload the code to your ESP32 board this needs to be switched from run to bootloader mode. Boards with USB bridge like Heltec and TTGO usually have an onboard logic which allows soft switching by the upload tool. In PlatformIO this happenes automatically.<p>
|
To upload the code to your ESP32 board this needs to be switched from run to bootloader mode. Boards with USB bridge like Heltec and TTGO usually have an onboard logic which allows soft switching by the upload tool. In PlatformIO this happenes automatically.<p>
|
||||||
@ -177,7 +181,7 @@ Note: all settings are stored in NVRAM and will be reloaded when device starts.
|
|||||||
|
|
||||||
0x80 get device configuration
|
0x80 get device configuration
|
||||||
|
|
||||||
device answers with it's current configuration. The configuration is a C structure declared in file [globals.h](src/globals.h#L23-L38) with the following definition:
|
device answers with it's current configuration. The configuration is a C structure declared in file [globals.h](src/globals.h#L24-L41) with the following definition:
|
||||||
|
|
||||||
byte 1: Lora SF (7..12)
|
byte 1: Lora SF (7..12)
|
||||||
byte 2: Lora TXpower (2..15)
|
byte 2: Lora TXpower (2..15)
|
||||||
@ -205,14 +209,12 @@ device answers with it's current configuration. The configuration is a C structu
|
|||||||
|
|
||||||
# RGB Led color description
|
# RGB Led color description
|
||||||
|
|
||||||
Description of the RGB LED color (Lopy and Lolin32 only):
|
Description of the RGB LED color (LoPy/LoPy4 and Lolin32 only):
|
||||||
|
|
||||||
- Yellow quick blink
|
- Yellow quick blink: joining LoRaWAN network in progress or pending
|
||||||
- LoRaWAN join
|
- Blue blink: LoRaWAN data transmit (including waiting for receive windows) in progress or pending
|
||||||
- Blue blink
|
- Green each blink: seen a Wifi device, new or not, while Wifi scanning
|
||||||
- LoRaWAN transmit (including receive windows)
|
- Magenta each blink: seen a BLE device, new or not, while BLE scanning
|
||||||
- Magenta each blink
|
|
||||||
- BLE Scan, seen a device (new or not)
|
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#define CFG_sx1276_radio 1
|
#define CFG_sx1276_radio 1
|
||||||
|
|
||||||
#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C // OLED-Display on board
|
#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C // OLED-Display on board
|
||||||
|
//#define DISPLAY_FLIP 1 // uncomment this for rotated display
|
||||||
#define HAS_LED GPIO_NUM_25 // white LED on board
|
#define HAS_LED GPIO_NUM_25 // white LED on board
|
||||||
#define HAS_BUTTON GPIO_NUM_0 // button "PROG" on board
|
#define HAS_BUTTON GPIO_NUM_0 // button "PROG" on board
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
|
#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
|
||||||
|
|
||||||
#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C // OLED-Display on board
|
#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C // OLED-Display on board
|
||||||
|
//#define DISPLAY_FLIP 1 // uncomment this for rotated display
|
||||||
#define HAS_LED NOT_A_PIN // Led os on same pin as Lora SS pin, to avoid problems, we don't use it
|
#define HAS_LED NOT_A_PIN // Led os on same pin as Lora SS pin, to avoid problems, we don't use it
|
||||||
#define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW
|
#define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW
|
||||||
// Anyway shield is on over the LoLin32 board, so we won't be able to see this LED
|
// Anyway shield is on over the LoLin32 board, so we won't be able to see this LED
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
|
#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
|
||||||
|
|
||||||
#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C // OLED-Display on board
|
#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C // OLED-Display on board
|
||||||
|
//#define DISPLAY_FLIP 1 // uncomment this for rotated display
|
||||||
#define HAS_LED 22 // ESP32 GPIO12 (pin22) On Board LED
|
#define HAS_LED 22 // ESP32 GPIO12 (pin22) On Board LED
|
||||||
#define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW
|
#define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW
|
||||||
#define HAS_RGB_LED 13 // ESP32 GPIO13 (pin13) On Board Shield WS2812B RGB LED
|
#define HAS_RGB_LED 13 // ESP32 GPIO13 (pin13) On Board Shield WS2812B RGB LED
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#define CFG_sx1276_radio 1
|
#define CFG_sx1276_radio 1
|
||||||
|
|
||||||
#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C // OLED-Display on board
|
#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C // OLED-Display on board
|
||||||
|
//#define DISPLAY_FLIP 1 // uncomment this for rotated display
|
||||||
#define HAS_LED GPIO_NUM_2 // white LED on board
|
#define HAS_LED GPIO_NUM_2 // white LED on board
|
||||||
#define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW
|
#define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW
|
||||||
#define HAS_BUTTON GPIO_NUM_0 // button "PRG" on board
|
#define HAS_BUTTON GPIO_NUM_0 // button "PRG" on board
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#define CFG_sx1276_radio 1 // HPD13A LoRa SoC
|
#define CFG_sx1276_radio 1 // HPD13A LoRa SoC
|
||||||
|
|
||||||
#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C
|
#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C
|
||||||
|
//#define DISPLAY_FLIP 1 // uncomment this for rotated display
|
||||||
#define HAS_LED NOT_A_PIN // on-board LED is wired to SCL (used by display) therefore totally useless
|
#define HAS_LED NOT_A_PIN // on-board LED is wired to SCL (used by display) therefore totally useless
|
||||||
|
|
||||||
// disable brownout detection (needed on TTGOv2 for battery powered operation)
|
// disable brownout detection (needed on TTGOv2 for battery powered operation)
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
// Set your DEVEUI here, if you have one. You can leave this untouched,
|
// Set your DEVEUI here, if you have one. You can leave this untouched,
|
||||||
// then the DEVEUI will be generated during runtime from device's MAC adress
|
// then the DEVEUI will be generated during runtime from device's MAC adress
|
||||||
// Note: Use same format as in TTN console (cut & paste, for your convenience)
|
// Note: Use same format as in TTN console (cut & paste, for your convenience)
|
||||||
|
// *** Take care : If Using a board with Microchip 24AA02E64 Uinique ID for deveui, **
|
||||||
|
// *** this DEVEUI will be overwriten by the one contained in the Microchip module ***
|
||||||
static const u1_t DEVEUI[8]={ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
static const u1_t DEVEUI[8]={ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
// Note: Use msb format for APPEUI as in TTN console (cut & paste, for your convenience)
|
// Note: Use msb format for APPEUI as in TTN console (cut & paste, for your convenience)
|
||||||
|
@ -7,6 +7,10 @@
|
|||||||
#include <lmic.h>
|
#include <lmic.h>
|
||||||
#include <hal/hal.h>
|
#include <hal/hal.h>
|
||||||
|
|
||||||
|
#ifdef MCP_24AA02E64_I2C_ADDRESS
|
||||||
|
#include <Wire.h> // Needed for 24AA02E64, does not hurt anything if included and not used
|
||||||
|
#endif
|
||||||
|
|
||||||
uint8_t mydata[] = "0000";
|
uint8_t mydata[] = "0000";
|
||||||
|
|
||||||
// Local logging Tag
|
// Local logging Tag
|
||||||
@ -31,9 +35,9 @@ void gen_lora_deveui(uint8_t *pdeveui) {
|
|||||||
*p++ = 0xFF;
|
*p++ = 0xFF;
|
||||||
*p++ = 0xFE;
|
*p++ = 0xFE;
|
||||||
// Then next 6 bytes are mac address reversed
|
// Then next 6 bytes are mac address reversed
|
||||||
for ( i=0; i<6 ; i++) {
|
for ( i=0; i<6 ; i++) {
|
||||||
*p++ = dmac[5-i];
|
*p++ = dmac[5-i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to do a byte swap in a byte array
|
// Function to do a byte swap in a byte array
|
||||||
@ -46,6 +50,37 @@ void RevBytes(unsigned char* b, size_t c)
|
|||||||
b[c - 1 - i] = t; }
|
b[c - 1 - i] = t; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void get_hard_deveui(uint8_t *pdeveui) {
|
||||||
|
// read DEVEUI from Microchip 24AA02E64 2Kb serial eeprom if present
|
||||||
|
#ifdef MCP_24AA02E64_I2C_ADDRESS
|
||||||
|
uint8_t i2c_ret;
|
||||||
|
// Init this just in case, no more to 100KHz
|
||||||
|
Wire.begin(OLED_SDA, OLED_SCL, 100000);
|
||||||
|
Wire.beginTransmission(MCP_24AA02E64_I2C_ADDRESS);
|
||||||
|
Wire.write(MCP_24AA02E64_MAC_ADDRESS);
|
||||||
|
i2c_ret = Wire.endTransmission();
|
||||||
|
// check if device seen on i2c bus
|
||||||
|
if (i2c_ret == 0) {
|
||||||
|
char deveui[32]="";
|
||||||
|
uint8_t data;
|
||||||
|
Wire.beginTransmission(MCP_24AA02E64_I2C_ADDRESS);
|
||||||
|
Wire.write(MCP_24AA02E64_MAC_ADDRESS);
|
||||||
|
Wire.requestFrom(MCP_24AA02E64_I2C_ADDRESS, 8);
|
||||||
|
while (Wire.available()) {
|
||||||
|
data = Wire.read();
|
||||||
|
sprintf(deveui+strlen(deveui), "%02X ", data) ;
|
||||||
|
*pdeveui++ = data;
|
||||||
|
}
|
||||||
|
i2c_ret = Wire.endTransmission();
|
||||||
|
ESP_LOGI(TAG, "Serial EEPROM 24AA02E64 found, read DEVEUI %s", deveui);
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(TAG, "Serial EEPROM 24AA02E64 not found ret=%d", i2c_ret);
|
||||||
|
}
|
||||||
|
// Set back to 400KHz to speed up OLED
|
||||||
|
Wire.setClock(400000);
|
||||||
|
#endif // MCP 24AA02E64
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef VERBOSE
|
#ifdef VERBOSE
|
||||||
|
|
||||||
// Display a key
|
// Display a key
|
||||||
|
@ -53,11 +53,15 @@ bool mac_add(uint8_t *paddr, int8_t rssi, bool sniff_type) {
|
|||||||
added = newmac.second; // true if hashed MAC is unique in container
|
added = newmac.second; // true if hashed MAC is unique in container
|
||||||
|
|
||||||
if (sniff_type == MAC_SNIFF_WIFI ) {
|
if (sniff_type == MAC_SNIFF_WIFI ) {
|
||||||
|
rgb_set_color(COLOR_GREEN);
|
||||||
newmac = wifis.insert(hashedmac); // add hashed MAC to wifi container if new unique
|
newmac = wifis.insert(hashedmac); // add hashed MAC to wifi container if new unique
|
||||||
strcpy(typebuff, "WiFi");
|
strcpy(typebuff, "WiFi");
|
||||||
|
rgb_set_color(COLOR_NONE);
|
||||||
} else if (sniff_type == MAC_SNIFF_BLE ) {
|
} else if (sniff_type == MAC_SNIFF_BLE ) {
|
||||||
|
rgb_set_color(COLOR_MAGENTA);
|
||||||
newmac = bles.insert(hashedmac); // add hashed MAC to BLE container if new unique
|
newmac = bles.insert(hashedmac); // add hashed MAC to BLE container if new unique
|
||||||
strcpy(typebuff, "BLE ");
|
strcpy(typebuff, "BLE ");
|
||||||
|
rgb_set_color(COLOR_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (added) { // first time seen this WIFI or BLE MAC
|
if (added) { // first time seen this WIFI or BLE MAC
|
||||||
@ -85,14 +89,11 @@ class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
|
|||||||
void onResult(BLEAdvertisedDevice advertisedDevice) {
|
void onResult(BLEAdvertisedDevice advertisedDevice) {
|
||||||
uint8_t *p = (uint8_t *) advertisedDevice.getAddress().getNative();
|
uint8_t *p = (uint8_t *) advertisedDevice.getAddress().getNative();
|
||||||
|
|
||||||
rgb_set_color(COLOR_MAGENTA);
|
|
||||||
// Current devices seen on this scan session
|
// Current devices seen on this scan session
|
||||||
currentScanDevice++;
|
currentScanDevice++;
|
||||||
mac_add(p, advertisedDevice.getRSSI(), MAC_SNIFF_BLE);
|
mac_add(p, advertisedDevice.getRSSI(), MAC_SNIFF_BLE);
|
||||||
u8x8.setCursor(12,3);
|
u8x8.setCursor(12,3);
|
||||||
u8x8.printf("%d", currentScanDevice);
|
u8x8.printf("%d", currentScanDevice);
|
||||||
rgb_set_color(COLOR_NONE);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
46
src/main.cpp
46
src/main.cpp
@ -29,7 +29,7 @@ Refer to LICENSE.txt file in repository for more details.
|
|||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
// OLED driver
|
// OLED driver
|
||||||
#include <U8x8lib.h> // includes <wire.h> if needed for other on board i2c components
|
#include <U8x8lib.h>
|
||||||
|
|
||||||
// LMIC-Arduino LoRaWAN Stack
|
// LMIC-Arduino LoRaWAN Stack
|
||||||
#include "loraconf.h"
|
#include "loraconf.h"
|
||||||
@ -85,6 +85,8 @@ void loadConfig(void);
|
|||||||
// defined in lorawan.cpp
|
// defined in lorawan.cpp
|
||||||
void gen_lora_deveui(uint8_t * pdeveui);
|
void gen_lora_deveui(uint8_t * pdeveui);
|
||||||
void RevBytes(unsigned char* b, size_t c);
|
void RevBytes(unsigned char* b, size_t c);
|
||||||
|
void get_hard_deveui(uint8_t *pdeveui);
|
||||||
|
|
||||||
|
|
||||||
#ifdef VERBOSE
|
#ifdef VERBOSE
|
||||||
void printKeys(void);
|
void printKeys(void);
|
||||||
@ -103,12 +105,20 @@ void os_getArtEui (u1_t *buf) {
|
|||||||
void os_getDevEui (u1_t* buf) {
|
void os_getDevEui (u1_t* buf) {
|
||||||
int i=0, k=0;
|
int i=0, k=0;
|
||||||
memcpy(buf, DEVEUI, 8); // get fixed DEVEUI from loraconf.h
|
memcpy(buf, DEVEUI, 8); // get fixed DEVEUI from loraconf.h
|
||||||
for (i=0; i<8 ; i++)
|
for (i=0; i<8 ; i++) {
|
||||||
k += buf[i];
|
k += buf[i];
|
||||||
if (k)
|
}
|
||||||
|
if (k) {
|
||||||
RevBytes(buf, 8); // use fixed DEVEUI and swap bytes to LSB format
|
RevBytes(buf, 8); // use fixed DEVEUI and swap bytes to LSB format
|
||||||
else
|
} else {
|
||||||
gen_lora_deveui(buf); // generate DEVEUI from device's MAC
|
gen_lora_deveui(buf); // generate DEVEUI from device's MAC
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get MCP 24AA02E64 hardware DEVEUI (override default settings if found)
|
||||||
|
#ifdef MCP_24AA02E64_I2C_ADDRESS
|
||||||
|
get_hard_deveui(buf);
|
||||||
|
RevBytes(buf, 8); // swap bytes to LSB format
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// LMIC enhanced Pin mapping
|
// LMIC enhanced Pin mapping
|
||||||
@ -367,6 +377,10 @@ void init_display(const char *Productname, const char *Version) {
|
|||||||
u8x8.setFlipMode(0);
|
u8x8.setFlipMode(0);
|
||||||
u8x8.clear();
|
u8x8.clear();
|
||||||
|
|
||||||
|
#ifdef DISPLAY_FLIP
|
||||||
|
u8x8.setFlipMode(1);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Display chip information
|
// Display chip information
|
||||||
#ifdef VERBOSE
|
#ifdef VERBOSE
|
||||||
esp_chip_info_t chip_info;
|
esp_chip_info_t chip_info;
|
||||||
@ -457,30 +471,6 @@ void setup() {
|
|||||||
antenna_init();
|
antenna_init();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// read DEVEUI from Microchip 24AA02E64 2Kb serial eeprom if present
|
|
||||||
#ifdef MCP_24AA02E64_I2C_ADDRESS
|
|
||||||
uint8_t i2c_ret;
|
|
||||||
// Init this before OLED, we just need to get value then we're done with i2c bus
|
|
||||||
Wire.begin(OLED_SDA, OLED_SDA, 100000);
|
|
||||||
Wire.beginTransmission(MCP_24AA02E64_I2C_ADDRESS);
|
|
||||||
Wire.write(MCP_24AA02E64_MAC_ADDRESS);
|
|
||||||
i2c_ret = Wire.endTransmission();
|
|
||||||
// check if device seen on i2c bus
|
|
||||||
if (i2c_ret == 0) {
|
|
||||||
char deveui[24];
|
|
||||||
uint8_t data;
|
|
||||||
Wire.beginTransmission(MCP_24AA02E64_I2C_ADDRESS);
|
|
||||||
while (Wire.available()) {
|
|
||||||
data = Wire.read();
|
|
||||||
sprintf(deveui+strlen(deveui), "%02X ", data) ;
|
|
||||||
}
|
|
||||||
i2c_ret = Wire.endTransmission();
|
|
||||||
ESP_LOGI(TAG, "Serial EEPROM 24AA02E64 found, read DEVEUI %s", deveui);
|
|
||||||
} else {
|
|
||||||
ESP_LOGI(TAG, "Serial EEPROM 24AA02E64 not found ret=%d", i2c_ret);
|
|
||||||
}
|
|
||||||
#endif // MCP 24AA02E64
|
|
||||||
|
|
||||||
// initialize display
|
// initialize display
|
||||||
init_display(PROGNAME, PROGVERSION);
|
init_display(PROGNAME, PROGVERSION);
|
||||||
u8x8.setPowerSave(!cfg.screenon); // set display off if disabled
|
u8x8.setPowerSave(!cfg.screenon); // set display off if disabled
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// program version - note: increment version after modifications to configData_t struct!!
|
// program version - note: increment version after modifications to configData_t struct!!
|
||||||
#define PROGVERSION "1.2.9" // use max 10 chars here!
|
#define PROGVERSION "1.2.93" // use max 10 chars here!
|
||||||
#define PROGNAME "PAXCNT"
|
#define PROGNAME "PAXCNT"
|
||||||
|
|
||||||
// Verbose enables serial output
|
// Verbose enables serial output
|
||||||
|
Loading…
Reference in New Issue
Block a user