// Copyright (C)2025, Philip Munts dba Munts Technologies.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
using System;
using static System.Environment;
using static IO.Bindings.libwioe5ham2;
namespace IO.Devices.WioE5.Ham2
{
///
/// Encapsulates the
///
/// Wio-E5 LoRa Transceiver Module in test aka P2P (Point to
/// Point or Peer to Peer) broadcast mode, adding Amateur Radio Unicast
/// Flavor #2 (Local Area Network with stations using different network
/// ID's aka call signs) address information.
///
///
/// See more information.
///
public class Device
{
private readonly int handle;
///
/// Constructor for a Wio-E5 LoRa Transceiver Module device object
/// instance.
///
/// Serial Port device name e.g.
/// "/dev/ttyAMA0" or "/dev/ttyUSB0" or "COM1".
///
/// Serial port data rate in bits per second
/// (9600, 19200, 38400, 57600, 115200, or 230400).
/// Network ID aka callsign, 10 ASCII
/// characters, left justified and automatically space padded
/// e.g. "WA7AAA" or "KL7/SA7AAA".
/// Node ID, ARCNET Style: 1 to 255.
/// RF center frequency in MHz, 902.0 to 928.0
/// (U.S.
/// Amateur Radio Allocation).
/// Spreading Factor, 7 to 12.
/// Bandwidth in kHz, 125, 250, or 500.
/// Number of transmit preamble bits.
/// Number of receive preamble bits.
/// Transmit power in dBm, -1 to 22.
public Device(string portname, int baudrate, string network,
int node, float freq, int spreading = 7, int bandwidth = 500,
int txpreamble = 12, int rxpreamble = 15, int power = 22)
{
wioe5ham2_init(portname, baudrate, network, node, freq,
spreading, bandwidth, txpreamble, rxpreamble, power,
out this.handle, out int error);
if (error != 0)
{
throw new Exception("wioe5ham2_init() failed, " +
errno.strerror(error));
}
}
///
/// Parameterless constructor for a Wio-E5 LoRa Transceiver Module
/// device object instance. Settings are obtained from environment
/// variables, some of which have default values.
///
///
/// This is mostly for
/// MuntsOS Embedded Linux targets with
/// configuration parameters defined in /etc/environment
/// using the following environment variables:
///
/// WIOE5_PORT
/// WIOE5_BAUD (Default: 115200)
/// WIOE5_NETWORK
/// WIOE5_NODE
/// WIOE5_FREQ
/// WIOE5_SPREADING (Default: 7)
/// WIOE5_BANDWIDTH (Default: 500)
/// WIOE5_TXPREAMBLE (Default: 12)
/// WIOE5_RXPREAMBLE (Default: 15)
/// WIOE5_TXPOWER (Default: 22)
///
public Device()
{
var port = GetEnvironmentVariable("WIOE5_PORT");
if (port == null)
{
throw new Exception("WIOE5_PORT environment variable is undefined");
}
var sbaudrate = GetEnvironmentVariable("WIOE5_BAUD");
if (sbaudrate == null)
{
sbaudrate = "115200";
}
if (!int.TryParse(sbaudrate, out int baudrate))
{
throw new Exception("WIOE5_PORT environment variable is invalid");
}
var network = GetEnvironmentVariable("WIOE5_NETWORK");
if (network == null)
{
throw new Exception("WIOE5_NETWORK environment variable is undefined");
}
var snode = GetEnvironmentVariable("WIOE5_NODE");
if (snode == null)
{
throw new Exception("WIOE5_NODE environment variable is undefined");
}
if (!int.TryParse(snode, out int node))
{
throw new Exception("WIOE5_NODE environment variable is undefined");
}
var sfreq = GetEnvironmentVariable("WIOE5_FREQ");
if (sfreq == null)
{
throw new Exception("WIOE5_FREQ environment variable is undefined");
}
if (!float.TryParse(sfreq, out float freq))
{
throw new Exception("WIOE5_FREQ environment variable is invalid");
}
var sspreading = GetEnvironmentVariable("WIOE5_SPREADING");
if (sspreading == null)
{
sspreading = "7";
}
if (!int.TryParse(sspreading, out int spreading))
{
throw new Exception("WIOE5_FREQ environment variable is invalid");
}
var sbandwidth = GetEnvironmentVariable("WIOE5_BANDWIDTH");
if (sbandwidth == null)
{
sbandwidth = "500";
}
if (!int.TryParse(sbandwidth, out int bandwidth))
{
throw new Exception("WIOE5_BANDWIDTH environment variable is invalid");
}
var stxpreamble = GetEnvironmentVariable("WIOE5_TXPREAMBLE");
if (stxpreamble == null)
{
stxpreamble = "12";
}
if (!int.TryParse(stxpreamble, out int txpreamble))
{
throw new Exception("WIOE5_TXPREAMBLE environment variable is invalid");
}
var srxpreamble = GetEnvironmentVariable("WIOE5_RXPREAMBLE");
if (srxpreamble == null)
{
srxpreamble = "15";
}
if (!int.TryParse(srxpreamble, out int rxpreamble))
{
throw new Exception("WIOE5_RXPREAMBLE environment variable is invalid");
}
var spower = GetEnvironmentVariable("WIOE5_POWER");
if (spower == null)
{
spower = "22";
}
if (!int.TryParse(spower, out int power))
{
throw new Exception("WIOE5_POWER environment variable is invalid");
}
wioe5ham2_init(port, baudrate, network, node, freq, spreading,
bandwidth, txpreamble, rxpreamble, power, out this.handle,
out int error);
if (error != 0)
{
throw new Exception("wioe5ham2_init() failed, " +
errno.strerror(error));
}
}
///
/// Finalizer for a Wio-E5 LoRa Transceiver Module device object
/// instance.
///
~Device()
{
wioe5ham2_exit(handle, out int error);
}
///
/// Send a text message.
///
/// Text message to send. Must be 1 to 241
/// characters.
/// Destination network ID.
/// Destination node ID (ARCNET style: 0=broadcast,
/// or 1 to 255).
public void Send(string s, string dstnet, int dstnode)
{
wioe5ham2_send_string(this.handle,
s, dstnet, dstnode, out int error);
if (error != 0)
{
throw new Exception("wioe5ham2_send_string() failed, " +
errno.strerror(error));
}
}
///
/// Send a binary message.
///
/// Binary message.
/// Message length in bytes, 1 to 241.
/// Destination network ID.
/// Destination node ID (ARCNET style: 0=broadcast,
/// or 1 to 255).
public void Send(byte[] msg, int len, string dstnet, int dstnode)
{
wioe5ham2_send(this.handle, msg, len, dstnet, dstnode, out int error);
if (error != 0)
{
throw new Exception("wioe5ham2_receive() failed, " +
errno.strerror(error));
}
}
///
/// Receive a binary message.
///
/// Binary message. Must be at least 241 bytes.
///
/// Number of bytes received.
/// Source network ID.
/// Source node ID (ARCNET style: 1 to 255).
/// Destination network ID.
/// Destination node ID (ARCNET style: 0=broadcast,
/// or 1 to 255).
/// Received Signal Strength in dBm.
/// Signal to Noise Ratio in dB.
public void Receive(byte[]msg, out int len, out string srcnet,
out int srcnode, out string dstnet, out int dstnode, out int RSS,
out int SNR)
{
var cdstnet = new char[11];
var csrcnet = new char[11];
wioe5ham2_receive(this.handle, msg, out len, csrcnet,
out srcnode, cdstnet, out dstnode, out RSS, out SNR,
out int error);
if (error != 0)
{
throw new Exception("wioe5ham2_receive() failed, " +
errno.strerror(error));
}
srcnet = new string(csrcnet).Trim(' ');
dstnet = new string(cdstnet).Trim(' ');
}
}
}