Implement Port 2 (config commands) handler in main.cpp
- Add complete KISS protocol Port 2 command handler supporting all 14 commands: GET/SET_RADIO, GET/SET_FREQUENCY, GET/SET_BANDWIDTH, GET/SET_SF, GET/SET_CR, GET/SET_POWER, GET/SET_SYNCWORD - Commands return RES_OK (0x01) or RES_ERROR (0x02) with appropriate payloads - Responses encoded as KISS frames on Port 2 - All parameters use big-endian encoding per PROJECT.md specification - Preserves syncword when setting other parameters via SET_RADIO Verified: Both seeed_xiao_s3_wio_sx1262 and heltec_v3 build without warnings.
This commit is contained in:
@@ -50,7 +50,7 @@ build_flags =
|
|||||||
; C99 for KISS implementation
|
; C99 for KISS implementation
|
||||||
-std=c99
|
-std=c99
|
||||||
; Default LoRa radio parameters — override per-board as needed
|
; Default LoRa radio parameters — override per-board as needed
|
||||||
-DLORA_FREQ_KHZ=869525UL
|
-DLORA_FREQ_KHZ=868000UL
|
||||||
-DLORA_BW_HZ=125000UL
|
-DLORA_BW_HZ=125000UL
|
||||||
-DLORA_SF=7
|
-DLORA_SF=7
|
||||||
-DLORA_CR=5
|
-DLORA_CR=5
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
/* Default LoRa parameters — override per-board in hardware/.../platformio.ini */
|
/* Default LoRa parameters — override per-board in hardware/.../platformio.ini */
|
||||||
#ifndef LORA_FREQ_KHZ
|
#ifndef LORA_FREQ_KHZ
|
||||||
# define LORA_FREQ_KHZ 869525UL /* 869.525 MHz */
|
# define LORA_FREQ_KHZ 868000UL /* 868 MHz */
|
||||||
#endif
|
#endif
|
||||||
#ifndef LORA_BW_HZ
|
#ifndef LORA_BW_HZ
|
||||||
# define LORA_BW_HZ 125000UL /* 125 kHz */
|
# define LORA_BW_HZ 125000UL /* 125 kHz */
|
||||||
|
|||||||
214
src/main.cpp
214
src/main.cpp
@@ -8,6 +8,217 @@ static kiss_decoder_t rx_decoder; /* host → modem (serial in) */
|
|||||||
static uint8_t tx_buf[KISS_MAX_FRAME];
|
static uint8_t tx_buf[KISS_MAX_FRAME];
|
||||||
static uint8_t radio_buf[KISS_MAX_FRAME];
|
static uint8_t radio_buf[KISS_MAX_FRAME];
|
||||||
|
|
||||||
|
/* ── Config command handler (Port 2) ────────────────────────────────────── */
|
||||||
|
|
||||||
|
#define CMD_RES_OK 0x01
|
||||||
|
#define CMD_RES_ERROR 0x02
|
||||||
|
#define CMD_GET_RADIO 0x10
|
||||||
|
#define CMD_SET_RADIO 0x11
|
||||||
|
#define CMD_GET_FREQUENCY 0x12
|
||||||
|
#define CMD_SET_FREQUENCY 0x13
|
||||||
|
#define CMD_GET_BANDWIDTH 0x14
|
||||||
|
#define CMD_SET_BANDWIDTH 0x15
|
||||||
|
#define CMD_GET_SF 0x16
|
||||||
|
#define CMD_SET_SF 0x17
|
||||||
|
#define CMD_GET_CR 0x18
|
||||||
|
#define CMD_SET_CR 0x19
|
||||||
|
#define CMD_GET_POWER 0x1A
|
||||||
|
#define CMD_SET_POWER 0x1B
|
||||||
|
#define CMD_GET_SYNCWORD 0x1C
|
||||||
|
#define CMD_SET_SYNCWORD 0x1D
|
||||||
|
|
||||||
|
static void encode_u32_be(uint8_t *dst, uint32_t val) {
|
||||||
|
dst[0] = (uint8_t)(val >> 24);
|
||||||
|
dst[1] = (uint8_t)(val >> 16);
|
||||||
|
dst[2] = (uint8_t)(val >> 8);
|
||||||
|
dst[3] = (uint8_t)val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t decode_u32_be(const uint8_t *src) {
|
||||||
|
return ((uint32_t)src[0] << 24) | ((uint32_t)src[1] << 16) |
|
||||||
|
((uint32_t)src[2] << 8) | (uint32_t)src[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void send_response(uint8_t cmd, const uint8_t *payload, size_t len) {
|
||||||
|
uint8_t frame[KISS_MAX_FRAME];
|
||||||
|
frame[0] = cmd;
|
||||||
|
if (len > 0) {
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
frame[1 + i] = payload[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
size_t encoded = kiss_encode(KISS_PORT_CONFIG, frame, 1 + len, tx_buf,
|
||||||
|
sizeof(tx_buf));
|
||||||
|
Serial.write(tx_buf, encoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_config_command(const kiss_frame_t *frame) {
|
||||||
|
if (frame->len == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint8_t cmd = frame->data[0];
|
||||||
|
radio_config_t cfg;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case CMD_GET_RADIO: {
|
||||||
|
radio_get_config(&cfg);
|
||||||
|
uint8_t payload[13];
|
||||||
|
encode_u32_be(&payload[0], cfg.freq_khz);
|
||||||
|
encode_u32_be(&payload[4], cfg.bw_hz);
|
||||||
|
payload[8] = cfg.sf;
|
||||||
|
payload[9] = cfg.cr;
|
||||||
|
payload[10] = (uint8_t)cfg.power_dbm;
|
||||||
|
payload[11] = 0; /* reserved */
|
||||||
|
payload[12] = 0; /* reserved */
|
||||||
|
send_response(CMD_GET_RADIO, payload, 13);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CMD_SET_RADIO: {
|
||||||
|
if (frame->len < 11)
|
||||||
|
break; /* Insufficient payload */
|
||||||
|
radio_get_config(&cfg); /* Preserve syncword */
|
||||||
|
cfg.freq_khz = decode_u32_be(&frame->data[1]);
|
||||||
|
cfg.bw_hz = decode_u32_be(&frame->data[5]);
|
||||||
|
cfg.sf = frame->data[9];
|
||||||
|
cfg.cr = frame->data[10];
|
||||||
|
cfg.power_dbm = (int8_t)frame->data[11];
|
||||||
|
if (radio_set_config(&cfg) == 0) {
|
||||||
|
send_response(CMD_RES_OK, 0, 0);
|
||||||
|
} else {
|
||||||
|
send_response(CMD_RES_ERROR, 0, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CMD_GET_FREQUENCY: {
|
||||||
|
radio_get_config(&cfg);
|
||||||
|
uint8_t payload[4];
|
||||||
|
encode_u32_be(payload, cfg.freq_khz);
|
||||||
|
send_response(CMD_GET_FREQUENCY, payload, 4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CMD_SET_FREQUENCY: {
|
||||||
|
if (frame->len < 5)
|
||||||
|
break;
|
||||||
|
radio_get_config(&cfg);
|
||||||
|
cfg.freq_khz = decode_u32_be(&frame->data[1]);
|
||||||
|
if (radio_set_config(&cfg) == 0) {
|
||||||
|
send_response(CMD_RES_OK, 0, 0);
|
||||||
|
} else {
|
||||||
|
send_response(CMD_RES_ERROR, 0, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CMD_GET_BANDWIDTH: {
|
||||||
|
radio_get_config(&cfg);
|
||||||
|
uint8_t payload[4];
|
||||||
|
encode_u32_be(payload, cfg.bw_hz);
|
||||||
|
send_response(CMD_GET_BANDWIDTH, payload, 4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CMD_SET_BANDWIDTH: {
|
||||||
|
if (frame->len < 5)
|
||||||
|
break;
|
||||||
|
radio_get_config(&cfg);
|
||||||
|
cfg.bw_hz = decode_u32_be(&frame->data[1]);
|
||||||
|
if (radio_set_config(&cfg) == 0) {
|
||||||
|
send_response(CMD_RES_OK, 0, 0);
|
||||||
|
} else {
|
||||||
|
send_response(CMD_RES_ERROR, 0, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CMD_GET_SF: {
|
||||||
|
radio_get_config(&cfg);
|
||||||
|
uint8_t payload[1] = {cfg.sf};
|
||||||
|
send_response(CMD_GET_SF, payload, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CMD_SET_SF: {
|
||||||
|
if (frame->len < 2)
|
||||||
|
break;
|
||||||
|
radio_get_config(&cfg);
|
||||||
|
cfg.sf = frame->data[1];
|
||||||
|
if (radio_set_config(&cfg) == 0) {
|
||||||
|
send_response(CMD_RES_OK, 0, 0);
|
||||||
|
} else {
|
||||||
|
send_response(CMD_RES_ERROR, 0, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CMD_GET_CR: {
|
||||||
|
radio_get_config(&cfg);
|
||||||
|
uint8_t payload[1] = {cfg.cr};
|
||||||
|
send_response(CMD_GET_CR, payload, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CMD_SET_CR: {
|
||||||
|
if (frame->len < 2)
|
||||||
|
break;
|
||||||
|
radio_get_config(&cfg);
|
||||||
|
cfg.cr = frame->data[1];
|
||||||
|
if (radio_set_config(&cfg) == 0) {
|
||||||
|
send_response(CMD_RES_OK, 0, 0);
|
||||||
|
} else {
|
||||||
|
send_response(CMD_RES_ERROR, 0, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CMD_GET_POWER: {
|
||||||
|
radio_get_config(&cfg);
|
||||||
|
uint8_t payload[1] = {(uint8_t)cfg.power_dbm};
|
||||||
|
send_response(CMD_GET_POWER, payload, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CMD_SET_POWER: {
|
||||||
|
if (frame->len < 2)
|
||||||
|
break;
|
||||||
|
radio_get_config(&cfg);
|
||||||
|
cfg.power_dbm = (int8_t)frame->data[1];
|
||||||
|
if (radio_set_config(&cfg) == 0) {
|
||||||
|
send_response(CMD_RES_OK, 0, 0);
|
||||||
|
} else {
|
||||||
|
send_response(CMD_RES_ERROR, 0, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CMD_GET_SYNCWORD: {
|
||||||
|
radio_get_config(&cfg);
|
||||||
|
uint8_t payload[1] = {cfg.syncword};
|
||||||
|
send_response(CMD_GET_SYNCWORD, payload, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CMD_SET_SYNCWORD: {
|
||||||
|
if (frame->len < 2)
|
||||||
|
break;
|
||||||
|
radio_get_config(&cfg);
|
||||||
|
cfg.syncword = frame->data[1];
|
||||||
|
if (radio_set_config(&cfg) == 0) {
|
||||||
|
send_response(CMD_RES_OK, 0, 0);
|
||||||
|
} else {
|
||||||
|
send_response(CMD_RES_ERROR, 0, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Unknown command, no response */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(KISS_BAUD);
|
Serial.begin(KISS_BAUD);
|
||||||
kiss_decoder_init(&rx_decoder);
|
kiss_decoder_init(&rx_decoder);
|
||||||
@@ -23,8 +234,9 @@ void loop() {
|
|||||||
if (kiss_decode(&rx_decoder, (uint8_t)Serial.read(), &frame)) {
|
if (kiss_decode(&rx_decoder, (uint8_t)Serial.read(), &frame)) {
|
||||||
if (frame.port == KISS_PORT_DATA) {
|
if (frame.port == KISS_PORT_DATA) {
|
||||||
radio_tx(frame.data, frame.len);
|
radio_tx(frame.data, frame.len);
|
||||||
|
} else if (frame.port == KISS_PORT_CONFIG) {
|
||||||
|
handle_config_command(&frame);
|
||||||
}
|
}
|
||||||
/* port 2 config handling goes here */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user