PXX2 first draft

This commit is contained in:
Bertrand Songis
2018-10-08 00:12:53 +02:00
parent ece41bdd75
commit 713402b572
12 changed files with 322 additions and 18 deletions
+6 -1
View File
@@ -47,6 +47,7 @@ option(FRSKY_STICKS "Reverse sticks for FrSky sticks" OFF)
option(NANO "Use nano newlib and binalloc")
option(NIGHTLY_BUILD_WARNING "Warn this is a nightly build" OFF)
option(MODULE_R9M_FLEX_FW "Add R9M options for non certified firmwwares" OFF)
option(PXX2 "Enable PXX v2 support" OFF)
# since we reset all default CMAKE compiler flags for firmware builds, provide an alternate way for user to specify additional flags.
set(FIRMWARE_C_FLAGS "" CACHE STRING "Additional flags for firmware target c compiler (note: all CMAKE_C_FLAGS[_*] are ignored for firmware/bootloader).")
@@ -313,7 +314,11 @@ if(NIGHTLY_BUILD_WARNING)
endif(NIGHTLY_BUILD_WARNING)
if(MODULE_R9M_FLEX_FW)
add_definitions(-DMODULE_R9M_FLEX_FW)
add_definitions(-DMODULE_R9M_FLEX_FW)
endif()
if(PXX2)
add_definitions(-DPXX2)
endif()
set(SRC
+27
View File
@@ -0,0 +1,27 @@
/*
* 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.
*/
#ifndef _IO_PXX2_H_
#define _IO_PXX2_H_
#define PXX2_BAUDRATE 230400
#define PXX2_PERIOD 4 // 4ms
#endif
+7 -1
View File
@@ -342,10 +342,16 @@ enum Protocols {
#endif
PROTO_MULTIMODULE,
PROTO_SBUS,
PROTO_MAX,
PROTO_PXX2,
PROTO_NONE
};
#if defined(PXX2)
#define PROTO_PXX_EXTERNAL_MODULE PROTO_PXX2
#else
#define PROTO_PXX_EXTERNAL_MODULE PROTO_PXX
#endif
enum XJTRFProtocols {
RF_PROTO_OFF = -1,
RF_PROTO_X16,
+22 -2
View File
@@ -20,6 +20,11 @@
#include "opentx.h"
#if defined(PXX2)
#include "io/pxx2.h"
#include "pulses/pxx2.h"
#endif
uint8_t s_pulses_paused = 0;
uint8_t s_current_protocol[NUM_MODULES] = { MODULES_INIT(255) };
uint16_t failsafeCounter[NUM_MODULES] = { MODULES_INIT(100) };
@@ -56,14 +61,13 @@ uint8_t getRequiredProtocol(uint8_t port)
#endif
default:
port = EXTERNAL_MODULE; // ensure it's external module only
switch (g_model.moduleData[EXTERNAL_MODULE].type) {
case MODULE_TYPE_PPM:
required_protocol = PROTO_PPM;
break;
case MODULE_TYPE_XJT:
case MODULE_TYPE_R9M:
required_protocol = PROTO_PXX;
required_protocol = PROTO_PXX_EXTERNAL_MODULE; // either PXX or PXX2 depending on compilation options
break;
case MODULE_TYPE_SBUS:
required_protocol = PROTO_SBUS;
@@ -146,6 +150,12 @@ void setupPulses(uint8_t port)
break;
#endif
#if defined(PXX2)
case PROTO_PXX2:
disable_pxx2(port);
break;
#endif
#if defined(MULTIMODULE)
case PROTO_MULTIMODULE:
#endif
@@ -208,6 +218,16 @@ void setupPulses(uint8_t port)
break;
#endif
#if defined(PXX2)
case PROTO_PXX2:
if (telemetryProtocol == PROTOCOL_FRSKY_SPORT && !init_needed) {
createPXX2ChannelsFrame(port);
sportSendBuffer(modulePulsesData[port].pxx_uart.pulses, modulePulsesData[port].pxx_uart.ptr - modulePulsesData[port].pxx_uart.pulses);
}
scheduleNextMixerCalculation(port, PXX2_PERIOD);
break;
#endif
#if defined(MULTIMODULE)
case PROTO_MULTIMODULE:
setupPulsesMultimodule(port);
+2 -2
View File
@@ -86,7 +86,7 @@ PACK(struct Dsm2TimerPulsesData {
});
#endif
#if defined(INTMODULE_USART) || defined(EXTMODULE_USART)
#if defined(INTMODULE_USART) || defined(EXTMODULE_USART) || defined(PXX2)
PACK(struct PxxUartPulsesData {
uint8_t pulses[64];
uint8_t * ptr;
@@ -131,7 +131,7 @@ PACK(struct CrossfirePulsesData {
});
union ModulePulsesData {
#if defined(INTMODULE_USART) || defined(EXTMODULE_USART)
#if defined(INTMODULE_USART) || defined(EXTMODULE_USART) || defined(PXX2)
PxxUartPulsesData pxx_uart;
#endif
#if defined(PPM_PIN_SERIAL)
+23
View File
@@ -0,0 +1,23 @@
/*
* 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.
*/
#define PXX_SEND_BIND 0x01
#define PXX_SEND_FAILSAFE (1 << 4)
#define PXX_SEND_RANGECHECK (1 << 5)
+184
View File
@@ -0,0 +1,184 @@
/*
* 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 "opentx.h"
#include "pulses/pxx.h"
void uartInitPcmArray(uint8_t port)
{
modulePulsesData[port].pxx_uart.pcmCrc = 0;
modulePulsesData[port].pxx_uart.ptr = modulePulsesData[port].pxx_uart.pulses;
}
void putPXX2Byte(uint8_t port, uint8_t byte)
{
modulePulsesData[port].pxx_uart.pcmCrc = (modulePulsesData[port].pxx_uart.pcmCrc<<8) ^ (CRCTable[((modulePulsesData[port].pxx_uart.pcmCrc>>8) ^ byte) & 0xFF]);
*modulePulsesData[port].pxx_uart.ptr++ = byte;
}
void createPXX2ChannelsFrame(uint8_t port)
{
uint16_t pulseValue=0, pulseValueLow=0;
static uint8_t pass[NUM_MODULES] = { MODULES_INIT(0) };
uint8_t sendUpperChannels = 0;
if (pass[port]++ & 0x01) {
sendUpperChannels = g_model.moduleData[port].channelsCount;
}
uartInitPcmArray(port);
// Model ID
putPXX2Byte(port, g_model.header.modelId[port]);
// Flag1
uint8_t flag1 = (g_model.moduleData[port].rfProtocol << 6);
if (moduleFlag[port] == MODULE_BIND) {
flag1 |= (g_eeGeneral.countryCode << 1) | PXX_SEND_BIND;
}
else if (moduleFlag[port] == MODULE_RANGECHECK) {
flag1 |= PXX_SEND_RANGECHECK;
}
else if (g_model.moduleData[port].failsafeMode != FAILSAFE_NOT_SET && g_model.moduleData[port].failsafeMode != FAILSAFE_RECEIVER) {
if (failsafeCounter[port]-- == 0) {
failsafeCounter[port] = 1000;
flag1 |= PXX_SEND_FAILSAFE;
}
if (failsafeCounter[port] == 0 && g_model.moduleData[port].channelsCount > 0) {
flag1 |= PXX_SEND_FAILSAFE;
}
}
putPXX2Byte(port, flag1);
// Flag2
putPXX2Byte(port, 0);
// Channels
for (int i=0; i<8; i++) {
if (flag1 & PXX_SEND_FAILSAFE) {
if (g_model.moduleData[port].failsafeMode == FAILSAFE_HOLD) {
pulseValue = (i < sendUpperChannels ? 4095 : 2047);
}
else if (g_model.moduleData[port].failsafeMode == FAILSAFE_NOPULSES) {
pulseValue = (i < sendUpperChannels ? 2048 : 0);
}
else {
if (i < sendUpperChannels) {
int16_t failsafeValue = g_model.moduleData[port].failsafeChannels[8+i];
if (failsafeValue == FAILSAFE_CHANNEL_HOLD) {
pulseValue = 4095;
}
else if (failsafeValue == FAILSAFE_CHANNEL_NOPULSE) {
pulseValue = 2048;
}
else {
failsafeValue += 2*PPM_CH_CENTER(8+g_model.moduleData[port].channelsStart+i) - 2*PPM_CENTER;
pulseValue = limit(2049, (failsafeValue * 512 / 682) + 3072, 4094);
}
}
else {
int16_t failsafeValue = g_model.moduleData[port].failsafeChannels[i];
if (failsafeValue == FAILSAFE_CHANNEL_HOLD) {
pulseValue = 2047;
}
else if (failsafeValue == FAILSAFE_CHANNEL_NOPULSE) {
pulseValue = 0;
}
else {
failsafeValue += 2*PPM_CH_CENTER(g_model.moduleData[port].channelsStart+i) - 2*PPM_CENTER;
pulseValue = limit(1, (failsafeValue * 512 / 682) + 1024, 2046);
}
}
}
}
else {
if (i < sendUpperChannels) {
int channel = 8 + g_model.moduleData[port].channelsStart + i;
int value = channelOutputs[channel] + 2*PPM_CH_CENTER(channel) - 2*PPM_CENTER;
pulseValue = limit(2049, (value * 512 / 682) + 3072, 4094);
}
else if (i < sentModuleChannels(port)) {
int channel = g_model.moduleData[port].channelsStart + i;
int value = channelOutputs[channel] + 2*PPM_CH_CENTER(channel) - 2*PPM_CENTER;
pulseValue = limit(1, (value * 512 / 682) + 1024, 2046);
}
else {
pulseValue = 1024;
}
}
if (i & 1) {
putPXX2Byte(port, pulseValueLow); // Low byte of channel
putPXX2Byte(port, ((pulseValueLow >> 8) & 0x0F) | (pulseValue << 4)); // 4 bits each from 2 channels
putPXX2Byte(port, pulseValue >> 4); // High byte of channel
}
else {
pulseValueLow = pulseValue;
}
}
// Ext. flag (holds antenna selection on Horus internal module, 0x00 otherwise)
uint8_t extra_flags = 0;
#if defined(PCBHORUS) || defined(PCBXLITE)
if (port == INTERNAL_MODULE) {
extra_flags |= (g_model.moduleData[port].pxx.external_antenna << 0);
}
#endif
extra_flags |= (g_model.moduleData[port].pxx.receiver_telem_off << 1);
extra_flags |= (g_model.moduleData[port].pxx.receiver_channel_9_16 << 2);
if (isModuleR9M(port)) {
extra_flags |= (min(g_model.moduleData[port].pxx.power, isModuleR9M_FCC_VARIANT(port) ? (uint8_t)R9M_FCC_POWER_MAX : (uint8_t)R9M_LBT_POWER_MAX) << 3);
if (isModuleR9M_EUPLUS(port)) {
extra_flags |= (1 << 6);
}
}
// Disable S.PORT if internal module is active
if (IS_TELEMETRY_INTERNAL_MODULE()) {
extra_flags |= (1 << 5);
}
putPXX2Byte(port, extra_flags);
// Flag3, reserved
putPXX2Byte(port, 0);
#if defined(LUA)
if (outputTelemetryBufferTrigger != 0x00 && outputTelemetryBufferSize > 0) {
// CMD/Resp
putPXX2Byte(port, 1);
// primID (1 byte) + dataID (2 bytes) + value (4 bytes)
for (uint8_t i=0; i<7; i++) {
putPXX2Byte(port, outputTelemetryBuffer[i]);
}
outputTelemetryBufferTrigger = 0x00;
outputTelemetryBufferSize = 0;
}
else {
// CMD/Resp
putPXX2Byte(port, 0);
}
#else
// CMD/Resp
putPXX2Byte(port, 0);
#endif
// CRC
putPXX2Byte(port, modulePulsesData[port].pxx_uart.pcmCrc); // TODO need to check the CRC chosen algorithm
}
+21
View File
@@ -0,0 +1,21 @@
/*
* 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.
*/
void createPXX2ChannelsFrame(uint8_t port);
+1 -4
View File
@@ -19,10 +19,7 @@
*/
#include "opentx.h"
#define PXX_SEND_BIND 0x01
#define PXX_SEND_FAILSAFE (1 << 4)
#define PXX_SEND_RANGECHECK (1 << 5)
#include "pulses/pxx.h"
const uint16_t CRCTable[]=
{
@@ -9,6 +9,7 @@ option(USB_SERIAL "Enable USB serial (CDC)" OFF)
set(ARCH ARM)
set(STM32USB_DIR ${THIRDPARTY_DIR}/STM32_USB-Host-Device_Lib_V2.2.0/Libraries)
add_definitions(-DSTM32 -DLUA_INPUTS -DVARIO -DCROSSFIRE)
include_directories(${RADIO_SRC_DIRECTORY}/targets/common/arm/stm32)
include_directories(${STM32USB_DIR}/STM32_USB_OTG_Driver/inc)
include_directories(${STM32USB_DIR}/STM32_USB_Device_Library/Core/inc)
@@ -90,12 +91,21 @@ foreach(FILE ${STM32USB_SRC})
${STM32USB_DIR}/${FILE}
)
endforeach()
set(SRC
${SRC}
telemetry/crossfire.cpp
io/bootloader_flash.cpp
)
set(PULSES_SRC
${PULSES_SRC}
crossfire.cpp
)
if(PXX2)
set(PULSES_SRC
${PULSES_SRC}
pxx2.cpp
)
endif()
+10 -8
View File
@@ -182,14 +182,16 @@ uint32_t isBootloaderStart(const uint8_t * buffer);
#endif
void init_no_pulses(uint32_t port);
void disable_no_pulses(uint32_t port);
void init_ppm( uint32_t module_index );
void disable_ppm( uint32_t module_index );
void init_pxx( uint32_t module_index );
void disable_pxx( uint32_t module_index );
void init_serial( uint32_t module_index, uint32_t baudrate, uint32_t period );
void disable_serial( uint32_t module_index );
void init_crossfire( uint32_t module_index );
void disable_crossfire( uint32_t module_index );
void init_ppm( uint32_t module_index);
void disable_ppm( uint32_t module_index);
void init_pxx( uint32_t module_index);
void disable_pxx( uint32_t module_index);
void init_serial( uint32_t module_index, uint32_t baudrate, uint32_t period);
void disable_serial( uint32_t module_index);
void init_crossfire( uint32_t module_index);
void disable_crossfire( uint32_t module_index);
void init_pxx2( uint32_t module_index);
void disable_pxx2( uint32_t module_index);
// Trainer driver
#define SLAVE_MODE() (g_model.trainerMode == TRAINER_MODE_SLAVE)
@@ -120,3 +120,12 @@ void disable_crossfire(uint32_t port)
extmoduleStop();
}
}
void disable_pxx2(uint32_t port)
{
if (port == EXTERNAL_MODULE) {
extmoduleStop();
}
}