Skip to content

Commit eae2fba

Browse files
authored
Merge pull request #1082 from KR4DIO/dev
Ikoka Handheld variant
2 parents 13bf82f + 2a33246 commit eae2fba

File tree

7 files changed

+562
-0
lines changed

7 files changed

+562
-0
lines changed
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#ifdef IKOKA_NRF52
2+
3+
#include <Arduino.h>
4+
#include <Wire.h>
5+
#include <bluefruit.h>
6+
7+
#include "IkokaNrf52Board.h"
8+
9+
static BLEDfu bledfu;
10+
11+
static void connect_callback(uint16_t conn_handle) {
12+
(void)conn_handle;
13+
MESH_DEBUG_PRINTLN("BLE client connected");
14+
}
15+
16+
static void disconnect_callback(uint16_t conn_handle, uint8_t reason) {
17+
(void)conn_handle;
18+
(void)reason;
19+
20+
MESH_DEBUG_PRINTLN("BLE client disconnected");
21+
}
22+
23+
void IkokaNrf52Board::begin() {
24+
// for future use, sub-classes SHOULD call this from their begin()
25+
startup_reason = BD_STARTUP_NORMAL;
26+
27+
// ensure we have pull ups on the screen i2c, this isn't always available
28+
// in hardware and it should only be 20k ohms. Disable the pullups if we
29+
// are using the rotated lcd breakout board
30+
#if defined(DISPLAY_CLASS) && DISPLAY_ROTATION == 0
31+
pinMode(PIN_WIRE_SDA, INPUT_PULLUP);
32+
pinMode(PIN_WIRE_SCL, INPUT_PULLUP);
33+
#endif
34+
35+
pinMode(PIN_VBAT, INPUT);
36+
pinMode(VBAT_ENABLE, OUTPUT);
37+
digitalWrite(VBAT_ENABLE, HIGH);
38+
39+
// required button pullup is handled as part of button initilization
40+
// in target.cpp
41+
42+
#if defined(PIN_WIRE_SDA) && defined(PIN_WIRE_SCL)
43+
Wire.setPins(PIN_WIRE_SDA, PIN_WIRE_SCL);
44+
#endif
45+
46+
Wire.begin();
47+
48+
#ifdef P_LORA_TX_LED
49+
pinMode(P_LORA_TX_LED, OUTPUT);
50+
digitalWrite(P_LORA_TX_LED, HIGH);
51+
#endif
52+
53+
delay(10); // give sx1262 some time to power up
54+
}
55+
56+
bool IkokaNrf52Board::startOTAUpdate(const char *id, char reply[]) {
57+
// Config the peripheral connection with maximum bandwidth
58+
// more SRAM required by SoftDevice
59+
// Note: All config***() function must be called before begin()
60+
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
61+
Bluefruit.configPrphConn(92, BLE_GAP_EVENT_LENGTH_MIN, 16, 16);
62+
63+
Bluefruit.begin(1, 0);
64+
// Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
65+
Bluefruit.setTxPower(4);
66+
// Set the BLE device name
67+
Bluefruit.setName("XIAO_NRF52_OTA");
68+
69+
Bluefruit.Periph.setConnectCallback(connect_callback);
70+
Bluefruit.Periph.setDisconnectCallback(disconnect_callback);
71+
72+
// To be consistent OTA DFU should be added first if it exists
73+
bledfu.begin();
74+
75+
// Set up and start advertising
76+
// Advertising packet
77+
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
78+
Bluefruit.Advertising.addTxPower();
79+
Bluefruit.Advertising.addName();
80+
81+
/* Start Advertising
82+
- Enable auto advertising if disconnected
83+
- Interval: fast mode = 20 ms, slow mode = 152.5 ms
84+
- Timeout for fast mode is 30 seconds
85+
- Start(timeout) with timeout = 0 will advertise forever (until connected)
86+
87+
For recommended advertising interval
88+
https://developer.apple.com/library/content/qa/qa1931/_index.html
89+
*/
90+
Bluefruit.Advertising.restartOnDisconnect(true);
91+
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
92+
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
93+
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
94+
95+
strcpy(reply, "OK - started");
96+
97+
return true;
98+
}
99+
100+
#endif
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#pragma once
2+
3+
#include <MeshCore.h>
4+
#include <Arduino.h>
5+
6+
#ifdef IKOKA_NRF52
7+
8+
class IkokaNrf52Board : public mesh::MainBoard {
9+
protected:
10+
uint8_t startup_reason;
11+
12+
public:
13+
void begin();
14+
uint8_t getStartupReason() const override { return startup_reason; }
15+
16+
#if defined(P_LORA_TX_LED)
17+
void onBeforeTransmit() override {
18+
digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED on
19+
}
20+
void onAfterTransmit() override {
21+
digitalWrite(P_LORA_TX_LED, HIGH); // turn TX LED off
22+
}
23+
#endif
24+
25+
uint16_t getBattMilliVolts() override {
26+
// Please read befor going further ;)
27+
// https://wiki.seeedstudio.com/XIAO_BLE#q3-what-are-the-considerations-when-using-xiao-nrf52840-sense-for-battery-charging
28+
29+
// We can't drive VBAT_ENABLE to HIGH as long
30+
// as we don't know wether we are charging or not ...
31+
// this is a 3mA loss (4/1500)
32+
digitalWrite(VBAT_ENABLE, LOW);
33+
int adcvalue = 0;
34+
analogReadResolution(12);
35+
analogReference(AR_INTERNAL_3_0);
36+
delay(10);
37+
adcvalue = analogRead(PIN_VBAT);
38+
return (adcvalue * ADC_MULTIPLIER * AREF_VOLTAGE) / 4.096;
39+
}
40+
41+
const char* getManufacturerName() const override {
42+
return "Ikoka Handheld E22 30dBm (Xiao_nrf52)";
43+
}
44+
45+
void reboot() override {
46+
NVIC_SystemReset();
47+
}
48+
49+
bool startOTAUpdate(const char* id, char reply[]) override;
50+
};
51+
52+
#endif
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
[ikoka_nrf52]
2+
extends = Xiao_nrf52
3+
lib_deps = ${nrf52_base.lib_deps}
4+
${sensor_base.lib_deps}
5+
densaugeo/base64 @ ~1.4.0
6+
build_flags = ${nrf52_base.build_flags}
7+
${sensor_base.build_flags}
8+
-I lib/nrf52/s140_nrf52_7.3.0_API/include
9+
-I lib/nrf52/s140_nrf52_7.3.0_API/include/nrf52
10+
-I variants/ikoka_handheld_nrf
11+
-UENV_INCLUDE_GPS
12+
-D IKOKA_NRF52
13+
-D RADIO_CLASS=CustomSX1262
14+
-D WRAPPER_CLASS=CustomSX1262Wrapper
15+
-D P_LORA_TX_LED=11
16+
-D P_LORA_DIO_1=D1
17+
-D P_LORA_RESET=D2
18+
-D P_LORA_BUSY=D3
19+
-D P_LORA_NSS=D4
20+
-D SX126X_RXEN=D5
21+
-D SX126X_TXEN=RADIOLIB_NC
22+
-D SX126X_DIO2_AS_RF_SWITCH=1
23+
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
24+
-D SX126X_CURRENT_LIMIT=140
25+
-D SX126X_RX_BOOSTED_GAIN=1
26+
build_src_filter = ${nrf52_base.build_src_filter}
27+
+<../variants/ikoka_handheld_nrf>
28+
+<helpers/sensors>
29+
30+
# larger screen has a different driver, this is for the 0.96 inch
31+
[ikoka_nrf52_ssd1306_companion]
32+
lib_deps = ${ikoka_nrf52.lib_deps}
33+
adafruit/Adafruit SSD1306 @ ^2.5.13
34+
build_flags = ${ikoka_nrf52.build_flags}
35+
-D DISPLAY_CLASS=SSD1306Display
36+
-D DISPLAY_ROTATION=0
37+
-D PIN_WIRE_SCL=D6
38+
-D PIN_WIRE_SDA=D7
39+
-D PIN_USER_BTN=D0
40+
-D MAX_CONTACTS=350
41+
-D MAX_GROUP_CHANNELS=40
42+
-D OFFLINE_QUEUE_SIZE=256
43+
-D QSPIFLASH=1
44+
-I examples/companion_radio/ui-new
45+
build_src_filter = ${ikoka_nrf52.build_src_filter}
46+
+<helpers/ui/SSD1306Display.cpp>
47+
+<../examples/companion_radio/ui-new/UITask.cpp>
48+
+<../examples/companion_radio/*.cpp>
49+
50+
[env:ikoka_handheld_nrf_e22_30dbm_096_companion_radio_ble]
51+
extends = ikoka_nrf52
52+
build_flags = ${ikoka_nrf52_ssd1306_companion.build_flags}
53+
-D BLE_PIN_CODE=123456
54+
-D LORA_TX_POWER=20
55+
build_src_filter = ${ikoka_nrf52_ssd1306_companion.build_src_filter}
56+
+<helpers/nrf52/SerialBLEInterface.cpp>
57+
58+
[env:ikoka_handheld_nrf_e22_30dbm_096_rotated_companion_radio_ble]
59+
extends = ikoka_nrf52
60+
build_flags = ${ikoka_nrf52_ssd1306_companion.build_flags}
61+
-D BLE_PIN_CODE=123456
62+
-D LORA_TX_POWER=20
63+
-D DISPLAY_ROTATION=2
64+
build_src_filter = ${ikoka_nrf52_ssd1306_companion.build_src_filter}
65+
+<helpers/nrf52/SerialBLEInterface.cpp>
66+
67+
[env:ikoka_handheld_nrf_e22_30dbm_096_companion_radio_usb]
68+
extends = ikoka_nrf52
69+
build_flags = ${ikoka_nrf52_ssd1306_companion.build_flags}
70+
-D LORA_TX_POWER=20
71+
build_src_filter = ${ikoka_nrf52_ssd1306_companion.build_src_filter}
72+
73+
[env:ikoka_handheld_nrf_e22_30dbm_096_rotated_companion_radio_usb]
74+
extends = ikoka_nrf52
75+
build_flags = ${ikoka_nrf52_ssd1306_companion.build_flags}
76+
-D LORA_TX_POWER=20
77+
-D DISPLAY_ROTATION=2
78+
build_src_filter = ${ikoka_nrf52_ssd1306_companion.build_src_filter}
79+
80+
[env:ikoka_handheld_nrf_e22_30dbm_repeater]
81+
extends = ikoka_nrf52
82+
build_flags =
83+
${ikoka_nrf52.build_flags}
84+
-D ADVERT_NAME='"ikoka_handheld Repeater"'
85+
-D ADVERT_LAT=0.0
86+
-D ADVERT_LON=0.0
87+
-D ADMIN_PASSWORD='"password"'
88+
-D MAX_NEIGHBOURS=50
89+
-D LORA_TX_POWER=20
90+
build_src_filter = ${ikoka_nrf52.build_src_filter}
91+
+<../examples/simple_repeater/*.cpp>
92+
93+
[env:ikoka_handheld_nrf_e22_30dbm_room_server]
94+
extends = ikoka_nrf52
95+
build_flags =
96+
${ikoka_nrf52.build_flags}
97+
-D ADVERT_NAME='"ikoka_handheld Room"'
98+
-D ADVERT_LAT=0.0
99+
-D ADVERT_LON=0.0
100+
-D ADMIN_PASSWORD='"password"'
101+
-D LORA_TX_POWER=20
102+
build_src_filter = ${ikoka_nrf52.build_src_filter}
103+
+<../examples/simple_room_server/*.cpp>
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#include <Arduino.h>
2+
#include "target.h"
3+
#include <helpers/ArduinoHelpers.h>
4+
5+
IkokaNrf52Board board;
6+
7+
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI);
8+
9+
WRAPPER_CLASS radio_driver(radio, board);
10+
11+
VolatileRTCClock fallback_clock;
12+
AutoDiscoverRTCClock rtc_clock(fallback_clock);
13+
14+
EnvironmentSensorManager sensors;
15+
16+
#ifdef DISPLAY_CLASS
17+
DISPLAY_CLASS display;
18+
MomentaryButton user_btn(PIN_USER_BTN, 1000, true, true);
19+
#endif
20+
21+
22+
bool radio_init() {
23+
rtc_clock.begin(Wire);
24+
25+
return radio.std_init(&SPI);
26+
}
27+
28+
uint32_t radio_get_rng_seed() {
29+
return radio.random(0x7FFFFFFF);
30+
}
31+
32+
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
33+
radio.setFrequency(freq);
34+
radio.setSpreadingFactor(sf);
35+
radio.setBandwidth(bw);
36+
radio.setCodingRate(cr);
37+
}
38+
39+
void radio_set_tx_power(uint8_t dbm) {
40+
radio.setOutputPower(dbm);
41+
}
42+
43+
mesh::LocalIdentity radio_new_identity() {
44+
RadioNoiseListener rng(radio);
45+
return mesh::LocalIdentity(&rng); // create new random identity
46+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#pragma once
2+
3+
#define RADIOLIB_STATIC_ONLY 1
4+
#include <RadioLib.h>
5+
#include <helpers/radiolib/RadioLibWrappers.h>
6+
#include <IkokaNrf52Board.h>
7+
#include <helpers/radiolib/CustomSX1262Wrapper.h>
8+
#include <helpers/AutoDiscoverRTCClock.h>
9+
#include <helpers/ArduinoHelpers.h>
10+
#include <helpers/sensors/EnvironmentSensorManager.h>
11+
12+
#ifdef DISPLAY_CLASS
13+
#include <helpers/ui/SSD1306Display.h>
14+
#include <helpers/ui/MomentaryButton.h>
15+
extern DISPLAY_CLASS display;
16+
extern MomentaryButton user_btn;
17+
#endif
18+
19+
20+
extern IkokaNrf52Board board;
21+
extern WRAPPER_CLASS radio_driver;
22+
extern AutoDiscoverRTCClock rtc_clock;
23+
extern EnvironmentSensorManager sensors;
24+
25+
bool radio_init();
26+
uint32_t radio_get_rng_seed();
27+
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
28+
void radio_set_tx_power(uint8_t dbm);
29+
mesh::LocalIdentity radio_new_identity();

0 commit comments

Comments
 (0)