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"
35 #include "pg/pg_ids.h"
37 #include "drivers/io.h"
38 #include "drivers/light_led.h"
39 #include "drivers/nvic.h"
40 #include "drivers/pwm_output.h"
41 #include "drivers/serial.h"
42 #include "drivers/serial_escserial.h"
43 #include "drivers/time.h"
44 #include "drivers/timer.h"
46 #include "flight/mixer.h"
48 #include "io/serial.h"
52 BAUDRATE_NORMAL
= 19200,
53 BAUDRATE_SIMONK
= 28800, // = 9600 * 3
54 BAUDRATE_KISS
= 38400,
55 BAUDRATE_CASTLE
= 18880
58 #define RX_TOTAL_BITS 10
59 #define TX_TOTAL_BITS 10
61 #define MAX_ESCSERIAL_PORTS 1
62 static serialPort_t
*escPort
= NULL
;
63 static serialPort_t
*passPort
= NULL
;
65 #define ICPOLARITY_RISING true
66 #define ICPOLARITY_FALLING false
68 typedef struct escSerial_s
{
74 const timerHardware_t
*rxTimerHardware
;
75 volatile uint8_t rxBuffer
[ESCSERIAL_BUFFER_SIZE
];
76 const timerHardware_t
*txTimerHardware
;
77 volatile uint8_t txBuffer
[ESCSERIAL_BUFFER_SIZE
];
80 const TIM_HandleTypeDef
*txTimerHandle
;
81 const TIM_HandleTypeDef
*rxTimerHandle
;
84 uint8_t isSearchingForStartBit
;
86 uint8_t rxLastLeadingEdgeAtBitIndex
;
89 uint8_t isTransmittingData
;
90 uint8_t isReceivingData
;
91 int8_t bitsLeftToTransmit
;
93 uint16_t internalTxBuffer
; // includes start and stop bits
94 uint16_t internalRxBuffer
; // includes start and stop bits
96 uint16_t receiveTimeout
;
97 uint16_t transmissionErrors
;
98 uint16_t receiveErrors
;
100 uint8_t escSerialPortIndex
;
104 timerCCHandlerRec_t timerCb
;
105 timerCCHandlerRec_t edgeCb
;
113 escOutputs_t escOutputs
[MAX_SUPPORTED_MOTORS
];
115 extern timerHardware_t
* serialTimerHardware
;
117 const struct serialPortVTable escSerialVTable
[];
119 escSerial_t escSerialPorts
[MAX_ESCSERIAL_PORTS
];
121 PG_REGISTER_WITH_RESET_TEMPLATE(escSerialConfig_t
, escSerialConfig
, PG_ESCSERIAL_CONFIG
, 0);
123 #ifndef ESCSERIAL_TIMER_TX_PIN
124 #define ESCSERIAL_TIMER_TX_PIN NONE
127 PG_RESET_TEMPLATE(escSerialConfig_t
, escSerialConfig
,
128 .ioTag
= IO_TAG(ESCSERIAL_TIMER_TX_PIN
),
136 #define STOP_BIT_MASK (1 << 0)
137 #define START_BIT_MASK (1 << (RX_TOTAL_BITS - 1))
139 // XXX No TIM_DeInit equivalent in HAL driver???
140 #ifdef USE_HAL_DRIVER
141 static void TIM_DeInit(TIM_TypeDef
*tim
)
147 static void setTxSignalEsc(escSerial_t
*escSerial
, uint8_t state
)
149 if (escSerial
->mode
== PROTOCOL_KISSALL
)
151 for (volatile uint8_t i
= 0; i
< escSerial
->outputCount
; i
++) {
152 uint8_t state_temp
= state
;
153 if (escOutputs
[i
].inverted
) {
154 state_temp
^= ENABLE
;
158 IOHi(escOutputs
[i
].io
);
160 IOLo(escOutputs
[i
].io
);
166 if (escSerial
->rxTimerHardware
->output
& TIMER_OUTPUT_INVERTED
) {
171 IOHi(escSerial
->txIO
);
173 IOLo(escSerial
->txIO
);
178 static void escSerialGPIOConfig(const timerHardware_t
*timhw
, ioConfig_t cfg
)
180 ioTag_t tag
= timhw
->tag
;
186 IOInit(IOGetByTag(tag
), OWNER_MOTOR
, 0);
188 IOConfigGPIOAF(IOGetByTag(tag
), cfg
, timhw
->alternateFunction
);
190 IOConfigGPIO(IOGetByTag(tag
), cfg
);
194 static void escSerialInputPortConfig(const timerHardware_t
*timerHardwarePtr
)
197 escSerialGPIOConfig(timerHardwarePtr
, IOCFG_IPU
);
199 escSerialGPIOConfig(timerHardwarePtr
, IOCFG_AF_PP_UP
);
201 timerChClearCCFlag(timerHardwarePtr
);
202 timerChITConfig(timerHardwarePtr
,ENABLE
);
206 static bool isTimerPeriodTooLarge(uint32_t timerPeriod
)
208 return timerPeriod
> 0xFFFF;
211 static bool isEscSerialTransmitBufferEmpty(const serialPort_t
*instance
)
214 return instance
->txBufferHead
== instance
->txBufferTail
;
217 static void escSerialOutputPortConfig(const timerHardware_t
*timerHardwarePtr
)
219 escSerialGPIOConfig(timerHardwarePtr
, IOCFG_OUT_PP
);
220 timerChITConfig(timerHardwarePtr
,DISABLE
);
223 static void processTxStateBL(escSerial_t
*escSerial
)
226 if (escSerial
->isReceivingData
) {
230 if (!escSerial
->isTransmittingData
) {
232 if (isEscSerialTransmitBufferEmpty((serialPort_t
*)escSerial
)) {
238 byteToSend
= escSerial
->port
.txBuffer
[escSerial
->port
.txBufferTail
++];
239 if (escSerial
->port
.txBufferTail
>= escSerial
->port
.txBufferSize
) {
240 escSerial
->port
.txBufferTail
= 0;
243 // build internal buffer, MSB = Stop Bit (1) + data bits (MSB to LSB) + start bit(0) LSB
244 escSerial
->internalTxBuffer
= (1 << (TX_TOTAL_BITS
- 1)) | (byteToSend
<< 1);
245 escSerial
->bitsLeftToTransmit
= TX_TOTAL_BITS
;
246 escSerial
->isTransmittingData
= true;
250 if (escSerial
->mode
==PROTOCOL_BLHELI
|| escSerial
->mode
==PROTOCOL_CASTLE
) {
251 escSerialOutputPortConfig(escSerial
->rxTimerHardware
);
256 if (escSerial
->bitsLeftToTransmit
) {
257 mask
= escSerial
->internalTxBuffer
& 1;
258 escSerial
->internalTxBuffer
>>= 1;
260 setTxSignalEsc(escSerial
, mask
);
261 escSerial
->bitsLeftToTransmit
--;
265 escSerial
->isTransmittingData
= false;
266 if (isEscSerialTransmitBufferEmpty((serialPort_t
*)escSerial
)) {
267 if (escSerial
->mode
==PROTOCOL_BLHELI
|| escSerial
->mode
==PROTOCOL_CASTLE
)
269 escSerialInputPortConfig(escSerial
->rxTimerHardware
);
274 static void extractAndStoreRxByteBL(escSerial_t
*escSerial
)
276 if ((escSerial
->port
.mode
& MODE_RX
) == 0) {
280 uint8_t haveStartBit
= (escSerial
->internalRxBuffer
& START_BIT_MASK
) == 0;
281 uint8_t haveStopBit
= (escSerial
->internalRxBuffer
& STOP_BIT_MASK
) == 1;
283 if (!haveStartBit
|| !haveStopBit
) {
284 escSerial
->receiveErrors
++;
288 uint8_t rxByte
= (escSerial
->internalRxBuffer
>> 1) & 0xFF;
290 if (escSerial
->port
.rxCallback
) {
291 escSerial
->port
.rxCallback(rxByte
, escSerial
->port
.rxCallbackData
);
293 escSerial
->port
.rxBuffer
[escSerial
->port
.rxBufferHead
] = rxByte
;
294 escSerial
->port
.rxBufferHead
= (escSerial
->port
.rxBufferHead
+ 1) % escSerial
->port
.rxBufferSize
;
298 static void prepareForNextRxByteBL(escSerial_t
*escSerial
)
300 // prepare for next byte
301 escSerial
->rxBitIndex
= 0;
302 escSerial
->isSearchingForStartBit
= true;
303 if (escSerial
->rxEdge
== LEADING
) {
304 escSerial
->rxEdge
= TRAILING
;
306 escSerial
->rxTimerHardware
,
307 (escSerial
->port
.options
& SERIAL_INVERTED
) ? ICPOLARITY_RISING
: ICPOLARITY_FALLING
, 0
312 static void applyChangedBitsBL(escSerial_t
*escSerial
)
314 if (escSerial
->rxEdge
== TRAILING
) {
316 for (bitToSet
= escSerial
->rxLastLeadingEdgeAtBitIndex
; bitToSet
< escSerial
->rxBitIndex
; bitToSet
++) {
317 escSerial
->internalRxBuffer
|= 1 << bitToSet
;
322 static void processRxStateBL(escSerial_t
*escSerial
)
324 if (escSerial
->isSearchingForStartBit
) {
328 escSerial
->rxBitIndex
++;
330 if (escSerial
->rxBitIndex
== RX_TOTAL_BITS
- 1) {
331 applyChangedBitsBL(escSerial
);
335 if (escSerial
->rxBitIndex
== RX_TOTAL_BITS
) {
337 if (escSerial
->rxEdge
== TRAILING
) {
338 escSerial
->internalRxBuffer
|= STOP_BIT_MASK
;
341 extractAndStoreRxByteBL(escSerial
);
342 prepareForNextRxByteBL(escSerial
);
346 static void onSerialTimerBL(timerCCHandlerRec_t
*cbRec
, captureCompare_t capture
)
349 escSerial_t
*escSerial
= container_of(cbRec
, escSerial_t
, timerCb
);
351 processTxStateBL(escSerial
);
352 processRxStateBL(escSerial
);
355 static void serialTimerTxConfigBL(const timerHardware_t
*timerHardwarePtr
, uint8_t reference
, uint32_t baud
)
357 uint32_t clock
= SystemCoreClock
/2;
358 uint32_t timerPeriod
;
359 TIM_DeInit(timerHardwarePtr
->tim
);
361 timerPeriod
= clock
/ baud
;
362 if (isTimerPeriodTooLarge(timerPeriod
)) {
364 clock
= clock
/ 2; // this is wrong - mhz stays the same ... This will double baudrate until ok (but minimum baudrate is < 1200)
366 // TODO unable to continue, unable to determine clock and timerPeriods for the given baud
370 } while (isTimerPeriodTooLarge(timerPeriod
));
372 timerConfigure(timerHardwarePtr
, timerPeriod
, clock
);
373 timerChCCHandlerInit(&escSerialPorts
[reference
].timerCb
, onSerialTimerBL
);
374 timerChConfigCallbacks(timerHardwarePtr
, &escSerialPorts
[reference
].timerCb
, NULL
);
377 static void onSerialRxPinChangeBL(timerCCHandlerRec_t
*cbRec
, captureCompare_t capture
)
381 escSerial_t
*escSerial
= container_of(cbRec
, escSerial_t
, edgeCb
);
382 bool inverted
= escSerial
->port
.options
& SERIAL_INVERTED
;
384 if ((escSerial
->port
.mode
& MODE_RX
) == 0) {
388 if (escSerial
->isSearchingForStartBit
) {
389 // Adjust the timing so it will interrupt on the middle.
390 // This is clobbers transmission, but it is okay because we are
391 // always half-duplex.
392 #ifdef USE_HAL_DRIVER
393 __HAL_TIM_SetCounter(escSerial
->txTimerHandle
, __HAL_TIM_GetAutoreload(escSerial
->txTimerHandle
) / 2);
395 TIM_SetCounter(escSerial
->txTimerHardware
->tim
, escSerial
->txTimerHardware
->tim
->ARR
/ 2);
397 if (escSerial
->isTransmittingData
) {
398 escSerial
->transmissionErrors
++;
401 timerChConfigIC(escSerial
->rxTimerHardware
, inverted
? ICPOLARITY_FALLING
: ICPOLARITY_RISING
, 0);
402 escSerial
->rxEdge
= LEADING
;
404 escSerial
->rxBitIndex
= 0;
405 escSerial
->rxLastLeadingEdgeAtBitIndex
= 0;
406 escSerial
->internalRxBuffer
= 0;
407 escSerial
->isSearchingForStartBit
= false;
411 if (escSerial
->rxEdge
== LEADING
) {
412 escSerial
->rxLastLeadingEdgeAtBitIndex
= escSerial
->rxBitIndex
;
415 applyChangedBitsBL(escSerial
);
417 if (escSerial
->rxEdge
== TRAILING
) {
418 escSerial
->rxEdge
= LEADING
;
419 timerChConfigIC(escSerial
->rxTimerHardware
, inverted
? ICPOLARITY_FALLING
: ICPOLARITY_RISING
, 0);
421 escSerial
->rxEdge
= TRAILING
;
422 timerChConfigIC(escSerial
->rxTimerHardware
, inverted
? ICPOLARITY_RISING
: ICPOLARITY_FALLING
, 0);
426 static void serialTimerRxConfigBL(const timerHardware_t
*timerHardwarePtr
, uint8_t reference
, portOptions_e options
)
428 // start bit is usually a FALLING signal
429 TIM_DeInit(timerHardwarePtr
->tim
);
430 timerConfigure(timerHardwarePtr
, 0xFFFF, SystemCoreClock
/ 2);
431 timerChConfigIC(timerHardwarePtr
, (options
& SERIAL_INVERTED
) ? ICPOLARITY_RISING
: ICPOLARITY_FALLING
, 0);
432 timerChCCHandlerInit(&escSerialPorts
[reference
].edgeCb
, onSerialRxPinChangeBL
);
433 timerChConfigCallbacks(timerHardwarePtr
, &escSerialPorts
[reference
].edgeCb
, NULL
);
436 #ifdef USE_ESCSERIAL_SIMONK
437 static void processTxStateEsc(escSerial_t
*escSerial
)
440 static uint8_t bitq
=0, transmitStart
=0;
441 if (escSerial
->isReceivingData
) {
445 if (transmitStart
==0)
447 setTxSignalEsc(escSerial
, 1);
449 if (!escSerial
->isTransmittingData
) {
452 if (isEscSerialTransmitBufferEmpty((serialPort_t
*)escSerial
)) {
460 if (transmitStart
==0)
462 if (transmitStart
==1)
464 if (transmitStart
==2)
470 byteToSend
= escSerial
->port
.txBuffer
[escSerial
->port
.txBufferTail
++];
471 if (escSerial
->port
.txBufferTail
>= escSerial
->port
.txBufferSize
) {
472 escSerial
->port
.txBufferTail
= 0;
477 // build internal buffer, data bits (MSB to LSB)
478 escSerial
->internalTxBuffer
= byteToSend
;
479 escSerial
->bitsLeftToTransmit
= 8;
480 escSerial
->isTransmittingData
= true;
483 escSerialOutputPortConfig(escSerial
->rxTimerHardware
);
487 if (escSerial
->bitsLeftToTransmit
) {
488 mask
= escSerial
->internalTxBuffer
& 1;
491 if (bitq
==0 || bitq
==1)
493 setTxSignalEsc(escSerial
, 1);
495 if (bitq
==2 || bitq
==3)
497 setTxSignalEsc(escSerial
, 0);
502 if (bitq
==0 || bitq
==2)
504 setTxSignalEsc(escSerial
, 1);
506 if (bitq
==1 ||bitq
==3)
508 setTxSignalEsc(escSerial
, 0);
514 escSerial
->internalTxBuffer
>>= 1;
515 escSerial
->bitsLeftToTransmit
--;
517 if (escSerial
->bitsLeftToTransmit
==0)
525 if (isEscSerialTransmitBufferEmpty((serialPort_t
*)escSerial
)) {
526 escSerial
->isTransmittingData
= false;
527 escSerialInputPortConfig(escSerial
->rxTimerHardware
);
531 static void onSerialTimerEsc(timerCCHandlerRec_t
*cbRec
, captureCompare_t capture
)
534 escSerial_t
*escSerial
= container_of(cbRec
, escSerial_t
, timerCb
);
536 if (escSerial
->isReceivingData
)
538 escSerial
->receiveTimeout
++;
539 if (escSerial
->receiveTimeout
>8)
541 escSerial
->isReceivingData
=0;
542 escSerial
->receiveTimeout
=0;
543 timerChConfigIC(escSerial
->rxTimerHardware
, ICPOLARITY_FALLING
, 0);
547 processTxStateEsc(escSerial
);
550 static void escSerialTimerTxConfig(const timerHardware_t
*timerHardwarePtr
, uint8_t reference
)
552 uint32_t timerPeriod
= 34;
553 TIM_DeInit(timerHardwarePtr
->tim
);
554 timerConfigure(timerHardwarePtr
, timerPeriod
, MHZ_TO_HZ(1));
555 timerChCCHandlerInit(&escSerialPorts
[reference
].timerCb
, onSerialTimerEsc
);
556 timerChConfigCallbacks(timerHardwarePtr
, &escSerialPorts
[reference
].timerCb
, NULL
);
559 static void extractAndStoreRxByteEsc(escSerial_t
*escSerial
)
561 if ((escSerial
->port
.mode
& MODE_RX
) == 0) {
565 uint8_t rxByte
= (escSerial
->internalRxBuffer
) & 0xFF;
567 if (escSerial
->port
.rxCallback
) {
568 escSerial
->port
.rxCallback(rxByte
, escSerial
->port
.rxCallbackData
);
570 escSerial
->port
.rxBuffer
[escSerial
->port
.rxBufferHead
] = rxByte
;
571 escSerial
->port
.rxBufferHead
= (escSerial
->port
.rxBufferHead
+ 1) % escSerial
->port
.rxBufferSize
;
575 static void onSerialRxPinChangeEsc(timerCCHandlerRec_t
*cbRec
, captureCompare_t capture
)
578 static uint8_t zerofirst
=0;
579 static uint8_t bits
=0;
580 static uint16_t bytes
=0;
582 escSerial_t
*escSerial
= container_of(cbRec
, escSerial_t
, edgeCb
);
585 #ifdef USE_HAL_DRIVER
586 __HAL_TIM_SetCounter(escSerial
->rxTimerHandle
, 0);
588 TIM_SetCounter(escSerial
->rxTimerHardware
->tim
,0);
591 if (capture
> 40 && capture
< 90)
597 escSerial
->internalRxBuffer
= escSerial
->internalRxBuffer
>>1;
601 else if (capture
>90 && capture
< 200)
604 escSerial
->internalRxBuffer
= escSerial
->internalRxBuffer
>>1;
605 escSerial
->internalRxBuffer
|= 0x80;
610 if (!escSerial
->isReceivingData
)
615 escSerial
->isReceivingData
= 1;
619 escSerial
->internalRxBuffer
= 0x80;
621 timerChConfigIC(escSerial
->rxTimerHardware
, ICPOLARITY_RISING
, 0);
624 escSerial
->receiveTimeout
= 0;
632 extractAndStoreRxByteEsc(escSerial
);
634 escSerial
->internalRxBuffer
=0;
639 static void escSerialTimerRxConfig(const timerHardware_t
*timerHardwarePtr
, uint8_t reference
)
641 // start bit is usually a FALLING signal
642 TIM_DeInit(timerHardwarePtr
->tim
);
643 timerConfigure(timerHardwarePtr
, 0xFFFF, MHZ_TO_HZ(1));
644 timerChConfigIC(timerHardwarePtr
, ICPOLARITY_FALLING
, 0);
645 timerChCCHandlerInit(&escSerialPorts
[reference
].edgeCb
, onSerialRxPinChangeEsc
);
646 timerChConfigCallbacks(timerHardwarePtr
, &escSerialPorts
[reference
].edgeCb
, NULL
);
650 static void resetBuffers(escSerial_t
*escSerial
)
652 escSerial
->port
.rxBufferSize
= ESCSERIAL_BUFFER_SIZE
;
653 escSerial
->port
.rxBuffer
= escSerial
->rxBuffer
;
654 escSerial
->port
.rxBufferTail
= 0;
655 escSerial
->port
.rxBufferHead
= 0;
657 escSerial
->port
.txBuffer
= escSerial
->txBuffer
;
658 escSerial
->port
.txBufferSize
= ESCSERIAL_BUFFER_SIZE
;
659 escSerial
->port
.txBufferTail
= 0;
660 escSerial
->port
.txBufferHead
= 0;
663 static serialPort_t
*openEscSerial(escSerialPortIndex_e portIndex
, serialReceiveCallbackPtr callback
, uint16_t output
, uint32_t baud
, portOptions_e options
, uint8_t mode
)
665 escSerial_t
*escSerial
= &(escSerialPorts
[portIndex
]);
667 if (mode
!= PROTOCOL_KISSALL
) {
668 escSerial
->rxTimerHardware
= &(timerHardware
[output
]);
669 // N-Channels can't be used as RX.
670 if (escSerial
->rxTimerHardware
->output
& TIMER_OUTPUT_N_CHANNEL
) {
673 #ifdef USE_HAL_DRIVER
674 escSerial
->rxTimerHandle
= timerFindTimerHandle(escSerial
->rxTimerHardware
->tim
);
678 escSerial
->mode
= mode
;
679 escSerial
->txTimerHardware
= timerGetByTag(escSerialConfig()->ioTag
);
681 #ifdef USE_HAL_DRIVER
682 escSerial
->txTimerHandle
= timerFindTimerHandle(escSerial
->txTimerHardware
->tim
);
685 escSerial
->port
.vTable
= escSerialVTable
;
686 escSerial
->port
.baudRate
= baud
;
687 escSerial
->port
.mode
= MODE_RXTX
;
688 escSerial
->port
.options
= options
;
689 escSerial
->port
.rxCallback
= callback
;
691 resetBuffers(escSerial
);
693 escSerial
->isTransmittingData
= false;
695 escSerial
->isSearchingForStartBit
= true;
696 escSerial
->rxBitIndex
= 0;
698 escSerial
->transmissionErrors
= 0;
699 escSerial
->receiveErrors
= 0;
700 escSerial
->receiveTimeout
= 0;
702 escSerial
->escSerialPortIndex
= portIndex
;
704 if (mode
!= PROTOCOL_KISSALL
)
706 escSerial
->txIO
= IOGetByTag(escSerial
->rxTimerHardware
->tag
);
707 escSerialInputPortConfig(escSerial
->rxTimerHardware
);
708 setTxSignalEsc(escSerial
, ENABLE
);
712 #ifdef USE_ESCSERIAL_SIMONK
713 if (mode
==PROTOCOL_SIMONK
) {
714 escSerialTimerTxConfig(escSerial
->txTimerHardware
, portIndex
);
715 escSerialTimerRxConfig(escSerial
->rxTimerHardware
, portIndex
);
719 if (mode
==PROTOCOL_BLHELI
) {
720 serialTimerTxConfigBL(escSerial
->txTimerHardware
, portIndex
, baud
);
721 serialTimerRxConfigBL(escSerial
->rxTimerHardware
, portIndex
, options
);
723 else if (mode
==PROTOCOL_KISS
) {
724 escSerialOutputPortConfig(escSerial
->rxTimerHardware
); // rx is the pin used
725 serialTimerTxConfigBL(escSerial
->txTimerHardware
, portIndex
, baud
);
727 else if (mode
==PROTOCOL_KISSALL
) {
728 escSerial
->outputCount
= 0;
729 memset(&escOutputs
, 0, sizeof(escOutputs
));
730 pwmOutputPort_t
*pwmMotors
= pwmGetMotors();
731 for (volatile uint8_t i
= 0; i
< MAX_SUPPORTED_MOTORS
; i
++) {
732 if (pwmMotors
[i
].enabled
) {
733 if (pwmMotors
[i
].io
!= IO_NONE
) {
734 for (volatile uint8_t j
= 0; j
< USABLE_TIMER_CHANNEL_COUNT
; j
++) {
735 if (pwmMotors
[i
].io
== IOGetByTag(timerHardware
[j
].tag
))
737 escSerialOutputPortConfig(&timerHardware
[j
]);
738 if (timerHardware
[j
].output
& TIMER_OUTPUT_INVERTED
) {
739 escOutputs
[escSerial
->outputCount
].inverted
= 1;
744 escOutputs
[escSerial
->outputCount
].io
= pwmMotors
[i
].io
;
745 escSerial
->outputCount
++;
749 setTxSignalEsc(escSerial
, ENABLE
);
750 serialTimerTxConfigBL(escSerial
->txTimerHardware
, portIndex
, baud
);
752 else if (mode
== PROTOCOL_CASTLE
){
753 escSerialOutputPortConfig(escSerial
->rxTimerHardware
);
754 serialTimerTxConfigBL(escSerial
->txTimerHardware
, portIndex
, baud
);
755 serialTimerRxConfigBL(escSerial
->rxTimerHardware
, portIndex
, options
);
757 return &escSerial
->port
;
761 static void escSerialInputPortDeConfig(const timerHardware_t
*timerHardwarePtr
)
763 timerChClearCCFlag(timerHardwarePtr
);
764 timerChITConfig(timerHardwarePtr
,DISABLE
);
765 escSerialGPIOConfig(timerHardwarePtr
, IOCFG_IPU
);
769 static void closeEscSerial(escSerialPortIndex_e portIndex
, uint8_t mode
)
771 escSerial_t
*escSerial
= &(escSerialPorts
[portIndex
]);
773 if (mode
!= PROTOCOL_KISSALL
) {
774 escSerialInputPortDeConfig(escSerial
->rxTimerHardware
);
775 timerChConfigCallbacks(escSerial
->rxTimerHardware
,NULL
,NULL
);
776 TIM_DeInit(escSerial
->rxTimerHardware
->tim
);
779 timerChConfigCallbacks(escSerial
->txTimerHardware
,NULL
,NULL
);
780 TIM_DeInit(escSerial
->txTimerHardware
->tim
);
783 static uint32_t escSerialTotalBytesWaiting(const serialPort_t
*instance
)
785 if ((instance
->mode
& MODE_RX
) == 0) {
789 escSerial_t
*s
= (escSerial_t
*)instance
;
791 return (s
->port
.rxBufferHead
- s
->port
.rxBufferTail
) & (s
->port
.rxBufferSize
- 1);
794 static uint8_t escSerialReadByte(serialPort_t
*instance
)
798 if ((instance
->mode
& MODE_RX
) == 0) {
802 if (escSerialTotalBytesWaiting(instance
) == 0) {
806 ch
= instance
->rxBuffer
[instance
->rxBufferTail
];
807 instance
->rxBufferTail
= (instance
->rxBufferTail
+ 1) % instance
->rxBufferSize
;
811 static void escSerialWriteByte(serialPort_t
*s
, uint8_t ch
)
813 if ((s
->mode
& MODE_TX
) == 0) {
817 s
->txBuffer
[s
->txBufferHead
] = ch
;
818 s
->txBufferHead
= (s
->txBufferHead
+ 1) % s
->txBufferSize
;
821 static void escSerialSetBaudRate(serialPort_t
*s
, uint32_t baudRate
)
827 static void escSerialSetMode(serialPort_t
*instance
, portMode_e mode
)
829 instance
->mode
= mode
;
832 static uint32_t escSerialTxBytesFree(const serialPort_t
*instance
)
834 if ((instance
->mode
& MODE_TX
) == 0) {
838 escSerial_t
*s
= (escSerial_t
*)instance
;
840 uint8_t bytesUsed
= (s
->port
.txBufferHead
- s
->port
.txBufferTail
) & (s
->port
.txBufferSize
- 1);
842 return (s
->port
.txBufferSize
- 1) - bytesUsed
;
845 const struct serialPortVTable escSerialVTable
[] = {
847 .serialWrite
= escSerialWriteByte
,
848 .serialTotalRxWaiting
= escSerialTotalBytesWaiting
,
849 .serialTotalTxFree
= escSerialTxBytesFree
,
850 .serialRead
= escSerialReadByte
,
851 .serialSetBaudRate
= escSerialSetBaudRate
,
852 .isSerialTransmitBufferEmpty
= isEscSerialTransmitBufferEmpty
,
853 .setMode
= escSerialSetMode
,
854 .setCtrlLineStateCb
= NULL
,
855 .setBaudRateCb
= NULL
,
872 typedef struct mspPort_s
{
882 static mspPort_t currentPort
;
884 static bool processExitCommand(uint8_t c
)
886 if (currentPort
.c_state
== IDLE
) {
888 currentPort
.c_state
= HEADER_START
;
892 } else if (currentPort
.c_state
== HEADER_START
) {
893 currentPort
.c_state
= (c
== 'M') ? HEADER_M
: IDLE
;
894 } else if (currentPort
.c_state
== HEADER_M
) {
895 currentPort
.c_state
= (c
== '<') ? HEADER_ARROW
: IDLE
;
896 } else if (currentPort
.c_state
== HEADER_ARROW
) {
898 currentPort
.c_state
= IDLE
;
901 currentPort
.dataSize
= c
;
902 currentPort
.offset
= 0;
903 currentPort
.checksum
= 0;
904 currentPort
.indRX
= 0;
905 currentPort
.checksum
^= c
;
906 currentPort
.c_state
= HEADER_SIZE
;
908 } else if (currentPort
.c_state
== HEADER_SIZE
) {
909 currentPort
.cmdMSP
= c
;
910 currentPort
.checksum
^= c
;
911 currentPort
.c_state
= HEADER_CMD
;
912 } else if (currentPort
.c_state
== HEADER_CMD
&& currentPort
.offset
< currentPort
.dataSize
) {
913 currentPort
.checksum
^= c
;
914 currentPort
.inBuf
[currentPort
.offset
++] = c
;
915 } else if (currentPort
.c_state
== HEADER_CMD
&& currentPort
.offset
>= currentPort
.dataSize
) {
916 if (currentPort
.checksum
== c
) {
917 currentPort
.c_state
= COMMAND_RECEIVED
;
919 if ((currentPort
.cmdMSP
== 0xF4) && (currentPort
.dataSize
==0))
921 currentPort
.c_state
= IDLE
;
925 currentPort
.c_state
= IDLE
;
932 void escEnablePassthrough(serialPort_t
*escPassthroughPort
, uint16_t output
, uint8_t mode
)
934 bool exitEsc
= false;
935 uint8_t motor_output
= 0;
938 //StopPwmAllMotors();
940 passPort
= escPassthroughPort
;
942 uint32_t escBaudrate
;
945 escBaudrate
= BAUDRATE_KISS
;
947 case PROTOCOL_CASTLE
:
948 escBaudrate
= BAUDRATE_CASTLE
;
951 escBaudrate
= BAUDRATE_NORMAL
;
955 if ((mode
== PROTOCOL_KISS
) && (output
== 255)) {
957 mode
= PROTOCOL_KISSALL
;
960 uint8_t first_output
= 0;
961 for (unsigned i
= 0; i
< USABLE_TIMER_CHANNEL_COUNT
; i
++) {
962 if (timerHardware
[i
].usageFlags
& TIM_USE_MOTOR
) {
968 //doesn't work with messy timertable
969 motor_output
= first_output
+ output
;
970 if (motor_output
>= USABLE_TIMER_CHANNEL_COUNT
) {
975 escPort
= openEscSerial(ESCSERIAL1
, NULL
, motor_output
, escBaudrate
, 0, mode
);
985 if (serialRxBytesWaiting(escPort
)) {
987 while (serialRxBytesWaiting(escPort
))
989 ch
= serialRead(escPort
);
990 serialWrite(escPassthroughPort
, ch
);
995 if (serialRxBytesWaiting(escPassthroughPort
)) {
997 while (serialRxBytesWaiting(escPassthroughPort
))
999 ch
= serialRead(escPassthroughPort
);
1000 exitEsc
= processExitCommand(ch
);
1003 serialWrite(escPassthroughPort
, 0x24);
1004 serialWrite(escPassthroughPort
, 0x4D);
1005 serialWrite(escPassthroughPort
, 0x3E);
1006 serialWrite(escPassthroughPort
, 0x00);
1007 serialWrite(escPassthroughPort
, 0xF4);
1008 serialWrite(escPassthroughPort
, 0xF4);
1009 closeEscSerial(ESCSERIAL1
, mode
);
1012 if (mode
==PROTOCOL_BLHELI
) {
1013 serialWrite(escPassthroughPort
, ch
); // blheli loopback
1015 serialWrite(escPort
, ch
);
1019 if (mode
!= PROTOCOL_CASTLE
) {