/* * Copyright (C) OpenTX * * Based on code named * th9x - http://code.google.com/p/th9x * er9x - http://code.google.com/p/er9x * gruvin9x - http://code.google.com/p/gruvin9x * * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include uint8_t telemetryStreaming = 0; uint8_t R9ModuleStreaming = 0; uint8_t telemetryRxBuffer[TELEMETRY_RX_PACKET_SIZE]; // Receive buffer. 9 bytes (full packet), worst case 18 bytes with byte-stuffing (+1) uint8_t telemetryRxBufferCount = 0; #if defined(WS_HOW_HIGH) uint8_t wshhStreaming = 0; #endif uint8_t telemetryState = TELEMETRY_INIT; TelemetryData telemetryData; uint8_t telemetryProtocol = 255; #if defined(PCBSKY9X) && defined(REVX) uint8_t serialInversion = 0; #endif void processTelemetryData(uint8_t data) { #if defined(CROSSFIRE) if (telemetryProtocol == PROTOCOL_TELEMETRY_CROSSFIRE) { processCrossfireTelemetryData(data); return; } #endif #if defined(MULTIMODULE) if (telemetryProtocol == PROTOCOL_TELEMETRY_SPEKTRUM) { processSpektrumTelemetryData(data); return; } if (telemetryProtocol == PROTOCOL_TELEMETRY_FLYSKY_IBUS) { processFlySkyTelemetryData(data); return; } if (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE) { processMultiTelemetryData(data); return; } #endif if (telemetryProtocol == PROTOCOL_TELEMETRY_PXX2) { processFrskyPXX2Data(data); return; } processFrskyTelemetryData(data); } void processRegisterFrame(uint8_t module, uint8_t * frame) { if (moduleSettings[module].mode != MODULE_MODE_REGISTER) { return; } if (frame[3] == 0x00) { // RX_ID follows, we discard it for now reusableBuffer.modelsetup.pxx2_register_or_bind_step = REGISTER_COUNTER_ID_RECEIVED; } else if (frame[3] == 0x01) { // RX_ID follows, we check it is good if (1) { } // PASSWORD follows, we check it is good if (memcmp(&frame[8], g_model.modelRegistrationID, PXX2_LEN_REGISTRATION_ID) == 0) { reusableBuffer.modelsetup.pxx2_register_or_bind_step = REGISTER_OK; moduleSettings[module].mode = MODULE_MODE_NORMAL; POPUP_INFORMATION(STR_REG_OK); } } } void processBindFrame(uint8_t module, uint8_t * frame) { if (moduleSettings[module].mode != MODULE_MODE_BIND) { return; } if (frame[3] == 0x00) { bool found = false; for (uint8_t i=0; i> 4); *c++ = (quartet >= 10 ? quartet + 'A' - 10 : quartet + '0'); quartet = (byte & 0x0f); *c++ = (quartet >= 10 ? quartet + 'A' - 10 : quartet + '0'); *c++ = ' '; } *c = '\0'; ++reusableBuffer.modelsetup.pxx2_bind_candidate_receivers_count; reusableBuffer.modelsetup.pxx2_register_or_bind_step = BIND_RX_ID_RECEIVED; } } else if (frame[3] == 0x01) { if (memcmp(reusableBuffer.modelsetup.pxx2_bind_candidate_receivers_ids[reusableBuffer.modelsetup.pxx2_bind_selected_receiver_index], &frame[4], PXX2_LEN_RX_ID) == 0) { reusableBuffer.modelsetup.pxx2_register_or_bind_step = BIND_OK; moduleSettings[module].mode = MODULE_MODE_NORMAL; POPUP_INFORMATION(STR_BIND_OK); } } } void processSpectrumFrame(uint8_t module, uint8_t * frame) { if (moduleSettings[module].mode != MODULE_MODE_SPECTRUM_ANALYSER) { return; } uint32_t * frequency = (uint32_t *)&frame[4]; int8_t * power = (int8_t *)&frame[8]; // center = 2440000000; // 2440MHz // span = 40000000; // 40MHz // left = 2440000000 - 20000000 // step = 10000 int32_t D = *frequency - (2440000000 - 40000000 / 2); // TRACE("Fq=%u, Pw=%d, X=%d, Y=%d", *frequency, int32_t(*power), D * 128 / 40000000, int32_t(127 + *power)); uint8_t x = D * 128 / 40000000; reusableBuffer.spectrum.bars[x] = 127 + *power; } void processRadioFrame(uint8_t module, uint8_t * frame) { switch (frame[2]) { case PXX2_TYPE_ID_REGISTER: processRegisterFrame(module, frame); break; case PXX2_TYPE_ID_BIND: processBindFrame(module, frame); break; } } void processPowerMeterFrame(uint8_t module, uint8_t * frame) { switch (frame[2]) { case PXX2_TYPE_ID_POWER_METER: // TODO break; case PXX2_TYPE_ID_SPECTRUM: processSpectrumFrame(module, frame); break; } } void processModuleFrame(uint8_t module, uint8_t * frame) { switch (frame[1]) { case PXX2_TYPE_C_MODULE: processRadioFrame(module, frame); break; case PXX2_TYPE_C_POWER_METER: processPowerMeterFrame(module, frame); break; default: break; } } void telemetryWakeup() { uint8_t requiredTelemetryProtocol = modelTelemetryProtocol(); #if defined(REVX) uint8_t requiredSerialInversion = g_model.moduleData[EXTERNAL_MODULE].invertedSerial; if (telemetryProtocol != requiredTelemetryProtocol || serialInversion != requiredSerialInversion) { serialInversion = requiredSerialInversion; telemetryInit(requiredTelemetryProtocol); } #else if (telemetryProtocol != requiredTelemetryProtocol) { telemetryInit(requiredTelemetryProtocol); } #endif #if defined(INTMODULE_USART) uint8_t frame[32]; if (intmoduleFifo.getFrame(frame)) { processModuleFrame(INTERNAL_MODULE, frame); } #endif #if defined(STM32) uint8_t data; if (telemetryGetByte(&data)) { LOG_TELEMETRY_WRITE_START(); do { processTelemetryData(data); LOG_TELEMETRY_WRITE_BYTE(data); } while (telemetryGetByte(&data)); } #elif defined(PCBSKY9X) if (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_D_SECONDARY) { uint8_t data; while (telemetrySecondPortReceive(data)) { processTelemetryData(data); } } else { // Receive serial data here rxPdcUsart(processTelemetryData); } #endif for (int i=0; i 0x33) static tmr10ms_t alarmsCheckTime = 0; #define SCHEDULE_NEXT_ALARMS_CHECK(seconds) alarmsCheckTime = get_tmr10ms() + (100*(seconds)) if (int32_t(get_tmr10ms() - alarmsCheckTime) > 0) { SCHEDULE_NEXT_ALARMS_CHECK(1/*second*/); bool sensor_lost = false; for (int i=0; i TELEMETRY_VALUE_OLD_THRESHOLD) { TelemetrySensor * sensor = & g_model.telemetrySensors[i]; if (sensor->unit != UNIT_DATETIME) { item.setOld(); sensor_lost = true; } } } } if (sensor_lost && TELEMETRY_STREAMING() && !g_model.rssiAlarms.disabled) { audioEvent(AU_SENSOR_LOST); } #if defined(PCBTARANIS) || defined(PCBHORUS) if ((isModulePXX(INTERNAL_MODULE) || isModulePXX(EXTERNAL_MODULE)) && FRSKY_BAD_ANTENNA()) { AUDIO_RAS_RED(); POPUP_WARNING(STR_WARNING); const char * w = STR_ANTENNAPROBLEM; SET_WARNING_INFO(w, strlen(w), 0); SCHEDULE_NEXT_ALARMS_CHECK(10/*seconds*/); } #endif if (!g_model.rssiAlarms.disabled) { if (TELEMETRY_STREAMING()) { if (TELEMETRY_RSSI() < g_model.rssiAlarms.getCriticalRssi() ) { AUDIO_RSSI_RED(); SCHEDULE_NEXT_ALARMS_CHECK(10/*seconds*/); } else if (TELEMETRY_RSSI() < g_model.rssiAlarms.getWarningRssi() ) { AUDIO_RSSI_ORANGE(); SCHEDULE_NEXT_ALARMS_CHECK(10/*seconds*/); } } if (TELEMETRY_STREAMING()) { if (telemetryState == TELEMETRY_KO) { AUDIO_TELEMETRY_BACK(); } telemetryState = TELEMETRY_OK; } else if (telemetryState == TELEMETRY_OK) { telemetryState = TELEMETRY_KO; AUDIO_TELEMETRY_LOST(); } } } } void telemetryInterrupt10ms() { if (TELEMETRY_STREAMING()) { if (!TELEMETRY_OPENXSENSOR()) { for (int i=0; i 0) { wshhStreaming--; } #endif if (R9ModuleStreaming > 0) { R9ModuleStreaming--; } if (telemetryStreaming > 0) { telemetryStreaming--; } else { #if !defined(SIMU) telemetryData.rssi.reset(); #endif } } void telemetryReset() { memclear(&telemetryData, sizeof(telemetryData)); for (int index=0; index * luaInputTelemetryFifo = NULL; #endif