mirror of
https://github.com/betaflight/betaflight.git
synced 2025-07-23 00:05:33 +03:00
Softserial with monotimer and bidir
This commit is contained in:
parent
b2c32b84e3
commit
97b5dbc386
11 changed files with 450 additions and 100 deletions
|
@ -25,8 +25,12 @@
|
|||
#include "build/build_config.h"
|
||||
#include "build/atomic.h"
|
||||
|
||||
#include "build/debug.h"
|
||||
|
||||
#include "common/utils.h"
|
||||
|
||||
#include "config/config_master.h"
|
||||
|
||||
#include "nvic.h"
|
||||
#include "system.h"
|
||||
#include "io.h"
|
||||
|
@ -44,21 +48,29 @@
|
|||
#define MAX_SOFTSERIAL_PORTS 1
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
TIMER_MODE_SINGLE,
|
||||
TIMER_MODE_DUAL,
|
||||
} timerMode_e;
|
||||
|
||||
typedef struct softSerial_s {
|
||||
serialPort_t port;
|
||||
|
||||
IO_t rxIO;
|
||||
IO_t txIO;
|
||||
const timerHardware_t *rxTimerHardware;
|
||||
volatile uint8_t rxBuffer[SOFTSERIAL_BUFFER_SIZE];
|
||||
|
||||
const timerHardware_t *txTimerHardware;
|
||||
const timerHardware_t *timerHardware;
|
||||
const timerHardware_t *exTimerHardware;
|
||||
uint32_t ccEnableBit;
|
||||
|
||||
volatile uint8_t rxBuffer[SOFTSERIAL_BUFFER_SIZE];
|
||||
volatile uint8_t txBuffer[SOFTSERIAL_BUFFER_SIZE];
|
||||
|
||||
uint8_t isSearchingForStartBit;
|
||||
uint8_t rxBitIndex;
|
||||
uint8_t rxLastLeadingEdgeAtBitIndex;
|
||||
uint8_t rxEdge;
|
||||
uint8_t rxActive;
|
||||
|
||||
uint8_t isTransmittingData;
|
||||
int8_t bitsLeftToTransmit;
|
||||
|
@ -70,23 +82,20 @@ typedef struct softSerial_s {
|
|||
uint16_t receiveErrors;
|
||||
|
||||
uint8_t softSerialPortIndex;
|
||||
timerMode_e timerMode;
|
||||
|
||||
timerCCHandlerRec_t timerCb;
|
||||
timerOvrHandlerRec_t overCb;
|
||||
timerCCHandlerRec_t edgeCb;
|
||||
} softSerial_t;
|
||||
|
||||
extern timerHardware_t* serialTimerHardware;
|
||||
extern softSerial_t softSerialPorts[];
|
||||
static const struct serialPortVTable softSerialVTable; // Forward
|
||||
|
||||
extern const struct serialPortVTable softSerialVTable[];
|
||||
static softSerial_t softSerialPorts[MAX_SOFTSERIAL_PORTS];
|
||||
|
||||
|
||||
softSerial_t softSerialPorts[MAX_SOFTSERIAL_PORTS];
|
||||
|
||||
void onSerialTimer(timerCCHandlerRec_t *cbRec, captureCompare_t capture);
|
||||
void onSerialTimerOverflow(timerOvrHandlerRec_t *cbRec, captureCompare_t capture);
|
||||
void onSerialRxPinChange(timerCCHandlerRec_t *cbRec, captureCompare_t capture);
|
||||
|
||||
void setTxSignal(softSerial_t *softSerial, uint8_t state)
|
||||
static void setTxSignal(softSerial_t *softSerial, uint8_t state)
|
||||
{
|
||||
if (softSerial->port.options & SERIAL_INVERTED) {
|
||||
state = !state;
|
||||
|
@ -99,20 +108,83 @@ void setTxSignal(softSerial_t *softSerial, uint8_t state)
|
|||
}
|
||||
}
|
||||
|
||||
void serialInputPortConfig(ioTag_t pin, uint8_t portIndex)
|
||||
// XXX CCEnableBit: Compute CCxE bit.
|
||||
// XXX (Note: timer.c:timerChICPolarity() uses "TIM_CCER_CC1P << timHw->channel".)
|
||||
|
||||
static uint32_t CCEnableBit(int channel)
|
||||
{
|
||||
IOInit(IOGetByTag(pin), OWNER_SERIAL_RX, RESOURCE_INDEX(portIndex) + RESOURCE_SOFT_OFFSET);
|
||||
#ifdef STM32F1
|
||||
IOConfigGPIO(IOGetByTag(pin), IOCFG_IPU);
|
||||
uint32_t bit;
|
||||
|
||||
#if defined(STM32F7)
|
||||
switch (channel) {
|
||||
case TIM_CHANNEL_1:
|
||||
bit = TIM_CCER_CC1E;
|
||||
break;
|
||||
case TIM_CHANNEL_2:
|
||||
bit = TIM_CCER_CC2E;
|
||||
break;
|
||||
case TIM_CHANNEL_3:
|
||||
bit = TIM_CCER_CC3E;
|
||||
break;
|
||||
case TIM_CHANNEL_4:
|
||||
bit = TIM_CCER_CC4E;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
IOConfigGPIO(IOGetByTag(pin), IOCFG_AF_PP_UP);
|
||||
switch (channel) {
|
||||
case TIM_Channel_1:
|
||||
bit = TIM_CCER_CC1E;
|
||||
break;
|
||||
case TIM_Channel_2:
|
||||
bit = TIM_CCER_CC2E;
|
||||
break;
|
||||
case TIM_Channel_3:
|
||||
bit = TIM_CCER_CC3E;
|
||||
break;
|
||||
case TIM_Channel_4:
|
||||
bit = TIM_CCER_CC4E;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
return bit;
|
||||
}
|
||||
|
||||
static void serialOutputPortConfig(ioTag_t pin, uint8_t portIndex)
|
||||
static void serialInputPortActivate(softSerial_t *softSerial)
|
||||
{
|
||||
IOInit(IOGetByTag(pin), OWNER_SERIAL_TX, RESOURCE_INDEX(portIndex) + RESOURCE_SOFT_OFFSET);
|
||||
IOConfigGPIO(IOGetByTag(pin), IOCFG_OUT_PP);
|
||||
softSerial->rxActive = true;
|
||||
#ifdef STM32F1
|
||||
IOConfigGPIO(softSerial->rxIO, IOCFG_IPU);
|
||||
#else
|
||||
IOConfigGPIO(softSerial->rxIO, IOCFG_AF_PP_UP);
|
||||
#endif
|
||||
|
||||
softSerial->isSearchingForStartBit = true;
|
||||
softSerial->rxBitIndex = 0;
|
||||
|
||||
// Enable input capture
|
||||
|
||||
softSerial->timerHardware->tim->CCER |= softSerial->ccEnableBit;
|
||||
}
|
||||
|
||||
static void serialInputPortDeActivate(softSerial_t *softSerial)
|
||||
{
|
||||
// Disable input capture
|
||||
|
||||
softSerial->timerHardware->tim->CCER &= ~softSerial->ccEnableBit;
|
||||
|
||||
IOConfigGPIO(softSerial->rxIO, IOCFG_IN_FLOATING);
|
||||
softSerial->rxActive = false;
|
||||
}
|
||||
|
||||
static void serialOutputPortActivate(softSerial_t *softSerial)
|
||||
{
|
||||
IOConfigGPIO(softSerial->txIO, IOCFG_OUT_PP);
|
||||
}
|
||||
|
||||
static void serialOutputPortDeActivate(softSerial_t *softSerial)
|
||||
{
|
||||
IOConfigGPIO(softSerial->txIO, IOCFG_IN_FLOATING);
|
||||
}
|
||||
|
||||
static bool isTimerPeriodTooLarge(uint32_t timerPeriod)
|
||||
|
@ -120,10 +192,12 @@ static bool isTimerPeriodTooLarge(uint32_t timerPeriod)
|
|||
return timerPeriod > 0xFFFF;
|
||||
}
|
||||
|
||||
static void serialTimerTxConfig(const timerHardware_t *timerHardwarePtr, uint8_t reference, uint32_t baud)
|
||||
static void serialTimerConfigureTimebase(const timerHardware_t *timerHardwarePtr, uint32_t baud)
|
||||
{
|
||||
uint32_t clock = SystemCoreClock;
|
||||
uint32_t baseClock = SystemCoreClock / timerClockDivisor(timerHardwarePtr->tim);
|
||||
uint32_t clock = baseClock;
|
||||
uint32_t timerPeriod;
|
||||
|
||||
do {
|
||||
timerPeriod = clock / baud;
|
||||
if (isTimerPeriodTooLarge(timerPeriod)) {
|
||||
|
@ -136,10 +210,9 @@ static void serialTimerTxConfig(const timerHardware_t *timerHardwarePtr, uint8_t
|
|||
}
|
||||
} while (isTimerPeriodTooLarge(timerPeriod));
|
||||
|
||||
uint8_t mhz = SystemCoreClock / 1000000;
|
||||
uint8_t mhz = baseClock / 1000000;
|
||||
|
||||
timerConfigure(timerHardwarePtr, timerPeriod, mhz);
|
||||
timerChCCHandlerInit(&softSerialPorts[reference].timerCb, onSerialTimer);
|
||||
timerChConfigCallbacks(timerHardwarePtr, &softSerialPorts[reference].timerCb, NULL);
|
||||
}
|
||||
|
||||
static void serialICConfig(TIM_TypeDef *tim, uint8_t channel, uint16_t polarity)
|
||||
|
@ -156,14 +229,6 @@ static void serialICConfig(TIM_TypeDef *tim, uint8_t channel, uint16_t polarity)
|
|||
TIM_ICInit(tim, &TIM_ICInitStructure);
|
||||
}
|
||||
|
||||
static void serialTimerRxConfig(const timerHardware_t *timerHardwarePtr, uint8_t reference, portOptions_t options)
|
||||
{
|
||||
// start bit is usually a FALLING signal
|
||||
serialICConfig(timerHardwarePtr->tim, timerHardwarePtr->channel, (options & SERIAL_INVERTED) ? TIM_ICPolarity_Rising : TIM_ICPolarity_Falling);
|
||||
timerChCCHandlerInit(&softSerialPorts[reference].edgeCb, onSerialRxPinChange);
|
||||
timerChConfigCallbacks(timerHardwarePtr, &softSerialPorts[reference].edgeCb, NULL);
|
||||
}
|
||||
|
||||
static void resetBuffers(softSerial_t *softSerial)
|
||||
{
|
||||
softSerial->port.rxBufferSize = SOFTSERIAL_BUFFER_SIZE;
|
||||
|
@ -177,71 +242,131 @@ static void resetBuffers(softSerial_t *softSerial)
|
|||
softSerial->port.txBufferHead = 0;
|
||||
}
|
||||
|
||||
serialPort_t *openSoftSerial(softSerialPortIndex_e portIndex, serialReceiveCallbackPtr rxCallback, uint32_t baud, portOptions_t options)
|
||||
serialPort_t *openSoftSerial(softSerialPortIndex_e portIndex, serialReceiveCallbackPtr rxCallback, uint32_t baud, portMode_t mode, portOptions_t options)
|
||||
{
|
||||
softSerial_t *softSerial = &(softSerialPorts[portIndex]);
|
||||
|
||||
#ifdef USE_SOFTSERIAL1
|
||||
if (portIndex == SOFTSERIAL1) {
|
||||
softSerial->rxTimerHardware = &(timerHardware[SOFTSERIAL_1_TIMER_RX_HARDWARE]);
|
||||
softSerial->txTimerHardware = &(timerHardware[SOFTSERIAL_1_TIMER_TX_HARDWARE]);
|
||||
}
|
||||
#endif
|
||||
int pinCfgIndex = portIndex + RESOURCE_SOFT_OFFSET;
|
||||
|
||||
#ifdef USE_SOFTSERIAL2
|
||||
if (portIndex == SOFTSERIAL2) {
|
||||
softSerial->rxTimerHardware = &(timerHardware[SOFTSERIAL_2_TIMER_RX_HARDWARE]);
|
||||
softSerial->txTimerHardware = &(timerHardware[SOFTSERIAL_2_TIMER_TX_HARDWARE]);
|
||||
}
|
||||
#endif
|
||||
ioTag_t tagRx = serialPinConfig()->ioTagRx[pinCfgIndex];
|
||||
ioTag_t tagTx = serialPinConfig()->ioTagTx[pinCfgIndex];
|
||||
|
||||
softSerial->port.vTable = softSerialVTable;
|
||||
const timerHardware_t *timerRx = timerGetByTag(tagRx, TIM_USE_ANY);
|
||||
const timerHardware_t *timerTx = timerGetByTag(tagTx, TIM_USE_ANY);
|
||||
|
||||
IO_t rxIO = IOGetByTag(tagRx);
|
||||
IO_t txIO = IOGetByTag(tagTx);
|
||||
|
||||
if (options & SERIAL_BIDIR) {
|
||||
// If RX and TX pins are both assigned, we CAN use either with a timer.
|
||||
// However, for consistency with hardware UARTs, we only use TX pin,
|
||||
// and this pin must have a timer.
|
||||
if (!timerTx)
|
||||
return NULL;
|
||||
|
||||
softSerial->timerHardware = timerTx;
|
||||
softSerial->txIO = txIO;
|
||||
softSerial->rxIO = txIO;
|
||||
IOInit(txIO, OWNER_SERIAL_TX, RESOURCE_INDEX(portIndex) + RESOURCE_SOFT_OFFSET);
|
||||
} else {
|
||||
if (mode & MODE_RX) {
|
||||
// Need a pin & a timer on RX
|
||||
if (!(tagRx && timerRx))
|
||||
return NULL;
|
||||
|
||||
softSerial->rxIO = rxIO;
|
||||
softSerial->timerHardware = timerRx;
|
||||
IOInit(rxIO, OWNER_SERIAL_RX, RESOURCE_INDEX(portIndex) + RESOURCE_SOFT_OFFSET);
|
||||
}
|
||||
|
||||
if (mode & MODE_TX) {
|
||||
// Need a pin on TX
|
||||
if (!tagTx)
|
||||
return NULL;
|
||||
|
||||
softSerial->txIO = txIO;
|
||||
softSerial->exTimerHardware = timerTx;
|
||||
IOInit(txIO, OWNER_SERIAL_TX, RESOURCE_INDEX(portIndex) + RESOURCE_SOFT_OFFSET);
|
||||
}
|
||||
}
|
||||
|
||||
softSerial->ccEnableBit = CCEnableBit(softSerial->timerHardware->channel);
|
||||
|
||||
//debug[2] = softSerial->ccEnableBit;
|
||||
|
||||
softSerial->port.vTable = &softSerialVTable;
|
||||
softSerial->port.baudRate = baud;
|
||||
softSerial->port.mode = MODE_RXTX;
|
||||
softSerial->port.mode = mode;
|
||||
softSerial->port.options = options;
|
||||
softSerial->port.rxCallback = rxCallback;
|
||||
|
||||
resetBuffers(softSerial);
|
||||
|
||||
softSerial->isTransmittingData = false;
|
||||
|
||||
softSerial->isSearchingForStartBit = true;
|
||||
softSerial->rxBitIndex = 0;
|
||||
softSerial->softSerialPortIndex = portIndex;
|
||||
|
||||
softSerial->transmissionErrors = 0;
|
||||
softSerial->receiveErrors = 0;
|
||||
|
||||
softSerial->softSerialPortIndex = portIndex;
|
||||
softSerial->rxActive = false;
|
||||
softSerial->isTransmittingData = false;
|
||||
|
||||
softSerial->txIO = IOGetByTag(softSerial->txTimerHardware->tag);
|
||||
serialOutputPortConfig(softSerial->txTimerHardware->tag, portIndex);
|
||||
// Configure master timer (on RX); time base and input capture
|
||||
|
||||
softSerial->rxIO = IOGetByTag(softSerial->rxTimerHardware->tag);
|
||||
serialInputPortConfig(softSerial->rxTimerHardware->tag, portIndex);
|
||||
serialTimerConfigureTimebase(softSerial->timerHardware, baud);
|
||||
serialICConfig(softSerial->timerHardware->tim, softSerial->timerHardware->channel, (options & SERIAL_INVERTED) ? TIM_ICPolarity_Rising : TIM_ICPolarity_Falling);
|
||||
|
||||
setTxSignal(softSerial, ENABLE);
|
||||
delay(50);
|
||||
// Initialize callbacks
|
||||
timerChCCHandlerInit(&softSerial->edgeCb, onSerialRxPinChange);
|
||||
timerChOvrHandlerInit(&softSerial->overCb, onSerialTimerOverflow);
|
||||
|
||||
serialTimerTxConfig(softSerial->txTimerHardware, portIndex, baud);
|
||||
serialTimerRxConfig(softSerial->rxTimerHardware, portIndex, options);
|
||||
// Configure bit clock interrupt & handler.
|
||||
// If we have an extra timer (on TX), it is initialized and configured
|
||||
// for overflow interrupt.
|
||||
// Receiver input capture is configured when input is activated.
|
||||
|
||||
if ((mode & MODE_TX) && softSerial->exTimerHardware && softSerial->exTimerHardware->tim != softSerial->timerHardware->tim) {
|
||||
softSerial->timerMode = TIMER_MODE_DUAL;
|
||||
serialTimerConfigureTimebase(softSerial->exTimerHardware, baud);
|
||||
timerChConfigCallbacks(softSerial->exTimerHardware, NULL, &softSerial->overCb);
|
||||
timerChConfigCallbacks(softSerial->timerHardware, &softSerial->edgeCb, NULL);
|
||||
} else {
|
||||
softSerial->timerMode = TIMER_MODE_SINGLE;
|
||||
timerChConfigCallbacks(softSerial->timerHardware, &softSerial->edgeCb, &softSerial->overCb);
|
||||
}
|
||||
|
||||
if (!(options & SERIAL_BIDIR)) {
|
||||
serialOutputPortActivate(softSerial);
|
||||
setTxSignal(softSerial, ENABLE);
|
||||
}
|
||||
|
||||
serialInputPortActivate(softSerial);
|
||||
|
||||
return &softSerial->port;
|
||||
}
|
||||
|
||||
/*********************************************/
|
||||
|
||||
//
|
||||
// Serial engines
|
||||
//
|
||||
|
||||
void processTxState(softSerial_t *softSerial)
|
||||
{
|
||||
uint8_t mask;
|
||||
|
||||
if (!softSerial->isTransmittingData) {
|
||||
char byteToSend;
|
||||
if (isSoftSerialTransmitBufferEmpty((serialPort_t *)softSerial)) {
|
||||
// Transmit buffer empty.
|
||||
// Start listening if not already in if half-duplex
|
||||
if (!softSerial->rxActive && softSerial->port.options & SERIAL_BIDIR) {
|
||||
serialOutputPortDeActivate(softSerial);
|
||||
serialInputPortActivate(softSerial);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// data to send
|
||||
byteToSend = softSerial->port.txBuffer[softSerial->port.txBufferTail++];
|
||||
char byteToSend = softSerial->port.txBuffer[softSerial->port.txBufferTail++];
|
||||
if (softSerial->port.txBufferTail >= softSerial->port.txBufferSize) {
|
||||
softSerial->port.txBufferTail = 0;
|
||||
}
|
||||
|
@ -251,6 +376,12 @@ void processTxState(softSerial_t *softSerial)
|
|||
softSerial->bitsLeftToTransmit = TX_TOTAL_BITS;
|
||||
softSerial->isTransmittingData = true;
|
||||
|
||||
if (softSerial->rxActive && (softSerial->port.options & SERIAL_BIDIR)) {
|
||||
// Half-duplex: Deactivate receiver, activate transmitter
|
||||
serialInputPortDeActivate(softSerial);
|
||||
serialOutputPortActivate(softSerial);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -288,9 +419,7 @@ void prepareForNextRxByte(softSerial_t *softSerial)
|
|||
softSerial->isSearchingForStartBit = true;
|
||||
if (softSerial->rxEdge == LEADING) {
|
||||
softSerial->rxEdge = TRAILING;
|
||||
serialICConfig(
|
||||
softSerial->rxTimerHardware->tim,
|
||||
softSerial->rxTimerHardware->channel,
|
||||
serialICConfig(softSerial->timerHardware->tim, softSerial->timerHardware->channel,
|
||||
(softSerial->port.options & SERIAL_INVERTED) ? TIM_ICPolarity_Rising : TIM_ICPolarity_Falling
|
||||
);
|
||||
}
|
||||
|
@ -347,18 +476,24 @@ void processRxState(softSerial_t *softSerial)
|
|||
}
|
||||
}
|
||||
|
||||
void onSerialTimer(timerCCHandlerRec_t *cbRec, captureCompare_t capture)
|
||||
void onSerialTimerOverflow(timerOvrHandlerRec_t *cbRec, captureCompare_t capture)
|
||||
{
|
||||
UNUSED(capture);
|
||||
softSerial_t *softSerial = container_of(cbRec, softSerial_t, timerCb);
|
||||
//debug[0]++;
|
||||
|
||||
processTxState(softSerial);
|
||||
processRxState(softSerial);
|
||||
softSerial_t *softSerial = container_of(cbRec, softSerial_t, overCb);
|
||||
|
||||
if (softSerial->port.mode & MODE_TX)
|
||||
processTxState(softSerial);
|
||||
|
||||
if (softSerial->port.mode & MODE_RX)
|
||||
processRxState(softSerial);
|
||||
}
|
||||
|
||||
void onSerialRxPinChange(timerCCHandlerRec_t *cbRec, captureCompare_t capture)
|
||||
{
|
||||
UNUSED(capture);
|
||||
//debug[1]++;
|
||||
|
||||
softSerial_t *softSerial = container_of(cbRec, softSerial_t, edgeCb);
|
||||
bool inverted = softSerial->port.options & SERIAL_INVERTED;
|
||||
|
@ -371,12 +506,12 @@ void onSerialRxPinChange(timerCCHandlerRec_t *cbRec, captureCompare_t capture)
|
|||
// synchronise bit counter
|
||||
// FIXME this reduces functionality somewhat as receiving breaks concurrent transmission on all ports because
|
||||
// the next callback to the onSerialTimer will happen too early causing transmission errors.
|
||||
TIM_SetCounter(softSerial->rxTimerHardware->tim, softSerial->rxTimerHardware->tim->ARR / 2);
|
||||
if (softSerial->isTransmittingData) {
|
||||
TIM_SetCounter(softSerial->timerHardware->tim, softSerial->timerHardware->tim->ARR / 2);
|
||||
if ((softSerial->timerMode != TIMER_MODE_DUAL) && softSerial->isTransmittingData) {
|
||||
softSerial->transmissionErrors++;
|
||||
}
|
||||
|
||||
serialICConfig(softSerial->rxTimerHardware->tim, softSerial->rxTimerHardware->channel, inverted ? TIM_ICPolarity_Falling : TIM_ICPolarity_Rising);
|
||||
serialICConfig(softSerial->timerHardware->tim, softSerial->timerHardware->channel, inverted ? TIM_ICPolarity_Falling : TIM_ICPolarity_Rising);
|
||||
softSerial->rxEdge = LEADING;
|
||||
|
||||
softSerial->rxBitIndex = 0;
|
||||
|
@ -394,13 +529,17 @@ void onSerialRxPinChange(timerCCHandlerRec_t *cbRec, captureCompare_t capture)
|
|||
|
||||
if (softSerial->rxEdge == TRAILING) {
|
||||
softSerial->rxEdge = LEADING;
|
||||
serialICConfig(softSerial->rxTimerHardware->tim, softSerial->rxTimerHardware->channel, inverted ? TIM_ICPolarity_Falling : TIM_ICPolarity_Rising);
|
||||
serialICConfig(softSerial->timerHardware->tim, softSerial->timerHardware->channel, inverted ? TIM_ICPolarity_Falling : TIM_ICPolarity_Rising);
|
||||
} else {
|
||||
softSerial->rxEdge = TRAILING;
|
||||
serialICConfig(softSerial->rxTimerHardware->tim, softSerial->rxTimerHardware->channel, inverted ? TIM_ICPolarity_Rising : TIM_ICPolarity_Falling);
|
||||
serialICConfig(softSerial->timerHardware->tim, softSerial->timerHardware->channel, inverted ? TIM_ICPolarity_Rising : TIM_ICPolarity_Falling);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Standard serial driver API
|
||||
//
|
||||
|
||||
uint32_t softSerialRxBytesWaiting(const serialPort_t *instance)
|
||||
{
|
||||
if ((instance->mode & MODE_RX) == 0) {
|
||||
|
@ -455,7 +594,10 @@ void softSerialWriteByte(serialPort_t *s, uint8_t ch)
|
|||
void softSerialSetBaudRate(serialPort_t *s, uint32_t baudRate)
|
||||
{
|
||||
softSerial_t *softSerial = (softSerial_t *)s;
|
||||
openSoftSerial(softSerial->softSerialPortIndex, s->rxCallback, baudRate, softSerial->port.options);
|
||||
|
||||
softSerial->port.baudRate = baudRate;
|
||||
|
||||
serialTimerConfigureTimebase(softSerial->timerHardware, baudRate);
|
||||
}
|
||||
|
||||
void softSerialSetMode(serialPort_t *instance, portMode_t mode)
|
||||
|
@ -468,19 +610,17 @@ bool isSoftSerialTransmitBufferEmpty(const serialPort_t *instance)
|
|||
return instance->txBufferHead == instance->txBufferTail;
|
||||
}
|
||||
|
||||
const struct serialPortVTable softSerialVTable[] = {
|
||||
{
|
||||
.serialWrite = softSerialWriteByte,
|
||||
.serialTotalRxWaiting = softSerialRxBytesWaiting,
|
||||
.serialTotalTxFree = softSerialTxBytesFree,
|
||||
.serialRead = softSerialReadByte,
|
||||
.serialSetBaudRate = softSerialSetBaudRate,
|
||||
.isSerialTransmitBufferEmpty = isSoftSerialTransmitBufferEmpty,
|
||||
.setMode = softSerialSetMode,
|
||||
.writeBuf = NULL,
|
||||
.beginWrite = NULL,
|
||||
.endWrite = NULL
|
||||
}
|
||||
static const struct serialPortVTable softSerialVTable = {
|
||||
.serialWrite = softSerialWriteByte,
|
||||
.serialTotalRxWaiting = softSerialRxBytesWaiting,
|
||||
.serialTotalTxFree = softSerialTxBytesFree,
|
||||
.serialRead = softSerialReadByte,
|
||||
.serialSetBaudRate = softSerialSetBaudRate,
|
||||
.isSerialTransmitBufferEmpty = isSoftSerialTransmitBufferEmpty,
|
||||
.setMode = softSerialSetMode,
|
||||
.writeBuf = NULL,
|
||||
.beginWrite = NULL,
|
||||
.endWrite = NULL
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue