2 * This file is part of INAV.
4 * INAV is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * INAV is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with INAV. If not, see <http://www.gnu.org/licenses/>.
24 #if defined(USE_SMARTPORT_MASTER)
26 #include "build/debug.h"
28 #include "common/utils.h"
30 #include "config/parameter_group.h"
31 #include "config/parameter_group_ids.h"
33 #include "drivers/serial.h"
34 #include "drivers/time.h"
36 #include "fc/settings.h"
38 #include "io/serial.h"
39 #include "io/smartport_master.h"
41 #include "rx/frsky_crc.h"
44 PRIM_DISCARD_FRAME
= 0x00,
45 PRIM_DATA_FRAME
= 0x10,
46 PRIM_WORKING_STATE
= 0x20,
47 PRIM_IDLE_STATE
= 0x21,
48 PRIM_CONFIG_READ
= 0x30,
49 PRIM_CONFIG_WRITE
= 0x31,
50 PRIM_CONFIG_RESPONSE
= 0x32,
51 PRIM_DIAG_READ
= 0X40,
52 PRIM_DIAG_WRITE
= 0X41,
53 PRIM_ENABLE_APP_NODE
= 0x70,
54 PRIM_DISABLE_APP_NODE
= 0x71,
59 DATAID_SPEED
= 0x0830,
61 DATAID_CURRENT
= 0x0200,
63 DATAID_ALTITUDE
= 0x0100,
67 DATAID_LATLONG
= 0x0800,
68 DATAID_CAP_USED
= 0x0600,
69 DATAID_VARIO
= 0x0110,
70 DATAID_CELLS
= 0x0300,
71 DATAID_CELLS_LAST
= 0x030F,
72 DATAID_HEADING
= 0x0840,
74 DATAID_PITCH
= 0x0430,
81 DATAID_HOME_DIST
= 0x0420,
82 DATAID_GPS_ALT
= 0x0820,
89 #define SMARTPORT_BAUD 57600
90 #define SMARTPORT_UART_MODE MODE_RXTX
92 #define SMARTPORT_PHYID_MAX 0x1B
93 #define SMARTPORT_PHYID_COUNT (SMARTPORT_PHYID_MAX + 1)
95 #define SMARTPORT_POLLING_INTERVAL 12 // ms
97 #define SMARTPORT_FRAME_START 0x7E
98 #define SMARTPORT_BYTESTUFFING_MARKER 0x7D
99 #define SMARTPORT_BYTESTUFFING_XOR_VALUE 0x20
101 #define SMARTPORT_SENSOR_DATA_TIMEOUT 500 // ms
103 #define SMARTPORT_FORWARD_REQUESTS_MAX 10
110 typedef struct smartPortMasterFrame_s
{
113 smartPortPayload_t payload
;
115 } PACKED smartportFrame_t
;
118 smartportFrame_t frame
;
119 uint8_t bytes
[sizeof(smartportFrame_t
)];
120 } smartportFrameBuffer_u
;
124 timeUs_t cellsTimestamp
;
126 timeUs_t vs600Timestamp
;
128 timeUs_t altitudeTimestamp
;
130 timeUs_t varioTimestamp
;
131 } smartportSensorsData_t
;
135 smartPortPayload_t payload
;
136 } smartportForwardData_t
;
138 PG_REGISTER_WITH_RESET_TEMPLATE(smartportMasterConfig_t
, smartportMasterConfig
, PG_SMARTPORT_MASTER_CONFIG
, 0);
140 PG_RESET_TEMPLATE(smartportMasterConfig_t
, smartportMasterConfig
,
141 .halfDuplex
= SETTING_SMARTPORT_MASTER_HALFDUPLEX_DEFAULT
,
142 .inverted
= SETTING_SMARTPORT_MASTER_INVERTED_DEFAULT
145 static serialPort_t
*smartportMasterSerialPort
= NULL
;
146 static serialPortConfig_t
*portConfig
;
147 static int8_t currentPolledPhyID
= -1;
148 static int8_t forcedPolledPhyID
= -1;
149 static uint8_t rxBufferLen
= 0;
151 static uint32_t activePhyIDs
= 0;
152 static smartPortPayload_t sensorPayloadCache
[SMARTPORT_PHYID_COUNT
];
154 static uint8_t forwardRequestsStart
= 0;
155 static uint8_t forwardRequestsEnd
= 0;
156 static smartportForwardData_t forwardRequests
[SMARTPORT_FORWARD_REQUESTS_MAX
]; // Forward requests' circular buffer
158 static uint8_t forwardResponsesCount
= 0;
159 static smartportForwardData_t forwardResponses
[SMARTPORT_FORWARD_REQUESTS_MAX
]; // Forward responses' buffer
161 static smartportSensorsData_t sensorsData
;
164 bool smartportMasterInit(void)
166 portConfig
= findSerialPortConfig(FUNCTION_TELEMETRY_SMARTPORT_MASTER
);
171 portOptions_t portOptions
= (smartportMasterConfig()->halfDuplex
? SERIAL_BIDIR
: SERIAL_UNIDIR
) | (smartportMasterConfig()->inverted
? SERIAL_NOT_INVERTED
: SERIAL_INVERTED
);
172 smartportMasterSerialPort
= openSerialPort(portConfig
->identifier
, FUNCTION_TELEMETRY_SMARTPORT_MASTER
, NULL
, NULL
, SMARTPORT_BAUD
, SMARTPORT_UART_MODE
, portOptions
);
174 memset(&sensorsData
, 0, sizeof(sensorsData
));
179 static void phyIDSetActive(uint8_t phyID
, bool active
)
181 uint32_t mask
= 1 << phyID
;
183 activePhyIDs
|= mask
;
185 activePhyIDs
&= ~mask
;
189 static uint32_t phyIDAllActiveMask(void)
192 for (uint8_t i
= 0; i
< SMARTPORT_PHYID_COUNT
; ++i
) {
198 static int8_t phyIDNext(uint8_t start
, bool active
, bool loop
)
200 for (uint8_t i
= start
; i
< ((loop
? start
: 0) + SMARTPORT_PHYID_COUNT
); ++i
) {
201 uint8_t phyID
= i
% SMARTPORT_PHYID_COUNT
;
202 uint32_t mask
= 1 << phyID
;
203 uint32_t phyIDMasked
= activePhyIDs
& mask
;
204 if ((active
&& phyIDMasked
) || !(active
|| phyIDMasked
)) {
211 static bool phyIDIsActive(uint8_t id
)
213 return !!(activePhyIDs
& (1 << id
));
216 static bool phyIDNoneActive(void)
218 return activePhyIDs
== 0;
221 static bool phyIDAllActive(void)
223 static uint32_t allActiveMask
= 0;
225 if (!allActiveMask
) {
226 allActiveMask
= phyIDAllActiveMask();
229 return !!((activePhyIDs
& allActiveMask
) == allActiveMask
);
232 static bool phyIDAnyActive(void)
234 return !!activePhyIDs
;
237 static void smartportMasterSendByte(uint8_t byte
)
239 serialWrite(smartportMasterSerialPort
, byte
);
242 static void smartportMasterPhyIDFillCheckBits(uint8_t *phyIDByte
)
244 *phyIDByte
|= (GET_BIT(*phyIDByte
, 0) ^ GET_BIT(*phyIDByte
, 1) ^ GET_BIT(*phyIDByte
, 2)) << 5;
245 *phyIDByte
|= (GET_BIT(*phyIDByte
, 2) ^ GET_BIT(*phyIDByte
, 3) ^ GET_BIT(*phyIDByte
, 4)) << 6;
246 *phyIDByte
|= (GET_BIT(*phyIDByte
, 0) ^ GET_BIT(*phyIDByte
, 2) ^ GET_BIT(*phyIDByte
, 4)) << 7;
249 static void smartportMasterPoll(void)
251 static pollType_e nextPollType
= PT_INACTIVE_ID
;
252 static uint8_t nextActivePhyID
= 0, nextInactivePhyID
= 0;
255 if (currentPolledPhyID
!= -1) {
256 // currentPolledPhyID hasn't been reset by smartportMasterReceive so we didn't get valid data for this PhyID (inactive)
257 phyIDSetActive(currentPolledPhyID
, false);
260 if (forcedPolledPhyID
!= -1) {
262 phyIDToPoll
= forcedPolledPhyID
;
263 forcedPolledPhyID
= -1;
267 if (phyIDNoneActive()) {
268 nextPollType
= PT_INACTIVE_ID
;
269 } else if (phyIDAllActive()) {
270 nextPollType
= PT_ACTIVE_ID
;
273 switch (nextPollType
) {
276 int8_t activePhyIDToPoll
= phyIDNext(nextActivePhyID
, true, false);
277 if (activePhyIDToPoll
== -1) {
279 nextPollType
= PT_INACTIVE_ID
;
281 phyIDToPoll
= activePhyIDToPoll
;
282 if (phyIDToPoll
== SMARTPORT_PHYID_MAX
) {
284 if (!phyIDAllActive()) {
285 nextPollType
= PT_INACTIVE_ID
;
288 nextActivePhyID
= phyIDToPoll
+ 1;
295 case PT_INACTIVE_ID
: {
296 phyIDToPoll
= phyIDNext(nextInactivePhyID
, false, true);
297 nextInactivePhyID
= (phyIDToPoll
== SMARTPORT_PHYID_MAX
? 0 : phyIDToPoll
+ 1);
298 if (phyIDAnyActive()) {
299 nextPollType
= PT_ACTIVE_ID
;
304 default: // should not happen
311 currentPolledPhyID
= phyIDToPoll
;
312 smartportMasterPhyIDFillCheckBits(&phyIDToPoll
);
315 smartportMasterSendByte(SMARTPORT_FRAME_START
);
316 smartportMasterSendByte(phyIDToPoll
);
318 rxBufferLen
= 0; // discard incomplete frames received during previous poll
321 static void smartportMasterForwardNextPayload(void)
323 smartportForwardData_t
*request
= forwardRequests
+ forwardRequestsStart
;
325 /*forcedPolledPhyID = request->phyID; // force next poll to the request's phyID XXX disabled, doesn't seem necessary */
327 smartportMasterPhyIDFillCheckBits(&request
->phyID
);
328 smartportMasterSendByte(SMARTPORT_FRAME_START
);
329 smartportMasterSendByte(request
->phyID
);
331 uint16_t checksum
= 0;
332 uint8_t *payloadPtr
= (uint8_t *)&request
->payload
;
333 for (uint8_t i
= 0; i
< sizeof(request
->payload
); ++i
) {
334 uint8_t c
= *payloadPtr
++;
335 if ((c
== SMARTPORT_FRAME_START
) || (c
== SMARTPORT_BYTESTUFFING_MARKER
)) {
336 smartportMasterSendByte(SMARTPORT_BYTESTUFFING_MARKER
);
337 smartportMasterSendByte(c
^ SMARTPORT_BYTESTUFFING_XOR_VALUE
);
339 smartportMasterSendByte(c
);
343 checksum
= 0xff - ((checksum
& 0xff) + (checksum
>> 8));
344 smartportMasterSendByte(checksum
);
346 forwardRequestsStart
= (forwardRequestsStart
+ 1) % SMARTPORT_FORWARD_REQUESTS_MAX
;
349 static void decodeCellsData(uint32_t sdata
)
351 uint8_t voltageStartIndex
= sdata
& 0xF;
352 uint8_t count
= sdata
>> 4 & 0xF;
353 uint16_t voltage1
= (sdata
>> 8 & 0xFFF) * 2;
354 uint16_t voltage2
= (sdata
>> 20 & 0xFFF) * 2;
355 if ((voltageStartIndex
<= 4) && (count
<= 6)) { // sanity check
356 cellsData_t
*cd
= &sensorsData
.cells
;
358 cd
->voltage
[voltageStartIndex
] = voltage1
;
359 cd
->voltage
[voltageStartIndex
+1] = voltage2
;
363 static void decodeVS600Data(uint32_t sdata
)
365 vs600Data_t
*vs600
= &sensorsData
.vs600
;
366 vs600
->power
= (sdata
>> 8) & 0xFF;
367 vs600
->band
= (sdata
>> 16) & 0xFF;
368 vs600
->channel
= (sdata
>> 24) & 0xFF;
371 static void decodeAltitudeData(uint32_t sdata
)
373 sensorsData
.altitude
= sdata
* 5; // cm
376 static void decodeVarioData(uint32_t sdata
)
378 sensorsData
.vario
= sdata
* 2; // mm/s
381 static void processSensorPayload(smartPortPayload_t
*payload
, timeUs_t currentTimeUs
)
383 switch (payload
->valueId
) {
385 decodeCellsData(payload
->data
);
386 sensorsData
.cellsTimestamp
= currentTimeUs
;
390 decodeVS600Data(payload
->data
);
391 sensorsData
.vs600Timestamp
= currentTimeUs
;
394 case DATAID_ALTITUDE
:
395 decodeAltitudeData(payload
->data
);
396 sensorsData
.altitudeTimestamp
= currentTimeUs
;
400 decodeVarioData(payload
->data
);
401 sensorsData
.varioTimestamp
= currentTimeUs
;
404 sensorPayloadCache
[currentPolledPhyID
] = *payload
;
407 static void processPayload(smartPortPayload_t
*payload
, timeUs_t currentTimeUs
)
409 switch (payload
->frameId
) {
411 case PRIM_DISCARD_FRAME
:
414 case PRIM_DATA_FRAME
:
415 processSensorPayload(payload
, currentTimeUs
);
419 if (forwardResponsesCount
< SMARTPORT_FORWARD_REQUESTS_MAX
) {
420 smartportForwardData_t
*response
= forwardResponses
+ forwardResponsesCount
;
421 response
->phyID
= currentPolledPhyID
;
422 response
->payload
= *payload
;
423 forwardResponsesCount
+= 1;
429 static void smartportMasterReceive(timeUs_t currentTimeUs
)
431 static smartportFrameBuffer_u buffer
;
432 static bool processByteStuffing
= false;
435 processByteStuffing
= false;
438 while (serialRxBytesWaiting(smartportMasterSerialPort
)) {
440 uint8_t c
= serialRead(smartportMasterSerialPort
);
442 if (currentPolledPhyID
== -1) { // We did not poll a sensor or a packet has already been received and processed
446 if (processByteStuffing
) {
447 c
^= SMARTPORT_BYTESTUFFING_XOR_VALUE
;
448 processByteStuffing
= false;
449 } else if (c
== SMARTPORT_BYTESTUFFING_MARKER
) {
450 processByteStuffing
= true;
454 buffer
.bytes
[rxBufferLen
] = c
;
457 if (rxBufferLen
== sizeof(buffer
)) { // frame complete
459 uint8_t calcCRC
= frskyCheckSum((uint8_t *)&buffer
.frame
.payload
, sizeof(buffer
.frame
.payload
));
461 if (buffer
.frame
.crc
== calcCRC
) {
462 phyIDSetActive(currentPolledPhyID
, true);
463 processPayload(&buffer
.frame
.payload
, currentTimeUs
);
466 currentPolledPhyID
= -1; // previously polled PhyID has answered, not expecting more data until next poll
467 rxBufferLen
= 0; // reset buffer
474 bool smartportMasterGetSensorPayload(uint8_t phyID
, smartPortPayload_t
*payload
)
476 if ((phyID
> SMARTPORT_PHYID_MAX
) || !phyIDIsActive(phyID
)) {
480 *payload
= sensorPayloadCache
[phyID
];
484 bool smartportMasterHasForwardResponse(uint8_t phyID
)
486 for (uint8_t i
= 0; i
< forwardResponsesCount
; ++i
) {
487 smartportForwardData_t
*response
= forwardResponses
+ i
;
488 if (response
->phyID
== phyID
) {
496 bool smartportMasterNextForwardResponse(uint8_t phyID
, smartPortPayload_t
*payload
)
498 for (uint8_t i
= 0; i
< forwardResponsesCount
; ++i
) {
499 smartportForwardData_t
*response
= forwardResponses
+ i
;
500 if (response
->phyID
== phyID
) {
501 *payload
= response
->payload
;
502 forwardResponsesCount
-= 1;
503 memmove(response
, response
+ 1, (forwardResponsesCount
- i
) * sizeof(*response
));
511 static uint8_t forwardRequestCount(void)
513 if (forwardRequestsStart
> forwardRequestsEnd
) {
514 return SMARTPORT_FORWARD_REQUESTS_MAX
- forwardRequestsStart
+ forwardRequestsEnd
;
516 return forwardRequestsEnd
- forwardRequestsStart
;
520 bool smartportMasterForward(uint8_t phyID
, smartPortPayload_t
*payload
)
522 if (forwardRequestCount() == SMARTPORT_FORWARD_REQUESTS_MAX
) {
526 smartportForwardData_t
*request
= forwardRequests
+ forwardRequestsEnd
;
527 request
->phyID
= phyID
;
528 request
->payload
= *payload
;
529 forwardRequestsEnd
= (forwardRequestsEnd
+ 1) % SMARTPORT_FORWARD_REQUESTS_MAX
;
533 void smartportMasterHandle(timeUs_t currentTimeUs
)
535 static timeUs_t pollTimestamp
= 0;
537 if (!smartportMasterSerialPort
) {
541 if (!pollTimestamp
|| (cmpTimeUs(currentTimeUs
, pollTimestamp
) > MS2US(SMARTPORT_POLLING_INTERVAL
))) {
542 if (forwardRequestCount() && (forcedPolledPhyID
== -1)) { // forward next payload if there is one in queue and we are not waiting from the response of the previous one
543 smartportMasterForwardNextPayload();
545 smartportMasterPoll();
547 pollTimestamp
= currentTimeUs
;
549 smartportMasterReceive(currentTimeUs
);
553 cellsData_t
*smartportMasterGetCellsData(void)
555 if (micros() - sensorsData
.cellsTimestamp
> SMARTPORT_SENSOR_DATA_TIMEOUT
) {
559 return &sensorsData
.cells
;
562 vs600Data_t
*smartportMasterGetVS600Data(void)
564 if (micros() - sensorsData
.vs600Timestamp
> SMARTPORT_SENSOR_DATA_TIMEOUT
) {
568 return &sensorsData
.vs600
;
571 bool smartportMasterPhyIDIsActive(uint8_t phyID
)
573 return phyIDIsActive(phyID
);
576 int8_t smartportMasterStripPhyIDCheckBits(uint8_t phyID
)
578 uint8_t smartportPhyID
= phyID
& 0x1F;
579 uint8_t phyIDCheck
= smartportPhyID
;
580 smartportMasterPhyIDFillCheckBits(&phyIDCheck
);
581 return phyID
== phyIDCheck
? smartportPhyID
: -1;