Files
Embedded-Hacking/0x001aa_cb/src/lora.c
T

152 lines
5.0 KiB
C

// MIT License
//
// Copyright (c) 2026 Kevin Thomas
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// Author: Kevin Thomas
// Email: kevin@mytechnotalent.com
// GitHub: https://github.com/mytechnotalent
// File: lora.c
// Desc: Implements UART1 driver for REYAX RYLR998 LoRa transceiver.
// Created: 2026
#include "lora.h"
#include "hardware/gpio.h"
#include "pico/stdlib.h"
#include <stdio.h>
#include <string.h>
/**
* @brief Discard all pending bytes from the LoRa UART receive FIFO.
* @param void No parameters.
* @return void No return value.
*/
static void drain_lora_rx(void) {
while (uart_is_readable(LORA_UART)) {
(void)uart_getc(LORA_UART);
}
}
/**
* @brief Send an AT command to the radio and drain its response.
* @param cmd Null-terminated AT command string to transmit.
* @return void No return value.
*/
static void send_at_cmd(const char *cmd) {
uart_write_blocking(LORA_UART, (const uint8_t *)cmd, strlen(cmd));
sleep_ms(200);
drain_lora_rx();
}
/**
* @brief Program the RYLR998 RF parameters via the AT command set.
* @param void No parameters.
* @return void No return value.
*/
static void configure_lora_rf(void) {
sleep_ms(1500);
send_at_cmd("AT\r\n");
send_at_cmd("AT+NETWORKID=18\r\n");
send_at_cmd("AT+BAND=915000000\r\n");
send_at_cmd("AT+PARAMETER=9,7,1,12\r\n");
send_at_cmd("AT+ADDRESS=3\r\n");
}
void init_lora(void) {
uart_init(LORA_UART, LORA_BAUD);
uart_set_translate_crlf(LORA_UART, false);
gpio_set_function(LORA_TX_PIN, GPIO_FUNC_UART);
gpio_set_function(LORA_RX_PIN, GPIO_FUNC_UART);
configure_lora_rf();
}
void lora_send(const char *msg) {
char cmd[128];
int len = (int)strlen(msg);
snprintf(cmd, sizeof(cmd), "AT+SEND=0,%d,%s\r\n", len, msg);
uart_write_blocking(LORA_UART, (const uint8_t *)cmd, strlen(cmd));
}
/**
* @brief Extract the payload field from a +RCV receive line.
* @param line Mutable receive line buffer to parse.
* @param out Buffer receiving the extracted payload string.
* @param max_len Capacity of out in bytes.
* @return true when the payload was extracted, false otherwise.
*/
static bool extract_rcv_data(char *line, char *out, size_t max_len) {
char *c1 = strchr(line, ',');
if (!c1) return false;
char *c2 = strchr(c1 + 1, ',');
if (!c2) return false;
char *c3 = strchr(c2 + 1, ',');
if (c3) *c3 = '\0';
snprintf(out, max_len, "%s", c2 + 1);
return true;
}
/**
* @brief Parse one complete UART line and capture payload data.
* @param line Mutable line buffer to parse.
* @param out Buffer receiving the extracted payload string.
* @param max_len Capacity of out in bytes.
* @return true when the line carried payload data, false otherwise.
*/
static bool parse_line(char *line, char *out, size_t max_len) {
if (strstr(line, "+RCV="))
return extract_rcv_data(line, out, max_len);
if (strncmp(line, "+", 1) != 0 && strncmp(line, "OK", 2) != 0) {
snprintf(out, max_len, "%s", line);
return true;
}
return false;
}
/**
* @brief Feed one received byte into the line assembly state machine.
* @param c Received byte to process.
* @param buf Line assembly buffer.
* @param idx Pointer to the current write index into buf.
* @param out Buffer receiving the extracted payload string.
* @param max_len Capacity of out in bytes.
* @return true when a complete payload was produced, false otherwise.
*/
static bool process_rx_byte(char c, char *buf, size_t *idx, char *out, size_t max_len) {
if (c == '\r' || c == '\n') {
buf[*idx] = '\0';
bool ok = (*idx > 0) && parse_line(buf, out, max_len);
*idx = 0;
return ok;
}
if (*idx < 127) buf[(*idx)++] = c;
return false;
}
bool lora_poll_packet(char *payload_out, size_t max_len) {
static char buf[128];
static size_t idx = 0;
while (uart_is_readable(LORA_UART)) {
char c = (char)uart_getc(LORA_UART);
if (process_rx_byte(c, buf, &idx, payload_out, max_len))
return true;
}
return false;
}