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 chip
pull/4/head
bob 2018-07-17 13:59:42 +10:00
rodzic eda158af9b
commit b363092805
21 zmienionych plików z 582 dodań i 429 usunięć

Wyświetl plik

@ -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

Wyświetl plik

@ -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, ...);

Wyświetl plik

@ -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

Wyświetl plik

@ -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, ...);

Wyświetl plik

@ -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)

Wyświetl plik

@ -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)

Wyświetl plik

@ -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);

Wyświetl plik

@ -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);
}
}

Wyświetl plik

@ -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);

Wyświetl plik

@ -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;

Wyświetl plik

@ -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); \
}
*/
/*

Wyświetl plik

@ -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)

Wyświetl plik

@ -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;

Wyświetl plik

@ -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;

Wyświetl plik

@ -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");

Wyświetl plik

@ -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);
}
/**

Wyświetl plik

@ -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);

Wyświetl plik

@ -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. */

Wyświetl plik

@ -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));
}
/**

Wyświetl plik

@ -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_ */

Wyświetl plik

@ -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. */
/** @} */