PXX2 first draft
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -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()
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user