2 ******************************************************************************
3 * @addtogroup OpenPilotModules OpenPilot Modules
5 * @addtogroup TelemetryModule Telemetry Module
6 * @brief Main telemetry module
7 * Starts three tasks (RX, TX, and priority TX) that watch event queues
8 * and handle all the telemetry of the UAVobjects
12 * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015.
13 * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2015.
14 * @brief Telemetry module, handles telemetry and UAVObject updates
16 * @see The GNU Public License (GPL) Version 3
18 *****************************************************************************/
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 3 of the License, or
23 * (at your option) any later version.
25 * This program is distributed in the hope that it will be useful, but
26 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
27 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
30 * You should have received a copy of the GNU General Public License along
31 * with this program; if not, write to the Free Software Foundation, Inc.,
32 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
35 /* Telemetry uses four tasks. Two are created for the main telemetry
36 * stream called "TelTx" and "TelRx". Two are created to handle the OPLink
37 * radio connection, called "RadioTx" and "RadioRx", the latter being
38 * overridden by USB if connected.
40 * The following code uses a "local" prefix to refer to the telemetry channel
41 * associated with a port on the FC and a "radio" prefix to refer to the
42 * telemetry channel associated with the OPLink/USB.
44 * The "local" telemetry port to use is defined by PIOS_COM_TELEM_RF in
47 * A UAVTalk connection instance, telemUavTalkCon, is associated with the
48 * "local" channel and another, radioUavTalkCon, with the "radio" channel.
49 * Associated with each instance is a transmit routine which will send data
50 * to the appropriate port.
52 * Data is passed on the telemetry channels using queues. If
53 * PIOS_TELEM_PRIORITY_QUEUE is defined then two queues are created, one normal
54 * priority and the other high priority.
56 * The "Tx" tasks read events first from the priority queue and then from
57 * the normal queue, passing each event to processObjEvent() which ultimately
58 * passes each event to the UAVTalk library which results in the appropriate
59 * transmit routine being called to send the data back to the recipient on
60 * the "local" or "radio" link.
63 #include <openpilot.h>
65 #include "telemetry.h"
67 #include "flighttelemetrystats.h"
68 #include "gcstelemetrystats.h"
69 #include "hwsettings.h"
73 #define MAX_QUEUE_SIZE TELEM_QUEUE_SIZE
74 // Three different stack size parameter are accepted for Telemetry(RX PIOS_TELEM_RX_STACK_SIZE)
75 // Tx(PIOS_TELEM_TX_STACK_SIZE) and Radio RX(PIOS_TELEM_RADIO_RX_STACK_SIZE)
76 #ifdef PIOS_TELEM_RX_STACK_SIZE
77 #define STACK_SIZE_RX_BYTES PIOS_TELEM_RX_STACK_SIZE
78 #define STACK_SIZE_TX_BYTES PIOS_TELEM_TX_STACK_SIZE
80 #define STACK_SIZE_RX_BYTES PIOS_TELEM_STACK_SIZE
81 #define STACK_SIZE_TX_BYTES PIOS_TELEM_STACK_SIZE
84 #ifdef PIOS_TELEM_RADIO_RX_STACK_SIZE
85 #define STACK_SIZE_RADIO_RX_BYTES PIOS_TELEM_RADIO_RX_STACK_SIZE
86 #define STACK_SIZE_RADIO_TX_BYTES PIOS_TELEM_RADIO_TX_STACK_SIZE
88 #define STACK_SIZE_RADIO_RX_BYTES STACK_SIZE_RX_BYTES
89 #define STACK_SIZE_RADIO_TX_BYTES STACK_SIZE_TX_BYTES
91 #define TASK_PRIORITY_RX (tskIDLE_PRIORITY + 2)
92 #define TASK_PRIORITY_TX (tskIDLE_PRIORITY + 2)
93 #define TASK_PRIORITY_RADRX (tskIDLE_PRIORITY + 2)
94 #define TASK_PRIORITY_RADTX (tskIDLE_PRIORITY + 2)
95 #define REQ_TIMEOUT_MS 250
97 #define STATS_UPDATE_PERIOD_MS 4000
98 #define CONNECTION_TIMEOUT_MS 8000
100 #ifdef PIOS_INCLUDE_RFM22B
106 // Determine port on which to communicate telemetry information
107 uint32_t (*getPort
)();
108 // Main telemetry queue
111 #ifdef PIOS_TELEM_PRIORITY_QUEUE
112 // Priority telemetry queue
113 xQueueHandle priorityQueue
;
114 #endif /* PIOS_TELEM_PRIORITY_QUEUE */
116 // Transmit/receive task handles
117 xTaskHandle txTaskHandle
;
118 xTaskHandle rxTaskHandle
;
120 UAVTalkConnection uavTalkCon
;
124 // Main telemetry channel
125 static channelContext localChannel
;
126 static int32_t transmitLocalData(uint8_t *data
, int32_t length
);
127 static void registerLocalObject(UAVObjHandle obj
);
128 static uint32_t localPort();
129 #endif /* ifdef HAS_RADIO */
131 static void updateSettings(channelContext
*channel
);
133 // OPLink telemetry channel
134 static channelContext radioChannel
;
135 static int32_t transmitRadioData(uint8_t *data
, int32_t length
);
136 static void registerRadioObject(UAVObjHandle obj
);
137 static uint32_t radioPort();
138 static uint32_t radio_port
;
142 static uint32_t txErrors
;
143 static uint32_t txRetries
;
144 static uint32_t timeOfLastObjectUpdate
;
146 static void telemetryTxTask(void *parameters
);
147 static void telemetryRxTask(void *parameters
);
148 static void updateObject(
149 channelContext
*channel
,
152 static void processObjEvent(
153 channelContext
*channel
,
155 static int32_t setUpdatePeriod(
156 channelContext
*channel
,
158 int32_t updatePeriodMs
);
159 static int32_t setLoggingPeriod(
160 channelContext
*channel
,
162 int32_t updatePeriodMs
);
163 static void updateTelemetryStats();
164 static void gcsTelemetryStatsUpdated();
167 * Initialise the telemetry module
168 * \return -1 if initialisation failed
169 * \return 0 on success
171 int32_t TelemetryStart(void)
174 // Only start the local telemetry tasks if needed
176 UAVObjIterate(®isterLocalObject
);
178 // Listen to objects of interest
179 #ifdef PIOS_TELEM_PRIORITY_QUEUE
180 GCSTelemetryStatsConnectQueue(localChannel
.priorityQueue
);
181 #else /* PIOS_TELEM_PRIORITY_QUEUE */
182 GCSTelemetryStatsConnectQueue(localChannel
.queue
);
183 #endif /* PIOS_TELEM_PRIORITY_QUEUE */
184 // Start telemetry tasks
185 xTaskCreate(telemetryTxTask
,
187 STACK_SIZE_TX_BYTES
/ 4,
190 &localChannel
.txTaskHandle
);
191 PIOS_TASK_MONITOR_RegisterTask(TASKINFO_RUNNING_TELEMETRYTX
,
192 localChannel
.txTaskHandle
);
193 xTaskCreate(telemetryRxTask
,
195 STACK_SIZE_RX_BYTES
/ 4,
198 &localChannel
.rxTaskHandle
);
199 PIOS_TASK_MONITOR_RegisterTask(TASKINFO_RUNNING_TELEMETRYRX
,
200 localChannel
.rxTaskHandle
);
202 #endif /* ifdef HAS_RADIO */
204 // Start the telemetry tasks associated with Radio/USB
205 UAVObjIterate(®isterRadioObject
);
207 // Listen to objects of interest
208 #ifdef PIOS_TELEM_PRIORITY_QUEUE
209 GCSTelemetryStatsConnectQueue(radioChannel
.priorityQueue
);
210 #else /* PIOS_TELEM_PRIORITY_QUEUE */
211 GCSTelemetryStatsConnectQueue(radioChannel
.queue
);
212 #endif /* PIOS_TELEM_PRIORITY_QUEUE */
214 xTaskCreate(telemetryTxTask
,
216 STACK_SIZE_RADIO_TX_BYTES
/ 4,
219 &radioChannel
.txTaskHandle
);
220 PIOS_TASK_MONITOR_RegisterTask(TASKINFO_RUNNING_RADIOTX
,
221 radioChannel
.txTaskHandle
);
222 xTaskCreate(telemetryRxTask
,
224 STACK_SIZE_RADIO_RX_BYTES
/ 4,
227 &radioChannel
.rxTaskHandle
);
228 PIOS_TASK_MONITOR_RegisterTask(TASKINFO_RUNNING_RADIORX
,
229 radioChannel
.rxTaskHandle
);
234 /* Intialise a telemetry channel */
235 void TelemetryInitializeChannel(channelContext
*channel
)
237 // Create object queues
238 channel
->queue
= xQueueCreate(MAX_QUEUE_SIZE
,
239 sizeof(UAVObjEvent
));
241 #if defined(PIOS_TELEM_PRIORITY_QUEUE)
242 channel
->priorityQueue
= xQueueCreate(MAX_QUEUE_SIZE
,
243 sizeof(UAVObjEvent
));
244 #endif /* PIOS_TELEM_PRIORITY_QUEUE */
246 // Create periodic event that will be used to update the telemetry stats
248 memset(&ev
, 0, sizeof(UAVObjEvent
));
250 #ifdef PIOS_TELEM_PRIORITY_QUEUE
251 EventPeriodicQueueCreate(&ev
,
252 channel
->priorityQueue
,
253 STATS_UPDATE_PERIOD_MS
);
254 #else /* PIOS_TELEM_PRIORITY_QUEUE */
255 EventPeriodicQueueCreate(&ev
,
257 STATS_UPDATE_PERIOD_MS
);
258 #endif /* PIOS_TELEM_PRIORITY_QUEUE */
262 * Initialise the telemetry module
263 * \return -1 if initialisation failed
264 * \return 0 on success
266 int32_t TelemetryInitialize(void)
268 HwSettingsInitialize();
270 #ifdef PIOS_INCLUDE_RFM22B
271 OPLinkSettingsInitialize();
272 OPLinkSettingsData data
;
274 OPLinkSettingsGet(&data
);
275 bool ppm_only
= (data
.LinkType
== OPLINKSETTINGS_LINKTYPE_CONTROL
);
279 radio_port
= PIOS_COM_RF
;
281 #else /* PIOS_INCLUDE_RFM22B */
282 radio_port
= PIOS_COM_TELEM_RF
;
283 #endif /* PIOS_INCLUDE_RFM22B */
285 FlightTelemetryStatsInitialize();
286 GCSTelemetryStatsInitialize();
289 timeOfLastObjectUpdate
= 0;
296 // Set channel port handlers
297 localChannel
.getPort
= localPort
;
299 // Set the local telemetry baud rate
300 updateSettings(&localChannel
);
302 // Only initialise local channel if telemetry port enabled
304 // Initialise channel
305 TelemetryInitializeChannel(&localChannel
);
306 // Initialise UAVTalk
307 localChannel
.uavTalkCon
= UAVTalkInitialize(&transmitLocalData
);
309 #endif /* ifdef HAS_RADIO */
311 // Set channel port handlers
312 radioChannel
.getPort
= radioPort
;
314 // Set the channel port baud rate
315 updateSettings(&radioChannel
);
317 // Initialise channel
318 TelemetryInitializeChannel(&radioChannel
);
319 // Initialise UAVTalk
320 radioChannel
.uavTalkCon
= UAVTalkInitialize(&transmitRadioData
);
325 MODULE_INITCALL(TelemetryInitialize
, TelemetryStart
);
329 * Register a new object, adds object to local list and connects the queue depending on the object's
330 * telemetry settings.
331 * \param[in] obj Object to connect
333 static void registerLocalObject(UAVObjHandle obj
)
335 if (UAVObjIsMetaobject(obj
)) {
336 // Only connect change notifications for meta objects. No periodic updates
337 #ifdef PIOS_TELEM_PRIORITY_QUEUE
338 UAVObjConnectQueue(obj
, localChannel
.priorityQueue
, EV_MASK_ALL_UPDATES
);
339 #else /* PIOS_TELEM_PRIORITY_QUEUE */
340 UAVObjConnectQueue(obj
, localChannel
.queue
, EV_MASK_ALL_UPDATES
);
341 #endif /* PIOS_TELEM_PRIORITY_QUEUE */
343 // Setup object for periodic updates
350 #endif /* ifdef HAS_RADIO */
352 static void registerRadioObject(UAVObjHandle obj
)
354 if (UAVObjIsMetaobject(obj
)) {
355 // Only connect change notifications for meta objects. No periodic updates
356 #ifdef PIOS_TELEM_PRIORITY_QUEUE
357 UAVObjConnectQueue(obj
, radioChannel
.priorityQueue
, EV_MASK_ALL_UPDATES
);
358 #else /* PIOS_TELEM_PRIORITY_QUEUE */
359 UAVObjConnectQueue(obj
, radioChannel
.queue
, EV_MASK_ALL_UPDATES
);
360 #endif /* PIOS_TELEM_PRIORITY_QUEUE */
362 // Setup object for periodic updates
371 * Update object's queue connections and timer, depending on object's settings
372 * \param[in] telemetry channel context
373 * \param[in] obj Object to updates
375 static void updateObject(
376 channelContext
*channel
,
380 UAVObjMetadata metadata
;
381 UAVObjUpdateMode updateMode
, loggingMode
;
384 if (UAVObjIsMetaobject(obj
)) {
385 // This function updates the periodic updates for the object.
386 // Meta Objects cannot have periodic updates.
392 UAVObjGetMetadata(obj
, &metadata
);
393 updateMode
= UAVObjGetTelemetryUpdateMode(&metadata
);
394 loggingMode
= UAVObjGetLoggingUpdateMode(&metadata
);
396 // Setup object depending on update mode
398 switch (updateMode
) {
399 case UPDATEMODE_PERIODIC
:
401 setUpdatePeriod(channel
,
403 metadata
.telemetryUpdatePeriod
);
405 eventMask
|= EV_UPDATED_PERIODIC
| EV_UPDATED_MANUAL
| EV_UPDATE_REQ
;
407 case UPDATEMODE_ONCHANGE
:
409 setUpdatePeriod(channel
, obj
, 0);
411 eventMask
|= EV_UPDATED
| EV_UPDATED_MANUAL
| EV_UPDATE_REQ
;
413 case UPDATEMODE_THROTTLED
:
414 if ((eventType
== EV_UPDATED_PERIODIC
) || (eventType
== EV_NONE
)) {
415 // If we received a periodic update, we can change back to update on change
416 eventMask
|= EV_UPDATED
| EV_UPDATED_MANUAL
| EV_UPDATE_REQ
;
417 // Set update period on initialization and metadata change
418 if (eventType
== EV_NONE
) {
419 setUpdatePeriod(channel
,
421 metadata
.telemetryUpdatePeriod
);
424 // Otherwise, we just received an object update, so switch to periodic for the timeout period to prevent more updates
425 eventMask
|= EV_UPDATED_PERIODIC
| EV_UPDATED_MANUAL
| EV_UPDATE_REQ
;
428 case UPDATEMODE_MANUAL
:
430 setUpdatePeriod(channel
, obj
, 0);
432 eventMask
|= EV_UPDATED_MANUAL
| EV_UPDATE_REQ
;
435 switch (loggingMode
) {
436 case UPDATEMODE_PERIODIC
:
438 setLoggingPeriod(channel
, obj
, metadata
.loggingUpdatePeriod
);
440 eventMask
|= EV_LOGGING_PERIODIC
| EV_LOGGING_MANUAL
;
442 case UPDATEMODE_ONCHANGE
:
444 setLoggingPeriod(channel
, obj
, 0);
446 eventMask
|= EV_UPDATED
| EV_LOGGING_MANUAL
;
448 case UPDATEMODE_THROTTLED
:
449 if ((eventType
== EV_LOGGING_PERIODIC
) || (eventType
== EV_NONE
)) {
450 // If we received a periodic update, we can change back to update on change
451 eventMask
|= EV_UPDATED
| EV_LOGGING_MANUAL
;
452 // Set update period on initialization and metadata change
453 if (eventType
== EV_NONE
) {
454 setLoggingPeriod(channel
,
456 metadata
.loggingUpdatePeriod
);
459 // Otherwise, we just received an object update, so switch to periodic for the timeout period to prevent more updates
460 eventMask
|= EV_LOGGING_PERIODIC
| EV_LOGGING_MANUAL
;
463 case UPDATEMODE_MANUAL
:
465 setLoggingPeriod(channel
, obj
, 0);
467 eventMask
|= EV_LOGGING_MANUAL
;
471 // note that all setting objects have implicitly IsPriority=true
472 #ifdef PIOS_TELEM_PRIORITY_QUEUE
473 if (UAVObjIsPriority(obj
)) {
474 UAVObjConnectQueue(obj
, channel
->priorityQueue
, eventMask
);
476 #endif /* PIOS_TELEM_PRIORITY_QUEUE */
478 UAVObjConnectQueue(obj
, channel
->queue
, eventMask
);
483 * Processes queue events
485 static void processObjEvent(
486 channelContext
*channel
,
489 UAVObjMetadata metadata
;
490 UAVObjUpdateMode updateMode
;
495 updateTelemetryStats();
496 } else if (ev
->obj
== GCSTelemetryStatsHandle()) {
497 gcsTelemetryStatsUpdated();
499 // Get object metadata
500 UAVObjGetMetadata(ev
->obj
, &metadata
);
501 updateMode
= UAVObjGetTelemetryUpdateMode(&metadata
);
506 if ((ev
->event
== EV_UPDATED
&& (updateMode
== UPDATEMODE_ONCHANGE
|| updateMode
== UPDATEMODE_THROTTLED
))
507 || ev
->event
== EV_UPDATED_MANUAL
508 || (ev
->event
== EV_UPDATED_PERIODIC
&& updateMode
!= UPDATEMODE_THROTTLED
)) {
509 // Send update to GCS (with retries)
510 while (retries
< MAX_RETRIES
&& success
== -1) {
511 // call blocks until ack is received or timeout
512 success
= UAVTalkSendObject(channel
->uavTalkCon
,
515 UAVObjGetTelemetryAcked(&metadata
), REQ_TIMEOUT_MS
);
521 txRetries
+= retries
;
525 } else if (ev
->event
== EV_UPDATE_REQ
) {
526 // Request object update from GCS (with retries)
527 while (retries
< MAX_RETRIES
&& success
== -1) {
528 // call blocks until update is received or timeout
529 success
= UAVTalkSendObjectRequest(channel
->uavTalkCon
,
538 txRetries
+= retries
;
543 // If this is a metaobject then make necessary telemetry updates
544 if (UAVObjIsMetaobject(ev
->obj
)) {
545 // linked object will be the actual object the metadata are for
548 UAVObjGetLinkedObj(ev
->obj
),
551 if (updateMode
== UPDATEMODE_THROTTLED
) {
552 // If this is UPDATEMODE_THROTTLED, the event mask changes on every event.
560 // Log UAVObject if necessary
562 updateMode
= UAVObjGetLoggingUpdateMode(&metadata
);
563 if ((ev
->event
== EV_UPDATED
&& (updateMode
== UPDATEMODE_ONCHANGE
|| updateMode
== UPDATEMODE_THROTTLED
))
564 || ev
->event
== EV_LOGGING_MANUAL
565 || (ev
->event
== EV_LOGGING_PERIODIC
&& updateMode
!= UPDATEMODE_THROTTLED
)) {
566 if (ev
->instId
== UAVOBJ_ALL_INSTANCES
) {
567 success
= UAVObjGetNumInstances(ev
->obj
);
568 for (retries
= 0; retries
< success
; retries
++) {
569 UAVObjInstanceWriteToLog(ev
->obj
, retries
);
572 UAVObjInstanceWriteToLog(ev
->obj
, ev
->instId
);
575 if (updateMode
== UPDATEMODE_THROTTLED
) {
576 // If this is UPDATEMODE_THROTTLED, the event mask changes on every event.
586 * Telemetry transmit task, regular priority
588 static void telemetryTxTask(void *parameters
)
590 channelContext
*channel
= (channelContext
*)parameters
;
593 /* Check for a bad context */
601 * Tries to empty the high priority queue before handling any standard priority item
604 #ifdef PIOS_TELEM_PRIORITY_QUEUE
605 // empty priority queue, non-blocking
606 while (xQueueReceive(channel
->priorityQueue
, &ev
, 0) == pdTRUE
) {
608 processObjEvent(channel
, &ev
);
610 // check regular queue and process update - non-blocking
611 if (xQueueReceive(channel
->queue
, &ev
, 0) == pdTRUE
) {
613 processObjEvent(channel
, &ev
);
614 // if both queues are empty, wait on priority queue for updates (1 tick) then repeat cycle
615 } else if (xQueueReceive(channel
->priorityQueue
, &ev
, 1) == pdTRUE
) {
617 processObjEvent(channel
, &ev
);
620 // wait on queue for updates (1 tick) then repeat cycle
621 if (xQueueReceive(channel
->queue
, &ev
, 1) == pdTRUE
) {
623 processObjEvent(channel
, &ev
);
625 #endif /* PIOS_TELEM_PRIORITY_QUEUE */
631 * Telemetry receive task. Processes queue events and periodic updates.
633 static void telemetryRxTask(void *parameters
)
635 channelContext
*channel
= (channelContext
*)parameters
;
637 /* Check for a bad context */
644 uint32_t inputPort
= channel
->getPort();
647 // Block until data are available
648 uint8_t serial_data
[16];
649 uint16_t bytes_to_process
;
651 bytes_to_process
= PIOS_COM_ReceiveBuffer(inputPort
, serial_data
, sizeof(serial_data
), 500);
652 if (bytes_to_process
> 0) {
653 UAVTalkProcessInputStream(channel
->uavTalkCon
, serial_data
, bytes_to_process
);
663 * Determine the port to be used for communication on the telemetry channel
664 * \return com port number
666 static uint32_t localPort()
668 return PIOS_COM_TELEM_RF
;
671 #endif /* ifdef HAS_RADIO */
674 * Determine the port to be used for communication on the radio channel
675 * \return com port number
677 static uint32_t radioPort()
679 uint32_t port
= radio_port
;
681 #ifdef PIOS_INCLUDE_USB
682 // if USB is connected, USB takes precedence for telemetry
683 if (PIOS_COM_Available(PIOS_COM_TELEM_USB
)) {
684 port
= PIOS_COM_TELEM_USB
;
686 #endif /* PIOS_INCLUDE_USB */
693 * Transmit data buffer to the modem or USB port.
694 * \param[in] data Data buffer to send
695 * \param[in] length Length of buffer
696 * \return -1 on failure
697 * \return number of bytes transmitted on success
699 static int32_t transmitLocalData(uint8_t *data
, int32_t length
)
701 uint32_t outputPort
= localChannel
.getPort();
704 return PIOS_COM_SendBuffer(outputPort
, data
, length
);
709 #endif /* ifdef HAS_RADIO */
712 * Transmit data buffer to the radioport.
713 * \param[in] data Data buffer to send
714 * \param[in] length Length of buffer
715 * \return -1 on failure
716 * \return number of bytes transmitted on success
718 static int32_t transmitRadioData(uint8_t *data
, int32_t length
)
720 uint32_t outputPort
= radioChannel
.getPort();
723 return PIOS_COM_SendBuffer(outputPort
, data
, length
);
730 * Set update period of object (it must be already setup for periodic updates)
731 * \param[in] telemetry channel context
732 * \param[in] obj The object to update
733 * \param[in] updatePeriodMs The update period in ms, if zero then periodic updates are disabled
737 static int32_t setUpdatePeriod(
738 channelContext
*channel
,
740 int32_t updatePeriodMs
)
745 // Add or update object for periodic updates
747 ev
.instId
= UAVOBJ_ALL_INSTANCES
;
748 ev
.event
= EV_UPDATED_PERIODIC
;
749 ev
.lowPriority
= true;
751 #ifdef PIOS_TELEM_PRIORITY_QUEUE
752 xQueueHandle targetQueue
= UAVObjIsPriority(obj
) ? channel
->priorityQueue
:
754 #else /* PIOS_TELEM_PRIORITY_QUEUE */
755 xQueueHandle targetQueue
= channel
->queue
;
756 #endif /* PIOS_TELEM_PRIORITY_QUEUE */
758 ret
= EventPeriodicQueueUpdate(&ev
, targetQueue
, updatePeriodMs
);
760 ret
= EventPeriodicQueueCreate(&ev
, targetQueue
, updatePeriodMs
);
766 * Set logging update period of object (it must be already setup for periodic updates)
767 * \param[in] telemetry channel context
768 * \param[in] obj The object to update
769 * \param[in] updatePeriodMs The update period in ms, if zero then periodic updates are disabled
773 static int32_t setLoggingPeriod(
774 channelContext
*channel
,
776 int32_t updatePeriodMs
)
781 // Add or update object for periodic updates
783 ev
.instId
= UAVOBJ_ALL_INSTANCES
;
784 ev
.event
= EV_LOGGING_PERIODIC
;
785 ev
.lowPriority
= true;
787 #ifdef PIOS_TELEM_PRIORITY_QUEUE
788 xQueueHandle targetQueue
= UAVObjIsPriority(obj
) ? channel
->priorityQueue
:
790 #else /* PIOS_TELEM_PRIORITY_QUEUE */
791 xQueueHandle targetQueue
= channel
->queue
;
792 #endif /* PIOS_TELEM_PRIORITY_QUEUE */
794 ret
= EventPeriodicQueueUpdate(&ev
, targetQueue
, updatePeriodMs
);
796 ret
= EventPeriodicQueueCreate(&ev
, targetQueue
, updatePeriodMs
);
802 * Called each time the GCS telemetry stats object is updated.
803 * Trigger a flight telemetry stats update if a connection is not
806 static void gcsTelemetryStatsUpdated()
808 FlightTelemetryStatsData flightStats
;
809 GCSTelemetryStatsData gcsStats
;
811 FlightTelemetryStatsGet(&flightStats
);
812 GCSTelemetryStatsGet(&gcsStats
);
813 if (flightStats
.Status
!= FLIGHTTELEMETRYSTATS_STATUS_CONNECTED
|| gcsStats
.Status
!= GCSTELEMETRYSTATS_STATUS_CONNECTED
) {
814 updateTelemetryStats();
819 * Update telemetry statistics and handle connection handshake
821 static void updateTelemetryStats()
823 UAVTalkStats utalkStats
;
824 FlightTelemetryStatsData flightStats
;
825 GCSTelemetryStatsData gcsStats
;
827 uint8_t connectionTimeout
;
831 UAVTalkGetStats(radioChannel
.uavTalkCon
, &utalkStats
, true);
834 UAVTalkAddStats(localChannel
.uavTalkCon
, &utalkStats
, true);
838 FlightTelemetryStatsGet(&flightStats
);
839 GCSTelemetryStatsGet(&gcsStats
);
841 // Update stats object
842 if (flightStats
.Status
== FLIGHTTELEMETRYSTATS_STATUS_CONNECTED
) {
843 flightStats
.TxDataRate
= (float)utalkStats
.txBytes
/ ((float)STATS_UPDATE_PERIOD_MS
/ 1000.0f
);
844 flightStats
.TxBytes
+= utalkStats
.txBytes
;
845 flightStats
.TxFailures
+= txErrors
;
846 flightStats
.TxRetries
+= txRetries
;
848 flightStats
.RxDataRate
= (float)utalkStats
.rxBytes
/ ((float)STATS_UPDATE_PERIOD_MS
/ 1000.0f
);
849 flightStats
.RxBytes
+= utalkStats
.rxBytes
;
850 flightStats
.RxFailures
+= utalkStats
.rxErrors
;
851 flightStats
.RxSyncErrors
+= utalkStats
.rxSyncErrors
;
852 flightStats
.RxCrcErrors
+= utalkStats
.rxCrcErrors
;
854 flightStats
.TxDataRate
= 0;
855 flightStats
.TxBytes
= 0;
856 flightStats
.TxFailures
= 0;
857 flightStats
.TxRetries
= 0;
859 flightStats
.RxDataRate
= 0;
860 flightStats
.RxBytes
= 0;
861 flightStats
.RxFailures
= 0;
862 flightStats
.RxSyncErrors
= 0;
863 flightStats
.RxCrcErrors
= 0;
868 // Check for connection timeout
869 timeNow
= xTaskGetTickCount() * portTICK_RATE_MS
;
870 if (utalkStats
.rxObjects
> 0) {
871 timeOfLastObjectUpdate
= timeNow
;
873 if ((timeNow
- timeOfLastObjectUpdate
) > CONNECTION_TIMEOUT_MS
) {
874 connectionTimeout
= 1;
876 connectionTimeout
= 0;
879 // Update connection state
881 if (flightStats
.Status
== FLIGHTTELEMETRYSTATS_STATUS_DISCONNECTED
) {
882 // Wait for connection request
883 if (gcsStats
.Status
== GCSTELEMETRYSTATS_STATUS_HANDSHAKEREQ
) {
884 flightStats
.Status
= FLIGHTTELEMETRYSTATS_STATUS_HANDSHAKEACK
;
886 } else if (flightStats
.Status
== FLIGHTTELEMETRYSTATS_STATUS_HANDSHAKEACK
) {
887 // Wait for connection
888 if (gcsStats
.Status
== GCSTELEMETRYSTATS_STATUS_CONNECTED
) {
889 flightStats
.Status
= FLIGHTTELEMETRYSTATS_STATUS_CONNECTED
;
890 } else if (gcsStats
.Status
== GCSTELEMETRYSTATS_STATUS_DISCONNECTED
) {
891 flightStats
.Status
= FLIGHTTELEMETRYSTATS_STATUS_DISCONNECTED
;
893 } else if (flightStats
.Status
== FLIGHTTELEMETRYSTATS_STATUS_CONNECTED
) {
894 if (gcsStats
.Status
!= GCSTELEMETRYSTATS_STATUS_CONNECTED
|| connectionTimeout
) {
895 flightStats
.Status
= FLIGHTTELEMETRYSTATS_STATUS_DISCONNECTED
;
900 flightStats
.Status
= FLIGHTTELEMETRYSTATS_STATUS_DISCONNECTED
;
903 // TODO: check whether is there any error condition worth raising an alarm
904 // Disconnection is actually a normal (non)working status so it is not raising alarms anymore.
905 if (flightStats
.Status
== FLIGHTTELEMETRYSTATS_STATUS_CONNECTED
) {
906 AlarmsClear(SYSTEMALARMS_ALARM_TELEMETRY
);
910 FlightTelemetryStatsSet(&flightStats
);
912 // Force telemetry update if not connected
914 FlightTelemetryStatsUpdated();
919 * Update the telemetry settings, called on startup.
920 * FIXME: This should be in the TelemetrySettings object. But objects
921 * have too much overhead yet. Also the telemetry has no any specific
922 * settings, etc. Thus the HwSettings object which contains the
923 * telemetry port speed is used for now.
925 static void updateSettings(channelContext
*channel
)
927 uint32_t port
= channel
->getPort();
931 HwSettingsTelemetrySpeedOptions speed
;
932 HwSettingsTelemetrySpeedGet(&speed
);
936 case HWSETTINGS_TELEMETRYSPEED_2400
:
937 PIOS_COM_ChangeBaud(port
, 2400);
939 case HWSETTINGS_TELEMETRYSPEED_4800
:
940 PIOS_COM_ChangeBaud(port
, 4800);
942 case HWSETTINGS_TELEMETRYSPEED_9600
:
943 PIOS_COM_ChangeBaud(port
, 9600);
945 case HWSETTINGS_TELEMETRYSPEED_19200
:
946 PIOS_COM_ChangeBaud(port
, 19200);
948 case HWSETTINGS_TELEMETRYSPEED_38400
:
949 PIOS_COM_ChangeBaud(port
, 38400);
951 case HWSETTINGS_TELEMETRYSPEED_57600
:
952 PIOS_COM_ChangeBaud(port
, 57600);
954 case HWSETTINGS_TELEMETRYSPEED_115200
:
955 PIOS_COM_ChangeBaud(port
, 115200);