Life is a struggle, and I've been struggling for the past few days with this project and many other things.
I've spent most of my free time with CNC path operations for a small boat plug that I'm building out of XPS foam layers at school, but thats another story.
With this project I've mostly had problems with passing/converting the serial output of the e5 mini 'gateway' to UDP packets that Chirpstack would understand.
Nevertheless, I've succeeded in forwarding messages with my own python script. I thought that I'm too cool for the legacy Semtech Packet Forwarder so I wrote my own. Well... it took me ages, I'm a bit rusty with my boat adventures and everything happening lately. First I wanted to test the packet forwarder functionality with netcat, but ran into encoding issues. Then I tried C and got lost. Finally python solved the problem, python is not my forte, but it just worked. Next I need to implement downlink functionality to my UDP socket python script.
import serial
import socket
serial_port = serial.Serial(port="/dev/ttyUSB0", baudrate=115200,
bytesize=8, timeout=2, stopbits=serial.STOPBITS_ONE)
remote = ("hush.super.secret", 1700)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
while (1):
if (serial_port.in_waiting > 0):
serial_buffer = serial_port.readline()
sock.sendto(serial_buffer, remote)
# data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
# print("received message: %s" % data)
Python packet forwarder
#include "STM32WL_LoRaRadio.h"
#include "events/EventQueue.h"
#include "jems.h"
#include "mbed.h"
#define MAX_LEVEL 10 // how deeply nested the JSON structures can get
static jems_level_t jems_levels[MAX_LEVEL];
static jems_t jems;
#define FREQUENCY 868000000
#define TX_POWER 22 // max should be 22 in lib
#define BANDWIDTH 0
#define PREAMBLE_LENGTH 8
#define DOWNLINK_MAX_LENGTH 51 // keep sf12 max until we settle on a better number
#define FREQ_HOP_ON 0
#define HOP_PERIOD 4
BufferedSerial router(USBTX, USBRX);
static STM32WL_LoRaRadio radio;
static EventQueue ev_queue(10 * EVENTS_EVENT_SIZE);
DigitalOut led1(LED1);
static void write_char(char ch, uintptr_t arg)
{
// fputc(ch, (FILE *)arg);
router.write(&ch, 1);
}
// Bytes | Function
// :------:|---------------------------------------------------------------------
// 0 | protocol version = 2
// 1-2 | random token
// 3 | PUSH_DATA identifier 0x00
// 4-11 | Gateway unique identifier (MAC address)
// 12-end | JSON object, starting with {, ending with }, see section 4
static void forward_packet(const uint8_t *payload, uint16_t size, int16_t rssi,
int8_t snr)
{
// char string_payload[(size << 1) + 1];
// for (size_t i = 0; i < size; i++)
// {
// sprintf(&string_payload[i * 2], "%02X", payload[i]);
// }
char gw_id[] = {0x02, 0xCF, 0x9A, 0x00, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB};
router.write(gw_id, 12);
jems_init(&jems, jems_levels, MAX_LEVEL, write_char, (uintptr_t)stdout);
jems_object_open(&jems);
jems_string(&jems, "rxpk");
jems_array_open(&jems);
jems_object_open(&jems);
// jems_string(&jems, "time");
// jems_string(&jems, "2022-02-15T22:17:00.000000Z");
// jems_string(&jems, "tmst");
// jems_number(&jems, 3512348611);
// jems_string(&jems, "chan");
// jems_number(&jems, 2);
// jems_string(&jems, "rfch");
// jems_number(&jems, 0);
jems_string(&jems, "freq");
jems_number(&jems, FREQUENCY);
jems_string(&jems, "stat");
jems_number(&jems, 1);
jems_string(&jems, "modu");
jems_string(&jems, "LORA");
jems_string(&jems, "datr");
jems_string(&jems, "SF9BW125");
jems_string(&jems, "codr");
jems_string(&jems, "4/5");
jems_string(&jems, "rssi");
jems_number(&jems, rssi);
jems_string(&jems, "lsnr");
jems_number(&jems, snr);
jems_string(&jems, "size");
jems_number(&jems, size);
jems_string(&jems, "data");
jems_string(&jems, "APtfAPB+1bNwjr3JaVJHXQAFUIADzW0=");
jems_object_close(&jems);
jems_array_close(&jems);
jems_object_close(&jems);
}
static void stat_message()
{
char gw_id[] = {0x02, 0xCF, 0x9A, 0x00, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB};
router.write(gw_id, 12);
jems_init(&jems, jems_levels, MAX_LEVEL, write_char, (uintptr_t)stdout);
jems_object_open(&jems);
jems_string(&jems, "stat");
jems_object_open(&jems);
// jems_string(&jems, "time");
// jems_string(&jems, "2023-02-16.18:51:48.GMT");
// jems_string(&jems, "rxnb");
// jems_number(&jems, 0);
// jems_string(&jems, "rxok");
// jems_number(&jems, 0);
// jems_string(&jems, "rxfw");
// jems_number(&jems, 0);
// jems_string(&jems, "ackr");
// jems_number(&jems, 0);
// jems_string(&jems, "dwnb");
// jems_number(&jems, 0);
// jems_string(&jems, "txnb");
// jems_number(&jems, 0);
jems_object_close(&jems);
jems_object_close(&jems);
}
static void cad_done(bool channel_busy)
{
ev_queue.call(debug, "cad_done in context %p\n", ThisThread::get_id());
}
static void fhss_change_channel(uint8_t current_channel)
{
ev_queue.call(debug, "fhss_done in context %p\n", ThisThread::get_id());
}
static void rx_done(const uint8_t *payload, uint16_t size, int16_t rssi,
int8_t snr)
{
ev_queue.call(forward_packet, payload, size, rssi, snr);
}
static void rx_error(void)
{
ev_queue.call(debug, "rx_error in context %p\n", ThisThread::get_id());
}
static void rx_timeout(void)
{
ev_queue.call(debug, "rx_timeout in context %p\n", ThisThread::get_id());
}
static void tx_done(void)
{
radio.receive();
ev_queue.call(debug, "tx_done in context %p, starting rx\n",
ThisThread::get_id());
}
static void tx_timeout(void)
{
ev_queue.call(debug, "tx_timeout in context %p\n", ThisThread::get_id());
}
static radio_events_t RadioEvents = {.cad_done = cad_done,
.fhss_change_channel = fhss_change_channel,
.rx_done = rx_done,
.rx_error = rx_error,
.rx_timeout = rx_timeout,
.tx_done = tx_done,
.tx_timeout = tx_timeout};
// static void onSerialReceived()
// {
// char buff;
// while (router.readable())
// {
// router.read(&buff, 1);
// router.write(&buff, 1);
// }
// }
// void onSigio(void)
// {
// ev_queue.call(onSerialReceived);
// }
int main()
{
led1 = 1;
radio.init_radio(&RadioEvents);
radio.set_channel(FREQUENCY);
radio.set_tx_config(MODEM_LORA, TX_POWER, 0, BANDWIDTH, LORA_SF9, LORA_CR_4_5,
PREAMBLE_LENGTH, LORA_PACKET_EXPLICIT, LORA_CRC_ON,
FREQ_HOP_ON, HOP_PERIOD, LORA_IQ_INVERTED, 0);
radio.set_rx_config(MODEM_LORA, BANDWIDTH, LORA_SF9, LORA_CR_4_5, 0,
PREAMBLE_LENGTH, 5, LORA_PACKET_EXPLICIT, 0, LORA_CRC_ON,
FREQ_HOP_ON, HOP_PERIOD, LORA_IQ_NORMAL, 1);
radio.set_public_network(true);
radio.set_max_payload_length(MODEM_LORA, DOWNLINK_MAX_LENGTH);
radio.receive();
// router.sigio(callback(onSigio));
ev_queue.call_every(30s, stat_message);
ev_queue.dispatch_forever();
}
Mbed code. Need to base64 encode the payload and do a bunch of other stuff, but progress is progress.
The pieces are there, just need to headbang my way through the never ending walls of challenges, that's how I roll.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.