2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
27 #if defined(USE_ESCSERIAL)
29 #include "build/build_config.h"
30 #include "build/atomic.h"
32 #include "common/utils.h"
34 #include "drivers/io.h"
35 #include "drivers/light_led.h"
36 #include "drivers/nvic.h"
37 #include "drivers/pwm_output.h"
38 #include "drivers/serial.h"
39 #include "drivers/serial_escserial.h"
40 #include "drivers/time.h"
41 #include "drivers/timer.h"
43 #include "flight/mixer.h"
45 #include "io/serial.h"
51 BAUDRATE_NORMAL
= 19200,
52 BAUDRATE_SIMONK
= 28800, // = 9600 * 3
53 BAUDRATE_KISS
= 38400,
54 BAUDRATE_CASTLE
= 18880
57 #define RX_TOTAL_BITS 10
58 #define TX_TOTAL_BITS 10
60 #define MAX_ESCSERIAL_PORTS 1
61 static serialPort_t
*escPort
= NULL
;
62 static serialPort_t
*passPort
= NULL
;
64 #define ICPOLARITY_RISING true
65 #define ICPOLARITY_FALLING false
67 typedef struct escSerial_s
{
73 const timerHardware_t
*rxTimerHardware
;
74 volatile uint8_t rxBuffer
[ESCSERIAL_BUFFER_SIZE
];
75 const timerHardware_t
*txTimerHardware
;
76 volatile uint8_t txBuffer
[ESCSERIAL_BUFFER_SIZE
];
79 const TIM_HandleTypeDef
*txTimerHandle
;
80 const TIM_HandleTypeDef
*rxTimerHandle
;
83 uint8_t isSearchingForStartBit
;
85 uint8_t rxLastLeadingEdgeAtBitIndex
;
88 uint8_t isTransmittingData
;
89 uint8_t isReceivingData
;
90 int8_t bitsLeftToTransmit
;
92 uint16_t internalTxBuffer
; // includes start and stop bits
93 uint16_t internalRxBuffer
; // includes start and stop bits
95 uint16_t receiveTimeout
;
96 uint16_t transmissionErrors
;
97 uint16_t receiveErrors
;
99 uint8_t escSerialPortIndex
;
103 timerCCHandlerRec_t timerCb
;
104 timerCCHandlerRec_t edgeCb
;
112 escOutputs_t escOutputs
[MAX_SUPPORTED_MOTORS
];
114 extern timerHardware_t
* serialTimerHardware
;
116 const struct serialPortVTable escSerialVTable
[];
118 escSerial_t escSerialPorts
[MAX_ESCSERIAL_PORTS
];
120 PG_REGISTER_WITH_RESET_TEMPLATE(escSerialConfig_t
, escSerialConfig
, PG_ESCSERIAL_CONFIG
, 0);
122 #ifndef ESCSERIAL_TIMER_TX_PIN
123 #define ESCSERIAL_TIMER_TX_PIN NONE
126 PG_RESET_TEMPLATE(escSerialConfig_t
, escSerialConfig
,
127 .ioTag
= IO_TAG(ESCSERIAL_TIMER_TX_PIN
),
135 #define STOP_BIT_MASK (1 << 0)
136 #define START_BIT_MASK (1 << (RX_TOTAL_BITS - 1))
138 // XXX No TIM_DeInit equivalent in HAL driver???
139 #ifdef USE_HAL_DRIVER
140 static void TIM_DeInit(TIM_TypeDef
*tim
)
146 static void setTxSignalEsc(escSerial_t
*escSerial
, uint8_t state
)
148 if (escSerial
->mode
== PROTOCOL_KISSALL
)
150 for (volatile uint8_t i
= 0; i
< escSerial
->outputCount
; i
++) {
151 uint8_t state_temp
= state
;
152 if (escOutputs
[i
].inverted
) {
153 state_temp
^= ENABLE
;
157 IOHi(escOutputs
[i
].io
);
159 IOLo(escOutputs
[i
].io
);
165 if (escSerial
->rxTimerHardware
->output
& TIMER_OUTPUT_INVERTED
) {
170 IOHi(escSerial
->txIO
);
172 IOLo(escSerial
->txIO
);
177 static void escSerialGPIOConfig(const timerHardware_t
*timhw
, ioConfig_t cfg
)
179 ioTag_t tag
= timhw
->tag
;
185 IOInit(IOGetByTag(tag
), OWNER_MOTOR
, 0);
187 IOConfigGPIOAF(IOGetByTag(tag
), cfg
, timhw
->alternateFunction
);
189 IOConfigGPIO(IOGetByTag(tag
), cfg
);
193 static void escSerialInputPortConfig(const timerHardware_t
*timerHardwarePtr
)
196 escSerialGPIOConfig(timerHardwarePtr
, IOCFG_IPU
);
198 escSerialGPIOConfig(timerHardwarePtr
, IOCFG_AF_PP_UP
);
200 timerChClearCCFlag(timerHardwarePtr
);
201 timerChITConfig(timerHardwarePtr
,ENABLE
);
205 static bool isTimerPeriodTooLarge(uint32_t timerPeriod
)
207 return timerPeriod
> 0xFFFF;
210 static bool isEscSerialTransmitBufferEmpty(const serialPort_t
*instance
)
213 return instance
->txBufferHead
== instance
->txBufferTail
;
216 static void escSerialOutputPortConfig(const timerHardware_t
*timerHardwarePtr
)
218 escSerialGPIOConfig(timerHardwarePtr
, IOCFG_OUT_PP
);
219 timerChITConfig(timerHardwarePtr
,DISABLE
);
222 static void processTxStateBL(escSerial_t
*escSerial
)
225 if (escSerial
->isReceivingData
) {
229 if (!escSerial
->isTransmittingData
) {
231 if (isEscSerialTransmitBufferEmpty((serialPort_t
*)escSerial
)) {
237 byteToSend
= escSerial
->port
.txBuffer
[escSerial
->port
.txBufferTail
++];
238 if (escSerial
->port
.txBufferTail
>= escSerial
->port
.txBufferSize
) {
239 escSerial
->port
.txBufferTail
= 0;
242 // build internal buffer, MSB = Stop Bit (1) + data bits (MSB to LSB) + start bit(0) LSB
243 escSerial
->internalTxBuffer
= (1 << (TX_TOTAL_BITS
- 1)) | (byteToSend
<< 1);
244 escSerial
->bitsLeftToTransmit
= TX_TOTAL_BITS
;
245 escSerial
->isTransmittingData
= true;
249 if (escSerial
->mode
==PROTOCOL_BLHELI
|| escSerial
->mode
==PROTOCOL_CASTLE
) {
250 escSerialOutputPortConfig(escSerial
->rxTimerHardware
);
255 if (escSerial
->bitsLeftToTransmit
) {
256 mask
= escSerial
->internalTxBuffer
& 1;
257 escSerial
->internalTxBuffer
>>= 1;
259 setTxSignalEsc(escSerial
, mask
);
260 escSerial
->bitsLeftToTransmit
--;
264 escSerial
->isTransmittingData
= false;
265 if (isEscSerialTransmitBufferEmpty((serialPort_t
*)escSerial
)) {
266 if (escSerial
->mode
==PROTOCOL_BLHELI
|| escSerial
->mode
==PROTOCOL_CASTLE
)
268 escSerialInputPortConfig(escSerial
->rxTimerHardware
);
273 static void extractAndStoreRxByteBL(escSerial_t
*escSerial
)
275 if ((escSerial
->port
.mode
& MODE_RX
) == 0) {
279 uint8_t haveStartBit
= (escSerial
->internalRxBuffer
& START_BIT_MASK
) == 0;
280 uint8_t haveStopBit
= (escSerial
->internalRxBuffer
& STOP_BIT_MASK
) == 1;
282 if (!haveStartBit
|| !haveStopBit
) {
283 escSerial
->receiveErrors
++;
287 uint8_t rxByte
= (escSerial
->internalRxBuffer
>> 1) & 0xFF;
289 if (escSerial
->port
.rxCallback
) {
290 escSerial
->port
.rxCallback(rxByte
, escSerial
->port
.rxCallbackData
);
292 escSerial
->port
.rxBuffer
[escSerial
->port
.rxBufferHead
] = rxByte
;
293 escSerial
->port
.rxBufferHead
= (escSerial
->port
.rxBufferHead
+ 1) % escSerial
->port
.rxBufferSize
;
297 static void prepareForNextRxByteBL(escSerial_t
*escSerial
)
299 // prepare for next byte
300 escSerial
->rxBitIndex
= 0;
301 escSerial
->isSearchingForStartBit
= true;
302 if (escSerial
->rxEdge
== LEADING
) {
303 escSerial
->rxEdge
= TRAILING
;
305 escSerial
->rxTimerHardware
,
306 (escSerial
->port
.options
& SERIAL_INVERTED
) ? ICPOLARITY_RISING
: ICPOLARITY_FALLING
, 0
311 static void applyChangedBitsBL(escSerial_t
*escSerial
)
313 if (escSerial
->rxEdge
== TRAILING
) {
315 for (bitToSet
= escSerial
->rxLastLeadingEdgeAtBitIndex
; bitToSet
< escSerial
->rxBitIndex
; bitToSet
++) {
316 escSerial
->internalRxBuffer
|= 1 << bitToSet
;
321 static void processRxStateBL(escSerial_t
*escSerial
)
323 if (escSerial
->isSearchingForStartBit
) {
327 escSerial
->rxBitIndex
++;
329 if (escSerial
->rxBitIndex
== RX_TOTAL_BITS
- 1) {
330 applyChangedBitsBL(escSerial
);
334 if (escSerial
->rxBitIndex
== RX_TOTAL_BITS
) {
336 if (escSerial
->rxEdge
== TRAILING
) {
337 escSerial
->internalRxBuffer
|= STOP_BIT_MASK
;
340 extractAndStoreRxByteBL(escSerial
);
341 prepareForNextRxByteBL(escSerial
);
345 static void onSerialTimerBL(timerCCHandlerRec_t
*cbRec
, captureCompare_t capture
)
348 escSerial_t
*escSerial
= container_of(cbRec
, escSerial_t
, timerCb
);
350 processTxStateBL(escSerial
);
351 processRxStateBL(escSerial
);
354 static void serialTimerTxConfigBL(const timerHardware_t
*timerHardwarePtr
, uint8_t reference
, uint32_t baud
)
356 uint32_t clock
= SystemCoreClock
/2;
357 uint32_t timerPeriod
;
358 TIM_DeInit(timerHardwarePtr
->tim
);
360 timerPeriod
= clock
/ baud
;
361 if (isTimerPeriodTooLarge(timerPeriod
)) {
363 clock
= clock
/ 2; // this is wrong - mhz stays the same ... This will double baudrate until ok (but minimum baudrate is < 1200)
365 // TODO unable to continue, unable to determine clock and timerPeriods for the given baud
369 } while (isTimerPeriodTooLarge(timerPeriod
));
371 timerConfigure(timerHardwarePtr
, timerPeriod
, clock
);
372 timerChCCHandlerInit(&escSerialPorts
[reference
].timerCb
, onSerialTimerBL
);
373 timerChConfigCallbacks(timerHardwarePtr
, &escSerialPorts
[reference
].timerCb
, NULL
);
376 static void onSerialRxPinChangeBL(timerCCHandlerRec_t
*cbRec
, captureCompare_t capture
)
380 escSerial_t
*escSerial
= container_of(cbRec
, escSerial_t
, edgeCb
);
381 bool inverted
= escSerial
->port
.options
& SERIAL_INVERTED
;
383 if ((escSerial
->port
.mode
& MODE_RX
) == 0) {
387 if (escSerial
->isSearchingForStartBit
) {
388 // Adjust the timing so it will interrupt on the middle.
389 // This is clobbers transmission, but it is okay because we are
390 // always half-duplex.
391 #ifdef USE_HAL_DRIVER
392 __HAL_TIM_SetCounter(escSerial
->txTimerHandle
, __HAL_TIM_GetAutoreload(escSerial
->txTimerHandle
) / 2);
394 TIM_SetCounter(escSerial
->txTimerHardware
->tim
, escSerial
->txTimerHardware
->tim
->ARR
/ 2);
396 if (escSerial
->isTransmittingData
) {
397 escSerial
->transmissionErrors
++;
400 timerChConfigIC(escSerial
->rxTimerHardware
, inverted
? ICPOLARITY_FALLING
: ICPOLARITY_RISING
, 0);
401 escSerial
->rxEdge
= LEADING
;
403 escSerial
->rxBitIndex
= 0;
404 escSerial
->rxLastLeadingEdgeAtBitIndex
= 0;
405 escSerial
->internalRxBuffer
= 0;
406 escSerial
->isSearchingForStartBit
= false;
410 if (escSerial
->rxEdge
== LEADING
) {
411 escSerial
->rxLastLeadingEdgeAtBitIndex
= escSerial
->rxBitIndex
;
414 applyChangedBitsBL(escSerial
);
416 if (escSerial
->rxEdge
== TRAILING
) {
417 escSerial
->rxEdge
= LEADING
;
418 timerChConfigIC(escSerial
->rxTimerHardware
, inverted
? ICPOLARITY_FALLING
: ICPOLARITY_RISING
, 0);
420 escSerial
->rxEdge
= TRAILING
;
421 timerChConfigIC(escSerial
->rxTimerHardware
, inverted
? ICPOLARITY_RISING
: ICPOLARITY_FALLING
, 0);
425 static void serialTimerRxConfigBL(const timerHardware_t
*timerHardwarePtr
, uint8_t reference
, portOptions_e options
)
427 // start bit is usually a FALLING signal
428 TIM_DeInit(timerHardwarePtr
->tim
);
429 timerConfigure(timerHardwarePtr
, 0xFFFF, SystemCoreClock
/ 2);
430 timerChConfigIC(timerHardwarePtr
, (options
& SERIAL_INVERTED
) ? ICPOLARITY_RISING
: ICPOLARITY_FALLING
, 0);
431 timerChCCHandlerInit(&escSerialPorts
[reference
].edgeCb
, onSerialRxPinChangeBL
);
432 timerChConfigCallbacks(timerHardwarePtr
, &escSerialPorts
[reference
].edgeCb
, NULL
);
435 #ifdef USE_ESCSERIAL_SIMONK
436 static void processTxStateEsc(escSerial_t
*escSerial
)
439 static uint8_t bitq
=0, transmitStart
=0;
440 if (escSerial
->isReceivingData
) {
444 if (transmitStart
==0)
446 setTxSignalEsc(escSerial
, 1);
448 if (!escSerial
->isTransmittingData
) {
451 if (isEscSerialTransmitBufferEmpty((serialPort_t
*)escSerial
)) {
459 if (transmitStart
==0)
461 if (transmitStart
==1)
463 if (transmitStart
==2)
469 byteToSend
= escSerial
->port
.txBuffer
[escSerial
->port
.txBufferTail
++];
470 if (escSerial
->port
.txBufferTail
>= escSerial
->port
.txBufferSize
) {
471 escSerial
->port
.txBufferTail
= 0;
476 // build internal buffer, data bits (MSB to LSB)
477 escSerial
->internalTxBuffer
= byteToSend
;
478 escSerial
->bitsLeftToTransmit
= 8;
479 escSerial
->isTransmittingData
= true;
482 escSerialOutputPortConfig(escSerial
->rxTimerHardware
);
486 if (escSerial
->bitsLeftToTransmit
) {
487 mask
= escSerial
->internalTxBuffer
& 1;
490 if (bitq
==0 || bitq
==1)
492 setTxSignalEsc(escSerial
, 1);
494 if (bitq
==2 || bitq
==3)
496 setTxSignalEsc(escSerial
, 0);
501 if (bitq
==0 || bitq
==2)
503 setTxSignalEsc(escSerial
, 1);
505 if (bitq
==1 ||bitq
==3)
507 setTxSignalEsc(escSerial
, 0);
513 escSerial
->internalTxBuffer
>>= 1;
514 escSerial
->bitsLeftToTransmit
--;
516 if (escSerial
->bitsLeftToTransmit
==0)
524 if (isEscSerialTransmitBufferEmpty((serialPort_t
*)escSerial
)) {
525 escSerial
->isTransmittingData
= false;
526 escSerialInputPortConfig(escSerial
->rxTimerHardware
);
530 static void onSerialTimerEsc(timerCCHandlerRec_t
*cbRec
, captureCompare_t capture
)
533 escSerial_t
*escSerial
= container_of(cbRec
, escSerial_t
, timerCb
);
535 if (escSerial
->isReceivingData
)
537 escSerial
->receiveTimeout
++;
538 if (escSerial
->receiveTimeout
>8)
540 escSerial
->isReceivingData
=0;
541 escSerial
->receiveTimeout
=0;
542 timerChConfigIC(escSerial
->rxTimerHardware
, ICPOLARITY_FALLING
, 0);
546 processTxStateEsc(escSerial
);
549 static void escSerialTimerTxConfig(const timerHardware_t
*timerHardwarePtr
, uint8_t reference
)
551 uint32_t timerPeriod
= 34;
552 TIM_DeInit(timerHardwarePtr
->tim
);
553 timerConfigure(timerHardwarePtr
, timerPeriod
, MHZ_TO_HZ(1));
554 timerChCCHandlerInit(&escSerialPorts
[reference
].timerCb
, onSerialTimerEsc
);
555 timerChConfigCallbacks(timerHardwarePtr
, &escSerialPorts
[reference
].timerCb
, NULL
);
558 static void extractAndStoreRxByteEsc(escSerial_t
*escSerial
)
560 if ((escSerial
->port
.mode
& MODE_RX
) == 0) {
564 uint8_t rxByte
= (escSerial
->internalRxBuffer
) & 0xFF;
566 if (escSerial
->port
.rxCallback
) {
567 escSerial
->port
.rxCallback(rxByte
, escSerial
->port
.rxCallbackData
);
569 escSerial
->port
.rxBuffer
[escSerial
->port
.rxBufferHead
] = rxByte
;
570 escSerial
->port
.rxBufferHead
= (escSerial
->port
.rxBufferHead
+ 1) % escSerial
->port
.rxBufferSize
;
574 static void onSerialRxPinChangeEsc(timerCCHandlerRec_t
*cbRec
, captureCompare_t capture
)
577 static uint8_t zerofirst
=0;
578 static uint8_t bits
=0;
579 static uint16_t bytes
=0;
581 escSerial_t
*escSerial
= container_of(cbRec
, escSerial_t
, edgeCb
);
584 #ifdef USE_HAL_DRIVER
585 __HAL_TIM_SetCounter(escSerial
->rxTimerHandle
, 0);
587 TIM_SetCounter(escSerial
->rxTimerHardware
->tim
,0);
590 if (capture
> 40 && capture
< 90)
596 escSerial
->internalRxBuffer
= escSerial
->internalRxBuffer
>>1;
600 else if (capture
>90 && capture
< 200)
603 escSerial
->internalRxBuffer
= escSerial
->internalRxBuffer
>>1;
604 escSerial
->internalRxBuffer
|= 0x80;
609 if (!escSerial
->isReceivingData
)
614 escSerial
->isReceivingData
= 1;
618 escSerial
->internalRxBuffer
= 0x80;
620 timerChConfigIC(escSerial
->rxTimerHardware
, ICPOLARITY_RISING
, 0);
623 escSerial
->receiveTimeout
= 0;
631 extractAndStoreRxByteEsc(escSerial
);
633 escSerial
->internalRxBuffer
=0;
638 static void escSerialTimerRxConfig(const timerHardware_t
*timerHardwarePtr
, uint8_t reference
)
640 // start bit is usually a FALLING signal
641 TIM_DeInit(timerHardwarePtr
->tim
);
642 timerConfigure(timerHardwarePtr
, 0xFFFF, MHZ_TO_HZ(1));
643 timerChConfigIC(timerHardwarePtr
, ICPOLARITY_FALLING
, 0);
644 timerChCCHandlerInit(&escSerialPorts
[reference
].edgeCb
, onSerialRxPinChangeEsc
);
645 timerChConfigCallbacks(timerHardwarePtr
, &escSerialPorts
[reference
].edgeCb
, NULL
);
649 static void resetBuffers(escSerial_t
*escSerial
)
651 escSerial
->port
.rxBufferSize
= ESCSERIAL_BUFFER_SIZE
;
652 escSerial
->port
.rxBuffer
= escSerial
->rxBuffer
;
653 escSerial
->port
.rxBufferTail
= 0;
654 escSerial
->port
.rxBufferHead
= 0;
656 escSerial
->port
.txBuffer
= escSerial
->txBuffer
;
657 escSerial
->port
.txBufferSize
= ESCSERIAL_BUFFER_SIZE
;
658 escSerial
->port
.txBufferTail
= 0;
659 escSerial
->port
.txBufferHead
= 0;
662 static serialPort_t
*openEscSerial(const motorDevConfig_t
*motorConfig
, escSerialPortIndex_e portIndex
, serialReceiveCallbackPtr callback
, uint16_t output
, uint32_t baud
, portOptions_e options
, uint8_t mode
)
664 escSerial_t
*escSerial
= &(escSerialPorts
[portIndex
]);
666 if (escSerialConfig()->ioTag
== IO_TAG_NONE
) {
669 if (mode
!= PROTOCOL_KISSALL
) {
670 const ioTag_t tag
= motorConfig
->ioTags
[output
];
671 const timerHardware_t
*timerHardware
= timerAllocate(tag
, OWNER_MOTOR
, 0);
673 if (timerHardware
== NULL
) {
677 escSerial
->rxTimerHardware
= timerHardware
;
678 // N-Channels can't be used as RX.
679 if (escSerial
->rxTimerHardware
->output
& TIMER_OUTPUT_N_CHANNEL
) {
683 #ifdef USE_HAL_DRIVER
684 escSerial
->rxTimerHandle
= timerFindTimerHandle(escSerial
->rxTimerHardware
->tim
);
688 escSerial
->mode
= mode
;
689 escSerial
->txTimerHardware
= timerAllocate(escSerialConfig()->ioTag
, OWNER_MOTOR
, 0);
690 if (escSerial
->txTimerHardware
== NULL
) {
694 #ifdef USE_HAL_DRIVER
695 escSerial
->txTimerHandle
= timerFindTimerHandle(escSerial
->txTimerHardware
->tim
);
698 escSerial
->port
.vTable
= escSerialVTable
;
699 escSerial
->port
.baudRate
= baud
;
700 escSerial
->port
.mode
= MODE_RXTX
;
701 escSerial
->port
.options
= options
;
702 escSerial
->port
.rxCallback
= callback
;
704 resetBuffers(escSerial
);
706 escSerial
->isTransmittingData
= false;
708 escSerial
->isSearchingForStartBit
= true;
709 escSerial
->rxBitIndex
= 0;
711 escSerial
->transmissionErrors
= 0;
712 escSerial
->receiveErrors
= 0;
713 escSerial
->receiveTimeout
= 0;
715 escSerial
->escSerialPortIndex
= portIndex
;
717 if (mode
!= PROTOCOL_KISSALL
)
719 escSerial
->txIO
= IOGetByTag(escSerial
->rxTimerHardware
->tag
);
720 escSerialInputPortConfig(escSerial
->rxTimerHardware
);
721 setTxSignalEsc(escSerial
, ENABLE
);
725 #ifdef USE_ESCSERIAL_SIMONK
726 if (mode
==PROTOCOL_SIMONK
) {
727 escSerialTimerTxConfig(escSerial
->txTimerHardware
, portIndex
);
728 escSerialTimerRxConfig(escSerial
->rxTimerHardware
, portIndex
);
732 if (mode
==PROTOCOL_BLHELI
) {
733 serialTimerTxConfigBL(escSerial
->txTimerHardware
, portIndex
, baud
);
734 serialTimerRxConfigBL(escSerial
->rxTimerHardware
, portIndex
, options
);
736 else if (mode
==PROTOCOL_KISS
) {
737 escSerialOutputPortConfig(escSerial
->rxTimerHardware
); // rx is the pin used
738 serialTimerTxConfigBL(escSerial
->txTimerHardware
, portIndex
, baud
);
740 else if (mode
==PROTOCOL_KISSALL
) {
741 escSerial
->outputCount
= 0;
742 memset(&escOutputs
, 0, sizeof(escOutputs
));
743 pwmOutputPort_t
*pwmMotors
= pwmGetMotors();
744 for (volatile uint8_t i
= 0; i
< MAX_SUPPORTED_MOTORS
; i
++) {
745 if (pwmMotors
[i
].enabled
&& pwmMotors
[i
].io
!= IO_NONE
) {
746 const ioTag_t tag
= motorConfig
->ioTags
[i
];
747 if (tag
!= IO_TAG_NONE
) {
748 const timerHardware_t
*timerHardware
= timerAllocate(tag
, OWNER_MOTOR
, 0);
750 escSerialOutputPortConfig(timerHardware
);
751 escOutputs
[escSerial
->outputCount
].io
= pwmMotors
[i
].io
;
752 if (timerHardware
->output
& TIMER_OUTPUT_INVERTED
) {
753 escOutputs
[escSerial
->outputCount
].inverted
= 1;
755 escSerial
->outputCount
++;
760 setTxSignalEsc(escSerial
, ENABLE
);
761 serialTimerTxConfigBL(escSerial
->txTimerHardware
, portIndex
, baud
);
763 else if (mode
== PROTOCOL_CASTLE
) {
764 escSerialOutputPortConfig(escSerial
->rxTimerHardware
);
765 serialTimerTxConfigBL(escSerial
->txTimerHardware
, portIndex
, baud
);
766 serialTimerRxConfigBL(escSerial
->rxTimerHardware
, portIndex
, options
);
768 return &escSerial
->port
;
772 static void escSerialInputPortDeConfig(const timerHardware_t
*timerHardwarePtr
)
774 timerChClearCCFlag(timerHardwarePtr
);
775 timerChITConfig(timerHardwarePtr
,DISABLE
);
776 escSerialGPIOConfig(timerHardwarePtr
, IOCFG_IPU
);
780 static void closeEscSerial(escSerialPortIndex_e portIndex
, uint8_t mode
)
782 escSerial_t
*escSerial
= &(escSerialPorts
[portIndex
]);
784 if (mode
!= PROTOCOL_KISSALL
) {
785 escSerialInputPortDeConfig(escSerial
->rxTimerHardware
);
786 timerChConfigCallbacks(escSerial
->rxTimerHardware
,NULL
,NULL
);
787 TIM_DeInit(escSerial
->rxTimerHardware
->tim
);
790 timerChConfigCallbacks(escSerial
->txTimerHardware
,NULL
,NULL
);
791 TIM_DeInit(escSerial
->txTimerHardware
->tim
);
794 static uint32_t escSerialTotalBytesWaiting(const serialPort_t
*instance
)
796 if ((instance
->mode
& MODE_RX
) == 0) {
800 escSerial_t
*s
= (escSerial_t
*)instance
;
802 return (s
->port
.rxBufferHead
- s
->port
.rxBufferTail
) & (s
->port
.rxBufferSize
- 1);
805 static uint8_t escSerialReadByte(serialPort_t
*instance
)
809 if ((instance
->mode
& MODE_RX
) == 0) {
813 if (escSerialTotalBytesWaiting(instance
) == 0) {
817 ch
= instance
->rxBuffer
[instance
->rxBufferTail
];
818 instance
->rxBufferTail
= (instance
->rxBufferTail
+ 1) % instance
->rxBufferSize
;
822 static void escSerialWriteByte(serialPort_t
*s
, uint8_t ch
)
824 if ((s
->mode
& MODE_TX
) == 0) {
828 s
->txBuffer
[s
->txBufferHead
] = ch
;
829 s
->txBufferHead
= (s
->txBufferHead
+ 1) % s
->txBufferSize
;
832 static void escSerialSetBaudRate(serialPort_t
*s
, uint32_t baudRate
)
838 static void escSerialSetMode(serialPort_t
*instance
, portMode_e mode
)
840 instance
->mode
= mode
;
843 static uint32_t escSerialTxBytesFree(const serialPort_t
*instance
)
845 if ((instance
->mode
& MODE_TX
) == 0) {
849 escSerial_t
*s
= (escSerial_t
*)instance
;
851 uint8_t bytesUsed
= (s
->port
.txBufferHead
- s
->port
.txBufferTail
) & (s
->port
.txBufferSize
- 1);
853 return (s
->port
.txBufferSize
- 1) - bytesUsed
;
856 const struct serialPortVTable escSerialVTable
[] = {
858 .serialWrite
= escSerialWriteByte
,
859 .serialTotalRxWaiting
= escSerialTotalBytesWaiting
,
860 .serialTotalTxFree
= escSerialTxBytesFree
,
861 .serialRead
= escSerialReadByte
,
862 .serialSetBaudRate
= escSerialSetBaudRate
,
863 .isSerialTransmitBufferEmpty
= isEscSerialTransmitBufferEmpty
,
864 .setMode
= escSerialSetMode
,
865 .setCtrlLineStateCb
= NULL
,
866 .setBaudRateCb
= NULL
,
883 typedef struct mspPort_s
{
893 static mspPort_t currentPort
;
895 static bool processExitCommand(uint8_t c
)
897 if (currentPort
.c_state
== IDLE
) {
899 currentPort
.c_state
= HEADER_START
;
903 } else if (currentPort
.c_state
== HEADER_START
) {
904 currentPort
.c_state
= (c
== 'M') ? HEADER_M
: IDLE
;
905 } else if (currentPort
.c_state
== HEADER_M
) {
906 currentPort
.c_state
= (c
== '<') ? HEADER_ARROW
: IDLE
;
907 } else if (currentPort
.c_state
== HEADER_ARROW
) {
909 currentPort
.c_state
= IDLE
;
912 currentPort
.dataSize
= c
;
913 currentPort
.offset
= 0;
914 currentPort
.checksum
= 0;
915 currentPort
.indRX
= 0;
916 currentPort
.checksum
^= c
;
917 currentPort
.c_state
= HEADER_SIZE
;
919 } else if (currentPort
.c_state
== HEADER_SIZE
) {
920 currentPort
.cmdMSP
= c
;
921 currentPort
.checksum
^= c
;
922 currentPort
.c_state
= HEADER_CMD
;
923 } else if (currentPort
.c_state
== HEADER_CMD
&& currentPort
.offset
< currentPort
.dataSize
) {
924 currentPort
.checksum
^= c
;
925 currentPort
.inBuf
[currentPort
.offset
++] = c
;
926 } else if (currentPort
.c_state
== HEADER_CMD
&& currentPort
.offset
>= currentPort
.dataSize
) {
927 if (currentPort
.checksum
== c
) {
928 currentPort
.c_state
= COMMAND_RECEIVED
;
930 if ((currentPort
.cmdMSP
== 0xF4) && (currentPort
.dataSize
==0))
932 currentPort
.c_state
= IDLE
;
936 currentPort
.c_state
= IDLE
;
943 bool escEnablePassthrough(serialPort_t
*escPassthroughPort
, const motorDevConfig_t
*motorConfig
, uint16_t escIndex
, uint8_t mode
)
945 bool exitEsc
= false;
946 uint8_t motor_output
= escIndex
;
949 //StopPwmAllMotors();
950 // XXX Review effect of motor refactor
951 //pwmDisableMotors();
953 passPort
= escPassthroughPort
;
955 uint32_t escBaudrate
;
958 escBaudrate
= BAUDRATE_KISS
;
960 case PROTOCOL_CASTLE
:
961 escBaudrate
= BAUDRATE_CASTLE
;
964 escBaudrate
= BAUDRATE_NORMAL
;
968 if ((mode
== PROTOCOL_KISS
) && (motor_output
== 255)) {
969 mode
= PROTOCOL_KISSALL
;
970 } else if (motor_output
>= MAX_SUPPORTED_MOTORS
) {
974 escPort
= openEscSerial(motorConfig
, ESCSERIAL1
, NULL
, motor_output
, escBaudrate
, 0, mode
);
984 if (serialRxBytesWaiting(escPort
)) {
986 while (serialRxBytesWaiting(escPort
))
988 ch
= serialRead(escPort
);
989 serialWrite(escPassthroughPort
, ch
);
994 if (serialRxBytesWaiting(escPassthroughPort
)) {
996 while (serialRxBytesWaiting(escPassthroughPort
))
998 ch
= serialRead(escPassthroughPort
);
999 exitEsc
= processExitCommand(ch
);
1002 serialWrite(escPassthroughPort
, 0x24);
1003 serialWrite(escPassthroughPort
, 0x4D);
1004 serialWrite(escPassthroughPort
, 0x3E);
1005 serialWrite(escPassthroughPort
, 0x00);
1006 serialWrite(escPassthroughPort
, 0xF4);
1007 serialWrite(escPassthroughPort
, 0xF4);
1008 closeEscSerial(ESCSERIAL1
, mode
);
1011 if (mode
==PROTOCOL_BLHELI
) {
1012 serialWrite(escPassthroughPort
, ch
); // blheli loopback
1014 serialWrite(escPort
, ch
);
1018 if (mode
!= PROTOCOL_CASTLE
) {