2024-09-14 11:42:27 +00:00
#!/usr/bin/env python
#
# Radio Wrappers for Wenet Transmissions
#
# Copyright (C) 2024 Mark Jessop <vk5qi@rfhead.net>
# Released under GNU GPL v3 or later
#
# For RFM98W support, requires pySX127x:
# https://github.com/darksidelemm/pySX127x
# (This is included with the Wenet repository)
#
# Uses spidev for comms with a RFM98W module.
#
# Note: As with the RFM22B version, all this script does
# is get the RFM98W onto the right frequency, and into the right mode.
#
# SPI: Connected to CE0 (like most of my LoRa shields)
# RPi TXD: Connected to RFM98W's DIO2 pin.
#
import sys
import argparse
import logging
import serial
import time
import numpy as np
2025-03-25 10:29:36 +00:00
try :
import alsaaudio
except :
logging . warning ( " No alsaaudio - i2s support disabled " )
# Allow for testing without a radio
try :
from SX127x . LoRa import *
from SX127x . hardware_piloragateway import HardwareInterface
except :
HardwareInterface = None
logging . error ( " Could not load SX127x. modules " )
2024-09-14 11:42:27 +00:00
2025-03-25 10:59:16 +00:00
class RFM98W ( object ) :
2024-09-14 11:42:27 +00:00
"""
2025-03-25 10:59:16 +00:00
RFM98W Wrapper for Wenet Transmission , using 2 - FSK Direct - Asynchronous Modulation
"""
2024-09-14 11:42:27 +00:00
def __init__ (
self ,
spidevice = 0 ,
frequency = 443.500 ,
baudrate = 115200 ,
tx_power_dbm = 17 ,
2025-03-25 10:59:16 +00:00
reinit_count = 5000 ,
led = None
2024-09-14 11:42:27 +00:00
) :
self . spidevice = spidevice
self . frequency = frequency
self . baudrate = baudrate
self . tx_power_dbm = tx_power_dbm
self . reinit_count = reinit_count
self . hw = None
self . lora = None
self . tx_packet_count = 0
2024-09-22 03:07:10 +00:00
self . temperature = - 999
2025-03-25 10:59:16 +00:00
self . led = led
2024-09-14 11:42:27 +00:00
def start ( self ) :
"""
Initialise ( or re - initialise ) both the RFM98W and Serial connections .
Configure the RFM98W into direct asynchronous FSK mode , with the appropriate power , deviation , and transmit frequency .
"""
2024-10-06 22:51:46 +00:00
# Cleanup any open file handlers.
if self . hw :
self . hw . teardown ( )
2025-03-25 10:59:16 +00:00
if self . led :
self . hw = HardwareInterface ( self . spidevice , LED = self . led )
else :
self . hw = HardwareInterface ( self . spidevice )
2024-09-14 11:42:27 +00:00
self . lora = LoRaRFM98W ( self . hw , verbose = False )
logging . debug ( f " RFM98W - SX127x Register Dump: { self . lora . backup_registers } " )
logging . debug ( f " RFM98W - SX127x device version: { hex ( self . lora . get_version ( ) ) } " )
if not self . comms_ok ( ) :
logging . critical ( " RFM98W - No communication with RFM98W IC! " )
self . shutdown ( )
return
# Deviation selection.
if self . baudrate == 9600 :
deviation = 4800
elif self . baudrate == 4800 :
deviation = 2400
2025-07-07 04:07:42 +00:00
elif self . baudrate in [ 115177 , 115200 ] :
2024-09-14 11:42:27 +00:00
# Default deviation, for 115200 baud
2025-07-07 04:07:42 +00:00
# The origin of this number is unknown
2024-09-14 11:42:27 +00:00
deviation = 71797
2025-07-07 04:07:42 +00:00
else :
deviation = self . baudrate / / 2
2024-09-14 11:42:27 +00:00
# Refer https://cdn.sparkfun.com/assets/learn_tutorials/8/0/4/RFM95_96_97_98W.pdf
self . lora . set_register ( 0x01 , 0x00 ) # FSK Sleep Mode
self . lora . set_register ( 0x31 , 0x00 ) # Set Continuous Transmit Mode
2024-09-22 03:07:10 +00:00
# Get the IC temperature
2024-09-27 06:35:39 +00:00
self . get_temperature ( )
2024-09-22 03:07:10 +00:00
2024-09-14 11:42:27 +00:00
self . lora . set_freq ( self . frequency )
logging . info ( f " RFM98W - Frequency set to: { self . frequency } MHz. " )
# Set Deviation (~70 kHz). Signals ends up looking a bit wider than the RFM22B version.
_dev_lsbs = int ( deviation / 61.03 )
_dev_msb = _dev_lsbs >> 8
_dev_lsb = _dev_lsbs % 256
self . lora . set_register ( 0x04 , _dev_msb )
self . lora . set_register ( 0x05 , _dev_lsb )
# Set Transmit power
tx_power_lookup = { 0 : 0x80 , 1 : 0x80 , 2 : 0x80 , 3 : 0x81 , 4 : 0x82 , 5 : 0x83 , 6 : 0x84 , 7 : 0x85 , 8 : 0x86 , 9 : 0x87 , 10 : 0x88 , 11 : 0x89 , 12 : 0x8A , 13 : 0x8B , 14 : 0x8C , 15 : 0x8D , 16 : 0x8E , 17 : 0x8F }
if self . tx_power_dbm in tx_power_lookup :
self . lora . set_register ( 0x09 , tx_power_lookup [ self . tx_power_dbm ] )
logging . info ( f " RFM98W - TX Power set to { self . tx_power_dbm } dBm ( { hex ( tx_power_lookup [ self . tx_power_dbm ] ) } ). " )
else :
# Default to low power, 1.5mW or so
self . lora . set_register ( 0x09 , 0x80 )
logging . info ( f " RFM98W - Unknown TX power, setting to 2 dBm (0x80). " )
# Go into TX mode.
self . lora . set_register ( 0x01 , 0x02 ) # .. via FSTX mode (where the transmit frequency actually gets set)
self . lora . set_register ( 0x01 , 0x03 ) # Now we're in TX mode...
# Seems we need to briefly sleep before we can read the register correctly.
time . sleep ( 0.1 )
# Confirm we've gone into transmit mode.
if self . lora . get_register ( 0x01 ) == 0x03 :
logging . info ( " RFM98W - Radio initialised! " )
else :
logging . critical ( " RFM98W - TX Mode not set correctly! " )
2025-07-06 12:07:06 +00:00
def scramble ( self , data ) :
return data
2024-09-14 11:42:27 +00:00
def shutdown ( self ) :
"""
Shutdown the RFM98W , and close the SPI and Serial connections .
"""
try :
# Set radio into FSK sleep mode
self . lora . set_register ( 0x01 , 0x00 )
logging . info ( " RFM98W - Set radio into sleep mode. " )
self . lora = None
except :
pass
try :
# Shutdown SPI device
self . hw . teardown ( )
logging . info ( " RFM98W - Disconnected from SPI. " )
self . hw = None
except :
pass
return
def comms_ok ( self ) :
"""
Test SPI communications with the RFM98W and return true if ok .
"""
try :
_ver = self . lora . get_version ( )
if _ver == 0x00 or _ver == 0xFF or _ver == None :
return False
else :
return True
except Exception as e :
logging . critical ( " RFM98W - Could not read device version! " )
return False
return False
def transmit_packet ( self , packet ) :
# Increment transmit packet counter
self . tx_packet_count + = 1
# If we have a reinitialisation count set, reinitialise the radio.
if self . reinit_count :
if self . tx_packet_count % self . reinit_count == 0 :
logging . info ( f " RFM98W - Reinitialising Radio at { self . tx_packet_count } packets. " )
self . start ( )
2024-09-22 03:07:10 +00:00
def get_temperature ( self ) :
"""
Get radio module temperature ( uncalibrated )
"""
# Make temperature measurement
2024-09-27 06:35:39 +00:00
self . temperature = self . lora . get_register ( 0x3c ) * ( - 1 )
if self . temperature < - 63 :
self . temperature + = 255
2024-09-22 03:07:10 +00:00
logging . info ( f " RFM98W - Temperature: { self . temperature } C " )
2024-09-27 06:35:39 +00:00
return self . temperature
2024-09-14 11:42:27 +00:00
2025-03-25 10:59:16 +00:00
class RFM98W_Serial ( RFM98W ) :
2025-03-25 10:29:36 +00:00
"""
2025-03-25 10:59:16 +00:00
RFM98W Wrapper for Wenet Transmission , using 2 - FSK Direct - Asynchronous Modulation via a UART .
2025-03-25 10:29:36 +00:00
"""
def __init__ (
self ,
spidevice = 0 ,
frequency = 443.500 ,
2025-03-25 10:59:16 +00:00
baudrate = 115200 ,
serial_port = None ,
2025-03-25 10:29:36 +00:00
tx_power_dbm = 17 ,
reinit_count = 5000
) :
2025-03-25 10:59:16 +00:00
self . serial_port = serial_port
2025-07-09 11:22:55 +00:00
super ( ) . __init__ ( spidevice , frequency , baudrate , tx_power_dbm , reinit_count , led = 5 )
2025-03-25 10:59:16 +00:00
self . start ( )
def start ( self ) :
"""
Initialise ( or re - initialise ) both the RFM98W and Serial connections .
Configure the RFM98W into direct asynchronous FSK mode , with the appropriate power , deviation , and transmit frequency .
"""
super ( ) . start ( )
# Now initialise the Serial port for modulation
if self . serial_port :
try :
self . serial = serial . Serial ( self . serial_port , self . baudrate )
logging . info ( f " RFM98W - Opened Serial port { self . serial_port } for modulation. " )
except Exception as e :
logging . critical ( f " Could not open serial port! Error: { str ( e ) } " )
self . serial = None
else :
# If no serial port info provided, write out to a binary debug file.
self . serial = BinaryDebug ( )
logging . info ( " No serial port provided - using Binary Debug output (binary_debug.bin) " )
2025-03-25 10:29:36 +00:00
2025-03-25 10:59:16 +00:00
def shutdown ( self ) :
"""
Shutdown the RFM98W , and close the SPI and Serial connections .
"""
super ( ) . shutdown ( )
try :
# Close the serial connection
self . serial . close ( )
logging . info ( " RFM98W - Closed Serial Port " )
self . serial = None
except :
pass
return
def transmit_packet ( self , packet ) :
"""
Modulate serial data , using a UART .
"""
if self . serial :
self . serial . write ( packet )
super ( ) . transmit_packet ( packet ) # used to reinit the radio occasionally
class RFM98W_I2S ( RFM98W ) :
"""
RFM98W Wrapper for Wenet Transmission , using 2 - FSK Direct - Asynchronous Modulation via a I2S .
"""
def __init__ (
self ,
spidevice = 0 ,
2025-03-25 11:39:20 +00:00
baudrate = 96000 ,
2025-03-25 10:59:16 +00:00
frequency = 443.500 ,
audio_device = " hw:CARD=i2smaster,DEV=0 " ,
tx_power_dbm = 17 ,
reinit_count = 5000
) :
2025-03-25 11:39:20 +00:00
2025-03-25 10:29:36 +00:00
self . audio_width = 2 # bytes
self . audio_rate = 48000
2025-03-25 11:39:20 +00:00
self . channels = 2
audio_rates = [ 8000 , 16000 , 22050 , 44100 , 48000 , 96000 , 176400 , 192000 ]
2025-03-25 12:47:30 +00:00
logging . debug ( f " Searching for best audio sample rate for { baudrate } " )
# This is a naive approach and there are totally more options avaliable to us than this.
# We also aren't strictly limited to just whole bytes for sretching the time, however that's easiest.
2025-03-25 11:39:20 +00:00
for self . audio_rate in audio_rates :
self . audio_bit_rate = self . audio_rate * self . channels * ( self . audio_width * 8 )
self . bytes_per_bit = self . audio_bit_rate / / baudrate / / 8
try :
actual_rf_bitrate = self . audio_bit_rate / ( self . bytes_per_bit * 8 )
except ZeroDivisionError :
logging . debug ( f " NO - { self . audio_rate } " )
continue
if ( self . audio_bit_rate / baudrate ) % 8 != 0 :
logging . debug ( f " NO - { self . audio_rate } RF bitrate = { actual_rf_bitrate } " )
else :
2025-03-25 12:47:30 +00:00
logging . debug ( f " YES - RF bitrate = { actual_rf_bitrate } Audio bitrate = { self . audio_bit_rate } Audio samplerate = { self . audio_rate } Audio Bytes Per Modem Bit = { self . bytes_per_bit } " )
2025-03-25 11:39:20 +00:00
break
else :
2025-03-25 12:47:30 +00:00
logging . critical ( " Exhausted all audio sample rates " )
2025-03-25 11:39:20 +00:00
raise ValueError ( " Baudrate not suitable for soundcard. " )
super ( ) . __init__ ( spidevice , frequency , baudrate , tx_power_dbm , reinit_count , led = 5 ) # can't use 21 for LED as I2S is there
2025-03-25 10:29:36 +00:00
if (
2025-03-25 10:59:16 +00:00
( ( self . audio_rate * self . channels * self . audio_width * 8 ) / self . baudrate ) % 8 != 0
2025-03-25 10:29:36 +00:00
) :
2025-03-25 10:59:16 +00:00
raise ValueError ( f " Not aligned audio rate. Must be a whole byte per bit. audio_rate: { self . audio_rate } rate: { self . baudrate } " )
2025-03-25 10:29:36 +00:00
2025-03-25 10:59:16 +00:00
2025-03-25 10:29:36 +00:00
self . audio_device = audio_device
self . precompute_bytes ( )
self . periodsize = None
self . pcm = None
self . start ( )
def start ( self ) :
"""
Initialise ( or re - initialise ) both the RFM98W and Serial connections .
Configure the RFM98W into direct asynchronous FSK mode , with the appropriate power , deviation , and transmit frequency .
"""
2025-03-25 10:59:16 +00:00
super ( ) . start ( )
2025-03-25 10:29:36 +00:00
# Now initialise the Serial port for modulation
if self . audio_device and alsaaudio and not self . pcm :
try :
self . pcm = alsaaudio . PCM ( device = self . audio_device )
logging . info ( f " RFM98W - Opened audio device { self . pcm . cardname ( ) } for modulation. " )
if self . pcm . setrate ( self . audio_rate ) != self . audio_rate :
logging . critical ( " Could not set correct audio rate for datarate " )
if self . pcm . setchannels ( self . channels ) != self . channels :
logging . critical ( " could not set channel number " )
except Exception as e :
logging . critical ( f " Could not open audio device! Error: { str ( e ) } " )
elif not self . pcm :
logging . error ( " No alsaaudio - debugging mode " )
self . pcm = BinaryDebug ( )
2025-07-06 12:07:06 +00:00
# first 1000 digits of "A Million Random Digits with 100,000 Normal Deviates"
# convert to binary by doing odd/even
# a = "1009..."
# binary_list=[]
# for digit in a:
# binary_list.append (1 if int(digit) % 2 else 0)
# y=0
# byte_out=0
# for x in binary_list:
# byte_out = byte_out | (x << y)
# y += 1
# if y > 7:
# print(hex(byte_out))
# byte_out=0
# y=0
def scramble ( self , data ) :
scramble_code = [ 0xb9 , 0x97 , 0x93 , 0x13 , 0xf7 , 0xab , 0x1e , 0x88 , 0x12 , 0xc4 ,
0x28 , 0x80 , 0x9 , 0xf8 , 0xb4 , 0x92 , 0xfc , 0x32 , 0xc6 , 0xa6 ,
0xae , 0xf7 , 0x8b , 0x3a , 0xd2 , 0xf1 , 0xf1 , 0x8a , 0x72 , 0xcf ,
0x3d , 0xc3 , 0x9e , 0x52 , 0x6e , 0x7a , 0x7e , 0x37 , 0xa2 , 0x7 ,
0x17 , 0x71 , 0x2d , 0x9d , 0x1c , 0x58 , 0xc1 , 0xb4 , 0x65 , 0xe4 ,
0xbe , 0x5b , 0xd1 , 0xf , 0xa0 , 0x5a , 0x3c , 0x6f , 0xd9 , 0x8 ,
0x9c , 0x6c , 0x5c , 0x6e , 0x85 , 0x94 , 0xb1 , 0x5d , 0xde , 0xd4 ,
0xc3 , 0x55 , 0x20 , 0x61 , 0xd7 , 0x6a , 0x81 , 0x78 , 0x52 , 0x46 ,
0x7c , 0x43 , 0x40 , 0x63 , 0xf1 , 0x25 , 0xcb , 0xf1 , 0x8c , 0xa7 ,
0x83 , 0x5c , 0xa3 , 0xba , 0x5c , 0xa3 , 0xc5 , 0xb6 , 0xf , 0x2a ,
0x64 , 0x5f , 0xec , 0x98 , 0xcf , 0xf5 , 0xb6 , 0x3d , 0x96 , 0x42 ,
0x16 , 0x7 , 0xec , 0x20 , 0x32 , 0x4d , 0xc6 , 0x17 , 0x92 , 0xa6 ,
0x91 , 0xc1 , 0x92 , 0x43 , 0x69 ]
out_data = b ' '
index = 0
for x in data :
out_data + = ( x ^ scramble_code [ index % len ( scramble_code ) ] ) . to_bytes ( )
index + = 1
return out_data
2025-03-25 10:29:36 +00:00
def precompute_bytes ( self ) :
logging . debug ( " Precomputing byte lookup table " )
self . byte_to_i2s_bytes = { }
for x in range ( 256 ) :
buffer = b ' '
for bit_i in range ( 7 , - 1 , - 1 ) :
bit = ( x >> ( bit_i ) ) & 0b1
bit = b ' \xff ' if bit else b ' \x00 '
buffer = buffer + ( bit * self . bytes_per_bit )
self . byte_to_i2s_bytes [ x ] = buffer
logging . debug ( " Finished creating lookup table " )
def shutdown ( self ) :
"""
Shutdown the RFM98W , and close the SPI and Serial connections .
"""
try :
# Close the audio device
self . pcm . close ( )
logging . info ( " RFM98W - Closed audio device " )
self . pcm = None
except :
pass
return
def transmit_packet ( self , packet ) :
"""
Modulate audio data , using a I2S .
"""
if self . pcm :
desired_period_size = ( len ( packet ) * 8 * self . bytes_per_bit ) / / self . channels / / self . audio_width
if (
self . periodsize == None or
self . periodsize != desired_period_size
) :
logging . debug ( f " Setting period size to: { desired_period_size } " )
if self . pcm . setperiodsize ( desired_period_size ) != desired_period_size :
logging . critical ( f " could not set period size to match packet size: got { self . pcm . setperiodsize ( desired_period_size ) } " )
else :
self . periodsize = desired_period_size
2025-03-25 10:59:16 +00:00
logging . debug ( f " Period size set " )
2025-03-25 10:29:36 +00:00
buffer = b ' '
for i_byte in packet :
buffer = buffer + self . byte_to_i2s_bytes [ i_byte ]
frame_length = ( len ( buffer ) / / self . channels / / self . audio_width )
if frame_length % self . periodsize != 0 :
logging . critical ( f " buffer frames length { frame_length } != periodsize { self . periodsize } " )
self . pcm . write ( buffer )
2025-03-25 10:59:16 +00:00
super ( ) . transmit_packet ( packet ) # used to reinit the radio occasionally
2025-03-25 10:29:36 +00:00
2024-09-15 04:36:22 +00:00
class SerialOnly ( object ) :
"""
Transmitter Wrapper that does not initialise any radios .
"""
def __init__ (
self ,
baudrate = 115200 ,
serial_port = None ,
reinit_count = 5000
) :
self . baudrate = baudrate
self . serial_port = serial_port
self . reinit_count = reinit_count
self . tx_packet_count = 0
self . start ( )
def start ( self ) :
"""
Initialise ( or re - initialise ) the Serial connection .
"""
# Initialise the Serial port for modulation
if self . serial_port :
try :
self . serial = serial . Serial ( self . serial_port , self . baudrate )
logging . info ( f " SerialOnly - Opened Serial port { self . serial_port } for modulation. " )
except Exception as e :
logging . critical ( f " SerialOnly - Could not open serial port! Error: { str ( e ) } " )
self . serial = None
else :
# If no serial port info provided, write out to a binary debug file.
self . serial = BinaryDebug ( )
logging . info ( " SerialOnly - No serial port provided - using Binary Debug output (binary_debug.bin) " )
2025-07-06 12:07:06 +00:00
def scramble ( self , data ) :
return data
2024-09-15 04:36:22 +00:00
def shutdown ( self ) :
"""
Shutdown the Serial connection .
"""
try :
# Close the serial connection
self . serial . close ( )
logging . info ( " SerialOnly - Closed Serial Port " )
self . serial = None
except :
pass
return
def comms_ok ( self ) :
"""
Dummy function , no radio comms to test .
"""
return True
def transmit_packet ( self , packet ) :
"""
Modulate serial data , using a UART .
"""
if self . serial :
self . serial . write ( packet )
# Increment transmit packet counter
self . tx_packet_count + = 1
# If we have a reinitialisation count set, reinitialise the radio.
if self . reinit_count :
if self . tx_packet_count % self . reinit_count == 0 :
logging . info ( f " SerialOnly - Reinitialising Serial at { self . tx_packet_count } packets. " )
self . start ( )
2024-09-14 11:42:27 +00:00
class BinaryDebug ( object ) :
""" Debug binary ' transmitter ' Class
Used to write packet data to a file in one - bit - per - char ( i . e . 0 = 0x00 , 1 = 0x01 )
format for use with codec2 - dev ' s fsk modulator.
Useful for debugging , that ' s about it.
"""
def __init__ ( self ) :
self . f = open ( " binary_debug.bin " , ' wb ' )
def write ( self , data ) :
# TODO: Add in RS232 framing
raw_data = np . array ( [ ] , dtype = np . uint8 )
for d in data :
2025-03-25 10:29:36 +00:00
d_array = np . unpackbits ( np . frombuffer ( bytes ( [ d ] ) , dtype = np . uint8 ) )
2024-09-14 11:42:27 +00:00
raw_data = np . concatenate ( ( raw_data , [ 0 ] , d_array [ : : - 1 ] , [ 1 ] ) )
self . f . write ( raw_data . astype ( np . uint8 ) . tostring ( ) )
def close ( self ) :
self . f . close ( )
if __name__ == ' __main__ ' :
# Test code for the above. Allows enabling a radio and (optionally) sending some test packets.
import time
parser = argparse . ArgumentParser ( )
2025-03-25 10:29:36 +00:00
parser . add_argument ( " --rfm98w " , default = None , type = int , help = " If set, configure a RFM98W on this SPI device number. Using UART " )
parser . add_argument ( " --rfm98w-i2s " , default = None , type = int , help = " If set, configure a RFM98W on this SPI device number. Using I2S " )
parser . add_argument ( " --audio-device " , default = " hw:CARD=i2smaster,DEV=0 " , type = str , help = " Sets the audio device for rfm98w-i2s mode. " )
2024-09-14 11:42:27 +00:00
parser . add_argument ( " --frequency " , default = 443.500 , type = float , help = " Transmit Frequency (MHz). (Default: 443.500 MHz) " )
2025-03-25 11:44:51 +00:00
parser . add_argument ( " --baudrate " , default = None , type = int , help = " Wenet TX baud rate. (Default: 115200 for uart and 96000 for I2S). Known working I2S baudrates: 8000, 24000, 48000, 96000 " )
2024-09-14 11:42:27 +00:00
parser . add_argument ( " --serial_port " , default = " /dev/ttyAMA0 " , type = str , help = " Serial Port for modulation. " )
parser . add_argument ( " --tx_power " , default = 17 , type = int , help = " Transmit power in dBm (Default: 17 dBm, 50mW. Allowed values: 2-17) " )
parser . add_argument ( " --shutdown " , default = False , action = " store_true " , help = " Shutdown Transmitter after configuration. " )
parser . add_argument ( " --test_modulation " , default = False , action = " store_true " , help = " Transmit a sequence of dummy packets as a test. " )
parser . add_argument ( " -v " , " --verbose " , action = ' store_true ' , default = False , help = " Show additional debug info. " )
args = parser . parse_args ( )
2025-03-25 11:39:20 +00:00
if args . baudrate == None :
if args . rfm98w :
args . baudrate = 115200
elif args . rfm98w_i2s :
args . baudrate = 96000
2024-09-14 11:42:27 +00:00
if args . verbose :
logging_level = logging . DEBUG
else :
logging_level = logging . INFO
# Set up logging
logging . basicConfig ( format = " %(asctime)s %(levelname)s : %(message)s " , level = logging_level )
radio = None
if args . rfm98w is not None :
radio = RFM98W_Serial (
spidevice = args . rfm98w ,
frequency = args . frequency ,
baudrate = args . baudrate ,
serial_port = args . serial_port ,
tx_power_dbm = args . tx_power
)
2025-03-25 10:29:36 +00:00
elif args . rfm98w_i2s is not None :
radio = RFM98W_I2S (
spidevice = args . rfm98w ,
2025-03-25 11:39:20 +00:00
baudrate = args . baudrate ,
2025-03-25 10:29:36 +00:00
frequency = args . frequency ,
audio_device = args . audio_device ,
tx_power_dbm = args . tx_power
)
2024-09-14 11:42:27 +00:00
# Other radio options would go here.
else :
logging . critical ( " No radio type specified! Exiting " )
sys . exit ( 1 )
if args . test_modulation :
# Transmit a canned text message a few times
time . sleep ( 1 )
test_packet = b ' UUUUUUUUUUUUUUUU \xab \xcd \xef \x01 \x00 \x1d \x00 \x01 This is a Wenet test message!UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU5 \x89 \xad 5 \xff \xfb gX \x96 \xaa \x10 \xb9 \x05 , \x8c o \xf7 \xf0 \xdd \x19 \x1b s2 \xd9 $ \x85 \xa2 \xc2 \xd5 \xc9 \x15 \xef \xac \x06 \xb6 \x11 H \xb0 ; \xc3 \xae \x1b \xe0 _ \x8c C \x13 L* \x04 \x17 ( \x9a \xa6 \x95 \x84 \xf1 UB { \xf5 \x96 \xb9 \x14 \x05 \xa8 @ '
logging . info ( " Sending 100 test packets. " )
for x in range ( 100 ) :
radio . transmit_packet ( test_packet )
time . sleep ( 0.1 )
if args . shutdown :
logging . info ( " Sleeping 5 seconds before shutdown " )
time . sleep ( 5 )
radio . shutdown ( )
sys . exit ( 0 )