dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
tbs_smartaudio.c
Go to the documentation of this file.
1 
15 /*
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.
20  *
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
24  * for more details.
25  *
26  * You should have received a copy of the GNU General Public License along
27  * with this program; if not, see <http://www.gnu.org/licenses/>
28  *
29  * Additional note on redistribution: The copyright and license notices above
30  * must be maintained in each individual source file that is a derivative work
31  * of this source file; otherwise redistribution is prohibited.
32  */
33 
34 #include "openpilot.h"
35 
36 #include "pios_thread.h"
37 #include "pios_crc.h"
38 
39 #include "vtxinfo.h"
40 
41 #define NUM_TBS_CH 40
42 
43 const uint16_t TBS_CH[NUM_TBS_CH] = {
44  5865, 5845, 5825, 5805, 5785, 5765, 5745, 5725, // band A
45  5733, 5752, 5771, 5790, 5809, 5828, 5847, 5866, // band B
46  5705, 5685, 5665, 5645, 5885, 5905, 5925, 5945, // band E
47  5740, 5760, 5780, 5800, 5820, 5840, 5860, 5880, // Airwave
48  5658, 5695, 5732, 5769, 5806, 5843, 5880, 5917 // Raceband
49 };
50 
55 };
56 
57 
58 typedef struct {
59  uint8_t command;
60  uint8_t length;
61  uint8_t channel;
62  uint8_t pwr_level;
63  uint8_t operation_mode;
64  uint8_t freq0;
65  uint8_t freq1;
66  uint8_t crc;
67 } __attribute__((packed)) GET_INFO;
68 
69 typedef struct {
70  uint8_t command;
71  uint8_t length;
72  uint8_t channel;
73  uint8_t dummy;
74  uint8_t crc;
75 } __attribute__((packed)) SET_CHANNEL;
76 
77 
78 typedef struct {
79  uint8_t command;
80  uint8_t length;
81  uint8_t pwr;
82  uint8_t dummy;
83  uint8_t crc;
84 } __attribute__((packed)) SET_POWER;
85 
86 typedef struct {
87  uint8_t command;
88  uint8_t length;
89  uint8_t mode;
90  uint8_t crc;
91 } __attribute__((packed)) SET_MODE;
92 
93 
95 
96 
97 static int32_t tbsvtx_tx_msg(uintptr_t usart_id, uint8_t *buff, uint8_t n_bytes)
98 {
99  // The CRC is the second last byte, the first byte is dummy
100  buff[n_bytes - 2] = PIOS_CRC_updateCRC_TBS(0, &buff[1], n_bytes - 3);
101 
102  if (PIOS_COM_SendBuffer(usart_id, buff, n_bytes) < 0) {
103  return -1;
104  }
105  // this is single wire, so flush the same number of bytes out of the rx buffer
106  uint8_t c;
107  for (int i=0; i<n_bytes; i++) {
108  PIOS_COM_ReceiveBuffer(usart_id, &c, 1, 2);
109  }
110  return 0;
111 }
112 
113 int32_t tbsvtx_rx_msg(uintptr_t usart_id, uint8_t n_bytes, uint8_t *buff, uint16_t timeout)
114 {
115  uint32_t start = PIOS_Thread_Systime();
116  uint8_t c = 0;
117  uint8_t c_prev;
118  uint8_t bytes_rx = 2;
119  bool rx_ok = false;
120 
121  // Due to the non-standard signal levels (0.9V when idle) the first two bytes are often garbled,
122  // so we match directly for the length field.
123  while (PIOS_Thread_Systime() - start < timeout) {
124  c_prev = c;
125  if (PIOS_COM_ReceiveBuffer(usart_id, &c, 1, 4) > 0) {
126  if (c == n_bytes - 2) {
127  rx_ok = true;
128  break;
129  }
130  }
131  }
132  if (!rx_ok) {
133  return -1;
134  }
135  buff[0] = c_prev;
136  buff[1] = c;
137 
138  while(bytes_rx < n_bytes) {
139  if (PIOS_COM_ReceiveBuffer(usart_id, &c, 1, 4) > 0) {
140  buff[bytes_rx++] = c;
141  }
142  if (PIOS_Thread_Systime() - start > timeout) {
143  return - 1;
144  }
145  }
146 
147  // check CRC
148  uint8_t crc = PIOS_CRC_updateCRC_TBS(0, buff, n_bytes - 1);
149 
150  if (crc != buff[n_bytes - 1]) {
151  return - 2;
152  }
153 
154  return 0;
155 }
156 
157 
158 int32_t tbsvtx_get_state(uintptr_t usart_id, VTXInfoData *info)
159 {
160  // Send dummy 00 byte before, so line goes high
161  uint8_t msg[7] = {0x00, 0xAA, 0x55, 0x03, 0x00, 0x00, 0x00};
162  //msg[5] = PIOS_CRC_updateCRC_TBS(0, &msg[1], 4);
163  tbsvtx_tx_msg(usart_id, msg, 7);
164  //uint8_t msg[5] = {0x00, 0xAA, 0x55, 0x03, 0x00};
165  //PIOS_COM_SendBuffer(usart_id, msg, 5);
166 
167  GET_INFO info_msg;
168  if (tbsvtx_rx_msg(usart_id, sizeof(info_msg), (uint8_t*)&info_msg, 200) < 0) {
169  return -1;
170  }
171 
172  // Do some additional sanity checks
173  if (((info_msg.command & 0x07) != 0x01) || (info_msg.channel >= NUM_TBS_CH)) {
174  return -2;
175  }
176 
177  switch ((info_msg.command >> 3) & 0x1F) {
178  case 0x00:
179  info->Model = VTXINFO_MODEL_TBSUNIFYPRO5G8;
181  break;
182  case 0x01:
183  info->Model = VTXINFO_MODEL_TBSUNIFYPRO5G8HV;
185  break;
186  default:
187  info->Model = VTXINFO_MODEL_NONE;
189  return -3;
190  }
191 
192  info->Frequency = TBS_CH[info_msg.channel];
193 
194  switch (vtx_protocol) {
195  case TBS_SMARTAUDIO_1:
196  switch(info_msg.pwr_level) {
197  case 0x07:
198  info->Power = 25;
199  break;
200  case 0x10:
201  info->Power = 200;
202  break;
203  case 0x19:
204  info->Power = 500;
205  break;
206  case 0x28:
207  info->Power = 800;
208  break;
209  default:
210  info->Power = 25;
211  }
212  break;
213  case TBS_SMARTAUDIO_2:
214  if (info_msg.operation_mode & 0x02) {
215  // Pit mode active, report 0mW
216  info->Power = 0;
217  }
218  else {
219  switch(info_msg.pwr_level) {
220  case 0x00:
221  info->Power = 25;
222  break;
223  case 0x01:
224  info->Power = 200;
225  break;
226  case 0x02:
227  info->Power = 500;
228  break;
229  case 0x03:
230  info->Power = 800;
231  break;
232  default:
233  info->Power = 25;
234  }
235  }
236  break;
237  case UNKNOWN:
238  info->Power = 0;
239  }
240 
241  return 0;
242 }
243 
244 int32_t tbsvtx_set_freq(uintptr_t usart_id, uint16_t frequency)
245 {
246  // find the channel
247  uint8_t channel = 255;
248  for (int i=0; i<NUM_TBS_CH; i++) {
249  if (TBS_CH[i] == frequency) {
250  channel = i;
251  break;
252  }
253  }
254  if (channel == 255) {
255  // invalid frequency
256  return -1;
257  }
258 
259  uint8_t set_ch_msg[8] = {0x00, 0xAA, 0x55, 0x07, 0x01, 0x00, 0x00, 0x00};
260  set_ch_msg[5] = channel;
261  tbsvtx_tx_msg(usart_id, set_ch_msg, 8);
262 
263  SET_CHANNEL set_ch_resp;
264  if (tbsvtx_rx_msg(usart_id, sizeof(set_ch_resp), (uint8_t*)&set_ch_resp, 200) < 0) {
265  return -2;
266  }
267 
268  // Do some sanity checks
269  if ((set_ch_resp.command != 0x03) || (set_ch_resp.channel != channel)) {
270  return -3;
271  }
272 
273  return 0;
274 }
275 
276 static int32_t tbsvtx_set_mode(uintptr_t usart_id, uint8_t mode)
277 {
278  uint8_t mode_msg[8] = {0x00, 0xAA, 0x55, 0x0B, 0x01, 0x00, 0x00, 0x00};
279  mode_msg[5] = mode;
280  tbsvtx_tx_msg(usart_id, mode_msg, 8);
281 
282  SET_MODE set_mode_resp;
283  if (tbsvtx_rx_msg(usart_id, sizeof(set_mode_resp), (uint8_t*)&set_mode_resp, 200) < 0) {
284  return -1;
285  }
286 
287  // Do some sanity checks
288  if ((set_mode_resp.command != 0x05) || (set_mode_resp.mode != mode)) {
289  return -2;
290  }
291 
292  return 0;
293 }
294 
295 int32_t tbsvtx_set_power(uintptr_t usart_id, uint16_t power)
296 {
297  // Make sure the VTX is unlocked
298  if ((vtx_protocol == TBS_SMARTAUDIO_2) && (power > 25)){
299  tbsvtx_set_mode(usart_id, 0x10);
300  PIOS_Thread_Sleep(200);
301  }
302 
303  uint8_t power_byte;
304  switch (vtx_protocol) {
305  case TBS_SMARTAUDIO_1:
306  switch (power) {
307  case 25:
308  power_byte = 0x07;
309  break;
310  case 200:
311  power_byte = 0x10;
312  break;
313  case 500:
314  power_byte = 0x19;
315  break;
316  case 800:
317  power_byte = 0x28;
318  break;
319  default:
320  return -2;
321  }
322  break;
323  case TBS_SMARTAUDIO_2:
324  switch (power) {
325  case 25:
326  power_byte = 0x00;
327  break;
328  case 200:
329  power_byte = 0x01;
330  break;
331  case 500:
332  power_byte = 0x02;
333  break;
334  case 800:
335  power_byte = 0x03;
336  break;
337  default:
338  return -2;
339  }
340  break;
341  default:
342  return -4;
343  }
344 
345  uint8_t set_pwr_msg[8] = {0x00, 0xAA, 0x55, 0x05, 0x01, 0x00, 0x00, 0x00};
346  set_pwr_msg[5] = power_byte;
347  tbsvtx_tx_msg(usart_id, set_pwr_msg, 8);
348 
349  SET_POWER set_pwr_resp;
350  if (tbsvtx_rx_msg(usart_id, sizeof(set_pwr_resp), (uint8_t*)&set_pwr_resp, 200) < 0) {
351  return -5;
352  }
353 
354  // Do some sanity checks
355  if ((set_pwr_resp.command != 0x02) || (set_pwr_resp.pwr != power_byte)) {
356  return -6;
357  }
358 
359  return 0;
360 }
CRC functions header.
union @12 crc
Definition: common.h:35
uint32_t PIOS_Thread_Systime(void)
Definition: pios_thread.c:212
uint8_t pwr_level
#define NUM_TBS_CH
uint8_t operation_mode
static enum TBS_VTX_PROTOCOL vtx_protocol
const uint16_t TBS_CH[NUM_TBS_CH]
int32_t tbsvtx_set_freq(uintptr_t usart_id, uint16_t frequency)
uint8_t length
uint16_t PIOS_COM_ReceiveBuffer(uintptr_t com_id, uint8_t *buf, uint16_t buf_len, uint32_t timeout_ms)
int32_t tbsvtx_rx_msg(uintptr_t usart_id, uint8_t n_bytes, uint8_t *buff, uint16_t timeout)
int32_t tbsvtx_set_power(uintptr_t usart_id, uint16_t power)
uint8_t PIOS_CRC_updateCRC_TBS(uint8_t crc, const uint8_t *data, int32_t length)
Definition: pios_crc.c:185
uint8_t i
Definition: msp_messages.h:97
enum channel_mode mode
Definition: pios_servo.c:58
static int32_t tbsvtx_set_mode(uintptr_t usart_id, uint8_t mode)
static int32_t tbsvtx_tx_msg(uintptr_t usart_id, uint8_t *buff, uint8_t n_bytes)
void PIOS_Thread_Sleep(uint32_t time_ms)
Definition: pios_thread.c:229
PIOS_COM_SendBuffer(shub_global->frsky_port, shub_global->serial_buf, msg_length)
Includes PiOS and core architecture components.
TBS_VTX_PROTOCOL
int32_t tbsvtx_get_state(uintptr_t usart_id, VTXInfoData *info)
typedef __attribute__
Definition: serial_4way.h:43