Initial commit of Arduino libraries
This commit is contained in:
50
RadioLib/extras/SSTV_Image_Converter/ImageConverter.py
Normal file
50
RadioLib/extras/SSTV_Image_Converter/ImageConverter.py
Normal file
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/python3
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
import argparse
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
from argparse import RawTextHelpFormatter
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(formatter_class=RawTextHelpFormatter, description='''
|
||||
RadioLib image to array conversion tool.
|
||||
|
||||
Input is a PNG image to be transmitted via RadioLib SSTV.
|
||||
The image must have correct size for the chose SSTV mode!
|
||||
|
||||
Output is a file (by default named "img.h") which can be included and transmitted.
|
||||
The resulting array will be very large (typically 320 kB),
|
||||
make sure your platform has sufficient Flash/RAM space.
|
||||
''')
|
||||
parser.add_argument('input',
|
||||
type=str,
|
||||
help='Input PNG file')
|
||||
parser.add_argument('output',
|
||||
type=str,
|
||||
nargs='?',
|
||||
default='img',
|
||||
help='Output header file')
|
||||
args = parser.parse_args()
|
||||
outfile = f'{args.output}.h'
|
||||
print(f'Converting "{args.input}" to "{outfile}"')
|
||||
|
||||
# open the image as numpy array
|
||||
img = Image.open(args.input)
|
||||
arr = np.array(img)
|
||||
|
||||
# open the output file
|
||||
with open(outfile, 'w') as f:
|
||||
print(f'const uint32_t img[{arr.shape[0]}][{arr.shape[1]}] = {{', file=f)
|
||||
for row in arr:
|
||||
print(' { ', end='', file=f)
|
||||
for pix in row:
|
||||
rgb = pix[0] << 16 | pix[1] << 8 | pix[2]
|
||||
print(hex(rgb), end=', ', file=f)
|
||||
print(' },', file=f)
|
||||
print('};', file=f)
|
||||
|
||||
print('Done!')
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
BIN
RadioLib/extras/SSTV_Image_Converter/radiolib.png
Normal file
BIN
RadioLib/extras/SSTV_Image_Converter/radiolib.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
176
RadioLib/extras/SX126x_Spectrum_Scan/SpectrumScan.py
Normal file
176
RadioLib/extras/SX126x_Spectrum_Scan/SpectrumScan.py
Normal file
@@ -0,0 +1,176 @@
|
||||
#!/usr/bin/python3
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
import argparse
|
||||
import serial
|
||||
import sys
|
||||
import numpy as np
|
||||
import matplotlib as mpl
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
from datetime import datetime
|
||||
from argparse import RawTextHelpFormatter
|
||||
|
||||
# number of samples in each scanline
|
||||
SCAN_WIDTH = 33
|
||||
|
||||
# scanline Serial start/end markers
|
||||
SCAN_MARK_START = 'SCAN '
|
||||
SCAN_MARK_FREQ = 'FREQ '
|
||||
SCAN_MARK_END = ' END'
|
||||
|
||||
# output path
|
||||
OUT_PATH = 'out'
|
||||
|
||||
# default settings
|
||||
DEFAULT_BAUDRATE = 115200
|
||||
DEFAULT_COLOR_MAP = 'viridis'
|
||||
DEFAULT_SCAN_LEN = 200
|
||||
DEFAULT_RSSI_OFFSET = -11
|
||||
|
||||
# Print iterations progress
|
||||
# from https://stackoverflow.com/questions/3173320/text-progress-bar-in-terminal-with-block-characters
|
||||
def printProgressBar (iteration, total, prefix = '', suffix = '', decimals = 1, length = 50, fill = '█', printEnd = "\r"):
|
||||
"""
|
||||
Call in a loop to create terminal progress bar
|
||||
@params:
|
||||
iteration - Required : current iteration (Int)
|
||||
total - Required : total iterations (Int)
|
||||
prefix - Optional : prefix string (Str)
|
||||
suffix - Optional : suffix string (Str)
|
||||
decimals - Optional : positive number of decimals in percent complete (Int)
|
||||
length - Optional : character length of bar (Int)
|
||||
fill - Optional : bar fill character (Str)
|
||||
printEnd - Optional : end character (e.g. "\r", "\r\n") (Str)
|
||||
"""
|
||||
percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
|
||||
filledLength = int(length * iteration // total)
|
||||
bar = fill * filledLength + '-' * (length - filledLength)
|
||||
print(f'\r{prefix} |{bar}| {percent}% {suffix}', end = printEnd)
|
||||
if iteration == total:
|
||||
print()
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(formatter_class=RawTextHelpFormatter, description='''
|
||||
RadioLib SX126x_Spectrum_Scan plotter script. Displays output from SX126x_Spectrum_Scan example
|
||||
as grayscale and
|
||||
|
||||
Depends on pyserial and matplotlib, install by:
|
||||
'python3 -m pip install pyserial matplotlib'
|
||||
|
||||
Step-by-step guide on how to use the script:
|
||||
1. Upload the SX126x_Spectrum_Scan example to your Arduino board with SX1262 connected.
|
||||
2. Run the script with appropriate arguments.
|
||||
3. Once the scan is complete, output files will be saved to out/
|
||||
''')
|
||||
parser.add_argument('port',
|
||||
type=str,
|
||||
help='COM port to connect to the device')
|
||||
parser.add_argument('--speed',
|
||||
default=DEFAULT_BAUDRATE,
|
||||
type=int,
|
||||
help=f'COM port baudrate (defaults to {DEFAULT_BAUDRATE})')
|
||||
parser.add_argument('--map',
|
||||
default=DEFAULT_COLOR_MAP,
|
||||
type=str,
|
||||
help=f'Matplotlib color map to use for the output (defaults to "{DEFAULT_COLOR_MAP}")')
|
||||
parser.add_argument('--len',
|
||||
default=DEFAULT_SCAN_LEN,
|
||||
type=int,
|
||||
help=f'Number of scanlines to record (defaults to {DEFAULT_SCAN_LEN})')
|
||||
parser.add_argument('--offset',
|
||||
default=DEFAULT_RSSI_OFFSET,
|
||||
type=int,
|
||||
help=f'Default RSSI offset in dBm (defaults to {DEFAULT_RSSI_OFFSET})')
|
||||
parser.add_argument('--freq',
|
||||
default=-1,
|
||||
type=float,
|
||||
help=f'Default starting frequency in MHz')
|
||||
args = parser.parse_args()
|
||||
|
||||
freq_mode = False
|
||||
scan_len = args.len
|
||||
if (args.freq != -1):
|
||||
freq_mode = True
|
||||
scan_len = 1000
|
||||
|
||||
# create the color map and the result array
|
||||
arr = np.zeros((SCAN_WIDTH, scan_len))
|
||||
|
||||
# scanline counter
|
||||
row = 0
|
||||
|
||||
# list of frequencies in frequency mode
|
||||
freq_list = []
|
||||
|
||||
# open the COM port
|
||||
with serial.Serial(args.port, args.speed, timeout=None) as com:
|
||||
while(True):
|
||||
# update the progress bar
|
||||
if not freq_mode:
|
||||
printProgressBar(row, scan_len)
|
||||
|
||||
# read a single line
|
||||
try:
|
||||
line = com.readline().decode('utf-8')
|
||||
except:
|
||||
continue
|
||||
|
||||
if SCAN_MARK_FREQ in line:
|
||||
new_freq = float(line.split(' ')[1])
|
||||
if (len(freq_list) > 1) and (new_freq < freq_list[-1]):
|
||||
break
|
||||
|
||||
freq_list.append(new_freq)
|
||||
print('{:.3f}'.format(new_freq), end = '\r')
|
||||
continue
|
||||
|
||||
# check the markers
|
||||
if (SCAN_MARK_START in line) and (SCAN_MARK_END in line):
|
||||
# get the values
|
||||
scanline = line[len(SCAN_MARK_START):-len(SCAN_MARK_END)].split(',')
|
||||
for col in range(SCAN_WIDTH):
|
||||
arr[col][row] = int(scanline[col])
|
||||
|
||||
# increment the row counter
|
||||
row = row + 1
|
||||
|
||||
# check if we're done
|
||||
if (not freq_mode) and (row >= scan_len):
|
||||
break
|
||||
|
||||
# scale to the number of scans (sum of any given scanline)
|
||||
num_samples = arr.sum(axis=0)[0]
|
||||
arr *= (num_samples/arr.max())
|
||||
|
||||
if freq_mode:
|
||||
scan_len = len(freq_list)
|
||||
|
||||
# create the figure
|
||||
fig, ax = plt.subplots()
|
||||
|
||||
# display the result as heatmap
|
||||
extent = [0, scan_len, -4*(SCAN_WIDTH + 1), args.offset]
|
||||
if freq_mode:
|
||||
extent[0] = freq_list[0]
|
||||
extent[1] = freq_list[-1]
|
||||
im = ax.imshow(arr[:,:scan_len], cmap=args.map, extent=extent)
|
||||
fig.colorbar(im)
|
||||
|
||||
# set some properites and show
|
||||
timestamp = datetime.now().strftime('%y-%m-%d %H-%M-%S')
|
||||
title = f'RadioLib SX126x Spectral Scan {timestamp}'
|
||||
if freq_mode:
|
||||
plt.xlabel("Frequency [Hz]")
|
||||
else:
|
||||
plt.xlabel("Time [sample]")
|
||||
plt.ylabel("RSSI [dBm]")
|
||||
ax.set_aspect('auto')
|
||||
fig.suptitle(title)
|
||||
fig.canvas.manager.set_window_title(title)
|
||||
plt.savefig(f'{OUT_PATH}/{title.replace(" ", "_")}.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
20
RadioLib/extras/cppcheck/cppcheck.sh
Normal file
20
RadioLib/extras/cppcheck/cppcheck.sh
Normal file
@@ -0,0 +1,20 @@
|
||||
#! /bin/bash
|
||||
|
||||
file=cppcheck.txt
|
||||
cppcheck --version
|
||||
cppcheck src --enable=all --force --inline-suppr --suppress=ConfigurationNotChecked --suppress=unusedFunction --quiet >> $file 2>&1
|
||||
echo "Cppcheck finished with exit code $?"
|
||||
|
||||
error=$(grep ": error:" $file | wc -l)
|
||||
warning=$(grep ": warning:" $file | wc -l)
|
||||
style=$(grep ": style:" $file | wc -l)
|
||||
performance=$(grep ": performance:" $file | wc -l)
|
||||
echo "found $error erros, $warning warnings, $style style and $performance performance issues"
|
||||
if [ $error -gt "0" ] || [ $warning -gt "0" ] || [ $style -gt "0" ] || [ $performance -gt "0" ]
|
||||
then
|
||||
cat $file
|
||||
exitcode=1
|
||||
fi
|
||||
|
||||
rm $file
|
||||
exit $exitcode
|
||||
22
RadioLib/extras/template/ModuleTemplate.cpp
Normal file
22
RadioLib/extras/template/ModuleTemplate.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "<module_name>.h"
|
||||
#if !defined(RADIOLIB_EXCLUDE_<module_name>)
|
||||
|
||||
<module_name>::<module_name>(Module* mod) {
|
||||
/*
|
||||
Constructor implementation MUST assign the provided "mod" pointer to the private "_mod" pointer.
|
||||
*/
|
||||
_mod = mod;
|
||||
}
|
||||
|
||||
int16_t <module_name>::begin() {
|
||||
/*
|
||||
"begin" method implementation MUST call the "init" method with appropriate settings.
|
||||
*/
|
||||
_mod->init();
|
||||
|
||||
/*
|
||||
"begin" method SHOULD implement some sort of mechanism to verify the connection between Arduino and the module.
|
||||
|
||||
For example, reading a version register
|
||||
*/
|
||||
}
|
||||
99
RadioLib/extras/template/ModuleTemplate.h
Normal file
99
RadioLib/extras/template/ModuleTemplate.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
RadioLib Module Template header file
|
||||
|
||||
Before opening pull request, please make sure that:
|
||||
1. All files MUST be compiled without errors using default Arduino IDE settings.
|
||||
2. All files SHOULD be compiled without warnings with compiler warnings set to "All".
|
||||
3. Example sketches MUST be working correctly and MUST be stable enough to run for prolonged periods of time.
|
||||
4. Writing style SHOULD be consistent.
|
||||
5. Comments SHOULD be in place for the most important chunks of code and SHOULD be free of typos.
|
||||
6. To indent, 2 spaces MUST be used.
|
||||
|
||||
If at any point you are unsure about the required style, please refer to the rest of the modules.
|
||||
*/
|
||||
|
||||
#if !defined(_RADIOLIB_<module_name>_H) && !defined(RADIOLIB_EXCLUDE_<module_name>)
|
||||
#if !defined(_RADIOLIB_<module_name>_H)
|
||||
#define _RADIOLIB_<module_name>_H
|
||||
|
||||
/*
|
||||
Header file for each module MUST include Module.h and TypeDef.h in the src folder.
|
||||
The header file MAY include additional header files.
|
||||
*/
|
||||
#include "../../Module.h"
|
||||
#include "../../TypeDef.h"
|
||||
|
||||
/*
|
||||
Only use the following include if the module implements methods for OSI physical layer control.
|
||||
This concerns only modules similar to SX127x/RF69/CC1101 etc.
|
||||
|
||||
In this case, your class MUST implement all virtual methods of PhysicalLayer class.
|
||||
*/
|
||||
//#include "../../protocols/PhysicalLayer/PhysicalLayer.h"
|
||||
|
||||
/*
|
||||
Register map
|
||||
Definition of SPI register map SHOULD be placed here. The register map SHOULD have two parts:
|
||||
|
||||
1 - Address map: only defines register names and addresses. Register names MUST match names in
|
||||
official documentation (datasheets etc.).
|
||||
2 - Variable map: defines variables inside register. This functions as a bit range map for a specific register.
|
||||
Bit range (MSB and LSB) as well as short description for each variable MUST be provided in a comment.
|
||||
|
||||
See RF69 and SX127x header files for examples of register maps.
|
||||
*/
|
||||
// <module_name> register map | spaces up to this point
|
||||
#define RADIOLIB_<module_name>_REG_<register_name> 0x00
|
||||
|
||||
// <module_name>_REG_<register_name> MSB LSB DESCRIPTION
|
||||
#define RADIOLIB_<module_name>_<register_variable> 0b00000000 // 7 0 <description>
|
||||
|
||||
|
||||
/*
|
||||
Module class definition
|
||||
|
||||
The module class MAY inherit from the following classes:
|
||||
|
||||
1 - PhysicalLayer: In case the module implements methods for OSI physical layer control (e.g. SX127x).
|
||||
2 - Common class: In case the module further specifies some more generic class (e.g. SX127x/SX1278)
|
||||
*/
|
||||
class <module_name> {
|
||||
public:
|
||||
/*
|
||||
Constructor MUST have only one parameter "Module* mod".
|
||||
The class MAY implement additional overloaded constructors.
|
||||
*/
|
||||
// constructor
|
||||
<module_name>(Module* mod);
|
||||
|
||||
/*
|
||||
The class MUST implement at least one basic method called "begin".
|
||||
The "begin" method MUST initialize the module and return the status as int16_t type.
|
||||
*/
|
||||
// basic methods
|
||||
int16_t begin();
|
||||
|
||||
/*
|
||||
The class MAY implement additional methods.
|
||||
All implemented methods SHOULD return the status as int16_t type.
|
||||
*/
|
||||
|
||||
#if !defined(RADIOLIB_GODMODE)
|
||||
private:
|
||||
#endif
|
||||
/*
|
||||
The class MUST contain private member "Module* _mod"
|
||||
*/
|
||||
Module* _mod;
|
||||
|
||||
/*
|
||||
The class MAY contain additional private variables and/or methods.
|
||||
Private member variables MUST have a name prefixed with "_" (underscore, ASCII 0x5F)
|
||||
|
||||
Usually, these are variables for saving module configuration, or methods that do not have to be exposed to the end user.
|
||||
*/
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
21
RadioLib/extras/test/SX126x/CMakeLists.txt
Normal file
21
RadioLib/extras/test/SX126x/CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
|
||||
# create the project
|
||||
project(rpi-sx1261)
|
||||
|
||||
# when using debuggers such as gdb, the following line can be used
|
||||
#set(CMAKE_BUILD_TYPE Debug)
|
||||
|
||||
# if you did not build RadioLib as shared library (see README),
|
||||
# you will have to add it as source directory
|
||||
# the following is just an example, yours will likely be different
|
||||
#add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CURRENT_BINARY_DIR}/RadioLib")
|
||||
|
||||
# add the executable
|
||||
add_executable(${PROJECT_NAME} main.cpp)
|
||||
|
||||
# link both libraries
|
||||
target_link_libraries(${PROJECT_NAME} RadioLib pigpio)
|
||||
|
||||
# you can also specify RadioLib compile-time flags here
|
||||
#target_compile_definitions(${PROJECT_NAME} PUBLIC RADIOLIB_DEBUG RADIOLIB_VERBOSE)
|
||||
151
RadioLib/extras/test/SX126x/PiHal.h
Normal file
151
RadioLib/extras/test/SX126x/PiHal.h
Normal file
@@ -0,0 +1,151 @@
|
||||
#ifndef PI_HAL_H
|
||||
#define PI_HAL_H
|
||||
|
||||
// include RadioLib
|
||||
#include <RadioLib/RadioLib.h>
|
||||
|
||||
// include the library for Raspberry GPIO pins
|
||||
#include "pigpio.h"
|
||||
|
||||
// create a new Raspberry Pi hardware abstraction layer
|
||||
// using the pigpio library
|
||||
// the HAL must inherit from the base RadioLibHal class
|
||||
// and implement all of its virtual methods
|
||||
class PiHal : public RadioLibHal {
|
||||
public:
|
||||
// default constructor - initializes the base HAL and any needed private members
|
||||
PiHal(uint8_t spiChannel, uint32_t spiSpeed = 2000000)
|
||||
: RadioLibHal(PI_INPUT, PI_OUTPUT, PI_LOW, PI_HIGH, RISING_EDGE, FALLING_EDGE),
|
||||
_spiChannel(spiChannel),
|
||||
_spiSpeed(spiSpeed) {
|
||||
}
|
||||
|
||||
void init() override {
|
||||
// first initialise pigpio library
|
||||
gpioInitialise();
|
||||
|
||||
// now the SPI
|
||||
spiBegin();
|
||||
|
||||
// Waveshare LoRaWAN Hat also needs pin 18 to be pulled high to enable the radio
|
||||
gpioSetMode(18, PI_OUTPUT);
|
||||
gpioWrite(18, PI_HIGH);
|
||||
}
|
||||
|
||||
void term() override {
|
||||
// stop the SPI
|
||||
spiEnd();
|
||||
|
||||
// pull the enable pin low
|
||||
gpioSetMode(18, PI_OUTPUT);
|
||||
gpioWrite(18, PI_LOW);
|
||||
|
||||
// finally, stop the pigpio library
|
||||
gpioTerminate();
|
||||
}
|
||||
|
||||
// GPIO-related methods (pinMode, digitalWrite etc.) should check
|
||||
// RADIOLIB_NC as an alias for non-connected pins
|
||||
void pinMode(uint32_t pin, uint32_t mode) override {
|
||||
if(pin == RADIOLIB_NC) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpioSetMode(pin, mode);
|
||||
}
|
||||
|
||||
void digitalWrite(uint32_t pin, uint32_t value) override {
|
||||
if(pin == RADIOLIB_NC) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpioWrite(pin, value);
|
||||
}
|
||||
|
||||
uint32_t digitalRead(uint32_t pin) override {
|
||||
if(pin == RADIOLIB_NC) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
return(gpioRead(pin));
|
||||
}
|
||||
|
||||
void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override {
|
||||
if(interruptNum == RADIOLIB_NC) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpioSetISRFunc(interruptNum, mode, 0, (gpioISRFunc_t)interruptCb);
|
||||
}
|
||||
|
||||
void detachInterrupt(uint32_t interruptNum) override {
|
||||
if(interruptNum == RADIOLIB_NC) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpioSetISRFunc(interruptNum, 0, 0, NULL);
|
||||
}
|
||||
|
||||
void delay(RadioLibTime_t ms) override {
|
||||
gpioDelay(ms * 1000);
|
||||
}
|
||||
|
||||
void delayMicroseconds(RadioLibTime_t us) override {
|
||||
gpioDelay(us);
|
||||
}
|
||||
|
||||
RadioLibTime_t millis() override {
|
||||
return(gpioTick() / 1000);
|
||||
}
|
||||
|
||||
RadioLibTime_t micros() override {
|
||||
return(gpioTick());
|
||||
}
|
||||
|
||||
long pulseIn(uint32_t pin, uint32_t state, RadioLibTime_t timeout) override {
|
||||
if(pin == RADIOLIB_NC) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
this->pinMode(pin, PI_INPUT);
|
||||
RadioLibTime_t start = this->micros();
|
||||
RadioLibTime_t curtick = this->micros();
|
||||
|
||||
while(this->digitalRead(pin) == state) {
|
||||
if((this->micros() - curtick) > timeout) {
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
return(this->micros() - start);
|
||||
}
|
||||
|
||||
void spiBegin() {
|
||||
if(_spiHandle < 0) {
|
||||
_spiHandle = spiOpen(_spiChannel, _spiSpeed, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void spiBeginTransaction() {}
|
||||
|
||||
void spiTransfer(uint8_t* out, size_t len, uint8_t* in) {
|
||||
spiXfer(_spiHandle, (char*)out, (char*)in, len);
|
||||
}
|
||||
|
||||
void spiEndTransaction() {}
|
||||
|
||||
void spiEnd() {
|
||||
if(_spiHandle >= 0) {
|
||||
spiClose(_spiHandle);
|
||||
_spiHandle = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// the HAL can contain any additional private members
|
||||
const unsigned int _spiSpeed;
|
||||
const uint8_t _spiChannel;
|
||||
int _spiHandle = -1;
|
||||
};
|
||||
|
||||
#endif
|
||||
8
RadioLib/extras/test/SX126x/build.sh
Normal file
8
RadioLib/extras/test/SX126x/build.sh
Normal file
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake -G "CodeBlocks - Unix Makefiles" ..
|
||||
make -j4
|
||||
cd ..
|
||||
3
RadioLib/extras/test/SX126x/clean.sh
Normal file
3
RadioLib/extras/test/SX126x/clean.sh
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
rm -rf ./build
|
||||
26
RadioLib/extras/test/SX126x/main.cpp
Normal file
26
RadioLib/extras/test/SX126x/main.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
// this is an autotest file for the SX126x
|
||||
// runs on Raspberry Pi with Waveshare LoRaWAN hat
|
||||
|
||||
#include <RadioLib/RadioLib.h>
|
||||
#include "PiHal.h"
|
||||
|
||||
#define RADIOLIB_TEST_ASSERT(STATEVAR) { if((STATEVAR) != RADIOLIB_ERR_NONE) { return(-1*(STATEVAR)); } }
|
||||
|
||||
PiHal* hal = new PiHal(1);
|
||||
SX1261 radio = new Module(hal, 7, 17, 22, RADIOLIB_NC);
|
||||
|
||||
// the entry point for the program
|
||||
int main(int argc, char** argv) {
|
||||
int state = RADIOLIB_ERR_UNKNOWN;
|
||||
|
||||
state = radio.begin();
|
||||
printf("[SX1261] Test:begin() = %d\n", state);
|
||||
RADIOLIB_TEST_ASSERT(state);
|
||||
|
||||
state = radio.transmit("Hello World!");
|
||||
printf("[SX1261] Test:transmit() = %d\n", state);
|
||||
RADIOLIB_TEST_ASSERT(state);
|
||||
|
||||
hal->term();
|
||||
return(0);
|
||||
}
|
||||
13
RadioLib/extras/test/ci/build_arduino.sh
Normal file
13
RadioLib/extras/test/ci/build_arduino.sh
Normal file
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
board=$1
|
||||
sketch=$2
|
||||
flags=$3
|
||||
warnings="all"
|
||||
|
||||
arduino-cli compile \
|
||||
--libraries ../../../../ \
|
||||
--fqbn $board \
|
||||
--build-property compiler.cpp.extra_flags="$flags" \
|
||||
--warnings=$warnings \
|
||||
$sketch --export-binaries
|
||||
41
RadioLib/extras/test/ci/build_examples.sh
Normal file
41
RadioLib/extras/test/ci/build_examples.sh
Normal file
@@ -0,0 +1,41 @@
|
||||
#!/bin/bash
|
||||
|
||||
#board=arduino:avr:mega
|
||||
board="$1"
|
||||
#skip="(STM32WL|LR11x0_Firmware_Update|NonArduino)"
|
||||
skip="$2"
|
||||
#options=""
|
||||
options="$3"
|
||||
|
||||
# file for saving the compiled binary size reports
|
||||
size_file="size_$board.txt"
|
||||
rm -f $size_file
|
||||
|
||||
path="../../../examples"
|
||||
for example in $(find $path -name '*.ino' | sort); do
|
||||
# check whether to skip this sketch
|
||||
if [ ! -z '$skip' ] && [[ ${example} =~ ${skip} ]]; then
|
||||
# skip sketch
|
||||
echo -e "\n\033[1;33mSkipped ${example##*/} (matched with $skip)\033[0m";
|
||||
else
|
||||
# apply special flags for LoRaWAN
|
||||
if [[ ${example} =~ "LoRaWAN" ]]; then
|
||||
flags="-DRADIOLIB_LORAWAN_DEV_ADDR=0 -DRADIOLIB_LORAWAN_FNWKSINT_KEY=0 -DRADIOLIB_LORAWAN_SNWKSINT_KEY=0 -DRADIOLIB_LORAWAN_NWKSENC_KEY=0 -DRADIOLIB_LORAWAN_APPS_KEY=0 -DRADIOLIB_LORAWAN_APP_KEY=0 -DRADIOLIB_LORAWAN_NWK_KEY=0 -DRADIOLIB_LORAWAN_DEV_EUI=0 -DARDUINO_TTGO_LORA32_V1"
|
||||
fi
|
||||
|
||||
# build sketch
|
||||
echo -e "\n\033[1;33mBuilding ${example##*/} ... \033[0m";
|
||||
board_opts=$board$options
|
||||
./build_arduino.sh $board_opts $example "$flags"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "\033[1;31m${example##*/} build FAILED\033[0m\n";
|
||||
exit 1;
|
||||
else
|
||||
echo -e "\033[1;32m${example##*/} build PASSED\033[0m\n";
|
||||
dir="$(dirname -- "$example")"
|
||||
file="$(basename -- "$example")"
|
||||
size="$(size $dir/build/*/$file.elf)"
|
||||
echo $size >> $size_file
|
||||
fi
|
||||
fi
|
||||
done
|
||||
24
RadioLib/extras/test/ci/parse_size.sh
Normal file
24
RadioLib/extras/test/ci/parse_size.sh
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
|
||||
board=$1
|
||||
hash=$(git rev-parse --short HEAD)
|
||||
|
||||
in_file="size_$board.txt"
|
||||
out_file="size_${hash}_${board//:/-}.csv"
|
||||
rm -f $out_file
|
||||
|
||||
# write the header
|
||||
echo "text,data,bss,dec,hex,filename" > "$out_file"
|
||||
|
||||
# convert to CSV
|
||||
awk 'NR > 1 {
|
||||
split($12, path_parts, "/");
|
||||
filename_with_ext = path_parts[length(path_parts)];
|
||||
split(filename_with_ext, filename_parts, ".");
|
||||
filename = filename_parts[1];
|
||||
print $7 "," $8 "," $9 "," $10 "," $11 "," filename
|
||||
}' "$in_file" >> "$out_file"
|
||||
|
||||
# remove input file
|
||||
rm -f $in_file
|
||||
|
||||
29
RadioLib/extras/test/unit/CMakeLists.txt
Normal file
29
RadioLib/extras/test/unit/CMakeLists.txt
Normal file
@@ -0,0 +1,29 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
project(radiolib-unittest)
|
||||
|
||||
# add RadioLib sources
|
||||
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CURRENT_BINARY_DIR}/RadioLib")
|
||||
|
||||
# add test sources
|
||||
file(GLOB_RECURSE TEST_SOURCES
|
||||
"tests/main.cpp"
|
||||
"tests/TestModule.cpp"
|
||||
)
|
||||
|
||||
# create the executable
|
||||
add_executable(${PROJECT_NAME} ${TEST_SOURCES})
|
||||
|
||||
# include directories
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC include)
|
||||
|
||||
# link RadioLib
|
||||
target_link_libraries(${PROJECT_NAME} RadioLib fmt)
|
||||
|
||||
# set target properties and options
|
||||
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20)
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra)
|
||||
|
||||
# set RadioLib debug
|
||||
#target_compile_definitions(RadioLib PUBLIC RADIOLIB_DEBUG_BASIC RADIOLIB_DEBUG_SPI)
|
||||
#target_compile_definitions(RadioLib PUBLIC RADIOLIB_DEBUG_PORT=stdout)
|
||||
71
RadioLib/extras/test/unit/include/HardwareEmulation.hpp
Normal file
71
RadioLib/extras/test/unit/include/HardwareEmulation.hpp
Normal file
@@ -0,0 +1,71 @@
|
||||
#ifndef HARDWARE_EMULATION_HPP
|
||||
#define HARDWARE_EMULATION_HPP
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// value that is returned by the emualted radio class when performing SPI transfer to it
|
||||
#define EMULATED_RADIO_SPI_RETURN (0xFF)
|
||||
|
||||
// pin indexes
|
||||
#define EMULATED_RADIO_NSS_PIN (1)
|
||||
#define EMULATED_RADIO_IRQ_PIN (2)
|
||||
#define EMULATED_RADIO_RST_PIN (3)
|
||||
#define EMULATED_RADIO_GPIO_PIN (4)
|
||||
|
||||
enum PinFunction_t {
|
||||
PIN_UNASSIGNED = 0,
|
||||
PIN_CS,
|
||||
PIN_IRQ,
|
||||
PIN_RST,
|
||||
PIN_GPIO,
|
||||
};
|
||||
|
||||
// structure for emulating GPIO pins
|
||||
struct EmulatedPin_t {
|
||||
uint32_t mode;
|
||||
uint32_t value;
|
||||
bool event;
|
||||
PinFunction_t func;
|
||||
};
|
||||
|
||||
// structure for emulating SPI registers
|
||||
struct EmulatedRegister_t {
|
||||
uint8_t value;
|
||||
uint8_t readOnlyBitFlags;
|
||||
bool bufferAccess;
|
||||
};
|
||||
|
||||
// base class for emulated radio modules (SX126x etc.)
|
||||
class EmulatedRadio {
|
||||
public:
|
||||
void connect(EmulatedPin_t* csPin, EmulatedPin_t* irqPin, EmulatedPin_t* rstPin, EmulatedPin_t* gpioPin) {
|
||||
this->cs = csPin;
|
||||
this->cs->func = PIN_CS;
|
||||
this->irq = irqPin;
|
||||
this->irq->func = PIN_IRQ;
|
||||
this->rst = rstPin;
|
||||
this->rst->func = PIN_RST;
|
||||
this->gpio = gpioPin;
|
||||
this->gpio->func = PIN_GPIO;
|
||||
}
|
||||
|
||||
virtual uint8_t HandleSPI(uint8_t b) {
|
||||
(void)b;
|
||||
// handle the SPI input and generate output here
|
||||
return(EMULATED_RADIO_SPI_RETURN);
|
||||
}
|
||||
|
||||
virtual void HandleGPIO() {
|
||||
// handle discrete GPIO signals here (e.g. reset state machine on NSS falling edge)
|
||||
}
|
||||
|
||||
protected:
|
||||
// pointers to emulated GPIO pins
|
||||
// this is done via pointers so that the same GPIO entity is shared, like with a real hardware
|
||||
EmulatedPin_t* cs;
|
||||
EmulatedPin_t* irq;
|
||||
EmulatedPin_t* rst;
|
||||
EmulatedPin_t* gpio;
|
||||
};
|
||||
|
||||
#endif
|
||||
237
RadioLib/extras/test/unit/include/TestHal.hpp
Normal file
237
RadioLib/extras/test/unit/include/TestHal.hpp
Normal file
@@ -0,0 +1,237 @@
|
||||
#ifndef TEST_HAL_HPP
|
||||
#define TEST_HAL_HPP
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <RadioLib.h>
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#if defined(TEST_HAL_LOG)
|
||||
#define HAL_LOG(...) BOOST_TEST_MESSAGE(__VA_ARGS__)
|
||||
#else
|
||||
#define HAL_LOG(...) {}
|
||||
#endif
|
||||
|
||||
#include "HardwareEmulation.hpp"
|
||||
|
||||
#define TEST_HAL_INPUT (0)
|
||||
#define TEST_HAL_OUTPUT (1)
|
||||
#define TEST_HAL_LOW (0)
|
||||
#define TEST_HAL_HIGH (1)
|
||||
#define TEST_HAL_RISING (0)
|
||||
#define TEST_HAL_FALLING (1)
|
||||
|
||||
// number of emulated GPIO pins
|
||||
#define TEST_HAL_NUM_GPIO_PINS (32)
|
||||
|
||||
#define TEST_HAL_SPI_LOG_LENGTH (512)
|
||||
|
||||
class TestHal : public RadioLibHal {
|
||||
public:
|
||||
TestHal() : RadioLibHal(TEST_HAL_INPUT, TEST_HAL_OUTPUT, TEST_HAL_LOW, TEST_HAL_HIGH, TEST_HAL_RISING, TEST_HAL_FALLING) { }
|
||||
|
||||
void init() override {
|
||||
HAL_LOG("TestHal::init()");
|
||||
|
||||
// save program start timestamp
|
||||
start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
// init emulated GPIO
|
||||
for(int i = 0; i < TEST_HAL_NUM_GPIO_PINS; i++) {
|
||||
this->gpio[i].mode = 0;
|
||||
this->gpio[i].value = 0;
|
||||
this->gpio[i].event = false;
|
||||
this->gpio[i].func = PIN_UNASSIGNED;
|
||||
}
|
||||
}
|
||||
|
||||
void term() override {
|
||||
HAL_LOG("TestHal::term()");
|
||||
}
|
||||
|
||||
void pinMode(uint32_t pin, uint32_t mode) override {
|
||||
HAL_LOG("TestHal::pinMode(pin=" << pin << ", mode=" << mode << " [" << ((mode == TEST_HAL_INPUT) ? "INPUT" : "OUTPUT") << "])");
|
||||
|
||||
// check the range
|
||||
BOOST_ASSERT_MSG(pin < TEST_HAL_NUM_GPIO_PINS, "Pin number out of range");
|
||||
|
||||
// check known modes
|
||||
BOOST_ASSERT_MSG(((mode == TEST_HAL_INPUT) || (mode == TEST_HAL_OUTPUT)), "Invalid pin mode");
|
||||
|
||||
// set mode
|
||||
this->gpio[pin].mode = mode;
|
||||
}
|
||||
|
||||
void digitalWrite(uint32_t pin, uint32_t value) override {
|
||||
HAL_LOG("TestHal::digitalWrite(pin=" << pin << ", value=" << value << " [" << ((value == TEST_HAL_LOW) ? "LOW" : "HIGH") << "])");
|
||||
|
||||
// check the range
|
||||
BOOST_ASSERT_MSG(pin < TEST_HAL_NUM_GPIO_PINS, "Pin number out of range");
|
||||
|
||||
// check it is output
|
||||
BOOST_ASSERT_MSG(this->gpio[pin].mode == TEST_HAL_OUTPUT, "GPIO is not output!");
|
||||
|
||||
// check known values
|
||||
BOOST_ASSERT_MSG(((value == TEST_HAL_LOW) || (value == TEST_HAL_HIGH)), "Invalid output value");
|
||||
|
||||
// set value
|
||||
this->gpio[pin].value = value;
|
||||
this->gpio[pin].event = true;
|
||||
if(radio) {
|
||||
this->radio->HandleGPIO();
|
||||
}
|
||||
this->gpio[pin].event = false;
|
||||
}
|
||||
|
||||
uint32_t digitalRead(uint32_t pin) override {
|
||||
HAL_LOG("TestHal::digitalRead(pin=" << pin << ")");
|
||||
|
||||
// check the range
|
||||
BOOST_ASSERT_MSG(pin < TEST_HAL_NUM_GPIO_PINS, "Pin number out of range");
|
||||
|
||||
// check it is input
|
||||
BOOST_ASSERT_MSG(this->gpio[pin].mode == TEST_HAL_INPUT, "GPIO is not input");
|
||||
|
||||
// read the value
|
||||
uint32_t value = this->gpio[pin].value;
|
||||
HAL_LOG("TestHal::digitalRead(pin=" << pin << ")=" << value << " [" << ((value == TEST_HAL_LOW) ? "LOW" : "HIGH") << "]");
|
||||
return(value);
|
||||
}
|
||||
|
||||
void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override {
|
||||
HAL_LOG("TestHal::attachInterrupt(interruptNum=" << interruptNum << ", interruptCb=" << interruptCb << ", mode=" << mode << ")");
|
||||
}
|
||||
|
||||
void detachInterrupt(uint32_t interruptNum) override {
|
||||
HAL_LOG("TestHal::detachInterrupt(interruptNum=" << interruptNum << ")");
|
||||
}
|
||||
|
||||
void delay(unsigned long ms) override {
|
||||
HAL_LOG("TestHal::delay(ms=" << ms << ")");
|
||||
const auto start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
// sleep_for is sufficient for ms-precision sleep
|
||||
std::this_thread::sleep_for(std::chrono::duration<unsigned long, std::milli>(ms));
|
||||
|
||||
// measure and print
|
||||
const auto end = std::chrono::high_resolution_clock::now();
|
||||
const std::chrono::duration<double, std::milli> elapsed = end - start;
|
||||
HAL_LOG("TestHal::delay(ms=" << ms << ")=" << elapsed.count() << "ms");
|
||||
}
|
||||
|
||||
void delayMicroseconds(unsigned long us) override {
|
||||
HAL_LOG("TestHal::delayMicroseconds(us=" << us << ")");
|
||||
const auto start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
// busy wait is needed for microseconds precision
|
||||
const auto len = std::chrono::microseconds(us);
|
||||
while(std::chrono::high_resolution_clock::now() - start < len);
|
||||
|
||||
// measure and print
|
||||
const auto end = std::chrono::high_resolution_clock::now();
|
||||
const std::chrono::duration<double, std::micro> elapsed = end - start;
|
||||
HAL_LOG("TestHal::delayMicroseconds(us=" << us << ")=" << elapsed.count() << "us");
|
||||
}
|
||||
|
||||
void yield() override {
|
||||
HAL_LOG("TestHal::yield()");
|
||||
}
|
||||
|
||||
unsigned long millis() override {
|
||||
HAL_LOG("TestHal::millis()");
|
||||
std::chrono::time_point now = std::chrono::high_resolution_clock::now();
|
||||
auto res = std::chrono::duration_cast<std::chrono::milliseconds>(now - this->start);
|
||||
HAL_LOG("TestHal::millis()=" << res.count());
|
||||
return(res.count());
|
||||
}
|
||||
|
||||
unsigned long micros() override {
|
||||
HAL_LOG("TestHal::micros()");
|
||||
std::chrono::time_point now = std::chrono::high_resolution_clock::now();
|
||||
auto res = std::chrono::duration_cast<std::chrono::microseconds>(now - this->start);
|
||||
HAL_LOG("TestHal::micros()=" << res.count());
|
||||
return(res.count());
|
||||
}
|
||||
|
||||
long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override {
|
||||
HAL_LOG("TestHal::pulseIn(pin=" << pin << ", state=" << state << ", timeout=" << timeout << ")");
|
||||
return(0);
|
||||
}
|
||||
|
||||
void spiBegin() {
|
||||
HAL_LOG("TestHal::spiBegin()");
|
||||
}
|
||||
|
||||
void spiBeginTransaction() {
|
||||
HAL_LOG("TestHal::spiBeginTransaction()");
|
||||
|
||||
// wipe history log
|
||||
memset(this->spiLog, 0x00, TEST_HAL_SPI_LOG_LENGTH);
|
||||
this->spiLogPtr = this->spiLog;
|
||||
}
|
||||
|
||||
void spiTransfer(uint8_t* out, size_t len, uint8_t* in) {
|
||||
HAL_LOG("TestHal::spiTransfer(len=" << len << ")");
|
||||
|
||||
for(size_t i = 0; i < len; i++) {
|
||||
// append to log
|
||||
(*this->spiLogPtr++) = out[i];
|
||||
|
||||
// process the SPI byte
|
||||
in[i] = this->radio->HandleSPI(out[i]);
|
||||
|
||||
// outpu debug
|
||||
HAL_LOG(fmt::format("out={:#02x}, in={:#02x}", out[i], in[i]));
|
||||
}
|
||||
}
|
||||
|
||||
void spiEndTransaction() {
|
||||
HAL_LOG("TestHal::spiEndTransaction()");
|
||||
}
|
||||
|
||||
void spiEnd() {
|
||||
HAL_LOG("TestHal::spiEnd()");
|
||||
}
|
||||
|
||||
void tone(uint32_t pin, unsigned int frequency, unsigned long duration = 0) {
|
||||
HAL_LOG("TestHal::tone(pin=" << pin << ", frequency=" << frequency << ", duration=" << duration << ")");
|
||||
}
|
||||
|
||||
void noTone(uint32_t pin) {
|
||||
HAL_LOG("TestHal::noTone(pin=" << pin << ")");
|
||||
}
|
||||
|
||||
// method to compare buffer to the internal SPI log, for verifying SPI transactions
|
||||
int spiLogMemcmp(const void* in, size_t n) {
|
||||
return(memcmp(this->spiLog, in, n));
|
||||
}
|
||||
|
||||
// method that "connects" the emualted radio hardware to this HAL
|
||||
void connectRadio(EmulatedRadio* r) {
|
||||
this->radio = r;
|
||||
this->radio->connect(&this->gpio[EMULATED_RADIO_NSS_PIN],
|
||||
&this->gpio[EMULATED_RADIO_IRQ_PIN],
|
||||
&this->gpio[EMULATED_RADIO_RST_PIN],
|
||||
&this->gpio[EMULATED_RADIO_GPIO_PIN]);
|
||||
}
|
||||
|
||||
private:
|
||||
// array of emulated GPIO pins
|
||||
EmulatedPin_t gpio[TEST_HAL_NUM_GPIO_PINS];
|
||||
|
||||
// start time point
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> start;
|
||||
|
||||
// emulated radio hardware
|
||||
EmulatedRadio* radio;
|
||||
|
||||
// SPI history log
|
||||
uint8_t spiLog[TEST_HAL_SPI_LOG_LENGTH];
|
||||
uint8_t* spiLogPtr;
|
||||
};
|
||||
|
||||
#endif
|
||||
13
RadioLib/extras/test/unit/test.sh
Normal file
13
RadioLib/extras/test/unit/test.sh
Normal file
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# build the test binary
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake -G "CodeBlocks - Unix Makefiles" ..
|
||||
make -j4
|
||||
|
||||
# run it
|
||||
cd ..
|
||||
./build/radiolib-unittest --log_level=message
|
||||
103
RadioLib/extras/test/unit/tests/TestModule.cpp
Normal file
103
RadioLib/extras/test/unit/tests/TestModule.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
// boost test header
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
// mock HAL
|
||||
#include "TestHal.hpp"
|
||||
|
||||
// testing fixture
|
||||
struct ModuleFixture {
|
||||
TestHal* hal = nullptr;
|
||||
Module* mod = nullptr;
|
||||
EmulatedRadio* radioHardware = nullptr;
|
||||
|
||||
ModuleFixture() {
|
||||
BOOST_TEST_MESSAGE("--- Module fixture setup ---");
|
||||
hal = new TestHal();
|
||||
radioHardware = new EmulatedRadio();
|
||||
hal->connectRadio(radioHardware);
|
||||
|
||||
mod = new Module(hal, EMULATED_RADIO_NSS_PIN, EMULATED_RADIO_IRQ_PIN, EMULATED_RADIO_RST_PIN, EMULATED_RADIO_GPIO_PIN);
|
||||
mod->init();
|
||||
}
|
||||
|
||||
~ModuleFixture() {
|
||||
BOOST_TEST_MESSAGE("--- Module fixture teardown ---");
|
||||
mod->term();
|
||||
delete[] mod;
|
||||
delete[] hal;
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(suite_Module, ModuleFixture)
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(Module_SPIgetRegValue_reg, ModuleFixture)
|
||||
{
|
||||
BOOST_TEST_MESSAGE("--- Test Module::SPIgetRegValue register access ---");
|
||||
int16_t ret;
|
||||
|
||||
// basic register read with default config
|
||||
const uint8_t address = 0x12;
|
||||
const uint8_t spiTxn[] = { address, 0x00 };
|
||||
ret = mod->SPIgetRegValue(address);
|
||||
|
||||
// check return code, value and history log
|
||||
BOOST_TEST(ret >= RADIOLIB_ERR_NONE);
|
||||
BOOST_TEST(ret == EMULATED_RADIO_SPI_RETURN);
|
||||
BOOST_TEST(hal->spiLogMemcmp(spiTxn, sizeof(spiTxn)) == 0);
|
||||
|
||||
// register read masking test
|
||||
const uint8_t msb = 5;
|
||||
const uint8_t lsb = 1;
|
||||
ret = mod->SPIgetRegValue(address, msb, lsb);
|
||||
BOOST_TEST(ret == 0x3E);
|
||||
|
||||
// invalid mask tests (swapped MSB and LSB, out of range bit masks)
|
||||
ret = mod->SPIgetRegValue(address, lsb, msb);
|
||||
BOOST_TEST(ret == RADIOLIB_ERR_INVALID_BIT_RANGE);
|
||||
ret = mod->SPIgetRegValue(address, 10, lsb);
|
||||
BOOST_TEST(ret == RADIOLIB_ERR_INVALID_BIT_RANGE);
|
||||
ret = mod->SPIgetRegValue(address, msb, 10);
|
||||
BOOST_TEST(ret == RADIOLIB_ERR_INVALID_BIT_RANGE);
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(Module_SPIgetRegValue_stream, ModuleFixture)
|
||||
{
|
||||
BOOST_TEST_MESSAGE("--- Test Module::SPIgetRegValue stream access ---");
|
||||
int16_t ret;
|
||||
|
||||
// change settings to stream type
|
||||
mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16;
|
||||
mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8;
|
||||
mod->spiConfig.statusPos = 1;
|
||||
mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX126X_CMD_READ_REGISTER;
|
||||
mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX126X_CMD_WRITE_REGISTER;
|
||||
mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX126X_CMD_NOP;
|
||||
mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX126X_CMD_GET_STATUS;
|
||||
mod->spiConfig.stream = true;
|
||||
|
||||
// basic register read
|
||||
const uint8_t address = 0x12;
|
||||
const uint8_t spiTxn[] = { RADIOLIB_SX126X_CMD_READ_REGISTER, 0x00, address, 0x00, 0x00 };
|
||||
ret = mod->SPIgetRegValue(address);
|
||||
|
||||
// check return code, value and history log
|
||||
BOOST_TEST(ret >= RADIOLIB_ERR_NONE);
|
||||
BOOST_TEST(ret == EMULATED_RADIO_SPI_RETURN);
|
||||
BOOST_TEST(hal->spiLogMemcmp(spiTxn, sizeof(spiTxn)) == 0);
|
||||
|
||||
// register read masking test
|
||||
const uint8_t msb = 5;
|
||||
const uint8_t lsb = 1;
|
||||
ret = mod->SPIgetRegValue(address, msb, lsb);
|
||||
BOOST_TEST(ret == 0x3E);
|
||||
|
||||
// invalid mask tests (swapped MSB and LSB, out of range bit masks)
|
||||
ret = mod->SPIgetRegValue(address, lsb, msb);
|
||||
BOOST_TEST(ret == RADIOLIB_ERR_INVALID_BIT_RANGE);
|
||||
ret = mod->SPIgetRegValue(address, 10, lsb);
|
||||
BOOST_TEST(ret == RADIOLIB_ERR_INVALID_BIT_RANGE);
|
||||
ret = mod->SPIgetRegValue(address, msb, 10);
|
||||
BOOST_TEST(ret == RADIOLIB_ERR_INVALID_BIT_RANGE);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
5
RadioLib/extras/test/unit/tests/main.cpp
Normal file
5
RadioLib/extras/test/unit/tests/main.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
#define BOOST_TEST_MODULE "RadioLib Unit test"
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
|
||||
// intentionally left blank, boost.test creates its own entrypoint
|
||||
|
||||
Reference in New Issue
Block a user