Add ESP-IDF and STM32 C examples; document platform examples
Both compile the same portable core (src/meshcore_companion.c) and differ only in the UART transport: - examples-esp-idf/tty_bridge: full ESP-IDF project (UART driver), core compiled directly via the component CMakeLists (no copy) - examples-stm32/uart_bridge: HAL drop-in (meshcore_setup/meshcore_poll) for a CubeMX/CubeIDE project, with integration README README updated: new examples in layout + an 'Other platform examples' section. Verified host build/test still pass and both new examples pass -Wall -Wextra syntax checks against stubbed platform headers. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* main.c -- ESP-IDF example: drive a MeshCore Companion Radio over a UART.
|
||||
*
|
||||
* Same portable C99 core as every other example (src/meshcore_companion.{c,h}),
|
||||
* here with the ESP-IDF UART driver as the byte transport. Wire the companion
|
||||
* radio's serial lines to MC_UART_TX_PIN / MC_UART_RX_PIN and flash this onto an
|
||||
* ESP32 / ESP32-S3 / ESP32-C3 etc.
|
||||
*
|
||||
* idf.py set-target esp32s3
|
||||
* idf.py build flash monitor
|
||||
*
|
||||
* The companion radio must run the serial companion firmware (companion_radio_usb)
|
||||
* with its interface bound to this UART.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
* Author: Scott Penrose / Digital Dimensions.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "driver/uart.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "meshcore_companion.h"
|
||||
|
||||
/* --- UART wiring: change to free pins on your board --- */
|
||||
#define MC_UART_NUM UART_NUM_1
|
||||
#define MC_UART_TX_PIN 17 /* host TX -> companion RX */
|
||||
#define MC_UART_RX_PIN 16 /* host RX <- companion TX */
|
||||
#define MC_UART_BAUD 115200
|
||||
#define MC_UART_BUFSZ 1024
|
||||
|
||||
static const char *TAG = "meshcore";
|
||||
|
||||
static void send_payload(const uint8_t *payload, size_t len)
|
||||
{
|
||||
uint8_t frame[MC_RX_BUFSZ];
|
||||
size_t flen = mc_frame_encode(payload, len, frame, sizeof frame);
|
||||
if (flen) uart_write_bytes(MC_UART_NUM, (const char *)frame, flen);
|
||||
}
|
||||
|
||||
static void on_event(const mc_event_t *ev)
|
||||
{
|
||||
switch (ev->code) {
|
||||
case MC_RESP_DEVICE_INFO:
|
||||
ESP_LOGI(TAG, "radio model=%s fw=%d channels=%u build=%s",
|
||||
ev->u.device_info.model, ev->u.device_info.fw_ver,
|
||||
(unsigned)ev->u.device_info.max_channels,
|
||||
ev->u.device_info.build_date);
|
||||
break;
|
||||
case MC_RESP_CHANNEL_MSG_RECV: /* body is "SenderName: message" */
|
||||
ESP_LOGI(TAG, "[ch %d] %s", ev->u.channel_msg.channel_idx,
|
||||
ev->u.channel_msg.text);
|
||||
break;
|
||||
case MC_RESP_CHANNEL_DATA_RECV: {
|
||||
/* SNR is q4 (x4). Print exact dB without floating-point printf. */
|
||||
int centi = ev->u.channel_data.snr_q4 * 25; /* /4 then *100 */
|
||||
const char *sign = centi < 0 ? "-" : "";
|
||||
ESP_LOGI(TAG, "[ch %d] %u bytes type=0x%04X snr=%s%d.%02d dB %s",
|
||||
ev->u.channel_data.channel_idx,
|
||||
(unsigned)ev->u.channel_data.data_len,
|
||||
(unsigned)ev->u.channel_data.data_type,
|
||||
sign, abs(centi) / 100, abs(centi) % 100,
|
||||
ev->u.channel_data.path_len == MC_PATH_DIRECT ? "direct" : "flood");
|
||||
break;
|
||||
}
|
||||
case MC_RESP_CURR_TIME:
|
||||
ESP_LOGI(TAG, "device time = %u (epoch secs)", (unsigned)ev->u.curr_time);
|
||||
break;
|
||||
case MC_RESP_ERR:
|
||||
ESP_LOGW(TAG, "radio error response (code=%d)", ev->u.err_code);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
const uart_config_t cfg = {
|
||||
.baud_rate = MC_UART_BAUD,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
};
|
||||
ESP_ERROR_CHECK(uart_driver_install(MC_UART_NUM, MC_UART_BUFSZ, 0, 0, NULL, 0));
|
||||
ESP_ERROR_CHECK(uart_param_config(MC_UART_NUM, &cfg));
|
||||
ESP_ERROR_CHECK(uart_set_pin(MC_UART_NUM, MC_UART_TX_PIN, MC_UART_RX_PIN,
|
||||
UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||
|
||||
/* Handshake: AppStart -> SelfInfo, DeviceQuery -> DeviceInfo. */
|
||||
uint8_t cmd[MC_MAX_PAYLOAD];
|
||||
size_t n;
|
||||
n = mc_cmd_app_start(cmd, sizeof cmd, "esp-idf"); if (n) send_payload(cmd, n);
|
||||
n = mc_cmd_device_query(cmd, sizeof cmd, 1); if (n) send_payload(cmd, n);
|
||||
n = mc_cmd_get_device_time(cmd, sizeof cmd); if (n) send_payload(cmd, n);
|
||||
|
||||
mc_rx_t rx;
|
||||
mc_rx_init(&rx);
|
||||
ESP_LOGI(TAG, "listening on UART%d (rx=%d tx=%d)",
|
||||
MC_UART_NUM, MC_UART_RX_PIN, MC_UART_TX_PIN);
|
||||
|
||||
for (;;) {
|
||||
uint8_t in[128];
|
||||
int got = uart_read_bytes(MC_UART_NUM, in, sizeof in, pdMS_TO_TICKS(100));
|
||||
if (got <= 0) continue;
|
||||
|
||||
mc_rx_feed(&rx, in, (size_t)got);
|
||||
|
||||
uint8_t payload[MC_MAX_PAYLOAD];
|
||||
size_t plen;
|
||||
while (mc_rx_poll(&rx, payload, sizeof payload, &plen)) {
|
||||
mc_event_t ev;
|
||||
if (!mc_parse(payload, plen, &ev)) continue;
|
||||
on_event(&ev);
|
||||
/* Drain the radio's queue when it signals waiting messages. */
|
||||
if (ev.code == MC_PUSH_MSG_WAITING ||
|
||||
ev.code == MC_RESP_CHANNEL_MSG_RECV ||
|
||||
ev.code == MC_RESP_CHANNEL_DATA_RECV ||
|
||||
ev.code == MC_RESP_CONTACT_MSG_RECV) {
|
||||
n = mc_cmd_sync_next_message(cmd, sizeof cmd);
|
||||
if (n) send_payload(cmd, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user