kopia lustrzana https://github.com/DL7AD/pecanpico10
Multiple changes:
- Rework packet system event codes - Revise radio manager to support pending changes to 446x driver - Minor updates to documentation - WIP update 446x driver to dynamically configure 4464/4463 chippull/4/head
rodzic
eda158af9b
commit
b363092805
|
@ -122,6 +122,13 @@ void pktSetLineModeICU(void) {
|
|||
palSetLineMode(LINE_ICU, PAL_MODE_INPUT | PAL_MODE_ALTERNATE(2));
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Move this into pktconf.h and use general GPIO to setup.
|
||||
*/
|
||||
void pktSetLineModeRadioCTS(void) {
|
||||
palSetLineMode(LINE_RADIO_GPIO1, PAL_MODE_INPUT_PULLDOWN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read GPIO that are used for:
|
||||
* a) general use or
|
||||
|
|
|
@ -17,11 +17,8 @@
|
|||
* Serial port definitions
|
||||
*/
|
||||
#define SERIAL_CFG_DEBUG_DRIVER &SD3
|
||||
//#define SERIAL_CFG_PACKET_DRIVER &SD4
|
||||
|
||||
|
||||
#define USE_SPI_ATTACHED_RADIO TRUE
|
||||
//#define DUMP_PACKET_TO_SERIAL FALSE
|
||||
//#define USE_SPI_ATTACHED_RADIO TRUE
|
||||
|
||||
/*
|
||||
* TODO: Need to use radio unit ID to set assigned GPIO & SPI.
|
||||
|
@ -277,6 +274,7 @@ extern "C" {
|
|||
void pktConfigSerialPkt(void);
|
||||
void pktConfigureCoreIO(void);
|
||||
void pktSetLineModeICU(void);
|
||||
void pktSetLineModeRadioCTS(void);
|
||||
void pktSerialStart(void);
|
||||
void dbgWrite(uint8_t level, uint8_t *buf, uint32_t len);
|
||||
int dbgPrintf(uint8_t level, const char *format, ...);
|
||||
|
|
|
@ -123,6 +123,13 @@ void pktSetLineModeICU(void) {
|
|||
palSetLineMode(LINE_ICU, PAL_MODE_INPUT | PAL_MODE_ALTERNATE(2));
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Move this into pktconf.h and use general GPIO to setup.
|
||||
*/
|
||||
void pktSetLineModeRadioCTS(void) {
|
||||
palSetLineMode(LINE_RADIO_GPIO1, PAL_MODE_INPUT_PULLDOWN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read GPIO that are used for:
|
||||
* a) general use or
|
||||
|
|
|
@ -17,11 +17,6 @@
|
|||
* Serial port definitions
|
||||
*/
|
||||
#define SERIAL_CFG_DEBUG_DRIVER &SD3
|
||||
//#define SERIAL_CFG_PACKET_DRIVER &SD4
|
||||
|
||||
|
||||
#define USE_SPI_ATTACHED_RADIO TRUE
|
||||
//#define DUMP_PACKET_TO_SERIAL FALSE
|
||||
|
||||
/*
|
||||
* TODO: Need to use radio unit ID to set assigned GPIO & SPI.
|
||||
|
@ -276,6 +271,7 @@ extern "C" {
|
|||
void pktConfigSerialPkt(void);
|
||||
void pktConfigureCoreIO(void);
|
||||
void pktSetLineModeICU(void);
|
||||
void pktSetLineModeRadioCTS(void);
|
||||
void pktSerialStart(void);
|
||||
void dbgWrite(uint8_t level, uint8_t *buf, uint32_t len);
|
||||
int dbgPrintf(uint8_t level, const char *format, ...);
|
||||
|
|
|
@ -16,7 +16,7 @@ int main(void) {
|
|||
pktConfigureCoreIO();
|
||||
|
||||
/* Setup the mutex for trace output. */
|
||||
DEBUG_INIT();
|
||||
//DEBUG_INIT();
|
||||
|
||||
#if ACTIVATE_CONSOLE
|
||||
/* Start console. */
|
||||
|
@ -39,13 +39,15 @@ int main(void) {
|
|||
* Create a packet radio service.
|
||||
* For now there is just one radio.
|
||||
*/
|
||||
if(!pktServiceCreate(PKT_RADIO_1)) {
|
||||
TRACE_ERROR("MAIN > Unable to create packet services");
|
||||
} else {
|
||||
pktEnableEventTrace(PKT_RADIO_1);
|
||||
while(!pktServiceCreate(PKT_RADIO_1)) {
|
||||
TRACE_ERROR("MAIN > Unable to create packet radio services");
|
||||
chThdSleep(TIME_S2I(10));
|
||||
}
|
||||
|
||||
TRACE_INFO("MAIN > Starting threads");
|
||||
pktEnableEventTrace(PKT_RADIO_1);
|
||||
TRACE_INFO("MAIN > Started packet radio service for radio %d", PKT_RADIO_1);
|
||||
|
||||
TRACE_INFO("MAIN > Starting application and ancillary threads");
|
||||
|
||||
// Startup threads
|
||||
start_essential_threads(); // Startup required modules (tracking manager, watchdog)
|
||||
|
|
|
@ -13,7 +13,7 @@ const conf_t conf_flash_default = {
|
|||
// Primary position app
|
||||
.pos_pri = {
|
||||
.beacon = {
|
||||
.active = false,
|
||||
.active = true,
|
||||
.cycle = TIME_S2I(60 * 5),
|
||||
.init_delay = TIME_S2I(60),
|
||||
.fixed = false // Add lat, lon alt fields if enabling fixed
|
||||
|
@ -81,7 +81,7 @@ const conf_t conf_flash_default = {
|
|||
// Secondary image app
|
||||
.img_sec = {
|
||||
.svc_conf = {
|
||||
.active = false,
|
||||
.active = true,
|
||||
.cycle = TIME_S2I(60 * 30),
|
||||
.init_delay = TIME_S2I(60 * 1),
|
||||
.send_spacing = TIME_S2I(30)
|
||||
|
|
|
@ -989,8 +989,8 @@ msg_t OV5640_LockResourcesForCapture(void) {
|
|||
pktLLDradioPauseDecoding(PKT_RADIO_1);
|
||||
//pktPauseDecoding(PKT_RADIO_1);
|
||||
/* Hold TRACE output on USB. */
|
||||
if(isUSBactive())
|
||||
chMtxLock(&trace_mtx);
|
||||
/* if(isUSBactive())
|
||||
chMtxLock(&trace_mtx);*/
|
||||
return MSG_OK;
|
||||
}
|
||||
|
||||
|
@ -999,8 +999,8 @@ msg_t OV5640_LockResourcesForCapture(void) {
|
|||
*/
|
||||
void OV5640_UnlockResourcesForCapture(void) {
|
||||
/* Re-enable TRACE output on USB. */
|
||||
if(isUSBactive())
|
||||
chMtxUnlock(&trace_mtx);
|
||||
/* if(isUSBactive())
|
||||
chMtxUnlock(&trace_mtx);*/
|
||||
I2C_Unlock();
|
||||
/* TODO: have to make this a loop which would handle multiple receivers. */
|
||||
pktLLDradioResumeDecoding(PKT_RADIO_1);
|
||||
|
|
|
@ -27,6 +27,48 @@ static const SPIConfig ls_spicfg = {
|
|||
.cr1 = SPI_CR1_MSTR
|
||||
};
|
||||
|
||||
/**
|
||||
* SPI write which uses CTS on GPIO1.
|
||||
* Use this when first taking radio out of shutdown.
|
||||
* The MCU GPIO pin connected to 446x GPIO1 must be already configured.
|
||||
*/
|
||||
static bool Si446x_writeInit(const uint8_t* txData, uint32_t len) {
|
||||
/* Write data via SPI with CTS checked via GPIO1. */
|
||||
/* TODO: Add radio unit ID and get specific radio SPI driver. */
|
||||
uint8_t null_spi[len];
|
||||
|
||||
/* Acquire bus and then start SPI. */
|
||||
spiAcquireBus(PKT_RADIO_SPI);
|
||||
spiStart(PKT_RADIO_SPI, &ls_spicfg);
|
||||
|
||||
/* Poll for CTS. */
|
||||
uint8_t timeout = 100;
|
||||
do {
|
||||
if(timeout != 100)
|
||||
chThdSleep(TIME_MS2I(1));
|
||||
} while(palReadLine(LINE_RADIO_GPIO1) != PAL_HIGH && timeout--);
|
||||
|
||||
if(!timeout) {
|
||||
TRACE_ERROR("SI > CTS not received");
|
||||
/* Stop SPI and relinquish bus. */
|
||||
spiStop(PKT_RADIO_SPI);
|
||||
spiReleaseBus(PKT_RADIO_SPI);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Transfer data. Discard read back. */
|
||||
spiSelect(PKT_RADIO_SPI);
|
||||
spiExchange(PKT_RADIO_SPI, len, txData, null_spi);
|
||||
spiUnselect(PKT_RADIO_SPI);
|
||||
|
||||
/* Stop SPI and relinquish bus. */
|
||||
spiStop(PKT_RADIO_SPI);
|
||||
spiReleaseBus(PKT_RADIO_SPI);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool Si446x_write(const uint8_t* txData, uint32_t len) {
|
||||
// Transmit data by SPI
|
||||
/* TODO: Add radio unit ID and get specific radio SPI driver. */
|
||||
|
@ -135,160 +177,189 @@ static bool Si446x_read(const uint8_t* txData, uint32_t txlen,
|
|||
return true;
|
||||
}
|
||||
|
||||
/* TODO: Make set property a single func with size parameter. */
|
||||
static void Si446x_setProperty8(uint16_t reg, uint8_t val) {
|
||||
uint8_t msg[] = {0x11, (reg >> 8) & 0xFF, 0x01, reg & 0xFF, val};
|
||||
Si446x_write(msg, 5);
|
||||
uint8_t msg[] = {Si446x_SET_PROPERTY,
|
||||
(reg >> 8) & 0xFF, 0x01, reg & 0xFF, val};
|
||||
Si446x_write(msg, sizeof(msg));
|
||||
}
|
||||
|
||||
static void Si446x_setProperty16(uint16_t reg, uint8_t val1, uint8_t val2) {
|
||||
uint8_t msg[] = {0x11, (reg >> 8) & 0xFF, 0x02, reg & 0xFF, val1, val2};
|
||||
Si446x_write(msg, 6);
|
||||
uint8_t msg[] = {Si446x_SET_PROPERTY,
|
||||
(reg >> 8) & 0xFF, 0x02, reg & 0xFF, val1, val2};
|
||||
Si446x_write(msg, sizeof(msg));
|
||||
}
|
||||
|
||||
static void Si446x_setProperty24(uint16_t reg, uint8_t val1, uint8_t val2, uint8_t val3) {
|
||||
uint8_t msg[] = {0x11, (reg >> 8) & 0xFF, 0x03, reg & 0xFF, val1, val2, val3};
|
||||
Si446x_write(msg, 7);
|
||||
static void Si446x_setProperty24(uint16_t reg, uint8_t val1,
|
||||
uint8_t val2, uint8_t val3) {
|
||||
uint8_t msg[] = {Si446x_SET_PROPERTY,
|
||||
(reg >> 8) & 0xFF, 0x03, reg & 0xFF, val1, val2, val3};
|
||||
Si446x_write(msg, sizeof(msg));
|
||||
}
|
||||
|
||||
static void Si446x_setProperty32(uint16_t reg, uint8_t val1, uint8_t val2, uint8_t val3, uint8_t val4) {
|
||||
uint8_t msg[] = {0x11, (reg >> 8) & 0xFF, 0x04, reg & 0xFF, val1, val2, val3, val4};
|
||||
Si446x_write(msg, 8);
|
||||
static void Si446x_setProperty32(uint16_t reg, uint8_t val1,
|
||||
uint8_t val2, uint8_t val3, uint8_t val4) {
|
||||
uint8_t msg[] = {Si446x_SET_PROPERTY,
|
||||
(reg >> 8) & 0xFF, 0x04, reg & 0xFF,
|
||||
val1, val2, val3, val4};
|
||||
Si446x_write(msg, sizeof(msg));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes Si446x transceiver chip. Adjusts the frequency which is shifted by variable
|
||||
* oscillator voltage.
|
||||
* @param mv Oscillator voltage in mv
|
||||
* Initializes Si446x transceiver chip.
|
||||
*/
|
||||
static void Si446x_init(const radio_unit_t radio) {
|
||||
static bool Si446x_init(const radio_unit_t radio) {
|
||||
|
||||
TRACE_INFO("SI > Init radio");
|
||||
TRACE_INFO("SI > Wake up and initialize radio %d", radio);
|
||||
|
||||
packet_svc_t *handler = pktGetServiceObject(radio);
|
||||
|
||||
chDbgAssert(handler != NULL, "invalid radio ID");
|
||||
|
||||
Si446x_powerup(radio);
|
||||
/* Wake up radio. */
|
||||
if(!Si446x_radioWakeup(radio)) {
|
||||
TRACE_ERROR("SI > Wake up of radio %d failed", radio);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Power up (send oscillator type)
|
||||
const uint8_t x3 = (Si446x_CCLK >> 24) & 0x0FF;
|
||||
const uint8_t x2 = (Si446x_CCLK >> 16) & 0x0FF;
|
||||
const uint8_t x1 = (Si446x_CCLK >> 8) & 0x0FF;
|
||||
const uint8_t x0 = (Si446x_CCLK >> 0) & 0x0FF;
|
||||
const uint8_t init_command[] = {0x02, 0x01, (Si446x_CLK_TCXO_EN & 0x1), x3, x2, x1, x0};
|
||||
Si446x_write(init_command, 7);
|
||||
chThdSleep(TIME_MS2I(25));
|
||||
/* Calculate clock source parameters. */
|
||||
const uint8_t x3 = (Si446x_CCLK >> 24) & 0x0FF;
|
||||
const uint8_t x2 = (Si446x_CCLK >> 16) & 0x0FF;
|
||||
const uint8_t x1 = (Si446x_CCLK >> 8) & 0x0FF;
|
||||
const uint8_t x0 = (Si446x_CCLK >> 0) & 0x0FF;
|
||||
|
||||
// Set transceiver GPIOs
|
||||
uint8_t gpio_pin_cfg_command[] = {
|
||||
0x13, // Command type = GPIO settings
|
||||
0x00, // GPIO0 GPIO_MODE = DONOTHING
|
||||
0x15, // GPIO1 GPIO_MODE = RAW_RX_DATA
|
||||
0x21, // GPIO2 GPIO_MODE = RX_STATE
|
||||
0x20, // GPIO3 GPIO_MODE = TX_STATE
|
||||
0x1B, // NIRQ NIRQ_MODE = CCA
|
||||
0x0B, // SDO SDO_MODE = SDO
|
||||
0x00 // GEN_CONFIG
|
||||
};
|
||||
Si446x_write(gpio_pin_cfg_command, 8);
|
||||
chThdSleep(TIME_MS2I(25));
|
||||
/*
|
||||
* Start the chip API with the POWER_UP command.
|
||||
* The first POWER_UP is done without patch bit or func set.
|
||||
* We need to get PART_INFO to determine if this is a 4464 or 4463.
|
||||
* For a 4463 a patch will be loaded.
|
||||
* This is done with a new reset, load and POWER_UP sequence.
|
||||
*/
|
||||
|
||||
#if !Si446x_CLK_TCXO_EN
|
||||
Si446x_setProperty8(Si446x_GLOBAL_XO_TUNE, 0x00);
|
||||
#endif
|
||||
const uint8_t init_command[] = {Si446x_POWER_UP, 0x01,
|
||||
(Si446x_CLK_TCXO_EN & 0x1),
|
||||
x3, x2, x1, x0};
|
||||
/*
|
||||
* Use of writeInit() enables SPI write without using OS delays.
|
||||
* CTS is available on GPIO1 after wake up for checking command ready.
|
||||
*
|
||||
* The SDO pin is configured to SDO data by POWER_UP.
|
||||
*/
|
||||
Si446x_writeInit(init_command, sizeof(init_command));
|
||||
//chThdSleep(TIME_MS2I(25));
|
||||
|
||||
Si446x_setProperty8(Si446x_FRR_CTL_A_MODE, 0x00);
|
||||
Si446x_setProperty8(Si446x_FRR_CTL_B_MODE, 0x00);
|
||||
Si446x_setProperty8(Si446x_FRR_CTL_C_MODE, 0x00);
|
||||
Si446x_setProperty8(Si446x_FRR_CTL_D_MODE, 0x00);
|
||||
Si446x_setProperty8(Si446x_INT_CTL_ENABLE, 0x00);
|
||||
/* Set combined FIFO mode = 0x70. */
|
||||
//Si446x_setProperty8(Si446x_GLOBAL_CONFIG, 0x60);
|
||||
Si446x_setProperty8(Si446x_GLOBAL_CONFIG, 0x70);
|
||||
/* TODO: We should clear interrupts here with a GET_INT_STATUS. */
|
||||
|
||||
/* Clear FIFO. */
|
||||
const uint8_t reset_fifo[] = {0x15, 0x01};
|
||||
Si446x_write(reset_fifo, 2);
|
||||
/* No need to unset bits... see si docs. */
|
||||
/* Set transceiver GPIOs to enable reading of PART_INFO. */
|
||||
uint8_t gpio_pin_cfg_command[] = {
|
||||
Si446x_GPIO_PIN_CFG, // Command type = GPIO settings
|
||||
0x00, // GPIO0 GPIO_MODE = DONOTHING
|
||||
0x15, // GPIO1 GPIO_MODE = RAW_RX_DATA
|
||||
0x21, // GPIO2 GPIO_MODE = RX_STATE
|
||||
0x20, // GPIO3 GPIO_MODE = TX_STATE
|
||||
0x1B, // NIRQ NIRQ_MODE = CCA
|
||||
0x0B, // SDO SDO_MODE = SDO
|
||||
0x00 // GEN_CONFIG
|
||||
};
|
||||
|
||||
Si446x_writeInit(gpio_pin_cfg_command, sizeof(gpio_pin_cfg_command));
|
||||
|
||||
/* Now SPI CTS is configured and can be relied upon for CTS. */
|
||||
//chThdSleep(TIME_MS2I(25));
|
||||
/* TODO:
|
||||
* - Next get the PART_INFO and FUNC_INFO.
|
||||
* - Store these for reference.
|
||||
* - If the part requires a patch then reset and delay (TBD).
|
||||
* - Output the patch and re-execute the POWER_UP and GPIO commands.
|
||||
* - Then continue.
|
||||
*/
|
||||
|
||||
si446x_info_t part_info;
|
||||
Si446x_getPartInfo(radio, &part_info);
|
||||
|
||||
#if !Si446x_CLK_TCXO_EN
|
||||
Si446x_setProperty8(Si446x_GLOBAL_XO_TUNE, 0x00);
|
||||
#endif
|
||||
|
||||
Si446x_setProperty8(Si446x_FRR_CTL_A_MODE, 0x00);
|
||||
Si446x_setProperty8(Si446x_FRR_CTL_B_MODE, 0x00);
|
||||
Si446x_setProperty8(Si446x_FRR_CTL_C_MODE, 0x00);
|
||||
Si446x_setProperty8(Si446x_FRR_CTL_D_MODE, 0x00);
|
||||
Si446x_setProperty8(Si446x_INT_CTL_ENABLE, 0x00);
|
||||
/* Set combined FIFO mode = 0x70. */
|
||||
//Si446x_setProperty8(Si446x_GLOBAL_CONFIG, 0x60);
|
||||
Si446x_setProperty8(Si446x_GLOBAL_CONFIG, 0x70);
|
||||
|
||||
/* Clear FIFO. */
|
||||
const uint8_t reset_fifo[] = {0x15, 0x01};
|
||||
Si446x_write(reset_fifo, 2);
|
||||
/* No need to unset bits... see si docs. */
|
||||
|
||||
|
||||
/*
|
||||
* TODO: Move the TX and RX settings out into the respective functions.
|
||||
* This would split up into AFSK and FSK for RX & TX.
|
||||
* Leave only common setup and init in here for selected base band frequency.
|
||||
*/
|
||||
Si446x_setProperty8(Si446x_PREAMBLE_TX_LENGTH, 0x00);
|
||||
/* TODO: Use PREAMBLE_CONFIG_NSTD, etc. to send flags?
|
||||
* To do this with AFSK up-sampling requires a preamble pattern of 88 bits.
|
||||
* The 446x only has up to 32 pattern bits.
|
||||
* Why 88 bits? Due to the oversampling used to create AFSK at 13.2ksps.
|
||||
* Each HDLC bit takes 11 TX bit times.
|
||||
*
|
||||
* The alternative is to use TX_FIELDS.
|
||||
* Send preamble (HDLC flags) using FIELD_1 in a loop with fixed data 0x7E.
|
||||
* Field length can be 4096 bytes so up to 372 flags could be sent.
|
||||
* The flag bit stream uses 11 bytes per flag.
|
||||
* Using 200 flags would be 11 * 200 = 2200 bytes (17,600 stream bits).
|
||||
* Set FIELD_1 as 2,200 bytes and feed 200 x the bit pattern to the FIFO.
|
||||
* The transition to FIELD_2 is handled in the 446x packet handler.
|
||||
* Then FIELD_2 FIFO data is fed from the layer0 (bit stream) data buffer.
|
||||
*/
|
||||
Si446x_setProperty8(Si446x_SYNC_CONFIG, 0x80);
|
||||
/*
|
||||
* TODO: Move the TX and RX settings out into the respective functions.
|
||||
* This would split up into AFSK and FSK for RX & TX.
|
||||
* Leave only common setup and init here.
|
||||
*/
|
||||
Si446x_setProperty8(Si446x_PREAMBLE_TX_LENGTH, 0x00);
|
||||
Si446x_setProperty8(Si446x_SYNC_CONFIG, 0x80);
|
||||
|
||||
Si446x_setProperty8(Si446x_GLOBAL_CLK_CFG, 0x00);
|
||||
Si446x_setProperty8(Si446x_MODEM_RSSI_CONTROL, 0x00);
|
||||
/* TODO: Don't need this setting? */
|
||||
Si446x_setProperty8(Si446x_PREAMBLE_CONFIG_STD_1, 0x14);
|
||||
Si446x_setProperty8(Si446x_PKT_CONFIG1, 0x41);
|
||||
Si446x_setProperty8(Si446x_MODEM_MAP_CONTROL, 0x00);
|
||||
Si446x_setProperty8(Si446x_MODEM_DSM_CTRL, 0x07);
|
||||
Si446x_setProperty8(Si446x_MODEM_CLKGEN_BAND, 0x0D);
|
||||
/* 32K clock disabled. Divided clock disabled. */
|
||||
Si446x_setProperty8(Si446x_GLOBAL_CLK_CFG, 0x00);
|
||||
Si446x_setProperty8(Si446x_MODEM_RSSI_CONTROL, 0x00);
|
||||
/* TODO: Don't need this setting? */
|
||||
Si446x_setProperty8(Si446x_PREAMBLE_CONFIG_STD_1, 0x14);
|
||||
Si446x_setProperty8(Si446x_PKT_CONFIG1, 0x41);
|
||||
Si446x_setProperty8(Si446x_MODEM_MAP_CONTROL, 0x00);
|
||||
Si446x_setProperty8(Si446x_MODEM_DSM_CTRL, 0x07);
|
||||
Si446x_setProperty8(Si446x_MODEM_CLKGEN_BAND, 0x0D);
|
||||
|
||||
Si446x_setProperty24(Si446x_MODEM_FREQ_DEV, 0x00, 0x00, 0x79);
|
||||
Si446x_setProperty8(Si446x_MODEM_TX_RAMP_DELAY, 0x01);
|
||||
Si446x_setProperty8(Si446x_PA_TC, 0x3D);
|
||||
Si446x_setProperty8(Si446x_FREQ_CONTROL_INTE, 0x41);
|
||||
Si446x_setProperty24(Si446x_FREQ_CONTROL_FRAC, 0x0B, 0xB1, 0x3B);
|
||||
Si446x_setProperty16(Si446x_FREQ_CONTROL_CHANNEL_STEP_SIZE, 0x0B, 0xD1);
|
||||
Si446x_setProperty8(Si446x_FREQ_CONTROL_W_SIZE, 0x20);
|
||||
Si446x_setProperty8(Si446x_FREQ_CONTROL_VCOCNT_RX_ADJ, 0xFA);
|
||||
Si446x_setProperty8(Si446x_MODEM_MDM_CTRL, 0x80);
|
||||
Si446x_setProperty8(Si446x_MODEM_IF_CONTROL, 0x08);
|
||||
Si446x_setProperty24(Si446x_MODEM_IF_FREQ, 0x02, 0x80, 0x00);
|
||||
Si446x_setProperty8(Si446x_MODEM_DECIMATION_CFG1, 0x70);
|
||||
Si446x_setProperty8(Si446x_MODEM_DECIMATION_CFG0, 0x10);
|
||||
Si446x_setProperty16(Si446x_MODEM_BCR_OSR, 0x01, 0xC3);
|
||||
Si446x_setProperty24(Si446x_MODEM_BCR_NCO_OFFSET, 0x01, 0x22, 0x60);
|
||||
Si446x_setProperty16(Si446x_MODEM_BCR_GAIN, 0x00, 0x91);
|
||||
Si446x_setProperty8(Si446x_MODEM_BCR_GEAR, 0x00);
|
||||
Si446x_setProperty8(Si446x_MODEM_BCR_MISC1, 0xC2);
|
||||
Si446x_setProperty8(Si446x_MODEM_AFC_GEAR, 0x54);
|
||||
Si446x_setProperty8(Si446x_MODEM_AFC_WAIT, 0x36);
|
||||
Si446x_setProperty16(Si446x_MODEM_AFC_GAIN, 0x80, 0xAB);
|
||||
Si446x_setProperty16(Si446x_MODEM_AFC_LIMITER, 0x02, 0x50);
|
||||
Si446x_setProperty8(Si446x_MODEM_AFC_MISC, 0x80);
|
||||
Si446x_setProperty8(Si446x_MODEM_AGC_CONTROL, 0xE2);
|
||||
Si446x_setProperty8(Si446x_MODEM_AGC_WINDOW_SIZE, 0x11);
|
||||
Si446x_setProperty8(Si446x_MODEM_AGC_RFPD_DECAY, 0x63);
|
||||
Si446x_setProperty8(Si446x_MODEM_AGC_IFPD_DECAY, 0x63);
|
||||
Si446x_setProperty8(Si446x_MODEM_FSK4_GAIN1, 0x00);
|
||||
Si446x_setProperty8(Si446x_MODEM_FSK4_GAIN0, 0x02);
|
||||
Si446x_setProperty16(Si446x_MODEM_FSK4_TH, 0x35, 0x55);
|
||||
Si446x_setProperty8(Si446x_MODEM_FSK4_MAP, 0x00);
|
||||
Si446x_setProperty8(Si446x_MODEM_OOK_PDTC, 0x2A);
|
||||
Si446x_setProperty8(Si446x_MODEM_OOK_CNT1, 0x85);
|
||||
Si446x_setProperty8(Si446x_MODEM_OOK_MISC, 0x23);
|
||||
Si446x_setProperty8(Si446x_MODEM_RAW_SEARCH, 0xD6);
|
||||
Si446x_setProperty8(Si446x_MODEM_RAW_CONTROL, 0x8F);
|
||||
Si446x_setProperty16(Si446x_MODEM_RAW_EYE, 0x00, 0x3B);
|
||||
Si446x_setProperty8(Si446x_MODEM_ANT_DIV_MODE, 0x01);
|
||||
Si446x_setProperty8(Si446x_MODEM_ANT_DIV_CONTROL, 0x80);
|
||||
Si446x_setProperty8(Si446x_MODEM_RSSI_COMP, 0x40);
|
||||
Si446x_setProperty24(Si446x_MODEM_FREQ_DEV, 0x00, 0x00, 0x79);
|
||||
Si446x_setProperty8(Si446x_MODEM_TX_RAMP_DELAY, 0x01);
|
||||
Si446x_setProperty8(Si446x_PA_TC, 0x3D);
|
||||
Si446x_setProperty8(Si446x_FREQ_CONTROL_INTE, 0x41);
|
||||
Si446x_setProperty24(Si446x_FREQ_CONTROL_FRAC, 0x0B, 0xB1, 0x3B);
|
||||
Si446x_setProperty16(Si446x_FREQ_CONTROL_CHANNEL_STEP_SIZE, 0x0B, 0xD1);
|
||||
Si446x_setProperty8(Si446x_FREQ_CONTROL_W_SIZE, 0x20);
|
||||
Si446x_setProperty8(Si446x_FREQ_CONTROL_VCOCNT_RX_ADJ, 0xFA);
|
||||
Si446x_setProperty8(Si446x_MODEM_MDM_CTRL, 0x80);
|
||||
Si446x_setProperty8(Si446x_MODEM_IF_CONTROL, 0x08);
|
||||
Si446x_setProperty24(Si446x_MODEM_IF_FREQ, 0x02, 0x80, 0x00);
|
||||
Si446x_setProperty8(Si446x_MODEM_DECIMATION_CFG1, 0x70);
|
||||
Si446x_setProperty8(Si446x_MODEM_DECIMATION_CFG0, 0x10);
|
||||
Si446x_setProperty16(Si446x_MODEM_BCR_OSR, 0x01, 0xC3);
|
||||
Si446x_setProperty24(Si446x_MODEM_BCR_NCO_OFFSET, 0x01, 0x22, 0x60);
|
||||
Si446x_setProperty16(Si446x_MODEM_BCR_GAIN, 0x00, 0x91);
|
||||
Si446x_setProperty8(Si446x_MODEM_BCR_GEAR, 0x00);
|
||||
Si446x_setProperty8(Si446x_MODEM_BCR_MISC1, 0xC2);
|
||||
Si446x_setProperty8(Si446x_MODEM_AFC_GEAR, 0x54);
|
||||
Si446x_setProperty8(Si446x_MODEM_AFC_WAIT, 0x36);
|
||||
Si446x_setProperty16(Si446x_MODEM_AFC_GAIN, 0x80, 0xAB);
|
||||
Si446x_setProperty16(Si446x_MODEM_AFC_LIMITER, 0x02, 0x50);
|
||||
Si446x_setProperty8(Si446x_MODEM_AFC_MISC, 0x80);
|
||||
Si446x_setProperty8(Si446x_MODEM_AGC_CONTROL, 0xE2);
|
||||
Si446x_setProperty8(Si446x_MODEM_AGC_WINDOW_SIZE, 0x11);
|
||||
Si446x_setProperty8(Si446x_MODEM_AGC_RFPD_DECAY, 0x63);
|
||||
Si446x_setProperty8(Si446x_MODEM_AGC_IFPD_DECAY, 0x63);
|
||||
Si446x_setProperty8(Si446x_MODEM_FSK4_GAIN1, 0x00);
|
||||
Si446x_setProperty8(Si446x_MODEM_FSK4_GAIN0, 0x02);
|
||||
Si446x_setProperty16(Si446x_MODEM_FSK4_TH, 0x35, 0x55);
|
||||
Si446x_setProperty8(Si446x_MODEM_FSK4_MAP, 0x00);
|
||||
Si446x_setProperty8(Si446x_MODEM_OOK_PDTC, 0x2A);
|
||||
Si446x_setProperty8(Si446x_MODEM_OOK_CNT1, 0x85);
|
||||
Si446x_setProperty8(Si446x_MODEM_OOK_MISC, 0x23);
|
||||
Si446x_setProperty8(Si446x_MODEM_RAW_SEARCH, 0xD6);
|
||||
Si446x_setProperty8(Si446x_MODEM_RAW_CONTROL, 0x8F);
|
||||
Si446x_setProperty16(Si446x_MODEM_RAW_EYE, 0x00, 0x3B);
|
||||
Si446x_setProperty8(Si446x_MODEM_ANT_DIV_MODE, 0x01);
|
||||
Si446x_setProperty8(Si446x_MODEM_ANT_DIV_CONTROL, 0x80);
|
||||
Si446x_setProperty8(Si446x_MODEM_RSSI_COMP, 0x40);
|
||||
|
||||
handler->radio_init = true;
|
||||
handler->radio_init = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Si446x_conditional_init(const radio_unit_t radio) {
|
||||
bool Si446x_conditional_init(const radio_unit_t radio) {
|
||||
// Initialize radio
|
||||
|
||||
packet_svc_t *handler = pktGetServiceObject(radio);
|
||||
|
@ -296,7 +367,8 @@ void Si446x_conditional_init(const radio_unit_t radio) {
|
|||
chDbgAssert(handler != NULL, "invalid radio ID");
|
||||
|
||||
if(!handler->radio_init)
|
||||
Si446x_init(radio);
|
||||
return Si446x_init(radio);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -329,8 +401,9 @@ bool Si446x_setBandParameters(const radio_unit_t radio,
|
|||
|
||||
/* Set the band parameter. */
|
||||
uint32_t sy_sel = 8;
|
||||
uint8_t set_band_property_command[] = {0x11, 0x20, 0x01, 0x51, (band + sy_sel)};
|
||||
Si446x_write(set_band_property_command, 5);
|
||||
uint8_t set_band_property_command[] = {Si446x_SET_PROPERTY,
|
||||
0x20, 0x01, 0x51, (band + sy_sel)};
|
||||
Si446x_write(set_band_property_command, sizeof(set_band_property_command));
|
||||
|
||||
/* Set the PLL parameters. */
|
||||
uint32_t f_pfd = 2 * Si446x_CCLK / outdiv;
|
||||
|
@ -347,15 +420,18 @@ bool Si446x_setBandParameters(const radio_unit_t radio,
|
|||
uint8_t c1 = channel_increment / 0x100;
|
||||
uint8_t c0 = channel_increment - (0x100 * c1);
|
||||
|
||||
uint8_t set_frequency_property_command[] = {0x11, 0x40, 0x04, 0x00, n, m2, m1, m0, c1, c0};
|
||||
Si446x_write(set_frequency_property_command, 10);
|
||||
uint8_t set_frequency_property_command[] = {Si446x_SET_PROPERTY,
|
||||
0x40, 0x04, 0x00, n,
|
||||
m2, m1, m0, c1, c0};
|
||||
Si446x_write(set_frequency_property_command,
|
||||
sizeof(set_frequency_property_command));
|
||||
|
||||
uint32_t x = ((((uint32_t)1 << 19) * outdiv * 1300.0)/(2*Si446x_CCLK))*2;
|
||||
uint8_t x2 = (x >> 16) & 0xFF;
|
||||
uint8_t x1 = (x >> 8) & 0xFF;
|
||||
uint8_t x0 = (x >> 0) & 0xFF;
|
||||
uint8_t set_deviation[] = {0x11, 0x20, 0x03, 0x0a, x2, x1, x0};
|
||||
Si446x_write(set_deviation, 7);
|
||||
uint8_t set_deviation[] = {Si446x_SET_PROPERTY, 0x20, 0x03, 0x0a, x2, x1, x0};
|
||||
Si446x_write(set_deviation, sizeof(set_deviation));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -379,8 +455,10 @@ bool Si446x_setBandParameters(const radio_unit_t radio,
|
|||
static void Si446x_setPowerLevel(const radio_pwr_t level)
|
||||
{
|
||||
// Set the Power
|
||||
uint8_t set_pa_pwr_lvl_property_command[] = {0x11, 0x22, 0x01, 0x01, level};
|
||||
Si446x_write(set_pa_pwr_lvl_property_command, 5);
|
||||
uint8_t set_pa_pwr_lvl_property_command[] = {Si446x_SET_PROPERTY,
|
||||
0x22, 0x01, 0x01, level};
|
||||
Si446x_write(set_pa_pwr_lvl_property_command,
|
||||
sizeof(set_pa_pwr_lvl_property_command));
|
||||
}
|
||||
|
||||
|
||||
|
@ -558,7 +636,7 @@ static uint8_t Si446x_getState(const radio_unit_t radio) {
|
|||
static void Si446x_setTXState(const radio_unit_t radio, uint8_t chan, uint16_t size){
|
||||
/* TODO: add hardware mapping. */
|
||||
(void)radio;
|
||||
uint8_t change_state_command[] = {0x31, chan,
|
||||
uint8_t change_state_command[] = {Si446x_START_TX, chan,
|
||||
(Si446x_STATE_READY << 4),
|
||||
(size >> 8) & 0x1F, size & 0xFF};
|
||||
Si446x_write(change_state_command, sizeof(change_state_command));
|
||||
|
@ -567,42 +645,73 @@ static void Si446x_setTXState(const radio_unit_t radio, uint8_t chan, uint16_t s
|
|||
static void Si446x_setReadyState(const radio_unit_t radio) {
|
||||
/* TODO: add hardware mapping. */
|
||||
(void)radio;
|
||||
const uint8_t change_state_command[] = {0x34, 0x03};
|
||||
const uint8_t change_state_command[] = {Si446x_CHANGE_STATE,
|
||||
Si446x_STATE_READY};
|
||||
Si446x_write(change_state_command, sizeof(change_state_command));
|
||||
}
|
||||
|
||||
static void Si446x_setRXState(const radio_unit_t radio, uint8_t chan){
|
||||
/* TODO: add hardware mapping. */
|
||||
(void)radio;
|
||||
const uint8_t change_state_command[] = {0x32, chan, 0x00, 0x00,
|
||||
const uint8_t change_state_command[] = {Si446x_START_RX, chan, 0x00, 0x00,
|
||||
0x00, 0x00, 0x08, 0x08};
|
||||
Si446x_write(change_state_command, sizeof(change_state_command));
|
||||
}
|
||||
|
||||
static void Si446x_setStandbyState(const radio_unit_t radio) {
|
||||
/* TODO: add hardware mapping. */
|
||||
(void)radio;
|
||||
const uint8_t change_state_command[] = {Si446x_CHANGE_STATE,
|
||||
Si446x_STATE_STANDBY};
|
||||
Si446x_write(change_state_command, sizeof(change_state_command));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void Si446x_powerup(const radio_unit_t radio) {
|
||||
TRACE_INFO("SI > Power up radio %i", radio);
|
||||
packet_svc_t *handler = pktGetServiceObject(radio);
|
||||
|
||||
chDbgAssert(handler != NULL, "invalid radio ID");
|
||||
palClearLine(LINE_RADIO_SDN); // Radio SDN low (power up transceiver)
|
||||
chThdSleep(TIME_MS2I(10)); // Wait for transceiver to power up
|
||||
void Si446x_enterStandby(const radio_unit_t radio) {
|
||||
Si446x_setStandbyState(radio);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void Si446x_shutdown(const radio_unit_t radio) {
|
||||
TRACE_INFO("SI > Shutdown radio %i", radio);
|
||||
bool Si446x_radioWakeup(const radio_unit_t radio) {
|
||||
/* The LINE_RADIO_SDN is set high in GPIO board initialization.
|
||||
* Hence the radio is started in shutdown by board initialization.
|
||||
* When the radio is shutdown by software the LINE_RADIO_SDN is also set high.
|
||||
* Si446x GPIO1 is configured to output CTS (option 8) during POR.
|
||||
* We use the MCU GPIO connected to radio GPIO1 to check CTS here.
|
||||
*
|
||||
* Radio init is performed in the radio manager thread init stage.
|
||||
* The use of GPIO1 of the radio can be changed after init is complete.
|
||||
*/
|
||||
TRACE_INFO("SI > Enable radio %i", radio);
|
||||
packet_svc_t *handler = pktGetServiceObject(radio);
|
||||
|
||||
chDbgAssert(handler != NULL, "invalid radio ID");
|
||||
/* Assert SDN low to perform POR wakeup. */
|
||||
palClearLine(LINE_RADIO_SDN);
|
||||
/* Set MCU GPIO input for CTS of radio on GPIO1. */
|
||||
pktSetLineModeRadioCTS();
|
||||
/* Wait for transceiver to wake up (maximum wakeup time is 6mS). */
|
||||
chThdSleep(TIME_MS2I(10));
|
||||
/* Return state of CTS after delay. */
|
||||
return pktReadGPIOline(LINE_RADIO_GPIO1) == PAL_HIGH;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void Si446x_radioShutdown(const radio_unit_t radio) {
|
||||
TRACE_INFO("SI > Disable radio %i", radio);
|
||||
packet_svc_t *handler = pktGetServiceObject(radio);
|
||||
|
||||
chDbgAssert(handler != NULL, "invalid radio ID");
|
||||
|
||||
//pktPowerDownRadio(radio);
|
||||
palSetLine(LINE_RADIO_SDN);
|
||||
handler->radio_init = false;
|
||||
chThdSleep(TIME_MS2I(1));
|
||||
}
|
||||
|
||||
/* ====================================================================== Radio TX/RX ======================================================================= */
|
||||
|
@ -616,8 +725,6 @@ static bool Si446x_checkCCAthreshold(const radio_unit_t radio, uint8_t ms) {
|
|||
/* TODO: Hardware mapping of radio. */
|
||||
(void)radio;
|
||||
uint16_t cca = 0;
|
||||
/* Tick per millisecond. */
|
||||
//sysinterval_t uslice = TIME_MS2I(1);
|
||||
/* Measure sliced CCA instances in period. */
|
||||
for(uint16_t i = 0; i < (ms * TIME_MS2I(1)); i++) {
|
||||
cca += Si446x_getCCA();
|
||||
|
@ -806,7 +913,7 @@ void Si446x_disableReceive(const radio_unit_t radio) {
|
|||
/* FIXME: */
|
||||
if(Si446x_getState(radio) == Si446x_STATE_RX) {
|
||||
//rx_frequency = 0;
|
||||
Si446x_shutdown(radio);
|
||||
Si446x_radioShutdown(radio);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
/* Si4464 States. */
|
||||
#define Si446x_STATE_NOCHANGE 0
|
||||
#define Si446x_STATE_SLEEP 1
|
||||
#define Si446x_STATE_STANDBY 1
|
||||
#define Si446x_STATE_SPI_ACTIVE 2
|
||||
#define Si446x_STATE_READY 3
|
||||
#define Si446x_STATE_READY2 4
|
||||
|
@ -31,16 +32,29 @@
|
|||
#define Si446x_STATE_RX 8
|
||||
|
||||
/* Commands. */
|
||||
#define Si446x_NOP 0x00
|
||||
#define Si446x_GET_PART_INFO 0x01
|
||||
#define Si446x_POWER_UP 0x02
|
||||
#define Si446x_GET_FUNC_INFO 0x10
|
||||
#define Si446x_SET_PROPERTY 0x11
|
||||
#define Si446x_GET_PROPERTY 0x12
|
||||
#define Si446x_GPIO_PIN_CFG 0x13
|
||||
#define Si446x_GET_ADC_READING 0x14
|
||||
#define Si446x_FIFO_INFO 0x15
|
||||
#define Si446x_PACKET_INFO 0x16
|
||||
#define Si446x_GET_INT_STATUS 0x20
|
||||
#define Si446x_GET_PH_STATUS 0x21
|
||||
#define Si446x_GET_MODEM_STATUS 0x22
|
||||
#define Si446x_GET_CHIP_STATUS 0x23
|
||||
#define Si446x_START_TX 0x31
|
||||
#define Si446x_START_RX 0x32
|
||||
#define Si446x_REQUEST_DEVICE_STATE 0x33
|
||||
#define Si446x_CHANGE_STATE 0x34
|
||||
#define Si446x_RX_HOP 0x36
|
||||
#define Si446x_TX_HOP 0x37
|
||||
#define Si446x_READ_CMD_BUFF 0x44
|
||||
#define Si446x_WRITE_TX_FIFO 0x66
|
||||
#define Si446x_READ_RX_FIFO 0x77
|
||||
|
||||
/* Defined response values. */
|
||||
#define Si446x_COMMAND_CTS 0xFF
|
||||
|
@ -237,8 +251,9 @@ extern void pktReleasePacketBuffer(packet_t pp);
|
|||
extern "C" {
|
||||
#endif
|
||||
int16_t Si446x_getLastTemperature(const radio_unit_t radio);
|
||||
void Si446x_powerup(const radio_unit_t radio);
|
||||
void Si446x_shutdown(const radio_unit_t radio);
|
||||
bool Si446x_radioWakeup(const radio_unit_t radio);
|
||||
void Si446x_radioShutdown(const radio_unit_t radio);
|
||||
void Si446x_enterStandby(const radio_unit_t radio);
|
||||
void Si446x_sendAFSK(packet_t pp);
|
||||
bool Si446x_blocSendAFSK(radio_task_object_t *rto);
|
||||
void Si446x_send2FSK(packet_t pp);
|
||||
|
@ -261,7 +276,7 @@ extern "C" {
|
|||
void Si446x_unlockRadio(const radio_mode_t mode);
|
||||
void Si446x_lockRadioByCamera(void);
|
||||
void Si446x_unlockRadioByCamera(void);
|
||||
void Si446x_conditional_init(radio_unit_t radio);
|
||||
bool Si446x_conditional_init(radio_unit_t radio);
|
||||
bool Si446x_setBandParameters(const radio_unit_t radio,
|
||||
radio_freq_t freq,
|
||||
channel_hz_t step);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#include "hal.h"
|
||||
#include "debug.h"
|
||||
|
||||
mutex_t trace_mtx; // Used internal to synchronize multiple chprintf in debug.h
|
||||
//mutex_t trace_mtx; // Used internal to synchronize multiple chprintf in debug.h
|
||||
|
||||
char error_list[ERROR_LIST_SIZE][ERROR_LIST_LENGTH];
|
||||
uint8_t error_counter;
|
||||
|
|
|
@ -22,9 +22,11 @@ extern const SerialConfig uart_config;
|
|||
extern uint8_t usb_trace_level;
|
||||
|
||||
// Initializer for serial debug and LEDs
|
||||
/*
|
||||
#define DEBUG_INIT() { \
|
||||
chMtxObjectInit(&trace_mtx); \
|
||||
}
|
||||
*/
|
||||
|
||||
#define TRACE_BASE(format, type, args...) { \
|
||||
if(isConsoleOutputAvailable()) { \
|
||||
|
@ -66,6 +68,7 @@ extern uint8_t usb_trace_level;
|
|||
#define TRACE_TAB " "
|
||||
#endif
|
||||
|
||||
/*
|
||||
#define TRACE_BIN(data, len) { \
|
||||
chMtxLock(&trace_mtx); \
|
||||
chprintf((BaseSequentialStream*)&SD3, "[%8d.%03d][DEBUG] ", chVTGetSystemTime()/CH_CFG_ST_FREQUENCY, (chVTGetSystemTime()*1000/CH_CFG_ST_FREQUENCY)%1000); \
|
||||
|
@ -85,6 +88,7 @@ extern uint8_t usb_trace_level;
|
|||
TRACE_TAB, i, (data)[i], (data)[i+1], (data)[i+2], (data)[i+3], (data)[i+4], (data)[i+5], (data)[i+6], (data)[i+7]); \
|
||||
chMtxUnlock(&trace_mtx); \
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
@ -151,7 +151,7 @@ msg_t pktStartConsole(void) {
|
|||
thread_t *console = chThdCreateFromHeap(NULL,
|
||||
THD_WORKING_AREA_SIZE(1024),
|
||||
"CON",
|
||||
NORMALPRIO - 10,
|
||||
LOWPRIO + 10,
|
||||
pktConsole,
|
||||
&SDU1);
|
||||
if(console == NULL)
|
||||
|
|
|
@ -843,9 +843,8 @@ THD_FUNCTION(pktAFSKDecoder, arg) {
|
|||
if(myPktBuffer == NULL) {
|
||||
/* Decrease ref count on AX25 FIFO. */
|
||||
chFactoryReleaseObjectsFIFO(pkt_fifo);
|
||||
pktAddEventFlags(myHandler, EVT_AX25_NO_BUFFER);
|
||||
myDriver->active_demod_object->status |=
|
||||
EVT_AX25_NO_BUFFER;
|
||||
pktAddEventFlags(myHandler, EVT_PKT_NO_BUFFER);
|
||||
//myDriver->active_demod_object->status |= EVT_AX25_NO_BUFFER;
|
||||
myDriver->decoder_state = DECODER_RESET;
|
||||
break;
|
||||
}
|
||||
|
@ -886,7 +885,7 @@ THD_FUNCTION(pktAFSKDecoder, arg) {
|
|||
if(n != sizeof(packed_pwm_counts_t)) {
|
||||
/* PWM stream wait timeout. */
|
||||
pktAddEventFlags(myHandler, EVT_PWM_STREAM_TIMEOUT);
|
||||
myDriver->active_demod_object->status |= EVT_PWM_STREAM_TIMEOUT;
|
||||
//myDriver->active_demod_object->status |= EVT_PWM_STREAM_TIMEOUT;
|
||||
myDriver->decoder_state = DECODER_RESET;
|
||||
break;
|
||||
}
|
||||
|
@ -1088,7 +1087,7 @@ THD_FUNCTION(pktAFSKDecoder, arg) {
|
|||
/*
|
||||
* Lock the PWM queue to stop any further radio data being written.
|
||||
*/
|
||||
myDriver->active_demod_object->status |= EVT_AFSK_DECODE_RESET;
|
||||
myDriver->active_demod_object->status |= STA_AFSK_DECODE_RESET;
|
||||
/*
|
||||
* Wait for FIFO stream control object to be free from the radio.
|
||||
* Normally this semaphore will not suspend as decoding is slow.
|
||||
|
@ -1152,22 +1151,23 @@ THD_FUNCTION(pktAFSKDecoder, arg) {
|
|||
* Indicate AFSK decode done.
|
||||
* If PWM is still being captured for this stream capture will cease.
|
||||
*/
|
||||
eventflags_t evtf = EVT_AFSK_DECODE_DONE;
|
||||
myDriver->active_demod_object->status |= evtf;
|
||||
//eventflags_t evtf = EVT_NONE;
|
||||
myDriver->active_demod_object->status |= STA_AFSK_DECODE_DONE;
|
||||
|
||||
/* Copy latest status into packet buffer object. */
|
||||
myHandler->active_packet_object->status =
|
||||
myDriver->active_demod_object->status;
|
||||
|
||||
/* Dispatch the packet buffer object and get AX25 events. */
|
||||
evtf |= pktDispatchReceivedBuffer(myHandler->active_packet_object);
|
||||
myHandler->active_packet_object->status |=
|
||||
pktDispatchReceivedBuffer(myHandler->active_packet_object);
|
||||
|
||||
/* Forget the packet object. */
|
||||
/* Remove the packet object reference. */
|
||||
myHandler->active_packet_object = NULL;
|
||||
|
||||
/* Send events then update demod object status. */
|
||||
pktAddEventFlags(myHandler, evtf);
|
||||
myDriver->active_demod_object->status |= evtf;
|
||||
//pktAddEventFlags(myHandler, evtf);
|
||||
//myDriver->active_demod_object->status |= evtf;
|
||||
} /* Active packet object != NULL. */
|
||||
myDriver->decoder_state = DECODER_RESET;
|
||||
break;
|
||||
|
|
|
@ -214,7 +214,7 @@ void pktClosePWMChannelI(ICUDriver *myICU, eventflags_t evt, pwm_code_t reason)
|
|||
/* Stop the ICU notification (callback). */
|
||||
icuDisableNotificationsI(myICU);
|
||||
if(myDemod->active_radio_object != NULL) {
|
||||
myDemod->active_radio_object->status |= (EVT_PWM_STREAM_CLOSED | evt);
|
||||
myDemod->active_radio_object->status |= (STA_PWM_STREAM_CLOSED | evt);
|
||||
pktAddEventFlagsI(myHandler, evt);
|
||||
#if USE_HEAP_PWM_BUFFER == TRUE
|
||||
input_queue_t *myQueue =
|
||||
|
@ -236,7 +236,7 @@ void pktClosePWMChannelI(ICUDriver *myICU, eventflags_t evt, pwm_code_t reason)
|
|||
* In any case flag the error.
|
||||
*/
|
||||
pktWriteGPIOline(LINE_OVERFLOW_LED, PAL_HIGH);
|
||||
myDemod->active_radio_object->status |= EVT_PWM_QUEUE_OVERRUN;
|
||||
//myDemod->active_radio_object->status |= EVT_PWM_QUEUE_OVERRUN;
|
||||
pktAddEventFlagsI(myHandler, EVT_PWM_QUEUE_OVERRUN);
|
||||
}
|
||||
/* Allow the decoder thread to release the stream FIFO object. */
|
||||
|
@ -649,7 +649,7 @@ void pktRadioICUPeriod(ICUDriver *myICU) {
|
|||
* flag may cause trailing PWM activity.
|
||||
*
|
||||
*/
|
||||
if((myDemod->active_radio_object->status & EVT_AFSK_DECODE_DONE) != 0) {
|
||||
if((myDemod->active_radio_object->status & STA_AFSK_DECODE_DONE) != 0) {
|
||||
pktClosePWMChannelI(myICU, EVT_NONE, PWM_ACK_DECODE_END);
|
||||
chSysUnlockFromISR();
|
||||
return;
|
||||
|
@ -660,7 +660,7 @@ void pktRadioICUPeriod(ICUDriver *myICU) {
|
|||
* This will happen when no AX25 buffer is available or overflows.
|
||||
* Close the PWM stream and wait for next radio CCA.
|
||||
*/
|
||||
if((myDemod->active_radio_object->status & EVT_AFSK_DECODE_RESET) != 0) {
|
||||
if((myDemod->active_radio_object->status & STA_AFSK_DECODE_RESET) != 0) {
|
||||
pktClosePWMChannelI(myICU, EVT_NONE, PWM_ACK_DECODE_ERROR);
|
||||
chSysUnlockFromISR();
|
||||
return;
|
||||
|
|
|
@ -41,20 +41,26 @@ eventmask_t evt = chEvtGetAndClearEvents(EVENT_MASK(1));
|
|||
if(flags & EVT_PWM_FIFO_EMPTY) {
|
||||
TRACE_WARN("PKT > PWM FIFO exhausted");
|
||||
}
|
||||
if(flags & EVT_AX25_NO_BUFFER) {
|
||||
if(flags & EVT_PKT_NO_BUFFER) {
|
||||
TRACE_WARN("PKT > AX25 FIFO exhausted");
|
||||
}
|
||||
if(flags & EVT_ICU_SLEEP_TIMEOUT) {
|
||||
TRACE_INFO("PKT > PWM ICU has entered sleep");
|
||||
}
|
||||
if(flags & EVT_AX25_BUFFER_FULL) {
|
||||
if(flags & EVT_PKT_BUFFER_FULL) {
|
||||
TRACE_WARN("PKT > AX25 receive buffer full");
|
||||
}
|
||||
if(flags & EVT_PWM_QUEUE_OVERRUN) {
|
||||
TRACE_ERROR("PKT > PWM queue overrun");
|
||||
}
|
||||
if(flags & EVT_PWM_INVALID_INBAND) {
|
||||
TRACE_ERROR("PKT > Invalid PWM in-band flag");
|
||||
TRACE_ERROR("PKT > Invalid PWM in-band message");
|
||||
}
|
||||
if(flags & EVT_PWM_NO_DATA) {
|
||||
TRACE_ERROR("PKT > No PWM data from radio");
|
||||
}
|
||||
if(flags & EVT_PKT_FAILED_CB_THD) {
|
||||
TRACE_ERROR("PKT > Failed to create RX callback thread");
|
||||
}
|
||||
/* if(flags & EVT_ICU_OVERFLOW) {
|
||||
TRACE_DEBUG("PKT > PWM ICU overflow");
|
||||
|
@ -63,7 +69,7 @@ eventmask_t evt = chEvtGetAndClearEvents(EVENT_MASK(1));
|
|||
TRACE_WARN("PKT > PWM stream timeout");
|
||||
}
|
||||
if(flags & EVT_PWM_NO_DATA) {
|
||||
TRACE_WARN("PKT > PWM data not started from radio");
|
||||
TRACE_WARN("PKT > No PWM data from radio");
|
||||
}
|
||||
if(flags & EVT_AFSK_START_FAIL) {
|
||||
TRACE_ERROR("PKT > AFSK decoder failed to start");
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
* @notes Receive tasks start the receive/decode system which are threads.
|
||||
* @notes Transmit tasks should be handled in threads (and are in 446x).
|
||||
*
|
||||
* @param[in] arg pointer to a @p radio task queue for this thread.
|
||||
* @param[in] arg pointer to a @p packet service object for this radio.
|
||||
*
|
||||
* @return status (MSG_OK) on exit.
|
||||
*
|
||||
|
@ -37,7 +37,7 @@
|
|||
*/
|
||||
THD_FUNCTION(pktRadioManager, arg) {
|
||||
/* When waiting for TX tasks to complete. */
|
||||
#define PKT_RADIO_TASK_MANAGER_WAIT_RATE_MS 100
|
||||
#define PKT_RADIO_TX_TASK_RECHECK_WAIT_MS 100
|
||||
|
||||
packet_svc_t *handler = arg;
|
||||
|
||||
|
@ -49,8 +49,19 @@ THD_FUNCTION(pktRadioManager, arg) {
|
|||
|
||||
chDbgAssert(radio_queue != NULL, "no queue in radio manager FIFO");
|
||||
|
||||
/* Run until terminate request and no outstanding TX tasks. */
|
||||
const radio_unit_t radio = handler->radio;
|
||||
|
||||
/* Take radio out of shutdown and initialize base registers. */
|
||||
bool init = pktLLDradioInit(radio);
|
||||
|
||||
thread_t *initiator = chMsgWait();
|
||||
chMsgGet(initiator);
|
||||
if(!init) {
|
||||
chMsgRelease(initiator, MSG_ERROR);
|
||||
chThdExit(MSG_OK);
|
||||
}
|
||||
chMsgRelease(initiator, MSG_OK);
|
||||
/* Run until close request and no outstanding TX tasks. */
|
||||
while(true) {
|
||||
/* Check for task requests. */
|
||||
radio_task_object_t *task_object;
|
||||
|
@ -58,26 +69,25 @@ THD_FUNCTION(pktRadioManager, arg) {
|
|||
(void *)&task_object, TIME_INFINITE);
|
||||
/* Something to do. */
|
||||
|
||||
const radio_unit_t radio = handler->radio;
|
||||
/* Process command. */
|
||||
switch(task_object->command) {
|
||||
case PKT_RADIO_MGR_CLOSE: {
|
||||
/*
|
||||
* Radio manager terminate is sent as a task object.
|
||||
* Radio manager close is sent as a task object.
|
||||
* When no TX tasks are outstanding release the FIFO and terminate.
|
||||
* The task initiator waits with chThdWait(...).
|
||||
*/
|
||||
if(handler->tx_count == 0) {
|
||||
pktLLDradioShutdown(radio);
|
||||
chFactoryReleaseObjectsFIFO(handler->the_radio_fifo);
|
||||
chThdExit(MSG_OK);
|
||||
/* We never arrive here. */
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* There are still TX sessions running.
|
||||
* Wait, repost task, let the FIFO be processed and check again.
|
||||
*/
|
||||
chThdSleep(TIME_MS2I(PKT_RADIO_TASK_MANAGER_WAIT_RATE_MS));
|
||||
chThdSleep(TIME_MS2I(PKT_RADIO_TX_TASK_RECHECK_WAIT_MS));
|
||||
pktSubmitRadioTask(radio, task_object, NULL);
|
||||
continue;
|
||||
}
|
||||
|
@ -129,8 +139,6 @@ THD_FUNCTION(pktRadioManager, arg) {
|
|||
break;
|
||||
} /* End switch on modulation type. */
|
||||
|
||||
/* Initialise the radio. */
|
||||
pktLLDradioInit(radio);
|
||||
break;
|
||||
} /* End case PKT_RADIO_OPEN. */
|
||||
|
||||
|
@ -144,7 +152,6 @@ THD_FUNCTION(pktRadioManager, arg) {
|
|||
/* Enable receive. */
|
||||
if(pktLLDradioEnableReceive(radio, task_object))
|
||||
pktLLDradioStartDecoder(radio);
|
||||
//pktStartDecoder(radio);
|
||||
|
||||
/* Unlock radio and allow transmit requests. */
|
||||
pktReleaseRadio(radio);
|
||||
|
@ -165,7 +172,6 @@ THD_FUNCTION(pktRadioManager, arg) {
|
|||
/* TODO: Abstract acquire and release in LLD. */
|
||||
pktAcquireRadio(radio, TIME_INFINITE);
|
||||
pktLLDradioStopDecoder(radio);
|
||||
//pktStopDecoder(handler->radio);
|
||||
pktReleaseRadio(radio);
|
||||
break;
|
||||
} /* End case. */
|
||||
|
@ -183,7 +189,6 @@ THD_FUNCTION(pktRadioManager, arg) {
|
|||
++handler->radio_tx_config.tx_seq_num;
|
||||
/* Pause the decoder. */
|
||||
pktLLDradioPauseDecoding(radio);
|
||||
//pktPauseDecoding(radio);
|
||||
if(pktLLDradioSendPacket(task_object)) {
|
||||
/*
|
||||
* Keep count of active sends.
|
||||
|
@ -203,7 +208,8 @@ THD_FUNCTION(pktRadioManager, arg) {
|
|||
pktReleaseBufferChain(pp);
|
||||
if(pktIsReceivePaused(radio)) {
|
||||
if(!pktLLDradioResumeReceive(radio)) {
|
||||
TRACE_ERROR("RAD > Receive failed to resume after transmit");
|
||||
TRACE_ERROR("RAD > Receive on radio %d failed to "
|
||||
"resume after transmit", radio);
|
||||
break;
|
||||
}
|
||||
pktLLDradioResumeDecoding(radio);
|
||||
|
@ -217,8 +223,7 @@ THD_FUNCTION(pktRadioManager, arg) {
|
|||
thread_t *decoder = NULL;
|
||||
switch(task_object->type) {
|
||||
case MOD_AFSK: {
|
||||
/* TODO: Implement LLD abstraction closing decoder. */
|
||||
//Si446x_disableReceive(radio);
|
||||
/* Stop receive. */
|
||||
pktLLDradioDisableReceive(radio);
|
||||
/* TODO: This should be a function back in pktservice or rxafsk. */
|
||||
esp = pktGetEventSource((AFSKDemodDriver *)handler->link_controller);
|
||||
|
@ -278,25 +283,26 @@ THD_FUNCTION(pktRadioManager, arg) {
|
|||
msg_t send_msg = chThdWait(task_object->thread);
|
||||
|
||||
if(send_msg == MSG_TIMEOUT) {
|
||||
TRACE_ERROR("RAD > Transmit timeout");
|
||||
TRACE_ERROR("RAD > Transmit timeout on radio %d", radio);
|
||||
}
|
||||
if(send_msg == MSG_RESET) {
|
||||
TRACE_ERROR("RAD > Transmit failed to start");
|
||||
TRACE_ERROR("RAD > Transmit failed to start on radio %d", radio);
|
||||
}
|
||||
/* If no transmissions pending then enable RX or power down. */
|
||||
if(--handler->tx_count == 0) {
|
||||
/* Check at handler level is OK. No LLD required. */
|
||||
if(pktIsReceivePaused(radio)) {
|
||||
if(!pktLLDradioResumeReceive(radio)) {
|
||||
TRACE_ERROR("RAD > Receive failed to resume after transmit");
|
||||
TRACE_ERROR("RAD > Receive on radio %d failed to "
|
||||
"resume after transmit", radio);
|
||||
break;
|
||||
}
|
||||
/* TODO: Implement LLD since resume depends on radio and mod type. */
|
||||
pktLLDradioResumeDecoding(radio);
|
||||
//pktResumeDecoding(radio);
|
||||
} else {
|
||||
/* Power down radio. */
|
||||
pktLLDradioPowerDown(radio);
|
||||
/* Enter standby state (low power). */
|
||||
TRACE_INFO("RAD > Radio %d entering standby", radio);
|
||||
pktLLDradioStandby(radio);
|
||||
}
|
||||
} /* Else more TX tasks outstanding so let those complete. */
|
||||
break;
|
||||
|
@ -359,9 +365,22 @@ thread_t *pktRadioManagerCreate(const radio_unit_t radio) {
|
|||
|
||||
if(handler->radio_manager == NULL) {
|
||||
chFactoryReleaseObjectsFIFO(the_radio_fifo);
|
||||
handler->the_packet_fifo = NULL;
|
||||
return NULL;
|
||||
}
|
||||
return handler->radio_manager;
|
||||
msg_t init = chMsgSend(handler->radio_manager, MSG_OK);
|
||||
if(init == MSG_OK)
|
||||
return handler->radio_manager;
|
||||
|
||||
/* Radio init failed so clean up. */
|
||||
|
||||
chFactoryReleaseObjectsFIFO(the_radio_fifo);
|
||||
handler->the_packet_fifo = NULL;
|
||||
|
||||
chThdTerminate(handler->radio_manager);
|
||||
|
||||
handler->radio_manager = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -770,30 +789,20 @@ radio_freq_t pktComputeOperatingFrequency(const radio_unit_t radio,
|
|||
/**
|
||||
*
|
||||
*/
|
||||
void pktLLDradioInit(const radio_unit_t radio) {
|
||||
bool pktLLDradioInit(const radio_unit_t radio) {
|
||||
/* TODO: Implement hardware mapping. */
|
||||
Si446x_conditional_init(radio);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void pktLLDradioPowerUp(const radio_unit_t radio) {
|
||||
/* TODO: Implement hardware mapping. */
|
||||
(void)radio;
|
||||
/*
|
||||
* NOTE: RADIO_CS and RADIO_SDN pins are configured in board.h
|
||||
* RADIO_SDN is configured to open drain as it is pulled up on PCB by 100K.
|
||||
* RADIO_SDN is configured to open drain pullup.
|
||||
* It is also pulled up on PCB by 100K.
|
||||
* The radio powers up in SDN mode.
|
||||
*
|
||||
* CS is set as push-pull and initialized to HIGH.
|
||||
*/
|
||||
|
||||
// Power up transceiver
|
||||
Si446x_powerup(radio);
|
||||
return Si446x_conditional_init(radio);
|
||||
}
|
||||
|
||||
void pktLLDradioPowerDown(const radio_unit_t radio) {
|
||||
void pktLLDradioShutdown(const radio_unit_t radio) {
|
||||
/* TODO: Implement hardware mapping. */
|
||||
(void)radio;
|
||||
|
||||
|
@ -801,8 +810,18 @@ void pktLLDradioPowerDown(const radio_unit_t radio) {
|
|||
* Put radio in shutdown mode.
|
||||
* All registers are lost.
|
||||
*/
|
||||
//palSetLine(LINE_RADIO_SDN);
|
||||
Si446x_shutdown(radio);
|
||||
Si446x_radioShutdown(radio);
|
||||
}
|
||||
|
||||
void pktLLDradioStandby(const radio_unit_t radio) {
|
||||
/* TODO: Implement hardware mapping. */
|
||||
(void)radio;
|
||||
|
||||
/*
|
||||
* Put radio in standby (low power) mode.
|
||||
* All registers are retained.
|
||||
*/
|
||||
Si446x_enterStandby(radio);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -156,9 +156,10 @@ extern "C" {
|
|||
bool pktLLDradioResumeReceive(const radio_unit_t radio);
|
||||
bool pktLLDradioSendPacket(radio_task_object_t *rto);
|
||||
void pktLLDradioCaptureRSSI(const radio_unit_t radio);
|
||||
void pktLLDradioPowerUp(const radio_unit_t radio);
|
||||
void pktLLDradioInit(const radio_unit_t radio);
|
||||
void pktLLDradioPowerDown(const radio_unit_t radio);
|
||||
//bool pktLLDradioExitShutdown(const radio_unit_t radio);
|
||||
bool pktLLDradioInit(const radio_unit_t radio);
|
||||
void pktLLDradioStandby(const radio_unit_t radio);
|
||||
void pktLLDradioShutdown(const radio_unit_t radio);
|
||||
void pktLLDradioPauseDecoding(const radio_unit_t radio);
|
||||
void pktLLDradioResumeDecoding(const radio_unit_t radio);
|
||||
void pktLLDradioStartDecoder(const radio_unit_t radio);
|
||||
|
|
|
@ -609,10 +609,10 @@ eventflags_t pktDispatchReceivedBuffer(pkt_data_object_t *pkt_buffer) {
|
|||
if(magicCRC == CRC_INCLUSIVE_CONSTANT)
|
||||
handler->good_count++;
|
||||
flags |= (magicCRC == CRC_INCLUSIVE_CONSTANT)
|
||||
? EVT_AX25_FRAME_RDY
|
||||
: EVT_AX25_CRC_ERROR;
|
||||
? STA_PKT_FRAME_RDY
|
||||
: STA_PKT_CRC_ERROR;
|
||||
} else {
|
||||
flags |= EVT_PKT_INVALID_FRAME;
|
||||
flags |= STA_PKT_INVALID_FRAME;
|
||||
}
|
||||
|
||||
/* Update status in packet buffer object. */
|
||||
|
@ -633,9 +633,10 @@ eventflags_t pktDispatchReceivedBuffer(pkt_data_object_t *pkt_buffer) {
|
|||
chDbgAssert(cb_thd != NULL, "failed to create callback thread");
|
||||
|
||||
if(cb_thd == NULL) {
|
||||
/* Failed to create CB thread. Release buffer. Flag event. */
|
||||
/* Failed to create CB thread. Release buffer. Broadcast event. */
|
||||
chFifoReturnObject(pkt_fifo, pkt_buffer);
|
||||
flags |= EVT_PKT_FAILED_CB_THD;
|
||||
pktAddEventFlags(handler, EVT_PKT_FAILED_CB_THD);
|
||||
//flags |= EVT_PKT_FAILED_CB_THD;
|
||||
|
||||
} else {
|
||||
/* Increase outstanding callback count. */
|
||||
|
|
|
@ -512,7 +512,7 @@ static inline msg_t pktReceiveDataBufferTimeout(packet_svc_t *handler,
|
|||
static inline bool pktIsBufferValidAX25Frame(pkt_data_object_t *object) {
|
||||
chDbgAssert(object != NULL, "no pointer to packet object buffer");
|
||||
uint16_t frame_size = object->packet_size;
|
||||
return ((object->status & EVT_AFSK_DECODE_DONE)
|
||||
return ((object->status & STA_AFSK_DECODE_DONE)
|
||||
&& (frame_size >= PKT_MIN_FRAME));
|
||||
}
|
||||
|
||||
|
@ -525,13 +525,13 @@ static inline bool pktIsBufferValidAX25Frame(pkt_data_object_t *object) {
|
|||
*
|
||||
* @return The operation status.
|
||||
* @retval true if the frame is valid and has good CRC.
|
||||
* @retval false if the frame is valid and has bad CRC.
|
||||
* @retval false if the frame is invalid or has bad CRC.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
static inline bool pktGetAX25FrameStatus(pkt_data_object_t *object) {
|
||||
chDbgAssert(object != NULL, "no pointer to packet object buffer");
|
||||
return !(object->status & (EVT_PKT_INVALID_FRAME | EVT_AX25_CRC_ERROR));
|
||||
return !(object->status & (STA_PKT_INVALID_FRAME | STA_PKT_CRC_ERROR));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -57,22 +57,23 @@
|
|||
* The packet channel object holds the global events.
|
||||
* Events are broadcast to any listeners.
|
||||
*/
|
||||
#define EVT_AX25_FRAME_RDY EVENT_MASK(EVT_PRIORITY_BASE + 0)
|
||||
#define EVT_AX25_BUFFER_FULL EVENT_MASK(EVT_PRIORITY_BASE + 1)
|
||||
#define EVT_AX25_CRC_ERROR EVENT_MASK(EVT_PRIORITY_BASE + 2)
|
||||
#define EVT_AX25_NO_BUFFER EVENT_MASK(EVT_PRIORITY_BASE + 3)
|
||||
//#define STA_AX25_FRAME_RDY EVENT_MASK(EVT_PRIORITY_BASE + 0)
|
||||
#define EVT_PKT_BUFFER_FULL EVENT_MASK(EVT_PRIORITY_BASE + 1)
|
||||
//#define STA_AX25_CRC_ERROR EVENT_MASK(EVT_PRIORITY_BASE + 2)
|
||||
#define EVT_PKT_NO_BUFFER EVENT_MASK(EVT_PRIORITY_BASE + 3)
|
||||
|
||||
#define EVT_AFSK_TERMINATED EVENT_MASK(EVT_PRIORITY_BASE + 4)
|
||||
//#define EVT_AFSK_TERMINATED EVENT_MASK(EVT_PRIORITY_BASE + 4)
|
||||
#define EVT_AFSK_START_FAIL EVENT_MASK(EVT_PRIORITY_BASE + 5)
|
||||
#define EVT_AFSK_DECODE_RESET EVENT_MASK(EVT_PRIORITY_BASE + 6)
|
||||
#define EVT_AFSK_DECODE_DONE EVENT_MASK(EVT_PRIORITY_BASE + 7)
|
||||
//#define STA_AFSK_DECODE_RESET EVENT_MASK(EVT_PRIORITY_BASE + 6)
|
||||
//#define STA_AFSK_DECODE_DONE EVENT_MASK(EVT_PRIORITY_BASE + 7)
|
||||
|
||||
/* TODO: Create an AKSK event field in decoder for the PWM & radio events. */
|
||||
#define EVT_PWM_NO_DATA EVENT_MASK(EVT_PRIORITY_BASE + 8)
|
||||
#define EVT_PWM_INVALID_INBAND EVENT_MASK(EVT_PRIORITY_BASE + 9)
|
||||
#define EVT_PWM_FIFO_EMPTY EVENT_MASK(EVT_PRIORITY_BASE + 10)
|
||||
#define EVT_PWM_QUEUE_FULL EVENT_MASK(EVT_PRIORITY_BASE + 11)
|
||||
|
||||
#define EVT_PWM_STREAM_CLOSED EVENT_MASK(EVT_PRIORITY_BASE + 12)
|
||||
//#define STA_PWM_STREAM_CLOSED EVENT_MASK(EVT_PRIORITY_BASE + 12)
|
||||
#define EVT_PWM_STREAM_TIMEOUT EVENT_MASK(EVT_PRIORITY_BASE + 13)
|
||||
#define EVT_PWM_QUEUE_OVERRUN EVENT_MASK(EVT_PRIORITY_BASE + 14)
|
||||
#define EVT_PWM_BUFFER_FAIL EVENT_MASK(EVT_PRIORITY_BASE + 15)
|
||||
|
@ -80,7 +81,7 @@
|
|||
#define EVT_PWM_STREAM_OPEN EVENT_MASK(EVT_PRIORITY_BASE + 16)
|
||||
#define EVT_PWM_FIFO_REMNANT EVENT_MASK(EVT_PRIORITY_BASE + 17)
|
||||
//#define EVT_PWM_STREAM_CLOSE EVENT_MASK(EVT_PRIORITY_BASE + 18)
|
||||
#define EVT_PKT_INVALID_FRAME EVENT_MASK(EVT_PRIORITY_BASE + 19)
|
||||
//#define STA_PKT_INVALID_FRAME EVENT_MASK(EVT_PRIORITY_BASE + 19)
|
||||
|
||||
#define EVT_PKT_FAILED_CB_THD EVENT_MASK(EVT_PRIORITY_BASE + 20)
|
||||
#define EVT_PKT_BUFFER_MGR_FAIL EVENT_MASK(EVT_PRIORITY_BASE + 21)
|
||||
|
@ -126,7 +127,14 @@ typedef uint32_t statusmask_t; /**< Mask of status identifiers. */
|
|||
*/
|
||||
#define STATUS_MASK(sid) ((statusmask_t)1 << (statusmask_t)(sid))
|
||||
|
||||
#define STA_AFSK_DECODE_RESET STATUS_MASK(0)
|
||||
/* TODO: Classify status by PKT, AFSK and 2FSK types. */
|
||||
#define STA_PKT_FRAME_RDY STATUS_MASK(0)
|
||||
#define STA_PKT_CRC_ERROR STATUS_MASK(1)
|
||||
#define STA_PKT_INVALID_FRAME STATUS_MASK(2)
|
||||
#define STA_AFSK_DECODE_RESET STATUS_MASK(3)
|
||||
#define STA_AFSK_DECODE_DONE STATUS_MASK(4)
|
||||
#define STA_PWM_STREAM_CLOSED STATUS_MASK(5)
|
||||
|
||||
|
||||
#define useCCM __attribute__((section(".ram4")))
|
||||
|
||||
|
@ -234,7 +242,6 @@ static inline int8_t pktReadGPIOline(ioline_t line) {
|
|||
static inline msg_t pktSendRadioCommand(radio_unit_t radio,
|
||||
radio_task_object_t *task,
|
||||
radio_task_cb_t cb) {
|
||||
#if USE_SPI_ATTACHED_RADIO == TRUE
|
||||
radio_task_object_t *rt = NULL;
|
||||
msg_t msg = pktGetRadioTaskObject(radio, TIME_MS2I(3000), &rt);
|
||||
if(msg != MSG_OK)
|
||||
|
@ -242,11 +249,6 @@ static inline msg_t pktSendRadioCommand(radio_unit_t radio,
|
|||
*rt = *task;
|
||||
pktSubmitRadioTask(radio, rt, cb);
|
||||
return msg;
|
||||
#else
|
||||
(void)task;
|
||||
(void)handler;
|
||||
return MSG_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -258,12 +260,8 @@ static inline msg_t pktSendRadioCommand(radio_unit_t radio,
|
|||
* @api
|
||||
*/
|
||||
static inline void pktReleaseBufferObject(packet_t pp) {
|
||||
#if USE_SPI_ATTACHED_RADIO == TRUE
|
||||
chDbgAssert(pp != NULL, "no packet pointer");
|
||||
pktReleasePacketBuffer(pp);
|
||||
#else
|
||||
(void)pp;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -276,8 +274,6 @@ static inline void pktReleaseBufferObject(packet_t pp) {
|
|||
* @api
|
||||
*/
|
||||
static inline void pktReleaseBufferChain(packet_t pp) {
|
||||
#if USE_SPI_ATTACHED_RADIO == TRUE
|
||||
|
||||
chDbgAssert(pp != NULL, "no packet pointer");
|
||||
/* Release all packets in linked list. */
|
||||
do {
|
||||
|
@ -285,9 +281,6 @@ static inline void pktReleaseBufferChain(packet_t pp) {
|
|||
pktReleasePacketBuffer(pp);
|
||||
pp = np;
|
||||
} while(pp != NULL);
|
||||
#else
|
||||
(void)pp;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* _PKTCONF_H_ */
|
||||
|
|
|
@ -1,160 +1,157 @@
|
|||
/*
|
||||
Aerospace Decoder - Copyright (C) 2018 Bob Anderson (VK2GJ)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include "pktconf.h"
|
||||
|
||||
/**
|
||||
* @brief Extract HDLC from AFSK.
|
||||
* @post The HDLC state will be updated.
|
||||
* @notes In the case of an HDLC_RESET HDLC sync can be restarted.
|
||||
* @notes This is done where the AX25 payload is below minimum size.
|
||||
* @notes If the payload is above minimum size state HDLC_RESET is set.
|
||||
* @notes In that case it is left to the decoder to determine an action.
|
||||
*
|
||||
* @param[in] myDriver pointer to an @p AFSKDemodDriver structure.
|
||||
*
|
||||
* @return status of operation
|
||||
* @retval true character processed and HDLC state updated on flags.
|
||||
* @retval false frame buffer full.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
bool pktExtractHDLCfromAFSK(AFSKDemodDriver *myDriver) {
|
||||
|
||||
packet_svc_t *myHandler = myDriver->packet_handler;
|
||||
|
||||
/* Shift prior HDLC bits up before adding new bit. */
|
||||
myDriver->hdlc_bits <<= 1;
|
||||
myDriver->hdlc_bits &= 0xFE;
|
||||
/* Same tone indicates a 1. */
|
||||
if(myDriver->tone_freq == myDriver->prior_freq) {
|
||||
myDriver->hdlc_bits |= 1;
|
||||
}
|
||||
/* Update the prior frequency. */
|
||||
myDriver->prior_freq = myDriver->tone_freq;
|
||||
|
||||
/*
|
||||
* Check if we are in AX25 data capture mode.
|
||||
* If so check and act on HDLC codes otherwise just store data.
|
||||
*/
|
||||
switch(myDriver->frame_state) {
|
||||
case FRAME_OPEN: {
|
||||
switch(myDriver->hdlc_bits & HDLC_CODE_MASK) {
|
||||
case HDLC_FLAG: {
|
||||
/*
|
||||
* An HDLC flag after minimum packet size terminates the AX25 frame.
|
||||
*/
|
||||
if(myHandler->active_packet_object->packet_size >= PKT_MIN_FRAME) {
|
||||
/*
|
||||
* Frame size is valid.
|
||||
* Dump any bits already put into the AX25 byte.
|
||||
*/
|
||||
myDriver->bit_index = 0;
|
||||
/* Inform decoder thread of end of frame. */
|
||||
myDriver->frame_state = FRAME_CLOSE;
|
||||
return true;
|
||||
} /* End AX25 frame size check. */
|
||||
|
||||
/*
|
||||
* Frame size is not valid.
|
||||
* HDLC sync still in progress.
|
||||
* Reset AX25 counts and wait for next HDLC bit.
|
||||
*/
|
||||
pktResetDataCount(myHandler->active_packet_object);
|
||||
myDriver->bit_index = 0;
|
||||
return true;
|
||||
} /* End case. */
|
||||
|
||||
case HDLC_RESET: {
|
||||
/*
|
||||
* Can be a real HDLC reset or most likely incorrect bit sync.
|
||||
* TODO: Figure out correct handling.
|
||||
* Make a macro to test if no data stored?
|
||||
*/
|
||||
|
||||
myDriver->active_demod_object->status |= EVT_HDLC_RESET_RCVD;
|
||||
pktAddEventFlags(myHandler, EVT_HDLC_RESET_RCVD);
|
||||
if(myHandler->active_packet_object->packet_size < PKT_MIN_FRAME) {
|
||||
/* No data payload stored yet so go back to sync search. */
|
||||
myHandler->active_packet_object->packet_size = 0;
|
||||
myDriver->frame_state = FRAME_SEARCH;
|
||||
myHandler->sync_count--;
|
||||
break;
|
||||
}
|
||||
/* Else let the decoder determine what to do. */
|
||||
myDriver->frame_state = FRAME_RESET;
|
||||
return true;
|
||||
} /* End case. */
|
||||
|
||||
default: {
|
||||
/* Check for RLL encoding inserted ("stuffed") bit in the bit stream. */
|
||||
if((myDriver->hdlc_bits & HDLC_RLL_MASK) == HDLC_RLL_BIT) {
|
||||
/*
|
||||
* The stuffed bit is discarded.
|
||||
* We just wait for next HDLC bit.
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
* Else we have a non-special pattern.
|
||||
* Just put the bit into the AX25 data.
|
||||
* AX25 data bits arrive MSB -> LSB.
|
||||
*/
|
||||
myDriver->current_byte &= 0x7F;
|
||||
if((myDriver->hdlc_bits & 0x01) == 1) {
|
||||
myDriver->current_byte |= 0x80;
|
||||
}
|
||||
/* Check if we have a byte accumulated. */
|
||||
if(++myDriver->bit_index == 8U) {
|
||||
myDriver->bit_index = 0;
|
||||
if(pktStoreBufferData(myHandler->active_packet_object,
|
||||
myDriver->current_byte)) {
|
||||
return true;
|
||||
}
|
||||
pktAddEventFlags(myHandler, EVT_AX25_BUFFER_FULL);
|
||||
myDriver->active_demod_object->status |= EVT_AX25_BUFFER_FULL;
|
||||
return false;
|
||||
}
|
||||
/* Else shift the prior bit to make space for next bit. */
|
||||
myDriver->current_byte >>= 1;
|
||||
return true;
|
||||
} /* End case default. */
|
||||
} /* End switch. */
|
||||
} /* Else not frame_open... */
|
||||
|
||||
case FRAME_SEARCH: {
|
||||
/*
|
||||
* Frame start not yet detected.
|
||||
* Check for opening HDLC flag sequence.
|
||||
*/
|
||||
if(
|
||||
((myDriver->hdlc_bits & HDLC_FRAME_MASK_A) == HDLC_FRAME_OPEN_A)
|
||||
||
|
||||
((myDriver->hdlc_bits & HDLC_FRAME_MASK_B) == HDLC_FRAME_OPEN_B)
|
||||
) {
|
||||
|
||||
myDriver->frame_state = FRAME_OPEN;
|
||||
myHandler->sync_count++;
|
||||
/* Reset AX25 data indexes. */
|
||||
myHandler->active_packet_object->packet_size = 0;
|
||||
myDriver->bit_index = 0;
|
||||
|
||||
/*
|
||||
* AX25 data buffering is now enabled.
|
||||
* Data bytes will be written to the AX25 buffer.
|
||||
*/
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
return true;
|
||||
} /* End switch on frame state. */
|
||||
} /* End function. */
|
||||
|
||||
/** @} */
|
||||
/*
|
||||
Aerospace Decoder - Copyright (C) 2018 Bob Anderson (VK2GJ)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include "pktconf.h"
|
||||
|
||||
/**
|
||||
* @brief Extract HDLC from AFSK.
|
||||
* @post The HDLC state will be updated.
|
||||
* @notes In the case of an HDLC_RESET HDLC sync can be restarted.
|
||||
* @notes This is done where the AX25 payload is below minimum size.
|
||||
* @notes If the payload is above minimum size state HDLC_RESET is set.
|
||||
* @notes In that case it is left to the decoder to determine an action.
|
||||
*
|
||||
* @param[in] myDriver pointer to an @p AFSKDemodDriver structure.
|
||||
*
|
||||
* @return status of operation
|
||||
* @retval true character processed and HDLC state updated on flags.
|
||||
* @retval false frame buffer full.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
bool pktExtractHDLCfromAFSK(AFSKDemodDriver *myDriver) {
|
||||
|
||||
packet_svc_t *myHandler = myDriver->packet_handler;
|
||||
|
||||
/* Shift prior HDLC bits up before adding new bit. */
|
||||
myDriver->hdlc_bits <<= 1;
|
||||
myDriver->hdlc_bits &= 0xFE;
|
||||
/* Same tone indicates a 1. */
|
||||
if(myDriver->tone_freq == myDriver->prior_freq) {
|
||||
myDriver->hdlc_bits |= 1;
|
||||
}
|
||||
/* Update the prior frequency. */
|
||||
myDriver->prior_freq = myDriver->tone_freq;
|
||||
|
||||
/*
|
||||
* Check if we are in AX25 data capture mode.
|
||||
* If so check and act on HDLC codes otherwise just store data.
|
||||
*/
|
||||
switch(myDriver->frame_state) {
|
||||
case FRAME_OPEN: {
|
||||
switch(myDriver->hdlc_bits & HDLC_CODE_MASK) {
|
||||
case HDLC_FLAG: {
|
||||
/*
|
||||
* An HDLC flag after minimum packet size terminates the AX25 frame.
|
||||
*/
|
||||
if(myHandler->active_packet_object->packet_size >= PKT_MIN_FRAME) {
|
||||
/*
|
||||
* Frame size is valid.
|
||||
* Dump any bits already put into the AX25 byte.
|
||||
*/
|
||||
myDriver->bit_index = 0;
|
||||
/* Inform decoder thread of end of frame. */
|
||||
myDriver->frame_state = FRAME_CLOSE;
|
||||
return true;
|
||||
} /* End AX25 frame size check. */
|
||||
|
||||
/*
|
||||
* Frame size is not valid.
|
||||
* HDLC sync still in progress.
|
||||
* Reset AX25 counts and wait for next HDLC bit.
|
||||
*/
|
||||
pktResetDataCount(myHandler->active_packet_object);
|
||||
myDriver->bit_index = 0;
|
||||
return true;
|
||||
} /* End case. */
|
||||
|
||||
case HDLC_RESET: {
|
||||
/*
|
||||
* Can be a real HDLC reset or most likely incorrect bit sync.
|
||||
*/
|
||||
|
||||
//myDriver->active_demod_object->status |= STA_HDLC_RESET_RCVD;
|
||||
pktAddEventFlags(myHandler, EVT_HDLC_RESET_RCVD);
|
||||
if(myHandler->active_packet_object->packet_size < PKT_MIN_FRAME) {
|
||||
/* No data payload stored yet so go back to sync search. */
|
||||
myHandler->active_packet_object->packet_size = 0;
|
||||
myDriver->frame_state = FRAME_SEARCH;
|
||||
myHandler->sync_count--;
|
||||
break;
|
||||
}
|
||||
/* Else let the decoder determine what to do. */
|
||||
myDriver->frame_state = FRAME_RESET;
|
||||
return true;
|
||||
} /* End case. */
|
||||
|
||||
default: {
|
||||
/* Check for RLL encoding inserted ("stuffed") bit in the bit stream. */
|
||||
if((myDriver->hdlc_bits & HDLC_RLL_MASK) == HDLC_RLL_BIT) {
|
||||
/*
|
||||
* The stuffed bit is discarded.
|
||||
* We just wait for next HDLC bit.
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
* Else we have a non-special pattern.
|
||||
* Just put the bit into the AX25 data.
|
||||
* AX25 data bits arrive MSB -> LSB.
|
||||
*/
|
||||
myDriver->current_byte &= 0x7F;
|
||||
if((myDriver->hdlc_bits & 0x01) == 1) {
|
||||
myDriver->current_byte |= 0x80;
|
||||
}
|
||||
/* Check if we have a byte accumulated. */
|
||||
if(++myDriver->bit_index == 8U) {
|
||||
myDriver->bit_index = 0;
|
||||
if(pktStoreBufferData(myHandler->active_packet_object,
|
||||
myDriver->current_byte)) {
|
||||
return true;
|
||||
}
|
||||
pktAddEventFlags(myHandler, EVT_PKT_BUFFER_FULL);
|
||||
return false;
|
||||
}
|
||||
/* Else shift the prior bit to make space for next bit. */
|
||||
myDriver->current_byte >>= 1;
|
||||
return true;
|
||||
} /* End case default. */
|
||||
} /* End switch. */
|
||||
} /* Else not frame_open... */
|
||||
|
||||
case FRAME_SEARCH: {
|
||||
/*
|
||||
* Frame start not yet detected.
|
||||
* Check for opening HDLC flag sequence.
|
||||
*/
|
||||
if(
|
||||
((myDriver->hdlc_bits & HDLC_FRAME_MASK_A) == HDLC_FRAME_OPEN_A)
|
||||
||
|
||||
((myDriver->hdlc_bits & HDLC_FRAME_MASK_B) == HDLC_FRAME_OPEN_B)
|
||||
) {
|
||||
|
||||
myDriver->frame_state = FRAME_OPEN;
|
||||
myHandler->sync_count++;
|
||||
/* Reset AX25 data indexes. */
|
||||
myHandler->active_packet_object->packet_size = 0;
|
||||
myDriver->bit_index = 0;
|
||||
|
||||
/*
|
||||
* AX25 data buffering is now enabled.
|
||||
* Data bytes will be written to the AX25 buffer.
|
||||
*/
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
return true;
|
||||
} /* End switch on frame state. */
|
||||
} /* End function. */
|
||||
|
||||
/** @} */
|
||||
|
|
Ładowanie…
Reference in New Issue