dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
telemetry.c
Go to the documentation of this file.
1 
16 /*
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful, but
23  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25  * for more details.
26  *
27  * You should have received a copy of the GNU General Public License along
28  * with this program; if not, see <http://www.gnu.org/licenses/>
29  *
30  * Additional note on redistribution: The copyright and license notices above
31  * must be maintained in each individual source file that is a derivative work
32  * of this source file; otherwise redistribution is prohibited.
33  */
34 
35 #include "openpilot.h"
36 #include <eventdispatcher.h>
37 #include "flighttelemetrystats.h"
38 #include "gcstelemetrystats.h"
39 #include "modulesettings.h"
40 #include "pios_thread.h"
41 #include "pios_mutex.h"
42 #include "pios_queue.h"
43 
44 #include "pios_hal.h"
45 
46 #include <uavtalk.h>
47 
48 #ifndef TELEM_QUEUE_SIZE
49 /* 115200 = 11520 bytes/sec; if each transaction is 32 bytes,
50  * this is 160ms of stuff. Conversely, this is about 380 bytes
51  * of memory if each obj event is 7 bytes-ish.
52  */
53 #define TELEM_QUEUE_SIZE 60
54 #endif
55 
56 #ifndef TELEM_STACK_SIZE
57 #define TELEM_STACK_SIZE 624
58 #endif
59 
60 // Private constants
61 #define MAX_QUEUE_SIZE TELEM_QUEUE_SIZE
62 #define STACK_SIZE_BYTES TELEM_STACK_SIZE
63 #define TASK_PRIORITY_RX PIOS_THREAD_PRIO_NORMAL
64 #define TASK_PRIORITY_TX PIOS_THREAD_PRIO_NORMAL
65 #define MAX_RETRIES 2
66 
67 #define STATS_UPDATE_PERIOD_MS 1753
68 #define CONNECTION_TIMEOUT_MS 8000
69 #define USB_ACTIVITY_TIMEOUT_MS 6000
70 
71 #define MAX_ACKS_PENDING 3
72 #define MAX_REQS_PENDING 5
73 #define ACK_TIMEOUT_MS 250
74 
75 // Private types
76 
77 // Private variables
78 
79 struct pending_ack {
81  uint32_t timeout;
82 
83  uint16_t inst_id;
84  uint8_t retry_count;
85 };
86 
87 struct pending_req {
88  uint32_t obj_id;
89  uint16_t inst_id;
90  char valid;
91 };
92 
94  struct pios_queue *queue;
95 
96  uint32_t tx_errors;
97  uint32_t tx_retries;
99 
102 
104 
107 
109 };
110 
111 static struct telemetry_state telem_state = { };
112 
113 typedef struct telemetry_state *telem_t;
114 
115 // Private functions
116 static void telemetryTxTask(void *parameters);
117 static void telemetryRxTask(void *parameters);
118 
119 static int32_t transmitData(void *ctx, uint8_t *data, int32_t length);
120 static void addAckPending(telem_t telem, UAVObjHandle obj, uint16_t inst_id);
121 static void ackCallback(void *ctx, uint32_t obj_id, uint16_t inst_id);
122 static void reqCallback(void *ctx, uint32_t obj_id, uint16_t inst_id);
123 
124 static void registerObject(telem_t telem, UAVObjHandle obj);
125 static void updateObject(telem_t telem, UAVObjHandle obj, int32_t eventType);
126 static int32_t setUpdatePeriod(telem_t telem, UAVObjHandle obj, int32_t updatePeriodMs);
127 static void processObjEvent(telem_t telem, UAVObjEvent * ev);
128 static void updateTelemetryStats(telem_t telem);
129 static void gcsTelemetryStatsUpdated();
130 static void updateSettings();
131 static uintptr_t getComPort();
132 static void update_object_instances(uint32_t obj_id, uint32_t inst_id);
133 static bool processUsbActivity(bool seen_active);
134 
135 static int32_t fileReqCallback(void *ctx, uint8_t *buf,
136  uint32_t file_id, uint32_t offset, uint32_t len);
137 
139  registerObject(&telem_state, obj);
140 }
141 
147 int32_t TelemetryStart(void)
148 {
149  // Process all registered objects and connect queue for updates
151 
152  // Create periodic event that will be used to update the telemetry stats
153  UAVObjEvent ev;
154  memset(&ev, 0, sizeof(UAVObjEvent));
155 
157 
158  // Listen to objects of interest
159  GCSTelemetryStatsConnectQueue(telem_state.queue);
160 
161  struct pios_thread *telemetryTxTaskHandle;
162  struct pios_thread *telemetryRxTaskHandle;
163 
164  // Start telemetry tasks
165  telemetryTxTaskHandle = PIOS_Thread_Create(telemetryTxTask, "TelTx",
166  STACK_SIZE_BYTES, &telem_state, TASK_PRIORITY_TX);
167  telemetryRxTaskHandle = PIOS_Thread_Create(telemetryRxTask, "TelRx",
168  STACK_SIZE_BYTES, &telem_state, TASK_PRIORITY_RX);
169 
170  TaskMonitorAdd(TASKINFO_RUNNING_TELEMETRYTX, telemetryTxTaskHandle);
171  TaskMonitorAdd(TASKINFO_RUNNING_TELEMETRYRX, telemetryRxTaskHandle);
172 
173  return 0;
174 }
175 
181 int32_t TelemetryInitialize(void)
182 {
183  if (FlightTelemetryStatsInitialize() == -1 ||
184  GCSTelemetryStatsInitialize() == -1) {
185  return -1;
186  }
187 
188  telem_state.reqack_mutex = PIOS_Mutex_Create();
189 
190  if (!telem_state.reqack_mutex) {
191  return -1;
192  }
193 
194  // Initialize vars
195  telem_state.time_of_last_update = 0;
196 
197  // Create object queues
198  telem_state.queue = PIOS_Queue_Create(MAX_QUEUE_SIZE, sizeof(UAVObjEvent));
199 
200  // Initialise UAVTalk
201  telem_state.uavTalkCon = UAVTalkInitialize(&telem_state, transmitData,
203 
204  //register the new uavo instance callback function in the uavobjectmanager
206 
207  return 0;
208 }
209 
211 
212 
217 static void registerObject(telem_t telem, UAVObjHandle obj)
218 {
219  if (UAVObjIsMetaobject(obj)) {
220  /* Only connect change notifications for meta objects. No periodic updates */
221  UAVObjConnectQueue(obj, telem->queue, EV_MASK_ALL_UPDATES);
222  return;
223  } else {
224  UAVObjMetadata metadata;
225  UAVObjUpdateMode updateMode;
226  UAVObjGetMetadata(obj, &metadata);
227  updateMode = UAVObjGetTelemetryUpdateMode(&metadata);
228 
229  // Setup object for periodic updates
230  UAVObjEvent ev = {
231  .obj = obj,
232  .instId = UAVOBJ_ALL_INSTANCES,
233  .event = EV_UPDATED_PERIODIC,
234  };
235 
236  /* Only create a periodic event for objects that are periodic */
237  if (updateMode == UPDATEMODE_PERIODIC) {
238  EventPeriodicQueueCreate(&ev, telem->queue, 0);
239  }
240 
241  // Setup object for telemetry updates
242  updateObject(telem, obj, EV_NONE);
243  }
244 }
245 
250 static void updateObject(telem_t telem, UAVObjHandle obj, int32_t eventType)
251 {
252  UAVObjMetadata metadata;
253  UAVObjUpdateMode updateMode;
254  int32_t eventMask;
255 
256  if (UAVObjIsMetaobject(obj)) {
257  /* This function updates the periodic updates for the object.
258  * Meta Objects cannot have periodic updates.
259  */
260  PIOS_Assert(false);
261  return;
262  }
263 
264  // Get metadata
265  UAVObjGetMetadata(obj, &metadata);
266  updateMode = UAVObjGetTelemetryUpdateMode(&metadata);
267 
268  // Setup object depending on update mode
269  switch (updateMode) {
270  case UPDATEMODE_PERIODIC:
271  // Set update period
272  setUpdatePeriod(telem, obj, metadata.telemetryUpdatePeriod);
273 
274  // Connect queue
276  UAVObjConnectQueueThrottled(obj, telem->queue, eventMask, 0);
277  break;
278  case UPDATEMODE_ONCHANGE:
279  // Set update period
280  setUpdatePeriod(telem, obj, 0);
281 
282  // Connect queue
283  eventMask = EV_UPDATED | EV_UPDATED_MANUAL;
284  UAVObjConnectQueueThrottled(obj, telem->queue, eventMask, 0);
285  break;
287  setUpdatePeriod(telem, obj, 0);
288 
289  eventMask = EV_UPDATED | EV_UPDATED_MANUAL;
290  UAVObjConnectQueueThrottled(obj, telem->queue, eventMask,
291  metadata.telemetryUpdatePeriod);
292  break;
293  case UPDATEMODE_MANUAL:
294  // Set update period
295  setUpdatePeriod(telem, obj, 0);
296 
297  // Connect queue
298  eventMask = EV_UPDATED_MANUAL;
299  UAVObjConnectQueueThrottled(obj, telem->queue, eventMask, 0);
300  break;
301  }
302 }
303 
310 static void ackResendOrTimeout(telem_t telem, int idx)
311 {
312  if (telem->acks[idx].retry_count++ > MAX_RETRIES) {
313  DEBUG_PRINTF(3, "telem: abandoning ack wait for %d/%d\n",
314  UAVObjGetID(telem->acks[idx].obj),
315  telem->acks[idx].inst_id);
316 
317  /* Two different kinds of things in tx_errors-- objects that
318  * failed to transfer, and send errors (shouldn't happen) */
319  telem->tx_errors++;
320 
321  telem->acks[idx].obj = NULL;
322  } else {
323  DEBUG_PRINTF(3, "telem: abandoning ack wait for %d/%d\n",
324  UAVObjGetID(telem->acks[idx].obj),
325  telem->acks[idx].inst_id);
326 
327  int32_t success;
328 
329  telem->acks[idx].timeout = PIOS_Thread_Systime() +
331 
332  /* Must not hold lock while sending an object, because
333  * of lock ordering issues (though the lock should be
334  * severely squashed in uavtalk.c
335  */
337  success = UAVTalkSendObject(telem->uavTalkCon,
338  telem->acks[idx].obj,
339  telem->acks[idx].inst_id,
340  true);
342 
343  telem->tx_retries++;
344 
345  if (success == -1) {
346  telem->tx_errors++;
347  }
348  }
349 }
350 
356 static bool ackHousekeeping(telem_t telem)
357 {
358  bool did_something = false;
359 
360  uint32_t tm = PIOS_Thread_Systime();
361 
362  for (int i = 0; i < MAX_ACKS_PENDING; i++) {
363  if (telem->acks[i].obj) {
364  if (tm > telem->acks[i].timeout) {
365  ackResendOrTimeout(telem, i);
366 
367  did_something = true;
368  }
369  }
370  }
371 
372  return did_something;
373 }
374 
383 static void addAckPending(telem_t telem, UAVObjHandle obj, uint16_t inst_id)
384 {
385  DEBUG_PRINTF(3, "telem: want ack for %d/%d\n", UAVObjGetID(obj),
386  inst_id);
387 
388  while (true) {
390  ackHousekeeping(telem);
391 
392  /* There's a slight race here, if we're --already-- waiting
393  * for an ack on an object, we can end up putting it in here
394  * to wait again. In a perfect storm-- past retries cause two
395  * acks, and then the new object is lost-- we can be fooled.
396  * It seems like a lesser evil than most of the alternatives
397  * that keep good pipelining, though
398  */
399  for (int i = 0; i < MAX_ACKS_PENDING; i++) {
400  if (!telem->acks[i].obj) {
401  telem->acks[i].obj = obj;
402  telem->acks[i].inst_id = inst_id;
403  telem->acks[i].timeout =
406 
407  telem->acks[i].retry_count = 0;
408 
410  return;
411  }
412  }
413 
414  DEBUG_PRINTF(3, "telem: blocking because acks are full\n");
415 
416  /* Oh no. This is the bad case--- maximum number of things
417  * needing ack in flight.
418  */
419 
421 
422  /* TODO: Consider nicer wakeup mechanism here. */
424  }
425 }
426 
439 static int32_t fileReqCallback(void *ctx, uint8_t *buf,
440  uint32_t file_id, uint32_t offset, uint32_t len)
441 {
442  if (file_id < FLASH_PARTITION_NUM_LABELS) {
443  uintptr_t part_id;
444 
445  if (PIOS_FLASH_find_partition_id(file_id, &part_id)) {
446  return -1;
447  }
448 
449  uint32_t size;
450 
451  if (PIOS_FLASH_get_partition_size(part_id, &size)) {
452  return -2;
453  }
454 
455  if (offset >= size) {
456  return 0;
457  }
458 
459  uint32_t remaining = size - offset;
460 
461  if (len > remaining) {
462  len = remaining;
463  }
464 
465  if (PIOS_FLASH_start_transaction(part_id)) {
466  return -3;
467  }
468 
469  if (PIOS_FLASH_read_data(part_id, offset, buf, len)) {
470  len = -4;
471  }
472 
474 
475  return len;
476  }
477 
478  return -1;
479 }
480 
488 static void reqCallback(void *ctx, uint32_t obj_id, uint16_t inst_id)
489 {
490  telem_t telem = ctx;
491 
494 
495  int i;
496 
497  for (i = 0; i < MAX_REQS_PENDING - 1; i++) {
498  if (!telem->reqs[i].valid) {
499  break;
500  }
501  }
502 
503  if (i < MAX_REQS_PENDING) {
504  telem->reqs[i].valid = 1;
505  telem->reqs[i].obj_id = obj_id;
506  telem->reqs[i].inst_id = inst_id;
507  }
508 
509  // Unlock, to ensure new requests can come in OK.
511 }
512 
520 static void ackCallback(void *ctx, uint32_t obj_id, uint16_t inst_id)
521 {
522  telem_t telem = ctx;
523 
525 
526  for (int i = 0; i < MAX_ACKS_PENDING; i++) {
527  if (!telem->acks[i].obj) {
528  continue;
529  }
530 
531  if (inst_id != telem->acks[i].inst_id) {
532  continue;
533  }
534 
535  uint32_t other_obj_id = UAVObjGetID(telem->acks[i].obj);
536 
537  if (obj_id != other_obj_id) {
538  continue;
539  }
540 
541  telem->acks[i].obj = NULL;
542 
543  DEBUG_PRINTF(3, "telem: Got ack for %d/%d\n", obj_id, inst_id);
545  return;
546  }
547 
549 
550  DEBUG_PRINTF(3, "telem: Got UNEXPECTED ack for %d/%d\n", obj_id, inst_id);
551 }
552 
556 static void processObjEvent(telem_t telem, UAVObjEvent * ev)
557 {
558  if (ev->obj == 0) {
559  updateTelemetryStats(telem);
560  } else if (ev->obj == GCSTelemetryStatsHandle()) {
562  } else {
563  // Act on event
564  if (ev->event == EV_UPDATED || ev->event == EV_UPDATED_MANUAL ||
565  ev->event == EV_UPDATED_PERIODIC) {
566  int32_t success = -1;
567 
568  UAVObjMetadata metadata;
569 
570  bool acked = false;
571 
572  // Get object metadata
573  UAVObjGetMetadata(ev->obj, &metadata);
574 
575  if (UAVObjGetTelemetryAcked(&metadata)) {
576  acked = true;
577 
578  addAckPending(telem, ev->obj, ev->instId);
579  }
580 
581  success = UAVTalkSendObject(telem->uavTalkCon,
582  ev->obj, ev->instId,
583  acked);
584 
585  if (success == -1) {
586  telem->tx_errors++;
587  }
588  }
589 
590  // If this is a metaobject then make necessary
591  // telemetry updates
592  if (UAVObjIsMetaobject(ev->obj)) {
593  // linked object will be the actual object the
594  // metadata are for
595  updateObject(telem, UAVObjGetLinkedObj(ev->obj),
596  EV_NONE);
597  }
598  }
599 
601 }
602 
603 static bool sendRequestedObjs(telem_t telem)
604 {
605  // Must be called with the reqack mutex.
606  if (!telem->reqs[0].valid) {
607  return false;
608  }
609 
610  struct pending_req preq = telem->reqs[0];
611 
612  /* Expensive, but for as little as this comes up,
613  * who cares.
614  */
615  int i;
616 
617  for (i = 1; i < MAX_REQS_PENDING; i++) {
618  if (!telem->reqs[i].valid) {
619  break;
620  }
621  telem->reqs[i-1] = telem->reqs[i];
622  }
623 
624  telem->reqs[i-1].valid = 0;
625 
626  // Unlock, to ensure new requests can come in OK.
628 
629  // handle request
630  UAVObjHandle obj = UAVObjGetByID(preq.obj_id);
631 
632  // Send requested object if message is of type OBJ_REQ
633  if (!obj) {
634  UAVTalkSendNack(telem->uavTalkCon, preq.obj_id,
635  preq.inst_id);
636  } else {
637  if ((preq.inst_id == UAVOBJ_ALL_INSTANCES) ||
638  (preq.inst_id < UAVObjGetNumInstances(obj))) {
640  obj, preq.inst_id,
641  false);
642  } else {
644  preq.obj_id,
645  preq.inst_id);
646  }
647  }
648 
649 
652 
653  return true;
654 }
655 
659 static void telemetryTxTask(void *parameters)
660 {
661  telem_t telem = parameters;
662 
663  // Update telemetry settings
664  updateSettings();
665 
666  // Loop forever
667  while (1) {
668  UAVObjEvent ev;
669 
670  bool retval;
671 
672  if (telem->request_inhibit) {
673  telem->tx_inhibited = true;
675  continue;
676  }
677 
678  telem->tx_inhibited = false;
679 
680  // Wait for queue message or short timeout
681  retval = PIOS_Queue_Receive(telem->queue, &ev, 10);
682 
685 
686  /* Short-circuit means sendRequestedObjs "wins" */
687  while (sendRequestedObjs(telem) || ackHousekeeping(telem));
688 
690 
691  if (retval == true) {
692  // Process event
693  processObjEvent(telem, &ev);
694  }
695 
696  }
697 }
698 
702 static void telemetryRxTask(void *parameters)
703 {
704  telem_t telem = parameters;
705 
706  // Task loop
707  while (1) {
708  uintptr_t inputPort = getComPort();
709 
710  if (inputPort && (!telem->request_inhibit)) {
711  // Block until data are available
712  uint8_t serial_data[16];
713  uint16_t bytes_to_process;
714 
715  telem->rx_inhibited = false;
716 
717  bytes_to_process = PIOS_COM_ReceiveBuffer(inputPort,
718  serial_data, sizeof(serial_data), 100);
719 
720  if (bytes_to_process > 0) {
722  serial_data, bytes_to_process);
723 
724 #if defined(PIOS_COM_TELEM_USB)
725  if (inputPort == PIOS_COM_TELEM_USB) {
726  processUsbActivity(true);
727  }
728 #endif
729  }
730  } else {
731  telem->rx_inhibited = telem->request_inhibit;
733  }
734  }
735 }
736 
744 static int32_t transmitData(void *ctx, uint8_t * data, int32_t length)
745 {
746  (void) ctx;
747 
748  uintptr_t outputPort = getComPort();
749 
750  if (outputPort)
751  return PIOS_COM_SendBuffer(outputPort, data, length);
752 
753  return -1;
754 }
755 
763 static int32_t setUpdatePeriod(telem_t telem, UAVObjHandle obj,
764  int32_t updatePeriodMs)
765 {
766  UAVObjEvent ev;
767 
768  // Add object for periodic updates
769  ev.obj = obj;
772  return EventPeriodicQueueUpdate(&ev, telem->queue, updatePeriodMs);
773 }
774 
780 static void gcsTelemetryStatsUpdated(telem_t telem)
781 {
782  // XXX this is dumb. It needs to not be connected across global
783  // objects but "projected" so that multiple telemetry sessions
784  // can be supported.
785  FlightTelemetryStatsData flightStats;
786  GCSTelemetryStatsData gcsStats;
787  FlightTelemetryStatsGet(&flightStats);
788  GCSTelemetryStatsGet(&gcsStats);
789  if (flightStats.Status != FLIGHTTELEMETRYSTATS_STATUS_CONNECTED || gcsStats.Status != GCSTELEMETRYSTATS_STATUS_CONNECTED) {
790  updateTelemetryStats(telem);
791  }
792 }
793 
797 static void updateTelemetryStats(telem_t telem)
798 {
799  UAVTalkStats utalkStats;
800  FlightTelemetryStatsData flightStats;
801  GCSTelemetryStatsData gcsStats;
802  uint8_t forceUpdate;
803  uint8_t connectionTimeout;
804  uint32_t timeNow;
805 
806  // Get stats
807  UAVTalkGetStats(telem->uavTalkCon, &utalkStats);
808 
809  // Get object data
810  FlightTelemetryStatsGet(&flightStats);
811  GCSTelemetryStatsGet(&gcsStats);
812 
813  // Update stats object
814  if (flightStats.Status == FLIGHTTELEMETRYSTATS_STATUS_CONNECTED) {
815  /* This is bogus because updates to GCSTelemetryStats trigger
816  * this call, in addition to just the periodic stuff.
817  */
818  flightStats.RxDataRate = (float)utalkStats.rxBytes / ((float)STATS_UPDATE_PERIOD_MS / 1000.0f);
819  flightStats.TxDataRate = (float)utalkStats.txBytes / ((float)STATS_UPDATE_PERIOD_MS / 1000.0f);
820  flightStats.RxFailures += utalkStats.rxErrors;
821  flightStats.TxFailures += telem->tx_errors;
822  flightStats.TxRetries += telem->tx_retries;
823  telem->tx_errors = 0;
824  telem->tx_retries = 0;
825  } else {
826  flightStats.RxDataRate = 0;
827  flightStats.TxDataRate = 0;
828  flightStats.RxFailures = 0;
829  flightStats.TxFailures = 0;
830  flightStats.TxRetries = 0;
831  telem->tx_errors = 0;
832  telem->tx_retries = 0;
833  }
834 
835  // Check for connection timeout
836  timeNow = PIOS_Thread_Systime();
837  if (utalkStats.rxObjects > 0) {
838  telem->time_of_last_update = timeNow;
839  }
840  if ((timeNow - telem->time_of_last_update) > CONNECTION_TIMEOUT_MS) {
841  connectionTimeout = 1;
842  } else {
843  connectionTimeout = 0;
844  }
845 
846  // Update connection state
847  forceUpdate = 1;
848  if (flightStats.Status == FLIGHTTELEMETRYSTATS_STATUS_DISCONNECTED) {
849  // Wait for connection request
850  if (gcsStats.Status == GCSTELEMETRYSTATS_STATUS_HANDSHAKEREQ) {
851  flightStats.Status = FLIGHTTELEMETRYSTATS_STATUS_HANDSHAKEACK;
852  }
853  } else if (flightStats.Status == FLIGHTTELEMETRYSTATS_STATUS_HANDSHAKEACK) {
854  // Wait for connection
855  if (gcsStats.Status == GCSTELEMETRYSTATS_STATUS_CONNECTED) {
856  flightStats.Status = FLIGHTTELEMETRYSTATS_STATUS_CONNECTED;
857  } else if (gcsStats.Status == GCSTELEMETRYSTATS_STATUS_DISCONNECTED) {
858  flightStats.Status = FLIGHTTELEMETRYSTATS_STATUS_DISCONNECTED;
859  }
860  } else if (flightStats.Status == FLIGHTTELEMETRYSTATS_STATUS_CONNECTED) {
861  if (gcsStats.Status != GCSTELEMETRYSTATS_STATUS_CONNECTED || connectionTimeout) {
862  flightStats.Status = FLIGHTTELEMETRYSTATS_STATUS_DISCONNECTED;
863  } else {
864  forceUpdate = 0;
865  }
866  } else {
867  flightStats.Status = FLIGHTTELEMETRYSTATS_STATUS_DISCONNECTED;
868  }
869 
870 #ifndef PIPXTREME
871  // Update the telemetry alarm
872  if (flightStats.Status == FLIGHTTELEMETRYSTATS_STATUS_CONNECTED) {
873  AlarmsClear(SYSTEMALARMS_ALARM_TELEMETRY);
874  } else {
875  AlarmsSet(SYSTEMALARMS_ALARM_TELEMETRY, SYSTEMALARMS_ALARM_ERROR);
876  }
877 #endif
878 
879  // Update object
880  FlightTelemetryStatsSet(&flightStats);
881 
882  // Force telemetry update if not connected
883  if (forceUpdate) {
884  FlightTelemetryStatsUpdated();
885  }
886 }
887 
891 static void updateSettings()
892 {
893  if (PIOS_COM_TELEM_SER) {
894  // Retrieve settings
895  uint8_t speed;
896  ModuleSettingsTelemetrySpeedGet(&speed);
897 
899  }
900 }
901 
902 #if defined(PIOS_COM_TELEM_USB)
903 
909 static bool processUsbActivity(bool seen_active)
910 {
911  static volatile uint32_t usb_last_active;
912 
913  if (seen_active) {
914  usb_last_active = PIOS_Thread_Systime();
915 
916  return true;
917  }
918 
919  if (usb_last_active) {
920  if (!PIOS_Thread_Period_Elapsed(usb_last_active,
922  return true;
923  } else {
924  /* "Latch" expiration so it doesn't become true
925  * again.
926  */
927  usb_last_active = 0;
928  }
929  }
930 
931  return false;
932 }
933 #endif // PIOS_COM_TELEM_USB
934 
938 static uintptr_t getComPort()
939 {
940 #if defined(PIOS_COM_TELEM_USB)
942  /* Let's further qualify this. If there's anything spooled
943  * up for RX, bump the activity time.
944  */
945 
947 
948  if (processUsbActivity(rx_pending)) {
949  return PIOS_COM_TELEM_USB;
950  }
951 
953  return PIOS_COM_TELEM_USB;
954  }
955  }
956 #endif /* PIOS_COM_TELEM_USB */
957 
958 #ifndef PIPXTREME
959  /* Pipx: Don't ever natively telemeter over serial links, because
960  * they might be connected to a FC and we might overwrite the FC's
961  * objects with our own.
962  */
964  return PIOS_COM_TELEM_SER;
965 #endif
966 
967  return 0;
968 }
969 
976 static void update_object_instances(uint32_t obj_id, uint32_t inst_id)
977 {
978  /* XXX just send the new instance, reqack. */
979 }
980 
981 extern void telemetry_set_inhibit(bool inhibit)
982 {
983  if (inhibit) {
984  if (!telem_state.request_inhibit) {
985  telem_state.request_inhibit = true;
986 
987  while ((!telem_state.rx_inhibited) ||
988  (!telem_state.tx_inhibited)) {
990  }
991 
992  /* XXX: Consider nulling out flighttelemetrystats
993  * conn state.
994  */
995  }
996  } else {
997  if (telem_state.request_inhibit) {
998  telem_state.request_inhibit = false;
999 
1000  while (telem_state.rx_inhibited ||
1001  telem_state.tx_inhibited) {
1002  PIOS_Thread_Sleep(1);
1003  }
1004  }
1005  }
1006 }
1007 
uint32_t timeout
Definition: telemetry.c:81
uint16_t speed
Definition: msp_messages.h:101
int32_t PIOS_FLASH_find_partition_id(enum pios_flash_partition_labels label, uintptr_t *partition_id)
uint32_t PIOS_Thread_Systime(void)
Definition: pios_thread.c:212
UAVObjHandle UAVObjGetByID(uint32_t id)
struct pios_queue * PIOS_Queue_Create(size_t queue_length, size_t item_size)
Definition: pios_queue.c:47
static void updateObject(telem_t telem, UAVObjHandle obj, int32_t eventType)
Definition: telemetry.c:250
static void registerObjectShim(UAVObjHandle obj)
Definition: telemetry.c:138
bool UAVObjIsMetaobject(UAVObjHandle obj)
#define STATS_UPDATE_PERIOD_MS
Definition: telemetry.c:67
#define CONNECTION_TIMEOUT_MS
Definition: telemetry.c:68
uint32_t rxErrors
Definition: uavtalk.h:49
uint16_t inst_id
Definition: telemetry.c:83
int32_t EventPeriodicQueueCreate(UAVObjEvent *ev, struct pios_queue *queue, uint16_t periodMs)
Definition: systemmod.c:908
int32_t UAVTalkSendNack(UAVTalkConnection connectionHandle, uint32_t objId, uint16_t instId)
Definition: uavtalk.c:903
#define MAX_QUEUE_SIZE
Definition: telemetry.c:61
static void ackCallback(void *ctx, uint32_t obj_id, uint16_t inst_id)
Definition: telemetry.c:520
void UAVTalkGetStats(UAVTalkConnection connection, UAVTalkStats *stats)
Definition: uavtalk.c:93
uint8_t retry_count
Definition: telemetry.c:84
#define TASK_PRIORITY_RX
Definition: telemetry.c:63
static uintptr_t getComPort()
Definition: telemetry.c:938
int32_t PIOS_FLASH_get_partition_size(uintptr_t partition_id, uint32_t *partition_size)
static void processObjEvent(telem_t telem, UAVObjEvent *ev)
Definition: telemetry.c:556
UAVObjUpdateMode
uint32_t rxObjects
Definition: uavtalk.h:46
#define UAVOBJ_ALL_INSTANCES
static void gcsTelemetryStatsUpdated()
static void update_object_instances(uint32_t obj_id, uint32_t inst_id)
Definition: telemetry.c:976
int32_t AlarmsSet(SystemAlarmsAlarmElem alarm, SystemAlarmsAlarmOptions severity)
Definition: alarms.c:97
#define MAX_ACKS_PENDING
Definition: telemetry.c:71
UAVTalkConnection uavTalkCon
Definition: telemetry.c:108
int32_t UAVObjConnectQueueThrottled(UAVObjHandle obj_handle, struct pios_queue *queue, uint8_t eventMask, uint16_t interval)
bool PIOS_Queue_Receive(struct pios_queue *queuep, void *itemp, uint32_t timeout_ms)
Definition: pios_queue.c:213
void UAVTalkProcessInputStream(UAVTalkConnection connectionHandle, uint8_t *rxbytes, int numbytes)
Definition: uavtalk.c:423
#define MAX_RETRIES
Definition: telemetry.c:65
#define PIOS_COM_TELEM_USB
Definition: pios_board.h:114
#define DEBUG_PRINTF(level,...)
Definition: pios_board.h:39
bool PIOS_Mutex_Unlock(struct pios_mutex *mtx)
Definition: pios_mutex.c:104
static void reqCallback(void *ctx, uint32_t obj_id, uint16_t inst_id)
Definition: telemetry.c:488
struct pios_mutex * PIOS_Mutex_Create(void)
Definition: pios_mutex.c:43
UAVObjHandle obj
struct pios_mutex * reqack_mutex
Definition: telemetry.c:103
uint32_t txBytes
Definition: uavtalk.h:42
static void addAckPending(telem_t telem, UAVObjHandle obj, uint16_t inst_id)
Definition: telemetry.c:383
uint8_t UAVObjGetTelemetryAcked(const UAVObjMetadata *dataOut)
void PIOS_HAL_ConfigureSerialSpeed(uintptr_t com_id, HwSharedSpeedBpsOptions speed)
Definition: pios_hal.c:1115
uint8_t data[XFER_BYTES_PER_PACKET]
Definition: bl_messages.h:129
UAVObjHandle obj
Definition: telemetry.c:80
uint8_t length
static void updateSettings()
Definition: telemetry.c:891
uint32_t rxBytes
Definition: uavtalk.h:43
void * UAVTalkConnection
Definition: uavtalk.h:53
volatile bool rx_inhibited
Definition: telemetry.c:106
#define PIOS_COM_TELEM_SER
Definition: pios_hal.h:58
uint16_t inst_id
Definition: telemetry.c:89
#define STACK_SIZE_BYTES
Definition: telemetry.c:62
UAVTalkConnection UAVTalkInitialize(void *ctx, UAVTalkOutputCb outputStream, UAVTalkAckCb ackCallback, UAVTalkReqCb reqCallback, UAVTalkFileCb fileCallback)
Definition: uavtalk.c:59
static bool processUsbActivity(bool seen_active)
#define MODULE_HIPRI_INITCALL(ifn, sfn)
Definition: pios_initcall.h:66
struct pending_req reqs[MAX_REQS_PENDING]
Definition: telemetry.c:101
uint32_t UAVObjGetID(UAVObjHandle obj)
int32_t PIOS_FLASH_end_transaction(uintptr_t partition_id)
static void ackResendOrTimeout(telem_t telem, int idx)
Definition: telemetry.c:310
uint16_t PIOS_COM_ReceiveBuffer(uintptr_t com_id, uint8_t *buf, uint16_t buf_len, uint32_t timeout_ms)
static void telemetryRxTask(void *parameters)
Definition: telemetry.c:702
#define EV_MASK_ALL_UPDATES
int32_t TelemetryInitialize(void)
Definition: telemetry.c:181
struct pios_thread * PIOS_Thread_Create(void(*fp)(void *), const char *namep, size_t stack_bytes, void *argp, enum pios_thread_prio_e prio)
Definition: pios_thread.c:89
static int32_t transmitData(void *ctx, uint8_t *data, int32_t length)
Definition: telemetry.c:744
Event dispatcher, distributes object events as callbacks. Alternative to using tasks and queues...
#define USB_ACTIVITY_TIMEOUT_MS
Definition: telemetry.c:69
UAVObjUpdateMode UAVObjGetTelemetryUpdateMode(const UAVObjMetadata *dataOut)
char valid
Definition: telemetry.c:90
int32_t TaskMonitorAdd(TaskInfoRunningElem task, struct pios_thread *threadp)
Definition: taskmonitor.c:67
uint8_t i
Definition: msp_messages.h:97
static int32_t fileReqCallback(void *ctx, uint8_t *buf, uint32_t file_id, uint32_t offset, uint32_t len)
Definition: telemetry.c:439
uint32_t obj_id
int32_t EventPeriodicQueueUpdate(UAVObjEvent *ev, struct pios_queue *queue, uint16_t periodMs)
Definition: systemmod.c:920
#define TASK_PRIORITY_TX
Definition: telemetry.c:64
struct telemetry_state * telem_t
Definition: telemetry.c:113
void UAVObjUnblockThrottle(struct ObjectEventEntryThrottled *throttled)
bool PIOS_Thread_Period_Elapsed(const uint32_t prev_systime, const uint32_t increment_ms)
Determine if a period has elapsed since a datum.
Definition: pios_thread.c:281
uint16_t PIOS_COM_GetNumReceiveBytesPending(uintptr_t com_id)
uint32_t time_of_last_update
Definition: telemetry.c:98
Tracking statistics for a UAVTalk connection.
Definition: uavtalk.h:41
static void updateTelemetryStats(telem_t telem)
Definition: telemetry.c:797
void PIOS_Thread_Sleep(uint32_t time_ms)
Definition: pios_thread.c:229
int32_t TelemetryStart(void)
Definition: telemetry.c:147
PIOS_COM_SendBuffer(shub_global->frsky_port, shub_global->serial_buf, msg_length)
int32_t UAVObjConnectQueue(UAVObjHandle obj_handle, struct pios_queue *queue, uint8_t eventMask)
uint32_t offset
Definition: uavtalk_priv.h:51
static void registerObject(telem_t telem, UAVObjHandle obj)
Definition: telemetry.c:217
static bool ackHousekeeping(telem_t telem)
Definition: telemetry.c:356
int32_t UAVObjGetMetadata(UAVObjHandle obj_handle, UAVObjMetadata *dataOut)
int32_t UAVTalkSendObject(UAVTalkConnection connection, UAVObjHandle obj, uint16_t instId, uint8_t acked)
Definition: uavtalk.c:120
UAVObjHandle UAVObjGetLinkedObj(UAVObjHandle obj)
struct pios_queue * queue
Definition: telemetry.c:94
UAVObjEventType event
Includes PiOS and core architecture components.
int32_t AlarmsClear(SystemAlarmsAlarmElem alarm)
Definition: alarms.c:171
uint16_t UAVObjGetNumInstances(UAVObjHandle obj)
int32_t PIOS_FLASH_read_data(uintptr_t partition_id, uint32_t offset, uint8_t *data, uint16_t len)
uint32_t file_id
int32_t PIOS_FLASH_start_transaction(uintptr_t partition_id)
void telemetry_set_inhibit(bool inhibit)
Definition: telemetry.c:981
static int32_t setUpdatePeriod(telem_t telem, UAVObjHandle obj, int32_t updatePeriodMs)
Definition: telemetry.c:763
#define ACK_TIMEOUT_MS
Definition: telemetry.c:73
uint32_t tx_errors
Definition: telemetry.c:96
volatile bool request_inhibit
Definition: telemetry.c:106
volatile bool tx_inhibited
Definition: telemetry.c:106
static bool sendRequestedObjs(telem_t telem)
Definition: telemetry.c:603
struct ObjectEventEntryThrottled * throttle
#define PIOS_Assert(test)
Definition: pios_debug.h:52
void UAVObjRegisterNewInstanceCB(new_uavo_instance_cb_t callback)
#define MAX_REQS_PENDING
Definition: telemetry.c:72
static void telemetryTxTask(void *parameters)
Definition: telemetry.c:659
struct pios_semaphore * access_sem
Definition: telemetry.c:105
Include file of the UAVTalk library.
uint32_t obj_id
Definition: telemetry.c:88
uint32_t tx_retries
Definition: telemetry.c:97
static struct telemetry_state telem_state
Definition: telemetry.c:111
struct pending_ack acks[MAX_ACKS_PENDING]
Definition: telemetry.c:100
#define PIOS_MUTEX_TIMEOUT_MAX
Definition: pios_mutex.h:30
bool PIOS_COM_Available(uintptr_t com_id)
bool PIOS_Mutex_Lock(struct pios_mutex *mtx, uint32_t timeout_ms)
Definition: pios_mutex.c:66
void UAVObjIterate(void(*iterator)(UAVObjHandle obj))