2 ******************************************************************************
4 * @addtogroup OpenPilotModules OpenPilot Modules
6 * @addtogroup RadioComBridgeModule Com Port to Radio Bridge Module
7 * @brief Bridge Com and Radio ports
10 * @file RadioComBridge.c
11 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012-2013.
12 * @brief Bridges selected Com Port to the COM VCP emulated serial port
13 * @see The GNU Public License (GPL) Version 3
15 *****************************************************************************/
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.
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
27 * You should have received a copy of the GNU General Public License along
28 * with this program; if not, write to the Free Software Foundation, Inc.,
29 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 #include <openpilot.h>
35 #include <radiocombridge.h>
36 #include <oplinkstatus.h>
37 #include <objectpersistence.h>
38 #include <oplinksettings.h>
39 #include <oplinkreceiver.h>
40 #include <radiocombridgestats.h>
41 #include <uavtalk_priv.h>
42 #include <pios_rfm22b.h>
44 #if defined(PIOS_INCLUDE_FLASH_EEPROM)
45 #include <pios_eeprom.h>
53 #define STACK_SIZE_BYTES 150
54 #define TASK_PRIORITY (tskIDLE_PRIORITY + 1)
56 #define RETRY_TIMEOUT_MS 20
57 #define EVENT_QUEUE_SIZE 10
58 #define MAX_PORT_DELAY 200
59 #define SERIAL_RX_BUF_LEN 100
60 #define PPM_INPUT_TIMEOUT 100
68 xTaskHandle telemetryTxTaskHandle
;
69 xTaskHandle telemetryRxTaskHandle
;
70 xTaskHandle radioTxTaskHandle
;
71 xTaskHandle radioRxTaskHandle
;
72 xTaskHandle PPMInputTaskHandle
;
73 xTaskHandle serialRxTaskHandle
;
75 // The UAVTalk connection on the com side.
76 UAVTalkConnection telemUAVTalkCon
;
77 UAVTalkConnection radioUAVTalkCon
;
80 xQueueHandle uavtalkEventQueue
;
81 xQueueHandle radioEventQueue
;
83 // The raw serial Rx buffer
84 uint8_t serialRxBuf
[SERIAL_RX_BUF_LEN
];
87 uint32_t telemetryTxRetries
;
88 uint32_t radioTxRetries
;
90 // Is this modem the coordinator
93 // Should we parse UAVTalk?
96 // The current configured uart speed
97 OPLinkSettingsComSpeedOptions comSpeed
;
103 static void telemetryTxTask(void *parameters
);
104 static void telemetryRxTask(void *parameters
);
105 static void serialRxTask(void *parameters
);
106 static void radioTxTask(void *parameters
);
107 static void radioRxTask(void *parameters
);
108 static void PPMInputTask(void *parameters
);
109 static int32_t UAVTalkSendHandler(uint8_t *buf
, int32_t length
);
110 static int32_t RadioSendHandler(uint8_t *buf
, int32_t length
);
111 static void ProcessTelemetryStream(UAVTalkConnection inConnectionHandle
, UAVTalkConnection outConnectionHandle
, uint8_t *rxbuffer
, uint8_t count
);
112 static void ProcessRadioStream(UAVTalkConnection inConnectionHandle
, UAVTalkConnection outConnectionHandle
, uint8_t *rxbuffer
, uint8_t count
);
113 static void objectPersistenceUpdatedCb(UAVObjEvent
*objEv
);
114 static void registerObject(UAVObjHandle obj
);
119 static RadioComBridgeData
*data
;
122 * @brief Start the module
124 * @return -1 if initialisation failed, 0 on success
126 static int32_t RadioComBridgeStart(void)
130 OPLinkSettingsData oplinkSettings
;
131 OPLinkSettingsGet(&oplinkSettings
);
133 // Check if this is the coordinator modem
134 data
->isCoordinator
= (oplinkSettings
.Protocol
== OPLINKSETTINGS_PROTOCOL_OPLINKCOORDINATOR
);
136 // We will not parse/send UAVTalk if any ports are configured as Serial (except for over the USB HID port).
137 data
->parseUAVTalk
= ((oplinkSettings
.MainPort
!= OPLINKSETTINGS_MAINPORT_SERIAL
) &&
138 (oplinkSettings
.FlexiPort
!= OPLINKSETTINGS_FLEXIPORT_SERIAL
) &&
139 (oplinkSettings
.VCPPort
!= OPLINKSETTINGS_VCPPORT_SERIAL
));
141 // Set the maximum radio RF power.
142 switch (oplinkSettings
.MaxRFPower
) {
143 case OPLINKSETTINGS_MAXRFPOWER_125
:
144 PIOS_RFM22B_SetTxPower(pios_rfm22b_id
, RFM22_tx_pwr_txpow_0
);
146 case OPLINKSETTINGS_MAXRFPOWER_16
:
147 PIOS_RFM22B_SetTxPower(pios_rfm22b_id
, RFM22_tx_pwr_txpow_1
);
149 case OPLINKSETTINGS_MAXRFPOWER_316
:
150 PIOS_RFM22B_SetTxPower(pios_rfm22b_id
, RFM22_tx_pwr_txpow_2
);
152 case OPLINKSETTINGS_MAXRFPOWER_63
:
153 PIOS_RFM22B_SetTxPower(pios_rfm22b_id
, RFM22_tx_pwr_txpow_3
);
155 case OPLINKSETTINGS_MAXRFPOWER_126
:
156 PIOS_RFM22B_SetTxPower(pios_rfm22b_id
, RFM22_tx_pwr_txpow_4
);
158 case OPLINKSETTINGS_MAXRFPOWER_25
:
159 PIOS_RFM22B_SetTxPower(pios_rfm22b_id
, RFM22_tx_pwr_txpow_5
);
161 case OPLINKSETTINGS_MAXRFPOWER_50
:
162 PIOS_RFM22B_SetTxPower(pios_rfm22b_id
, RFM22_tx_pwr_txpow_6
);
164 case OPLINKSETTINGS_MAXRFPOWER_100
:
165 PIOS_RFM22B_SetTxPower(pios_rfm22b_id
, RFM22_tx_pwr_txpow_7
);
172 // Configure our UAVObjects for updates.
173 UAVObjConnectQueue(UAVObjGetByID(OBJECTPERSISTENCE_OBJID
), data
->uavtalkEventQueue
, EV_UPDATED
| EV_UPDATED_MANUAL
);
174 if (data
->isCoordinator
) {
175 UAVObjConnectQueue(UAVObjGetByID(OPLINKRECEIVER_OBJID
), data
->radioEventQueue
, EV_UPDATED
| EV_UPDATED_MANUAL
| EV_UPDATE_REQ
);
177 UAVObjConnectQueue(UAVObjGetByID(OPLINKRECEIVER_OBJID
), data
->uavtalkEventQueue
, EV_UPDATED
| EV_UPDATED_MANUAL
| EV_UPDATE_REQ
);
179 registerObject(OPLinkStatusHandle());
181 if (data
->isCoordinator
) {
182 registerObject(RadioComBridgeStatsHandle());
185 // Configure the UAVObject callbacks
186 ObjectPersistenceConnectCallback(&objectPersistenceUpdatedCb
);
188 // Start the primary tasks for receiving/sending UAVTalk packets from the GCS.
189 xTaskCreate(telemetryTxTask
, "telemetryTxTask", STACK_SIZE_BYTES
, NULL
, TASK_PRIORITY
, &(data
->telemetryTxTaskHandle
));
190 xTaskCreate(telemetryRxTask
, "telemetryRxTask", STACK_SIZE_BYTES
, NULL
, TASK_PRIORITY
, &(data
->telemetryRxTaskHandle
));
191 if (PIOS_PPM_RECEIVER
!= 0) {
192 xTaskCreate(PPMInputTask
, "PPMInputTask", STACK_SIZE_BYTES
, NULL
, TASK_PRIORITY
, &(data
->PPMInputTaskHandle
));
193 #ifdef PIOS_INCLUDE_WDG
194 PIOS_WDG_RegisterFlag(PIOS_WDG_PPMINPUT
);
197 if (!data
->parseUAVTalk
) {
198 // If the user wants raw serial communication, we need to spawn another thread to handle it.
199 xTaskCreate(serialRxTask
, "serialRxTask", STACK_SIZE_BYTES
, NULL
, TASK_PRIORITY
, &(data
->serialRxTaskHandle
));
200 #ifdef PIOS_INCLUDE_WDG
201 PIOS_WDG_RegisterFlag(PIOS_WDG_SERIALRX
);
204 xTaskCreate(radioTxTask
, "radioTxTask", STACK_SIZE_BYTES
, NULL
, TASK_PRIORITY
, &(data
->radioTxTaskHandle
));
205 xTaskCreate(radioRxTask
, "radioRxTask", STACK_SIZE_BYTES
, NULL
, TASK_PRIORITY
, &(data
->radioRxTaskHandle
));
207 // Register the watchdog timers.
208 #ifdef PIOS_INCLUDE_WDG
209 PIOS_WDG_RegisterFlag(PIOS_WDG_TELEMETRYTX
);
210 PIOS_WDG_RegisterFlag(PIOS_WDG_TELEMETRYRX
);
211 PIOS_WDG_RegisterFlag(PIOS_WDG_RADIOTX
);
212 PIOS_WDG_RegisterFlag(PIOS_WDG_RADIORX
);
221 * @brief Initialise the module
223 * @return -1 if initialisation failed on success
225 static int32_t RadioComBridgeInitialize(void)
227 // allocate and initialize the static data storage only if module is enabled
228 data
= (RadioComBridgeData
*)pios_malloc(sizeof(RadioComBridgeData
));
233 // Initialize the UAVObjects that we use
234 OPLinkStatusInitialize();
235 ObjectPersistenceInitialize();
236 OPLinkReceiverInitialize();
237 RadioComBridgeStatsInitialize();
239 // Initialise UAVTalk
240 data
->telemUAVTalkCon
= UAVTalkInitialize(&UAVTalkSendHandler
);
241 data
->radioUAVTalkCon
= UAVTalkInitialize(&RadioSendHandler
);
243 // Initialize the queues.
244 data
->uavtalkEventQueue
= xQueueCreate(EVENT_QUEUE_SIZE
, sizeof(UAVObjEvent
));
245 data
->radioEventQueue
= xQueueCreate(EVENT_QUEUE_SIZE
, sizeof(UAVObjEvent
));
247 // Initialize the statistics.
248 data
->telemetryTxRetries
= 0;
249 data
->radioTxRetries
= 0;
251 data
->parseUAVTalk
= true;
252 data
->comSpeed
= OPLINKSETTINGS_COMSPEED_9600
;
253 PIOS_COM_RADIO
= PIOS_COM_RFM22B
;
257 MODULE_INITCALL(RadioComBridgeInitialize
, RadioComBridgeStart
);
260 // TODO this code (badly) duplicates code from telemetry.c
261 // This method should be used only for periodically updated objects.
262 // The register method defined in telemetry.c should be factored out in a shared location so it can be
264 static void registerObject(UAVObjHandle obj
)
266 // Setup object for periodic updates
269 .instId
= UAVOBJ_ALL_INSTANCES
,
270 .event
= EV_UPDATED_PERIODIC
,
275 UAVObjMetadata metadata
;
277 UAVObjGetMetadata(obj
, &metadata
);
279 EventPeriodicQueueCreate(&ev
, data
->uavtalkEventQueue
, metadata
.telemetryUpdatePeriod
);
280 UAVObjConnectQueue(obj
, data
->uavtalkEventQueue
, EV_UPDATED_PERIODIC
| EV_UPDATED_MANUAL
| EV_UPDATE_REQ
);
284 * Update telemetry statistics
286 static void updateRadioComBridgeStats()
288 UAVTalkStats telemetryUAVTalkStats
;
289 UAVTalkStats radioUAVTalkStats
;
290 RadioComBridgeStatsData radioComBridgeStats
;
292 // Get telemetry stats
293 UAVTalkGetStats(data
->telemUAVTalkCon
, &telemetryUAVTalkStats
, true);
296 UAVTalkGetStats(data
->radioUAVTalkCon
, &radioUAVTalkStats
, true);
298 // Get stats object data
299 RadioComBridgeStatsGet(&radioComBridgeStats
);
301 radioComBridgeStats
.TelemetryTxRetries
= data
->telemetryTxRetries
;
302 radioComBridgeStats
.RadioTxRetries
= data
->radioTxRetries
;
304 // Update stats object
305 radioComBridgeStats
.TelemetryTxBytes
+= telemetryUAVTalkStats
.txBytes
;
306 radioComBridgeStats
.TelemetryTxFailures
+= telemetryUAVTalkStats
.txErrors
;
308 radioComBridgeStats
.TelemetryRxBytes
+= telemetryUAVTalkStats
.rxBytes
;
309 radioComBridgeStats
.TelemetryRxFailures
+= telemetryUAVTalkStats
.rxErrors
;
310 radioComBridgeStats
.TelemetryRxSyncErrors
+= telemetryUAVTalkStats
.rxSyncErrors
;
311 radioComBridgeStats
.TelemetryRxCrcErrors
+= telemetryUAVTalkStats
.rxCrcErrors
;
313 radioComBridgeStats
.RadioTxBytes
+= radioUAVTalkStats
.txBytes
;
314 radioComBridgeStats
.RadioTxFailures
+= radioUAVTalkStats
.txErrors
;
316 radioComBridgeStats
.RadioRxBytes
+= radioUAVTalkStats
.rxBytes
;
317 radioComBridgeStats
.RadioRxFailures
+= radioUAVTalkStats
.rxErrors
;
318 radioComBridgeStats
.RadioRxSyncErrors
+= radioUAVTalkStats
.rxSyncErrors
;
319 radioComBridgeStats
.RadioRxCrcErrors
+= radioUAVTalkStats
.rxCrcErrors
;
321 // Update stats object data
322 RadioComBridgeStatsSet(&radioComBridgeStats
);
326 * @brief Telemetry transmit task, regular priority
328 * @param[in] parameters The task parameters
330 static void telemetryTxTask(__attribute__((unused
)) void *parameters
)
336 #ifdef PIOS_INCLUDE_WDG
337 PIOS_WDG_UpdateFlag(PIOS_WDG_TELEMETRYTX
);
339 // Wait for queue message
340 if (xQueueReceive(data
->uavtalkEventQueue
, &ev
, MAX_PORT_DELAY
) == pdTRUE
) {
341 if (ev
.obj
== RadioComBridgeStatsHandle()) {
342 updateRadioComBridgeStats();
344 // Send update (with retries)
346 uint32_t retries
= 0;
347 while (retries
<= MAX_RETRIES
&& ret
== -1) {
348 ret
= UAVTalkSendObject(data
->telemUAVTalkCon
, ev
.obj
, ev
.instId
, 0, RETRY_TIMEOUT_MS
);
354 data
->telemetryTxRetries
+= retries
;
360 * @brief Radio tx task. Receive data packets from the com port and send to the radio.
362 * @param[in] parameters The task parameters
364 static void radioTxTask(__attribute__((unused
)) void *parameters
)
368 #ifdef PIOS_INCLUDE_WDG
369 PIOS_WDG_UpdateFlag(PIOS_WDG_RADIOTX
);
372 // Process the radio event queue, sending UAVObjects over the radio link as necessary.
375 // Wait for queue message
376 if (xQueueReceive(data
->radioEventQueue
, &ev
, MAX_PORT_DELAY
) == pdTRUE
) {
377 if ((ev
.event
== EV_UPDATED
) || (ev
.event
== EV_UPDATE_REQ
)) {
378 // Send update (with retries)
380 uint32_t retries
= 0;
381 while (retries
<= MAX_RETRIES
&& ret
== -1) {
382 ret
= UAVTalkSendObject(data
->radioUAVTalkCon
, ev
.obj
, ev
.instId
, 0, RETRY_TIMEOUT_MS
);
387 data
->radioTxRetries
+= retries
;
394 * @brief Radio rx task. Receive data packets from the radio and pass them on.
396 * @param[in] parameters The task parameters
398 static void radioRxTask(__attribute__((unused
)) void *parameters
)
402 #ifdef PIOS_INCLUDE_WDG
403 PIOS_WDG_UpdateFlag(PIOS_WDG_RADIORX
);
405 if (PIOS_COM_RADIO
) {
406 uint8_t serial_data
[16];
407 uint16_t bytes_to_process
= PIOS_COM_ReceiveBuffer(PIOS_COM_RADIO
, serial_data
, sizeof(serial_data
), MAX_PORT_DELAY
);
408 if (bytes_to_process
> 0) {
409 if (data
->parseUAVTalk
) {
410 // Pass the data through the UAVTalk parser.
411 ProcessRadioStream(data
->radioUAVTalkCon
, data
->telemUAVTalkCon
, serial_data
, bytes_to_process
);
412 } else if (PIOS_COM_TELEMETRY
) {
413 // Send the data straight to the telemetry port.
414 // Following call can fail with -2 error code (buffer full) or -3 error code (could not acquire send mutex)
415 // It is the caller responsibility to retry in such cases...
418 while (count
-- > 0 && ret
< -1) {
419 ret
= PIOS_COM_SendBufferNonBlocking(PIOS_COM_TELEMETRY
, serial_data
, bytes_to_process
);
430 * @brief Receive telemetry from the USB/COM port.
432 * @param[in] parameters The task parameters
434 static void telemetryRxTask(__attribute__((unused
)) void *parameters
)
438 uint32_t inputPort
= data
->parseUAVTalk
? PIOS_COM_TELEMETRY
: 0;
439 #ifdef PIOS_INCLUDE_WDG
440 PIOS_WDG_UpdateFlag(PIOS_WDG_TELEMETRYRX
);
442 #if defined(PIOS_INCLUDE_USB)
443 // Determine output port (USB takes priority over telemetry port)
444 if (PIOS_USB_CheckAvailable(0) && PIOS_COM_TELEM_USB_HID
) {
445 inputPort
= PIOS_COM_TELEM_USB_HID
;
447 #endif /* PIOS_INCLUDE_USB */
449 uint8_t serial_data
[16];
450 uint16_t bytes_to_process
= PIOS_COM_ReceiveBuffer(inputPort
, serial_data
, sizeof(serial_data
), MAX_PORT_DELAY
);
451 if (bytes_to_process
> 0) {
452 ProcessTelemetryStream(data
->telemUAVTalkCon
, data
->radioUAVTalkCon
, serial_data
, bytes_to_process
);
461 * @brief Reads the PPM input device and sends out OPLinkReceiver objects.
463 * @param[in] parameters The task parameters (unused)
465 static void PPMInputTask(__attribute__((unused
)) void *parameters
)
467 xSemaphoreHandle sem
= PIOS_RCVR_GetSemaphore(PIOS_PPM_RECEIVER
, 1);
468 int16_t channels
[RFM22B_PPM_NUM_CHANNELS
];
471 #ifdef PIOS_INCLUDE_WDG
472 PIOS_WDG_UpdateFlag(PIOS_WDG_PPMINPUT
);
475 // Wait for the receiver semaphore.
476 if (xSemaphoreTake(sem
, PPM_INPUT_TIMEOUT
) == pdTRUE
) {
477 // Read the receiver inputs.
478 for (uint8_t i
= 0; i
< RFM22B_PPM_NUM_CHANNELS
; ++i
) {
479 channels
[i
] = PIOS_RCVR_Read(PIOS_PPM_RECEIVER
, i
+ 1);
483 for (uint8_t i
= 0; i
< RFM22B_PPM_NUM_CHANNELS
; ++i
) {
484 channels
[i
] = PIOS_RCVR_INVALID
;
488 // Pass the channel values to the radio device.
489 PIOS_RFM22B_PPMSet(pios_rfm22b_id
, channels
, RFM22B_PPM_NUM_CHANNELS
);
494 * @brief Receive raw serial data from the USB/COM port.
496 * @param[in] parameters The task parameters
498 static void serialRxTask(__attribute__((unused
)) void *parameters
)
502 uint32_t inputPort
= PIOS_COM_TELEMETRY
;
503 #ifdef PIOS_INCLUDE_WDG
504 PIOS_WDG_UpdateFlag(PIOS_WDG_SERIALRX
);
506 if (inputPort
&& PIOS_COM_RADIO
) {
507 // Receive some data.
508 uint16_t bytes_to_process
= PIOS_COM_ReceiveBuffer(inputPort
, data
->serialRxBuf
, sizeof(data
->serialRxBuf
), MAX_PORT_DELAY
);
510 if (bytes_to_process
> 0) {
511 // Send the data over the radio link.
512 // Following call can fail with -2 error code (buffer full) or -3 error code (could not acquire send mutex)
513 // It is the caller responsibility to retry in such cases...
516 while (count
-- > 0 && ret
< -1) {
517 ret
= PIOS_COM_SendBufferNonBlocking(PIOS_COM_RADIO
, data
->serialRxBuf
, bytes_to_process
);
527 * @brief Transmit data buffer to the com port.
529 * @param[in] buf Data buffer to send
530 * @param[in] length Length of buffer
531 * @return -1 on failure
532 * @return number of bytes transmitted on success
534 static int32_t UAVTalkSendHandler(uint8_t *buf
, int32_t length
)
537 uint32_t outputPort
= data
->parseUAVTalk
? PIOS_COM_TELEMETRY
: 0;
539 #if defined(PIOS_INCLUDE_USB)
540 // Determine output port (USB takes priority over telemetry port)
541 if (PIOS_COM_TELEM_USB_HID
&& PIOS_COM_Available(PIOS_COM_TELEM_USB_HID
)) {
542 outputPort
= PIOS_COM_TELEM_USB_HID
;
544 #endif /* PIOS_INCLUDE_USB */
546 // Following call can fail with -2 error code (buffer full) or -3 error code (could not acquire send mutex)
547 // It is the caller responsibility to retry in such cases...
550 while (count
-- > 0 && ret
< -1) {
551 ret
= PIOS_COM_SendBufferNonBlocking(outputPort
, buf
, length
);
560 * Transmit data buffer to the com port.
562 * @param[in] buf Data buffer to send
563 * @param[in] length Length of buffer
564 * @return -1 on failure
565 * @return number of bytes transmitted on success
567 static int32_t RadioSendHandler(uint8_t *buf
, int32_t length
)
569 if (!data
->parseUAVTalk
) {
572 uint32_t outputPort
= PIOS_COM_RADIO
;
574 // Don't send any data unless the radio port is available.
575 if (outputPort
&& PIOS_COM_Available(outputPort
)) {
576 // Following call can fail with -2 error code (buffer full) or -3 error code (could not acquire send mutex)
577 // It is the caller responsibility to retry in such cases...
580 while (count
-- > 0 && ret
< -1) {
581 ret
= PIOS_COM_SendBufferNonBlocking(outputPort
, buf
, length
);
590 * @brief Process a byte of data received on the telemetry stream
592 * @param[in] inConnectionHandle The UAVTalk connection handle on the telemetry port
593 * @param[in] outConnectionHandle The UAVTalk connection handle on the radio port.
594 * @param[in] rxbyte The received byte.
596 static void ProcessTelemetryStream(UAVTalkConnection inConnectionHandle
, UAVTalkConnection outConnectionHandle
, uint8_t *rxbuffer
, uint8_t length
)
598 uint8_t position
= 0;
600 // Keep reading until we receive a completed packet.
601 while (position
< length
) {
602 UAVTalkRxState state
= UAVTalkProcessInputStreamQuiet(inConnectionHandle
, rxbuffer
, length
, &position
);
603 if (state
== UAVTALK_STATE_COMPLETE
) {
604 // We only want to unpack certain telemetry objects
605 uint32_t objId
= UAVTalkGetPacketObjId(inConnectionHandle
);
607 case OPLINKSTATUS_OBJID
:
608 case OPLINKSETTINGS_OBJID
:
609 case OPLINKRECEIVER_OBJID
:
610 case MetaObjectId(OPLINKSTATUS_OBJID
):
611 case MetaObjectId(OPLINKSETTINGS_OBJID
):
612 case MetaObjectId(OPLINKRECEIVER_OBJID
):
613 UAVTalkReceiveObject(inConnectionHandle
);
615 case OBJECTPERSISTENCE_OBJID
:
616 case MetaObjectId(OBJECTPERSISTENCE_OBJID
):
617 // receive object locally
618 // some objects will send back a response to telemetry
620 // OPLM will ack or nack all objects requests and acked object sends
621 // Receiver will probably also ack / nack the same messages
622 // This has some consequences like :
623 // Second ack/nack will not match an open transaction or will apply to wrong transaction
624 // Question : how does GCS handle receiving the same object twice
625 // The OBJECTPERSISTENCE logic can be broken too if for example OPLM nacks and then REVO acks...
626 UAVTalkReceiveObject(inConnectionHandle
);
627 // relay packet to remote modem
628 UAVTalkRelayPacket(inConnectionHandle
, outConnectionHandle
);
631 // all other packets are relayed to the remote modem
632 UAVTalkRelayPacket(inConnectionHandle
, outConnectionHandle
);
640 * @brief Process a byte of data received on the radio data stream.
642 * @param[in] inConnectionHandle The UAVTalk connection handle on the radio port.
643 * @param[in] outConnectionHandle The UAVTalk connection handle on the telemetry port.
644 * @param[in] rxbuffer The received buffer.
645 * @param[in] length buffer length
647 static void ProcessRadioStream(UAVTalkConnection inConnectionHandle
, UAVTalkConnection outConnectionHandle
, uint8_t *rxbuffer
, uint8_t length
)
649 uint8_t position
= 0;
651 // Keep reading until we receive a completed packet.
652 while (position
< length
) {
653 UAVTalkRxState state
= UAVTalkProcessInputStreamQuiet(inConnectionHandle
, rxbuffer
, length
, &position
);
654 if (state
== UAVTALK_STATE_COMPLETE
) {
655 // We only want to unpack certain objects from the remote modem
656 // Similarly we only want to relay certain objects to the telemetry port
657 uint32_t objId
= UAVTalkGetPacketObjId(inConnectionHandle
);
659 case OPLINKSTATUS_OBJID
:
660 case OPLINKSETTINGS_OBJID
:
661 case MetaObjectId(OPLINKSTATUS_OBJID
):
662 case MetaObjectId(OPLINKSETTINGS_OBJID
):
664 // These objects are shadowed by the modem and are not transmitted to the telemetry port
665 // - OPLINKSTATUS_OBJID : ground station will receive the OPLM link status instead
666 // - OPLINKSETTINGS_OBJID : ground station will read and write the OPLM settings instead
668 case OPLINKRECEIVER_OBJID
:
669 case MetaObjectId(OPLINKRECEIVER_OBJID
):
670 // Receive object locally
671 // These objects are received by the modem and are not transmitted to the telemetry port
672 // - OPLINKRECEIVER_OBJID : not sure why
673 // some objects will send back a response to the remote modem
674 UAVTalkReceiveObject(inConnectionHandle
);
677 // all other packets are relayed to the telemetry port
678 UAVTalkRelayPacket(inConnectionHandle
, outConnectionHandle
);
686 * @brief Callback that is called when the ObjectPersistence UAVObject is changed.
687 * @param[in] objEv The event that precipitated the callback.
689 static void objectPersistenceUpdatedCb(__attribute__((unused
)) UAVObjEvent
*objEv
)
691 // Get the ObjectPersistence object.
692 ObjectPersistenceData obj_per
;
694 ObjectPersistenceGet(&obj_per
);
696 // Is this concerning our setting object?
697 if (obj_per
.ObjectID
== OPLINKSETTINGS_OBJID
) {
698 // Is this a save, load, or delete?
699 bool success
= false;
700 switch (obj_per
.Operation
) {
701 case OBJECTPERSISTENCE_OPERATION_LOAD
:
703 #if defined(PIOS_INCLUDE_FLASH_LOGFS_SETTINGS)
704 // Load the settings.
705 void *obj
= UAVObjGetByID(obj_per
.ObjectID
);
709 // Load selected instance
710 success
= (UAVObjLoad(obj
, obj_per
.InstanceID
) == 0);
715 case OBJECTPERSISTENCE_OPERATION_SAVE
:
717 #if defined(PIOS_INCLUDE_FLASH_LOGFS_SETTINGS)
718 void *obj
= UAVObjGetByID(obj_per
.ObjectID
);
722 // Save selected instance
723 success
= UAVObjSave(obj
, obj_per
.InstanceID
) == 0;
728 case OBJECTPERSISTENCE_OPERATION_DELETE
:
730 #if defined(PIOS_INCLUDE_FLASH_LOGFS_SETTINGS)
731 void *obj
= UAVObjGetByID(obj_per
.ObjectID
);
735 // Save selected instance
736 success
= UAVObjDelete(obj
, obj_per
.InstanceID
) == 0;
744 if (success
== true) {
745 obj_per
.Operation
= OBJECTPERSISTENCE_OPERATION_COMPLETED
;
746 ObjectPersistenceSet(&obj_per
);