加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
sx126x-linux.c 19.23 KB
一键复制 编辑 原始数据 按行查看 历史
Lee Lup Yuen 李立源 提交于 2021-10-24 09:12 . Fix SX126xGetDio1PinState
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
// LoRa SX1262 Board Functions for Linux (PineDio USB)
#ifndef ARCH_RISCV // This file is for Linux only
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <assert.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
#include "radio.h"
#include "sx126x.h"
#include "sx126x-board.h"
#if defined( USE_RADIO_DEBUG )
/*!
* \brief Writes new Tx debug pin state
*
* \param [IN] state Debug pin state
*/
static void SX126xDbgPinTxWrite( uint8_t state );
/*!
* \brief Writes new Rx debug pin state
*
* \param [IN] state Debug pin state
*/
static void SX126xDbgPinRxWrite( uint8_t state );
#endif
/*!
* \brief Holds the internal operating mode of the radio
*/
static RadioOperatingModes_t OperatingMode;
/*!
* Antenna switch GPIO pins objects
*/
Gpio_t AntPow;
Gpio_t DeviceSel;
/*!
* Debug GPIO pins objects
*/
#if defined( USE_RADIO_DEBUG )
Gpio_t DbgPinTx;
Gpio_t DbgPinRx;
#endif
static int sx126x_write_register( const void* context, const uint16_t address, const uint8_t* buffer, const uint8_t size );
static int sx126x_read_register( const void* context, const uint16_t address, uint8_t* buffer, const uint8_t size );
static int sx126x_write_buffer( const void* context, const uint8_t offset, const uint8_t* buffer, const uint8_t size );
static int sx126x_read_buffer( const void* context, const uint8_t offset, uint8_t* buffer, const uint8_t size );
static int sx126x_hal_write(
const void* context, const uint8_t* command, const uint16_t command_length,
const uint8_t* data, const uint16_t data_length );
static int sx126x_hal_read(
const void* context, const uint8_t* command, const uint16_t command_length,
uint8_t* data, const uint16_t data_length, uint8_t *status );
static int init_spi(void);
///////////////////////////////////////////////////////////////////////////////
/// Initialise GPIO Pins and SPI Port. Called by SX126xIoIrqInit.
/// Note: This is different from the Reference Implementation,
/// which initialises the GPIO Pins and SPI Port at startup.
void SX126xIoInit( void )
{
printf("SX126xIoInit\r\n");
// Init SPI Bus
int rc = init_spi();
assert(rc == 0);
// TODO: Init GPIO Pins
}
/// Initialise GPIO Pins and SPI Port. Register GPIO Interrupt Handler for DIO1.
/// Note: This is different from the Reference Implementation,
/// which initialises the GPIO Pins and SPI Port at startup.
void SX126xIoIrqInit( DioIrqHandler dioIrq )
{
// Initialise GPIO Pins and SPI Port.
// Note: This is different from the Reference Implementation,
// which initialises the GPIO Pins and SPI Port at startup.
SX126xIoInit();
// TODO: Register GPIO Interrupt Handler for DIO1
printf("TODO: SX126X interrupt init\r\n");
}
void SX126xIoDeInit( void )
{
printf("SX126xIoDeInit\r\n");
}
void SX126xIoDbgInit( void )
{
#if defined( USE_RADIO_DEBUG )
GpioInitOutput( SX126X_DBG_PIN_TX, 0 );
GpioInitOutput( SX126X_DBG_PIN_RX, 0 );
#endif
}
void SX126xIoTcxoInit( void )
{
// No TCXO component available on this board design.
}
uint32_t SX126xGetBoardTcxoWakeupTime( void )
{
return SX126X_TCXO_WAKEUP_TIME;
}
void SX126xIoRfSwitchInit( void )
{
SX126xSetDio2AsRfSwitchCtrl( true );
}
RadioOperatingModes_t SX126xGetOperatingMode( void )
{
return OperatingMode;
}
void SX126xSetOperatingMode( RadioOperatingModes_t mode )
{
OperatingMode = mode;
#if defined( USE_RADIO_DEBUG )
switch( mode )
{
case MODE_TX:
SX126xDbgPinTxWrite( 1 );
SX126xDbgPinRxWrite( 0 );
break;
case MODE_RX:
case MODE_RX_DC:
SX126xDbgPinTxWrite( 0 );
SX126xDbgPinRxWrite( 1 );
break;
default:
SX126xDbgPinTxWrite( 0 );
SX126xDbgPinRxWrite( 0 );
break;
}
#endif
}
void SX126xReset(void)
{
//// #warning Check SX126xReset
printf("TODO: SX126xReset\r\n");
#ifdef TODO
// Set Reset pin to Low
rc = bl_gpio_output_set(SX126X_NRESET, 1);
assert(rc == 0);
// Wait 1 ms
DelayMs(1);
// Configure Reset pin as a GPIO Input Pin, no pullup, no pulldown
rc = bl_gpio_enable_input(SX126X_NRESET, 0, 0);
assert(rc == 0);
// Wait 6 ms
DelayMs(6);
#endif // TODO
}
void SX126xWaitOnBusy( void )
{
printf("TODO: SX126xWaitOnBusy\r\n");
// TODO: Fix the GPIO check for busy state.
// Meanwhile we sleep 10 milliseconds.
usleep(10 * 1000);
#ifdef TODO
while( bl_gpio_input_get_value( SX126X_BUSY_PIN ) == 1 );
#endif // TODO
}
void SX126xWakeup( void )
{
printf("SX126xWakeup\r\n");
CRITICAL_SECTION_BEGIN( );
// Write RADIO_GET_STATUS command followed by 0
uint8_t commands[1] = { RADIO_GET_STATUS };
uint8_t buffer[1] = { 0 };
int rc = sx126x_hal_write(NULL, commands, sizeof(commands), buffer, sizeof(buffer));
assert(rc == 0);
// Wait for chip to be ready.
SX126xWaitOnBusy( );
// Update operating mode context variable
SX126xSetOperatingMode( MODE_STDBY_RC );
CRITICAL_SECTION_END( );
}
void SX126xWriteCommand( RadioCommands_t command, uint8_t *buffer, uint16_t size )
{
SX126xCheckDeviceReady( );
// Write the command followed by buffer
uint8_t commands[1] = { (uint8_t) command };
int rc = sx126x_hal_write(NULL, commands, sizeof(commands), buffer, size);
assert(rc == 0);
if( command != RADIO_SET_SLEEP )
{
SX126xWaitOnBusy( );
}
}
uint8_t SX126xReadCommand( RadioCommands_t command, uint8_t *buffer, uint16_t size )
{
printf("SX126xReadCommand: command=0x%02x, size=%d\r\n", command, size);
uint8_t status = 0;
SX126xCheckDeviceReady( );
// Write the command, read the status and read the buffer
uint8_t commandStatus[2] = {
(uint8_t) command, // Command
0 // Status
};
int rc = sx126x_hal_read(NULL, commandStatus, sizeof(commandStatus), buffer, size, &status);
assert(rc == 0);
printf("status=0x%02x\n", status);
#ifdef NOTUSED // Previously...
bl_gpio_output_set( SX126X_SPI_CS_PIN, 0 );
if (SX126X_DEBUG_CS_PIN >= 0) { bl_gpio_output_set( SX126X_DEBUG_CS_PIN, 0 ); }
SpiInOut( SX126X_SPI_IDX, ( uint8_t )command );
status = SpiInOut( SX126X_SPI_IDX, 0x00 );
for( uint16_t i = 0; i < size; i++ )
{
buffer[i] = SpiInOut( SX126X_SPI_IDX, 0 );
}
bl_gpio_output_set( SX126X_SPI_CS_PIN, 1 );
if (SX126X_DEBUG_CS_PIN >= 0) { bl_gpio_output_set( SX126X_DEBUG_CS_PIN, 1 ); }
#endif // NOTUSED
SX126xWaitOnBusy( );
return status;
}
void SX126xWriteRegisters( uint16_t address, uint8_t *buffer, uint16_t size )
{
SX126xCheckDeviceReady( );
int rc = sx126x_write_register(NULL, address, buffer, size);
assert(rc == 0);
SX126xWaitOnBusy( );
}
void SX126xWriteRegister( uint16_t address, uint8_t value )
{
SX126xWriteRegisters( address, &value, 1 );
}
void SX126xReadRegisters( uint16_t address, uint8_t *buffer, uint16_t size )
{
SX126xCheckDeviceReady( );
int rc = sx126x_read_register(NULL, address, buffer, size);
assert(rc == 0);
SX126xWaitOnBusy( );
}
uint8_t SX126xReadRegister( uint16_t address )
{
uint8_t data;
SX126xReadRegisters( address, &data, 1 );
return data;
}
void SX126xWriteBuffer( uint8_t offset, uint8_t *buffer, uint8_t size )
{
SX126xCheckDeviceReady( );
int rc = sx126x_write_buffer(NULL, offset, buffer, size);
assert(rc == 0);
SX126xWaitOnBusy( );
}
void SX126xReadBuffer( uint8_t offset, uint8_t *buffer, uint8_t size )
{
SX126xCheckDeviceReady( );
int rc = sx126x_read_buffer(NULL, offset, buffer, size);
assert(rc == 0);
SX126xWaitOnBusy( );
}
void SX126xSetRfTxPower( int8_t power )
{
printf("SX126xSetRfTxPower\r\n");
////TODO: SX126xSetTxParams( power, RADIO_RAMP_40_US );
SX126xSetTxParams( power, RADIO_RAMP_3400_US );////TODO
}
uint8_t SX126xGetDeviceId( void )
{
// For SX1262
printf("SX126xGetDeviceId: SX1262\r\n");
return SX1262;
// For SX1261
// printf("SX126xGetDeviceId: SX1261\r\n");
// return SX1261;
}
void SX126xAntSwOn( void )
{
#if SX126X_HAS_ANT_SW
GpioInit( &AntPow, RADIO_ANT_SWITCH_POWER, PIN_OUTPUT, PIN_PUSH_PULL, PIN_PULL_UP, 1 );
#endif // SX126X_HAS_ANT_SW
}
void SX126xAntSwOff( void )
{
#if SX126X_HAS_ANT_SW
GpioInit( &AntPow, RADIO_ANT_SWITCH_POWER, PIN_ANALOGIC, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
#endif // SX126X_HAS_ANT_SW
}
bool SX126xCheckRfFrequency( uint32_t frequency )
{
// Implement check. Currently all frequencies are supported
return true;
}
uint32_t SX126xGetDio1PinState( void )
{
puts("TODO: SX126xGetDio1PinState");
return 0;
#ifdef TODO
return bl_gpio_input_get_value( SX126X_DIO1 );
#endif // TODO
}
#if defined( USE_RADIO_DEBUG )
static void SX126xDbgPinTxWrite( uint8_t state )
{
bl_gpio_output_set( SX126X_DBG_PIN_TX, state );
}
static void SX126xDbgPinRxWrite( uint8_t state )
{
bl_gpio_output_set( SX126X_DBG_PIN_RX, state );
}
#endif
///////////////////////////////////////////////////////////////////////////////
// Timer Functions
/// Initialise a timer
void TimerInit(
struct ble_npl_callout *timer, // The timer to initialize. Cannot be NULL.
ble_npl_event_fn *f) // The timer callback function. Cannot be NULL.
{
puts("TimerInit");
assert(timer != NULL);
assert(f != NULL);
// Event Queue containing Events to be processed, defined in demo.c. TODO: Move to header file.
extern struct ble_npl_eventq event_queue;
// Init the Callout Timer with the Callback Function
ble_npl_callout_init(
timer, // Callout Timer
&event_queue, // Event Queue that will handle the Callout upon timeout
f, // Callback Function
NULL // Argument to be passed to Callback Function
);
}
/// Stops a timer from running. Can be called even if timer is not running.
void TimerStop(
struct ble_npl_callout *timer) // Pointer to timer to stop. Cannot be NULL.
{
puts("TimerStop");
assert(timer != NULL);
// If Callout Timer is still running...
if (ble_npl_callout_is_active(timer)) {
// Stop the Callout Timer
ble_npl_callout_stop(timer);
}
}
/// Sets a timer that will expire ‘millisecs’ milliseconds from the current time.
void TimerStart(
struct ble_npl_callout *timer, // Pointer to timer. Cannot be NULL.
uint32_t millisecs) // The number of milliseconds from now at which the timer will expire.
{
puts("TimerStart");
assert(timer != NULL);
// Stop the timer if running
TimerStop(timer);
// Convert milliseconds to ticks
ble_npl_time_t ticks = ble_npl_time_ms_to_ticks32(
millisecs // Duration in milliseconds
);
// Wait at least 1 tick
if (ticks == 0) { ticks = 1; }
// Trigger the Callout Timer after the elapsed ticks
ble_npl_error_t rc = ble_npl_callout_reset(
timer, // Callout Timer
ticks // Number of ticks
);
assert(rc == 0);
}
/// Wait until ‘millisecs’ milliseconds has elapsed. This is a blocking delay.
void DelayMs(uint32_t millisecs) // The number of milliseconds to wait.
{
// Implement with Timer Functions from NimBLE Porting Layer.
// Convert milliseconds to ticks.
ble_npl_time_t ticks = ble_npl_time_ms_to_ticks32(
millisecs // Duration in milliseconds
);
// Wait at least 1 tick
if (ticks == 0) { ticks = 1; }
// Wait for the ticks
ble_npl_time_delay(ticks);
}
/// Return current time in microseconds
uint32_t TimerGetCurrentTime(void)
{
assert(false); return 0;
#ifdef TODO
// Convert ticks to milliseconds then microseconds
return xTaskGetTickCount() * portTICK_PERIOD_MS * 1000;
#endif // TODO
}
/// Return elased time in microseconds
uint32_t TimerGetElapsedTime(uint32_t saved_time)
{
assert(false); return 0;
#ifdef TODO
return TimerGetCurrentTime() - saved_time;
#endif // TODO
}
///////////////////////////////////////////////////////////////////////////////
// Register and Buffer Functions
/**
* Commands Interface buffer sizes
*/
typedef enum sx126x_commands_size_e
{
// Registers and buffer Access
// Full size: this value plus buffer size
SX126X_SIZE_WRITE_REGISTER = 3,
// Full size: this value plus buffer size
SX126X_SIZE_READ_REGISTER = 4,
// Full size: this value plus buffer size
SX126X_SIZE_WRITE_BUFFER = 2,
// Full size: this value plus buffer size
SX126X_SIZE_READ_BUFFER = 3,
} sx126x_commands_size_t;
static int sx126x_write_register( const void* context, const uint16_t address, const uint8_t* buffer,
const uint8_t size ) {
uint8_t buf[SX126X_SIZE_WRITE_REGISTER] = { 0 };
buf[0] = RADIO_WRITE_REGISTER;
buf[1] = ( uint8_t )( address >> 8 );
buf[2] = ( uint8_t )( address >> 0 );
return sx126x_hal_write( context, buf, SX126X_SIZE_WRITE_REGISTER, buffer, size );
}
static int sx126x_read_register( const void* context, const uint16_t address, uint8_t* buffer, const uint8_t size ) {
uint8_t buf[SX126X_SIZE_READ_REGISTER] = { 0 };
int status = -1;
buf[0] = RADIO_READ_REGISTER;
buf[1] = ( uint8_t )( address >> 8 );
buf[2] = ( uint8_t )( address >> 0 );
buf[3] = 0;
status = sx126x_hal_read( context, buf, SX126X_SIZE_READ_REGISTER, buffer, size, NULL );
return status;
}
static int sx126x_write_buffer( const void* context, const uint8_t offset, const uint8_t* buffer,
const uint8_t size ) {
uint8_t buf[SX126X_SIZE_WRITE_BUFFER] = { 0 };
buf[0] = RADIO_WRITE_BUFFER;
buf[1] = offset;
return sx126x_hal_write( context, buf, SX126X_SIZE_WRITE_BUFFER, buffer, size );
}
static int sx126x_read_buffer( const void* context, const uint8_t offset, uint8_t* buffer, const uint8_t size ) {
uint8_t buf[SX126X_SIZE_READ_BUFFER] = { 0 };
int status = -1;
buf[0] = RADIO_READ_BUFFER;
buf[1] = offset;
buf[2] = 0;
status = sx126x_hal_read( context, buf, SX126X_SIZE_READ_BUFFER, buffer, size, NULL );
return status;
}
///////////////////////////////////////////////////////////////////////////////
// SPI Functions
/// SPI Bus
static int spi = 0;
/// Max size of SPI transfers
#define SPI_BUFFER_SIZE 1024
/// SPI Transmit Buffer
static uint8_t spi_tx_buf[SPI_BUFFER_SIZE];
/// SPI Receive Buffer
static uint8_t spi_rx_buf[SPI_BUFFER_SIZE];
static int transfer_spi(const uint8_t *tx_buf, uint8_t *rx_buf, uint16_t len);
/**
* Radio data transfer - write
*
* @remark Shall be implemented by the user
*
* @param [in] context Radio implementation parameters
* @param [in] command Pointer to the buffer to be transmitted
* @param [in] command_length Buffer size to be transmitted
* @param [in] data Pointer to the buffer to be transmitted
* @param [in] data_length Buffer size to be transmitted
*
* @returns Operation status
*/
static int sx126x_hal_write(
const void* context, const uint8_t* command, const uint16_t command_length,
const uint8_t* data, const uint16_t data_length ) {
printf("sx126x_hal_write: command_length=%d, data_length=%d\n", command_length, data_length);
// Total length is command + data length
uint16_t len = command_length + data_length;
assert(len > 0);
assert(len <= SPI_BUFFER_SIZE);
// Clear the SPI Transmit and Receive buffers
memset(&spi_tx_buf, 0, len);
memset(&spi_rx_buf, 0, len);
// Copy command bytes to SPI Transmit Buffer
memcpy(&spi_tx_buf, command, command_length);
// Copy data bytes to SPI Transmit Buffer
memcpy(&spi_tx_buf[command_length], data, data_length);
// Transmit and receive the SPI buffers
int rc = transfer_spi(spi_tx_buf, spi_rx_buf, len);
assert(rc == 0);
return 0;
}
/**
* Radio data transfer - read
*
* @remark Shall be implemented by the user
*
* @param [in] context Radio implementation parameters
* @param [in] command Pointer to the buffer to be transmitted
* @param [in] command_length Buffer size to be transmitted
* @param [in] data Pointer to the buffer to be received
* @param [in] data_length Buffer size to be received
* @param [out] status If not null, return the second SPI byte received as status
*
* @returns Operation status
*/
static int sx126x_hal_read(
const void* context, const uint8_t* command, const uint16_t command_length,
uint8_t* data, const uint16_t data_length, uint8_t *status ) {
printf("sx126x_hal_read: command_length=%d, data_length=%d\n", command_length, data_length);
// Total length is command + data length
uint16_t len = command_length + data_length;
assert(len > 0);
assert(len <= SPI_BUFFER_SIZE);
// Clear the SPI Transmit and Receive buffers
memset(&spi_tx_buf, 0, len);
memset(&spi_rx_buf, 0, len);
// Copy command bytes to SPI Transmit Buffer
memcpy(&spi_tx_buf, command, command_length);
// Transmit and receive the SPI buffers
int rc = transfer_spi(spi_tx_buf, spi_rx_buf, len);
assert(rc == 0);
// Copy SPI Receive buffer to data buffer
memcpy(data, &spi_rx_buf[command_length], data_length);
// Return the second SPI byte received as status
if (status != NULL) {
assert(len >= 2);
*status = spi_rx_buf[1];
}
return 0;
}
#ifdef TODO
/**
* Reset the radio
*
* @remark Shall be implemented by the user
*
* @param [in] context Radio implementation parameters
*
* @returns Operation status
*/
static int sx126x_hal_reset( const void* context ) {
puts("sx126x_hal_reset");
assert(false);
return 0;
}
#endif // TODO
#ifdef TODO
/**
* Wake the radio up.
*
* @remark Shall be implemented by the user
*
* @param [in] context Radio implementation parameters
*
* @returns Operation status
*/
static int sx126x_hal_wakeup( const void* context ) {
puts("sx126x_hal_wakeup");
assert(false);
return 0;
}
#endif // TODO
/// Init the SPI Bus. Return 0 on success.
static int init_spi(void) {
// Open the SPI Bus
spi = open("/dev/spidev1.0", O_RDWR);
assert(spi > 0);
// Set to SPI Mode 0
uint8_t mmode = SPI_MODE_0;
int rc = ioctl(spi, SPI_IOC_WR_MODE, &mmode);
assert(rc == 0);
// Set LSB/MSB Mode
uint8_t lsb = 0;
rc = ioctl(spi, SPI_IOC_WR_LSB_FIRST, &lsb);
assert(rc == 0);
return 0;
}
/// Blocking call to transmit and receive buffers on SPI. Return 0 on success.
static int transfer_spi(const uint8_t *tx_buf, uint8_t *rx_buf, uint16_t len) {
assert(spi > 0);
assert(len > 0);
assert(len <= 31); // CAUTION: CH341 SPI doesn't seem to support 32-byte SPI transfers
// Prepare SPI Transfer
struct spi_ioc_transfer spi_trans;
memset(&spi_trans, 0, sizeof(spi_trans));
spi_trans.tx_buf = (unsigned long) tx_buf; // Transmit Buffer
spi_trans.rx_buf = (unsigned long) rx_buf; // Receive Buffer
spi_trans.cs_change = true; // Set SPI Chip Select to Low
spi_trans.len = len; // How many bytes
printf("spi tx: "); for (int i = 0; i < len; i++) { printf("%02x ", tx_buf[i]); } printf("\n");
// Transfer and receive the SPI buffers
int rc = ioctl(spi, SPI_IOC_MESSAGE(1), &spi_trans);
assert(rc >= 0);
assert(rc == len);
printf("spi rx: "); for (int i = 0; i < len; i++) { printf("%02x ", rx_buf[i]); } printf("\n");
return 0;
}
#endif // !ARCH_RISCV
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化