mirror of
https://github.com/peter-tanner/neptunium-firmware.git
synced 2024-11-30 20:10:19 +08:00
291 lines
11 KiB
C
291 lines
11 KiB
C
#include "radio.h"
|
|
|
|
void lora_direction()
|
|
{
|
|
}
|
|
|
|
void check_status(volatile uint8_t status)
|
|
{
|
|
if (SX126X_STATUS_OK != status)
|
|
HALT_BKPT();
|
|
}
|
|
|
|
struct sx126x_ctx
|
|
{
|
|
} ctx;
|
|
|
|
void lora_rx_data(void);
|
|
|
|
uint8_t rx_buf[256]; // MAXIMUM RECEIVE SIZE OF 256 FOR LORA
|
|
|
|
void lora_setup(uint8_t enable_reg)
|
|
{
|
|
if (!enable_reg)
|
|
return;
|
|
|
|
// 1. If not in STDBY_RC mode, then go to this mode with the command SetStandby(...)
|
|
sx126x_chip_status_t radio_status;
|
|
if (sx126x_get_status(&ctx, &radio_status) == SX126X_STATUS_OK)
|
|
{
|
|
check_status(sx126x_set_standby(&ctx, SX126X_STANDBY_CFG_RC));
|
|
}
|
|
else
|
|
HALT_BKPT();
|
|
|
|
volatile uint32_t number = 0;
|
|
sx126x_get_random_numbers(&ctx, &number, 1);
|
|
|
|
// 2. Define the protocol (LoRa® or FSK) with the command SetPacketType(...)
|
|
check_status(sx126x_set_pkt_type(&ctx, SX126X_PKT_TYPE_LORA));
|
|
|
|
// 3. Define the RF frequency with the command SetRfFrequency(...)
|
|
check_status(sx126x_set_rf_freq(&ctx, FREQUENCY));
|
|
|
|
// ENABLE DC-DC CONVERTER
|
|
check_status(sx126x_set_reg_mode(&ctx, SX126X_REG_MODE_DCDC));
|
|
|
|
if (enable_reg & EN_TX)
|
|
{
|
|
// 4. Define the Power Amplifier configuration with the command SetPaConfig(...)
|
|
// FROM DATASHEET:
|
|
// Table 13-21: PA Operating Modes with Optimal Settings
|
|
// Mode Output Power paDutyCycle hpMax deviceSel paLut Value in SetTxParams1
|
|
// SX1262 +22 dBm 0x04 0x07 0x00 0x01 +22 dBm
|
|
// Note:
|
|
// These changes make the use of nominal power either sub-optimal or unachievable.
|
|
// Caution!
|
|
// The following restrictions must be observed to avoid voltage overstress on the PA, exceeding the maximum ratings
|
|
// may cause irreversible damage to the device:
|
|
// • For SX1261 at synthesis frequency above 400 MHz, paDutyCycle should not be higher than 0x07.
|
|
// • For SX1261 at synthesis frequency below 400 MHz, paDutyCycle should not be higher than 0x04.
|
|
// • For SX1262, paDutyCycle should not be higher than 0x04.
|
|
sx126x_pa_cfg_params_t pa_params = {
|
|
.pa_duty_cycle = 0x04,
|
|
.hp_max = 0x07,
|
|
.device_sel = 0x00,
|
|
.pa_lut = 0x01};
|
|
check_status(sx126x_set_pa_cfg(&ctx, &pa_params));
|
|
|
|
// 5. Define output power and ramping time with the command SetTxParams(...)
|
|
sx126x_set_tx_params(&ctx, TX_PWR, RAMP_TIME);
|
|
}
|
|
if (enable_reg & EN_RX)
|
|
{
|
|
// ENABLE RX BOOSTED MODE
|
|
check_status(sx126x_cfg_rx_boosted(&ctx, true));
|
|
}
|
|
|
|
// 6. Define where the data payload will be stored with the command SetBufferBaseAddress(...)
|
|
check_status(sx126x_set_buffer_base_address(&ctx, 0x00, 0x00));
|
|
|
|
// ~~7. Send the payload to the data buffer with the command WriteBuffer(...)~~
|
|
|
|
// 8. Define the modulation parameter according to the chosen protocol with the command SetModulationParams(...)1
|
|
sx126x_mod_params_lora_t lora_mod_params = {
|
|
.sf = SX126X_LORA_SF7,
|
|
.bw = SX126X_LORA_BW_125,
|
|
.cr = SX126X_LORA_CR_4_5,
|
|
.ldro = 0x00};
|
|
check_status(sx126x_set_lora_mod_params(&ctx, &lora_mod_params));
|
|
|
|
// 9. Define the frame format to be used with the command SetPacketParams(...)2
|
|
// USED FOR RECEIVING - CALLED AGAIN WITH PROPER LENGTH DURING TX
|
|
sx126x_pkt_params_lora_t lora_pkt_params = {
|
|
.preamble_len_in_symb = 8,
|
|
.header_type = SX126X_LORA_PKT_EXPLICIT,
|
|
.pld_len_in_bytes = 0xFF,
|
|
.crc_is_on = true,
|
|
.invert_iq_is_on = false};
|
|
check_status(sx126x_set_lora_pkt_params(&ctx, &lora_pkt_params));
|
|
|
|
// 10. Configure DIO and IRQ: use the command SetDioIrqParams(...) to select TxDone IRQ and map this IRQ to a DIO (DIO1, DIO2 or DIO3)
|
|
// 7. Configure DIO and irq: use the command SetDioIrqParams(...) to select the IRQ RxDone and map this IRQ to a DIO (DIO1 or DIO2 or DIO3), set IRQ Timeout as well.
|
|
// ENABLE TCXO SOURCE ON DIO3
|
|
// TODO: CHECK IF THIS REQUIRES EXTERNAL 3.3V OR IF THE XTAL IS BUILT INTO THE MODULE).
|
|
// TIMEOUT = DELAY * 15.625 μs = 1.5625 ms
|
|
check_status(sx126x_set_dio3_as_tcxo_ctrl(&ctx, SX126X_TCXO_CTRL_3_3V, 100));
|
|
// ENABLE RF SWITCH ON DIO2
|
|
check_status(sx126x_set_dio2_as_rf_sw_ctrl(&ctx, true));
|
|
check_status(sx126x_set_tx(&ctx, 1000));
|
|
check_status(sx126x_set_rx(&ctx, 1000));
|
|
check_status(sx126x_set_tx(&ctx, 1000));
|
|
check_status(sx126x_set_rx(&ctx, 1000));
|
|
// ENABLE IRQ ON DIO1
|
|
uint16_t irq_mask = SX126X_IRQ_TIMEOUT | SX126X_IRQ_CRC_ERROR;
|
|
irq_mask |= (enable_reg & EN_RX ? SX126X_IRQ_RX_DONE : 0);
|
|
irq_mask |= (enable_reg & EN_TX ? SX126X_IRQ_TX_DONE : 0);
|
|
check_status(sx126x_set_dio_irq_params(&ctx, irq_mask,
|
|
irq_mask, SX126X_IRQ_NONE, SX126X_IRQ_NONE));
|
|
|
|
// 11. Define Sync Word value: use the command WriteReg(...) to write the value of the register via direct register access
|
|
check_status(sx126x_set_lora_sync_word(&ctx, 0x12));
|
|
|
|
sx126x_errors_mask_t errors = 0;
|
|
// IMAGE CALIBRATION
|
|
// When the 32 MHz clock is coming from a TCXO, the calibration will fail
|
|
// and the user should request a complete calibration after calling the
|
|
// function SetDIO3AsTcxoCtrl(...).
|
|
// Table 9-2: Image Calibration Over the ISM Bands
|
|
// Frequency Band [MHz] Freq1 Freq2
|
|
// 902 - 928 0xE1 (default) 0xE9 (default)
|
|
do
|
|
{
|
|
check_status(sx126x_cal_img(&ctx, 0xE1, 0xE9));
|
|
check_status(sx126x_cal(&ctx, SX126X_CAL_ALL));
|
|
sx126x_get_device_errors(&ctx, &errors);
|
|
} while (errors);
|
|
|
|
// 12. Set the circuit in transmitter mode to start transmission with the command SetTx(). Use the parameter to enable Timeout
|
|
// 9. Set the circuit in reception mode: use the command SetRx(). Set the parameter to enable timeout or continuous mode
|
|
|
|
// 13. Wait for the IRQ TxDone or Timeout: once the packet has been sent the chip goes automatically to STDBY_RC mode
|
|
// 10. Wait for IRQ RxDone2 or Timeout: the chip will stay in Rx and look for a new packet if the continuous mode is selected otherwise it will goes to STDBY_RC mode.
|
|
|
|
// 14. Clear the IRQ TxDone flag
|
|
// 11. In case of the IRQ RxDone, check the status to ensure CRC is correct: use the command GetIrqStatus()
|
|
|
|
// CHECK FOR ERRORS FIXME: it fails
|
|
}
|
|
|
|
void lora_handle_irq(void)
|
|
{
|
|
sx126x_irq_mask_t irq_mask;
|
|
if (sx126x_get_irq_status(&ctx, &irq_mask) == SX126X_STATUS_OK)
|
|
{
|
|
sx126x_clear_irq_status(&ctx, irq_mask);
|
|
if (irq_mask & SX126X_IRQ_TX_DONE)
|
|
__NOP();
|
|
if (irq_mask & SX126X_IRQ_RX_DONE)
|
|
lora_rx_data();
|
|
if (irq_mask & SX126X_IRQ_TIMEOUT)
|
|
__NOP();
|
|
if (irq_mask & SX126X_IRQ_CRC_ERROR)
|
|
__NOP();
|
|
}
|
|
}
|
|
|
|
void lora_rx_data(void)
|
|
{
|
|
// TODO: Should the chip go into standby mode here?
|
|
sx126x_set_standby(&ctx, SX126X_STANDBY_CFG_RC);
|
|
|
|
sx126x_pkt_status_lora_t pkt_status;
|
|
sx126x_get_lora_pkt_status(&ctx, &pkt_status); // TODO: Engineering logs
|
|
|
|
sx126x_rx_buffer_status_t buf_status;
|
|
sx126x_get_rx_buffer_status(&ctx, &buf_status);
|
|
if (buf_status.pld_len_in_bytes > 0)
|
|
{
|
|
sx126x_read_buffer(&ctx, buf_status.buffer_start_pointer, rx_buf, buf_status.pld_len_in_bytes);
|
|
tud_cdc_write(rx_buf, buf_status.pld_len_in_bytes);
|
|
}
|
|
}
|
|
|
|
void lora_tx_data(int8_t power, char *data, uint8_t length)
|
|
{
|
|
// TODO: Should the chip go into standby mode here?
|
|
sx126x_set_standby(&ctx, SX126X_STANDBY_CFG_RC);
|
|
|
|
check_status(sx126x_set_buffer_base_address(&ctx, 0x00, 0x00));
|
|
|
|
sx126x_pkt_params_lora_t lora_pkt_params = {
|
|
.preamble_len_in_symb = 8,
|
|
.header_type = SX126X_LORA_PKT_EXPLICIT,
|
|
.pld_len_in_bytes = length,
|
|
.crc_is_on = true,
|
|
.invert_iq_is_on = false};
|
|
check_status(sx126x_set_lora_pkt_params(&ctx, &lora_pkt_params));
|
|
|
|
check_status(sx126x_write_buffer(&ctx, 0, (uint8_t *)data, length));
|
|
|
|
check_status(sx126x_set_tx(&ctx, SX126X_MAX_TIMEOUT_IN_MS));
|
|
}
|
|
|
|
void lora_rx_mode(void)
|
|
{
|
|
check_status(sx126x_set_rx(&ctx, RADIO_RX_TIMEOUT));
|
|
// TODO: check and handle errors
|
|
}
|
|
|
|
#define SPI_TIMEOUT 1000
|
|
|
|
/**
|
|
* 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
|
|
*/
|
|
sx126x_hal_status_t sx126x_hal_write(const void *context, const uint8_t *command, const uint16_t command_length,
|
|
const uint8_t *data, const uint16_t data_length)
|
|
{
|
|
HAL_StatusTypeDef ok = HAL_OK;
|
|
HAL_GPIO_WritePin(LORA_CS_GPIO_Port, LORA_CS_Pin, GPIO_PIN_RESET);
|
|
ok |= HAL_SPI_Transmit(&hspi3, (uint8_t *)command, command_length, SPI_TIMEOUT);
|
|
if (data != NULL)
|
|
ok |= HAL_SPI_Transmit(&hspi3, (uint8_t *)data, data_length, SPI_TIMEOUT);
|
|
HAL_GPIO_WritePin(LORA_CS_GPIO_Port, LORA_CS_Pin, GPIO_PIN_SET);
|
|
return ok;
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
*
|
|
* @returns Operation status
|
|
*/
|
|
sx126x_hal_status_t sx126x_hal_read(const void *context, const uint8_t *command, const uint16_t command_length,
|
|
uint8_t *data, const uint16_t data_length)
|
|
{
|
|
HAL_StatusTypeDef ok = HAL_OK;
|
|
HAL_GPIO_WritePin(LORA_CS_GPIO_Port, LORA_CS_Pin, GPIO_PIN_RESET);
|
|
ok |= HAL_SPI_Transmit(&hspi3, (uint8_t *)command, command_length, SPI_TIMEOUT);
|
|
ok |= HAL_SPI_Receive(&hspi3, data, data_length, SPI_TIMEOUT);
|
|
HAL_GPIO_WritePin(LORA_CS_GPIO_Port, LORA_CS_Pin, GPIO_PIN_SET);
|
|
return ok;
|
|
}
|
|
|
|
/**
|
|
* Reset the radio
|
|
*
|
|
* @remark Shall be implemented by the user
|
|
*
|
|
* @param [in] context Radio implementation parameters
|
|
*
|
|
* @returns Operation status
|
|
*
|
|
* @warning NOT IMPLEMENTED
|
|
*/
|
|
sx126x_hal_status_t sx126x_hal_reset(const void *context)
|
|
{
|
|
// NOT IMPLEMENTED
|
|
}
|
|
|
|
/**
|
|
* Wake the radio up.
|
|
*
|
|
* @remark Shall be implemented by the user
|
|
*
|
|
* @param [in] context Radio implementation parameters
|
|
*
|
|
* @returns Operation status
|
|
*
|
|
* @warning NOT IMPLEMENTED
|
|
*/
|
|
sx126x_hal_status_t sx126x_hal_wakeup(const void *context)
|
|
{
|
|
// NOT IMPLEMENTED
|
|
} |