diff --git a/boards/seeed-xiao-afruitnrf52-nrf52840.json b/boards/seeed-xiao-afruitnrf52-nrf52840.json new file mode 100644 index 00000000..78855cd7 --- /dev/null +++ b/boards/seeed-xiao-afruitnrf52-nrf52840.json @@ -0,0 +1,61 @@ +{ + "build": { + "arduino": { + "ldscript": "nrf52840_s140_v7.ld" + }, + "core": "nRF5", + "cpu": "cortex-m4", + "extra_flags": "-DARDUINO_Seeed_XIAO_nRF52840 -DNRF52840_XXAA -DSEEED_XIAO_NRF52840 ", + "f_cpu": "64000000L", + "hwids": [ + [ "0x2886", "0x8044" ], + [ "0x2886", "0x0044" ] + ], + "mcu": "nrf52840", + "variant": "Seeed_XIAO_nRF52840", + "softdevice": { + "sd_flags": "-DS140", + "sd_name": "s140", + "sd_version": "7.3.0", + "sd_fwid": "0x0123" + }, + "bsp": { + "name": "adafruit" + }, + "bootloader": { + "settings_addr": "0xFF000" + }, + "usb_product": "XIAO nRF52840" + }, + "connectivity": [ + "bluetooth" + ], + "debug": { + "jlink_device": "nRF52840_xxAA", + "openocd_target": "nrf52.cfg", + "svd_path": "nrf52840.svd" + }, + "frameworks": [ + "arduino" + ], + "name": "Seeed Studio XIAO nRF52840", + "upload": { + "maximum_ram_size": 237568, + "maximum_size": 811008, + "protocol": "nrfutil", + "speed": 115200, + "protocols": [ + "jlink", + "nrfjprog", + "nrfutil", + "cmsis-dap", + "sam-ba", + "blackmagic" + ], + "use_1200bps_touch": true, + "require_upload_port": true, + "wait_for_upload_port": true + }, + "url": "https://wiki.seeedstudio.com/XIAO_BLE", + "vendor": "Seeed Studio" +} diff --git a/examples/companion_radio/UITask.cpp b/examples/companion_radio/UITask.cpp index c42bb094..2d2e95a6 100644 --- a/examples/companion_radio/UITask.cpp +++ b/examples/companion_radio/UITask.cpp @@ -25,16 +25,26 @@ static const uint8_t meshcore_logo [] PROGMEM = { 0xe3, 0xe3, 0x8f, 0xff, 0x1f, 0xfc, 0x3c, 0x0e, 0x1f, 0xf8, 0xff, 0xf8, 0x70, 0x3c, 0x7f, 0xf8, }; -void UITask::begin(DisplayDriver* display, const char* node_name, const char* build_date, uint32_t pin_code) { +void UITask::begin(DisplayDriver* display, const char* node_name, const char* build_date, const char* firmware_version, uint32_t pin_code) { _display = display; _auto_off = millis() + AUTO_OFF_MILLIS; clearMsgPreview(); _node_name = node_name; - _build_date = build_date; _pin_code = pin_code; if (_display != NULL) { _display->turnOn(); } + + // strip off dash and commit hash by changing dash to null terminator + // e.g: v1.2.3-abcdef -> v1.2.3 + char *version = strdup(firmware_version); + char *dash = strchr(version, '-'); + if(dash){ + *dash = 0; + } + + // v1.2.3 (1 Jan 2025) + sprintf(_version_info, "%s (%s)", version, build_date); } void UITask::msgRead(int msgcount) { @@ -90,10 +100,9 @@ void UITask::renderCurrScreen() { _display->setCursor(0, 20); _display->setTextSize(1); _display->print(_node_name); - - sprintf(tmp, "Build: %s", _build_date); + _display->setCursor(0, 32); - _display->print(tmp); + _display->print(_version_info); if (_connected) { //_display->printf("freq : %03.2f sf %d\n", _prefs.freq, _prefs.sf); diff --git a/examples/companion_radio/UITask.h b/examples/companion_radio/UITask.h index a0c60186..4cba1fca 100644 --- a/examples/companion_radio/UITask.h +++ b/examples/companion_radio/UITask.h @@ -11,7 +11,7 @@ class UITask { bool _connected; uint32_t _pin_code; const char* _node_name; - const char* _build_date; + char _version_info[32]; char _origin[62]; char _msg[80]; int _msgcount; @@ -26,7 +26,7 @@ public: _next_refresh = 0; _connected = false; } - void begin(DisplayDriver* display, const char* node_name, const char* build_date, uint32_t pin_code); + void begin(DisplayDriver* display, const char* node_name, const char* build_date, const char* firmware_version, uint32_t pin_code); void setHasConnection(bool connected) { _connected = connected; } bool hasDisplay() const { return _display != NULL; } diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 2a6af5b7..e0b5e2a5 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -83,14 +83,14 @@ static uint32_t _atoi(const char* sp) { /*------------ Frame Protocol --------------*/ -#define FIRMWARE_VER_CODE 3 +#define FIRMWARE_VER_CODE 4 #ifndef FIRMWARE_BUILD_DATE - #define FIRMWARE_BUILD_DATE "30 Mar 2025" + #define FIRMWARE_BUILD_DATE "7 Apr 2025" #endif #ifndef FIRMWARE_VERSION - #define FIRMWARE_VERSION "v1.4.2" + #define FIRMWARE_VERSION "v1.4.3" #endif #define CMD_APP_START 1 @@ -130,6 +130,7 @@ static uint32_t _atoi(const char* sp) { #define CMD_SIGN_FINISH 35 #define CMD_SEND_TRACE_PATH 36 #define CMD_SET_DEVICE_PIN 37 +#define CMD_SET_OTHER_PARAMS 38 #define RESP_CODE_OK 0 #define RESP_CODE_ERR 1 @@ -164,6 +165,7 @@ static uint32_t _atoi(const char* sp) { #define PUSH_CODE_STATUS_RESPONSE 0x87 #define PUSH_CODE_LOG_RX_DATA 0x88 #define PUSH_CODE_TRACE_DATA 0x89 +#define PUSH_CODE_NEW_ADVERT 0x8A #define ERR_CODE_UNSUPPORTED_CMD 1 #define ERR_CODE_NOT_FOUND 2 @@ -184,7 +186,7 @@ struct NodePrefs { // persisted to file uint8_t sf; uint8_t cr; uint8_t reserved1; - uint8_t reserved2; + uint8_t manual_add_contacts; float bw; uint8_t tx_power_dbm; uint8_t unused[3]; @@ -499,11 +501,19 @@ protected: } } + bool isAutoAddEnabled() const override { + return (_prefs.manual_add_contacts & 1) == 0; + } + void onDiscoveredContact(ContactInfo& contact, bool is_new) override { if (_serial->isConnected()) { - out_frame[0] = PUSH_CODE_ADVERT; - memcpy(&out_frame[1], contact.id.pub_key, PUB_KEY_SIZE); - _serial->writeFrame(out_frame, 1 + PUB_KEY_SIZE); + if (!isAutoAddEnabled() && is_new) { + writeContactRespFrame(PUSH_CODE_NEW_ADVERT, contact); + } else { + out_frame[0] = PUSH_CODE_ADVERT; + memcpy(&out_frame[1], contact.id.pub_key, PUB_KEY_SIZE); + _serial->writeFrame(out_frame, 1 + PUB_KEY_SIZE); + } } else { soundBuzzer(); } @@ -663,6 +673,10 @@ protected: } void onRawDataRecv(mesh::Packet* packet) override { + if (packet->payload_len + 4 > sizeof(out_frame)) { + MESH_DEBUG_PRINTLN("onRawDataRecv(), payload_len too long: %d", packet->payload_len); + return; + } int i = 0; out_frame[i++] = PUSH_CODE_RAW_DATA; out_frame[i++] = (int8_t)(_radio->getLastSNR() * 4); @@ -746,7 +760,7 @@ public: file.read((uint8_t *) &_prefs.sf, sizeof(_prefs.sf)); // 60 file.read((uint8_t *) &_prefs.cr, sizeof(_prefs.cr)); // 61 file.read((uint8_t *) &_prefs.reserved1, sizeof(_prefs.reserved1)); // 62 - file.read((uint8_t *) &_prefs.reserved2, sizeof(_prefs.reserved2)); // 63 + file.read((uint8_t *) &_prefs.manual_add_contacts, sizeof(_prefs.manual_add_contacts)); // 63 file.read((uint8_t *) &_prefs.bw, sizeof(_prefs.bw)); // 64 file.read((uint8_t *) &_prefs.tx_power_dbm, sizeof(_prefs.tx_power_dbm)); // 68 file.read((uint8_t *) _prefs.unused, sizeof(_prefs.unused)); // 69 @@ -847,7 +861,7 @@ public: file.write((uint8_t *) &_prefs.sf, sizeof(_prefs.sf)); // 60 file.write((uint8_t *) &_prefs.cr, sizeof(_prefs.cr)); // 61 file.write((uint8_t *) &_prefs.reserved1, sizeof(_prefs.reserved1)); // 62 - file.write((uint8_t *) &_prefs.reserved2, sizeof(_prefs.reserved2)); // 63 + file.write((uint8_t *) &_prefs.manual_add_contacts, sizeof(_prefs.manual_add_contacts)); // 63 file.write((uint8_t *) &_prefs.bw, sizeof(_prefs.bw)); // 64 file.write((uint8_t *) &_prefs.tx_power_dbm, sizeof(_prefs.tx_power_dbm)); // 68 file.write((uint8_t *) _prefs.unused, sizeof(_prefs.unused)); // 69 @@ -888,12 +902,15 @@ public: out_frame[i++] = MAX_LORA_TX_POWER; memcpy(&out_frame[i], self_id.pub_key, PUB_KEY_SIZE); i += PUB_KEY_SIZE; - int32_t lat, lon, alt = 0; + int32_t lat, lon; lat = (_prefs.node_lat * 1000000.0); lon = (_prefs.node_lon * 1000000.0); memcpy(&out_frame[i], &lat, 4); i += 4; memcpy(&out_frame[i], &lon, 4); i += 4; - memcpy(&out_frame[i], &alt, 4); i += 4; + out_frame[i++] = 0; // reserved + out_frame[i++] = 0; // reserved + out_frame[i++] = 0; // reserved + out_frame[i++] = _prefs.manual_add_contacts; uint32_t freq = _prefs.freq * 1000; memcpy(&out_frame[i], &freq, 4); i += 4; @@ -1177,6 +1194,10 @@ public: _prefs.airtime_factor = ((float)af) / 1000.0f; savePrefs(); writeOKFrame(); + } else if (cmd_frame[0] == CMD_SET_OTHER_PARAMS) { + _prefs.manual_add_contacts = cmd_frame[1]; + savePrefs(); + writeOKFrame(); } else if (cmd_frame[0] == CMD_REBOOT && memcmp(&cmd_frame[1], "reboot", 6) == 0) { board.reboot(); } else if (cmd_frame[0] == CMD_GET_BATTERY_VOLTAGE) { @@ -1505,7 +1526,7 @@ void setup() { #endif #ifdef HAS_UI - ui_task.begin(disp, the_mesh.getNodeName(), FIRMWARE_BUILD_DATE, the_mesh.getBLEPin()); + ui_task.begin(disp, the_mesh.getNodeName(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION, the_mesh.getBLEPin()); #endif } diff --git a/examples/simple_repeater/UITask.cpp b/examples/simple_repeater/UITask.cpp index e8a204e3..6fff675e 100644 --- a/examples/simple_repeater/UITask.cpp +++ b/examples/simple_repeater/UITask.cpp @@ -20,25 +20,33 @@ static const uint8_t meshcore_logo [] PROGMEM = { 0xe3, 0xe3, 0x8f, 0xff, 0x1f, 0xfc, 0x3c, 0x0e, 0x1f, 0xf8, 0xff, 0xf8, 0x70, 0x3c, 0x7f, 0xf8, }; -void UITask::begin(const char* node_name, const char* build_date) { +void UITask::begin(const char* node_name, const char* build_date, const char* firmware_version) { _prevBtnState = HIGH; _auto_off = millis() + AUTO_OFF_MILLIS; _node_name = node_name; - _build_date = build_date; _display->turnOn(); + + // strip off dash and commit hash by changing dash to null terminator + // e.g: v1.2.3-abcdef -> v1.2.3 + char *version = strdup(firmware_version); + char *dash = strchr(version, '-'); + if(dash){ + *dash = 0; + } + + // v1.2.3 (1 Jan 2025) + sprintf(_version_info, "%s (%s)", version, build_date); } void UITask::renderCurrScreen() { - char tmp[80]; // render 'home' screen _display->drawXbm(0, 0, meshcore_logo, 128, 13); _display->setCursor(0, 20); _display->setTextSize(1); _display->print(_node_name); - sprintf(tmp, "Build: %s", _build_date); _display->setCursor(0, 32); - _display->print(tmp); + _display->print(_version_info); _display->setCursor(0, 43); _display->print("< Repeater >"); //_display->printf("freq : %03.2f sf %d\n", _prefs.freq, _prefs.sf); diff --git a/examples/simple_repeater/UITask.h b/examples/simple_repeater/UITask.h index e58d6111..13005957 100644 --- a/examples/simple_repeater/UITask.h +++ b/examples/simple_repeater/UITask.h @@ -7,12 +7,12 @@ class UITask { unsigned long _next_read, _next_refresh, _auto_off; int _prevBtnState; const char* _node_name; - const char* _build_date; + char _version_info[32]; void renderCurrScreen(); public: UITask(DisplayDriver& display) : _display(&display) { _next_read = _next_refresh = 0; } - void begin(const char* node_name, const char* build_date); + void begin(const char* node_name, const char* build_date, const char* firmware_version); void loop(); }; \ No newline at end of file diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index 1c76264e..1d8cac6e 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -20,11 +20,11 @@ /* ------------------------------ Config -------------------------------- */ #ifndef FIRMWARE_BUILD_DATE - #define FIRMWARE_BUILD_DATE "30 Mar 2025" + #define FIRMWARE_BUILD_DATE "7 Apr 2025" #endif #ifndef FIRMWARE_VERSION - #define FIRMWARE_VERSION "v1.4.2" + #define FIRMWARE_VERSION "v1.4.3" #endif #ifndef LORA_FREQ @@ -658,7 +658,7 @@ void setup() { the_mesh.begin(fs); #ifdef DISPLAY_CLASS - ui_task.begin(the_mesh.getNodeName(), FIRMWARE_BUILD_DATE); + ui_task.begin(the_mesh.getNodeName(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION); #endif // send out initial Advertisement to the mesh diff --git a/examples/simple_room_server/UITask.cpp b/examples/simple_room_server/UITask.cpp index 2f1d8ae5..eb7be78e 100644 --- a/examples/simple_room_server/UITask.cpp +++ b/examples/simple_room_server/UITask.cpp @@ -20,25 +20,33 @@ static const uint8_t meshcore_logo [] PROGMEM = { 0xe3, 0xe3, 0x8f, 0xff, 0x1f, 0xfc, 0x3c, 0x0e, 0x1f, 0xf8, 0xff, 0xf8, 0x70, 0x3c, 0x7f, 0xf8, }; -void UITask::begin(const char* node_name, const char* build_date) { +void UITask::begin(const char* node_name, const char* build_date, const char* firmware_version) { _prevBtnState = HIGH; _auto_off = millis() + AUTO_OFF_MILLIS; _node_name = node_name; - _build_date = build_date; _display->turnOn(); + + // strip off dash and commit hash by changing dash to null terminator + // e.g: v1.2.3-abcdef -> v1.2.3 + char *version = strdup(firmware_version); + char *dash = strchr(version, '-'); + if(dash){ + *dash = 0; + } + + // v1.2.3 (1 Jan 2025) + sprintf(_version_info, "%s (%s)", version, build_date); } void UITask::renderCurrScreen() { - char tmp[80]; // render 'home' screen _display->drawXbm(0, 0, meshcore_logo, 128, 13); _display->setCursor(0, 20); _display->setTextSize(1); _display->print(_node_name); - sprintf(tmp, "Build: %s", _build_date); _display->setCursor(0, 32); - _display->print(tmp); + _display->print(_version_info); _display->setCursor(0, 43); _display->print("< Room Server >"); //_display->printf("freq : %03.2f sf %d\n", _prefs.freq, _prefs.sf); diff --git a/examples/simple_room_server/UITask.h b/examples/simple_room_server/UITask.h index e58d6111..13005957 100644 --- a/examples/simple_room_server/UITask.h +++ b/examples/simple_room_server/UITask.h @@ -7,12 +7,12 @@ class UITask { unsigned long _next_read, _next_refresh, _auto_off; int _prevBtnState; const char* _node_name; - const char* _build_date; + char _version_info[32]; void renderCurrScreen(); public: UITask(DisplayDriver& display) : _display(&display) { _next_read = _next_refresh = 0; } - void begin(const char* node_name, const char* build_date); + void begin(const char* node_name, const char* build_date, const char* firmware_version); void loop(); }; \ No newline at end of file diff --git a/examples/simple_room_server/main.cpp b/examples/simple_room_server/main.cpp index daf8b497..235638f8 100644 --- a/examples/simple_room_server/main.cpp +++ b/examples/simple_room_server/main.cpp @@ -20,11 +20,11 @@ /* ------------------------------ Config -------------------------------- */ #ifndef FIRMWARE_BUILD_DATE - #define FIRMWARE_BUILD_DATE "30 Mar 2025" + #define FIRMWARE_BUILD_DATE "7 Apr 2025" #endif #ifndef FIRMWARE_VERSION - #define FIRMWARE_VERSION "v1.4.2" + #define FIRMWARE_VERSION "v1.4.3" #endif #ifndef LORA_FREQ @@ -887,7 +887,7 @@ void setup() { the_mesh.begin(fs); #ifdef DISPLAY_CLASS - ui_task.begin(the_mesh.getNodeName(), FIRMWARE_BUILD_DATE); + ui_task.begin(the_mesh.getNodeName(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION); #endif // send out initial Advertisement to the mesh diff --git a/platformio.ini b/platformio.ini index 2b51b8a4..771ddf0d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -23,12 +23,14 @@ lib_deps = adafruit/RTClib @ ^2.1.3 melopero/Melopero RV3028 @ ^1.1.0 build_flags = -w -DNDEBUG -DRADIOLIB_STATIC_ONLY=1 -DRADIOLIB_GODMODE=1 - -D LORA_FREQ=869.525 - -D LORA_BW=250 - -D LORA_SF=11 -build_src_filter = - +<*.cpp> - + + -D LORA_FREQ=869.525 + -D LORA_BW=250 + -D LORA_SF=11 +build_src_filter = + +<*.cpp> + + + +; ----------------- ESP32 --------------------- [esp32_base] extends = arduino_base diff --git a/src/Dispatcher.cpp b/src/Dispatcher.cpp index ae225d36..7a415f07 100644 --- a/src/Dispatcher.cpp +++ b/src/Dispatcher.cpp @@ -101,6 +101,12 @@ void Dispatcher::checkRecv() { #endif pkt->header = raw[i++]; + if (pkt->hasTransportCodes()) { + memcpy(&pkt->transport_codes[0], &raw[i], 2); i += 2; + memcpy(&pkt->transport_codes[1], &raw[i], 2); i += 2; + } else { + pkt->transport_codes[0] = pkt->transport_codes[1] = 0; + } pkt->path_len = raw[i++]; if (pkt->path_len > MAX_PATH_SIZE || i + pkt->path_len > len) { @@ -132,7 +138,7 @@ void Dispatcher::checkRecv() { #if MESH_PACKET_LOGGING Serial.print(getLogDateTime()); Serial.printf(": RX, len=%d (type=%d, route=%s, payload_len=%d) SNR=%d RSSI=%d score=%d", - 2 + pkt->path_len + pkt->payload_len, pkt->getPayloadType(), pkt->isRouteDirect() ? "D" : "F", pkt->payload_len, + pkt->getRawLength(), pkt->getPayloadType(), pkt->isRouteDirect() ? "D" : "F", pkt->payload_len, (int)pkt->getSNR(), (int)_radio->getLastRSSI(), (int)(score*1000)); static uint8_t packet_hash[MAX_HASH_SIZE]; @@ -147,7 +153,7 @@ void Dispatcher::checkRecv() { Serial.printf("\n"); } #endif - logRx(pkt, 2 + pkt->path_len + pkt->payload_len, score); // hook for custom logging + logRx(pkt, pkt->getRawLength(), score); // hook for custom logging if (pkt->isRouteFlood()) { n_recv_flood++; @@ -212,6 +218,10 @@ void Dispatcher::checkSend() { raw[len++] = NODE_ID; #endif raw[len++] = outbound->header; + if (outbound->hasTransportCodes()) { + memcpy(&raw[len], &outbound->transport_codes[0], 2); len += 2; + memcpy(&raw[len], &outbound->transport_codes[1], 2); len += 2; + } raw[len++] = outbound->path_len; memcpy(&raw[len], outbound->path, outbound->path_len); len += outbound->path_len; diff --git a/src/Mesh.cpp b/src/Mesh.cpp index 0a0fd769..fe3b2473 100644 --- a/src/Mesh.cpp +++ b/src/Mesh.cpp @@ -15,7 +15,7 @@ bool Mesh::allowPacketForward(const mesh::Packet* packet) { return false; // by default, Transport NOT enabled } uint32_t Mesh::getRetransmitDelay(const mesh::Packet* packet) { - uint32_t t = (_radio->getEstAirtimeFor(packet->path_len + packet->payload_len + 2) * 52 / 50) / 2; + uint32_t t = (_radio->getEstAirtimeFor(packet->getRawLength()) * 52 / 50) / 2; return _rng->nextInt(0, 5)*t; } diff --git a/src/Packet.cpp b/src/Packet.cpp index e338b60d..cb31638c 100644 --- a/src/Packet.cpp +++ b/src/Packet.cpp @@ -10,6 +10,10 @@ Packet::Packet() { payload_len = 0; } +int Packet::getRawLength() const { + return 2 + path_len + payload_len + (hasTransportCodes() ? 4 : 0); +} + void Packet::calculatePacketHash(uint8_t* hash) const { SHA256 sha; uint8_t t = getPayloadType(); @@ -24,6 +28,10 @@ void Packet::calculatePacketHash(uint8_t* hash) const { uint8_t Packet::writeTo(uint8_t dest[]) const { uint8_t i = 0; dest[i++] = header; + if (hasTransportCodes()) { + memcpy(&dest[i], &transport_codes[0], 2); i += 2; + memcpy(&dest[i], &transport_codes[1], 2); i += 2; + } dest[i++] = path_len; memcpy(&dest[i], path, path_len); i += path_len; memcpy(&dest[i], payload, payload_len); i += payload_len; @@ -33,6 +41,12 @@ uint8_t Packet::writeTo(uint8_t dest[]) const { bool Packet::readFrom(const uint8_t src[], uint8_t len) { uint8_t i = 0; header = src[i++]; + if (hasTransportCodes()) { + memcpy(&transport_codes[0], &src[i], 2); i += 2; + memcpy(&transport_codes[1], &src[i], 2); i += 2; + } else { + transport_codes[0] = transport_codes[1] = 0; + } path_len = src[i++]; if (path_len > sizeof(path)) return false; // bad encoding memcpy(path, &src[i], path_len); i += path_len; diff --git a/src/Packet.h b/src/Packet.h index e20b3a49..7c7df8e3 100644 --- a/src/Packet.h +++ b/src/Packet.h @@ -11,10 +11,10 @@ namespace mesh { #define PH_VER_SHIFT 6 #define PH_VER_MASK 0x03 // 2-bits -#define ROUTE_TYPE_RESERVED1 0x00 // FUTURE -#define ROUTE_TYPE_FLOOD 0x01 // flood mode, needs 'path' to be built up (max 64 bytes) -#define ROUTE_TYPE_DIRECT 0x02 // direct route, 'path' is supplied -#define ROUTE_TYPE_RESERVED2 0x03 // FUTURE +#define ROUTE_TYPE_TRANSPORT_FLOOD 0x00 // flood mode + transport codes +#define ROUTE_TYPE_FLOOD 0x01 // flood mode, needs 'path' to be built up (max 64 bytes) +#define ROUTE_TYPE_DIRECT 0x02 // direct route, 'path' is supplied +#define ROUTE_TYPE_TRANSPORT_DIRECT 0x03 // direct route + transport codes #define PAYLOAD_TYPE_REQ 0x00 // request (prefixed with dest/src hashes, MAC) (enc data: timestamp, blob) #define PAYLOAD_TYPE_RESPONSE 0x01 // response to REQ or ANON_REQ (prefixed with dest/src hashes, MAC) (enc data: timestamp, blob) @@ -43,6 +43,7 @@ public: uint8_t header; uint16_t payload_len, path_len; + uint16_t transport_codes[2]; uint8_t path[MAX_PATH_SIZE]; uint8_t payload[MAX_PACKET_PAYLOAD]; int8_t _snr; @@ -58,8 +59,10 @@ public: */ uint8_t getRouteType() const { return header & PH_ROUTE_MASK; } - bool isRouteFlood() const { return getRouteType() == ROUTE_TYPE_FLOOD; } - bool isRouteDirect() const { return getRouteType() == ROUTE_TYPE_DIRECT; } + bool isRouteFlood() const { return getRouteType() == ROUTE_TYPE_FLOOD || getRouteType() == ROUTE_TYPE_TRANSPORT_FLOOD; } + bool isRouteDirect() const { return getRouteType() == ROUTE_TYPE_DIRECT || getRouteType() == ROUTE_TYPE_TRANSPORT_DIRECT; } + + bool hasTransportCodes() const { return getRouteType() == ROUTE_TYPE_TRANSPORT_FLOOD || getRouteType() == ROUTE_TYPE_TRANSPORT_DIRECT; } /** * \returns one of PAYLOAD_TYPE_ values @@ -76,6 +79,11 @@ public: float getSNR() const { return ((float)_snr) / 4.0f; } + /** + * \returns the encoded/wire format length of this packet + */ + int getRawLength() const; + /** * \brief save entire packet as a blob * \param dest (OUT) destination buffer (assumed to be MAX_MTU_SIZE) diff --git a/src/helpers/BaseChatMesh.cpp b/src/helpers/BaseChatMesh.cpp index 083a0629..97aefff4 100644 --- a/src/helpers/BaseChatMesh.cpp +++ b/src/helpers/BaseChatMesh.cpp @@ -31,8 +31,29 @@ void BaseChatMesh::onAdvertRecv(mesh::Packet* packet, const mesh::Identity& id, } } + // save a copy of raw advert packet (to support "Share..." function) + int plen = packet->writeTo(temp_buf); + putBlobByKey(id.pub_key, PUB_KEY_SIZE, temp_buf, plen); + bool is_new = false; if (from == NULL) { + if (!isAutoAddEnabled()) { + ContactInfo ci; + memset(&ci, 0, sizeof(ci)); + ci.id = id; + ci.out_path_len = -1; // initially out_path is unknown + StrHelper::strncpy(ci.name, parser.getName(), sizeof(ci.name)); + ci.type = parser.getType(); + if (parser.hasLatLon()) { + ci.gps_lat = parser.getIntLat(); + ci.gps_lon = parser.getIntLon(); + } + ci.last_advert_timestamp = timestamp; + ci.lastmod = getRTCClock()->getCurrentTime(); + onDiscoveredContact(ci, true); // let UI know + return; + } + is_new = true; if (num_contacts < MAX_CONTACTS) { from = &contacts[num_contacts++]; @@ -50,10 +71,6 @@ void BaseChatMesh::onAdvertRecv(mesh::Packet* packet, const mesh::Identity& id, } } - // save a copy of raw advert packet (to support "Share..." function) - int plen = packet->writeTo(temp_buf); - putBlobByKey(id.pub_key, PUB_KEY_SIZE, temp_buf, plen); - // update StrHelper::strncpy(from->name, parser.getName(), sizeof(from->name)); from->type = parser.getType(); @@ -252,7 +269,7 @@ int BaseChatMesh::sendMessage(const ContactInfo& recipient, uint32_t timestamp, mesh::Packet* pkt = composeMsgPacket(recipient, timestamp, attempt, text, expected_ack); if (pkt == NULL) return MSG_SEND_FAILED; - uint32_t t = _radio->getEstAirtimeFor(pkt->payload_len + pkt->path_len + 2); + uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength()); int rc; if (recipient.out_path_len < 0) { @@ -279,7 +296,7 @@ int BaseChatMesh::sendCommandData(const ContactInfo& recipient, uint32_t timest auto pkt = createDatagram(PAYLOAD_TYPE_TXT_MSG, recipient.id, recipient.shared_secret, temp, 5 + text_len); if (pkt == NULL) return MSG_SEND_FAILED; - uint32_t t = _radio->getEstAirtimeFor(pkt->payload_len + pkt->path_len + 2); + uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength()); int rc; if (recipient.out_path_len < 0) { sendFlood(pkt); @@ -362,7 +379,7 @@ int BaseChatMesh::sendLogin(const ContactInfo& recipient, const char* password, auto pkt = createAnonDatagram(PAYLOAD_TYPE_ANON_REQ, self_id, recipient.id, recipient.shared_secret, temp, tlen); if (pkt) { - uint32_t t = _radio->getEstAirtimeFor(pkt->payload_len + pkt->path_len + 2); + uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength()); if (recipient.out_path_len < 0) { sendFlood(pkt); est_timeout = calcFloodTimeoutMillisFor(t); @@ -386,7 +403,7 @@ int BaseChatMesh::sendStatusRequest(const ContactInfo& recipient, uint32_t& est auto pkt = createDatagram(PAYLOAD_TYPE_REQ, recipient.id, recipient.shared_secret, temp, sizeof(temp)); if (pkt) { - uint32_t t = _radio->getEstAirtimeFor(pkt->payload_len + pkt->path_len + 2); + uint32_t t = _radio->getEstAirtimeFor(pkt->getRawLength()); if (recipient.out_path_len < 0) { sendFlood(pkt); est_timeout = calcFloodTimeoutMillisFor(t); diff --git a/src/helpers/BaseChatMesh.h b/src/helpers/BaseChatMesh.h index 30598f6c..ed6e1c3a 100644 --- a/src/helpers/BaseChatMesh.h +++ b/src/helpers/BaseChatMesh.h @@ -103,6 +103,7 @@ protected: } // 'UI' concepts, for sub-classes to implement + virtual bool isAutoAddEnabled() const { return true; } virtual void onDiscoveredContact(ContactInfo& contact, bool is_new) = 0; virtual bool processAck(const uint8_t *data) = 0; virtual void onContactPathUpdated(const ContactInfo& contact) = 0; diff --git a/src/helpers/CustomLR1110Wrapper.h b/src/helpers/CustomLR1110Wrapper.h index fb3a4b91..3a96d3c2 100644 --- a/src/helpers/CustomLR1110Wrapper.h +++ b/src/helpers/CustomLR1110Wrapper.h @@ -27,4 +27,5 @@ public: float getLastRSSI() const override { return ((CustomLR1110 *)_radio)->getRSSI(); } float getLastSNR() const override { return ((CustomLR1110 *)_radio)->getSNR(); } + int16_t setRxBoostedGainMode(bool en) { return ((CustomLR1110 *)_radio)->setRxBoostedGainMode(en); }; }; diff --git a/src/helpers/TBeamBoard.h b/src/helpers/TBeamBoard.h index 6c6367fa..fc52e712 100644 --- a/src/helpers/TBeamBoard.h +++ b/src/helpers/TBeamBoard.h @@ -33,11 +33,11 @@ class TBeamBoard : public ESP32Board { public: void begin() { ESP32Board::begin(); - + power.setALDO2Voltage(3300); power.enableALDO2(); - pinMode(38,INPUT_PULLUP); + pinMode(38, INPUT_PULLUP); esp_reset_reason_t reason = esp_reset_reason(); if (reason == ESP_RST_DEEPSLEEP) { @@ -75,7 +75,7 @@ public: } uint16_t getBattMilliVolts() override { - return 0; + return power.getBattVoltage(); } const char* getManufacturerName() const override { diff --git a/src/helpers/nrf52/PromicroBoard.cpp b/src/helpers/nrf52/PromicroBoard.cpp index 58710509..b923e16e 100644 --- a/src/helpers/nrf52/PromicroBoard.cpp +++ b/src/helpers/nrf52/PromicroBoard.cpp @@ -14,7 +14,7 @@ void PromicroBoard::begin() { pinMode(PIN_VBAT_READ, INPUT); #ifdef BUTTON_PIN - pinMode(BUTTON_PIN, INPUT); + pinMode(BUTTON_PIN, INPUT_PULLUP); #endif #if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL) diff --git a/src/helpers/nrf52/RAK4631Board.cpp b/src/helpers/nrf52/RAK4631Board.cpp index 4d2f0edf..8b368734 100644 --- a/src/helpers/nrf52/RAK4631Board.cpp +++ b/src/helpers/nrf52/RAK4631Board.cpp @@ -27,7 +27,7 @@ void RAK4631Board::begin() { #endif #if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL) - Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL) + Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL); #endif Wire.begin(); diff --git a/src/helpers/nrf52/T1000eBoard.cpp b/src/helpers/nrf52/T1000eBoard.cpp index c6fc27a9..a17711db 100644 --- a/src/helpers/nrf52/T1000eBoard.cpp +++ b/src/helpers/nrf52/T1000eBoard.cpp @@ -18,7 +18,7 @@ void T1000eBoard::begin() { #endif #if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL) - Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL) + Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL); #endif Wire.begin(); diff --git a/src/helpers/nrf52/T1000eBoard.h b/src/helpers/nrf52/T1000eBoard.h index d71c829b..9511706b 100644 --- a/src/helpers/nrf52/T1000eBoard.h +++ b/src/helpers/nrf52/T1000eBoard.h @@ -29,9 +29,12 @@ public: uint16_t getBattMilliVolts() override { #ifdef BATTERY_PIN + digitalWrite(PIN_3V3_EN, HIGH); analogReference(AR_INTERNAL_3_0); analogReadResolution(12); + delay(10); float volts = (analogRead(BATTERY_PIN) * ADC_MULTIPLIER * AREF_VOLTAGE) / 4096; + digitalWrite(PIN_3V3_EN, LOW); analogReference(AR_DEFAULT); // put back to default analogReadResolution(10); diff --git a/src/helpers/nrf52/T114Board.cpp b/src/helpers/nrf52/T114Board.cpp index d39b3e71..1f8c5854 100644 --- a/src/helpers/nrf52/T114Board.cpp +++ b/src/helpers/nrf52/T114Board.cpp @@ -27,7 +27,7 @@ void T114Board::begin() { pinMode(PIN_VBAT_READ, INPUT); #if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL) - Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL) + Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL); #endif Wire.begin(); diff --git a/src/helpers/nrf52/TechoBoard.cpp b/src/helpers/nrf52/TechoBoard.cpp index 13a250e6..dee14688 100644 --- a/src/helpers/nrf52/TechoBoard.cpp +++ b/src/helpers/nrf52/TechoBoard.cpp @@ -24,19 +24,6 @@ void TechoBoard::begin() { // for future use, sub-classes SHOULD call this from their begin() startup_reason = BD_STARTUP_NORMAL; - delay(200); - pinMode(PIN_PWR_EN, OUTPUT); - digitalWrite(PIN_PWR_EN, HIGH); - pinMode(PIN_BUTTON1, INPUT_PULLUP); - pinMode(PIN_BUTTON2, INPUT_PULLUP); - pinMode(LED_RED, OUTPUT); - pinMode(LED_GREEN, OUTPUT); - pinMode(LED_BLUE, OUTPUT); - delay(200); - - pinMode(PIN_TXCO, OUTPUT); - digitalWrite(PIN_TXCO, HIGH); - Wire.begin(); pinMode(SX126X_POWER_EN, OUTPUT); diff --git a/src/helpers/nrf52/XiaoNrf52Board.cpp b/src/helpers/nrf52/XiaoNrf52Board.cpp new file mode 100644 index 00000000..c603b2af --- /dev/null +++ b/src/helpers/nrf52/XiaoNrf52Board.cpp @@ -0,0 +1,95 @@ +#ifdef XIAO_NRF52 + +#include +#include "XiaoNrf52Board.h" + +#include +#include + +static BLEDfu bledfu; + +static void connect_callback(uint16_t conn_handle) +{ + (void)conn_handle; + MESH_DEBUG_PRINTLN("BLE client connected"); +} + +static void disconnect_callback(uint16_t conn_handle, uint8_t reason) +{ + (void)conn_handle; + (void)reason; + + MESH_DEBUG_PRINTLN("BLE client disconnected"); +} + +void XiaoNrf52Board::begin() { + // for future use, sub-classes SHOULD call this from their begin() + startup_reason = BD_STARTUP_NORMAL; + + pinMode(PIN_VBAT, INPUT); + pinMode(VBAT_ENABLE, OUTPUT); + digitalWrite(VBAT_ENABLE, HIGH); + +#if defined(PIN_WIRE_SDA) && defined(PIN_WIRE_SCL) + Wire.setPins(PIN_WIRE_SDA, PIN_WIRE_SCL); +#endif + + Wire.begin(); + +#ifdef P_LORA_TX_LED + pinMode(P_LORA_TX_LED, OUTPUT); + digitalWrite(P_LORA_TX_LED, HIGH); +#endif + +// pinMode(SX126X_POWER_EN, OUTPUT); +// digitalWrite(SX126X_POWER_EN, HIGH); + delay(10); // give sx1262 some time to power up +} + +bool XiaoNrf52Board::startOTAUpdate(const char* id, char reply[]) { + // Config the peripheral connection with maximum bandwidth + // more SRAM required by SoftDevice + // Note: All config***() function must be called before begin() + Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); + Bluefruit.configPrphConn(92, BLE_GAP_EVENT_LENGTH_MIN, 16, 16); + + Bluefruit.begin(1, 0); + // Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4 + Bluefruit.setTxPower(4); + // Set the BLE device name + Bluefruit.setName("XIAO_NRF52_OTA"); + + Bluefruit.Periph.setConnectCallback(connect_callback); + Bluefruit.Periph.setDisconnectCallback(disconnect_callback); + + // To be consistent OTA DFU should be added first if it exists + bledfu.begin(); + + // Set up and start advertising + // Advertising packet + Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); + Bluefruit.Advertising.addTxPower(); + Bluefruit.Advertising.addName(); + + /* Start Advertising + - Enable auto advertising if disconnected + - Interval: fast mode = 20 ms, slow mode = 152.5 ms + - Timeout for fast mode is 30 seconds + - Start(timeout) with timeout = 0 will advertise forever (until connected) + + For recommended advertising interval + https://developer.apple.com/library/content/qa/qa1931/_index.html + */ + Bluefruit.Advertising.restartOnDisconnect(true); + Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms + Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode + Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds + + strcpy(reply, "OK - started"); + return true; + + + return false; +} + +#endif \ No newline at end of file diff --git a/src/helpers/nrf52/XiaoNrf52Board.h b/src/helpers/nrf52/XiaoNrf52Board.h new file mode 100644 index 00000000..1474892e --- /dev/null +++ b/src/helpers/nrf52/XiaoNrf52Board.h @@ -0,0 +1,79 @@ +#pragma once + +#include +#include + +#ifdef XIAO_NRF52 + +// LoRa radio module pins for Seeed Xiao-nrf52 +#ifdef SX1262_XIAO_S3_VARIANT + #define P_LORA_DIO_1 D0 + #define P_LORA_BUSY D1 + #define P_LORA_RESET D2 + #define P_LORA_NSS D3 + #define LORA_TX_BOOST_PIN D4 +#else + #define P_LORA_DIO_1 D1 + #define P_LORA_BUSY D3 + #define P_LORA_RESET D2 + #define P_LORA_NSS D4 + #define LORA_TX_BOOST_PIN D5 +#endif +#define P_LORA_SCLK PIN_SPI_SCK +#define P_LORA_MISO PIN_SPI_MISO +#define P_LORA_MOSI PIN_SPI_MOSI +//#define SX126X_POWER_EN 37 + +#define SX126X_DIO2_AS_RF_SWITCH true +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 + + +class XiaoNrf52Board : public mesh::MainBoard { +protected: + uint8_t startup_reason; + +public: + void begin(); + uint8_t getStartupReason() const override { return startup_reason; } + +#if defined(P_LORA_TX_LED) + void onBeforeTransmit() override { + digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED on + } + void onAfterTransmit() override { + digitalWrite(P_LORA_TX_LED, HIGH); // turn TX LED off + } +#endif + + uint16_t getBattMilliVolts() override { + // Please read befor going further ;) + // https://wiki.seeedstudio.com/XIAO_BLE#q3-what-are-the-considerations-when-using-xiao-nrf52840-sense-for-battery-charging + + pinMode(BAT_NOT_CHARGING, INPUT); + if (digitalRead(BAT_NOT_CHARGING) == HIGH) { + int adcvalue = 0; + analogReadResolution(12); + analogReference(AR_INTERNAL_3_0); + digitalWrite(VBAT_ENABLE, LOW); + delay(10); + adcvalue = analogRead(PIN_VBAT); + digitalWrite(VBAT_ENABLE, HIGH); + return (adcvalue * ADC_MULTIPLIER * AREF_VOLTAGE) / 4.096; + } else { + digitalWrite(VBAT_ENABLE, HIGH); // ensures high ! + return 4200; // charging value + } + } + + const char* getManufacturerName() const override { + return "Seeed Xiao-nrf52"; + } + + void reboot() override { + NVIC_SystemReset(); + } + + bool startOTAUpdate(const char* id, char reply[]) override; +}; + +#endif \ No newline at end of file diff --git a/variants/lilygo_tbeam/platformio.ini b/variants/lilygo_tbeam/platformio.ini index 007d06d2..01ab38e7 100644 --- a/variants/lilygo_tbeam/platformio.ini +++ b/variants/lilygo_tbeam/platformio.ini @@ -27,7 +27,7 @@ build_flags = ${LilyGo_TBeam.build_flags} -D DISPLAY_CLASS=SSD1306Display -D MAX_CONTACTS=100 - -D MAX_GROUP_CHANNELS=1 + -D MAX_GROUP_CHANNELS=8 -D BLE_PIN_CODE=123456 -D BLE_DEBUG_LOGGING=1 -D MESH_PACKET_LOGGING=1 diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index 63d6b6b8..f8708acd 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -7,13 +7,16 @@ build_flags = ${nrf52840_base.build_flags} -I variants/rak4631 -D RAK_4631 -D PIN_USER_BTN=9 + -D PIN_BOARD_SCL=14 + -D PIN_BOARD_SDA=13 + -D PIN_OLED_RESET=-1 -D RADIO_CLASS=CustomSX1262 -D WRAPPER_CLASS=CustomSX1262Wrapper -D LORA_TX_POWER=22 -D SX126X_CURRENT_LIMIT=130 -D SX126X_RX_BOOSTED_GAIN=1 build_src_filter = ${nrf52840_base.build_src_filter} - + + + +<../variants/rak4631> lib_deps = ${nrf52840_base.lib_deps} @@ -83,7 +86,7 @@ build_flags = ; -D MESH_DEBUG=1 build_src_filter = ${rak4631.build_src_filter} + - + + + +<../examples/companion_radio> lib_deps = ${rak4631.lib_deps} diff --git a/variants/t1000-e/variant.cpp b/variants/t1000-e/variant.cpp index a71a831b..f17b3a8d 100644 --- a/variants/t1000-e/variant.cpp +++ b/variants/t1000-e/variant.cpp @@ -83,13 +83,13 @@ void initVariant() pinMode(GPS_RTC_INT, OUTPUT); pinMode(LED_PIN, OUTPUT); - digitalWrite(PIN_3V3_EN, HIGH); + digitalWrite(PIN_3V3_EN, LOW); digitalWrite(PIN_3V3_ACC_EN, LOW); digitalWrite(BUZZER_EN, LOW); digitalWrite(SENSOR_EN, LOW); digitalWrite(GPS_EN, LOW); digitalWrite(GPS_RESET, LOW); - digitalWrite(GPS_VRTC_EN, HIGH); + digitalWrite(GPS_VRTC_EN, LOW); digitalWrite(GPS_SLEEP_INT, HIGH); digitalWrite(GPS_RTC_INT, LOW); digitalWrite(LED_PIN, LOW); diff --git a/variants/t114/platformio.ini b/variants/t114/platformio.ini index 297517d4..61a722d0 100644 --- a/variants/t114/platformio.ini +++ b/variants/t114/platformio.ini @@ -74,3 +74,22 @@ build_src_filter = ${Heltec_t114.build_src_filter} lib_deps = ${Heltec_t114.lib_deps} densaugeo/base64 @ ~1.4.0 + +[env:Heltec_t114_companion_radio_usb] +extends = Heltec_t114 +build_flags = + ${Heltec_t114.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 +; -D BLE_PIN_CODE=123456 +; -D BLE_DEBUG_LOGGING=1 +; -D ENABLE_PRIVATE_KEY_IMPORT=1 +; -D ENABLE_PRIVATE_KEY_EXPORT=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Heltec_t114.build_src_filter} + + + +<../examples/companion_radio/main.cpp> +lib_deps = + ${Heltec_t114.lib_deps} + densaugeo/base64 @ ~1.4.0 \ No newline at end of file diff --git a/variants/techo/variant.cpp b/variants/techo/variant.cpp index 3d3dc9c1..7b7bee95 100644 --- a/variants/techo/variant.cpp +++ b/variants/techo/variant.cpp @@ -9,14 +9,22 @@ const uint32_t g_ADigitalPinMap[] = { 40, 41, 42, 43, 44, 45, 46, 47 }; -void initVariant() -{ +void initVariant() { + pinMode(PIN_PWR_EN, OUTPUT); + digitalWrite(PIN_PWR_EN, HIGH); + + pinMode(PIN_BUTTON1, INPUT_PULLUP); + pinMode(PIN_BUTTON2, INPUT_PULLUP); + pinMode(LED_RED, OUTPUT); - ledOff(LED_RED); - pinMode(LED_GREEN, OUTPUT); - ledOff(LED_GREEN); - pinMode(LED_BLUE, OUTPUT); - ledOff(LED_BLUE); + digitalWrite(LED_BLUE, HIGH); + + pinMode(PIN_TXCO, OUTPUT); + digitalWrite(PIN_TXCO, HIGH); + + // shutdown gps + pinMode(PIN_GPS_STANDBY, OUTPUT); + digitalWrite(PIN_GPS_STANDBY, LOW); } diff --git a/variants/techo/variant.h b/variants/techo/variant.h index 8fcb765e..9f4da8e7 100644 --- a/variants/techo/variant.h +++ b/variants/techo/variant.h @@ -42,7 +42,6 @@ #define PIN_SERIAL1_RX (41) // GPS TX #define PIN_SERIAL1_TX (40) // GPS RX - //////////////////////////////////////////////////////////////////////////////// // I2C pin definition @@ -100,3 +99,25 @@ #define PIN_SPI1_MISO (39) #define PIN_SPI1_MOSI (29) #define PIN_SPI1_SCK (31) + +//////////////////////////////////////////////////////////////////////////////// +// Display + +#define DISP_MISO (38) +#define DISP_MOSI (29) +#define DISP_SCLK (31) +#define DISP_CS (30) +#define DISP_DC (28) +#define DISP_RST (2) +#define DISP_BUSY (3) +#define DISP_BACKLIGHT (43) + +//////////////////////////////////////////////////////////////////////////////// +// GPS + +#define PIN_GPS_RX (41) +#define PIN_GPS_TX (40) +#define PIN_GPS_WAKEUP (34) +#define PIN_GPS_RESET (37) +#define PIN_GPS_PPS (36) +#define PIN_GPS_STANDBY (34) diff --git a/variants/xiao_nrf52/platformio.ini b/variants/xiao_nrf52/platformio.ini new file mode 100644 index 00000000..0947d86e --- /dev/null +++ b/variants/xiao_nrf52/platformio.ini @@ -0,0 +1,81 @@ +[nrf52840_xiao] +extends = nrf52_base +platform_packages = + toolchain-gccarmnoneeabi@~1.100301.0 + framework-arduinoadafruitnrf52 +board = seeed-xiao-afruitnrf52-nrf52840 +board_build.ldscript = boards/nrf52840_s140_v7.ld +build_flags = ${nrf52_base.build_flags} + -D NRF52_PLATFORM -D XIAO_NRF52 + -I lib/nrf52/s140_nrf52_7.3.0_API/include + -I lib/nrf52/s140_nrf52_7.3.0_API/include/nrf52 +lib_ignore = + BluetoothOTA + lvgl + lib5b4 +lib_deps = + ${nrf52_base.lib_deps} + rweather/Crypto @ ^0.4.0 + +[Xiao_nrf52] +extends = nrf52840_xiao +;board_build.ldscript = boards/nrf52840_s140_v7.ld +build_flags = ${nrf52840_xiao.build_flags} + -D P_LORA_TX_LED=11 + -I variants/xiao_nrf52 + -I src/helpers/nrf52 + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D SX126X_CURRENT_LIMIT=130 + -D SX126X_RX_BOOSTED_GAIN=1 +build_src_filter = ${nrf52840_xiao.build_src_filter} + + + + + +<../variants/xiao_nrf52> +debug_tool = jlink +upload_protocol = nrfutil + +[env:Xiao_nrf52_companion_radio_ble] +extends = Xiao_nrf52 +build_flags = + ${Xiao_nrf52.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 + -D BLE_PIN_CODE=123456 +; -D BLE_DEBUG_LOGGING=1 +; -D ENABLE_PRIVATE_KEY_IMPORT=1 +; -D ENABLE_PRIVATE_KEY_EXPORT=1 + -D MESH_PACKET_LOGGING=1 + -D MESH_DEBUG=1 +build_src_filter = ${Xiao_nrf52.build_src_filter} + + + +<../examples/companion_radio/main.cpp> +lib_deps = + ${Xiao_nrf52.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:Xiao_nrf52_alt_pinout_companion_radio_ble] +extends = env:Xiao_nrf52_companion_radio_ble +build_flags = + ${env:Xiao_nrf52_companion_radio_ble.build_flags} + -D SX1262_XIAO_S3_VARIANT + +[env:Xiao_nrf52_repeater] +extends = Xiao_nrf52 +build_flags = + ${Xiao_nrf52.build_flags} + -D ADVERT_NAME='"Xiao_nrf52 Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Xiao_nrf52.build_src_filter} + +<../examples/simple_repeater/main.cpp> + +[env:Xiao_nrf52_alt_pinout_repeater] +extends = env:Xiao_nrf52_repeater +build_flags = + ${env:Xiao_nrf52_repeater.build_flags} + -D SX1262_XIAO_S3_VARIANT \ No newline at end of file diff --git a/variants/xiao_nrf52/target.cpp b/variants/xiao_nrf52/target.cpp new file mode 100644 index 00000000..0707aa39 --- /dev/null +++ b/variants/xiao_nrf52/target.cpp @@ -0,0 +1,68 @@ +#include +#include "target.h" +#include + +XiaoNrf52Board board; + +RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI); + +WRAPPER_CLASS radio_driver(radio, board); + +VolatileRTCClock rtc_clock; + +#ifndef LORA_CR + #define LORA_CR 5 +#endif + +bool radio_init() { +// rtc_clock.begin(Wire); + +#ifdef SX126X_DIO3_TCXO_VOLTAGE + float tcxo = SX126X_DIO3_TCXO_VOLTAGE; +#else + float tcxo = 1.6f; +#endif + + SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI); + SPI.begin(); + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo); + if (status != RADIOLIB_ERR_NONE) { + Serial.print("ERROR: radio init failed: "); + Serial.println(status); + return false; // fail + } + + radio.setCRC(1); + +#ifdef SX126X_CURRENT_LIMIT + radio.setCurrentLimit(SX126X_CURRENT_LIMIT); +#endif +#ifdef SX126X_DIO2_AS_RF_SWITCH + radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH); +#endif +#ifdef SX126X_RX_BOOSTED_GAIN + radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN); +#endif + + return true; // success +} + +uint32_t radio_get_rng_seed() { + return radio.random(0x7FFFFFFF); +} + +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { + radio.setFrequency(freq); + radio.setSpreadingFactor(sf); + radio.setBandwidth(bw); + radio.setCodingRate(cr); +} + +void radio_set_tx_power(uint8_t dbm) { + radio.setOutputPower(dbm); +} + +mesh::LocalIdentity radio_new_identity() { + RadioNoiseListener rng(radio); + return mesh::LocalIdentity(&rng); // create new random identity +} diff --git a/variants/xiao_nrf52/target.h b/variants/xiao_nrf52/target.h new file mode 100644 index 00000000..85f1ce1c --- /dev/null +++ b/variants/xiao_nrf52/target.h @@ -0,0 +1,18 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 +#include +#include +#include +#include +#include + +extern XiaoNrf52Board board; +extern WRAPPER_CLASS radio_driver; +extern VolatileRTCClock rtc_clock; + +bool radio_init(); +uint32_t radio_get_rng_seed(); +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); +void radio_set_tx_power(uint8_t dbm); +mesh::LocalIdentity radio_new_identity(); diff --git a/variants/xiao_nrf52/variant.cpp b/variants/xiao_nrf52/variant.cpp new file mode 100644 index 00000000..3c99b98d --- /dev/null +++ b/variants/xiao_nrf52/variant.cpp @@ -0,0 +1,78 @@ +#include "variant.h" +#include "wiring_constants.h" +#include "wiring_digital.h" +#include "nrf.h" + +const uint32_t g_ADigitalPinMap[] = +{ + // D0 .. D10 + 2, // D0 is P0.02 (A0) + 3, // D1 is P0.03 (A1) + 28, // D2 is P0.28 (A2) + 29, // D3 is P0.29 (A3) + 4, // D4 is P0.04 (A4,SDA) + 5, // D5 is P0.05 (A5,SCL) + 43, // D6 is P1.11 (TX) + 44, // D7 is P1.12 (RX) + 45, // D8 is P1.13 (SCK) + 46, // D9 is P1.14 (MISO) + 47, // D10 is P1.15 (MOSI) + + // LEDs + 26, // D11 is P0.26 (LED RED) + 6, // D12 is P0.06 (LED BLUE) + 30, // D13 is P0.30 (LED GREEN) + 14, // D14 is P0.14 (READ_BAT) + + // LSM6DS3TR + 40, // D15 is P1.08 (6D_PWR) + 27, // D16 is P0.27 (6D_I2C_SCL) + 7, // D17 is P0.07 (6D_I2C_SDA) + 11, // D18 is P0.11 (6D_INT1) + + // MIC + 42, // D19 is P1.10 (MIC_PWR) + 32, // D20 is P1.00 (PDM_CLK) + 16, // D21 is P0.16 (PDM_DATA) + + // BQ25100 + 13, // D22 is P0.13 (HICHG) + 17, // D23 is P0.17 (~CHG) + + // + 21, // D24 is P0.21 (QSPI_SCK) + 25, // D25 is P0.25 (QSPI_CSN) + 20, // D26 is P0.20 (QSPI_SIO_0 DI) + 24, // D27 is P0.24 (QSPI_SIO_1 DO) + 22, // D28 is P0.22 (QSPI_SIO_2 WP) + 23, // D29 is P0.23 (QSPI_SIO_3 HOLD) + + // NFC + 9, // D30 is P0.09 (NFC1) + 10, // D31 is P0.10 (NFC2) + + // VBAT + 31, // D32 is P0.31 (VBAT) +}; + +void initVariant() +{ + // Disable reading of the BAT voltage. + // https://wiki.seeedstudio.com/XIAO_BLE#q3-what-are-the-considerations-when-using-xiao-nrf52840-sense-for-battery-charging + pinMode(VBAT_ENABLE, OUTPUT); + digitalWrite(VBAT_ENABLE, HIGH); + + // Low charging current. + // https://wiki.seeedstudio.com/XIAO_BLE#battery-charging-current + pinMode(PIN_CHARGING_CURRENT, INPUT); + + pinMode(PIN_QSPI_CS, OUTPUT); + digitalWrite(PIN_QSPI_CS, HIGH); + + pinMode(LED_RED, OUTPUT); + digitalWrite(LED_RED, HIGH); + pinMode(LED_GREEN, OUTPUT); + digitalWrite(LED_GREEN, HIGH); + pinMode(LED_BLUE, OUTPUT); + digitalWrite(LED_BLUE, HIGH); +} diff --git a/variants/xiao_nrf52/variant.h b/variants/xiao_nrf52/variant.h new file mode 100644 index 00000000..5d68d270 --- /dev/null +++ b/variants/xiao_nrf52/variant.h @@ -0,0 +1,149 @@ +#ifndef _SEEED_XIAO_NRF52840_H_ +#define _SEEED_XIAO_NRF52840_H_ + +/** Master clock frequency */ +#define VARIANT_MCK (64000000ul) + +#define USE_LFXO // Board uses 32khz crystal for LF +//#define USE_LFRC // Board uses RC for LF + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +#define PINS_COUNT (33) +#define NUM_DIGITAL_PINS (33) +#define NUM_ANALOG_INPUTS (8) +#define NUM_ANALOG_OUTPUTS (0) + +// LEDs +#define PIN_LED (LED_RED) +#define LED_PWR (PINS_COUNT) +#define PIN_NEOPIXEL (PINS_COUNT) +#define NEOPIXEL_NUM (0) + +#define LED_BUILTIN (PIN_LED) + +#define LED_RED (11) +#define LED_GREEN (13) +#define LED_BLUE (12) + +#define LED_STATE_ON (1) // State when LED is litted + +// Buttons +#define PIN_BUTTON1 (PINS_COUNT) + +// Digital PINs +static const uint8_t D0 = 0 ; +static const uint8_t D1 = 1 ; +static const uint8_t D2 = 2 ; +static const uint8_t D3 = 3 ; +static const uint8_t D4 = 4 ; +static const uint8_t D5 = 5 ; +static const uint8_t D6 = 6 ; +static const uint8_t D7 = 7 ; +static const uint8_t D8 = 8 ; +static const uint8_t D9 = 9 ; +static const uint8_t D10 = 10; + +#define VBAT_ENABLE (14) // Output LOW to enable reading of the BAT voltage. + // https://wiki.seeedstudio.com/XIAO_BLE#q3-what-are-the-considerations-when-using-xiao-nrf52840-sense-for-battery-charging + +#define PIN_CHARGING_CURRENT (22) // Battery Charging current + // https://wiki.seeedstudio.com/XIAO_BLE#battery-charging-current + +// Analog pins +#define PIN_A0 (0) +#define PIN_A1 (1) +#define PIN_A2 (2) +#define PIN_A3 (3) +#define PIN_A4 (4) +#define PIN_A5 (5) +#define PIN_VBAT (32) // Read the BAT voltage. + // https://wiki.seeedstudio.com/XIAO_BLE#q3-what-are-the-considerations-when-using-xiao-nrf52840-sense-for-battery-charging + +#define BAT_NOT_CHARGING (23) // LOW when charging + +#define AREF_VOLTAGE (3.0) +#define ADC_MULTIPLIER (3.0F) // 1M, 512k divider bridge + +static const uint8_t A0 = PIN_A0; +static const uint8_t A1 = PIN_A1; +static const uint8_t A2 = PIN_A2; +static const uint8_t A3 = PIN_A3; +static const uint8_t A4 = PIN_A4; +static const uint8_t A5 = PIN_A5; + +#define ADC_RESOLUTION (12) + +// Other pins +#define PIN_NFC1 (30) +#define PIN_NFC2 (31) + +// Serial interfaces +#define PIN_SERIAL1_RX (7) +#define PIN_SERIAL1_TX (6) + +// SPI Interfaces +#define SPI_INTERFACES_COUNT (2) + +#define PIN_SPI_MISO (9) +#define PIN_SPI_MOSI (10) +#define PIN_SPI_SCK (8) + +static const uint8_t SS = D3; // NSS for sx ? +static const uint8_t MOSI = PIN_SPI_MOSI; +static const uint8_t MISO = PIN_SPI_MISO; +static const uint8_t SCK = PIN_SPI_SCK ; + +#define PIN_SPI1_MISO (25) +#define PIN_SPI1_MOSI (26) +#define PIN_SPI1_SCK (29) + +// Wire Interfaces +#define WIRE_INTERFACES_COUNT (1) + +#define PIN_WIRE_SDA (17) // 4 and 5 are used for the sx1262 ! +#define PIN_WIRE_SCL (16) // use WIRE1_SDA + +static const uint8_t SDA = PIN_WIRE_SDA; +static const uint8_t SCL = PIN_WIRE_SCL; + +//#define PIN_WIRE1_SDA (17) +//#define PIN_WIRE1_SCL (16) +#define PIN_LSM6DS3TR_C_POWER (15) +#define PIN_LSM6DS3TR_C_INT1 (18) + +// PDM Interfaces +#define PIN_PDM_PWR (19) +#define PIN_PDM_CLK (20) +#define PIN_PDM_DIN (21) + +// QSPI Pins +#define PIN_QSPI_SCK (24) +#define PIN_QSPI_CS (25) +#define PIN_QSPI_IO0 (26) +#define PIN_QSPI_IO1 (27) +#define PIN_QSPI_IO2 (28) +#define PIN_QSPI_IO3 (29) + +// On-board QSPI Flash +#define EXTERNAL_FLASH_DEVICES (P25Q16H) +#define EXTERNAL_FLASH_USE_QSPI + +#ifdef __cplusplus +} +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#endif