Skip to content
43 changes: 24 additions & 19 deletions docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -691,23 +691,28 @@ You can get the epoch time on <https://www.epochconverter.com> and use it to set
### 6.6. Q: My Heltec V3 keeps disconnecting from my smartphone. It can't hold a solid Bluetooth connection.
**A:** Heltec V3 has a very small coil antenna on its PCB for Wi-Fi and Bluetooth connectivity. It has a very short range, only a few feet. It is possible to remove the coil antenna and replace it with a 31mm wire. The BT range is much improved with the modification.

### 6.7. Q: My RAK/T1000-E/xiao_nRF52 device seems to be corrupted, how do I wipe it clean to start fresh?
**A:**

1. Connect USB-C cable to your device, per your device's instruction, get it to flash mode:
- For RAK, click the reset button **TWICE**
- For T1000-e, quickly disconnect and reconnect the magnetic side of the cable from the device **TWICE**
- For Heltec T114, click the reset button **TWICE** (the bottom button)
- For Xiao nRF52, click the reset button once. If that doesn't work, quickly double-click the reset button twice. If that doesn't work, disconnect the board from your PC and reconnect again ([seeed studio wiki](https://wiki.seeedstudio.com/XIAO_BLE/#access-the-swd-pins-for-debugging-and-reflashing-bootloader))
2. A new folder will appear on your computer's desktop
3. Download the `flash_erase*.uf2` file for your device on <https://flasher.meshcore.io>
- RAK WisBlock and Heltec T114: `Flash_erase-nRF32_softdevice_v6.uf2`
- Seeed Studio Xiao nRF52 WIO: `Flash_erase-nRF52_softdevice_v7.uf2`
4. drag and drop the uf2 file for your device to the root of the new folder
5. Wait for the copy to complete. You might get an error dialog, you can ignore it
6. Go to <https://flasher.meshcore.io>, click `Console` and select the serial port for your connected device
7. In the console, press enter. Your flash should now be erased
8. You may now flash the latest MeshCore firmware onto your device
### 6.7. Q: My RAK/T1000-E/xiao_nRF52/... device seems to be corrupted, how do I wipe it clean to start fresh?
**A: If you're able to connect to the device from your MeshCore app**
1. Navigate to Gear icon(Settings) on the upper right corner
2. Click on `Export Settings` button, choose `Select All` and Confirm. This will save your Node configuration
3. Now choose `Factory Reset` option
4. Confirm that you want to reset your device
5. Go to Bluetooth System settings and remove pairing of the device, so you can connect again
6. Connect your device in the app and enter the PIN
7. Navigate to Gear icon(Settings) on the upper right corner
8. Click on `Import Settings` and choose the file from 2., click on `Select All` and Confirm
9. Find `Reboot` button on of the Settings list

**B: You're not able to connect to the App**
1. Connect USB cable to your device
2. Go to https://flasher.meshcore.io
3. Search for your device in the list
4. Choose `Companion Bluetooth`
5. Press `Enter DFU mode` button, choose your USB device
6. Press `Erase Flash` button, choose the device again and wait until it completes
7. Press `Flash!` button and choose the USB device last time
8. The device is erased and newest firmware is installed
9. You might need to remove the pairing in Bluetooth System Settings in order to re-pair the app again.

Separately, starting in firmware version 1.7.0, there is a CLI Rescue mode. If your device has a user button (e.g. some RAK, T114), you can activate the rescue mode by holding down the user button of the device within 8 seconds of boot. Then you can use the 'Console' on <https://flasher.meshcore.io>

Expand All @@ -716,9 +721,9 @@ Separately, starting in firmware version 1.7.0, there is a CLI Rescue mode. If y

`NetworkError: Failed to execute 'open' on 'SerialPort': Failed to open serial port.`

Allow the browser user on it:
Allow user access on your USB port:

`# setfacl -m u:YOUR_USER_HERE:rw /dev/ttyUSB0`
`sudo setfacl -m u:$USER:rw /dev/ttyUSB0`

---

Expand Down
16 changes: 8 additions & 8 deletions docs/kiss_modem_protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ Standard KISS framing per the KA9Q/K3MC specification.
| `0xDD` | TFESC | Escaped FESC (FESC + TFESC = 0xDB) |

```
┌──────┬───────────┬──────────────┬──────┐
│ FEND │ Type Byte │ Data (escaped)│ FEND │
│ 0xC0 │ 1 byte │ 0-510 bytes │ 0xC0 │
└──────┴───────────┴──────────────┴──────┘
┌──────┬───────────┬────────────────┬──────┐
│ FEND │ Type Byte │ Data (escaped) │ FEND │
│ 0xC0 │ 1 byte │ 0-510 bytes │ 0xC0 │
└──────┴───────────┴────────────────┴──────┘
```

### Type Byte
Expand Down Expand Up @@ -82,10 +82,10 @@ MeshCore-specific functionality uses the standard KISS SetHardware command. The
### Frame Format

```
┌──────┬──────┬─────────────┬──────────────┬──────┐
│ FEND │ 0x06 │ Sub-command │ Data (escaped)│ FEND │
│ 0xC0 │ │ 1 byte │ variable │ 0xC0 │
└──────┴──────┴─────────────┴──────────────┴──────┘
┌──────┬──────┬─────────────┬────────────────┬──────┐
│ FEND │ 0x06 │ Sub-command │ Data (escaped) │ FEND │
│ 0xC0 │ │ 1 byte │ variable │ 0xC0 │
└──────┴──────┴─────────────┴────────────────┴──────┘
```

### Request Sub-commands (Host to TNC)
Expand Down
66 changes: 66 additions & 0 deletions docs/radio_presets.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Radio Presets

The radio presets are currently stored on the MeshCore App API server.

This allows us to update the presets without releasing new application updates.

The presets can be fetched from [https://api.meshcore.nz/api/v1/config](https://api.meshcore.nz/api/v1/config)

If you'd like a new radio preset to be added, this will need to be brought up for discussion in the [MeshCore Discord](https://meshcore.gg) server, or via the [issues section](https://github.com/meshcore-dev/MeshCore/issues) in our GitHub repo.

Before a new preset will be considered for being added, local radio regulations must be researched by the person suggesting the preset, and investigation of the frequencies with an SDR is advised to ensure the least interference to provide a decent user experience.

Once a preset is added, it's unlikely to be changed. Adding too many presets can lead to user frustration, as new users won't know which preset to select during setup.

At this time, presets provided by the MeshCore App API are just suggestions, but you are free to configure any radio settings through the companion applications, provided they comply with local laws/regulations.

> Note: We are planning to implement deep linking such as meshcore:// URLs, and QR codes so local mesh networks can easily distribute their own settings, without relying on the internet, or all the companion applications to provide all the settings.

## JSON Response

See the example JSON response below, which shows the expected format provided by the API server.

Your application should be programmed to expect any of the JSON keys to be missing from the response, as the format could change at any time without any notification.

Please configure an appropriate User Agent header string when sending your request to the server. We should be able to reach out to you if needed.

> Note: Some presets contain an optional `network_settings` section which defines the `path_hash_size` to use for this mesh network.

```json
{
"config": {
"suggested_radio_settings": {
"info_message": "These presets are suggested by the community.",
"entries": [
{
"title": "Australia (Narrow)",
"description": "916.575MHz / SF7 / BW62.5 / CR7",
"frequency": "916.575",
"spreading_factor": "7",
"bandwidth": "62.5",
"coding_rate": "7"
},
{
"title": "New Zealand (Narrow)",
"description": "917.375MHz / SF7 / BW62.5 / CR5 / 2B",
"frequency": "917.375",
"spreading_factor": "7",
"bandwidth": "62.5",
"coding_rate": "5",
"network_settings": {
"path_hash_size": 2
}
},
{
"title": "Portugal 868",
"description": "869.618MHz / SF7 / BW62.5 / CR6",
"frequency": "869.618",
"spreading_factor": "7",
"bandwidth": "62.5",
"coding_rate": "6"
}
]
}
}
}
```
2 changes: 2 additions & 0 deletions examples/companion_radio/AbstractUITask.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,6 @@ class AbstractUITask : public MyMesh::Listener {

virtual void notify(UIEventType t = UIEventType::none) = 0;
virtual void loop() = 0;
virtual bool applyTheme(const char* theme) { return false; }
virtual int getThemeCount() { return 0; }
};
17 changes: 17 additions & 0 deletions examples/companion_radio/MyMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2129,6 +2129,23 @@ bool MyMesh::handleCommand(const char* command, uint32_t sender_timestamp, char*
return true;
}

if (strncmp(command, "set theme ", 10) == 0) {
const char* theme = &command[10];
if (_ui != NULL && _ui->getThemeCount() > 0) {
if (_ui->applyTheme(theme)) {
strncpy(_prefs.ui_theme, theme, sizeof(_prefs.ui_theme) - 1);
_prefs.ui_theme[sizeof(_prefs.ui_theme) - 1] = 0;
savePrefs();
sprintf(reply, "> theme is now %s", _prefs.ui_theme);
} else {
strcpy(reply, "Error: theme not found or not supported by this display");
}
} else {
strcpy(reply, "Error: this device has no theme-capable display");
}
return true;
}

#ifdef ENABLE_WIFI_INTERFACE
if (memcmp(command, "set wifi.ssid ", 14) == 0) {
StrHelper::strncpy(_prefs.wifi_ssid, &command[14], sizeof(_prefs.wifi_ssid));
Expand Down
3 changes: 3 additions & 0 deletions examples/companion_radio/NodePrefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class NodePrefs : public ConfigSerializer { // persisted to file
uint8_t _client_repeat = 0; // DEPRECATED -> use repeat.disable_fwd
uint8_t path_hash_mode = 0; // which path mode to use when sending
uint8_t autoadd_max_hops = 0; // 0 = no limit, 1 = direct (0 hops), N = up to N-1 hops (max 64)
char ui_theme[16]; // UI theme, if supported by the display driver, e.g. "default" (light), "legacy" (dark)
uint8_t cad_enabled = 0;
uint8_t interference_threshold = 0;
uint8_t agc_reset_interval = 0; // secs / 4
Expand Down Expand Up @@ -165,6 +166,7 @@ class NodePrefs : public ConfigSerializer { // persisted to file
def("tel_base", _parent->telemetry_mode_base);
def("tel_loc", _parent->telemetry_mode_loc);
def("tel_env", _parent->telemetry_mode_env);
def("theme", _parent->ui_theme, sizeof(_parent->ui_theme));
def("tz_offset", _parent->tz_offset);
}
public:
Expand Down Expand Up @@ -214,6 +216,7 @@ class NodePrefs : public ConfigSerializer { // persisted to file
node_name[0] = 0;
default_scope_name[0] = 0;
memset(default_scope_key, 0, sizeof(default_scope_key));
strcpy(ui_theme, "default");
}
// new accessor methods
bool isRepeatEn() const { return repeat.disable_fwd == 0; }
Expand Down
9 changes: 9 additions & 0 deletions examples/companion_radio/ui-new/UITask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,7 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no
_node_prefs = node_prefs;

if (_display != NULL) {
_display->applyTheme(_node_prefs->ui_theme);
_display->turnOn();
}

Expand All @@ -759,6 +760,14 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no
setCurrScreen(splash);
}

bool UITask::applyTheme(const char* theme) {
return _display != NULL ? _display->applyTheme(theme) : false;
}

int UITask::getThemeCount() {
return _display != NULL ? _display->getThemeCount() : 0;
}

void UITask::showAlert(const char* text, int duration_millis) {
strcpy(_alert, text);
_alert_expiry = millis() + duration_millis;
Expand Down
2 changes: 2 additions & 0 deletions examples/companion_radio/ui-new/UITask.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ class UITask : public AbstractUITask {
// from AbstractUITask
void notify(UIEventType t = UIEventType::none) override;
void loop() override;
bool applyTheme(const char* theme) override;
int getThemeCount() override;

void shutdown(bool restart = false);
};
2 changes: 2 additions & 0 deletions src/helpers/ui/DisplayDriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class DisplayDriver {
virtual void startFrame(ColorVal bkg = UIColor::window_bkg) = 0;
virtual void setTextSize(int sz) = 0;
virtual void setColor(ColorVal c) = 0;
virtual bool applyTheme(const char* theme) { return false; }
virtual int getThemeCount() { return 0; }
virtual void setCursor(int x, int y) = 0;
virtual void print(const char* str) = 0;
virtual void printWordWrap(const char* str, int max_width) { print(str); } // fallback to basic print() if no override
Expand Down
27 changes: 27 additions & 0 deletions src/helpers/ui/LGFXDisplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,33 @@ ColorVal UIColor::popup_bkg = 0x07FF; // CYAN
ColorVal UIColor::popup_txt = 0x0000;
ColorVal UIColor::corp_blue = 0x001A;

bool LGFXDisplay::applyTheme(const char* theme) {
if (strcmp(theme, "legacy") == 0) {
UIColor::window_bkg = 0x0000;
UIColor::title_bkg = 0x0000;
UIColor::title_txt = 0x07E0;
UIColor::primary_txt = 0x07E0;
UIColor::secondary_txt = 0xFFE0;
UIColor::warning_txt = 0xF800;
UIColor::popup_bkg = 0x0000;
UIColor::popup_txt = 0xFFFF;
UIColor::corp_blue = 0x001F;
return true;
} else if (strcmp(theme, "default") == 0) {
UIColor::window_bkg = 0xFFFF;
UIColor::title_bkg = 0x001F;
UIColor::title_txt = 0xFFFF;
UIColor::primary_txt = 0x0000;
UIColor::secondary_txt = (18 << 11) | (36 << 5) | 18;
UIColor::warning_txt = 0xFD20;
UIColor::popup_bkg = 0x07FF;
UIColor::popup_txt = 0x0000;
UIColor::corp_blue = 0x001A;
return true;
}
return false;
}

bool LGFXDisplay::begin() {
turnOn();
display->init();
Expand Down
2 changes: 2 additions & 0 deletions src/helpers/ui/LGFXDisplay.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,7 @@ class LGFXDisplay : public DisplayDriver {
void drawXbm(int x, int y, const uint8_t* bits, int w, int h) override;
uint16_t getTextWidth(const char* str) override;
void endFrame() override;
bool applyTheme(const char* theme) override;
int getThemeCount() override { return 2; }
virtual bool getTouch(int *x, int *y);
};
27 changes: 27 additions & 0 deletions src/helpers/ui/NV3001BDisplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,33 @@ ColorVal UIColor::popup_bkg = 0x07FF; // CYAN
ColorVal UIColor::popup_txt = 0x0000;
ColorVal UIColor::corp_blue = 0x001A;

bool NV3001BDisplay::applyTheme(const char* theme) {
if (strcmp(theme, "legacy") == 0) {
UIColor::window_bkg = 0x0000;
UIColor::title_bkg = 0x0000;
UIColor::title_txt = 0x07E0;
UIColor::primary_txt = 0x07E0;
UIColor::secondary_txt = 0xFFE0;
UIColor::warning_txt = 0xF800;
UIColor::popup_bkg = 0x0000;
UIColor::popup_txt = 0xFFFF;
UIColor::corp_blue = 0x001F;
return true;
} else if (strcmp(theme, "default") == 0) {
UIColor::window_bkg = 0xFFFF;
UIColor::title_bkg = 0x001F;
UIColor::title_txt = 0xFFFF;
UIColor::primary_txt = 0x0000;
UIColor::secondary_txt = (18 << 11) | (36 << 5) | 18;
UIColor::warning_txt = 0xFD20;
UIColor::popup_bkg = 0x07FF;
UIColor::popup_txt = 0x0000;
UIColor::corp_blue = 0x001A;
return true;
}
return false;
}

static int scaleX(int x) {
return (int)(x * DISPLAY_SCALE_X);
}
Expand Down
2 changes: 2 additions & 0 deletions src/helpers/ui/NV3001BDisplay.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,6 @@ class NV3001BDisplay : public DisplayDriver {
void drawXbm(int x, int y, const uint8_t* bits, int w, int h) override;
uint16_t getTextWidth(const char* str) override;
void endFrame() override;
bool applyTheme(const char* theme) override;
int getThemeCount() override { return 2; }
};
27 changes: 27 additions & 0 deletions src/helpers/ui/ST7735Display.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,33 @@ ColorVal UIColor::popup_bkg = ST77XX_CYAN;
ColorVal UIColor::popup_txt = ST77XX_BLACK;
ColorVal UIColor::corp_blue = 0x001A;

bool ST7735Display::applyTheme(const char* theme) {
if (strcmp(theme, "legacy") == 0) {
UIColor::window_bkg = ST77XX_BLACK;
UIColor::title_bkg = ST77XX_BLACK;
UIColor::title_txt = ST77XX_GREEN;
UIColor::primary_txt = ST77XX_GREEN;
UIColor::secondary_txt = ST77XX_YELLOW;
UIColor::warning_txt = ST77XX_RED;
UIColor::popup_bkg = ST77XX_BLACK;
UIColor::popup_txt = ST77XX_WHITE;
UIColor::corp_blue = ST77XX_BLUE;
return true;
} else if (strcmp(theme, "default") == 0) {
UIColor::window_bkg = ST77XX_WHITE;
UIColor::title_bkg = ST77XX_BLUE;
UIColor::title_txt = ST77XX_WHITE;
UIColor::primary_txt = ST77XX_BLACK;
UIColor::secondary_txt = (18 << 11) | (36 << 5) | 18;
UIColor::warning_txt = ST77XX_ORANGE;
UIColor::popup_bkg = ST77XX_CYAN;
UIColor::popup_txt = ST77XX_BLACK;
UIColor::corp_blue = 0x001A;
return true;
}
return false;
}

bool ST7735Display::begin() {
if (!sprite) {
// alloc offscreen canvas
Expand Down
2 changes: 2 additions & 0 deletions src/helpers/ui/ST7735Display.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ class ST7735Display : public DisplayDriver {
void drawXbm(int x, int y, const uint8_t* bits, int w, int h) override;
uint16_t getTextWidth(const char* str) override;
void endFrame() override;
bool applyTheme(const char* theme) override;
int getThemeCount() override { return 2; }

protected:
void _resetAndInit();
Expand Down
Loading