Cosmetics
[opentx.git] / radio / src / pulses / pxx2.cpp
blob323dc3c1689751d5ebfe9c6230cb916519f0eb21
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 #include "opentx.h"
22 #include "pulses/pxx2.h"
23 #include "io/frsky_firmware_update.h"
25 uint8_t Pxx2Pulses::addFlag0(uint8_t module)
27 uint8_t flag0 = g_model.header.modelId[module] & 0x3F;
28 if (g_model.moduleData[module].failsafeMode != FAILSAFE_NOT_SET && g_model.moduleData[module].failsafeMode != FAILSAFE_RECEIVER) {
29 if (moduleState[module].counter == 0) {
30 flag0 |= PXX2_CHANNELS_FLAG0_FAILSAFE;
33 if (moduleState[module].mode == MODULE_MODE_RANGECHECK) {
34 flag0 |= PXX2_CHANNELS_FLAG0_RANGECHECK;
36 Pxx2Transport::addByte(flag0);
37 return flag0;
40 void Pxx2Pulses::addFlag1(uint8_t module)
42 uint8_t subType;
43 if (isModuleXJT(module)) {
44 static const uint8_t PXX2_XJT_MODULE_SUBTYPES[] = {0x01, 0x03, 0x02};
45 subType = PXX2_XJT_MODULE_SUBTYPES[min<uint8_t>(g_model.moduleData[module].subType, 2)];
47 else {
48 subType = g_model.moduleData[module].subType;
50 Pxx2Transport::addByte(subType << 4);
53 void Pxx2Pulses::addPulsesValues(uint16_t low, uint16_t high)
55 Pxx2Transport::addByte(low); // Low byte of channel
56 Pxx2Transport::addByte(((low >> 8) & 0x0F) | (high << 4)); // 4 bits each from 2 channels
57 Pxx2Transport::addByte(high >> 4); // High byte of channel
60 void Pxx2Pulses::addChannels(uint8_t module)
62 uint16_t pulseValue = 0;
63 uint16_t pulseValueLow = 0;
65 uint8_t channel = g_model.moduleData[module].channelsStart;
66 uint8_t count = sentModuleChannels(module);
68 for (int8_t i = 0; i < count; i++, channel++) {
69 int value = channelOutputs[channel] + 2*PPM_CH_CENTER(channel) - 2*PPM_CENTER;
70 pulseValue = limit(1, (value * 512 / 682) + 1024, 2046);
71 #if defined(DEBUG_LATENCY_RF_ONLY)
72 if (latencyToggleSwitch)
73 pulseValue = 1;
74 else
75 pulseValue = 2046;
76 #endif
77 if (i & 1)
78 addPulsesValues(pulseValueLow, pulseValue);
79 else
80 pulseValueLow = pulseValue;
84 void Pxx2Pulses::addFailsafe(uint8_t module)
86 uint16_t pulseValue = 0;
87 uint16_t pulseValueLow = 0;
89 uint8_t channel = g_model.moduleData[module].channelsStart;
90 uint8_t count = sentModuleChannels(module);
92 for (int8_t i = 0; i < count; i++, channel++) {
93 if (g_model.moduleData[module].failsafeMode == FAILSAFE_HOLD) {
94 pulseValue = 2047;
96 else if (g_model.moduleData[module].failsafeMode == FAILSAFE_NOPULSES) {
97 pulseValue = 0;
99 else {
100 int16_t failsafeValue = g_model.failsafeChannels[channel];
101 if (failsafeValue == FAILSAFE_CHANNEL_HOLD) {
102 pulseValue = 2047;
104 else if (failsafeValue == FAILSAFE_CHANNEL_NOPULSE) {
105 pulseValue = 0;
107 else {
108 failsafeValue += 2*PPM_CH_CENTER(channel) - 2*PPM_CENTER;
109 pulseValue = limit(1, (failsafeValue * 512 / 682) + 1024, 2046);
112 if (i & 1)
113 addPulsesValues(pulseValueLow, pulseValue);
114 else
115 pulseValueLow = pulseValue;
119 void Pxx2Pulses::setupChannelsFrame(uint8_t module)
121 addFrameType(PXX2_TYPE_C_MODULE, PXX2_TYPE_ID_CHANNELS);
123 // Flag0
124 uint8_t flag0 = addFlag0(module);
126 // Flag1
127 addFlag1(module);
129 // Failsafe / Channels
130 if (flag0 & PXX2_CHANNELS_FLAG0_FAILSAFE)
131 addFailsafe(module);
132 else
133 addChannels(module);
136 void Pxx2Pulses::setupTelemetryFrame(uint8_t module)
138 addFrameType(PXX2_TYPE_C_MODULE, PXX2_TYPE_ID_TELEMETRY);
139 Pxx2Transport::addByte(outputTelemetryBuffer.destination & 0x03);
140 for (uint8_t i = 0; i < sizeof(SportTelemetryPacket); i++) {
141 Pxx2Transport::addByte(outputTelemetryBuffer.data[i]);
145 void Pxx2Pulses::setupHardwareInfoFrame(uint8_t module)
147 ModuleInformation * destination = moduleState[module].moduleInformation;
149 if (destination->timeout == 0) {
150 if (destination->current <= destination->maximum) {
151 addFrameType(PXX2_TYPE_C_MODULE, PXX2_TYPE_ID_HW_INFO);
152 Pxx2Transport::addByte(destination->current);
153 destination->timeout = 60; /* 300ms */
154 destination->current++;
156 else {
157 moduleState[module].mode = MODULE_MODE_NORMAL;
158 setupChannelsFrame(module);
161 else {
162 destination->timeout--;
163 setupChannelsFrame(module);
167 void Pxx2Pulses::setupRegisterFrame(uint8_t module)
169 addFrameType(PXX2_TYPE_C_MODULE, PXX2_TYPE_ID_REGISTER);
171 if (reusableBuffer.moduleSetup.pxx2.registerStep == REGISTER_RX_NAME_SELECTED) {
172 Pxx2Transport::addByte(0x01);
173 for (uint8_t i=0; i<PXX2_LEN_RX_NAME; i++) {
174 Pxx2Transport::addByte(zchar2char(reusableBuffer.moduleSetup.pxx2.registerRxName[i]));
176 for (uint8_t i=0; i<PXX2_LEN_REGISTRATION_ID; i++) {
177 Pxx2Transport::addByte(zchar2char(g_model.modelRegistrationID[i]));
179 Pxx2Transport::addByte(reusableBuffer.moduleSetup.pxx2.registerLoopIndex);
181 else {
182 Pxx2Transport::addByte(0);
186 void Pxx2Pulses::setupModuleSettingsFrame(uint8_t module)
188 ModuleSettings * destination = moduleState[module].moduleSettings;
190 if (get_tmr10ms() > destination->timeout) {
191 addFrameType(PXX2_TYPE_C_MODULE, PXX2_TYPE_ID_TX_SETTINGS);
192 uint8_t flag0 = 0;
193 if (destination->state == PXX2_SETTINGS_WRITE)
194 flag0 |= PXX2_TX_SETTINGS_FLAG0_WRITE;
195 Pxx2Transport::addByte(flag0);
196 if (destination->state == PXX2_SETTINGS_WRITE) {
197 uint8_t flag1 = 0;
198 if (destination->externalAntenna)
199 flag1 |= PXX2_TX_SETTINGS_FLAG1_EXTERNAL_ANTENNA;
200 Pxx2Transport::addByte(flag1);
201 Pxx2Transport::addByte(destination->txPower);
203 destination->timeout = get_tmr10ms() + 200/*next try in 2s*/;
205 else {
206 setupChannelsFrame(module);
210 void Pxx2Pulses::setupReceiverSettingsFrame(uint8_t module)
212 if (get_tmr10ms() > reusableBuffer.hardwareAndSettings.receiverSettings.timeout) {
213 addFrameType(PXX2_TYPE_C_MODULE, PXX2_TYPE_ID_RX_SETTINGS);
214 uint8_t flag0 = reusableBuffer.hardwareAndSettings.receiverSettings.receiverId;
215 if (reusableBuffer.hardwareAndSettings.receiverSettings.state == PXX2_SETTINGS_WRITE)
216 flag0 |= PXX2_RX_SETTINGS_FLAG0_WRITE;
217 Pxx2Transport::addByte(flag0);
218 if (reusableBuffer.hardwareAndSettings.receiverSettings.state == PXX2_SETTINGS_WRITE) {
219 uint8_t flag1 = 0;
220 if (reusableBuffer.hardwareAndSettings.receiverSettings.telemetryDisabled)
221 flag1 |= PXX2_RX_SETTINGS_FLAG1_TELEMETRY_DISABLED;
222 if (reusableBuffer.hardwareAndSettings.receiverSettings.pwmRate)
223 flag1 |= PXX2_RX_SETTINGS_FLAG1_FASTPWM;
224 if (reusableBuffer.hardwareAndSettings.receiverSettings.fport)
225 flag1 |= PXX2_RX_SETTINGS_FLAG1_FPORT;
226 Pxx2Transport::addByte(flag1);
227 uint8_t outputsCount = min<uint8_t>(24, reusableBuffer.hardwareAndSettings.receiverSettings.outputsCount);
228 for (int i = 0; i < outputsCount; i++) {
229 Pxx2Transport::addByte(min<uint8_t>(23, reusableBuffer.hardwareAndSettings.receiverSettings.outputsMapping[i]));
232 reusableBuffer.hardwareAndSettings.receiverSettings.timeout = get_tmr10ms() + 200/*next try in 2s*/;
234 else {
235 setupChannelsFrame(module);
239 void Pxx2Pulses::setupAccstBindFrame(uint8_t module)
241 addFrameType(PXX2_TYPE_C_MODULE, PXX2_TYPE_ID_BIND);
242 Pxx2Transport::addByte(0x01); // DATA0
243 for (uint8_t i=0; i<PXX2_LEN_RX_NAME; i++) {
244 Pxx2Transport::addByte(0x00);
246 Pxx2Transport::addByte((g_model.moduleData[module].pxx.receiverHigherChannels << 7) + (g_model.moduleData[module].pxx.receiverTelemetryOff << 6));
247 Pxx2Transport::addByte(g_model.header.modelId[module]);
250 void Pxx2Pulses::setupAccessBindFrame(uint8_t module)
252 BindInformation * destination = moduleState[module].bindInformation;
254 if (destination->step == BIND_WAIT) {
255 if (get_tmr10ms() > destination->timeout) {
256 moduleState[module].mode = MODULE_MODE_NORMAL;
257 destination->step = BIND_OK;
258 POPUP_INFORMATION(STR_BIND_OK); // TODO rather use the new callback
260 return;
263 addFrameType(PXX2_TYPE_C_MODULE, PXX2_TYPE_ID_BIND);
265 if (destination->step == BIND_INFO_REQUEST) {
266 Pxx2Transport::addByte(0x02); // DATA0
267 for (uint8_t i=0; i<PXX2_LEN_RX_NAME; i++) {
268 Pxx2Transport::addByte(destination->candidateReceiversNames[destination->selectedReceiverIndex][i]);
271 else if (destination->step == BIND_START) {
272 Pxx2Transport::addByte(0x01); // DATA0
273 for (uint8_t i=0; i<PXX2_LEN_RX_NAME; i++) {
274 Pxx2Transport::addByte(destination->candidateReceiversNames[destination->selectedReceiverIndex][i]);
276 if (isModuleR9MAccess(module)) {
277 Pxx2Transport::addByte((destination->lbtMode << 6) + (destination->flexMode << 4) + destination->rxUid); // RX_UID is the slot index (which is unique and never moved)
279 else {
280 Pxx2Transport::addByte(destination->rxUid); // RX_UID is the slot index (which is unique and never moved)
282 Pxx2Transport::addByte(g_model.header.modelId[module]);
284 else {
285 Pxx2Transport::addByte(0x00); // DATA0
286 for (uint8_t i=0; i<PXX2_LEN_REGISTRATION_ID; i++) {
287 Pxx2Transport::addByte(zchar2char(g_model.modelRegistrationID[i]));
292 void Pxx2Pulses::setupResetFrame(uint8_t module)
294 addFrameType(PXX2_TYPE_C_MODULE, PXX2_TYPE_ID_RESET);
295 Pxx2Transport::addByte(reusableBuffer.moduleSetup.pxx2.resetReceiverIndex);
296 Pxx2Transport::addByte(reusableBuffer.moduleSetup.pxx2.resetReceiverFlags);
297 moduleState[module].mode = MODULE_MODE_NORMAL;
300 void Pxx2Pulses::setupSpectrumAnalyser(uint8_t module)
302 if (reusableBuffer.spectrumAnalyser.dirty) {
303 reusableBuffer.spectrumAnalyser.dirty = false;
304 #if defined(PCBHORUS)
305 memclear(&reusableBuffer.spectrumAnalyser.max, sizeof(reusableBuffer.spectrumAnalyser.max));
306 #endif
307 addFrameType(PXX2_TYPE_C_POWER_METER, PXX2_TYPE_ID_SPECTRUM);
308 Pxx2Transport::addByte(0x00);
309 Pxx2Transport::addWord(reusableBuffer.spectrumAnalyser.freq);
310 Pxx2Transport::addWord(reusableBuffer.spectrumAnalyser.span);
311 Pxx2Transport::addWord(reusableBuffer.spectrumAnalyser.step);
315 void Pxx2Pulses::setupPowerMeter(uint8_t module)
317 if (reusableBuffer.powerMeter.dirty) {
318 reusableBuffer.powerMeter.dirty = false;
319 addFrameType(PXX2_TYPE_C_POWER_METER, PXX2_TYPE_ID_POWER_METER);
320 Pxx2Transport::addByte(0x00);
321 Pxx2Transport::addWord(reusableBuffer.powerMeter.freq);
325 void Pxx2Pulses::setupShareMode(uint8_t module)
327 addFrameType(PXX2_TYPE_C_MODULE, PXX2_TYPE_ID_SHARE);
328 Pxx2Transport::addByte(reusableBuffer.moduleSetup.pxx2.shareReceiverIndex);
331 void Pxx2Pulses::sendOtaUpdate(uint8_t module, const char * rxName, uint32_t address, const char * data)
333 initFrame();
335 addFrameType(PXX2_TYPE_C_OTA, PXX2_TYPE_ID_OTA);
337 if (rxName) {
338 Pxx2Transport::addByte(0x00);
339 for (uint8_t i=0; i<PXX2_LEN_RX_NAME; i++) {
340 Pxx2Transport::addByte(rxName[i]);
343 else if (data) {
344 Pxx2Transport::addByte(0x01);
345 Pxx2Transport::addWord(address);
346 for (uint8_t i=0; i<32; i++) {
347 Pxx2Transport::addByte(data[i]);
350 else {
351 Pxx2Transport::addByte(0x02);
354 endFrame();
356 if (module == EXTERNAL_MODULE)
357 extmoduleSendNextFrame();
360 void Pxx2Pulses::setupAuthenticationFrame(uint8_t module, uint8_t mode, const uint8_t * outputMessage)
362 initFrame();
364 addFrameType(PXX2_TYPE_C_MODULE, PXX2_TYPE_ID_AUTHENTICATION);
366 Pxx2Transport::addByte(mode);
367 if (outputMessage) {
368 for (uint8_t i = 0; i < 16; i++) {
369 Pxx2Transport::addByte(outputMessage[i]);
373 endFrame();
376 bool Pxx2Pulses::setupFrame(uint8_t module)
378 if (moduleState[module].mode == MODULE_MODE_OTA_UPDATE)
379 return false;
381 if (moduleState[module].mode == MODULE_MODE_AUTHENTICATION) {
382 moduleState[module].mode = MODULE_MODE_NORMAL;
383 return false;
386 initFrame();
388 switch (moduleState[module].mode) {
389 case MODULE_MODE_GET_HARDWARE_INFO:
390 setupHardwareInfoFrame(module);
391 break;
392 case MODULE_MODE_MODULE_SETTINGS:
393 setupModuleSettingsFrame(module);
394 break;
395 case MODULE_MODE_RECEIVER_SETTINGS:
396 setupReceiverSettingsFrame(module);
397 break;
398 case MODULE_MODE_REGISTER:
399 setupRegisterFrame(module);
400 break;
401 case MODULE_MODE_BIND:
402 if (g_model.moduleData[module].type == MODULE_TYPE_ISRM_PXX2 && g_model.moduleData[module].subType != MODULE_SUBTYPE_ISRM_PXX2_ACCESS)
403 setupAccstBindFrame(module);
404 else if (g_model.moduleData[module].type == MODULE_TYPE_XJT_LITE_PXX2)
405 setupAccstBindFrame(module);
406 else
407 setupAccessBindFrame(module);
408 break;
409 case MODULE_MODE_RESET:
410 setupResetFrame(module);
411 break;
412 case MODULE_MODE_SPECTRUM_ANALYSER:
413 setupSpectrumAnalyser(module);
414 break;
415 case MODULE_MODE_POWER_METER:
416 setupPowerMeter(module);
417 break;
418 case MODULE_MODE_SHARE:
419 setupShareMode(module);
420 break;
421 default:
422 if (outputTelemetryBuffer.isModuleDestination(module)) {
423 setupTelemetryFrame(module);
424 outputTelemetryBuffer.reset();
426 else {
427 setupChannelsFrame(module);
429 break;
432 if (moduleState[module].counter-- == 0) {
433 moduleState[module].counter = 2500;
436 endFrame();
438 return true;
441 bool Pxx2OtaUpdate::waitStep(uint8_t step, uint8_t timeout)
443 OtaUpdateInformation * destination = moduleState[module].otaUpdateInformation;
444 uint8_t elapsed = 0;
446 watchdogSuspend(100 /*1s*/);
448 while (step != destination->step) {
449 if (elapsed++ > timeout) {
450 return false;
452 RTOS_WAIT_MS(1);
453 telemetryWakeup();
456 return true;
459 const char * Pxx2OtaUpdate::nextStep(uint8_t step, const char * rxName, uint32_t address, const uint8_t * buffer)
461 OtaUpdateInformation * destination = moduleState[module].otaUpdateInformation;
463 destination->step = step;
464 destination->address = address;
466 for (uint8_t retry = 0;; retry++) {
467 extmodulePulsesData.pxx2.sendOtaUpdate(module, rxName, address, (const char *) buffer);
468 if (waitStep(step + 1, 20)) {
469 return nullptr;
471 else if (retry == 100) {
472 return "Transfer failed";
477 const char * Pxx2OtaUpdate::doFlashFirmware(const char * filename)
479 FIL file;
480 uint8_t buffer[32];
481 UINT count;
482 const char * result;
484 result = nextStep(OTA_UPDATE_START, rxName, 0, nullptr);
485 if (result) {
486 return result;
489 if (f_open(&file, filename, FA_READ) != FR_OK) {
490 return "Open file failed";
493 uint32_t size;
494 const char * ext = getFileExtension(filename);
495 if (ext && !strcasecmp(ext, FRSKY_FIRMWARE_EXT)) {
496 FrSkyFirmwareInformation * information = (FrSkyFirmwareInformation *) buffer;
497 if (f_read(&file, buffer, sizeof(FrSkyFirmwareInformation), &count) != FR_OK || count != sizeof(FrSkyFirmwareInformation)) {
498 f_close(&file);
499 return "Format error";
501 size = information->size;
503 else {
504 size = f_size(&file);
507 uint32_t done = 0;
508 while (1) {
509 drawProgressScreen(getBasename(filename), STR_OTA_UPDATE, done, size);
510 if (f_read(&file, buffer, sizeof(buffer), &count) != FR_OK) {
511 f_close(&file);
512 return "Read file failed";
515 result = nextStep(OTA_UPDATE_TRANSFER, nullptr, done, buffer);
516 if (result) {
517 return result;
520 if (count < sizeof(buffer)) {
521 f_close(&file);
522 break;
525 done += count;
528 return nextStep(OTA_UPDATE_EOF, nullptr, done, nullptr);
531 void Pxx2OtaUpdate::flashFirmware(const char * filename)
533 pausePulses();
535 watchdogSuspend(100 /*1s*/);
536 RTOS_WAIT_MS(100);
538 moduleState[module].mode = MODULE_MODE_OTA_UPDATE;
539 const char * result = doFlashFirmware(filename);
540 moduleState[module].mode = MODULE_MODE_NORMAL;
542 AUDIO_PLAY(AU_SPECIAL_SOUND_BEEP1 );
543 BACKLIGHT_ENABLE();
545 if (result) {
546 POPUP_WARNING(STR_FIRMWARE_UPDATE_ERROR);
547 SET_WARNING_INFO(result, strlen(result), 0);
549 else {
550 POPUP_INFORMATION(STR_FIRMWARE_UPDATE_SUCCESS);
553 watchdogSuspend(100);
554 RTOS_WAIT_MS(100);
556 resumePulses();