2 ******************************************************************************
3 * @addtogroup PIOS PIOS Core hardware abstraction layer
5 * @addtogroup PIOS_OPLinkRCVR OPLink Receiver Input Functions
6 * @brief Code to read the channels within the OPLinkReceiver UAVObject
9 * @file pios_opinkrcvr.c
10 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2013.
11 * @brief GCS Input functions (STM32 dependent)
12 * @see The GNU Public License (GPL) Version 3
14 *****************************************************************************/
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 3 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful, but
22 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26 * You should have received a copy of the GNU General Public License along
27 * with this program; if not, write to the Free Software Foundation, Inc.,
28 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 #ifdef PIOS_INCLUDE_OPLINKRCVR
35 #include <uavobjectmanager.h>
36 #include <oplinkreceiver.h>
37 #include <oplinkstatus.h>
38 #include <pios_oplinkrcvr_priv.h>
40 static OPLinkReceiverData oplinkreceiverdata
;
42 /* Provide a RCVR driver */
43 static int32_t PIOS_OPLinkRCVR_Get(uint32_t rcvr_id
, uint8_t channel
);
44 static void PIOS_oplinkrcvr_Supervisor(uint32_t ppm_id
);
45 static uint8_t PIOS_OPLinkRCVR_Quality_Get(uint32_t oplinkrcvr_id
);
47 const struct pios_rcvr_driver pios_oplinkrcvr_rcvr_driver
= {
48 .read
= PIOS_OPLinkRCVR_Get
,
49 .get_quality
= PIOS_OPLinkRCVR_Quality_Get
53 enum pios_oplinkrcvr_dev_magic
{
54 PIOS_OPLINKRCVR_DEV_MAGIC
= 0x07ab9e2544cf5029,
57 struct pios_oplinkrcvr_dev
{
58 enum pios_oplinkrcvr_dev_magic magic
;
64 static struct pios_oplinkrcvr_dev
*global_oplinkrcvr_dev
;
66 static bool PIOS_oplinkrcvr_validate(struct pios_oplinkrcvr_dev
*oplinkrcvr_dev
)
68 return oplinkrcvr_dev
->magic
== PIOS_OPLINKRCVR_DEV_MAGIC
;
71 #if defined(PIOS_INCLUDE_FREERTOS)
72 static struct pios_oplinkrcvr_dev
*PIOS_oplinkrcvr_alloc(void)
74 struct pios_oplinkrcvr_dev
*oplinkrcvr_dev
;
76 oplinkrcvr_dev
= (struct pios_oplinkrcvr_dev
*)pios_malloc(sizeof(*oplinkrcvr_dev
));
77 if (!oplinkrcvr_dev
) {
81 oplinkrcvr_dev
->magic
= PIOS_OPLINKRCVR_DEV_MAGIC
;
82 oplinkrcvr_dev
->Fresh
= false;
83 oplinkrcvr_dev
->supv_timer
= 0;
85 /* The update callback cannot receive the device pointer, so set it in a global */
86 global_oplinkrcvr_dev
= oplinkrcvr_dev
;
88 return oplinkrcvr_dev
;
91 static struct pios_oplinkrcvr_dev pios_oplinkrcvr_devs
[PIOS_OPLINKRCVR_MAX_DEVS
];
92 static uint8_t pios_oplinkrcvr_num_devs
;
93 static struct pios_oplinkrcvr_dev
*PIOS_oplinkrcvr_alloc(void)
95 struct pios_oplinkrcvr_dev
*oplinkrcvr_dev
;
97 if (pios_oplinkrcvr_num_devs
>= PIOS_OPLINKRCVR_MAX_DEVS
) {
101 oplinkrcvr_dev
= &pios_oplinkrcvr_devs
[pios_oplinkrcvr_num_devs
++];
102 oplinkrcvr_dev
->magic
= PIOS_OPLINKRCVR_DEV_MAGIC
;
103 oplinkrcvr_dev
->Fresh
= false;
104 oplinkrcvr_dev
->supv_timer
= 0;
106 global_oplinkrcvr_dev
= oplinkrcvr_dev
;
108 return oplinkrcvr_dev
;
110 #endif /* if defined(PIOS_INCLUDE_FREERTOS) */
112 static void oplinkreceiver_updated(UAVObjEvent
*ev
)
114 struct pios_oplinkrcvr_dev
*oplinkrcvr_dev
= global_oplinkrcvr_dev
;
116 if (ev
->obj
== OPLinkReceiverHandle()) {
117 OPLinkReceiverGet(&oplinkreceiverdata
);
118 oplinkrcvr_dev
->Fresh
= true;
122 extern int32_t PIOS_OPLinkRCVR_Init(__attribute__((unused
)) uint32_t *oplinkrcvr_id
)
124 struct pios_oplinkrcvr_dev
*oplinkrcvr_dev
;
126 /* Allocate the device structure */
127 oplinkrcvr_dev
= (struct pios_oplinkrcvr_dev
*)PIOS_oplinkrcvr_alloc();
128 if (!oplinkrcvr_dev
) {
132 for (uint8_t i
= 0; i
< OPLINKRECEIVER_CHANNEL_NUMELEM
; i
++) {
134 oplinkreceiverdata
.Channel
[i
] = PIOS_RCVR_TIMEOUT
;
137 /* Register uavobj callback */
138 OPLinkReceiverConnectCallback(oplinkreceiver_updated
);
140 /* Register the failsafe timer callback. */
141 if (!PIOS_RTC_RegisterTickCallback(PIOS_oplinkrcvr_Supervisor
, (uint32_t)oplinkrcvr_dev
)) {
142 PIOS_DEBUG_Assert(0);
149 * Get the value of an input channel
150 * \param[in] channel Number of the channel desired (zero based)
151 * \output PIOS_RCVR_INVALID channel not available
152 * \output PIOS_RCVR_TIMEOUT failsafe condition or missing receiver
153 * \output >=0 channel value
155 static int32_t PIOS_OPLinkRCVR_Get(__attribute__((unused
)) uint32_t rcvr_id
, uint8_t channel
)
157 if (channel
>= OPLINKRECEIVER_CHANNEL_NUMELEM
) {
158 /* channel is out of range */
159 return PIOS_RCVR_INVALID
;
162 return oplinkreceiverdata
.Channel
[channel
];
165 static void PIOS_oplinkrcvr_Supervisor(uint32_t oplinkrcvr_id
)
167 /* Recover our device context */
168 struct pios_oplinkrcvr_dev
*oplinkrcvr_dev
= (struct pios_oplinkrcvr_dev
*)oplinkrcvr_id
;
170 if (!PIOS_oplinkrcvr_validate(oplinkrcvr_dev
)) {
171 /* Invalid device specified */
178 if (++(oplinkrcvr_dev
->supv_timer
) < (PIOS_OPLINK_RCVR_TIMEOUT_MS
* 1000 / 625)) {
181 oplinkrcvr_dev
->supv_timer
= 0;
183 if (!oplinkrcvr_dev
->Fresh
) {
184 for (int32_t i
= 0; i
< OPLINKRECEIVER_CHANNEL_NUMELEM
; i
++) {
185 oplinkreceiverdata
.Channel
[i
] = PIOS_RCVR_TIMEOUT
;
189 oplinkrcvr_dev
->Fresh
= false;
192 static uint8_t PIOS_OPLinkRCVR_Quality_Get(__attribute__((unused
)) uint32_t oplinkrcvr_id
)
194 uint8_t oplink_quality
;
196 OPLinkStatusLinkQualityGet(&oplink_quality
);
198 /* link_status is in the range 0-128, so scale to a % */
199 return oplink_quality
* 100 / 128;
202 #endif /* PIOS_INCLUDE_OPLINKRCVR */