1
0
Fork 0
mirror of https://github.com/EdgeTX/edgetx.git synced 2025-07-25 01:05:08 +03:00

refact: ADC, switches and keys

Add "hardware_defs" target to dump hardware defines from hal.h per target

Fixed hal.h definitions for switches & ADC inputs

Tools to generate hardware definitions from current hal.h

generator: add support for EXTx and analog switches

WiP

Add generated header to hardware_defs target

Add support for ADC input direction and index per GPIO port

Incredible: it compiles

Removed StdPeriph ADC driver

Works on QX7

Works on TX16S (VBat missing)

Switch driver using generated switches for stm32 targets

Switch driver with generated switches for simu

Use switch names from switch driver

Fixed single conversion handling

Fixed horus VBat reading

Added switch name

Fix warnings about bitfield offsets and GCC 4.4

This is caused by bitfields that cross type boundaries. In this particular case, it happens as the bitfield is not defined the same in `rtc_backup.cpp`.

Switches has already been moved to generic driver

Jitter measurement for each sample, not just for oversampled values

Moved periph clock init to the ADC driver

ADC & GPIOs.

Add switchInit() to init pins

Fix NV14 CMake

Fix taranis target

Fix NV14 (again)

Model audio files: use new interface for switch index

Fix X9-lite

Fix simu headers

Fix getSwitchName()

Add support for ADC switches

Fix switch warning YAML

Test only switches which are defined

Conversions tests for QX7 only on QX7

Fix X12S

Fix function switch names

Enable ADC periph clock before initialising channels

NV14: offset inputs for the sticks & fix switches

WiP: get rid of VSRCRAW and some more

Simu shall use normal ADC driver

fix x7

fix nv14

Fix 9x nav

fix 212x64

fix xlite

fix x9e

fix simu lib

fix unit tests

fix x7 tests

PWM stick values should be written directly into adcValues

... just like FlySky sticks.

fix x12s

fix nv14

Add some support for SPI ADC (only unit tests)

Remove `jq` usage

fix generate_yaml.py for newer libclang

fix pot config

fix stick names

Some YAML generator improvements

Max 16 Pots on COLORLCD

Fix some source names

Use 10 bits for switches to prevent overflow

Removed horus constants for switches & ADC inputs

Fix unit tests

Fix curve edit

Fix libsimulator

Fix function switches (tpro)

Refine ADC & analog API

Moved hardware definitions scripts and templates into own dir

cleanup API refine

Fix unit tests

Mixer: apply calibration only on required inputs

Place ADC switches after all other ADC inputs

Fix X12S

Remove useless TR_POTS_VSRCRAW, TR_SW_VSRCRAW, and TR_VSRCRAW

Cleanup redundant generated YAML parsers

Fixes Boxer rebase

Add boxer to generate-hw-defs.sh

Obsolete LUA exports

Add boxer ADC_DIRECTION

Split generate_hw_defs.py into multiple files

Some cleanup (+ LUA switches)

Fix AXIS definitions

Fixed translation strings declarations

Some rebase fixes

Remove some useless StdPeriph drivers

fix: set pin mode to reset state on usart deinit

fix: use canonical names for calibration data

fix: ADC driver does not care about unconfigured inputs

fix X12S ADC

Add support for ADC conversion chaining

Better X12S ADC implem

Moved X12S ADC driver to HAL/LL

Improve ADC driver separation

Fixed taranis & nv14

Moved PWM gimbals to HAL/LL

Removed useless TR_EXTRA_VSRCRAW

Fixed include guards

Small fixes

Renamed control inputs

Moved internal and external module pulse driver def to boards

Move more things to the generic_stm32 board

Remove STR_VMIXTRIMS

Added analog labels

Generate main control names

Misuse labels / short labels for main controls

Backward compatibility: sliders and legacy names

New keys driver

Let's get rid of StdPeriph headers in simu

Add jinja2 to CI workflows

Use `grep` instead of `sed`

chore: add python jinja2 oto msys setup script

Removed more static definitions and use dynamic ones instead

Fixes X9E

Fix x7 nav too

212 switch display

Fix default sliders

Removed NUM_STICKS

212 switch display working nicely

Surface radio 'stick' replacements

fix: switch, trim & rotary pin init

Remove old key drivers

Removed VKEYS

Removed ETX_FOURCC

Fixed SURFACE_NAME

Removed TR_VSWITCHES & TR_TRIMS_SWITCHES

Fix xpot switches

Store calibrated analogs in physical order

Use getSourceString in drawSource

Implement missing YAML read/write

Fix isSourceAvailableInInputs()

Fix isSourceAvailable()

Some surface fixes

Fix CLI debug

Ported colour UI of analog diagnostics to new ADC API

Small fixes

Better input mapping

Minor tpro fixes

Fix trims available

Remove TX mode choice on surface radio

Rename surface controls

Channel order alignement

Fix throttle warning

Fix checkTrims()

Fix pot config casting issue

Fix IS_SWITCH_FS()

Fixed input mapping

Fix fswitch auto-switch

Fixed storing / reading function switches in YAML

Fix enableVBatBridge() / disableVBatBridge()

Fix interesting mode conversion

Fix sources issues

Fix special funnction list

Proper function switch handling

128 GUI improvements

Fix compilation

Boxer cosmetics

128 hardware screen cosmetic

Fix TX12 switches

More switches fixes

Simplify CPU type handling

Fix flash size

Fixed page-up / page-down in libopenui
This commit is contained in:
Raphael Coeffic 2022-10-18 18:20:17 +02:00 committed by Malte Langermann
parent b6dd3a0ef8
commit 2b100e0eb5
323 changed files with 12813 additions and 22302 deletions

View file

@ -68,7 +68,7 @@ jobs:
setup-python: 'false'
- name: Install dependencies
run: python3 -m pip install --upgrade pip Pillow lz4 clang
run: python3 -m pip install --upgrade pip Pillow lz4 clang jinja2
- name: Patch GitHub macOS build
run: brew install pkg-config

View file

@ -71,7 +71,7 @@ jobs:
mingw-w64-x86_64-SDL2 \
mingw-w64-x86_64-clang \
mingw-w64-x86_64-nsis
python -m pip install clang
python -m pip install clang jinja2
- name: Install Qt
uses: jurplel/install-qt-action@v3

View file

@ -33,7 +33,6 @@ endif()
set(CMAKE_COLOR_MAKEFILE ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_CXX_STANDARD 11)
add_definitions(-D_GLIBCXX_USE_C99=1) # proper to_string definition
set(RADIO_DIRECTORY ${PROJECT_SOURCE_DIR}/radio)

View file

@ -16,11 +16,6 @@ macro(git_id RESULT)
endif()
endmacro(git_id)
macro(use_cxx11)
if (CMAKE_VERSION VERSION_LESS "3.1" AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set (CMAKE_CXX_FLAGS "--std=gnu++11 ${CMAKE_CXX_FLAGS}")
endif ()
endmacro(use_cxx11)
macro(PrintTargetReport targetName)
if(CMAKE_CXX_COMPILER MATCHES "/(clang-)?cl\\.exe$")
@ -60,7 +55,6 @@ function(AddCompilerFlags output)
endforeach()
# Add hotfix for arm64
set(ARGS ${ARGS} -Wno-asm-operand-widths -Wno-pragma-once-outside-header)
set(${output} ${${output}} ${ARGS} PARENT_SCOPE)
endfunction()
@ -73,6 +67,8 @@ function(GenerateDatacopy source output)
# Fetch defines / include directories in use
AddCompilerFlags(GEN_DATACOPY_ARGS)
# Hack to get rid of warnings in StdPeriph lib
set(GEN_DATACOPY_ARGS
# source file MUST be the first argument
${CMAKE_CURRENT_SOURCE_DIR}/${source}
@ -86,5 +82,51 @@ function(GenerateDatacopy source output)
COMMAND ${GEN_DATACOPY_CMD} > ${output}
DEPENDS ${GEN_DATACOPY_DEPEND}
)
endfunction()
function(AddHardwareDefTarget output)
AddCompilerFlags(HW_DEF_ARGS)
set(HW_DEF_SRC ${RADIO_DIRECTORY}/src/targets/${TARGET_DIR}/hal.h)
separate_arguments(flags UNIX_COMMAND ${CMAKE_CXX_FLAGS})
foreach(flag ${flags})
set(HW_DEF_ARGS ${HW_DEF_ARGS} ${flag})
endforeach()
set(GEN_HW_DEFS ${CMAKE_CXX_COMPILER} ${HW_DEF_ARGS} -x c++-header -E -dM ${HW_DEF_SRC})
set(GEN_HW_DEFS ${GEN_HW_DEFS} | grep -v "^#define _" | sort)
set(GEN_JSON ${PYTHON_EXECUTABLE} ${RADIO_DIRECTORY}/util/hw_defs/generate_hw_def.py)
set(GEN_JSON ${GEN_JSON} -i defines -T ${FLAVOUR} -)
add_custom_command(OUTPUT ${output}
COMMAND ${GEN_HW_DEFS} | ${GEN_JSON} > ${output}
DEPENDS ${HW_DEF_SRC} ${RADIO_DIRECTORY}/util/hw_defs/generate_hw_def.py
)
add_custom_command(OUTPUT ${output}.h
COMMAND ${GEN_HW_DEFS} > ${output}.h
DEPENDS ${HW_DEF_SRC} ${RADIO_DIRECTORY}/util/hw_defs/generate_hw_def.py
)
endfunction()
function(AddHWGenTarget input template output)
# Script
set(GEN_JSON ${PYTHON_EXECUTABLE} ${RADIO_DIRECTORY}/util/hw_defs/generate_hw_def.py)
# Inputs
set(INPUT_JSON ${CMAKE_CURRENT_BINARY_DIR}/${input})
set(TEMPLATE ${RADIO_DIRECTORY}/util/hw_defs/${template}.jinja)
set(LEGACY_JSON ${RADIO_DIRECTORY}/util/hw_defs/legacy_names.py)
# Command
set(GEN_JSON ${GEN_JSON} -t ${TEMPLATE} -T ${FLAVOUR} ${INPUT_JSON})
add_custom_command(OUTPUT ${output}
COMMAND ${GEN_JSON} > ${output}
DEPENDS ${INPUT_JSON} ${LEGACY_JSON} ${TEMPLATE}
)
endfunction()

View file

@ -1,6 +1,7 @@
# arm-none-eabi toolchain
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

View file

@ -1,10 +1,11 @@
# Native toolchain
set(CMAKE_CXX_STANDARD 17)
if(APPLE)
set(CMAKE_C_FLAGS "-Wno-asm-operand-widths -Wno-deprecated-declarations")
set(CMAKE_CXX_FLAGS "-Wno-asm-operand-widths -Wno-deprecated-declarations")
set(CMAKE_C_FLAGS_DEBUG "-Wno-asm-operand-widths -Wno-deprecated-declarations")
set(CMAKE_CXX_FLAGS_DEBUG "-Wno-asm-operand-widths -Wno-deprecated-declarations")
set(CMAKE_C_FLAGS "-Wno-deprecated-declarations")
set(CMAKE_CXX_FLAGS "-Wno-deprecated-declarations")
set(CMAKE_C_FLAGS_DEBUG "-Wno-deprecated-declarations")
set(CMAKE_CXX_FLAGS_DEBUG "-Wno-deprecated-declarations")
endif()
if(MINGW OR WIN32)

View file

@ -81,8 +81,6 @@ endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS}")
use_cxx11() # ensure gnu++11 in CXX_FLAGS with CMake < 3.1
include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}

View file

@ -20,8 +20,6 @@ if(GTEST_INCDIR AND GTEST_SRCDIR AND Qt5Widgets_FOUND)
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 ${WARNING_FLAGS}")
use_cxx11() # ensure gnu++11 in CXX_FLAGS with CMake < 3.1
add_executable(gtests-companion EXCLUDE_FROM_ALL ${TEST_SRC_FILES} ${CMAKE_CURRENT_SOURCE_DIR}/location.h.in)
add_dependencies(gtests-companion gtests-companion-lib)
target_link_libraries(gtests-companion gtests-companion-lib simulation firmwares storage common)

View file

@ -1,9 +1,5 @@
cmake_minimum_required(VERSION 2.8.12)
cmake_policy(SET CMP0020 NEW)
set(CMAKE_CXX_STANDARD 11)
if (CMAKE_VERSION VERSION_LESS "3.1" AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set (CMAKE_CXX_FLAGS "--std=gnu++11 ${CMAKE_CXX_FLAGS}")
endif ()
find_package(Qt5Core)
find_package(Qt5Widgets)

View file

@ -11,7 +11,7 @@ set(TRANSLATIONS "EN" CACHE STRING "Radio language, one of: ${RADIO_LANGUAGES}")
set_property(CACHE TRANSLATIONS PROPERTY STRINGS ${RADIO_LANGUAGES})
set(SPLASH "DEFAULT" CACHE STRING "Splash (DEFAULT/OFF/FRSKY)")
set_property(CACHE SPLASH PROPERTY STRINGS DEFAULT OFF FRSKY)
set(PPM_UNIT "PERCENT_PREC1" CACHE STRING "PPM display unit (US/PERCENT_PREC1/PERCENT_PREC0)")
set(PPM_UNIT "PERCENT_PREC0" CACHE STRING "PPM display unit (US/PERCENT_PREC1/PERCENT_PREC0)")
set_property(CACHE PPM_UNIT PROPERTY STRINGS US PERCENT_PREC1 PERCENT_PREC0)
set(DEFAULT_MODE "" CACHE STRING "Default sticks mode")
set(POPUP_LEVEL 2 CACHE STRING "Popup level")
@ -48,7 +48,6 @@ option(DEBUG_SEGGER_RTT "Debug output to Segger RTT" OFF)
option(DEBUG_WINDOWS "Turn on windows traces" OFF)
option(DEBUG_YAML "Turn on YAML traces" OFF)
option(DEBUG_LABELS "Turn on Labels traces" OFF)
option(FRSKY_STICKS "Reverse sticks for FrSky sticks" OFF)
option(NANO "Use nano newlib and binalloc")
option(TEST_BUILD_WARNING "Warn this is a test build" OFF)
option(MODULE_PROTOCOL_FCC "Add support for FCC modules" ON)
@ -73,15 +72,6 @@ set(FIRMWARE_C_FLAGS_DEBUG "-g" CACHE STRING "Additional flags for firmware targ
set(FIRMWARE_CXX_FLAGS "" CACHE STRING "Additional flags for firmware target c++ compiler (note: all CMAKE_CXX_FLAGS[_*] are ignored for firmware/bootloader).")
set(FIRMWARE_CXX_FLAGS_DEBUG "-g" CACHE STRING "Additional flags for firmware target (Debug config) c++ compiler (note: CMAKE_CXX_FLAGS_DEBUG is ignored for firmware/bootloader).")
set(GCC_ARM_PATH "" CACHE STRING "Alternative GCC ARM path")
set(FIRMWARE_C_COMPILER "${GCC_ARM_PATH}arm-none-eabi-gcc" CACHE STRING "Specific C compiler for firmware target.")
set(FIRMWARE_CXX_COMPILER "${GCC_ARM_PATH}arm-none-eabi-g++" CACHE STRING "Specific C++ compiler for firmware target.")
set(FIRMWARE_ASM_COMPILER "${GCC_ARM_PATH}arm-none-eabi-as" CACHE STRING "Specific assembler for firmware target.")
set(FIRMWARE_OBJCOPY "${GCC_ARM_PATH}arm-none-eabi-objcopy" CACHE STRING "Specific objcopy for firmware target.")
set(FIRMWARE_SIZE "${GCC_ARM_PATH}arm-none-eabi-size" CACHE STRING "Specific size for firmware target.")
set(FIRMWARE_RANLIB "${GCC_ARM_PATH}arm-none-eabi-ranlib" CACHE STRING "Specific ranlib for firmware target.")
set(THIRDPARTY_DIR thirdparty)
set(LUA_DIR ${THIRDPARTY_DIR}/Lua/src)
set(RTOS_DIR ${THIRDPARTY_DIR}/FreeRTOS)
@ -111,16 +101,17 @@ else()
message(FATAL_ERROR "Unknown PCB '${PCB}'")
endif()
set(HW_DESC_JSON ${FLAVOUR}.json)
AddHardwareDefTarget(${HW_DESC_JSON})
# enable generating JSON definition separately for debugging
add_custom_target(hardware_defs DEPENDS ${HW_DESC_JSON} ${HW_DESC_JSON}.h)
include(hal/CMakeLists.txt)
add_subdirectory(bitmaps)
add_subdirectory(fonts)
if(NOT PCB STREQUAL 9XRPRO)
option(DBLKEYS "Double Keys" ON)
if(DBLKEYS)
add_definitions(-DDBLKEYS)
endif()
endif()
if(CPU_TYPE STREQUAL STM32F4)
include(targets/common/arm/stm32/f4/CMakeLists.txt)
endif()
@ -131,6 +122,7 @@ endif()
if(CPU_FAMILY STREQUAL STM32)
include(targets/common/arm/stm32/CMakeLists.txt)
include(boards/generic_stm32/CMakeLists.txt)
endif()
if(ARCH STREQUAL ARM)
@ -185,7 +177,7 @@ if(RTC_BACKUP_RAM)
)
# Add custom target for debugging
add_custom_target(datacopy DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/datacopy.cpp)
add_custom_target(datacopy DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/datacopy.inc)
endif()
if(LUA)
@ -325,10 +317,6 @@ if(DEBUG_LABELS)
add_definitions(-DDEBUG_LABELS)
endif()
if(FRSKY_STICKS)
add_definitions(-DFRSKY_STICKS)
endif()
if(IMU_LSM6DS33)
add_definitions(-DIMU_LSM6DS33)
endif()
@ -405,6 +393,7 @@ set(SRC
functions.cpp
strhelpers.cpp
switches.cpp
analogs.cpp
mixer.cpp
mixer_scheduler.cpp
stamp.cpp
@ -413,7 +402,8 @@ set(SRC
model_init.cpp
serial.cpp
sbus.cpp
hal/module_port.cpp
input_mapping.cpp
inactivity_timer.cpp
tasks/mixer_task.cpp
)
@ -556,7 +546,7 @@ endif()
add_definitions(-DFREE_RTOS)
add_executable(firmware ${SRC} ${FIRMWARE_HEADERS})
add_executable(firmware ${SRC})
link_libraries(firmware -lstdc++)
add_dependencies(firmware ${RADIO_DEPENDENCIES})
set_target_properties(firmware PROPERTIES EXCLUDE_FROM_ALL TRUE)
@ -618,3 +608,5 @@ if(CPU_FAMILY STREQUAL STM32)
endif()
PrintTargetReport("firmware")
AddHardwareDefTarget(hardware_defs ${RADIO_DIRECTORY}/src/targets/hw_defs/${FLAVOUR}.json)

100
radio/src/analogs.cpp Normal file
View file

@ -0,0 +1,100 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* 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 "analogs.h"
#include "dataconstants.h"
#include "opentx_helpers.h"
#include "hal/adc_driver.h"
static char _custom_names[MAX_ANALOG_INPUTS][LEN_ANA_NAME + 1] = { 0 };
void analogSetCustomLabel(uint8_t type, uint8_t idx, const char* str, size_t len)
{
if (idx >= adcGetMaxInputs(type)) return;
idx += adcGetInputOffset(type);
strncpy(_custom_names[idx], str, min<size_t>(LEN_ANA_NAME, len));
_custom_names[idx][LEN_ANA_NAME] = '\0';
}
const char* analogGetCustomLabel(uint8_t type, uint8_t idx)
{
if (idx >= adcGetMaxInputs(type)) return "";
idx += adcGetInputOffset(type);
return _custom_names[idx];
}
bool analogHasCustomLabel(uint8_t type, uint8_t idx)
{
return *analogGetCustomLabel(type, idx) != 0;
}
static int _lookup_input_idx(uint8_t type, const char* name, size_t len,
const char* (*fct)(uint8_t,uint8_t))
{
auto max_inputs = adcGetMaxInputs(type);
if (!max_inputs) return -1;
for (uint8_t i = 0; i < max_inputs; i++) {
if (!strncmp(fct(type, i), name, len)) return i;
}
return -1;
}
int analogLookupPhysicalIdx(uint8_t type, const char* name, size_t len)
{
return _lookup_input_idx(type, name, len, adcGetInputName);
}
static int analogLookupLabelIdx(uint8_t type, const char* name, size_t len)
{
return _lookup_input_idx(type, name, len, adcGetInputLabel);
}
const char* analogGetPhysicalName(uint8_t type, uint8_t idx)
{
return adcGetInputName(type, idx);
}
const char* analogGetCanonicalName(uint8_t type, uint8_t idx)
{
// Main controls are special cases here as
// we use the label slot to place the specific names
// (2-gimbal radios vs. surface radios)
if (type == ADC_INPUT_MAIN)
return adcGetInputLabel(type, idx);
return adcGetInputName(type, idx);
}
int analogLookupCanonicalIdx(uint8_t type, const char* name, size_t len)
{
if (type == ADC_INPUT_MAIN) {
return analogLookupLabelIdx(type, name, len);
}
return analogLookupPhysicalIdx(type, name, len);
}

35
radio/src/analogs.h Normal file
View file

@ -0,0 +1,35 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* 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.
*/
#pragma once
#include <stddef.h>
#include <stdint.h>
void analogSetCustomLabel(uint8_t type, uint8_t idx, const char* str, size_t len);
const char* analogGetCustomLabel(uint8_t type, uint8_t idx);
bool analogHasCustomLabel(uint8_t type, uint8_t idx);
const char* analogGetPhysicalName(uint8_t type, uint8_t idx);
int analogLookupPhysicalIdx(uint8_t type, const char* name, size_t len);
const char* analogGetCanonicalName(uint8_t type, uint8_t idx);
int analogLookupCanonicalIdx(uint8_t type, const char* name, size_t len);

View file

@ -22,6 +22,8 @@
#include "opentx.h"
#include <math.h>
#include "switches.h"
#if defined(LIBOPENUI)
#include "libopenui.h"
#endif
@ -241,9 +243,12 @@ const char * const audioFilenames[] = {
"timovr3"
};
constexpr unsigned int MAX_SWITCH_POSITIONS =
MAX_SWITCHES * 3 + MAX_POTS * XPOTS_MULTIPOS_COUNT;
BitField<(AU_SPECIAL_SOUND_FIRST)> sdAvailableSystemAudioFiles;
BitField<(MAX_FLIGHT_MODES * 2/*on, off*/)> sdAvailableFlightmodeAudioFiles;
BitField<(SWSRC_LAST_SWITCH+NUM_XPOTS*XPOTS_MULTIPOS_COUNT)> sdAvailableSwitchAudioFiles;
BitField<MAX_SWITCH_POSITIONS> sdAvailableSwitchAudioFiles;
BitField<(MAX_LOGICAL_SWITCHES * 2/*on, off*/)> sdAvailableLogicalSwitchAudioFiles;
char * getAudioPath(char * path)
@ -330,22 +335,21 @@ void getSwitchAudioFile(char * filename, swsrc_t index)
{
char * str = getModelAudioPath(filename);
if (index <= SWSRC_LAST_SWITCH) {
if (index <= MAX_SWITCHES * 3) {
div_t swinfo = switchInfo(index);
*str++ = 'S';
*str++ = getRawSwitchFromIdx(swinfo.quot);
*str++ = switchGetLetter(swinfo.quot);
const char * positions[] = { "-up", "-mid", "-down" };
strcpy(str, positions[swinfo.rem]);
}
#if NUM_XPOTS > 0
else {
div_t swinfo = div(int(index - SWSRC_FIRST_MULTIPOS_SWITCH), XPOTS_MULTIPOS_COUNT);
index -= MAX_SWITCHES * 3;
div_t swinfo = div((int)index, XPOTS_MULTIPOS_COUNT);
*str++ = 'S';
*str++ = '1' + swinfo.quot;
*str++ = '1' + swinfo.rem;
*str = '\0';
}
#endif
strcat(str, SOUNDS_EXT);
}
@ -407,11 +411,11 @@ void referenceModelAudioFiles()
}
// Switches Audio Files <switchname>-[up|mid|down].wav
for (int i=SWSRC_FIRST_SWITCH; i<=SWSRC_LAST_SWITCH+NUM_XPOTS*XPOTS_MULTIPOS_COUNT && !found; i++) {
for (unsigned i = 0; i <= MAX_SWITCH_POSITIONS && !found; i++) {
getSwitchAudioFile(path, i);
// TRACE("referenceModelAudioFiles(): searching for %s in %s (%d)", path, fno.fname, i);
if (!strcasecmp(filename, fno.fname)) {
sdAvailableSwitchAudioFiles.setBit(i-SWSRC_FIRST_SWITCH);
sdAvailableSwitchAudioFiles.setBit(i);
found = true;
TRACE("\tfound: %s", filename);
}

View file

@ -32,9 +32,10 @@
Implements a bit field, number of bits is set by the template,
each bit can be modified and read by the provided methods.
*/
template <unsigned int NUM_BITS> class BitField {
template <unsigned int NUM_BITS> class BitField
{
private:
uint8_t bits[(NUM_BITS+7)/8];
uint8_t bits[(NUM_BITS + 7) / 8];
public:
BitField()
{
@ -54,7 +55,6 @@ template <unsigned int NUM_BITS> class BitField {
bool getBit(unsigned int bitNo) const
{
// assert(bitNo < NUM_BITS);
if (bitNo >= NUM_BITS) return false;
return bits[bitNo >> 3] & (1 << (bitNo & 0x07));
}

View file

@ -0,0 +1,40 @@
# Generate hardware struct defs
AddHWGenTarget(${HW_DESC_JSON} stm32_keys stm32_keys.inc)
AddHWGenTarget(${HW_DESC_JSON} stm32_switches stm32_switches.inc)
AddHWGenTarget(${HW_DESC_JSON} stm32_adc_inputs stm32_adc_inputs.inc)
AddHWGenTarget(${HW_DESC_JSON} hal_adc_inputs hal_adc_inputs.inc)
# Dependencies common to bootloader and firmware
set(MINIMAL_BOARD_LIB_SRC
${CMAKE_CURRENT_BINARY_DIR}/${HW_DESC_JSON}
${CMAKE_CURRENT_BINARY_DIR}/stm32_keys.inc
boards/generic_stm32/inputs.cpp
)
# Dependencies only used in firmware
set(BOARD_LIB_SRC
${CMAKE_CURRENT_BINARY_DIR}/stm32_switches.inc
${CMAKE_CURRENT_BINARY_DIR}/stm32_adc_inputs.inc
${CMAKE_CURRENT_BINARY_DIR}/hal_adc_inputs.inc
boards/generic_stm32/module_ports.cpp
boards/generic_stm32/aux_ports.cpp
boards/generic_stm32/sport_update.cpp
boards/generic_stm32/intmodule_heartbeat.cpp
boards/generic_stm32/analog_inputs.cpp
boards/generic_stm32/switches.cpp
)
add_library(minimal_board_lib OBJECT EXCLUDE_FROM_ALL ${MINIMAL_BOARD_LIB_SRC})
add_library(board_lib OBJECT EXCLUDE_FROM_ALL ${BOARD_LIB_SRC})
set(FIRMWARE_SRC ${FIRMWARE_SRC}
$<TARGET_OBJECTS:minimal_board_lib>
$<TARGET_OBJECTS:board_lib>
)
set(BOOTLOADER_SRC ${BOOTLOADER_SRC}
$<TARGET_OBJECTS:minimal_board_lib>
)

View file

@ -0,0 +1,85 @@
/*
* Copyright (C) EdgeTx
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* 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 "analog_inputs.h"
#include "stm32_adc.h"
#include "stm32_spi_adc.h"
#include "hal.h"
#if defined(ADC_SPI)
#include "ads79xx.h"
#endif
#include "definitions.h"
#include "myeeprom.h"
#include "translations.h"
#include <string.h>
// generated files
#include "stm32_adc_inputs.inc"
#include "hal_adc_inputs.inc"
constexpr uint8_t n_ADC = DIM(_ADC_adc);
constexpr uint8_t n_ADC_spi = DIM(_ADC_spi);
constexpr uint8_t n_GPIO = DIM(_ADC_GPIOs);
constexpr uint8_t n_inputs = DIM(_ADC_inputs);
static bool adc_init()
{
bool success = stm32_hal_adc_init(_ADC_adc, n_ADC, _ADC_inputs, _ADC_GPIOs, n_GPIO);
#if defined(ADC_SPI)
if (n_ADC_spi > 0) ads79xx_init(&_ADC_spi[0]);
#endif
return success;
}
static bool adc_start_read()
{
bool success = stm32_hal_adc_start_read(_ADC_adc, n_ADC, _ADC_inputs, n_inputs);
#if defined(ADC_SPI)
if (n_ADC_spi > 0) {
success = success && ads79xx_adc_start_read(&_ADC_spi[0], _ADC_inputs);
}
#endif
return success;
}
static void adc_wait_completion()
{
#if defined(ADC_SPI)
// ADS79xx does all the work in the completion function
// so it's probably better to poll it first
if (n_ADC_spi > 0) ads79xx_adc_wait_completion(&_ADC_spi[0], _ADC_inputs);
#endif
stm32_hal_adc_wait_completion(_ADC_adc, n_ADC, _ADC_inputs, n_inputs);
}
const etx_hal_adc_driver_t _adc_driver = {
_hal_inputs,
_pot_default_config,
adc_init,
adc_start_read,
adc_wait_completion
};

View file

@ -0,0 +1,24 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* 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 "hal/adc_driver.h"
extern const etx_hal_adc_driver_t _adc_driver;

View file

@ -0,0 +1,48 @@
/*
* Copyright (C) EdgeTx
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* 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 "hal/key_driver.h"
#include "stm32_hal_ll.h"
#include "stm32_gpio_driver.h"
#include "stm32_keys.inc"
void keysInit()
{
_init_keys();
_init_trims();
}
uint32_t readKeys()
{
return _read_keys();
}
uint32_t readTrims()
{
uint32_t trims = _read_trims();
#if defined(PCBXLITE)
if (_read_keys() & (1 << KEY_SHIFT))
return ((trims & 0x03) << 6) | ((trims & 0x0c) << 2);
#endif
return trims;
}

View file

@ -64,13 +64,54 @@ DEFINE_STM32_SERIAL_PORT(InternalModule, intmoduleUSART, INTMODULE_FIFO_SIZE, 0)
#include "stm32_pulse_driver.h"
#include "timers_driver.h"
extern const stm32_pulse_timer_t intmoduleTimer;
static stm32_pulse_dma_tc_cb_t _int_timer_DMA_TC_Callback;
static const stm32_pulse_timer_t intmoduleTimer = {
.GPIOx = INTMODULE_TX_GPIO,
.GPIO_Pin = INTMODULE_TX_GPIO_PIN,
.GPIO_Alternate = INTMODULE_TX_GPIO_AF,
.TIMx = INTMODULE_TIMER,
.TIM_Freq = INTMODULE_TIMER_FREQ,
.TIM_Channel = INTMODULE_TIMER_Channel,
.TIM_IRQn = INTMODULE_TIMER_IRQn,
.DMAx = INTMODULE_TIMER_DMA,
.DMA_Stream = INTMODULE_TIMER_DMA_STREAM,
.DMA_Channel = INTMODULE_TIMER_DMA_CHANNEL,
.DMA_IRQn = INTMODULE_TIMER_DMA_STREAM_IRQn,
.DMA_TC_CallbackPtr = &_int_timer_DMA_TC_Callback,
};
// Make sure the timer channel is supported
static_assert(__STM32_PULSE_IS_TIMER_CHANNEL_SUPPORTED(INTMODULE_TIMER_Channel),
"Unsupported timer channel");
// Make sure the DMA channel is supported
static_assert(__STM32_PULSE_IS_DMA_STREAM_SUPPORTED(INTMODULE_TIMER_DMA_STREAM),
"Unsupported DMA stream");
#if !defined(INTMODULE_TIMER_DMA_IRQHandler)
#error "Missing INTMODULE_TIMER_DMA_IRQHandler definition"
#endif
extern "C" void INTMODULE_TIMER_DMA_IRQHandler()
{
stm32_pulse_dma_tc_isr(&intmoduleTimer);
}
#if !defined(INTMODULE_TIMER_IRQHandler)
#error "Missing INTMODULE_TIMER_IRQHandler definition"
#endif
extern "C" void INTMODULE_TIMER_IRQHandler()
{
stm32_pulse_tim_update_isr(&intmoduleTimer);
}
DEFINE_STM32_SOFTSERIAL_PORT(InternalModule, intmoduleTimer);
#endif
#include "module_timer_driver.h"
#include "extmodule_driver.h"
#if defined(HARDWARE_EXTERNAL_MODULE)
#if defined(EXTMODULE_USART)
@ -135,6 +176,49 @@ DEFINE_STM32_SERIAL_PORT(ExternalModule, extmoduleUSART, INTMODULE_FIFO_SIZE, 0)
#endif
static stm32_pulse_dma_tc_cb_t _ext_timer_DMA_TC_Callback;
static const stm32_pulse_timer_t extmoduleTimer = {
.GPIOx = EXTMODULE_TX_GPIO,
.GPIO_Pin = EXTMODULE_TX_GPIO_PIN,
.GPIO_Alternate = EXTMODULE_TIMER_TX_GPIO_AF,
.TIMx = EXTMODULE_TIMER,
.TIM_Freq = EXTMODULE_TIMER_FREQ,
.TIM_Channel = EXTMODULE_TIMER_Channel,
.TIM_IRQn = EXTMODULE_TIMER_IRQn,
.DMAx = EXTMODULE_TIMER_DMA,
.DMA_Stream = EXTMODULE_TIMER_DMA_STREAM_LL,
.DMA_Channel = EXTMODULE_TIMER_DMA_CHANNEL,
.DMA_IRQn = EXTMODULE_TIMER_DMA_STREAM_IRQn,
.DMA_TC_CallbackPtr = &_ext_timer_DMA_TC_Callback,
};
// Make sure the timer channel is supported
static_assert(__STM32_PULSE_IS_TIMER_CHANNEL_SUPPORTED(EXTMODULE_TIMER_Channel),
"Unsupported timer channel");
// Make sure the DMA channel is supported
static_assert(__STM32_PULSE_IS_DMA_STREAM_SUPPORTED(EXTMODULE_TIMER_DMA_STREAM_LL),
"Unsupported DMA stream");
#if !defined(EXTMODULE_TIMER_DMA_IRQHandler)
#error "Missing EXTMODULE_TIMER_DMA_IRQHandler definition"
#endif
extern "C" void EXTMODULE_TIMER_DMA_IRQHandler()
{
stm32_pulse_dma_tc_isr(&extmoduleTimer);
}
#if !defined(EXTMODULE_TIMER_IRQHandler)
#error "Missing EXTMODULE_TIMER_IRQHandler definition"
#endif
extern "C" void EXTMODULE_TIMER_IRQHandler()
{
stm32_pulse_tim_update_isr(&extmoduleTimer);
}
DEFINE_STM32_SOFTSERIAL_PORT(ExternalModule, extmoduleTimer);
#endif

View file

@ -0,0 +1,110 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* 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 "hal/switch_driver.h"
#include "stm32_switch_driver.h"
#include "stm32_gpio_driver.h"
#include "definitions.h"
#include "opentx_constants.h"
#include "myeeprom.h"
// generated switch structs
#include "stm32_switches.inc"
#include <stdlib.h>
void switchInit()
{
_init_switches();
}
swconfig_t switchGetDefaultConfig()
{
return _switch_default_config;
}
switch_display_pos_t switchGetDisplayPosition(uint8_t idx)
{
if (idx >= DIM(_switch_display))
return {0, 0};
return _switch_display[idx];
}
uint8_t switchGetMaxSwitches()
{
return n_switches;
}
uint8_t getSwitchCount()
{
int count = 0;
for (int i = 0; i < switchGetMaxSwitches(); ++i) {
if (SWITCH_EXISTS(i)) {
++count;
}
}
return count;
}
uint8_t switchGetMaxRow(uint8_t col)
{
uint8_t lastrow = 0;
for (int i = 0; i < switchGetMaxSwitches(); ++i) {
if (SWITCH_EXISTS(i)) {
auto switch_display = switchGetDisplayPosition(i);
if (switch_display.col == col)
lastrow = switch_display.row > lastrow ? switch_display.row : lastrow;
}
}
return lastrow;
}
uint8_t switchGetMaxFctSwitches()
{
return n_fct_switches;
}
// returns state (0 / 1) of a specific switch position
uint32_t switchState(uint8_t pos_idx)
{
auto d = div(pos_idx, 3);
return stm32_switch_get_state(&_switch_defs[d.quot], (SwitchHwPos)d.rem);
}
SwitchHwPos switchGetPosition(uint8_t idx)
{
if (idx >= n_total_switches) return SWITCH_HW_UP;
return stm32_switch_get_position(&_switch_defs[idx]);
}
const char* switchGetName(uint8_t idx)
{
if (idx >= n_total_switches) return "";
return _switch_defs[idx].name;
}
SwitchHwType switchGetHwType(uint8_t idx)
{
if (idx >= n_total_switches) return SWITCH_HW_2POS;
return _switch_defs[idx].type;
}

View file

@ -25,11 +25,13 @@
#include "opentx.h"
#include "diskio.h"
#include "timers_driver.h"
#include "watchdog_driver.h"
#if defined(BLUETOOTH)
#include "bluetooth_driver.h"
#endif
#include "hal/adc_driver.h"
#include "hal/module_port.h"
#include "tasks.h"
@ -1254,6 +1256,9 @@ void printAudioVars()
#endif
#if defined(DEBUG)
#include "hal/switch_driver.h"
int cliDisplay(const char ** argv)
{
long long int address = 0;
@ -1266,32 +1271,32 @@ int cliDisplay(const char ** argv)
}
if (!strcmp(argv[1], "keys")) {
for (int i=0; i<TRM_BASE; i++) {
cliSerialPrint("[%s] = %s", STR_VKEYS[i]+1, keys[i].state() ? "on" : "off");
for (int i = 0; i <= MAX_KEYS; i++) {
if (keysGetSupported() & (1 << i)) {
cliSerialPrint("[Key %s] = %s",
keysGetLabel((EnumKeys)i),
keysGetState(i) ? "on" : "off");
}
#if defined(ROTARY_ENCODER_NAVIGATION)
typedef int32_t rotenc_t;
extern volatile rotenc_t rotencValue;
cliSerialPrint("[Enc.] = %d", rotencValue / ROTARY_ENCODER_GRANULARITY);
#endif
for (int i=TRM_BASE; i<=TRM_LAST; i++) {
cliSerialPrint("[Trim%d] = %s", i-TRM_BASE, keys[i].state() ? "on" : "off");
}
for (int i=MIXSRC_FIRST_SWITCH; i<=MIXSRC_LAST_SWITCH; i++) {
mixsrc_t sw = i - MIXSRC_FIRST_SWITCH;
if (SWITCH_EXISTS(sw)) {
static const char * const SWITCH_POSITIONS[] = { "down", "mid", "up" };
cliSerialPrint("[%s] = %s", STR_VSWITCHES[sw]+1, SWITCH_POSITIONS[1 + getValue(i) / 1024]);
for (int i = 0; i < keysGetMaxTrims(); i++) {
cliSerialPrint("[Trim %s] = %s", getTrimLabel(i),
keysGetTrimState(i) ? "on" : "off");
}
for (int i = 0; i < switchGetMaxSwitches(); i++) {
if (SWITCH_EXISTS(i)) {
static const char * const SWITCH_POSITIONS[] = { "up", "mid", "down" };
auto pos = switchGetPosition(i);
cliSerialPrint("[%s] = %s", switchGetName(i), SWITCH_POSITIONS[pos]);
}
}
}
else if (!strcmp(argv[1], "adc")) {
for (int i=0; i<NUM_ANALOGS; i++) {
cliSerialPrint("adc[%d] = %04X", i, (int)adcValues[i]);
for (int i = 0; i < adcGetMaxInputs(ADC_INPUT_ALL); i++) {
cliSerialPrint("adc[%d] = %04X", i, getAnalogValue(i));
}
}
else if (!strcmp(argv[1], "outputs")) {
for (int i=0; i<MAX_OUTPUT_CHANNELS; i++) {
for (int i = 0; i < MAX_OUTPUT_CHANNELS; i++) {
cliSerialPrint("outputs[%d] = %04d", i, (int)channelOutputs[i]);
}
}
@ -1398,7 +1403,7 @@ int cliDebugVars(const char ** argv)
cliSerialPrint("authenticateFrames=%d", authenticateFrames);
#endif
#elif defined(PCBTARANIS)
cliSerialPrint("telemetryErrors=%d", telemetryErrors);
//cliSerialPrint("telemetryErrors=%d", telemetryErrors);
#endif
return 0;
@ -1436,11 +1441,13 @@ int cliRepeat(const char ** argv)
int cliShowJitter(const char ** argv)
{
cliSerialPrint( "# anaIn rawJ avgJ");
for (int i=0; i<NUM_ANALOGS; i++) {
cliSerialPrint("A%02d %04X %04X %3d %3d", i, getAnalogValue(i), anaIn(i), rawJitter[i].get(), avgJitter[i].get());
if (IS_POT_MULTIPOS(i)) {
StepsCalibData * calib = (StepsCalibData *) &g_eeGeneral.calib[i];
for (int j=0; j<calib->count; j++) {
for (int i = 0; i < MAX_ANALOG_INPUTS; i++) {
cliSerialPrint("A%02d %04X %04X %3d %3d", i, getAnalogValue(i), anaIn(i),
rawJitter[i].get(), avgJitter[i].get());
if (i >= MAX_STICKS && IS_POT_MULTIPOS(i - MAX_STICKS)) {
StepsCalibData *calib = (StepsCalibData *)&g_eeGeneral.calib[i];
for (int j = 0; j < calib->count; j++) {
cliSerialPrint(" s%d %04X", j, calib->steps[j]);
}
}

View file

@ -25,7 +25,6 @@
#include "board.h"
#include "storage/yaml/yaml_defs.h"
#define NUM_STICKS 4
#if defined(EXPORT)
#define LUA_EXPORT(...) LEXP(__VA_ARGS__)
@ -136,12 +135,7 @@ enum CurveType {
#define MAX_CURVE_POINTS 512
#endif
// TODO: remove this
#if defined(PCBFRSKY) || defined(PCBNV14)
#define NUM_MODULES 2
#else
#define NUM_MODULES 1
#endif
#define NUM_MODULES 2
#define XPOTS_MULTIPOS_COUNT 6
@ -315,11 +309,6 @@ enum TelemetryUnit {
UNIT_KM,
UNIT_DBM,
UNIT_MAX = UNIT_DBM,
UNIT_SPARE6,
UNIT_SPARE7,
UNIT_SPARE8,
UNIT_SPARE9,
UNIT_SPARE10,
UNIT_HOURS,
UNIT_MINUTES,
UNIT_SECONDS,
@ -339,6 +328,7 @@ enum TelemetryUnit {
UNIT_DATETIME_SEC
};
// TODO: move to stdlcd UI
#if LCD_W >= 212
#define NUM_LINE_ITEMS 3
#else
@ -360,9 +350,14 @@ enum TelemetryScreenType {
TELEMETRY_SCREEN_TYPE_MAX = TELEMETRY_SCREEN_TYPE_BARS
#endif
};
#define MAX_TELEMETRY_SCREENS 4
#define TELEMETRY_SCREEN_TYPE(screenIndex) TelemetryScreenType((g_model.screensType >> (2*(screenIndex))) & 0x03)
#define IS_BARS_SCREEN(screenIndex) (TELEMETRY_SCREEN_TYPE(screenIndex) == TELEMETRY_SCREEN_TYPE_BARS)
#define TELEMETRY_SCREEN_TYPE(screenIndex) \
TelemetryScreenType((g_model.screensType >> (2 * (screenIndex))) & 0x03)
#define IS_BARS_SCREEN(screenIndex) \
(TELEMETRY_SCREEN_TYPE(screenIndex) == TELEMETRY_SCREEN_TYPE_BARS)
constexpr int16_t FAILSAFE_CHANNEL_HOLD = 2000;
constexpr int16_t FAILSAFE_CHANNEL_NOPULSE = 2001;
@ -382,161 +377,47 @@ enum PotsWarnMode {
#define GVAR_MAX 1024
#define GVAR_MIN -GVAR_MAX
// we reserve the space inside the range of values, like offset, weight, etc.
#define RESERVE_RANGE_FOR_GVARS 10
// even we do not spend space in EEPROM for 10 GVARS, we reserve the space inside the range of values, like offset, weight, etc.
#define MAX_GVARS 9
// Maximum number analog inputs by type
#define MAX_STICKS 4
#if defined(COLORLCD)
#define MAX_POTS 16
#define MAX_AXIS 2
#else
#define MAX_POTS 8
#define MAX_AXIS 0
#endif
#define MAX_VBAT 1
#define MAX_RTC_BAT 1
#define MAX_ANALOG_INPUTS (MAX_STICKS + MAX_POTS + MAX_AXIS + MAX_VBAT + MAX_RTC_BAT)
#define MAX_CALIB_ANALOG_INPUTS (MAX_STICKS + MAX_POTS + MAX_AXIS)
#define MAX_SWITCHES 20
#define MAX_TRIMS 6
#define MAX_XPOTS_POSITIONS (MAX_POTS * XPOTS_MULTIPOS_COUNT)
enum SwitchSources {
SWSRC_NONE = 0,
SWSRC_FIRST_SWITCH SKIP,
SWSRC_LAST_SWITCH SKIP = SWSRC_FIRST_SWITCH + (MAX_SWITCHES * 3) - 1,
#if defined(STORAGE_SWITCH_A)
SWSRC_SA0 = SWSRC_FIRST_SWITCH,
SWSRC_SA1,
SWSRC_SA2,
#endif
#if defined(STORAGE_SWITCH_B)
SWSRC_SB0,
SWSRC_SB1,
SWSRC_SB2,
#endif
#if defined(STORAGE_SWITCH_C)
SWSRC_SC0,
SWSRC_SC1,
SWSRC_SC2,
#endif
#if defined(STORAGE_SWITCH_D)
SWSRC_SD0,
SWSRC_SD1,
SWSRC_SD2,
#endif
#if defined(FUNCTION_SWITCHES) && defined(RADIO_TPRO)
SWSRC_FIRST_FUNCTION_SWITCH SKIP,
SWSRC_SE0 = SWSRC_FIRST_FUNCTION_SWITCH,
SWSRC_SE1,
SWSRC_SE2,
#elif defined(STORAGE_SWITCH_E)
SWSRC_SE0,
SWSRC_SE1,
SWSRC_SE2,
#endif
#if defined(STORAGE_SWITCH_F)
SWSRC_SF0,
SWSRC_SF1,
SWSRC_SF2,
#endif
#if defined(STORAGE_SWITCH_G)
SWSRC_SG0,
SWSRC_SG1,
SWSRC_SG2,
#endif
#if defined(STORAGE_SWITCH_H)
SWSRC_SH0,
SWSRC_SH1,
SWSRC_SH2,
#endif
#if defined(STORAGE_SWITCH_I)
SWSRC_SI0,
SWSRC_SI1,
SWSRC_SI2,
#endif
#if defined(STORAGE_SWITCH_J)
SWSRC_SJ0,
SWSRC_SJ1,
SWSRC_SJ2,
#endif
#if defined(STORAGE_SWITCH_K)
SWSRC_SK0,
SWSRC_SK1,
SWSRC_SK2,
#endif
#if defined(STORAGE_SWITCH_L)
SWSRC_SL0,
SWSRC_SL1,
SWSRC_SL2,
#endif
#if defined(STORAGE_SWITCH_M)
SWSRC_SM0,
SWSRC_SM1,
SWSRC_SM2,
#endif
#if defined(STORAGE_SWITCH_N)
SWSRC_SN0,
SWSRC_SN1,
SWSRC_SN2,
#endif
#if defined(STORAGE_SWITCH_O)
SWSRC_SO0,
SWSRC_SO1,
SWSRC_SO2,
#endif
#if defined(STORAGE_SWITCH_P)
SWSRC_SP0,
SWSRC_SP1,
SWSRC_SP2,
#endif
#if defined(STORAGE_SWITCH_Q)
SWSRC_SQ0,
SWSRC_SQ1,
SWSRC_SQ2,
#endif
#if defined(STORAGE_SWITCH_R)
SWSRC_SR0,
SWSRC_SR1,
SWSRC_SR2,
#endif
SWSRC_LAST_SWITCH SKIP = SWSRC_FIRST_SWITCH + STORAGE_NUM_SWITCHES_POSITIONS - 1,
#if NUM_XPOTS > 0
SWSRC_FIRST_MULTIPOS_SWITCH SKIP,
SWSRC_LAST_MULTIPOS_SWITCH SKIP = SWSRC_FIRST_MULTIPOS_SWITCH + (NUM_XPOTS * XPOTS_MULTIPOS_COUNT) - 1,
#endif
SWSRC_LAST_MULTIPOS_SWITCH SKIP = SWSRC_FIRST_MULTIPOS_SWITCH + MAX_XPOTS_POSITIONS - 1,
SWSRC_FIRST_TRIM SKIP,
SWSRC_TrimRudLeft = SWSRC_FIRST_TRIM,
SWSRC_TrimRudRight,
SWSRC_TrimEleDown,
SWSRC_TrimEleUp,
#if NUM_TRIMS > 2
SWSRC_TrimThrDown,
SWSRC_TrimThrUp,
SWSRC_TrimAilLeft,
SWSRC_TrimAilRight,
#endif
#if NUM_TRIMS > 4
SWSRC_TrimT5Down,
SWSRC_TrimT5Up,
SWSRC_TrimT6Down,
SWSRC_TrimT6Up,
#endif
SWSRC_LAST_TRIM SKIP = SWSRC_FIRST_TRIM + 2 * MAX_TRIMS - 1,
SWSRC_FIRST_LOGICAL_SWITCH SKIP,
SWSRC_SW1 = SWSRC_FIRST_LOGICAL_SWITCH,
SWSRC_SW2,
// ...
SWSRC_LAST_LOGICAL_SWITCH SKIP = SWSRC_FIRST_LOGICAL_SWITCH+MAX_LOGICAL_SWITCHES-1,
SWSRC_LAST_LOGICAL_SWITCH SKIP = SWSRC_FIRST_LOGICAL_SWITCH + MAX_LOGICAL_SWITCHES - 1,
SWSRC_ON,
SWSRC_ONE,
@ -571,247 +452,100 @@ enum SwitchSources {
SWSRC_INVERT SKIP = SWSRC_COUNT+1,
};
#if NUM_SWITCHES - NUM_FUNCTIONS_SWITCHES >= 8
#define SWSRC_TRAINER SWSRC_SH2
#else
#define SWSRC_TRAINER SWSRC_LAST_SWITCH,
#endif
#define SWSRC_LAST_TRIM (SWSRC_FIRST_TRIM + 2 * NUM_TRIMS - 1)
enum MixSources {
MIXSRC_NONE,
MIXSRC_FIRST_INPUT SKIP, LUA_EXPORT_MULTIPLE("input", "Input [I%d]", MAX_INPUTS)
MIXSRC_LAST_INPUT SKIP = MIXSRC_FIRST_INPUT+MAX_INPUTS-1,
MIXSRC_FIRST SKIP,
MIXSRC_FIRST_INPUT SKIP = MIXSRC_FIRST,
MIXSRC_LAST_INPUT SKIP = MIXSRC_FIRST_INPUT + MAX_INPUTS - 1,
#if defined(LUA_INPUTS)
MIXSRC_FIRST_LUA SKIP, LUA_EXPORT_MULTIPLE("lua", "Lua mix output %d", MAX_SCRIPTS*MAX_SCRIPT_OUTPUTS)
MIXSRC_LAST_LUA SKIP = MIXSRC_FIRST_LUA+(MAX_SCRIPTS*MAX_SCRIPT_OUTPUTS)-1,
MIXSRC_FIRST_LUA SKIP,
MIXSRC_LAST_LUA SKIP = MIXSRC_FIRST_LUA + (MAX_SCRIPTS * MAX_SCRIPT_OUTPUTS) - 1,
#endif
// Semantic sticks
MIXSRC_FIRST_STICK SKIP,
MIXSRC_Rud = MIXSRC_FIRST_STICK, LUA_EXPORT("rud", "Rudder")
MIXSRC_Ele, LUA_EXPORT("ele", "Elevator")
MIXSRC_Thr, LUA_EXPORT("thr", "Throttle")
MIXSRC_Ail, LUA_EXPORT("ail", "Aileron")
MIXSRC_LAST_STICK SKIP = MIXSRC_FIRST_STICK + MAX_STICKS - 1,
MIXSRC_LAST_STICK SKIP = MIXSRC_Ail,
MIXSRC_FIRST_POT SKIP,
#if defined(PCBHORUS)
MIXSRC_S1 = MIXSRC_FIRST_POT, LUA_EXPORT("s1", "Potentiometer S1")
MIXSRC_6POS, LUA_EXPORT("6pos", "Multipos Switch")
MIXSRC_S2, LUA_EXPORT("s2", "Potentiometer S2")
#if defined(PCBX10)
MIXSRC_EXT1, LUA_EXPORT("ext1", "Ext 1")
MIXSRC_EXT2, LUA_EXPORT("ext2", "Ext 2")
MIXSRC_EXT3, LUA_EXPORT("ext3", "Ext 3")
MIXSRC_EXT4, LUA_EXPORT("ext4", "Ext 4")
#endif
MIXSRC_FIRST_SLIDER SKIP,
#if defined(PCBX12S)
MIXSRC_S3 = MIXSRC_FIRST_SLIDER, LUA_EXPORT("s3", "Slider S3")
MIXSRC_S4, LUA_EXPORT("s4", "Slider S4")
MIXSRC_LS, LUA_EXPORT("ls", "Left rear slider")
MIXSRC_RS, LUA_EXPORT("rs", "Right rear slider")
#else
MIXSRC_LS = MIXSRC_FIRST_SLIDER, LUA_EXPORT("ls", "Left slider")
MIXSRC_RS, LUA_EXPORT("rs", "Right slider")
#endif
MIXSRC_LAST_POT SKIP = MIXSRC_RS,
#elif defined(PCBX9E)
MIXSRC_POT1 = MIXSRC_FIRST_POT, LUA_EXPORT("s1", "Potentiometer 1")
MIXSRC_POT2, LUA_EXPORT("s2", "Potentiometer 2")
MIXSRC_POT3, LUA_EXPORT("s3", "Potentiometer 3")
MIXSRC_POT4, LUA_EXPORT("s4", "Potentiometer 4 (X9E only)")
MIXSRC_FIRST_SLIDER SKIP,
MIXSRC_SLIDER1 = MIXSRC_FIRST_SLIDER, LUA_EXPORT("ls", "Left slider")
MIXSRC_SLIDER2, LUA_EXPORT("rs", "Right slider")
MIXSRC_SLIDER3, LUA_EXPORT("lcs", "Left center slider (X9E only)")
MIXSRC_SLIDER4, LUA_EXPORT("rcs", "Right center slider (X9E only)")
MIXSRC_LAST_POT SKIP = MIXSRC_SLIDER4,
#elif defined(RADIO_BOXER)
MIXSRC_POT1 = MIXSRC_FIRST_POT, LUA_EXPORT("s1", "Potentiometer 1")
MIXSRC_POT2, LUA_EXPORT("s2", "Potentiometer 2")
MIXSRC_POT3, LUA_EXPORT("s3", "6 POS")
MIXSRC_FIRST_SLIDER SKIP = MIXSRC_POT3,
MIXSRC_LAST_POT SKIP = MIXSRC_POT3,
#elif defined(PCBX7) || defined(PCBXLITE) || defined(PCBNV14)
MIXSRC_POT1 = MIXSRC_FIRST_POT, LUA_EXPORT("s1", "Potentiometer 1")
MIXSRC_POT2, LUA_EXPORT("s2", "Potentiometer 2")
MIXSRC_FIRST_SLIDER SKIP = MIXSRC_POT2,
MIXSRC_LAST_POT SKIP = MIXSRC_POT2,
#elif defined(PCBX9LITE)
MIXSRC_POT1 = MIXSRC_FIRST_POT, LUA_EXPORT("s1", "Potentiometer 1")
MIXSRC_FIRST_SLIDER SKIP = MIXSRC_POT1,
MIXSRC_LAST_POT SKIP = MIXSRC_POT1,
#elif defined(PCBTARANIS)
MIXSRC_POT1 = MIXSRC_FIRST_POT, LUA_EXPORT("s1", "Potentiometer 1")
MIXSRC_POT2, LUA_EXPORT("s2", "Potentiometer 2")
MIXSRC_POT3, LUA_EXPORT("s3", "Potentiometer 3")
MIXSRC_FIRST_SLIDER SKIP,
MIXSRC_SLIDER1 = MIXSRC_FIRST_SLIDER, LUA_EXPORT("ls", "Left slider")
MIXSRC_SLIDER2, LUA_EXPORT("rs", "Right slider")
MIXSRC_LAST_POT SKIP = MIXSRC_SLIDER2,
#else
MIXSRC_P1 = MIXSRC_FIRST_POT,
MIXSRC_P2,
MIXSRC_P3,
MIXSRC_LAST_POT SKIP = MIXSRC_P3,
#endif
MIXSRC_LAST_POT SKIP = MIXSRC_FIRST_POT + MAX_POTS - 1,
#if defined(PCBHORUS)
MIXSRC_MOUSE1, LUA_EXPORT("jsx", "Joystick X")
MIXSRC_MOUSE2, LUA_EXPORT("jsy", "Joystick Y")
#if MAX_AXIS > 0
MIXSRC_FIRST_AXIS SKIP,
MIXSRC_LAST_AXIS SKIP = MIXSRC_FIRST_AXIS + MAX_AXIS - 1,
#endif
#if defined(IMU)
MIXSRC_TILT_X, LUA_EXPORT("tiltx", "Tilt X")
MIXSRC_TILT_Y, LUA_EXPORT("tilty", "Tilt Y")
MIXSRC_TILT_X,
MIXSRC_TILT_Y,
#endif
#if defined(PCBHORUS)
MIXSRC_FIRST_SPACEMOUSE SKIP,
MIXSRC_SPACEMOUSE_A = MIXSRC_FIRST_SPACEMOUSE, LUA_EXPORT("sma", "SpaceMouse A")
MIXSRC_SPACEMOUSE_B, LUA_EXPORT("smb", "SpaceMouse B")
MIXSRC_SPACEMOUSE_C, LUA_EXPORT("smc", "SpaceMouse C")
MIXSRC_SPACEMOUSE_D, LUA_EXPORT("smd", "SpaceMouse D")
MIXSRC_SPACEMOUSE_E, LUA_EXPORT("sme", "SpaceMouse E")
MIXSRC_SPACEMOUSE_F, LUA_EXPORT("smf", "SpaceMouse F")
MIXSRC_SPACEMOUSE_A = MIXSRC_FIRST_SPACEMOUSE,
MIXSRC_SPACEMOUSE_B,
MIXSRC_SPACEMOUSE_C,
MIXSRC_SPACEMOUSE_D,
MIXSRC_SPACEMOUSE_E,
MIXSRC_SPACEMOUSE_F,
MIXSRC_LAST_SPACEMOUSE SKIP = MIXSRC_SPACEMOUSE_F,
#endif
MIXSRC_MAX, LUA_EXPORT("max", "MAX")
MIXSRC_MAX,
MIXSRC_FIRST_HELI SKIP,
MIXSRC_CYC1 = MIXSRC_FIRST_HELI, LUA_EXPORT("cyc1", "Cyclic 1")
MIXSRC_CYC2, LUA_EXPORT("cyc2", "Cyclic 2")
MIXSRC_CYC3, LUA_EXPORT("cyc3", "Cyclic 3")
MIXSRC_LAST_HELI SKIP = MIXSRC_CYC3,
MIXSRC_LAST_HELI SKIP = MIXSRC_FIRST_HELI + 2,
MIXSRC_FIRST_TRIM SKIP,
MIXSRC_TrimRud = MIXSRC_FIRST_TRIM, LUA_EXPORT("trim-rud", "Rudder trim")
MIXSRC_TrimEle, LUA_EXPORT("trim-ele", "Elevator trim")
MIXSRC_TrimThr, LUA_EXPORT("trim-thr", "Throttle trim")
MIXSRC_TrimAil, LUA_EXPORT("trim-ail", "Aileron trim")
#if defined(PCBHORUS)
MIXSRC_TrimT5, LUA_EXPORT("trim-t5", "Aux trim T5")
MIXSRC_TrimT6, LUA_EXPORT("trim-t6", "Aux trim T6")
MIXSRC_TrimRud = MIXSRC_FIRST_TRIM,
MIXSRC_TrimEle,
MIXSRC_TrimThr,
MIXSRC_TrimAil,
//#if defined(PCBHORUS)
MIXSRC_TrimT5,
MIXSRC_TrimT6,
MIXSRC_LAST_TRIM SKIP = MIXSRC_TrimT6,
#else
MIXSRC_LAST_TRIM SKIP = MIXSRC_TrimAil,
#endif
//#else
//MIXSRC_LAST_TRIM SKIP = MIXSRC_TrimAil,
//#endif
MIXSRC_FIRST_SWITCH SKIP,
MIXSRC_LAST_SWITCH SKIP = MIXSRC_FIRST_SWITCH + MAX_SWITCHES - 1,
#if defined(HARDWARE_SWITCH_A)
MIXSRC_SA = MIXSRC_FIRST_SWITCH, LUA_EXPORT("sa", "Switch A")
MIXSRC_SB, LUA_EXPORT("sb", "Switch B")
MIXSRC_SC, LUA_EXPORT("sc", "Switch C")
#endif
#if defined(HARDWARE_SWITCH_D)
MIXSRC_SD, LUA_EXPORT("sd", "Switch D")
#elif defined(STORAGE_SWITCH_D)
MIXSRC_SD,
#endif
#if defined(HARDWARE_SWITCH_E)
MIXSRC_SE, LUA_EXPORT("se", "Switch E")
#elif defined(STORAGE_SWITCH_E)
MIXSRC_SE,
#endif
#if defined(HARDWARE_SWITCH_F)
MIXSRC_SF, LUA_EXPORT("sf", "Switch F")
#elif defined(STORAGE_SWITCH_F)
MIXSRC_SF,
#endif
#if defined(HARDWARE_SWITCH_G)
MIXSRC_SG, LUA_EXPORT("sg", "Switch G")
#elif defined(STORAGE_SWITCH_G)
MIXSRC_SG,
#endif
#if defined(HARDWARE_SWITCH_H)
MIXSRC_SH, LUA_EXPORT("sh", "Switch H")
#elif defined(STORAGE_SWITCH_H)
MIXSRC_SH,
#endif
#if defined(HARDWARE_SWITCH_I)
MIXSRC_SI, LUA_EXPORT("si", "Switch I")
#elif defined(STORAGE_SWITCH_I)
MIXSRC_SI,
#endif
#if defined(HARDWARE_SWITCH_J)
MIXSRC_SJ, LUA_EXPORT("sj", "Switch J")
#elif defined(STORAGE_SWITCH_J)
MIXSRC_SJ,
#endif
#if defined(HARDWARE_SWITCH_K)
MIXSRC_SK, LUA_EXPORT("sk", "Switch K")
MIXSRC_SL, LUA_EXPORT("sl", "Switch L")
MIXSRC_SM, LUA_EXPORT("sm", "Switch M")
MIXSRC_SN, LUA_EXPORT("sn", "Switch N")
MIXSRC_SO, LUA_EXPORT("so", "Switch O")
MIXSRC_SP, LUA_EXPORT("sp", "Switch P")
MIXSRC_SQ, LUA_EXPORT("sq", "Switch Q")
MIXSRC_SR, LUA_EXPORT("sr", "Switch R")
#endif
MIXSRC_FIRST_LOGICAL_SWITCH SKIP,
MIXSRC_SW1 = MIXSRC_FIRST_LOGICAL_SWITCH, LUA_EXPORT_MULTIPLE("ls", "Logical switch L%d", MAX_LOGICAL_SWITCHES)
MIXSRC_LAST_LOGICAL_SWITCH SKIP = MIXSRC_FIRST_LOGICAL_SWITCH+MAX_LOGICAL_SWITCHES-1,
MIXSRC_LAST_LOGICAL_SWITCH SKIP = MIXSRC_FIRST_LOGICAL_SWITCH + MAX_LOGICAL_SWITCHES - 1,
MIXSRC_FIRST_TRAINER SKIP, LUA_EXPORT_MULTIPLE("trn", "Trainer input %d", MAX_TRAINER_CHANNELS)
MIXSRC_LAST_TRAINER SKIP = MIXSRC_FIRST_TRAINER+MAX_TRAINER_CHANNELS-1,
MIXSRC_FIRST_TRAINER SKIP,
MIXSRC_LAST_TRAINER SKIP = MIXSRC_FIRST_TRAINER + MAX_TRAINER_CHANNELS - 1,
MIXSRC_FIRST_CH SKIP,
MIXSRC_CH1 = MIXSRC_FIRST_CH, LUA_EXPORT_MULTIPLE("ch", "Channel CH%d", MAX_OUTPUT_CHANNELS)
MIXSRC_CH2,
MIXSRC_CH3,
MIXSRC_CH4,
MIXSRC_CH5,
MIXSRC_CH6,
MIXSRC_CH7,
MIXSRC_CH8,
MIXSRC_CH9,
MIXSRC_CH10,
MIXSRC_CH11,
MIXSRC_CH12,
MIXSRC_CH13,
MIXSRC_CH14,
MIXSRC_CH15,
MIXSRC_CH16,
MIXSRC_LAST_CH SKIP = MIXSRC_CH1+MAX_OUTPUT_CHANNELS-1,
MIXSRC_LAST_CH SKIP = MIXSRC_FIRST_CH + MAX_OUTPUT_CHANNELS - 1,
MIXSRC_FIRST_GVAR SKIP,
MIXSRC_GVAR1 = MIXSRC_FIRST_GVAR, LUA_EXPORT_MULTIPLE("gvar", "Global variable %d", MAX_GVARS)
MIXSRC_LAST_GVAR SKIP = MIXSRC_FIRST_GVAR+MAX_GVARS-1,
MIXSRC_LAST_GVAR SKIP = MIXSRC_FIRST_GVAR + MAX_GVARS - 1,
MIXSRC_TX_VOLTAGE, LUA_EXPORT("tx-voltage", "Transmitter battery voltage [volts]")
MIXSRC_TX_TIME, LUA_EXPORT("clock", "RTC clock [minutes from midnight]")
MIXSRC_TX_VOLTAGE,
MIXSRC_TX_TIME,
MIXSRC_TX_GPS,
MIXSRC_FIRST_RESERVE SKIP,
MIXSRC_RESERVE3 SKIP,
MIXSRC_RESERVE4 SKIP,
MIXSRC_LAST_RESERVE SKIP,
MIXSRC_FIRST_TIMER SKIP,
MIXSRC_TIMER1 = MIXSRC_FIRST_TIMER, LUA_EXPORT("timer1", "Timer 1 value [seconds]")
MIXSRC_TIMER2, LUA_EXPORT("timer2", "Timer 2 value [seconds]")
MIXSRC_TIMER3, LUA_EXPORT("timer3", "Timer 3 value [seconds]")
MIXSRC_LAST_TIMER SKIP = MIXSRC_TIMER3,
MIXSRC_FIRST_TELEM SKIP, LUA_EXPORT_MULTIPLE("telem", "Telemetry sensor %d", MAX_TELEMETRY_SENSORS)
MIXSRC_LAST_TELEM SKIP = MIXSRC_FIRST_TELEM+3*MAX_TELEMETRY_SENSORS-1
MIXSRC_FIRST_TIMER SKIP,
MIXSRC_LAST_TIMER SKIP = MIXSRC_FIRST_TIMER + MAX_TIMERS - 1,
MIXSRC_FIRST_TELEM SKIP,
MIXSRC_LAST_TELEM SKIP = MIXSRC_FIRST_TELEM + 3 * MAX_TELEMETRY_SENSORS - 1,
};
#if defined(__cplusplus)
static_assert(MIXSRC_FIRST_LOGICAL_SWITCH == MIXSRC_FIRST_SWITCH + STORAGE_NUM_SWITCHES, "Wrong switches definition in MIXSRC list");
#endif
#define MIXSRC_FIRST (MIXSRC_NONE + 1)
#define MIXSRC_LAST MIXSRC_LAST_CH
#define MIXSRC_LAST_SWITCH (MIXSRC_FIRST_SWITCH + STORAGE_NUM_SWITCHES - 1)
#define INPUTSRC_FIRST MIXSRC_Rud
#define INPUTSRC_FIRST MIXSRC_FIRST_STICK
#define INPUTSRC_LAST MIXSRC_LAST_TELEM
// TODO: this won't work forever (what about ground radios?)
#define MIXSRC_Thr (MIXSRC_FIRST_STICK + 2)
#if defined(FUNCTION_SWITCHES)
#define MIXSRC_LAST_REGULAR_SWITCH (MIXSRC_FIRST_SWITCH + NUM_REGULAR_SWITCHES - 1)
#define MIXSRC_LAST_REGULAR_SWITCH (MIXSRC_FIRST_SWITCH + switchGetMaxSwitches() - 1)
#define MIXSRC_FIRST_FS_SWITCH (MIXSRC_LAST_REGULAR_SWITCH + 1)
#endif
@ -840,9 +574,7 @@ enum Functions {
FUNC_PLAY_SOUND = FUNC_FIRST_WITHOUT_ENABLE,
FUNC_PLAY_TRACK,
FUNC_PLAY_VALUE,
FUNC_RESERVE4,
FUNC_PLAY_SCRIPT,
FUNC_RESERVE5,
FUNC_BACKGND_MUSIC,
FUNC_BACKGND_MUSIC_PAUSE,
FUNC_VARIO,

View file

@ -53,7 +53,7 @@ static inline void check_struct()
CHKSIZE(LimitData, 11);
CHKSIZE(LogicalSwitchData, 9);
CHKSIZE(CustomFunctionData, 11);
CHKSIZE(FlightModeData, 28 + 2*NUM_TRIMS);
CHKSIZE(FlightModeData, 28 + 2 * MAX_TRIMS);
CHKSIZE(TimerData, 12);
CHKSIZE(SwashRingData, 8);
CHKSIZE(FrSkyBarData, 6);
@ -67,7 +67,7 @@ static inline void check_struct()
CHKSIZE(LimitData, 13);
CHKSIZE(LogicalSwitchData, 9);
CHKSIZE(CustomFunctionData, 11);
CHKSIZE(FlightModeData, 40);
CHKSIZE(FlightModeData, 44);
CHKSIZE(TimerData, 17);
CHKSIZE(SwashRingData, 8);
CHKSIZE(FrSkyBarData, 6);
@ -117,37 +117,37 @@ static inline void check_struct()
CHKSIZE(TrainerData, 16);
#if defined(PCBXLITES)
CHKSIZE(RadioData, 864);
CHKSIZE(ModelData, 6220);
CHKSIZE(RadioData, 872);
CHKSIZE(ModelData, 6265);
#elif defined(PCBXLITE)
CHKSIZE(RadioData, 862);
CHKSIZE(ModelData, 6220);
CHKSIZE(RadioData, 870);
CHKSIZE(ModelData, 6265);
#elif defined(RADIO_TPRO)
CHKSIZE(RadioData, 845);
CHKSIZE(ModelData, 6245);
CHKSIZE(RadioData, 859);
CHKSIZE(ModelData, 6292);
#elif defined(RADIO_BOXER)
CHKSIZE(RadioData, 877);
CHKSIZE(ModelData, 6221);
CHKSIZE(RadioData, 870);
CHKSIZE(ModelData, 6265);
#elif defined(PCBX7)
CHKSIZE(RadioData, 868);
CHKSIZE(ModelData, 6220);
CHKSIZE(RadioData, 870);
CHKSIZE(ModelData, 6265);
#elif defined(PCBX9E)
CHKSIZE(RadioData, 958);
CHKSIZE(ModelData, 6672);
CHKSIZE(RadioData, 870);
CHKSIZE(ModelData, 6707);
#elif defined(PCBX9D) || defined(PCBX9DP)
CHKSIZE(RadioData, 900);
CHKSIZE(ModelData, 6664);
CHKSIZE(RadioData, 870);
CHKSIZE(ModelData, 6706);
#elif defined(PCBHORUS)
#if defined(PCBX10)
CHKSIZE(RadioData, 952);
CHKSIZE(ModelData, 15454);
CHKSIZE(RadioData, 916);
CHKSIZE(ModelData, 15463);
#else
CHKSIZE(RadioData, 934);
CHKSIZE(ModelData, 15452);
CHKSIZE(RadioData, 916);
CHKSIZE(ModelData, 15463);
#endif
#elif defined(PCBNV14)
CHKSIZE(RadioData, 880);
CHKSIZE(ModelData, 15268);
CHKSIZE(RadioData, 916);
CHKSIZE(ModelData, 15319);
#endif
#undef CHKSIZE

View file

@ -30,6 +30,7 @@
#include "globals.h"
#include "serial.h"
#include "usb_joystick.h"
#include "input_mapping.h"
#if defined(PCBTARANIS)
#define N_TARANIS_FIELD(x)
@ -78,8 +79,8 @@ PACK(struct MixData {
uint16_t mixWarn:2; // mixer warning
uint16_t mltpx:2 ENUM(MixerMultiplex);
uint16_t spare:1 SKIP;
int32_t offset:14 CUST(in_read_weight,in_write_weight);
int32_t swtch:9 CUST(r_swtchSrc,w_swtchSrc);
int32_t offset:13 CUST(in_read_weight,in_write_weight);
int32_t swtch:10 CUST(r_swtchSrc,w_swtchSrc);
uint32_t flightModes:9 CUST(r_flightModes, w_flightModes);
CurveRef curve;
uint8_t delayUp;
@ -100,10 +101,9 @@ PACK(struct ExpoData {
int16_t trimSource:6;
uint16_t srcRaw:10 ENUM(MixSources) CUST(r_mixSrcRaw,w_mixSrcRaw);
uint32_t chn:5;
int32_t swtch:9 CUST(r_swtchSrc,w_swtchSrc);
int32_t swtch:10 CUST(r_swtchSrc,w_swtchSrc);
uint32_t flightModes:9 CUST(r_flightModes, w_flightModes);
int32_t weight:8 CUST(in_read_weight,in_write_weight);
int32_t spare:1 SKIP;
NOBACKUP(char name[LEN_EXPOMIX_NAME]);
int8_t offset CUST(in_read_weight,in_write_weight);
CurveRef curve;
@ -134,9 +134,9 @@ PACK(struct LogicalSwitchData {
CUST_ATTR(def,r_logicSw,w_logicSw);
int32_t v1:10 SKIP;
int32_t v3:10 SKIP;
int32_t andsw:9 CUST(r_swtchSrc,w_swtchSrc); // TODO rename to xswtch
int32_t andsw:10 CUST(r_swtchSrc,w_swtchSrc); // TODO rename to xswtch
uint32_t andswtype:1 SKIP; // TODO rename to xswtchType (AND / OR)
uint32_t spare:2 SKIP; // anything else needed?
uint32_t spare:1 SKIP; // anything else needed?
int16_t v2 SKIP;
uint8_t delay;
uint8_t duration;
@ -154,8 +154,8 @@ PACK(struct LogicalSwitchData {
#endif
PACK(struct CustomFunctionData {
int16_t swtch:9 CUST(r_swtchSrc,w_swtchSrc);
uint16_t func:7 ENUM(Functions);
int16_t swtch:10 CUST(r_swtchSrc,w_swtchSrc);
uint16_t func:6 ENUM(Functions); // TODO: 6 bits for Functions?
CUST_ATTR(def,r_customFn,w_customFn);
PACK(union {
NOBACKUP(PACK(struct {
@ -192,10 +192,11 @@ PACK(struct trim_t {
});
PACK(struct FlightModeData {
trim_t trim[NUM_TRIMS];
trim_t trim[MAX_TRIMS];
NOBACKUP(char name[LEN_FLIGHT_MODE_NAME]);
int16_t swtch:9 ENUM(SwitchSources) CUST(r_swtchSrc,w_swtchSrc); // swtch of phase[0] is not used
int16_t spare:7 SKIP;
// swtch of phase[0] is not used
int16_t swtch:10 ENUM(SwitchSources) CUST(r_swtchSrc,w_swtchSrc);
int16_t spare:6 SKIP;
uint8_t fadeIn;
uint8_t fadeOut;
gvar_t gvars[MAX_GVARS] FUNC(gvar_is_active);
@ -555,19 +556,20 @@ PACK(struct ModelHeader {
#endif
});
#if defined(COLORLCD)
typedef uint32_t swconfig_t;
typedef uint32_t swarnstate_t;
#elif defined(PCBX9E)
typedef uint64_t swconfig_t;
typedef uint64_t swarnstate_t;
#elif defined(PCBX9D) || defined(PCBX9DP)
typedef uint32_t swconfig_t;
typedef uint32_t swarnstate_t;
#else
typedef uint16_t swconfig_t;
typedef uint32_t swarnstate_t;
#endif
// 2 bits per switch, max 32 switches
static_assert(sizeof(swconfig_t) >= (MAX_SWITCHES * 2 + 7) / 8,
"MAX_SWITCHES must fit swconfig_t");
static_assert(sizeof(swarnstate_t) >= (MAX_SWITCHES * 2 + 7) / 8,
"MAX_SWITCHES must fit swarnstate_t");
// pot config: 4 bits per pot
static_assert(sizeof(potconfig_t) * 8 >= ((MAX_POTS - 1) / 4) + 1,
"MAX_POTS must fit potconfig_t");
// pot warning enabled: 1 bit per pot
static_assert(sizeof(potwarnen_t) * 8 >= MAX_POTS,
"MAX_POTS must fit potwarnen_t");
#if defined(COLORLCD) && defined(BACKUP)
#define CUSTOM_SCREENS_DATA
@ -606,7 +608,7 @@ PACK(struct CustomScreenData {
#define SCRIPT_DATA
#endif
#if defined(FUNCTION_SWITCHES) && NUM_FUNCTIONS_SWITCHES < 8
#if defined(FUNCTION_SWITCHES)
#define FUNCTION_SWITCHS_FIELDS \
uint16_t functionSwitchConfig; \
uint16_t functionSwitchGroup; \
@ -719,8 +721,8 @@ PACK(struct ModelData {
SCRIPT_DATA
NOBACKUP(char inputNames[MAX_INPUTS][LEN_INPUT_NAME]);
NOBACKUP(uint16_t potsWarnEnabled);
NOBACKUP(int8_t potsWarnPosition[STORAGE_NUM_POTS+STORAGE_NUM_SLIDERS]);
NOBACKUP(potwarnen_t potsWarnEnabled);
NOBACKUP(int8_t potsWarnPosition[MAX_POTS]);
NOBACKUP(TelemetrySensor telemetrySensors[MAX_TELEMETRY_SENSORS];)
@ -734,30 +736,26 @@ PACK(struct ModelData {
uint8_t getThrottleStickTrimSource() const
{
// The order here is TERA, so that 0 (default) means Throttle
switch (thrTrimSw) {
case 0:
return MIXSRC_TrimThr;
case 2:
return MIXSRC_TrimRud;
default:
return thrTrimSw + MIXSRC_FIRST_TRIM;
// Makes Throttle the default (=0)
auto thr = inputMappingGetThrottle();
if (thrTrimSw == 0) {
return MIXSRC_FIRST_TRIM + thr;
} else if (thrTrimSw == thr) {
return MIXSRC_FIRST_TRIM;
} else {
return MIXSRC_FIRST_TRIM + thrTrimSw;
}
}
void setThrottleStickTrimSource(int16_t src)
{
// The order here is TERA, so that 0 (default) means Throttle
switch (src) {
case MIXSRC_TrimThr:
auto thr = inputMappingGetThrottle();
if (src == MIXSRC_FIRST_TRIM + thr) {
thrTrimSw = 0;
break;
case MIXSRC_TrimRud:
thrTrimSw = 2;
break;
default:
} else if (src == MIXSRC_FIRST_TRIM) {
thrTrimSw = thr;
} else {
thrTrimSw = src - MIXSRC_FIRST_TRIM;
break;
}
}
@ -820,12 +818,6 @@ PACK(struct TrainerData {
#if defined(COLORLCD)
#define EXTRA_GENERAL_FIELDS \
CUST_ARRAY(sticksConfig, struct_sticksConfig, stick_name_valid); \
swconfig_t switchConfig ARRAY(2,struct_switchConfig,nullptr); \
uint16_t potsConfig ARRAY(2,struct_potConfig,nullptr); /* two bits per pot */ \
uint8_t slidersConfig ARRAY(1,struct_sliderConfig,nullptr); /* 1 bit per slider */ \
NOBACKUP(char switchNames[STORAGE_NUM_SWITCHES][LEN_SWITCH_NAME] SKIP); \
NOBACKUP(char anaNames[NUM_STICKS + STORAGE_NUM_POTS + STORAGE_NUM_SLIDERS][LEN_ANA_NAME] SKIP); \
NOBACKUP(char currModelFilename[LEN_MODEL_FILENAME+1]); \
NOBACKUP(uint8_t modelQuickSelect:1); \
NOBACKUP(uint8_t blOffBright:7); \
@ -839,14 +831,7 @@ PACK(struct TrainerData {
#define BLUETOOTH_FIELDS
#endif
#define EXTRA_GENERAL_FIELDS \
uint8_t slidersConfig:4 ARRAY(1,struct_sliderConfig,nullptr); \
uint8_t spare5:4 SKIP; \
uint8_t potsConfig ARRAY(2,struct_potConfig,nullptr); /* two bits per pot */\
uint8_t backlightColor; \
CUST_ARRAY(sticksConfig, struct_sticksConfig, stick_name_valid); \
swconfig_t switchConfig ARRAY(2,struct_switchConfig,nullptr); \
char switchNames[STORAGE_NUM_SWITCHES - NUM_FUNCTIONS_SWITCHES][LEN_SWITCH_NAME] SKIP; \
char anaNames[NUM_STICKS+STORAGE_NUM_POTS+STORAGE_NUM_SLIDERS][LEN_ANA_NAME] SKIP; \
BLUETOOTH_FIELDS
#endif
@ -873,7 +858,7 @@ PACK(struct RadioData {
NOBACKUP(int8_t spare0:7 SKIP);
CUST_ATTR(semver,nullptr,w_semver);
CUST_ATTR(board,nullptr,w_board);
CalibData calib[NUM_STICKS + STORAGE_NUM_POTS + STORAGE_NUM_SLIDERS + STORAGE_NUM_MOUSE_ANALOGS] NO_IDX;
CalibData calib[MAX_CALIB_ANALOG_INPUTS] NO_IDX;
NOBACKUP(uint16_t chkSum SKIP);
N_HORUS_FIELD(int8_t currModel);
N_HORUS_FIELD(uint8_t contrast);
@ -883,7 +868,7 @@ PACK(struct RadioData {
int8_t antennaMode:2 ENUM(AntennaModes);
uint8_t disableRtcWarning:1;
uint8_t keysBacklight:1;
NOBACKUP(uint8_t spare1:1 SKIP);
uint8_t spare1:1 SKIP;
uint8_t internalModule ENUM(ModuleType);
NOBACKUP(TrainerData trainer);
NOBACKUP(uint8_t view); // index of view in main screen
@ -946,6 +931,11 @@ PACK(struct RadioData {
CUST_ATTR(aux2SerialMode, r_serialMode, nullptr);
NOBACKUP(uint32_t serialPort ARRAY(SERIAL_CONF_BITS_PER_PORT,struct_serialConfig,nullptr));
CUST_ARRAY(sticksConfig, struct_stickConfig, MAX_STICKS, stick_name_valid);
CUST_ARRAY(slidersConfig, struct_sliderConfig, MAX_POTS, nullptr);
potconfig_t potsConfig ARRAY(4,struct_potConfig,nullptr);
swconfig_t switchConfig ARRAY(2,struct_switchConfig,nullptr);
EXTRA_GENERAL_FIELDS
THEME_DATA

View file

@ -23,7 +23,6 @@
#define _DISK_CACHE_H_
#include "diskio.h"
#include "sdio_sd.h"
// tunable parameters
#define DISK_CACHE_BLOCKS_NUM 32 // no cache blocks

View file

@ -20,6 +20,7 @@
*/
#include "opentx.h"
#include "switches.h"
#if defined(COLORLCD)
void setRequestedMainView(uint8_t view);
@ -143,7 +144,7 @@ void evalFunctions(const CustomFunctionData * functions, CustomFunctionsContext
#endif
#if defined(GVARS)
for (uint8_t i=0; i<NUM_TRIMS; i++) {
for (uint8_t i=0; i<MAX_TRIMS; i++) {
trimGvar[i] = -1;
}
#endif
@ -173,9 +174,9 @@ void evalFunctions(const CustomFunctionData * functions, CustomFunctionsContext
uint8_t param = CFN_CH_INDEX(cfn);
if (param == 0)
newActiveFunctions |= 0x0F;
else if (param <= NUM_STICKS)
else if (param <= MAX_STICKS)
newActiveFunctions |= (1 << (param - 1));
else if (param == NUM_STICKS + 1)
else if (param == MAX_STICKS + 1)
newActiveFunctions |= (1u << FUNCTION_TRAINER_CHANNELS);
break;
}
@ -465,3 +466,76 @@ void evalFunctions(const CustomFunctionData * functions, CustomFunctionsContext
functionsContext.activeFunctions = newActiveFunctions;
}
const char* funcGetLabel(uint8_t func)
{
switch(func) {
case FUNC_OVERRIDE_CHANNEL:
return STR_SF_SAFETY;
case FUNC_TRAINER:
return STR_SF_TRAINER;
case FUNC_INSTANT_TRIM:
return STR_SF_INST_TRIM;
case FUNC_RESET:
return STR_SF_RESET;
case FUNC_SET_TIMER:
return STR_SF_SET_TIMER;
#if defined(GVARS)
case FUNC_ADJUST_GVAR:
return STR_ADJUST_GVAR;
#endif
case FUNC_VOLUME:
return STR_SF_VOLUME;
case FUNC_SET_FAILSAFE:
return STR_SF_FAILSAFE;
case FUNC_RANGECHECK:
return STR_SF_RANGE_CHECK;
case FUNC_BIND:
return STR_SF_MOD_BIND;
#if defined(AUDIO)
case FUNC_PLAY_SOUND:
return STR_SOUND;
#endif
#if defined(VOICE)
case FUNC_PLAY_TRACK:
return STR_PLAY_TRACK;
case FUNC_PLAY_VALUE:
return STR_PLAY_VALUE;
#endif
#if defined(LUA)
case FUNC_PLAY_SCRIPT:
return STR_SF_PLAY_SCRIPT;
#endif
case FUNC_BACKGND_MUSIC:
return STR_SF_BG_MUSIC;
case FUNC_BACKGND_MUSIC_PAUSE:
return STR_SF_BG_MUSIC_PAUSE;
#if defined(VARIO)
case FUNC_VARIO:
return STR_SF_VARIO;
#endif
#if defined(HAPTIC)
case FUNC_HAPTIC:
return STR_SF_HAPTIC;
#endif
case FUNC_LOGS:
return STR_SF_LOGS;
case FUNC_BACKLIGHT:
return STR_SF_BACKLIGHT;
case FUNC_SCREENSHOT:
return STR_SF_SCREENSHOT;
case FUNC_RACING_MODE:
return STR_SF_RACING_MODE;
#if defined(COLORLCD)
case FUNC_DISABLE_TOUCH:
return STR_SF_DISABLE_TOUCH;
case FUNC_SET_SCREEN:
return STR_SF_SET_SCREEN;
#endif
#if defined(DEBUG)
case FUNC_TEST:
return STR_SF_TEST;
#endif
default:
return STR_EMPTY;
}
}

View file

@ -32,8 +32,7 @@ PACK(struct GlobalData {
uint8_t authenticationCount:2;
uint8_t upgradeModulePopup:1;
uint8_t internalModuleVersionChecked:1;
uint8_t flyskygimbals:1;
uint8_t spare:1;
uint8_t spare:2;
});
extern GlobalData globalData;
@ -81,7 +80,7 @@ extern int32_t act[MAX_MIXERS];
extern int8_t virtualInputsTrims[MAX_INPUTS];
extern int16_t anas [MAX_INPUTS];
extern int16_t trims[NUM_TRIMS];
extern int16_t trims[MAX_TRIMS];
extern int32_t chans[MAX_OUTPUT_CHANNELS];
extern int16_t ex_chans[MAX_OUTPUT_CHANNELS]; // Outputs (before LIMITS) of the last perMain
extern int16_t channelOutputs[MAX_OUTPUT_CHANNELS];
@ -91,7 +90,7 @@ extern BeepANACenter bpanaCenter;
extern uint8_t s_mixer_first_run_done;
extern int16_t calibratedAnalogs[NUM_CALIBRATED_ANALOGS];
extern int16_t calibratedAnalogs[MAX_ANALOG_INPUTS];
extern uint8_t g_beepCnt;
extern uint8_t beepAgain;

View file

@ -25,6 +25,8 @@
#include "gui_common.h"
#include "menus.h"
#include "popups.h"
#include "navigation/navigation.h"
#include "common/stdlcd/draw_functions.h"
#define MENUS_SCROLLBAR_WIDTH 0
@ -57,147 +59,49 @@ extern uint8_t noHighlightCounter;
void drawSlider(coord_t x, coord_t y, uint8_t width, uint8_t value, uint8_t max, uint8_t attr);
void drawSlider(coord_t x, coord_t y, uint8_t value, uint8_t max, uint8_t attr);
extern int8_t checkIncDec_Ret; // global helper vars
#define EDIT_SELECT_FIELD 0
#define EDIT_MODIFY_FIELD 1
#define EDIT_MODIFY_STRING 2
extern int8_t s_editMode; // global editmode
// checkIncDec flags
// we leave room for EE_MODEL and EE_GENERAL
#define NO_INCDEC_MARKS 0x04
#define INCDEC_SWITCH 0x08
#define INCDEC_SOURCE 0x10
#define INCDEC_REP10 0x40
#define NO_DBLKEYS 0x80
#define INCDEC_DECLARE_VARS(f) uint8_t incdecFlag = (f); IsValueAvailable isValueAvailable = nullptr
#define INCDEC_SET_FLAG(f) incdecFlag = (f)
#define INCDEC_ENABLE_CHECK(fn) isValueAvailable = fn
#define CHECK_INCDEC_PARAM(event, var, min, max) checkIncDec(event, var, min, max, incdecFlag, isValueAvailable)
struct CheckIncDecStops {
const int count;
const int stops[];
int min() const
{
return stops[0];
}
int max() const
{
return stops[count-1];
}
bool contains(int value) const
{
for (int i=0; i<count; ++i) {
int stop = stops[i];
if (value == stop)
return true;
else if (value < stop)
return false;
}
return false;
}
};
extern const CheckIncDecStops &stops100;
extern const CheckIncDecStops &stops1000;
extern const CheckIncDecStops &stopsSwitch;
#define INIT_STOPS(var, ...) \
const int _ ## var[] = { __VA_ARGS__ }; \
const CheckIncDecStops &var = (const CheckIncDecStops&)_ ## var;
#define CATEGORY_END(val) \
(val), (val+1)
int checkIncDec(event_t event, int val, int i_min, int i_max, unsigned int i_flags=0, IsValueAvailable isValueAvailable=nullptr, const CheckIncDecStops &stops=stops100);
#define checkIncDecModel(event, i_val, i_min, i_max) checkIncDec(event, i_val, i_min, i_max, EE_MODEL)
#define checkIncDecModelZero(event, i_val, i_max) checkIncDec(event, i_val, 0, i_max, EE_MODEL)
#define checkIncDecGen(event, i_val, i_min, i_max) checkIncDec(event, i_val, i_min, i_max, EE_GENERAL)
#define CHECK_INCDEC_MODELVAR(event, var, min, max) \
var = checkIncDecModel(event, var, min, max)
#define CHECK_INCDEC_MODELVAR_ZERO(event, var, max) \
var = checkIncDecModelZero(event, var, max)
#define CHECK_INCDEC_MODELVAR_CHECK(event, var, min, max, check) \
var = checkIncDec(event, var, min, max, EE_MODEL, check)
#define CHECK_INCDEC_MODELVAR_ZERO_CHECK(event, var, max, check) \
var = checkIncDec(event, var, 0, max, EE_MODEL, check)
#define AUTOSWITCH_ENTER_LONG() (attr && event==EVT_KEY_LONG(KEY_ENTER))
#define CHECK_INCDEC_SWITCH(event, var, min, max, flags, available) \
var = checkIncDec(event, var, min, max, (flags)|INCDEC_SWITCH, available)
#define CHECK_INCDEC_MODELSWITCH(event, var, min, max, available) \
CHECK_INCDEC_SWITCH(event, var, min, max, EE_MODEL, available)
#define CHECK_INCDEC_MODELSOURCE(event, var, min, max) \
var = checkIncDec(event,var,min,max,EE_MODEL|INCDEC_SOURCE|NO_INCDEC_MARKS, isSourceAvailable)
#define CHECK_INCDEC_GENVAR(event, var, min, max) \
var = checkIncDecGen(event, var, min, max)
#if defined(PCBTARANIS)
#define CURSOR_ON_LINE() (menuHorizontalPosition < 0)
#else
#define CURSOR_ON_LINE() (0)
#endif
void check(event_t event, uint8_t curr, const MenuHandler *menuTab, uint8_t menuTabSize, const uint8_t *horTab, uint8_t horTabMax, vertpos_t maxrow);
void check_simple(event_t event, uint8_t curr, const MenuHandler *menuTab, uint8_t menuTabSize, vertpos_t maxrow);
void check_submenu_simple(event_t event, uint8_t maxrow);
void title(const char * s);
#define MENU_TAB(...) const uint8_t mstate_tab[] = __VA_ARGS__
#define MENU_CHECK(tab, menu, lines_count) \
check(event, menu, tab, DIM(tab), mstate_tab, DIM(mstate_tab)-1, (lines_count)-HEADER_LINE)
#define MENU(name, tab, menu, lines_count, ...) \
MENU_TAB(__VA_ARGS__); \
MENU_CHECK(tab, menu, lines_count); \
title(name)
#define SUBMENU_NOTITLE(lines_count, ...) \
MENU_TAB(__VA_ARGS__); \
check(event, 0, nullptr, 0, mstate_tab, DIM(mstate_tab)-1, (lines_count)-HEADER_LINE)
#define SIMPLE_MENU_NOTITLE(tab, menu, lines_count) \
check_simple(event, menu, tab, DIM(tab), (lines_count)-HEADER_LINE)
#define SIMPLE_SUBMENU_NOTITLE(lines_count) \
check_submenu_simple(event, (lines_count)-HEADER_LINE)
#define SUBMENU(name, lines_count, ...) \
MENU_TAB(__VA_ARGS__); \
check(event, 0, nullptr, 0, mstate_tab, DIM(mstate_tab)-1, (lines_count)-HEADER_LINE); \
title(name)
#define SIMPLE_MENU(name, tab, menu, lines_count) \
SIMPLE_MENU_NOTITLE(tab, menu, lines_count); \
title(name)
#define SIMPLE_SUBMENU(name, lines_count) \
SIMPLE_SUBMENU_NOTITLE(lines_count); \
title(name)
typedef int choice_t;
choice_t editChoice(coord_t x, coord_t y, const char * label, const char *const *values, choice_t value, choice_t min, choice_t max, LcdFlags attr, event_t event, IsValueAvailable isValueAvailable = nullptr);
uint8_t editCheckBox(uint8_t value, coord_t x, coord_t y, const char * label, LcdFlags attr, event_t event);
swsrc_t editSwitch(coord_t x, coord_t y, swsrc_t value, LcdFlags attr, event_t event);
choice_t editChoice(coord_t x, coord_t y, const char *label,
const char *const *values, choice_t value, choice_t min,
choice_t max, LcdFlags attr, event_t event,
IsValueAvailable isValueAvailable = nullptr);
uint8_t editCheckBox(uint8_t value, coord_t x, coord_t y, const char *label,
LcdFlags attr, event_t event);
swsrc_t editSwitch(coord_t x, coord_t y, swsrc_t value, LcdFlags attr,
event_t event);
#if defined(GVARS)
#define GVAR_MENU_ITEM(x, y, v, min, max, attr, editflags, event) editGVarFieldValue(x, y, v, min, max, attr, editflags, event)
int16_t editGVarFieldValue(coord_t x, coord_t y, int16_t value, int16_t min, int16_t max, LcdFlags attr, uint8_t editflags, event_t event);
void drawGVarValue(coord_t x, coord_t y, uint8_t gvar, gvar_t value, LcdFlags flags=0);
void editGVarValue(coord_t x, coord_t y, event_t event, uint8_t gvar, uint8_t flightMode, LcdFlags flags);
#define displayGVar(x, y, v, min, max) GVAR_MENU_ITEM(x, y, v, min, max, 0, 0, 0)
#else
int16_t editGVarFieldValue(coord_t x, coord_t y, int16_t value, int16_t min, int16_t max, LcdFlags attr, event_t event);
#define GVAR_MENU_ITEM(x, y, v, min, max, attr, editflags, event) editGVarFieldValue(x, y, v, min, max, attr, event)
#define GVAR_MENU_ITEM(x, y, v, min, max, attr, editflags, event) \
editGVarFieldValue(x, y, v, min, max, attr, editflags, event)
int16_t editGVarFieldValue(coord_t x, coord_t y, int16_t value, int16_t min,
int16_t max, LcdFlags attr, uint8_t editflags,
event_t event);
void drawGVarValue(coord_t x, coord_t y, uint8_t gvar, gvar_t value,
LcdFlags flags = 0);
void editGVarValue(coord_t x, coord_t y, event_t event, uint8_t gvar,
uint8_t flightMode, LcdFlags flags);
#define displayGVar(x, y, v, min, max) \
GVAR_MENU_ITEM(x, y, v, min, max, 0, 0, 0)
#else // GVARS
int16_t editGVarFieldValue(coord_t x, coord_t y, int16_t value, int16_t min,
int16_t max, LcdFlags attr, event_t event);
#define GVAR_MENU_ITEM(x, y, v, min, max, attr, editflags, event) \
editGVarFieldValue(x, y, v, min, max, attr, event)
#define displayGVar(x, y, v, min, max) lcdDraw8bitsNumber(x, y, v)
#endif
void gvarWeightItem(coord_t x, coord_t y, MixData * md, LcdFlags attr, event_t event);
@ -210,10 +114,12 @@ void editSingleName(coord_t x, coord_t y, const char *label, char *name,
uint8_t old_editMode);
uint8_t editDelay(coord_t y, event_t event, uint8_t attr, const char * str, uint8_t delay);
#define EDIT_DELAY(x, y, event, attr, str, delay) editDelay(y, event, attr, str, delay)
#define COPY_MODE 1
#define MOVE_MODE 2
extern uint8_t s_copyMode;
extern int8_t s_copySrcRow;
extern int8_t s_copyTgtOfs;
@ -243,33 +149,9 @@ void readModelNotes();
void menuChannelsView(event_t event);
void menuChannelsViewCommon(event_t event);
#define CURSOR_MOVED_LEFT(event) (IS_ROTARY_LEFT(event) || EVT_KEY_MASK(event) == KEY_LEFT)
#define CURSOR_MOVED_RIGHT(event) (IS_ROTARY_RIGHT(event) || EVT_KEY_MASK(event) == KEY_RIGHT)
void repeatLastCursorMove(event_t event);
#if defined(ROTARY_ENCODER_NAVIGATION)
#define IS_ROTARY_LEFT(evt) (evt == EVT_ROTARY_LEFT)
#define IS_ROTARY_RIGHT(evt) (evt == EVT_ROTARY_RIGHT)
#define IS_ROTARY_BREAK(evt) (evt == EVT_ROTARY_BREAK)
#define IS_ROTARY_LONG(evt) (evt == EVT_ROTARY_LONG)
#define IS_ROTARY_EVENT(evt) (EVT_KEY_MASK(evt) >= 0x0e)
void repeatLastCursorMove(event_t event);
#define REPEAT_LAST_CURSOR_MOVE() { if (EVT_KEY_MASK(event) >= 0x0e) pushEvent(event); else repeatLastCursorMove(event); }
#else
#define IS_ROTARY_LEFT(evt) (0)
#define IS_ROTARY_RIGHT(evt) (0)
#define IS_ROTARY_BREAK(evt) (0)
#define IS_ROTARY_LONG(evt) (0)
#define IS_ROTARY_EVENT(evt) (0)
void repeatLastCursorMove(event_t event);
#define REPEAT_LAST_CURSOR_MOVE() repeatLastCursorMove(event)
#endif
// TODO enum
#if defined(PCBX7) || defined(PCBX9LITE)
#define EDIT_MODE_INIT 0
#else
#define EDIT_MODE_INIT -1
#endif
extern uint8_t editNameCursorPos;
@ -280,6 +162,7 @@ uint8_t getMixesCount();
void insertMix(uint8_t idx);
void deleteMix(uint8_t idx);
void onSwitchLongEnterPress(const char *result);
void onSourceLongEnterPress(const char *result);
uint8_t switchToMix(uint8_t source);
@ -291,6 +174,8 @@ extern const unsigned char sticks[] ;
void drawSplash();
void drawScreenIndex(uint8_t index, uint8_t count, uint8_t attr);
void drawStick(coord_t centrex, int16_t xval, int16_t yval);
void drawWheel(coord_t centrex, int16_t wval);
void drawThrottle(coord_t centrex, int16_t tval);
void drawPotsBars();
void doMainScreenGraphics();

View file

@ -35,6 +35,9 @@
#if !defined(BOOT)
#include "opentx.h"
#include "hal/switch_driver.h"
#include "hal/adc_driver.h"
#include "switches.h"
#endif
pixel_t displayBuf[DISPLAY_BUFFER_SIZE] __DMA;
@ -707,7 +710,7 @@ void putsVBat(coord_t x, coord_t y, LcdFlags att)
void drawSource(coord_t x, coord_t y, uint32_t idx, LcdFlags att)
{
if (idx == MIXSRC_NONE) {
lcdDrawTextAtIndex(x, y, STR_VSRCRAW, 0, att); // TODO macro
lcdDrawText(x, y, STR_EMPTY, att);
}
else if (idx <= MIXSRC_LAST_INPUT) {
lcdDrawChar(x+2, y+1, CHR_INPUT, TINSIZE);
@ -734,98 +737,14 @@ void drawSource(coord_t x, coord_t y, uint32_t idx, LcdFlags att)
}
}
#endif
else if (idx <= MIXSRC_LAST_POT) {
idx = idx - MIXSRC_Rud;
if (g_eeGeneral.anaNames[idx][0]) {
if (idx < MIXSRC_FIRST_POT-MIXSRC_Rud )
lcdDrawSizedText(x, y, STR_CHAR_STICK, 2, att);
else if (idx <= MIXSRC_LAST_POT-MIXSRC_Rud )
lcdDrawSizedText(x, y, STR_CHAR_POT, 2, att);
else
lcdDrawSizedText(x, y, STR_CHAR_SLIDER, 2, att);
lcdDrawSizedText(lcdNextPos, y, g_eeGeneral.anaNames[idx], LEN_ANA_NAME, att);
}
else {
lcdDrawTextAtIndex(x, y, STR_VSRCRAW, idx + 1, att);
}
}
else if (idx >= MIXSRC_FIRST_SWITCH && idx <= MIXSRC_LAST_SWITCH) {
#if defined(FUNCTION_SWITCHES)
if(idx >= MIXSRC_FIRST_FS_SWITCH) {
idx = idx-(MIXSRC_FIRST_SWITCH+NUM_REGULAR_SWITCHES);
if (ZEXIST(g_model.switchNames[idx])) {
lcdDrawSizedText(x, y, STR_CHAR_SWITCH, 2, att);
lcdDrawSizedText(lcdNextPos, y, g_model.switchNames[idx], LEN_SWITCH_NAME, att);
}
else {
char s[LEN_SWITCH_NAME] = {'S', 'W'};
s[LEN_SWITCH_NAME-1] = '1' + idx;
lcdDrawSizedText(x, y, STR_CHAR_SWITCH, 2, att);
lcdDrawSizedText(lcdNextPos, y, s, LEN_SWITCH_NAME, att);
}
}
else {
idx = idx-MIXSRC_FIRST_SWITCH;
if (ZEXIST(g_eeGeneral.switchNames[idx])) {
lcdDrawSizedText(x, y, STR_CHAR_SWITCH, 2, att);
lcdDrawSizedText(lcdNextPos, y, g_eeGeneral.switchNames[idx], LEN_SWITCH_NAME, att);
}
else
lcdDrawTextAtIndex(x, y, STR_VSRCRAW, idx + MIXSRC_FIRST_SWITCH - MIXSRC_Rud + 1, att);
}
#else
idx = idx-MIXSRC_FIRST_SWITCH;
if (ZEXIST(g_eeGeneral.switchNames[idx])) {
lcdDrawSizedText(x, y, STR_CHAR_SWITCH, 2, att); //switch symbol
lcdDrawSizedText(lcdNextPos, y, g_eeGeneral.switchNames[idx], LEN_SWITCH_NAME, att);
}
else
lcdDrawTextAtIndex(x, y, STR_VSRCRAW, idx + MIXSRC_FIRST_SWITCH - MIXSRC_Rud + 1, att);
#endif
}
else if (idx < MIXSRC_SW1)
lcdDrawTextAtIndex(x, y, STR_VSRCRAW, idx-MIXSRC_Rud+1, att);
else if (idx <= MIXSRC_LAST_LOGICAL_SWITCH)
drawSwitch(x, y, SWSRC_SW1+idx-MIXSRC_SW1, att);
else if (idx < MIXSRC_CH1)
drawStringWithIndex(x, y, STR_PPM_TRAINER, idx-MIXSRC_FIRST_TRAINER+1, att);
else if (idx <= MIXSRC_LAST_CH) {
if (ZEXIST(g_model.limitData[idx-MIXSRC_CH1].name) && (att & STREXPANDED)) {
char s[LEN_CHANNEL_NAME + 3];
strcpy(s, STR_CHAR_CHANNEL);
strcat(s, g_model.limitData[idx-MIXSRC_CH1].name);
lcdDrawSizedText(x, y, s, LEN_CHANNEL_NAME+2, att);
} else {
drawStringWithIndex(x, y, STR_CH, idx-MIXSRC_CH1+1, att);
}
}
else if (idx <= MIXSRC_LAST_GVAR) {
drawStringWithIndex(x, y, STR_GV, idx-MIXSRC_GVAR1+1, att);
}
else if (idx < MIXSRC_FIRST_TIMER) {
lcdDrawTextAtIndex(x, y, STR_VSRCRAW, idx-MIXSRC_Rud+1-MAX_LOGICAL_SWITCHES-MAX_TRAINER_CHANNELS-MAX_OUTPUT_CHANNELS-MAX_GVARS, att);
}
else if (idx <= MIXSRC_LAST_TIMER) {
if(ZEXIST(g_model.timers[idx-MIXSRC_FIRST_TIMER].name)) {
lcdDrawSizedText(x, y, g_model.timers[idx-MIXSRC_FIRST_TIMER].name, LEN_TIMER_NAME, att);
}
else {
lcdDrawTextAtIndex(x, y, STR_VSRCRAW, idx-MIXSRC_Rud+1-MAX_LOGICAL_SWITCHES-MAX_TRAINER_CHANNELS-MAX_OUTPUT_CHANNELS-MAX_GVARS, att);
}
}
else {
idx -= MIXSRC_FIRST_TELEM;
div_t qr = div(idx, 3);
lcdDrawSizedText(x, y, g_model.telemetrySensors[qr.quot].label, TELEM_LABEL_LEN, att);
if (qr.rem) lcdDrawChar(lcdLastRightPos, y, qr.rem==2 ? '+' : '-', att);
lcdDrawText(x, y, getSourceString(idx), att);
}
}
void putsChnLetter(coord_t x, coord_t y, uint8_t idx, LcdFlags att)
{
lcdDrawTextAtIndex(x, y, STR_RETA123, idx-1, att);
lcdDrawText(x, y, getAnalogShortLabel(idx), att);
}
void drawModelName(coord_t x, coord_t y, char *name, uint8_t id, LcdFlags att)
@ -873,10 +792,10 @@ void drawShortTrimMode(coord_t x, coord_t y, uint8_t fm, uint8_t idx, LcdFlags a
uint8_t mode = v.mode;
uint8_t p = v.mode >> 1;
if (mode == TRIM_MODE_NONE) {
putsChnLetter(x, y, idx+1, att);
putsChnLetter(x, y, idx, att);
}
else {
lcdDrawChar(x, y, '0'+p, att);
lcdDrawChar(x, y, '0' + p, att);
}
}

View file

@ -126,7 +126,7 @@ void drawTimerMode(coord_t x, coord_t y, swsrc_t mode, LcdFlags att=0);
void drawShortTrimMode(coord_t x, coord_t y, uint8_t mode, uint8_t idx, LcdFlags att);
#define putsChn(x, y, idx, att) drawSource(x, y, MIXSRC_CH1+idx-1, att)
#define putsChn(x, y, idx, att) drawSource(x, y, MIXSRC_FIRST_CH + idx - 1, att)
void putsChnLetter(coord_t x, coord_t y, uint8_t idx, LcdFlags attr);
void putsVolts(coord_t x, coord_t y, uint16_t volts, LcdFlags att);

View file

@ -70,6 +70,7 @@ void menuRadioTrainer(event_t event);
void menuRadioVersion(event_t event);
void menuRadioDiagKeys(event_t event);
void menuRadioDiagAnalogs(event_t event);
void menuRadioDiagFS(event_t event);
void menuRadioHardware(event_t event);
void menuRadioTools(event_t event);
void menuRadioSpectrumAnalyser(event_t event);

View file

@ -20,6 +20,7 @@
*/
#include "opentx.h"
#include "hal/rotary_encoder.h"
void runPopupCurvePreset(event_t event)
{
@ -122,9 +123,7 @@ void menuModelCurveOne(event_t event)
lcdDrawNumber(INDENT_WIDTH, 6*FH+1, 5+crv.points, LEFT|attr);
lcdDrawText(lcdLastRightPos, 6*FH+1, STR_PTS, attr);
if (attr) {
#if defined(ROTARY_ENCODER_NAVIGATION)
rotencSpeed = ROTENC_LOWSPEED;
#endif
rotaryEncoderResetAccel();
int8_t count = checkIncDecModel(event, crv.points, -3, 12); // 2pts - 17pts
if (checkIncDec_Ret) {
int8_t newPoints[MAX_POINTS_PER_CURVE];
@ -174,7 +173,7 @@ void menuModelCurveOne(event_t event)
break;
#elif defined(NAVIGATION_XLITE)
case EVT_KEY_FIRST(KEY_ENTER):
if (IS_SHIFT_PRESSED()) {
if (keysGetState(KEY_SHIFT)) {
pushMenu(menuChannelsView);
killEvents(event);
}

View file

@ -118,7 +118,7 @@ void menuModelCustomScriptOne(event_t event)
scriptInputsOutputs[s_currIdx].inputsCount + 1) {
lcdDrawTextAlignedLeft(y, STR_OUTPUTS);
if (attr) {
REPEAT_LAST_CURSOR_MOVE();
repeatLastCursorMove(event);
}
} else if (i <= ITEM_MODEL_CUSTOMSCRIPT_PARAMS_LABEL +
scriptInputsOutputs[s_currIdx].inputsCount +

View file

@ -262,7 +262,7 @@ void menuModelDisplay(event_t event)
}
}
if (attr && menuHorizontalPosition == NUM_LINE_ITEMS) {
REPEAT_LAST_CURSOR_MOVE();
repeatLastCursorMove(event);
}
}
break;

View file

@ -111,17 +111,16 @@ void menuModelFlightModeOne(event_t event)
case ITEM_MODEL_FLIGHT_MODE_TRIMS:
lcdDrawTextAlignedLeft(y, STR_TRIMS);
for (uint8_t t = 0; t < NUM_STICKS; t++) {
{
auto trims = keysGetMaxTrims();
for (uint8_t t = 0; t < trims; t++) {
drawTrimMode(MIXES_2ND_COLUMN + (t*2*FW), y, s_currIdx, t, menuHorizontalPosition == t ? attr : 0);
#if defined(NAVIGATION_9X)
if (s_editMode > 0 && attr && menuHorizontalPosition == t) {
#else
if (s_editMode >= 0 && attr && menuHorizontalPosition == t) {
#endif
trim_t & v = fm->trim[t];
v.mode = checkIncDec(event, v.mode==TRIM_MODE_NONE ? -1 : v.mode, -1, k==0 ? 0 : 2*MAX_FLIGHT_MODES-1, EE_MODEL, isTrimModeAvailable);
}
}
}
break;
case ITEM_MODEL_FLIGHT_MODE_FADE_IN:
@ -188,64 +187,41 @@ void menuModelFlightModeOne(event_t event)
void menuModelFlightModesAll(event_t event)
{
SIMPLE_MENU(STR_MENUFLIGHTMODES, menuTabModel, MENU_MODEL_FLIGHT_MODES, HEADER_LINE+MAX_FLIGHT_MODES+1);
SIMPLE_MENU(STR_MENUFLIGHTMODES, menuTabModel, MENU_MODEL_FLIGHT_MODES,
HEADER_LINE+MAX_FLIGHT_MODES+1);
int8_t sub = menuVerticalPosition - HEADER_LINE;
switch (event) {
case EVT_KEY_FIRST(KEY_ENTER):
if (sub == MAX_FLIGHT_MODES) {
// "Check trims" button
if (sub == MAX_FLIGHT_MODES && event == EVT_KEY_FIRST(KEY_ENTER)) {
s_editMode = 0;
trimsCheckTimer = 200; // 2 seconds
}
// no break
#if !defined(PCBX7)
case EVT_KEY_FIRST(KEY_RIGHT):
#endif
if (sub >= 0 && sub < MAX_FLIGHT_MODES) {
// Flight mode lines
if (sub >= 0 && sub < MAX_FLIGHT_MODES &&
(event == EVT_KEY_FIRST(KEY_ENTER) || event == EVT_KEY_FIRST(KEY_RIGHT))) {
s_currIdx = sub;
pushMenu(menuModelFlightModeOne);
}
break;
}
uint8_t att;
for (uint8_t i=0; i<MAX_FLIGHT_MODES; i++) {
int8_t y = 1 + (1+i-menuVerticalOffset)*FH;
if (y<1*FH+1 || y>(LCD_LINES-1)*FH+1) continue;
att = (i==sub ? INVERS : 0);
FlightModeData * p = flightModeAddress(i);
drawFlightMode(0, y, i+1, att|(getFlightMode()==i ? BOLD : 0));
#if defined(PCBTARANIS)
for (uint8_t i = 0; i < MAX_FLIGHT_MODES; i++) {
int8_t y = 1 + (1 + i - menuVerticalOffset) * FH;
if (y < 1 * FH + 1 || y > (LCD_LINES - 1) * FH + 1) continue;
att = (i == sub ? INVERS : 0);
FlightModeData* p = flightModeAddress(i);
drawFlightMode(0, y, i + 1, att | (getFlightMode() == i ? BOLD : 0));
lcdDrawSizedText(NAME_POS, y, p->name, sizeof(p->name), 0);
#else
lcdDrawSizedText(4*FW+NAME_OFS, y, p->name, sizeof(p->name), 0);
#endif
if (i == 0) {
for (uint8_t t=0; t<NUM_STICKS; t++) {
#if defined(PCBTARANIS)
drawTrimMode(TRIMS_POS+t*FW*2, y, i, t, 0);
#else
drawShortTrimMode((9+LEN_FLIGHT_MODE_NAME+t)*FW+TRIMS_OFS, y, i, t, 0);
#endif
}
}
else {
#if defined(PCBTARANIS)
drawSwitch(SWITCH_POS, y, p->swtch, 0);
for (uint8_t t=0; t<NUM_STICKS; t++) {
drawTrimMode(TRIMS_POS+t*FW*2, y, i, t, 0);
}
#else
drawSwitch((4+LEN_FLIGHT_MODE_NAME)*FW+SWITCH_OFS, y, p->swtch, 0);
for (uint8_t t=0; t<NUM_STICKS; t++) {
drawShortTrimMode((9+LEN_FLIGHT_MODE_NAME+t)*FW+TRIMS_OFS, y, i, t, 0);
}
#endif
auto trims = min(keysGetMaxTrims(), (uint8_t)MAX_STICKS);
if (i > 0) drawSwitch(SWITCH_POS, y, p->swtch, 0);
for (uint8_t t = 0; t < trims; t++) {
drawTrimMode(TRIMS_POS + t * FW * 2, y, i, t, 0);
}
if (p->fadeIn || p->fadeOut) {
lcdDrawChar(LCD_W-FW, y, (p->fadeIn && p->fadeOut) ? '*' : (p->fadeIn ? 'I' : 'O'));
lcdDrawChar(LCD_W - FW, y,
(p->fadeIn && p->fadeOut) ? '*' : (p->fadeIn ? 'I' : 'O'));
}
}

View file

@ -68,7 +68,7 @@ void menuModelExpoOne(event_t event)
killEvents(event);
}
#elif defined(NAVIGATION_XLITE)
if (event == EVT_KEY_FIRST(KEY_ENTER) && IS_SHIFT_PRESSED()) {
if (event == EVT_KEY_FIRST(KEY_ENTER) && keysGetState(KEY_SHIFT)) {
pushMenu(menuChannelsView);
killEvents(event);
}
@ -159,12 +159,20 @@ void menuModelExpoOne(event_t event)
break;
case EXPO_FIELD_TRIM:
uint8_t notStick = (ed->srcRaw > MIXSRC_Ail);
int8_t trimSource = -ed->trimSource;
lcdDrawTextAlignedLeft(y, STR_TRIM);
lcdDrawTextAtIndex(EXPO_ONE_2ND_COLUMN, y, STR_VMIXTRIMS, (notStick && trimSource == 0) ? 0 : trimSource + 1, RIGHT | (menuHorizontalPosition==0 ? attr : 0));
if (attr)
ed->trimSource = -checkIncDecModel(event, trimSource, notStick ? TRIM_ON : -TRIM_OFF, -TRIM_LAST);
{
const char* trim_str = getTrimSourceLabel(ed->srcRaw, ed->trimSource);
LcdFlags flags = RIGHT | (menuHorizontalPosition==0 ? attr : 0);
lcdDrawText(EXPO_ONE_2ND_COLUMN, y, trim_str, flags);
if (attr) {
int8_t min = TRIM_ON;
if (ed->srcRaw >= MIXSRC_FIRST_STICK && ed->srcRaw <= MIXSRC_LAST_STICK) {
min = -TRIM_OFF;
}
ed->trimSource = -checkIncDecModel(event, -ed->trimSource, min, keysGetMaxTrims());
}
}
break;
}
y += FH;

View file

@ -60,7 +60,7 @@ void menuModelLogicalSwitchOne(event_t event)
LogicalSwitchData * cs = lswAddress(s_currIdx);
uint8_t sw = SWSRC_SW1+s_currIdx;
uint8_t sw = SWSRC_FIRST_LOGICAL_SWITCH+s_currIdx;
uint8_t cstate = lswFamily(cs->func);
drawSwitch(14*FW, 0, sw, (getSwitch(sw) ? BOLD : 0));
@ -209,7 +209,7 @@ void menuModelLogicalSwitchOne(event_t event)
if (cstate == LS_FAMILY_EDGE) {
lcdDrawText(CSWONE_2ND_COLUMN, y, STR_NA);
if (attr) {
REPEAT_LAST_CURSOR_MOVE();
repeatLastCursorMove(event);
}
break;
}
@ -285,7 +285,7 @@ void menuModelLogicalSwitches(event_t event)
LogicalSwitchData * cs = lswAddress(k);
// CSW name
uint8_t sw = SWSRC_SW1+k;
uint8_t sw = SWSRC_FIRST_LOGICAL_SWITCH+k;
drawSwitch(0, y, sw, (sub==k ? INVERS : 0) | (getSwitch(sw) ? BOLD : 0));

View file

@ -99,7 +99,7 @@ void menuModelMixOne(event_t event)
killEvents(event);
}
#elif defined(NAVIGATION_XLITE)
if (event == EVT_KEY_FIRST(KEY_ENTER) && IS_SHIFT_PRESSED()) {
if (event == EVT_KEY_FIRST(KEY_ENTER) && keysGetState(KEY_SHIFT)) {
pushMenu(menuChannelsView);
killEvents(event);
}

View file

@ -90,10 +90,35 @@ void onModelSelectMenu(const char * result)
#endif
}
static void moveToFreeModelSlot(bool forward, int8_t& sub, int8_t oldSub)
{
int8_t next_ofs = s_copyTgtOfs + oldSub - menuVerticalPosition;
if (next_ofs == MAX_MODELS || next_ofs == -MAX_MODELS) next_ofs = 0;
if (s_copySrcRow < 0 && s_copyMode == COPY_MODE) {
s_copySrcRow = oldSub;
// find a hole (in the first empty slot above / below)
sub = findEmptyModel(s_copySrcRow, forward);
if (sub < 0) {
// no free room for duplicating the model
AUDIO_ERROR();
sub = oldSub;
s_copyMode = 0;
}
next_ofs = 0;
menuVerticalPosition = sub;
}
s_copyTgtOfs = next_ofs;
}
void menuModelSelect(event_t event)
{
// Suppress "edit mode": model select has none
// Suppress exit in "copy mode": handled in this function
event_t _event_ = event;
if ((s_copyMode && IS_KEY_EVT(event, KEY_EXIT)) || event == EVT_KEY_BREAK(KEY_EXIT) || IS_ROTARY_BREAK(event) || IS_ROTARY_LONG(event)) {
if ((s_copyMode && IS_KEY_EVT(event, KEY_EXIT)) ||
event == EVT_KEY_BREAK(KEY_EXIT) || event == EVT_KEY_BREAK(KEY_ENTER) ||
event == EVT_KEY_LONG(KEY_ENTER)) {
_event_ = 0;
}
@ -179,7 +204,9 @@ void menuModelSelect(event_t event)
s_copyMode = 0;
event = EVT_ENTRY_UP;
}
else if (event == EVT_KEY_LONG(KEY_ENTER) || IS_ROTARY_BREAK(event)) {
else if (event == EVT_KEY_BREAK(KEY_ENTER) ||
event == EVT_KEY_LONG(KEY_ENTER)) {
s_copyMode = 0;
killEvents(event);
if (g_eeGeneral.currModel != sub) {
@ -232,57 +259,25 @@ void menuModelSelect(event_t event)
chainMenu(menuModelSetup);
break;
#else
#if defined(ROTARY_ENCODER_NAVIGATION)
case EVT_ROTARY_LEFT:
case EVT_ROTARY_RIGHT:
#endif
case EVT_KEY_FIRST(KEY_LEFT):
case EVT_KEY_FIRST(KEY_RIGHT):
#if defined(ROTARY_ENCODER_NAVIGATION)
if ((!IS_ROTARY_RIGHT(event) && !IS_ROTARY_LEFT(event)) || s_editMode < 0) {
#endif
if (sub == g_eeGeneral.currModel) {
chainMenu((IS_ROTARY_RIGHT(event) || event == EVT_KEY_FIRST(KEY_RIGHT)) ? menuModelSetup : menuTabModel[DIM(menuTabModel)-1].menuFunc);
}
else {
bool forward = (event == EVT_KEY_FIRST(KEY_RIGHT));
chainMenu(forward ? menuModelSetup
: menuTabModel[DIM(menuTabModel) - 1].menuFunc);
} else {
AUDIO_WARNING2();
}
break;
#if defined(ROTARY_ENCODER_NAVIGATION)
#endif
}
// no break
#endif
#endif
#if defined(ROTARY_ENCODER_NAVIGATION) && defined(NAVIGATION_X7)
case EVT_ROTARY_LEFT:
case EVT_ROTARY_RIGHT:
#endif
case EVT_KEY_FIRST(KEY_UP):
case EVT_KEY_REPT(KEY_UP):
case EVT_KEY_FIRST(KEY_DOWN):
case EVT_KEY_REPT(KEY_DOWN):
if (s_copyMode) {
int8_t next_ofs = s_copyTgtOfs + oldSub - menuVerticalPosition;
if (next_ofs == MAX_MODELS || next_ofs == -MAX_MODELS)
next_ofs = 0;
if (s_copySrcRow < 0 && s_copyMode==COPY_MODE) {
s_copySrcRow = oldSub;
// find a hole (in the first empty slot above / below)
sub = findEmptyModel(s_copySrcRow, IS_ROTARY_RIGHT(event) || event==EVT_KEY_FIRST(KEY_DOWN));
if (sub < 0) {
// no free room for duplicating the model
AUDIO_ERROR();
sub = oldSub;
s_copyMode = 0;
if (IS_PREVIOUS_EVENT(event)) {
moveToFreeModelSlot(false, sub, oldSub);
} else if (IS_NEXT_EVENT(event)) {
moveToFreeModelSlot(true, sub, oldSub);
}
next_ofs = 0;
menuVerticalPosition = sub;
}
s_copyTgtOfs = next_ofs;
}
break;
}
#if defined(EEPROM)
@ -295,8 +290,6 @@ void menuModelSelect(event_t event)
uint8_t sz = menuSize(menuTabModel, DIM(menuTabModel));
#if defined(NAVIGATION_X7)
drawScreenIndex(MENU_MODEL_SELECT, sz, 0);
#elif defined(ROTARY_ENCODER_NAVIGATION)
drawScreenIndex(MENU_MODEL_SELECT, sz, (sub == g_eeGeneral.currModel) ? ((IS_ROTARY_ENCODER_NAVIGATION_ENABLE() && s_editMode < 0) ? INVERS|BLINK : INVERS) : 0);
#else
drawScreenIndex(MENU_MODEL_SELECT, sz, (sub == g_eeGeneral.currModel) ? INVERS : 0);
#endif

View file

@ -21,6 +21,9 @@
#include "opentx.h"
#include "mixer_scheduler.h"
#include "hal/adc_driver.h"
#include "hal/switch_driver.h"
#include "switches.h"
#if defined(USBJ_EX)
#include "usb_joystick.h"
@ -44,18 +47,16 @@
uint8_t g_moduleIdx;
#if defined(PCBTARANIS)
uint8_t getSwitchWarningsCount()
{
uint8_t count = 0;
for (int i=0; i<NUM_SWITCHES - NUM_FUNCTIONS_SWITCHES; ++i) {
for (int i = 0; i < switchGetMaxSwitches(); ++i) {
if (SWITCH_WARNING_ALLOWED(i)) {
++count;
}
}
return count;
}
#endif
enum MenuModelSetupItems {
ITEM_MODEL_SETUP_NAME,
@ -329,7 +330,7 @@ inline uint8_t TIMER_ROW(uint8_t timer, uint8_t value)
return HIDDEN_ROW;
}
#define POT_WARN_ROWS PREFLIGHT_ROW(((g_model.potsWarnMode) ? (uint8_t)(NUM_POTS+NUM_SLIDERS) : (uint8_t)0))
#define POT_WARN_ROWS PREFLIGHT_ROW(((g_model.potsWarnMode) ? adcGetMaxInputs(ADC_INPUT_POT) : (uint8_t)0))
#define TIMER_ROWS(x) \
1, TIMER_ROW(x,0), \
@ -504,14 +505,9 @@ void editTimerCountdown(int timerIdx, coord_t y, LcdFlags attr, event_t event)
#define EXTERNAL_MODULE_ROWS
#endif
#if defined(PCBTARANIS)
#define WARN_ROWS \
#define WARN_ROWS \
SW_WARN_ROWS, /* Switch warning */ \
POT_WARN_ROWS, /* Pot warning */
#else
#define WARN_ROWS \
PREFLIGHT_ROW((NUM_SWITCHES - 1), /* Switch warning */
#endif
#if defined(USBJ_EX)
inline uint8_t USB_JOYSTICK_EXTROW()
@ -585,7 +581,7 @@ void menuModelSetup(event_t event)
PREFLIGHT_ROW(0), // Custom position for throttle warning value
WARN_ROWS
NUM_STICKS + NUM_POTS + NUM_SLIDERS - 1, // Center beeps
uint8_t(NAVIGATION_LINE_BY_LINE | (adcGetInputOffset(ADC_INPUT_POT + 1) - 1)), // Center beeps
0, // ADC Jitter filter
@ -795,7 +791,8 @@ void menuModelSetup(event_t event)
{
int index = k - ITEM_MODEL_SETUP_SW1;
int config = FSWITCH_CONFIG(index);
lcdDrawTextAtIndex(INDENT_WIDTH, y, STR_VSRCRAW, MIXSRC_FIRST_SWITCH + NUM_REGULAR_SWITCHES - MIXSRC_Rud + index + 1, menuHorizontalPosition < 0 ? attr : 0);
lcdDrawSizedText(INDENT_WIDTH, y, STR_CHAR_SWITCH, 2, menuHorizontalPosition < 0 ? attr : 0);
drawStringWithIndex(lcdNextPos, y, STR_FUNC_SW, index, menuHorizontalPosition < 0 ? attr : 0);
if (ZEXIST(g_model.switchNames[index]) || (attr && s_editMode > 0 && menuHorizontalPosition == 0))
editName(35, y, g_model.switchNames[index], LEN_SWITCH_NAME, event, menuHorizontalPosition == 0 ? attr : 0, 0, old_editMode);
else
@ -822,7 +819,7 @@ void menuModelSetup(event_t event)
}
}
else if (attr && menuHorizontalPosition == 3) { // Non visible checkbox
REPEAT_LAST_CURSOR_MOVE();
repeatLastCursorMove(event);
}
break;
}
@ -891,7 +888,7 @@ void menuModelSetup(event_t event)
if (attr)
CHECK_INCDEC_MODELVAR_ZERO_CHECK(
event, g_model.thrTraceSrc,
NUM_POTS + NUM_SLIDERS + MAX_OUTPUT_CHANNELS,
adcGetMaxInputs(ADC_INPUT_POT) + MAX_OUTPUT_CHANNELS,
isThrottleSourceAvailable);
uint8_t idx = throttleSource2Source(g_model.thrTraceSrc);
@ -907,7 +904,7 @@ void menuModelSetup(event_t event)
case ITEM_MODEL_SETUP_THROTTLE_TRIM_SWITCH:
lcdDrawText(INDENT_WIDTH, y, STR_TTRIM_SW);
if (attr)
CHECK_INCDEC_MODELVAR_ZERO(event, g_model.thrTrimSw, NUM_TRIMS - 1);
CHECK_INCDEC_MODELVAR_ZERO(event, g_model.thrTrimSw, keysGetMaxTrims() - 1);
drawSource(MODEL_SETUP_2ND_COLUMN+20, y, g_model.getThrottleStickTrimSource(), attr);
break;
@ -939,7 +936,7 @@ void menuModelSetup(event_t event)
case ITEM_MODEL_SETUP_SWITCHES_WARNING2:
if (i==0) {
if (CURSOR_MOVED_LEFT(event))
if (IS_PREVIOUS_EVENT(event))
menuVerticalOffset--;
else
menuVerticalOffset++;
@ -948,13 +945,12 @@ void menuModelSetup(event_t event)
case ITEM_MODEL_SETUP_SWITCHES_WARNING1:
{
#define FIRSTSW_STR (&STR_VSRCRAW[MIXSRC_FIRST_SWITCH-MIXSRC_FIRST_STICK+1])
uint8_t switchWarningsCount = getSwitchWarningsCount();
//uint8_t length = STR_VSRCRAW[0];
horzpos_t l_posHorz = menuHorizontalPosition;
if (i>=NUM_BODY_LINES-2 && getSwitchWarningsCount() > MAX_SWITCH_PER_LINE*(NUM_BODY_LINES-i)) {
if (CURSOR_MOVED_LEFT(event))
if (IS_PREVIOUS_EVENT(event))
menuVerticalOffset--;
else
menuVerticalOffset++;
@ -987,7 +983,7 @@ void menuModelSetup(event_t event)
getMovedSwitch();
// Mask switches enabled for warnings
swarnstate_t sw_mask = 0;
for(uint8_t i=0; i<NUM_SWITCHES; i++) {
for(uint8_t i = 0; i < switchGetMaxSwitches(); i++) {
if (SWITCH_WARNING_ALLOWED(i))
if (g_model.switchWarningState & (0x07 << (3 * i)))
sw_mask |= (0x07 << (3 * i));
@ -1003,7 +999,7 @@ void menuModelSetup(event_t event)
}
int current = 0;
for (int i = 0; i < NUM_SWITCHES - NUM_FUNCTIONS_SWITCHES; i++) {
for (int i = 0; i < switchGetMaxSwitches(); i++) {
if (SWITCH_WARNING_ALLOWED(i)) {
div_t qr = div(current, MAX_SWITCH_PER_LINE);
if (!READ_ONLY() && event == EVT_KEY_BREAK(KEY_ENTER) && attr &&
@ -1019,9 +1015,10 @@ void menuModelSetup(event_t event)
s_editMode = 0;
#endif
}
lcdDrawSizedText(
lcdDrawChar(
MODEL_SETUP_2ND_COLUMN + qr.rem * ((2 * FW) + 1),
y + FH * qr.quot, FIRSTSW_STR[i] + sizeof(STR_CHAR_SWITCH), 1,
y + FH * qr.quot, switchGetLetter(i),
attr && (menuHorizontalPosition == current) ? INVERS : 0);
lcdDrawText(lcdNextPos, y + FH * qr.quot,
getSwitchWarnSymbol(states & 0x03));
@ -1066,30 +1063,38 @@ void menuModelSetup(event_t event)
}
if (g_model.potsWarnMode) {
coord_t x = MODEL_SETUP_2ND_COLUMN+28;
for (int i=0; i<NUM_POTS+NUM_SLIDERS; ++i) {
if (i<NUM_XPOTS && !IS_POT_SLIDER_AVAILABLE(POT1+i)) {
if (attr && (menuHorizontalPosition==i+1)) REPEAT_LAST_CURSOR_MOVE();
uint8_t max_pots = adcGetMaxInputs(ADC_INPUT_POT);
for (int i = 0; i < max_pots; ++i) {
if (!IS_POT_SLIDER_AVAILABLE(i)) {
// skip non configured pot
if (attr && (menuHorizontalPosition==i+1)) repeatLastCursorMove(event);
}
else {
LcdFlags flags = ((menuHorizontalPosition==i+1) && attr) ? BLINK : 0;
if ((!attr || menuHorizontalPosition >= 0) && (g_model.potsWarnEnabled & (1 << i))) {
if ((!attr || menuHorizontalPosition >= 0) &&
(g_model.potsWarnEnabled & (1 << i))) {
flags |= INVERS;
}
// skip "---" (+1) and source symbol (+2)
const char* source = STR_VSRCRAW[NUM_STICKS + 1 + i] + 2;
lcdDrawSizedText(x, y, source, UINT8_MAX, flags);
lcdDrawText(x, y, getPotLabel(i), flags);
x = lcdNextPos+3;
}
}
}
break;
case ITEM_MODEL_SETUP_BEEP_CENTER:
case ITEM_MODEL_SETUP_BEEP_CENTER: {
lcdDrawTextAlignedLeft(y, STR_BEEPCTR);
for (uint8_t i = 0; i < NUM_STICKS+NUM_POTS+NUM_SLIDERS; i++) {
uint8_t input_max = adcGetMaxInputs(ADC_INPUT_MAIN) + adcGetMaxInputs(ADC_INPUT_POT);
for (uint8_t i = 0; i < input_max; i++) {
coord_t x = MODEL_SETUP_2ND_COLUMN + i*FW;
lcdDrawTextAtIndex(x, y, STR_RETA123, i, ((menuHorizontalPosition==i) && attr) ? BLINK | INVERS : (((g_model.beepANACenter & ((BeepANACenter)1<<i)) || (attr && CURSOR_ON_LINE())) ? INVERS : 0 ) );
LcdFlags flags = 0;
if ((menuHorizontalPosition == i) && attr)
flags = BLINK | INVERS;
else if (ANALOG_CENTER_BEEP(x) || (attr && CURSOR_ON_LINE()))
flags = INVERS;
lcdDrawText(x, y, getAnalogShortLabel(i), flags);
}
if (attr) {
if (event == EVT_KEY_BREAK(KEY_ENTER)) {
@ -1100,7 +1105,7 @@ void menuModelSetup(event_t event)
}
}
}
break;
} break;
case ITEM_MODEL_SETUP_USE_JITTER_FILTER:
g_model.jitterFilter = editChoice(MODEL_SETUP_2ND_COLUMN, y, STR_JITTER_FILTER, STR_ADCFILTERVALUES, g_model.jitterFilter, 0, 2, attr, event);
@ -1970,7 +1975,7 @@ void menuModelSetup(event_t event)
if (isModuleTypeR9MLiteNonPro(module.type)) { // R9M lite FCC has only one power value, so displayed for info only
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_R9M_LITE_FCC_POWER_VALUES, 0, LEFT);
if (attr) {
REPEAT_LAST_CURSOR_MOVE();
repeatLastCursorMove(event);
}
}
else {

View file

@ -153,7 +153,7 @@ void menuSpecialFunctions(event_t event, CustomFunctionData * functions, CustomF
#if defined(PCBTARANIS)
#if defined(PCBXLITE)
// ENT LONG on xlite brings up switch type menu, so this menu is activated with SHIFT + ENT LONG
if (menuHorizontalPosition==0 && event==EVT_KEY_LONG(KEY_ENTER) && IS_SHIFT_PRESSED() && !READ_ONLY()) {
if (menuHorizontalPosition==0 && event==EVT_KEY_LONG(KEY_ENTER) && keysGetState(KEY_SHIFT) && !READ_ONLY()) {
#else
if (menuHorizontalPosition<0 && event==EVT_KEY_LONG(KEY_ENTER) && !READ_ONLY()) {
#endif
@ -203,7 +203,7 @@ void menuSpecialFunctions(event_t event, CustomFunctionData * functions, CustomF
case 1:
if (CFN_SWITCH(cfn)) {
lcdDrawTextAtIndex(MODEL_SPECIAL_FUNC_2ND_COLUMN, y, STR_VFSWFUNC, func, attr);
lcdDrawText(MODEL_SPECIAL_FUNC_2ND_COLUMN, y, funcGetLabel(func), attr);
if (active) {
CFN_FUNC(cfn) = checkIncDec(event, CFN_FUNC(cfn), 0, FUNC_MAX-1, eeFlags, isAssignableFunctionAvailable);
if (checkIncDec_Ret) CFN_RESET(cfn);
@ -212,7 +212,7 @@ void menuSpecialFunctions(event_t event, CustomFunctionData * functions, CustomF
else {
j = 4; // skip other fields
if (sub==k && menuHorizontalPosition > 0) {
REPEAT_LAST_CURSOR_MOVE();
repeatLastCursorMove(event);
}
}
break;
@ -227,31 +227,31 @@ void menuSpecialFunctions(event_t event, CustomFunctionData * functions, CustomF
else
#endif
if (func == FUNC_TRAINER) {
maxParam = NUM_STICKS + 1;
maxParam = MAX_STICKS + 1;
uint8_t param = CFN_CH_INDEX(cfn);
if (param == 0)
lcdDrawText(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, STR_STICKS, attr);
else if (param == NUM_STICKS + 1)
else if (param == MAX_STICKS + 1)
lcdDrawText(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, STR_CHANS, attr);
else
drawSource(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, MIXSRC_Rud + param - 1, attr);
drawSource(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, MIXSRC_FIRST_STICK + param - 1, attr);
}
#if defined(GVARS)
else if (func == FUNC_ADJUST_GVAR) {
maxParam = MAX_GVARS-1;
maxParam = MAX_GVARS - 1;
drawStringWithIndex(lcdNextPos + 2, y, STR_GV, CFN_GVAR_INDEX(cfn)+1, attr);
if (active) CFN_GVAR_INDEX(cfn) = checkIncDec(event, CFN_GVAR_INDEX(cfn), 0, maxParam, eeFlags);
break;
}
#endif // GVARS
else if (func == FUNC_SET_TIMER) {
maxParam = MAX_TIMERS-1;
maxParam = MAX_TIMERS - 1;
lcdDrawTextAtIndex(lcdNextPos, y, STR_VFSWRESET, CFN_TIMER_INDEX(cfn), attr);
if (active) CFN_TIMER_INDEX(cfn) = checkIncDec(event, CFN_TIMER_INDEX(cfn), 0, maxParam, eeFlags);
break;
}
else if (attr) {
REPEAT_LAST_CURSOR_MOVE();
repeatLastCursorMove(event);
}
if (active) CHECK_INCDEC_MODELVAR_ZERO(event, CFN_CH_INDEX(cfn), maxParam);
break;
@ -406,7 +406,7 @@ void menuSpecialFunctions(event_t event, CustomFunctionData * functions, CustomF
}
#endif // GVARS
else if (attr) {
REPEAT_LAST_CURSOR_MOVE();
repeatLastCursorMove(event);
}
#if defined(NAVIGATION_X7)
if (active || event==EVT_KEY_LONG(KEY_ENTER)) {
@ -456,7 +456,7 @@ void menuSpecialFunctions(event_t event, CustomFunctionData * functions, CustomF
}
}
else if (attr) {
REPEAT_LAST_CURSOR_MOVE();
repeatLastCursorMove(event);
}
break;
}

View file

@ -21,175 +21,7 @@
#include "opentx.h"
#include "hal/adc_driver.h"
#define XPOT_DELTA 10
#define XPOT_DELAY 10 /* cycles */
void menuCommonCalib(event_t event)
{
for (uint8_t i=0; i<NUM_STICKS+NUM_POTS+NUM_SLIDERS; i++) { // get low and high values for sticks, pots and sliders
int16_t vt = anaIn(i);
reusableBuffer.calib.loVals[i] = min(vt, reusableBuffer.calib.loVals[i]);
reusableBuffer.calib.hiVals[i] = max(vt, reusableBuffer.calib.hiVals[i]);
if (i >= POT1 && i <= POT_LAST) {
if (IS_POT_WITHOUT_DETENT(i)) {
reusableBuffer.calib.midVals[i] = (reusableBuffer.calib.hiVals[i] + reusableBuffer.calib.loVals[i]) / 2;
}
#if defined(PCBTARANIS)
uint8_t idx = i - POT1;
int count = reusableBuffer.calib.xpotsCalib[idx].stepsCount;
if (IS_POT_MULTIPOS(i) && count <= XPOTS_MULTIPOS_COUNT) {
// use raw analog value for multipos calibraton, anaIn() already has multipos decoded value
vt = getAnalogValue(i) >> 1;
if (reusableBuffer.calib.xpotsCalib[idx].lastCount == 0 ||
vt < reusableBuffer.calib.xpotsCalib[idx].lastPosition - XPOT_DELTA ||
vt > reusableBuffer.calib.xpotsCalib[idx].lastPosition + XPOT_DELTA) {
reusableBuffer.calib.xpotsCalib[idx].lastPosition = vt;
reusableBuffer.calib.xpotsCalib[idx].lastCount = 1;
}
else {
if (reusableBuffer.calib.xpotsCalib[idx].lastCount < 255)
reusableBuffer.calib.xpotsCalib[idx].lastCount++;
}
if (reusableBuffer.calib.xpotsCalib[idx].lastCount == XPOT_DELAY) {
int16_t position = reusableBuffer.calib.xpotsCalib[idx].lastPosition;
bool found = false;
for (int j=0; j<count; j++) {
int16_t step = reusableBuffer.calib.xpotsCalib[idx].steps[j];
if (position >= step-XPOT_DELTA && position <= step+XPOT_DELTA) {
found = true;
break;
}
}
if (!found) {
if (count < XPOTS_MULTIPOS_COUNT) {
reusableBuffer.calib.xpotsCalib[idx].steps[count] = position;
}
reusableBuffer.calib.xpotsCalib[idx].stepsCount += 1;
}
}
}
#endif
}
}
menuCalibrationState = reusableBuffer.calib.state; // make sure we don't scroll while calibrating
switch (event) {
case EVT_ENTRY:
case EVT_KEY_BREAK(KEY_EXIT):
reusableBuffer.calib.state = CALIB_START;
break;
case EVT_KEY_BREAK(KEY_ENTER):
reusableBuffer.calib.state++;
break;
}
switch (reusableBuffer.calib.state) {
case CALIB_START:
// START CALIBRATION
if (!READ_ONLY()) {
lcdDrawTextAlignedLeft(MENU_HEADER_HEIGHT+2*FH, STR_MENUTOSTART);
}
break;
case CALIB_SET_MIDPOINT:
// SET MIDPOINT
lcdDrawText(0*FW, MENU_HEADER_HEIGHT+FH, STR_SETMIDPOINT, INVERS);
lcdDrawTextAlignedLeft(MENU_HEADER_HEIGHT+2*FH, STR_MENUWHENDONE);
for (uint8_t i=0; i<NUM_STICKS+NUM_POTS+NUM_SLIDERS; i++) {
reusableBuffer.calib.loVals[i] = 15000;
reusableBuffer.calib.hiVals[i] = -15000;
#if defined(PCBTARANIS)
#if defined(FLYSKY_GIMBAL)
if (globalData.flyskygimbals && (i < FIRST_ANALOG_ADC_FS) )
{
reusableBuffer.calib.midVals[i] = anaIn(i);
}
else
#endif
{
reusableBuffer.calib.midVals[i] = getAnalogValue(i) >> 1;
}
if (i<NUM_XPOTS) {
reusableBuffer.calib.xpotsCalib[i].stepsCount = 0;
reusableBuffer.calib.xpotsCalib[i].lastCount = 0;
}
#else
reusableBuffer.calib.midVals[i] = anaIn(i);
#endif
}
break;
case CALIB_MOVE_STICKS:
// MOVE STICKS/POTS
lcdDrawText(0*FW, MENU_HEADER_HEIGHT+FH, STR_MOVESTICKSPOTS, INVERS);
lcdDrawTextAlignedLeft(MENU_HEADER_HEIGHT+2*FH, STR_MENUWHENDONE);
for (uint8_t i=0; i<NUM_STICKS+NUM_POTS+NUM_SLIDERS; i++) {
if (abs(reusableBuffer.calib.loVals[i]-reusableBuffer.calib.hiVals[i]) > 50) {
g_eeGeneral.calib[i].mid = reusableBuffer.calib.midVals[i];
int16_t v = reusableBuffer.calib.midVals[i] - reusableBuffer.calib.loVals[i];
g_eeGeneral.calib[i].spanNeg = v - v/STICK_TOLERANCE;
v = reusableBuffer.calib.hiVals[i] - reusableBuffer.calib.midVals[i];
g_eeGeneral.calib[i].spanPos = v - v/STICK_TOLERANCE;
}
}
#if defined(PCBTARANIS)
for (uint8_t i=POT1; i<=POT_LAST; i++) {
int idx = i - POT1;
int count = reusableBuffer.calib.xpotsCalib[idx].stepsCount;
if (IS_POT_MULTIPOS(i)) {
if (count > 1 && count <= XPOTS_MULTIPOS_COUNT) {
for (int j=0; j<count; j++) {
for (int k=j+1; k<count; k++) {
if (reusableBuffer.calib.xpotsCalib[idx].steps[k] < reusableBuffer.calib.xpotsCalib[idx].steps[j]) {
SWAP(reusableBuffer.calib.xpotsCalib[idx].steps[j], reusableBuffer.calib.xpotsCalib[idx].steps[k]);
}
}
}
StepsCalibData * calib = (StepsCalibData *) &g_eeGeneral.calib[i];
calib->count = count - 1;
for (int j=0; j<calib->count; j++) {
calib->steps[j] = (reusableBuffer.calib.xpotsCalib[idx].steps[j+1] + reusableBuffer.calib.xpotsCalib[idx].steps[j]) >> 5;
}
}
}
}
#endif
break;
case CALIB_STORE:
#if defined(RADIO_BOXER)
for (uint8_t i=POT1; i<=POT_LAST; i++) {
int idx = i - POT1;
if (IS_POT_MULTIPOS(i)) {
int count = reusableBuffer.calib.xpotsCalib[idx].stepsCount;
if (count < XPOTS_MULTIPOS_COUNT)
{
// load 6-pos calib with factory data if 6-pos was not manually calibrated
constexpr int16_t factoryValues[]= {0x5,0xd,0x16,0x1f,0x28};
StepsCalibData * calib = (StepsCalibData *) &g_eeGeneral.calib[POT3];
calib->count = 5;
for (int j=0; j<calib->count ; j++) {
calib->steps[j] = factoryValues[j];
}
}
}
}
#endif
g_eeGeneral.chkSum = evalChkSum();
storageDirty(EE_GENERAL);
reusableBuffer.calib.state = CALIB_FINISHED;
break;
default:
reusableBuffer.calib.state = CALIB_START;
break;
}
doMainScreenGraphics();
}
#include "gui/common/stdlcd/calibration.h"
void menuRadioCalibration(event_t event)
{

View file

@ -20,18 +20,14 @@
*/
#include "opentx.h"
#include "../../hal/adc_driver.h"
#if defined(FLYSKY_GIMBAL)
#include "flysky_gimbal_driver.h"
#endif
#include "hal/adc_driver.h"
#define HOLDANAVALUEFRAMES 4 /* 4* 50ms = 200 ms update rate */
void menuRadioDiagAnalogs(event_t event)
{
static int8_t entryCount = 0;
static int16_t lastShownAnalogValue[NUM_STICKS+NUM_POTS+NUM_SLIDERS];
static uint16_t lastShownAnalogValue[MAX_ANALOG_INPUTS];
enum ANAVIEWS{
ANAVIEW_FIRST,
@ -50,12 +46,9 @@ void menuRadioDiagAnalogs(event_t event)
#endif
switch (event) {
case EVT_KEY_FIRST(KEY_UP):
#if defined(KEYS_GPIO_REG_PAGEDN)
case EVT_KEY_FIRST(KEY_RIGHT):
case EVT_KEY_BREAK(KEY_PAGEDN):
#elif defined(NAVIGATION_X7)
case EVT_KEY_BREAK(KEY_PAGE):
#endif
{
if (viewpage == ANAVIEW_LAST)
viewpage = ANAVIEW_FIRST;
@ -65,12 +58,9 @@ void menuRadioDiagAnalogs(event_t event)
break;
}
case EVT_KEY_FIRST(KEY_DOWN):
#if defined(KEYS_GPIO_REG_PAGEUP)
case EVT_KEY_FIRST(KEY_LEFT):
case EVT_KEY_BREAK(KEY_PAGEUP):
#elif defined(NAVIGATION_X7)
case EVT_KEY_LONG(KEY_PAGE):
#endif
{
if (viewpage == ANAVIEW_FIRST)
viewpage = ANAVIEW_LAST;
@ -94,10 +84,10 @@ void menuRadioDiagAnalogs(event_t event)
coord_t y = MENU_HEADER_HEIGHT + 1;
lcdDrawTextAlignedLeft(y, STICKS_PWM_ENABLED() ? STR_PWM_STICKS_POTS_SLIDERS
: STR_STICKS_POTS_SLIDERS);
lcdDrawTextAlignedLeft(y, STR_STICKS_POTS_SLIDERS);
for (uint8_t i = 0; i < NUM_STICKS + NUM_POTS + NUM_SLIDERS; i++) {
for (uint8_t i = 0; i < adcGetMaxInputs(ADC_INPUT_ALL); i++) {
// TODO: if available
uint8_t x;
if (i & 1) {
x = LCD_W / 2 + INDENT_WIDTH;
@ -110,16 +100,8 @@ void menuRadioDiagAnalogs(event_t event)
switch (viewpage) {
case (ANAVIEW_RAWLOWFPS):
if (entryCount == 0) {
#if !defined(SIMU) && defined(FLYSKY_GIMBAL)
if (globalData.flyskygimbals && i < FIRST_ANALOG_ADC_FS)
{
lastShownAnalogValue[i] = hall_raw_values[i];
} else
#endif
{
lastShownAnalogValue[i] = getAnalogValue(i); // Update value
}
}
lcdDrawNumber(x+3*FW-1, y, lastShownAnalogValue[i],
LEADING0|LEFT, 4);
break;
@ -129,7 +111,7 @@ void menuRadioDiagAnalogs(event_t event)
break;
}
lcdDrawNumber(x+10*FW-1, y,
(int16_t)calibratedAnalogs[CONVERT_MODE(i)]*25/256,
(int16_t)calibratedAnalogs[i]*25/256,
RIGHT);
}

View file

@ -20,18 +20,56 @@
*/
#include "opentx.h"
#include "hal/rotary_encoder.h"
#include "hal/switch_driver.h"
#include "hal/key_driver.h"
#include "switches.h"
void displayKeyState(uint8_t x, uint8_t y, uint8_t key)
{
uint8_t t = keys[key].state();
uint8_t t = keysGetState(key);
lcdDrawChar(x, y, t+'0', t ? INVERS : 0);
}
#if !defined(PCBTARANIS)
void displaySwitchState(uint8_t x, uint8_t y, uint8_t sw)
void displayTrimState(uint8_t x, uint8_t y, uint8_t trim)
{
swsrc_t t = switchState(sw);
lcdDrawChar(x, y, (t ? '1' : '0'), t ? INVERS : 0);
uint8_t t = keysGetTrimState(trim);
lcdDrawChar(x, y, t+'0', t ? INVERS : 0);
}
static EnumKeys get_ith_key(uint8_t i)
{
auto supported_keys = keysGetSupported();
for (uint8_t k = 0; k < MAX_KEYS; k++) {
if (supported_keys & (1 << k)) {
if (i-- == 0) return (EnumKeys)k;
}
}
// should not get here,
// we assume: i < keysGetMaxKeys()
return (EnumKeys)0;
}
#if defined(FUNCTION_SWITCHES)
void menuRadioDiagFS(event_t event)
{
constexpr coord_t FS_1ST_COLUMN = 40;
constexpr coord_t FS_2ND_COLUMN = 70;
constexpr coord_t FS_3RD_COLUMN = 100;
SIMPLE_SUBMENU(STR_MENU_FSWITCH, 1);
lcdDrawText(FS_1ST_COLUMN, MENU_HEADER_HEIGHT + 1, "Phys");
lcdDrawText(FS_2ND_COLUMN, MENU_HEADER_HEIGHT + 1, "Log");
lcdDrawText(FS_3RD_COLUMN, MENU_HEADER_HEIGHT + 1, "Led");
for(uint8_t i=0; i < NUM_FUNCTIONS_SWITCHES; i++) {
coord_t y = 2*FH + i*FH;
lcdDrawText(INDENT_WIDTH, y, STR_CHAR_SWITCH, 0);
lcdDrawText(lcdNextPos, y, switchGetName(i+switchGetMaxSwitches()), 0);
lcdDrawNumber(FS_1ST_COLUMN + 2, y, getFSPhysicalState(i));
lcdDrawNumber(FS_2ND_COLUMN + 5, y, getFSLogicalState(i));
lcdDrawNumber(FS_3RD_COLUMN + 5, y, getFSLedState(i));
}
}
#endif
@ -41,62 +79,50 @@ void menuRadioDiagKeys(event_t event)
lcdDrawText(14*FW, MENU_HEADER_HEIGHT + 1, STR_VTRIM);
for (uint8_t i=0; i<10; i++) {
for (uint8_t i = 0; i < 10; i++) {
coord_t y;
if (i < NUM_TRIMS_KEYS) {
y = MENU_HEADER_HEIGHT + 1 + FH + FH*(i/2);
if (i&1) lcdDraw1bitBitmap(14*FW, y, sticks, i/2, 0);
displayKeyState(i&1? 20*FW : 18*FW, y, TRM_BASE+i);
if (i < keysGetMaxTrims() * 2) {
y = MENU_HEADER_HEIGHT + 1 + FH + FH * (i / 2);
if (i & 1) lcdDraw1bitBitmap(14 * FW, y, sticks, i / 2, 0);
displayTrimState(i & 1 ? 20 * FW : 18 * FW, y, i);
}
if (i <= KEY_MAX) {
if (i == 7) { // T8 8th key???
if (i < keysGetMaxKeys()) {
auto k = get_ith_key(i);
if (i >= 7) { // max 7 lines on display
y = MENU_HEADER_HEIGHT + 1 + FH * 6;
lcdDrawTextAtIndex(8, y, STR_VKEYS, i, 0);
lcdDrawText(8, y, keysGetLabel(k), 0);
displayKeyState(lcdNextPos + 10, y, i);
}
else {
y = MENU_HEADER_HEIGHT + 1 + FH * i;
lcdDrawTextAtIndex(0, y, STR_VKEYS, i, 0);
lcdDrawText(0, y, keysGetLabel(k), 0);
displayKeyState(5 * FW + 2, y, i);
}
}
#if (NUM_SWITCHES > 6)
if (i < NUM_SWITCHES) {
if (i < switchGetMaxSwitches()) {
if (SWITCH_EXISTS(i)) {
y = (i > 4) ? FH*(i-4)+1 : MENU_HEADER_HEIGHT + FH*i + 1;
getvalue_t val = getValue(MIXSRC_FIRST_SWITCH+i);
getvalue_t sw = ((val < 0) ? 3*i+1 : ((val == 0) ? 3*i+2 : 3*i+3));
drawSwitch(i > 4 ? 11*FW-5: 8*FW-9, y, sw, 0, false);
y = (i > 4) ? FH * (i - 4) + 1 : MENU_HEADER_HEIGHT + FH * i + 1;
getvalue_t val = getValue(MIXSRC_FIRST_SWITCH + i);
getvalue_t sw =
((val < 0) ? 3 * i + 1 : ((val == 0) ? 3 * i + 2 : 3 * i + 3));
drawSwitch(i > 4 ? 11 * FW - 5 : 8 * FW - 9, y, sw, 0, false);
}
}
#else
if (i < NUM_SWITCHES) {
if (SWITCH_EXISTS(i)) {
y = (NUM_SWITCHES - NUM_FUNCTIONS_SWITCHES > 6 ? 0 : MENU_HEADER_HEIGHT) + FH*i;
getvalue_t val = getValue(MIXSRC_FIRST_SWITCH+i);
getvalue_t sw = ((val < 0) ? 3*i+1 : ((val == 0) ? 3*i+2 : 3*i+3));
drawSwitch(8*FW+4, y, sw, 0);
}
}
#endif
}
#if defined(FUNCTION_SWITCHES) && defined(DEBUG)
lcdDrawText(LCD_W / 2 , LCD_H - 2 * FH, "Phys");
lcdDrawText(LCD_W / 2 , LCD_H - 1 * FH, "Log");
for (uint8_t i = 0; i < NUM_FUNCTIONS_SWITCHES; i++) {
lcdDrawNumber(LCD_W / 2 + 20 + (i + 1) * FW , LCD_H - 2 * FH, getFSPhysicalState(i));
lcdDrawNumber(LCD_W / 2 + 20 + (i + 1) * FW , LCD_H - 1 * FH, getFSLogicalState(i));
}
#if defined(AUTOSWITCH)
lcdDrawText(13*FW+FWNUM, LCD_H - FH + 1,"Last");
swsrc_t swtch = getMovedSwitch();
if (swtch)
drawSwitch(17*FW+FWNUM+2, LCD_H - FH + 1, swtch, 0);
#endif
#if defined(ROTARY_ENCODER_NAVIGATION)
coord_t y = LCD_H - FH + 1;
lcdDrawText(8*FW-9, y, STR_ROTARY_ENCODER);
lcdDrawNumber(12*FW+FWNUM+2, y, rotencValue / ROTARY_ENCODER_GRANULARITY, RIGHT);
lcdDrawNumber(12*FW+FWNUM+2, y, rotaryEncoderGetValue(), RIGHT);
#endif
}

View file

@ -23,6 +23,8 @@
#include "opentx.h"
#include "tasks/mixer_task.h"
#include "hal/adc_driver.h"
#include "input_mapping.h"
const unsigned char sticks[] = {
#include "sticks.lbm"
@ -48,6 +50,12 @@ const unsigned char sticks[] = {
#define CASE_BATTGRAPH(x)
#endif
#if !defined(SURFACE_RTADIO)
#define CASE_TX_MODE(x) x,
#else
#define CASE_TX_MODE(x)
#endif
enum {
CASE_RTCLOCK(ITEM_RADIO_SETUP_DATE)
CASE_RTCLOCK(ITEM_RADIO_SETUP_TIME)
@ -104,8 +112,10 @@ enum {
CASE_JACK_DETECT(ITEM_RADIO_SETUP_JACK_MODE)
ITEM_RADIO_SETUP_RX_CHANNEL_ORD,
CASE_ROTARY_ENCODER(ITEM_RADIO_SETUP_ROTARY_ENC_MODE)
#if !defined(SURFACE_RADIO)
ITEM_RADIO_SETUP_STICK_MODE_LABELS,
ITEM_RADIO_SETUP_STICK_MODE,
#endif
ITEM_VIEW_OPTIONS_LABEL,
ITEM_VIEW_OPTIONS_RADIO_TAB,
ITEM_VIEW_OPTIONS_GF,
@ -121,12 +131,6 @@ enum {
ITEM_RADIO_SETUP_MAX
};
#if defined(FRSKY_STICKS) && !defined(PCBTARANIS)
#define COL_TX_MODE 0
#else
#define COL_TX_MODE LABEL(TX_MODE)
#endif
uint8_t viewOptCheckBox(coord_t y, const char* title, uint8_t value, uint8_t attr, event_t event)
{
lcdDrawText(INDENT_WIDTH, y, title);
@ -139,9 +143,11 @@ void menuRadioSetup(event_t event)
struct gtm t;
gettime(&t);
if ((menuVerticalPosition==ITEM_RADIO_SETUP_DATE+HEADER_LINE || menuVerticalPosition==ITEM_RADIO_SETUP_TIME+HEADER_LINE) &&
(s_editMode>0) &&
(event==EVT_KEY_FIRST(KEY_ENTER) || event==EVT_KEY_FIRST(KEY_EXIT) || IS_ROTARY_BREAK(event) || IS_ROTARY_LONG(event))) {
if ((menuVerticalPosition == ITEM_RADIO_SETUP_DATE + HEADER_LINE ||
menuVerticalPosition == ITEM_RADIO_SETUP_TIME + HEADER_LINE) &&
(s_editMode > 0) &&
(event == EVT_KEY_FIRST(KEY_ENTER) || event == EVT_KEY_LONG(KEY_ENTER) ||
event == EVT_KEY_FIRST(KEY_EXIT))) {
// set the date and time into RTC chip
rtcSetTime(&t);
}
@ -198,7 +204,9 @@ void menuRadioSetup(event_t event)
0, // USB mode
CASE_JACK_DETECT(0) // Jack mode
CASE_ROTARY_ENCODER(0)
0, COL_TX_MODE, 0,
0,
CASE_TX_MODE(LABEL(TX_MODE))
CASE_TX_MODE(0)
LABEL(ViewOptions), LABEL(RadioMenuTabs), 0, 0, LABEL(ModelMenuTabs), CASE_HELI(0) CASE_FLIGHT_MODES(0) 0, 0, 0, CASE_LUA_MODEL_SCRIPTS(0) 0,
1/*to force edit mode*/});
@ -661,31 +669,47 @@ void menuRadioSetup(event_t event)
case ITEM_RADIO_SETUP_RX_CHANNEL_ORD:
lcdDrawTextAlignedLeft(y, STR_DEF_CHAN_ORD); // RAET->AETR
for (uint8_t i=1; i<=4; i++) {
putsChnLetter(RADIO_SETUP_2ND_COLUMN - FW + i*FW, y, channelOrder(i), attr);
{
for (uint8_t i = 0; i < adcGetMaxInputs(ADC_INPUT_MAIN); i++) {
putsChnLetter(RADIO_SETUP_2ND_COLUMN + i*FW, y, inputMappingChannelOrder(i), attr);
}
if (attr) {
auto max_order = inputMappingGetMaxChannelOrder() - 1;
CHECK_INCDEC_GENVAR(event, g_eeGeneral.templateSetup, 0, max_order);
}
}
if (attr) CHECK_INCDEC_GENVAR(event, g_eeGeneral.templateSetup, 0, 23);
break;
#if !defined(SURFACE_RADIO)
case ITEM_RADIO_SETUP_STICK_MODE_LABELS:
lcdDrawTextAlignedLeft(y, STR_MODE);
for (uint8_t i=0; i<4; i++) {
lcdDraw1bitBitmap(5*FW+i*(4*FW+2), y, sticks, i, 0);
#if defined(FRSKY_STICKS) && !defined(PCBTARANIS)
if (g_eeGeneral.stickReverse & (1<<i)) {
lcdDrawFilledRect(5*FW+i*(4*FW+2), y, 3*FW, FH-1);
}
#endif
}
#if defined(FRSKY_STICKS) && !defined(PCBTARANIS)
if (attr) {
s_editMode = 0;
CHECK_INCDEC_GENVAR(event, g_eeGeneral.stickReverse, 0, 15);
lcdDrawRect(5*FW-1, y-1, 16*FW+2, 9);
}
#endif
break;
case ITEM_RADIO_SETUP_STICK_MODE:
lcdDrawChar(2*FW, y, '1'+reusableBuffer.generalSettings.stickMode, attr);
{
auto controls = adcGetMaxInputs(ADC_INPUT_MAIN);
auto mode = reusableBuffer.generalSettings.stickMode;
for (uint8_t i = 0; i < controls; i++) {
source_t src = MIXSRC_FIRST_STICK + inputMappingConvertMode(mode, i);
drawSource((5 * FW - 3) + i * (4 * FW + 2), y, src, 0);
}
}
if (attr && s_editMode > 0) {
CHECK_INCDEC_GENVAR(event, reusableBuffer.generalSettings.stickMode, 0, 3);
} else if (reusableBuffer.generalSettings.stickMode !=
g_eeGeneral.stickMode) {
mixerTaskStop();
g_eeGeneral.stickMode = reusableBuffer.generalSettings.stickMode;
checkThrottleStick();
mixerTaskStart();
waitKeysReleased();
}
break;
#endif
#if defined(ROTARY_ENCODER_NAVIGATION)
case ITEM_RADIO_SETUP_ROTARY_ENC_MODE:
lcdDrawTextAlignedLeft(y, STR_ROTARY_ENC_MODE);
@ -705,23 +729,6 @@ void menuRadioSetup(event_t event)
break;
#endif
case ITEM_RADIO_SETUP_STICK_MODE:
lcdDrawChar(2*FW, y, '1'+reusableBuffer.generalSettings.stickMode, attr);
for (uint8_t i=0; i<NUM_STICKS; i++) {
drawSource((5*FW-3)+i*(4*FW+2), y, MIXSRC_Rud + *(modn12x3 + 4*reusableBuffer.generalSettings.stickMode + i), 0);
}
if (attr && s_editMode>0) {
CHECK_INCDEC_GENVAR(event, reusableBuffer.generalSettings.stickMode, 0, 3);
}
else if (reusableBuffer.generalSettings.stickMode != g_eeGeneral.stickMode) {
mixerTaskStop();
g_eeGeneral.stickMode = reusableBuffer.generalSettings.stickMode;
checkThrottleStick();
mixerTaskStart();
waitKeysReleased();
}
break;
case ITEM_VIEW_OPTIONS_LABEL:
lcdDrawTextAlignedLeft(y, STR_ENABLED_FEATURES);
break;

View file

@ -20,6 +20,11 @@
*/
#include "opentx.h"
#include "hal/adc_driver.h"
#include "hal/switch_driver.h"
#include "switches.h"
#include "input_mapping.h"
#define BIGSIZE DBLSIZE
#if defined (PCBTARANIS)
@ -76,38 +81,58 @@ void drawExternalAntennaAndRSSI()
void drawPotsBars()
{
// Optimization by Mike Blandford
for (uint8_t x = LCD_W / 2 - (NUM_POTS + NUM_SLIDERS - 1) * 5 / 2 - 1, i = NUM_STICKS; i < NUM_STICKS + NUM_POTS + NUM_SLIDERS; x += 5, i++) {
uint8_t max_pots = adcGetMaxInputs(ADC_INPUT_POT);
uint8_t offset = adcGetInputOffset(ADC_INPUT_POT);
uint8_t configured_pots = 0;
for (uint8_t i = 0; i < max_pots; i++) {
if (IS_POT_SLIDER_AVAILABLE(i)) {
uint8_t len = ((calibratedAnalogs[i] + RESX) * BAR_HEIGHT / (RESX * 2)) + 1l; // calculate once per loop
V_BAR(x, LCD_H - 8, len);
configured_pots ++;
}
}
uint8_t lines = configured_pots > 3 ? 2 : 1;
uint8_t cols = configured_pots > 4 ? 3 : configured_pots % 2 ? 3 : 2;
coord_t xstart = LCD_W / 2 - (cols % 2 ? 5 : 3);
for (uint8_t i = 0; i < max_pots; i++) {
if (IS_POT_SLIDER_AVAILABLE(i)) {
coord_t x = xstart + (i % cols) * 5;
coord_t y = i >= cols ? (LCD_H - 8 - BAR_HEIGHT / 2) : (LCD_H - 8);
auto v = calibratedAnalogs[offset + i] + RESX;
uint8_t len = (v * BAR_HEIGHT / (RESX * 2 * lines)) + 1l;
V_BAR(x, y, len);
}
}
}
void doMainScreenGraphics()
{
int16_t calibStickVert = calibratedAnalogs[CONVERT_MODE(1)];
if (g_model.throttleReversed && CONVERT_MODE(1) == THR_STICK)
#if defined(SURFACE_RADIO)
drawWheel(LBOX_CENTERX, calibratedAnalogs[ADC_MAIN_ST]);
drawThrottle(RBOX_CENTERX, calibratedAnalogs[ADC_MAIN_TH]);
#else
int16_t calibStickVert = calibratedAnalogs[ADC_MAIN_LV];
if (g_model.throttleReversed && inputMappingConvertMode(ADC_MAIN_LV) == THR_STICK)
calibStickVert = -calibStickVert;
drawStick(LBOX_CENTERX, calibratedAnalogs[CONVERT_MODE(0)], calibStickVert);
drawStick(LBOX_CENTERX, calibratedAnalogs[ADC_MAIN_LH], calibStickVert);
calibStickVert = calibratedAnalogs[CONVERT_MODE(2)];
if (g_model.throttleReversed && CONVERT_MODE(2) == THR_STICK)
calibStickVert = calibratedAnalogs[ADC_MAIN_RV];
if (g_model.throttleReversed && inputMappingConvertMode(ADC_MAIN_RV) == THR_STICK)
calibStickVert = -calibStickVert;
drawStick(RBOX_CENTERX, calibratedAnalogs[CONVERT_MODE(3)], calibStickVert);
#if defined(HARDWARE_POT1)
drawPotsBars();
drawStick(RBOX_CENTERX, calibratedAnalogs[ADC_MAIN_RH], calibStickVert);
#endif
drawPotsBars();
}
void displayTrims(uint8_t phase)
{
for (uint8_t i = 0; i < 4; i++) {
static coord_t x[4] = {TRIM_LH_X, TRIM_LV_X, TRIM_RV_X, TRIM_RH_X};
static uint8_t vert[4] = {0, 1, 1, 0};
for (uint8_t i = 0; i < keysGetMaxTrims(); i++) {
static coord_t x[] = {TRIM_LH_X, TRIM_LV_X, TRIM_RV_X, TRIM_RH_X, TRIM_LH_X, TRIM_LV_X, TRIM_RH_X, TRIM_RV_X};
static uint8_t vert[] = {0, 1, 1, 0, 0, 1, 0, 1};
coord_t xm, ym;
uint8_t stickIndex = CONVERT_MODE(i);
uint8_t stickIndex = inputMappingConvertMode(i);
xm = x[stickIndex];
uint8_t att = ROUND;
int16_t val = getTrimValue(phase, i);
@ -132,7 +157,9 @@ void displayTrims(uint8_t phase)
if (vert[i]) {
ym = 31;
if (i < 4)
lcdDrawSolidVerticalLine(xm, ym - TRIM_LEN, TRIM_LEN * 2 + 1);
if (keysGetMaxTrims() <= 4) {
if (i != 2 || !g_model.thrTrim) {
lcdDrawSolidVerticalLine(xm - 1, ym - 1, 3);
lcdDrawSolidVerticalLine(xm + 1, ym - 1, 3);
@ -149,14 +176,33 @@ void displayTrims(uint8_t phase)
lcdDrawSolidHorizontalLine(xm - 1, ym, 3);
}
if (g_model.displayTrims != DISPLAY_TRIMS_NEVER && dir != 0) {
if (g_model.displayTrims == DISPLAY_TRIMS_ALWAYS || (trimsDisplayTimer > 0 && (trimsDisplayMask & (1 << i)))) {
lcdDrawNumber(dir > 0 ? 12 : 40, xm - 2, -abs(dir), TINSIZE | VERTICAL);
if (g_model.displayTrims == DISPLAY_TRIMS_ALWAYS ||
(trimsDisplayTimer > 0 && (trimsDisplayMask & (1 << i)))) {
lcdDrawNumber(dir > 0 ? 12 : 40, xm - 2, -abs(dir),
TINSIZE | VERTICAL);
}
}
lcdDrawSquare(xm - 3, ym - 3, 7, att);
}
else {
ym -= val;
if ((i > 4 && xm < LCD_W / 2) || (i < 4 && xm > LCD_W / 2) ) {
lcdDrawSolidVerticalLine(xm - 1, ym, 1);
lcdDrawSolidVerticalLine(xm - 2, ym - 1, 3);
lcdDrawSolidVerticalLine(xm - 3, ym - 2, 5);
}
else {
lcdDrawSolidVerticalLine(xm + 1, ym, 1);
lcdDrawSolidVerticalLine(xm + 2, ym - 1, 3);
lcdDrawSolidVerticalLine(xm + 3, ym - 2, 5);
}
}
}
else {
ym = 60;
if (i < 4)
lcdDrawSolidHorizontalLine(xm - TRIM_LEN, ym, TRIM_LEN * 2 + 1);
if (keysGetMaxTrims() <= 4) {
lcdDrawSolidHorizontalLine(xm - 1, ym - 1, 3);
lcdDrawSolidHorizontalLine(xm - 1, ym + 1, 3);
xm += val;
@ -171,13 +217,32 @@ void displayTrims(uint8_t phase)
lcdDrawSolidVerticalLine(xm, ym - 1, 3);
}
if (g_model.displayTrims != DISPLAY_TRIMS_NEVER && dir != 0) {
if (g_model.displayTrims == DISPLAY_TRIMS_ALWAYS || (trimsDisplayTimer > 0 && (trimsDisplayMask & (1 << i)))) {
lcdDrawNumber((stickIndex == 0 ? (dir > 0 ? TRIM_LH_POS : TRIM_LH_NEG) : (dir > 0 ? TRIM_RH_POS : TRIM_RH_NEG)), ym - 2, -abs(dir), TINSIZE);
}
if (g_model.displayTrims == DISPLAY_TRIMS_ALWAYS ||
(trimsDisplayTimer > 0 && (trimsDisplayMask & (1 << i)))) {
lcdDrawNumber(
(stickIndex == 0 ? (dir > 0 ? TRIM_LH_POS : TRIM_LH_NEG)
: (dir > 0 ? TRIM_RH_POS : TRIM_RH_NEG)),
ym - 2, -abs(dir), TINSIZE);
}
}
lcdDrawSquare(xm - 3, ym - 3, 7, att);
}
else {
xm += val;
if (i > 3) {
lcdDrawSolidHorizontalLine(xm, ym + 1, 1);
lcdDrawSolidHorizontalLine(xm - 1, ym + 2, 3);
lcdDrawSolidHorizontalLine(xm - 2, ym + 3, 5);
}
else {
lcdDrawSolidHorizontalLine(xm, ym - 1, 1);
lcdDrawSolidHorizontalLine(xm - 1, ym - 2, 3);
lcdDrawSolidHorizontalLine(xm - 2, ym - 3, 5);
}
}
}
}
}
void displayBattVoltage()
@ -491,64 +556,46 @@ void menuMainView(event_t event)
doMainScreenGraphics();
// Switches
#if defined(PCBX9LITES)
static const uint8_t x[NUM_SWITCHES-2] = {2*FW-2, 2*FW-2, 17*FW+1, 2*FW-2, 17*FW+1};
static const uint8_t y[NUM_SWITCHES-2] = {4*FH+1, 5*FH+1, 5*FH+1, 6*FH+1, 6*FH+1};
for (int i=0; i<NUM_SWITCHES - 2; ++i) {
// -> 2 columns: one for each side
// -> 4 slots on each side (3 normal / 1 small)
uint8_t switches = switchGetMaxSwitches();
uint8_t configured_switches = 0;
for (uint8_t i = 0; i < switches; i++) {
if (SWITCH_EXISTS(i)) {
getvalue_t val = getValue(MIXSRC_FIRST_SWITCH + i);
getvalue_t sw = ((val < 0) ? 3 * i + 1 : ((val == 0) ? 3 * i + 2 : 3 * i + 3));
drawSwitch(x[i], y[i], sw, 0, false);
configured_switches ++;
}
}
drawSmallSwitch(29, 5*FH+1, 4, SW_SF);
drawSmallSwitch(16*FW+1, 5*FH+1, 4, SW_SG);
#elif defined(PCBX9LITE)
static const uint8_t x[NUM_SWITCHES] = {2 * FW - 2, 2 * FW - 2, 16 * FW + 1, 2 * FW - 2, 16 * FW + 1};
static const uint8_t y[NUM_SWITCHES] = {4 * FH + 1, 5 * FH + 1, 5 * FH + 1, 6 * FH + 1, 6 * FH + 1};
for (int i = 0; i < NUM_SWITCHES; ++i) {
if (SWITCH_EXISTS(i)) {
getvalue_t val = getValue(MIXSRC_FIRST_SWITCH + i);
getvalue_t sw = ((val < 0) ? 3 * i + 1 : ((val == 0) ? 3 * i + 2 : 3 * i + 3));
drawSwitch(x[i], y[i], sw, 0, false);
}
}
#elif defined(PCBXLITES)
static const uint8_t x[NUM_SWITCHES] = {2*FW-2, 16*FW+1, 2*FW-2, 16*FW+1, 2*FW-2, 16*FW+1};
static const uint8_t y[NUM_SWITCHES] = {4*FH+1, 4*FH+1, 6*FH+1, 6*FH+1, 5*FH+1, 5*FH+1};
for (int i=0; i<NUM_SWITCHES; ++i) {
if (SWITCH_EXISTS(i)) {
getvalue_t val = getValue(MIXSRC_FIRST_SWITCH + i);
getvalue_t sw = ((val < 0) ? 3 * i + 1 : ((val == 0) ? 3 * i + 2 : 3 * i + 3));
drawSwitch(x[i], y[i], sw, 0, false);
}
}
#elif defined(PCBTARANIS)
uint8_t switches = min(NUM_SWITCHES- NUM_FUNCTIONS_SWITCHES, 6);
if (configured_switches < 9) {
for (int i = 0; i < switches; ++i) {
if (SWITCH_EXISTS(i)) {
uint8_t x = 2 * FW - 2, y = 4 * FH + i * FH + 1;
if (i >= switches / 2) {
x = 16 * FW + 1;
y -= (switches / 2) * FH;
auto switch_display = switchGetDisplayPosition(i);
if (switch_display.row >= 3) {
drawSmallSwitch(switch_display.col == 0 ? 28 : 16 * FW + 1,
5 * FH + 1, 4, i);
}
else {
coord_t x = switch_display.col == 0 ? 2 * FW - 2 : 16 * FW + 7;
coord_t y = 33 + switch_display.row * FH;
getvalue_t val = getValue(MIXSRC_FIRST_SWITCH + i);
getvalue_t sw = ((val < 0) ? 3 * i + 1 : ((val == 0) ? 3 * i + 2 : 3 * i + 3));
getvalue_t sw =
((val < 0) ? 3 * i + 1
: ((val == 0) ? 3 * i + 2 : 3 * i + 3));
drawSwitch(x, y, sw, 0, false);
}
}
#else
// The ID0 3-POS switch is merged with the TRN switch
for (uint8_t i = SWSRC_THR; i <= SWSRC_TRN; i++) {
int8_t sw = (i == SWSRC_TRN ? (switchState(SW_ID0) ? SWSRC_ID0 : (switchState(SW_ID1) ? SWSRC_ID1 : SWSRC_ID2)) : i);
uint8_t x = 2 * FW - 2, y = i * FH + 1;
if (i >= SWSRC_AIL) {
x = 17 * FW - 1;
y -= 3 * FH;
}
drawSwitch(x, y, sw, getSwitch(i) ? INVERS : 0, false);
}
#endif
else {
for (int i = 0; i < switches; ++i) {
if (SWITCH_EXISTS(i)) {
auto switch_display = switchGetDisplayPosition(i);
coord_t x = (switch_display.col == 0 ? 8 : 96) + switch_display.row * 5;
drawSmallSwitch(x, 5 * FH + 1, 4, i);
}
}
}
}
else {
// Logical Switches
@ -556,7 +603,7 @@ void menuMainView(event_t event)
uint8_t y = LCD_H - 20;
for (uint8_t line = 0; line < 2; line++) {
for (uint8_t column = 0; column < MAX_LOGICAL_SWITCHES / 2; column++) {
int8_t len = getSwitch(SWSRC_SW1 + index) ? 10 : 1;
int8_t len = getSwitch(SWSRC_FIRST_LOGICAL_SWITCH + index) ? 10 : 1;
uint8_t x = (16 + 3 * column);
lcdDrawSolidVerticalLine(x - 1, y - len, len);
lcdDrawSolidVerticalLine(x, y - len, len);

View file

@ -22,6 +22,8 @@
#include "opentx.h"
#include "tasks.h"
#include "hal/adc_driver.h"
#if defined(BLUETOOTH)
#include "bluetooth_driver.h"
#endif
@ -60,9 +62,6 @@ void menuStatisticsView(event_t event)
#endif
break;
#if !defined(PCBTARANIS)
case EVT_KEY_LONG(KEY_MENU): // historical
#endif
case EVT_KEY_LONG(KEY_ENTER):
g_eeGeneral.globalTimer = 0;
storageDirty(EE_GENERAL);

View file

@ -21,6 +21,34 @@
#include "opentx.h"
// For surface radio
void drawWheel(coord_t centrex, int16_t tval)
{
constexpr coord_t BOX_CENTERY = (LCD_H - 9 - BOX_WIDTH / 2);
constexpr coord_t MARKER_WIDTH = 5;
lcdDrawSquare(centrex-BOX_WIDTH/2, BOX_CENTERY-BOX_WIDTH/2, BOX_WIDTH);
lcdDrawSolidHorizontalLine(centrex - MARKER_WIDTH /2 , BOX_CENTERY, MARKER_WIDTH);
coord_t x1 = centrex - MARKER_WIDTH - tval / 300;
coord_t x2 = centrex - MARKER_WIDTH + tval / 300;
lcdDrawLine( x1, BOX_CENTERY+BOX_WIDTH / MARKER_WIDTH, x2, BOX_CENTERY-BOX_WIDTH / MARKER_WIDTH, SOLID, FORCE);
lcdDrawLine( x1 + BOX_WIDTH/2, BOX_CENTERY+BOX_WIDTH / MARKER_WIDTH,
x2 + BOX_WIDTH / 2, BOX_CENTERY-BOX_WIDTH / MARKER_WIDTH, SOLID, FORCE);
#undef BOX_CENTERY
#undef MARKER_WIDTH
}
// For surface radio
void drawThrottle(coord_t centrex, int16_t wval)
{
constexpr coord_t BOX_CENTERY = (LCD_H - 9 - BOX_WIDTH / 2);
constexpr coord_t MARKER_WIDTH = 5;
lcdDrawSquare(centrex-BOX_WIDTH/2, BOX_CENTERY-BOX_WIDTH/2, BOX_WIDTH);
lcdDrawSolidHorizontalLine(centrex - MARKER_WIDTH, BOX_CENTERY, 2 * MARKER_WIDTH + 1);
coord_t tsize = wval / 150;
lcdDrawLine( centrex - tsize, BOX_CENTERY, centrex, BOX_CENTERY + tsize, SOLID, FORCE);
lcdDrawLine( centrex + tsize, BOX_CENTERY, centrex, BOX_CENTERY + tsize, SOLID, FORCE);
}
void drawStick(coord_t centrex, int16_t xval, int16_t yval)
{
#define BOX_CENTERY (LCD_H-9-BOX_WIDTH/2)

View file

@ -26,6 +26,8 @@
#include "lcd.h"
#include "menus.h"
#include "popups.h"
#include "navigation/navigation.h"
#include "common/stdlcd/draw_functions.h"
#define HEADER_LINE 0
@ -76,153 +78,45 @@ void showAlertBox(const char * title, const char * text, const char * action, ui
void doMainScreenGraphics();
extern int8_t checkIncDec_Ret; // global helper vars
#define EDIT_SELECT_FIELD 0
#define EDIT_MODIFY_FIELD 1
#define EDIT_MODIFY_STRING 2
extern int8_t s_editMode; // global editmode
// checkIncDec flags
// we leave room for EE_MODEL and EE_GENERAL
#define NO_INCDEC_MARKS 0x04
#define INCDEC_SWITCH 0x08
#define INCDEC_SOURCE 0x10
#define INCDEC_REP10 0x40
#define NO_DBLKEYS 0x80
#define INCDEC_DECLARE_VARS(f) uint8_t incdecFlag = (f); IsValueAvailable isValueAvailable = nullptr
#define INCDEC_SET_FLAG(f) incdecFlag = (f)
#define INCDEC_ENABLE_CHECK(fn) isValueAvailable = fn
#define CHECK_INCDEC_PARAM(event, var, min, max) checkIncDec(event, var, min, max, incdecFlag, isValueAvailable)
struct CheckIncDecStops
{
const int count;
const int stops[];
int min() const
{
return stops[0];
}
int max() const
{
return stops[count-1];
}
bool contains(int value) const
{
for (int i=0; i<count; ++i) {
int stop = stops[i];
if (value == stop)
return true;
else if (value < stop)
return false;
}
return false;
}
};
extern const CheckIncDecStops &stops100;
extern const CheckIncDecStops &stops1000;
extern const CheckIncDecStops &stopsSwitch;
#define INIT_STOPS(var, ...) \
const int _ ## var[] = { __VA_ARGS__ }; \
const CheckIncDecStops &var = (const CheckIncDecStops&)_ ## var;
#define CATEGORY_END(val) \
(val), (val+1)
int checkIncDec(event_t event, int val, int i_min, int i_max, unsigned int i_flags=0, IsValueAvailable isValueAvailable=nullptr, const CheckIncDecStops &stops=stops100);
#define checkIncDecModel(event, i_val, i_min, i_max) checkIncDec(event, i_val, i_min, i_max, EE_MODEL)
#define checkIncDecModelZero(event, i_val, i_max) checkIncDec(event, i_val, 0, i_max, EE_MODEL)
#define checkIncDecGen(event, i_val, i_min, i_max) checkIncDec(event, i_val, i_min, i_max, EE_GENERAL)
#define CHECK_INCDEC_MODELVAR(event, var, min, max) \
var = checkIncDecModel(event, var, min, max)
#define CHECK_INCDEC_MODELVAR_ZERO(event, var, max) \
var = checkIncDecModelZero(event, var, max)
#define CHECK_INCDEC_MODELVAR_CHECK(event, var, min, max, check) \
var = checkIncDec(event, var, min, max, EE_MODEL, check)
#define CHECK_INCDEC_MODELVAR_ZERO_CHECK(event, var, max, check) \
var = checkIncDec(event, var, 0, max, EE_MODEL, check)
#define AUTOSWITCH_ENTER_LONG() (attr && event==EVT_KEY_LONG(KEY_ENTER))
#define CHECK_INCDEC_SWITCH(event, var, min, max, flags, available) \
var = checkIncDec(event, var, min, max, (flags)|INCDEC_SWITCH, available)
#define CHECK_INCDEC_MODELSWITCH(event, var, min, max, available) \
CHECK_INCDEC_SWITCH(event, var, min, max, EE_MODEL, available)
#define CHECK_INCDEC_MODELSOURCE(event, var, min, max) \
var = checkIncDec(event, var, min, max, EE_MODEL|INCDEC_SOURCE|NO_INCDEC_MARKS, isSourceAvailable)
#define CHECK_INCDEC_GENVAR(event, var, min, max) \
var = checkIncDecGen(event, var, min, max)
#define NAVIGATION_LINE_BY_LINE 0x40
#define CURSOR_ON_LINE() (menuHorizontalPosition<0)
#define CHECK_FLAG_NO_SCREEN_INDEX 1
void check(event_t event, uint8_t curr, const MenuHandler *menuTab, uint8_t menuTabSize, const uint8_t *horTab, uint8_t horTabMax, vertpos_t maxrow, uint8_t flags=0);
void check_simple(event_t event, uint8_t curr, const MenuHandler *menuTab, uint8_t menuTabSize, vertpos_t maxrow);
void check_submenu_simple(event_t event, uint8_t maxrow);
void title(const char * s);
#define MENU_TAB(...) const uint8_t mstate_tab[] = __VA_ARGS__
#define MENU_CHECK(tab, menu, lines_count) \
check(event, menu, tab, DIM(tab), mstate_tab, DIM(mstate_tab)-1, lines_count)
#define MENU_CHECK_FLAGS(tab, menu, flags, lines_count) \
check(event, menu, tab, DIM(tab), mstate_tab, DIM(mstate_tab)-1, lines_count, flags)
#define MENU(name, tab, menu, lines_count, ...) \
MENU_TAB(__VA_ARGS__); \
MENU_CHECK(tab, menu, lines_count); \
title(name)
#define MENU_FLAGS(name, tab, menu, flags, lines_count, ...) \
MENU_TAB(__VA_ARGS__); \
MENU_CHECK_FLAGS(tab, menu, flags, lines_count); \
title(name)
#define SIMPLE_MENU(name, tab, menu, lines_count) \
check_simple(event, menu, tab, DIM(tab), lines_count); \
title(name)
#define SUBMENU_NOTITLE(lines_count, ...) \
MENU_TAB(__VA_ARGS__); \
check(event, 0, nullptr, 0, mstate_tab, DIM(mstate_tab)-1, lines_count);
#define SUBMENU(name, lines_count, ...) \
MENU_TAB(__VA_ARGS__); \
check(event, 0, nullptr, 0, mstate_tab, DIM(mstate_tab)-1, lines_count); \
title(name)
#define SIMPLE_SUBMENU_NOTITLE(lines_count) \
check_submenu_simple(event, lines_count)
#define SIMPLE_SUBMENU(name, lines_count) \
SIMPLE_SUBMENU_NOTITLE(lines_count); \
title(name)
typedef int choice_t;
choice_t editChoice(coord_t x, coord_t y, const char *label, const char* const* values, choice_t value, choice_t min, choice_t max, LcdFlags attr, event_t event, IsValueAvailable isValueAvailable = nullptr);
uint8_t editCheckBox(uint8_t value, coord_t x, coord_t y, const char *label, LcdFlags attr, event_t event);
swsrc_t editSwitch(coord_t x, coord_t y, swsrc_t value, LcdFlags attr, event_t event);
choice_t editChoice(coord_t x, coord_t y, const char *label,
const char *const *values, choice_t value, choice_t min,
choice_t max, LcdFlags attr, event_t event,
IsValueAvailable isValueAvailable = nullptr);
uint8_t editCheckBox(uint8_t value, coord_t x, coord_t y, const char *label,
LcdFlags attr, event_t event);
swsrc_t editSwitch(coord_t x, coord_t y, swsrc_t value, LcdFlags attr,
event_t event);
#if defined(GVARS)
void drawGVarValue(coord_t x, coord_t y, uint8_t gvar, gvar_t value, LcdFlags flags=0);
int16_t editGVarFieldValue(coord_t x, coord_t y, int16_t value, int16_t min, int16_t max, LcdFlags attr, uint8_t editflags, event_t event);
#define GVAR_MENU_ITEM(x, y, v, min, max, lcdattr, editflags, event) editGVarFieldValue(x, y, v, min, max, lcdattr, editflags, event)
#define displayGVar(x, y, v, min, max) GVAR_MENU_ITEM(x, y, v, min, max, 0, 0, 0)
#else
#define GVAR_MENU_ITEM(x, y, v, min, max, lcdattr, editflags, event) editGVarFieldValue(x, y, v, min, max, lcdattr, event)
int16_t editGVarFieldValue(coord_t x, coord_t y, int16_t value, int16_t min, int16_t max, LcdFlags attr, event_t event);
#define displayGVar(x, y, v, min, max) lcdDrawNumber(x, y, v)
void drawGVarValue(coord_t x, coord_t y, uint8_t gvar, gvar_t value,
LcdFlags flags = 0);
int16_t editGVarFieldValue(coord_t x, coord_t y, int16_t value, int16_t min,
int16_t max, LcdFlags attr, uint8_t editflags,
event_t event);
#define GVAR_MENU_ITEM(x, y, v, min, max, lcdattr, editflags, event) \
editGVarFieldValue(x, y, v, min, max, lcdattr, editflags, event)
#define displayGVar(x, y, v, min, max) \
GVAR_MENU_ITEM(x, y, v, min, max, 0, 0, 0)
#else // GVARS
#define GVAR_MENU_ITEM(x, y, v, min, max, lcdattr, editflags, event) \
editGVarFieldValue(x, y, v, min, max, lcdattr, event)
int16_t editGVarFieldValue(coord_t x, coord_t y, int16_t value, int16_t min,
int16_t max, LcdFlags attr, event_t event);
#define displayGVar(x, y, v, min, max) lcdDrawNumber(x, y, v)
#endif
void gvarWeightItem(coord_t x, coord_t y, MixData * md, LcdFlags attr, event_t event);
@ -239,12 +133,14 @@ void editSingleName(coord_t x, coord_t y, const char *label, char *name,
uint8_t old_editMode);
uint8_t editDelay(coord_t y, event_t event, uint8_t attr, const char * str, uint8_t delay);
#define EDIT_DELAY(y, event, attr, str, delay) editDelay(y, event, attr, str, delay)
void copySelection(char * dst, const char * src, uint8_t size);
#define COPY_MODE 1
#define MOVE_MODE 2
extern uint8_t s_copyMode;
extern int8_t s_copySrcRow;
extern int8_t s_copyTgtOfs;
@ -252,10 +148,10 @@ extern uint8_t s_currIdx;
extern uint8_t s_currIdxSubMenu;
extern uint16_t s_currSrcRaw;
extern uint16_t s_currScale;
extern uint8_t s_maxLines;
extern uint8_t s_copySrcIdx;
extern uint8_t s_copySrcCh;
extern int8_t s_currCh;
extern uint8_t s_maxLines;
uint8_t getExposCount();
void deleteExpo(uint8_t idx);
@ -277,18 +173,12 @@ void readModelNotes();
void menuChannelsView(event_t event);
#if defined(ROTARY_ENCODER_NAVIGATION)
#define CURSOR_MOVED_LEFT(event) (event==EVT_ROTARY_LEFT)
#define CURSOR_MOVED_RIGHT(event) (event==EVT_ROTARY_RIGHT)
#else
#define CURSOR_MOVED_LEFT(event) (EVT_KEY_MASK(event) == KEY_LEFT)
#define CURSOR_MOVED_RIGHT(event) (EVT_KEY_MASK(event) == KEY_RIGHT)
#endif
void repeatLastCursorMove(event_t event);
#define REPEAT_LAST_CURSOR_MOVE() { if (CURSOR_MOVED_LEFT(event) || CURSOR_MOVED_RIGHT(event)) pushEvent(event); else menuHorizontalPosition = 0; }
#define POS_HORZ_INIT(posVert) ((COLATTR(posVert) & NAVIGATION_LINE_BY_LINE) ? -1 : 0)
#define EDIT_MODE_INIT 0 // TODO enum
void onSwitchLongEnterPress(const char *result);
void onSourceLongEnterPress(const char *result);
uint8_t switchToMix(uint8_t source);

View file

@ -34,6 +34,9 @@
#if !defined(BOOT)
#include "opentx.h"
#include "hal/switch_driver.h"
#include "hal/adc_driver.h"
#include "switches.h"
#endif
#if (defined(PCBX9E) || defined(PCBX9DP)) && defined(LCD_DUAL_BUFFER)
@ -615,18 +618,15 @@ void putsVBat(coord_t x, coord_t y, LcdFlags att)
putsVolts(x, y, g_vbat100mV, att);
}
void drawStickName(coord_t x, coord_t y, uint8_t idx, LcdFlags att)
void drawMainControlLabel(coord_t x, coord_t y, uint8_t idx, LcdFlags att)
{
// Skip "---": idx + 1
// Skip source symbol: + 2
const char* stickName = STR_VSRCRAW[idx + 1] + 2;
lcdDrawSizedText(x, y, stickName, UINT8_MAX, att);
lcdDrawSizedText(x, y, getMainControlLabel(idx), UINT8_MAX, att);
}
void drawSource(coord_t x, coord_t y, uint32_t idx, LcdFlags att)
{
if (idx == MIXSRC_NONE) {
lcdDrawTextAtIndex(x, y, STR_VSRCRAW, 0, att); // TODO macro
lcdDrawText(x, y, STR_EMPTY, att);
}
else if (idx <= MIXSRC_LAST_INPUT) {
lcdDrawChar(x+2, y+1, CHR_INPUT, TINSIZE);
@ -654,54 +654,55 @@ void drawSource(coord_t x, coord_t y, uint32_t idx, LcdFlags att)
}
else if (idx <= MIXSRC_LAST_POT) {
idx = idx-MIXSRC_Rud;
if (g_eeGeneral.anaNames[idx][0]) {
if (idx < MIXSRC_FIRST_POT-MIXSRC_Rud )
lcdDrawSizedText(x, y, STR_CHAR_STICK, 2, att);
else if (idx < MIXSRC_FIRST_SLIDER-MIXSRC_Rud )
lcdDrawSizedText(x, y, STR_CHAR_POT, 2, att);
else
lcdDrawSizedText(x, y, STR_CHAR_SLIDER, 2, att);
lcdDrawSizedText(lcdNextPos, y, g_eeGeneral.anaNames[idx], LEN_ANA_NAME, att);
}
else
lcdDrawTextAtIndex(x, y, STR_VSRCRAW, idx+1, att);
lcdDrawText(x, y, getSourceString(idx), att);
}
else if (idx >= MIXSRC_FIRST_SWITCH && idx <= MIXSRC_LAST_SWITCH) {
idx = idx - MIXSRC_FIRST_SWITCH;
if (g_eeGeneral.switchNames[idx][0]) {
lcdDrawSizedText(x, y, STR_CHAR_SWITCH, 2, att);
lcdDrawSizedText(lcdNextPos, y, g_eeGeneral.switchNames[idx], LEN_SWITCH_NAME, att);
lcdDrawText(x, y, getSourceString(idx), att);
}
else {
lcdDrawTextAtIndex(x, y, STR_VSRCRAW, idx + MIXSRC_FIRST_SWITCH - MIXSRC_Rud + 1, att);
}
}
else if (idx < MIXSRC_SW1)
lcdDrawTextAtIndex(x, y, STR_VSRCRAW, idx-MIXSRC_Rud+1, att);
else if (idx <= MIXSRC_LAST_LOGICAL_SWITCH)
drawSwitch(x, y, SWSRC_SW1+idx-MIXSRC_SW1, att);
else if (idx < MIXSRC_CH1)
drawStringWithIndex(x, y, STR_PPM_TRAINER, idx-MIXSRC_FIRST_TRAINER+1, att);
else if (idx <= MIXSRC_LAST_CH) {
drawStringWithIndex(x, y, STR_CH, idx-MIXSRC_CH1+1, att);
if (ZEXIST(g_model.limitData[idx-MIXSRC_CH1].name) && (att & STREXPANDED)) {
else if (idx <= MIXSRC_LAST_LOGICAL_SWITCH) {
idx -= MIXSRC_FIRST_LOGICAL_SWITCH;
drawSwitch(x, y, idx + SWSRC_FIRST_LOGICAL_SWITCH, att);
} else if (idx <= MIXSRC_LAST_TRAINER) {
idx -= MIXSRC_FIRST_TRAINER;
drawStringWithIndex(x, y, STR_PPM_TRAINER, idx + 1, att);
} else if (idx <= MIXSRC_LAST_CH) {
idx -= MIXSRC_FIRST_CH;
drawStringWithIndex(x, y, STR_CH, idx + 1, att);
if (ZEXIST(g_model.limitData[idx].name) && (att & STREXPANDED)) {
lcdDrawChar(lcdLastRightPos, y, ' ', att|SMLSIZE);
lcdDrawSizedText(lcdLastRightPos+3, y, g_model.limitData[idx-MIXSRC_CH1].name, LEN_CHANNEL_NAME, att|SMLSIZE);
lcdDrawSizedText(lcdLastRightPos+3, y, g_model.limitData[idx].name, LEN_CHANNEL_NAME, att|SMLSIZE);
}
}
else if (idx <= MIXSRC_LAST_GVAR) {
drawStringWithIndex(x, y, STR_GV, idx-MIXSRC_GVAR1+1, att);
idx -= MIXSRC_FIRST_GVAR - 1;
drawStringWithIndex(x, y, STR_GV, idx, att);
}
else if (idx < MIXSRC_FIRST_TIMER) {
lcdDrawTextAtIndex(x, y, STR_VSRCRAW, idx-MIXSRC_Rud+1-MAX_LOGICAL_SWITCHES-MAX_TRAINER_CHANNELS-MAX_OUTPUT_CHANNELS-MAX_GVARS, att);
// Built-in sources: TX Voltage, Time, GPS (+ reserved)
const char* src_str;
switch(idx) {
case MIXSRC_TX_VOLTAGE:
src_str = STR_SRC_BATT;
break;
case MIXSRC_TX_TIME:
src_str = STR_SRC_TIME;
break;
case MIXSRC_TX_GPS:
src_str = STR_SRC_BATT;
break;
default:
src_str = "";
break;
}
lcdDrawText(x, y, src_str, att);
}
else if (idx <= MIXSRC_LAST_TIMER) {
if(ZEXIST(g_model.timers[idx-MIXSRC_FIRST_TIMER].name)) {
lcdDrawSizedText(x, y, g_model.timers[idx-MIXSRC_FIRST_TIMER].name, LEN_TIMER_NAME, att);
idx -= MIXSRC_FIRST_TIMER;
if(g_model.timers[idx].name[0]) {
lcdDrawSizedText(x, y, g_model.timers[idx].name, LEN_TIMER_NAME, att);
}
else {
lcdDrawTextAtIndex(x, y, STR_VSRCRAW, idx-MIXSRC_Rud+1-MAX_LOGICAL_SWITCHES-MAX_TRAINER_CHANNELS-MAX_OUTPUT_CHANNELS-MAX_GVARS, att);
drawStringWithIndex(x, y, STR_SRC_TIMER, idx, att);
}
}
else {
@ -714,7 +715,7 @@ void drawSource(coord_t x, coord_t y, uint32_t idx, LcdFlags att)
void putsChnLetter(coord_t x, coord_t y, uint8_t idx, LcdFlags att)
{
lcdDrawTextAtIndex(x, y, STR_RETA123, idx-1, att);
lcdDrawText(x, y, getAnalogShortLabel(idx), att);
}
void drawModelName(coord_t x, coord_t y, char *name, uint8_t id, LcdFlags att)

View file

@ -123,12 +123,12 @@ void lcdDrawNumber(coord_t x, coord_t y, int32_t val, LcdFlags mode=0);
void drawModelName(coord_t x, coord_t y, char *name, uint8_t id, LcdFlags att);
void drawSwitch(coord_t x, coord_t y, int32_t swtch, LcdFlags att=0, bool autoBold = true);
void drawStickName(coord_t x, coord_t y, uint8_t idx, LcdFlags att=0);
void drawMainControlLabel(coord_t x, coord_t y, uint8_t idx, LcdFlags att=0);
void drawSource(coord_t x, coord_t y, uint32_t idx, LcdFlags att=0);
void drawCurveName(coord_t x, coord_t y, int8_t idx, LcdFlags att=0);
void drawTimerMode(coord_t x, coord_t y, swsrc_t mode, LcdFlags att=0);
#define putsChn(x, y, idx, att) drawSource(x, y, MIXSRC_CH1+idx-1, att)
#define putsChn(x, y, idx, att) drawSource(x, y, MIXSRC_FIRST_CH+idx-1, att)
void putsChnLetter(coord_t x, coord_t y, uint8_t idx, LcdFlags attr);
void putsVolts(coord_t x, coord_t y, uint16_t volts, LcdFlags att);

View file

@ -20,6 +20,7 @@
*/
#include "opentx.h"
#include "hal/rotary_encoder.h"
void runPopupCurvePreset(event_t event)
{
@ -128,9 +129,7 @@ void menuModelCurveOne(event_t event)
lcdDrawNumber(INDENT_WIDTH, 6*FH+1, 5+crv.points, LEFT|attr);
lcdDrawText(lcdLastRightPos, 6*FH+1, STR_PTS, attr);
if (attr) {
#if defined(ROTARY_ENCODER_NAVIGATION)
rotencSpeed = ROTENC_LOWSPEED;
#endif
rotaryEncoderResetAccel();
int8_t count = checkIncDecModel(event, crv.points, -3, 12); // 2pts - 17pts
if (checkIncDec_Ret) {
int8_t newPoints[MAX_POINTS_PER_CURVE];

View file

@ -265,7 +265,7 @@ void menuModelDisplay(event_t event)
}
}
if (attr && menuHorizontalPosition == NUM_LINE_ITEMS) {
REPEAT_LAST_CURSOR_MOVE();
repeatLastCursorMove(event);
}
}
break;

View file

@ -150,11 +150,20 @@ void menuModelExpoOne(event_t event)
break;
case EXPO_FIELD_TRIM:
uint8_t not_stick = (ed->srcRaw > MIXSRC_Ail);
int8_t trimSource = -ed->trimSource;
lcdDrawTextAlignedLeft(y, STR_TRIM);
lcdDrawTextAtIndex(EXPO_ONE_2ND_COLUMN, y, STR_VMIXTRIMS, (not_stick && trimSource == 0) ? 0 : trimSource + 1, menuHorizontalPosition==0 ? attr : 0);
if (attr) ed->trimSource = -checkIncDecModel(event, trimSource, not_stick ? TRIM_ON : -TRIM_OFF, -TRIM_LAST);
{
const char* trim_str = getTrimSourceLabel(ed->srcRaw, ed->trimSource);
LcdFlags flags = RIGHT | (menuHorizontalPosition==0 ? attr : 0);
lcdDrawText(EXPO_ONE_2ND_COLUMN, y, trim_str, flags);
if (attr) {
int8_t min = TRIM_ON;
if (ed->srcRaw >= MIXSRC_FIRST_STICK && ed->srcRaw <= MIXSRC_LAST_STICK) {
min = -TRIM_OFF;
}
ed->trimSource = -checkIncDecModel(event, -ed->trimSource, min, keysGetMaxTrims());
}
}
break;
}
y += FH;

View file

@ -109,7 +109,7 @@ void menuModelLogicalSwitches(event_t event)
LogicalSwitchData * cs = lswAddress(k);
// CSW name
unsigned int sw = SWSRC_SW1+k;
unsigned int sw = SWSRC_FIRST_LOGICAL_SWITCH+k;
drawSwitch(0, y, sw, (getSwitch(sw) ? BOLD : 0) | ((sub==k && CURSOR_ON_LINE()) ? INVERS : 0));
// CSW func
@ -189,7 +189,7 @@ void menuModelLogicalSwitches(event_t event)
if (cstate == LS_FAMILY_EDGE) {
lcdDrawText(CSW_6TH_COLUMN, y, STR_NA);
if (attr && horz == LS_FIELD_DELAY) {
REPEAT_LAST_CURSOR_MOVE();
repeatLastCursorMove(event);
}
}
else if (cs->delay > 0) {
@ -200,7 +200,7 @@ void menuModelLogicalSwitches(event_t event)
}
if (attr && horz == LS_FIELD_V3 && cstate != LS_FAMILY_EDGE) {
REPEAT_LAST_CURSOR_MOVE();
repeatLastCursorMove(event);
}
if (s_editMode>0 && attr) {

View file

@ -79,6 +79,27 @@ void onModelSelectMenu(const char * result)
}
}
static void moveToFreeModelSlot(bool forward, int8_t& sub, int8_t oldSub)
{
int8_t next_ofs = s_copyTgtOfs + oldSub - menuVerticalPosition;
if (next_ofs == MAX_MODELS || next_ofs == -MAX_MODELS) next_ofs = 0;
if (s_copySrcRow < 0 && s_copyMode == COPY_MODE) {
s_copySrcRow = oldSub;
// find a hole (in the first empty slot above / below)
sub = findEmptyModel(s_copySrcRow, forward);
if (sub < 0) {
// no free room for duplicating the model
AUDIO_ERROR();
sub = oldSub;
s_copyMode = 0;
}
next_ofs = 0;
menuVerticalPosition = sub;
}
s_copyTgtOfs = next_ofs;
}
void menuModelSelect(event_t event)
{
if (warningResult) {
@ -89,10 +110,13 @@ void menuModelSelect(event_t event)
event = EVT_ENTRY_UP;
}
event_t _event_ = ((event==EVT_KEY_BREAK(KEY_ENTER) || event==EVT_KEY_LONG(KEY_ENTER)) ? 0 : event);
if ((s_copyMode && EVT_KEY_MASK(event) == KEY_EXIT) || event == EVT_KEY_BREAK(KEY_EXIT)) {
_event_ -= KEY_EXIT;
// Suppress "edit mode": model select has none
// Suppress exit in "copy mode": handled in this function
event_t _event_ = event;
if ((s_copyMode && IS_KEY_EVT(event, KEY_EXIT)) ||
event == EVT_KEY_BREAK(KEY_EXIT) || event == EVT_KEY_BREAK(KEY_ENTER) ||
event == EVT_KEY_LONG(KEY_ENTER)) {
_event_ = 0;
}
int8_t oldSub = menuVerticalPosition;
@ -101,7 +125,7 @@ void menuModelSelect(event_t event)
if (s_editMode > 0) s_editMode = 0;
int sub = menuVerticalPosition;
int8_t sub = menuVerticalPosition;
switch (event) {
case EVT_ENTRY:
@ -208,39 +232,19 @@ void menuModelSelect(event_t event)
case EVT_KEY_BREAK(KEY_PAGE):
case EVT_KEY_LONG(KEY_PAGE):
chainMenu(event == EVT_KEY_BREAK(KEY_PAGE) ? menuModelSetup : menuTabModel[DIM(menuTabModel)-1].menuFunc);
chainMenu(event == EVT_KEY_BREAK(KEY_PAGE)
? menuModelSetup
: menuTabModel[DIM(menuTabModel) - 1].menuFunc);
killEvents(event);
break;
}
case EVT_KEY_FIRST(KEY_UP):
case EVT_KEY_REPT(KEY_UP):
case EVT_KEY_FIRST(KEY_DOWN):
case EVT_KEY_REPT(KEY_DOWN):
#if defined(ROTARY_ENCODER_NAVIGATION)
case EVT_ROTARY_LEFT:
case EVT_ROTARY_RIGHT:
#endif
if (s_copyMode) {
int8_t next_ofs = s_copyTgtOfs + oldSub - menuVerticalPosition;
if (next_ofs == MAX_MODELS || next_ofs == -MAX_MODELS)
next_ofs = 0;
if (s_copySrcRow < 0 && s_copyMode==COPY_MODE) {
s_copySrcRow = oldSub;
// find a hole (in the first empty slot above / below)
sub = findEmptyModel(s_copySrcRow, event==EVT_KEY_FIRST(KEY_DOWN) || event==EVT_KEY_REPT(KEY_DOWN));
if (sub < 0) {
// no free room for duplicating the model
AUDIO_ERROR();
sub = oldSub;
s_copyMode = 0;
if (IS_PREVIOUS_EVENT(event)) {
moveToFreeModelSlot(false, sub, oldSub);
} else if (IS_NEXT_EVENT(event)) {
moveToFreeModelSlot(true, sub, oldSub);
}
next_ofs = 0;
menuVerticalPosition = sub;
}
s_copyTgtOfs = next_ofs;
}
break;
}
#if defined(EEPROM)

View file

@ -19,8 +19,13 @@
* GNU General Public License for more details.
*/
#include "hal/adc_driver.h"
#include "hal/adc_driver.h"
#include "hal/switch_driver.h"
#include "opentx.h"
#include "mixer_scheduler.h"
#include "switches.h"
#if defined(USBJ_EX)
#include "usb_joystick.h"
@ -35,7 +40,7 @@ uint8_t g_moduleIdx;
uint8_t getSwitchWarningsCount()
{
uint8_t count = 0;
for (int i=0; i<NUM_SWITCHES; ++i) {
for (int i = 0; i < switchGetMaxSwitches(); ++i) {
if (SWITCH_WARNING_ALLOWED(i)) {
++count;
}
@ -396,20 +401,21 @@ inline uint8_t EXTERNAL_MODULE_TYPE_ROW()
#elif TIMERS == 3
#define TIMERS_ROWS TIMER_ROWS(0), TIMER_ROWS(1), TIMER_ROWS(2)
#endif
#if defined(PCBX9E)
#define SW_WARN_ROWS \
PREFLIGHT_ROW(uint8_t(NAVIGATION_LINE_BY_LINE|(getSwitchWarningsCount()-1))), \
PREFLIGHT_ROW(uint8_t(getSwitchWarningsCount() > 8 ? TITLE_ROW : HIDDEN_ROW)), \
PREFLIGHT_ROW(uint8_t(getSwitchWarningsCount() > 16 ? TITLE_ROW : HIDDEN_ROW))
#define POT_WARN_ROWS \
PREFLIGHT_ROW(uint8_t(g_model.potsWarnMode ? NAVIGATION_LINE_BY_LINE|(NUM_POTS+NUM_SLIDERS) : 0)), \
PREFLIGHT_ROW(uint8_t(g_model.potsWarnMode ? NAVIGATION_LINE_BY_LINE|(MAX_POTS) : 0)), \
PREFLIGHT_ROW(uint8_t(g_model.potsWarnMode ? TITLE_ROW : HIDDEN_ROW))
#define TOPLCD_ROWS 0,
#else
#define SW_WARN_ROWS \
PREFLIGHT_ROW(uint8_t(NAVIGATION_LINE_BY_LINE|getSwitchWarningsCount()))
#define POT_WARN_ROWS \
PREFLIGHT_ROW(uint8_t(g_model.potsWarnMode ? NAVIGATION_LINE_BY_LINE|(NUM_POTS+NUM_SLIDERS) : 0))
PREFLIGHT_ROW(uint8_t(g_model.potsWarnMode ? NAVIGATION_LINE_BY_LINE|(MAX_POTS) : 0))
#define TOPLCD_ROWS
#endif
@ -537,7 +543,7 @@ void menuModelSetup(event_t event)
SW_WARN_ROWS, // Switch warning
POT_WARN_ROWS, // Pot warning
NAVIGATION_LINE_BY_LINE | (NUM_STICKS+NUM_POTS+NUM_SLIDERS-1), // Center beeps
uint8_t(NAVIGATION_LINE_BY_LINE | (adcGetInputOffset(ADC_INPUT_POT + 1) - 1)), // Center beeps
0, // ADC Jitter filter
@ -796,7 +802,7 @@ void menuModelSetup(event_t event)
if (attr)
CHECK_INCDEC_MODELVAR_ZERO_CHECK(
event, g_model.thrTraceSrc,
NUM_POTS + NUM_SLIDERS + MAX_OUTPUT_CHANNELS,
MAX_POTS + MAX_OUTPUT_CHANNELS,
isThrottleSourceAvailable);
uint8_t idx = throttleSource2Source(g_model.thrTraceSrc);
@ -811,7 +817,7 @@ void menuModelSetup(event_t event)
case ITEM_MODEL_SETUP_THROTTLE_TRIM_SWITCH:
lcdDrawTextAlignedLeft(y, STR_TTRIM_SW);
if (attr)
CHECK_INCDEC_MODELVAR_ZERO(event, g_model.thrTrimSw, NUM_TRIMS - 1);
CHECK_INCDEC_MODELVAR_ZERO(event, g_model.thrTrimSw, MAX_TRIMS - 1);
drawSource(MODEL_SETUP_2ND_COLUMN, y, g_model.getThrottleStickTrimSource(), attr);
break;
@ -846,7 +852,7 @@ void menuModelSetup(event_t event)
case ITEM_MODEL_SETUP_SWITCHES_WARNING3:
case ITEM_MODEL_SETUP_POTS_WARNING2:
if (i==0) {
if (CURSOR_MOVED_LEFT(event))
if (IS_PREVIOUS_EVENT(event))
menuVerticalOffset--;
else
menuVerticalOffset++;
@ -858,7 +864,7 @@ void menuModelSetup(event_t event)
{
#if defined(PCBX9E)
if (i>=NUM_BODY_LINES-2 && getSwitchWarningsCount() > 8*(NUM_BODY_LINES-i)) {
if (CURSOR_MOVED_LEFT(event))
if (IS_PREVIOUS_EVENT(event))
menuVerticalOffset--;
else
menuVerticalOffset++;
@ -881,7 +887,7 @@ void menuModelSetup(event_t event)
getMovedSwitch();
// Mask switches enabled for warnings
swarnstate_t sw_mask = 0;
for(uint8_t i=0; i<NUM_SWITCHES; i++) {
for(uint8_t i = 0; i < switchGetMaxSwitches(); i++) {
if (SWITCH_WARNING_ALLOWED(i))
if (g_model.switchWarningState & (0x07 << (3 * i)))
sw_mask |= (0x07 << (3 * i));
@ -899,7 +905,7 @@ void menuModelSetup(event_t event)
LcdFlags line = attr;
int current = 0;
for (int i=0; i<NUM_SWITCHES; i++) {
for (int i = 0; i < switchGetMaxSwitches(); i++) {
if (SWITCH_WARNING_ALLOWED(i)) {
div_t qr = div(current, 8);
if (!READ_ONLY() && event == EVT_KEY_BREAK(KEY_ENTER) && line &&
@ -935,7 +941,7 @@ void menuModelSetup(event_t event)
case ITEM_MODEL_SETUP_POTS_WARNING:
#if defined(PCBX9E)
if (i==NUM_BODY_LINES-1 && g_model.potsWarnMode) {
if (CURSOR_MOVED_LEFT(event))
if (IS_PREVIOUS_EVENT(event))
menuVerticalOffset--;
else
menuVerticalOffset++;
@ -971,25 +977,25 @@ void menuModelSetup(event_t event)
}
if (g_model.potsWarnMode) {
coord_t x = MODEL_SETUP_2ND_COLUMN+28;
for (int i=0; i<NUM_POTS+NUM_SLIDERS; ++i) {
if (i<NUM_XPOTS && !IS_POT_SLIDER_AVAILABLE(POT1+i)) {
if (attr && (menuHorizontalPosition==i+1)) REPEAT_LAST_CURSOR_MOVE();
uint8_t max_pots = adcGetMaxInputs(ADC_INPUT_POT);
for (int i = 0; i < max_pots; ++i) {
if (!IS_POT_SLIDER_AVAILABLE(i)) {
// skip non configured pot
if (attr && (menuHorizontalPosition==i+1)) repeatLastCursorMove(event);
}
else {
#if defined(PCBX9E)
if (i == NUM_XPOTS) {
if (max_pots > 5 && i == 3) {
y += FH;
x = MODEL_SETUP_2ND_COLUMN;
}
#endif
LcdFlags flags = ((menuHorizontalPosition==i+1) && attr) ? BLINK : 0;
if ((!attr || menuHorizontalPosition >= 0) && (g_model.potsWarnEnabled & (1 << i))) {
if ((!attr || menuHorizontalPosition >= 0) &&
(g_model.potsWarnEnabled & (1 << i))) {
flags |= INVERS;
}
// skip "---" (+1) and source symbol (+2)
const char* source = STR_VSRCRAW[NUM_STICKS + 1 + i] + 2;
lcdDrawSizedText(x, y, source, UINT8_MAX, flags);
lcdDrawText(x, y, getPotLabel(i), flags);
x = lcdNextPos+3;
}
}
@ -1003,17 +1009,22 @@ void menuModelSetup(event_t event)
}
break;
case ITEM_MODEL_SETUP_BEEP_CENTER:
{
case ITEM_MODEL_SETUP_BEEP_CENTER: {
lcdDrawTextAlignedLeft(y, STR_BEEPCTR);
coord_t x = MODEL_SETUP_2ND_COLUMN;
for (int i=0; i<NUM_STICKS+NUM_POTS+NUM_SLIDERS; i++) {
if (i>=POT1 && i<POT1+NUM_XPOTS && !IS_POT_SLIDER_AVAILABLE(i)) {
if (attr && menuHorizontalPosition == i) REPEAT_LAST_CURSOR_MOVE();
uint8_t pot_offset = adcGetInputOffset(ADC_INPUT_POT);
uint8_t max_inputs = adcGetMaxInputs(ADC_INPUT_MAIN) + adcGetMaxInputs(ADC_INPUT_POT);
for (uint8_t i = 0; i < max_inputs; i++) {
coord_t x = MODEL_SETUP_2ND_COLUMN + i*FW;
if ( i >= pot_offset && IS_POT_MULTIPOS(i - pot_offset) ) {
if (attr && menuHorizontalPosition == i) repeatLastCursorMove(event);
continue;
}
lcdDrawTextAtIndex(x, y, STR_RETA123, i, ((menuHorizontalPosition==i) && attr) ? BLINK|INVERS : (((g_model.beepANACenter & ((BeepANACenter)1<<i)) || (attr && CURSOR_ON_LINE())) ? INVERS : 0 ) );
x += FW;
LcdFlags flags = 0;
if ((menuHorizontalPosition == i) && attr)
flags = BLINK | INVERS;
else if (ANALOG_CENTER_BEEP(x) || (attr && CURSOR_ON_LINE()))
flags = INVERS;
lcdDrawText(x, y, getAnalogShortLabel(i), flags);
}
if (attr && CURSOR_ON_CELL) {
if (event==EVT_KEY_BREAK(KEY_ENTER)) {

View file

@ -195,7 +195,7 @@ void menuSpecialFunctions(event_t event, CustomFunctionData * functions, CustomF
case ITEM_CUSTOM_FUNCTIONS_FUNCTION:
if (CFN_SWITCH(cfn)) {
lcdDrawTextAtIndex(MODEL_SPECIAL_FUNC_2ND_COLUMN, y, STR_VFSWFUNC, func, attr);
lcdDrawText(MODEL_SPECIAL_FUNC_2ND_COLUMN, y, funcGetLabel(func), attr);
if (active) {
func = CFN_FUNC(cfn) = checkIncDec(event, CFN_FUNC(cfn), 0, FUNC_MAX-1, eeFlags, isAssignableFunctionAvailable);
if (checkIncDec_Ret) CFN_RESET(cfn);
@ -204,7 +204,7 @@ void menuSpecialFunctions(event_t event, CustomFunctionData * functions, CustomF
else {
j = ITEM_CUSTOM_FUNCTIONS_LAST; // skip other fields
if (sub==k && menuHorizontalPosition > 0) {
REPEAT_LAST_CURSOR_MOVE();
repeatLastCursorMove(event);
}
}
break;
@ -219,14 +219,14 @@ void menuSpecialFunctions(event_t event, CustomFunctionData * functions, CustomF
else
#endif
if (func == FUNC_TRAINER) {
maxParam = NUM_STICKS + 1;
maxParam = MAX_STICKS + 1;
uint8_t param = CFN_CH_INDEX(cfn);
if (param == 0)
lcdDrawText(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, STR_STICKS, attr);
else if (param == NUM_STICKS + 1)
else if (param == MAX_STICKS + 1)
lcdDrawText(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, STR_CHANS, attr);
else
drawSource(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, MIXSRC_Rud + param - 1, attr);
drawSource(MODEL_SPECIAL_FUNC_3RD_COLUMN, y, MIXSRC_FIRST_STICK + param - 1, attr);
}
#if defined(GVARS)
else if (func == FUNC_ADJUST_GVAR) {
@ -243,7 +243,7 @@ void menuSpecialFunctions(event_t event, CustomFunctionData * functions, CustomF
break;
}
else if (attr) {
REPEAT_LAST_CURSOR_MOVE();
repeatLastCursorMove(event);
}
if (active) CHECK_INCDEC_MODELVAR_ZERO(event, CFN_CH_INDEX(cfn), maxParam);
break;
@ -388,7 +388,7 @@ void menuSpecialFunctions(event_t event, CustomFunctionData * functions, CustomF
}
#endif
else if (attr) {
REPEAT_LAST_CURSOR_MOVE();
repeatLastCursorMove(event);
}
if (active || event==EVT_KEY_LONG(KEY_ENTER)) {
@ -436,7 +436,7 @@ void menuSpecialFunctions(event_t event, CustomFunctionData * functions, CustomF
}
}
else if (attr) {
REPEAT_LAST_CURSOR_MOVE();
repeatLastCursorMove(event);
}
break;
}

View file

@ -21,6 +21,7 @@
#include "opentx.h"
#include "hal/adc_driver.h"
#include "gui/common/stdlcd/calibration.h"
#define XPOT_DELTA 10
#define XPOT_DELAY 10 /* cycles */
@ -30,168 +31,28 @@
void drawPotsBars()
{
// Optimization by Mike Blandford
for (uint8_t x=LCD_W/2-(NUM_POTS+NUM_SLIDERS)/2*BAR_SPACING+BAR_SPACING/2, i=NUM_STICKS; i<NUM_STICKS+NUM_POTS+NUM_SLIDERS; x+=BAR_SPACING, i++) {
uint8_t max_pots = adcGetMaxInputs(ADC_INPUT_POT);
uint8_t offset = adcGetInputOffset(ADC_INPUT_POT);
for (uint8_t x = LCD_W / 2 - max_pots / 2 * BAR_SPACING + BAR_SPACING / 2,
i = 0;
i < max_pots; x += BAR_SPACING, i++) {
if (IS_POT_SLIDER_AVAILABLE(i)) {
uint8_t len = ((calibratedAnalogs[i]+RESX)*BAR_HEIGHT/(RESX*2))+1l; // calculate once per loop
V_BAR(x, LCD_H-8, len);
drawStickName(x-2, LCD_H-6, i, TINSIZE);
// calculate once per loop
auto v = calibratedAnalogs[offset + i] + RESX;
uint8_t len = (v * BAR_HEIGHT / (RESX * 2)) + 1l;
V_BAR(x, LCD_H - 8, len);
lcdDrawText(x - 2, LCD_H - 6, getPotLabel(i), TINSIZE);
}
}
}
void menuCommonCalib(event_t event)
{
for (uint8_t i=0; i<NUM_STICKS+NUM_POTS+NUM_SLIDERS; i++) { // get low and high vals for sticks and trims
int16_t vt = anaIn(i);
reusableBuffer.calib.loVals[i] = min(vt, reusableBuffer.calib.loVals[i]);
reusableBuffer.calib.hiVals[i] = max(vt, reusableBuffer.calib.hiVals[i]);
if (i >= POT1 && i <= POT_LAST) {
if (IS_POT_WITHOUT_DETENT(i)) {
reusableBuffer.calib.midVals[i] = (reusableBuffer.calib.hiVals[i] + reusableBuffer.calib.loVals[i]) / 2;
}
uint8_t idx = i - POT1;
int count = reusableBuffer.calib.xpotsCalib[idx].stepsCount;
if (IS_POT_MULTIPOS(i) && count <= XPOTS_MULTIPOS_COUNT) {
// use raw analog value for multipos calibraton, anaIn() already has multipos decoded value
vt = getAnalogValue(i) >> 1;
if (reusableBuffer.calib.xpotsCalib[idx].lastCount == 0 || vt < reusableBuffer.calib.xpotsCalib[idx].lastPosition - XPOT_DELTA || vt > reusableBuffer.calib.xpotsCalib[idx].lastPosition + XPOT_DELTA) {
reusableBuffer.calib.xpotsCalib[idx].lastPosition = vt;
reusableBuffer.calib.xpotsCalib[idx].lastCount = 1;
}
else {
if (reusableBuffer.calib.xpotsCalib[idx].lastCount < 255) reusableBuffer.calib.xpotsCalib[idx].lastCount++;
}
if (reusableBuffer.calib.xpotsCalib[idx].lastCount == XPOT_DELAY) {
int16_t position = reusableBuffer.calib.xpotsCalib[idx].lastPosition;
bool found = false;
for (int j=0; j<count; j++) {
int16_t step = reusableBuffer.calib.xpotsCalib[idx].steps[j];
if (position >= step-XPOT_DELTA && position <= step+XPOT_DELTA) {
found = true;
break;
}
}
if (!found) {
if (count < XPOTS_MULTIPOS_COUNT) {
reusableBuffer.calib.xpotsCalib[idx].steps[count] = position;
}
reusableBuffer.calib.xpotsCalib[idx].stepsCount += 1;
}
}
}
}
}
menuCalibrationState = reusableBuffer.calib.state; // make sure we don't scroll while calibrating
switch (event) {
case EVT_ENTRY:
case EVT_KEY_BREAK(KEY_EXIT):
reusableBuffer.calib.state = CALIB_START;
break;
case EVT_KEY_BREAK(KEY_ENTER):
reusableBuffer.calib.state++;
break;
}
switch (reusableBuffer.calib.state) {
case CALIB_START:
// START CALIBRATION
if (!READ_ONLY()) {
lcdDrawTextAlignedLeft(MENU_HEADER_HEIGHT+2*FH, STR_MENUTOSTART);
}
break;
case CALIB_SET_MIDPOINT:
// SET MIDPOINT
lcdDrawText(0*FW, MENU_HEADER_HEIGHT+FH, STR_SETMIDPOINT, INVERS);
lcdDrawTextAlignedLeft(MENU_HEADER_HEIGHT+2*FH, STR_MENUWHENDONE);
for (uint8_t i=0; i<NUM_STICKS+NUM_POTS+NUM_SLIDERS; i++) {
reusableBuffer.calib.loVals[i] = 15000;
reusableBuffer.calib.hiVals[i] = -15000;
reusableBuffer.calib.midVals[i] = getAnalogValue(i) >> 1;
if (i<NUM_XPOTS) {
reusableBuffer.calib.xpotsCalib[i].stepsCount = 0;
reusableBuffer.calib.xpotsCalib[i].lastCount = 0;
}
}
break;
case CALIB_MOVE_STICKS:
// MOVE STICKS/POTS
lcdDrawText(0*FW, MENU_HEADER_HEIGHT+FH, STR_MOVESTICKSPOTS, INVERS);
lcdDrawTextAlignedLeft(MENU_HEADER_HEIGHT+2*FH, STR_MENUWHENDONE);
for (uint8_t i=0; i<NUM_STICKS+NUM_POTS+NUM_SLIDERS; i++) {
if (abs(reusableBuffer.calib.loVals[i]-reusableBuffer.calib.hiVals[i]) > 50) {
g_eeGeneral.calib[i].mid = reusableBuffer.calib.midVals[i];
int16_t v = reusableBuffer.calib.midVals[i] - reusableBuffer.calib.loVals[i];
g_eeGeneral.calib[i].spanNeg = v - v/STICK_TOLERANCE;
v = reusableBuffer.calib.hiVals[i] - reusableBuffer.calib.midVals[i];
g_eeGeneral.calib[i].spanPos = v - v/STICK_TOLERANCE;
}
}
break;
case CALIB_STORE:
for (uint8_t i=POT1; i<=POT_LAST; i++) {
int idx = i - POT1;
int count = reusableBuffer.calib.xpotsCalib[idx].stepsCount;
if (IS_POT_MULTIPOS(i)) {
if (count > 1 && count <= XPOTS_MULTIPOS_COUNT) {
for (int j=0; j<count; j++) {
for (int k=j+1; k<count; k++) {
if (reusableBuffer.calib.xpotsCalib[idx].steps[k] < reusableBuffer.calib.xpotsCalib[idx].steps[j]) {
SWAP(reusableBuffer.calib.xpotsCalib[idx].steps[j], reusableBuffer.calib.xpotsCalib[idx].steps[k]);
}
}
}
StepsCalibData * calib = (StepsCalibData *) &g_eeGeneral.calib[i];
calib->count = count - 1;
for (int j=0; j<calib->count; j++) {
calib->steps[j] = (reusableBuffer.calib.xpotsCalib[idx].steps[j+1] + reusableBuffer.calib.xpotsCalib[idx].steps[j]) >> 5;
}
}
else {
g_eeGeneral.potsConfig &= ~(0x03<<(2*idx));
}
}
}
g_eeGeneral.chkSum = evalChkSum();
storageDirty(EE_GENERAL);
reusableBuffer.calib.state = CALIB_FINISHED;
break;
default:
reusableBuffer.calib.state = CALIB_START;
break;
}
doMainScreenGraphics();
drawPotsBars();
#if 0
for (int i=POT1; i<=POT_LAST; i++) {
uint8_t steps = 0;
if (reusableBuffer.calib.state == CALIB_MOVE_STICKS) {
steps = reusableBuffer.calib.xpotsCalib[i-POT1].stepsCount;
}
else if (IS_POT_MULTIPOS(i)) {
StepsCalibData * calib = (StepsCalibData *) &g_eeGeneral.calib[i];
steps = calib->count + 1;
}
if (steps > 0 && steps <= XPOTS_MULTIPOS_COUNT) {
lcdDrawNumber(LCD_W/2-2+(i-POT1)*5, LCD_H-6, steps, TINSIZE|RIGHT);
}
}
#endif
}
void menuRadioCalibration(event_t event)
{
check_submenu_simple(event, 0);
title(STR_MENUCALIBRATION);
menuCommonCalib(READ_ONLY() ? 0 : event);
drawPotsBars();
if (menuEvent) {
menuCalibrationState = CALIB_START;
}
@ -207,5 +68,6 @@ void menuFirstCalib(event_t event)
lcdDrawText(LCD_W / 2, 0, STR_MENUCALIBRATION, CENTERED);
lcdInvertLine(0);
menuCommonCalib(event);
drawPotsBars();
}
}

View file

@ -27,7 +27,7 @@
void menuRadioDiagAnalogs(event_t event)
{
static int8_t entryCount = 0;
static uint16_t lastShownAnalogValue[NUM_STICKS+NUM_POTS+NUM_SLIDERS];
static uint16_t lastShownAnalogValue[MAX_ANALOG_INPUTS];
enum ANAVIEWS{
ANAVIEW_FIRST,
@ -53,7 +53,7 @@ void menuRadioDiagAnalogs(event_t event)
case (ANAVIEW_RAWLOWFPS): SIMPLE_SUBMENU(STR_MENU_RADIO_ANALOGS_RAWLOWFPS, 0); break;
}
for (uint8_t i=0; i<NUM_STICKS+NUM_POTS+NUM_SLIDERS; i++) {
for (uint8_t i = 0; i < MAX_ANALOG_INPUTS; i++) {
coord_t y = MENU_HEADER_HEIGHT + 1 + (i/2)*FH;
uint8_t x = i&1 ? LCD_W/2 + FW : 0;
lcdDrawNumber(x, y, i+1, LEADING0|LEFT, 2);
@ -75,9 +75,9 @@ void menuRadioDiagAnalogs(event_t event)
#if defined(JITTER_MEASURE)
lcdDrawNumber(x+10*FW-1, y, rawJitter[i].get(), RIGHT);
lcdDrawNumber(x+13*FW-1, y, avgJitter[i].get(), RIGHT);
lcdDrawNumber(x+17*FW-1, y, (int16_t)calibratedAnalogs[CONVERT_MODE(i)]*25/256, RIGHT);
lcdDrawNumber(x+17*FW-1, y, (int16_t)calibratedAnalogs[i]*25/256, RIGHT);
#else
lcdDrawNumber(x+10*FW-1, y, (int16_t)calibratedAnalogs[CONVERT_MODE(i)]*25/256, RIGHT);
lcdDrawNumber(x+10*FW-1, y, (int16_t)calibratedAnalogs[i]*25/256, RIGHT);
#endif
}

View file

@ -21,32 +21,55 @@
#include "opentx.h"
#include "hal/rotary_encoder.h"
#include "hal/switch_driver.h"
void displayKeyState(uint8_t x, uint8_t y, uint8_t key)
{
uint8_t t = keys[key].state();
uint8_t t = keysGetState(key);
lcdDrawChar(x, y, t+'0', t ? INVERS : 0);
}
void displayTrimState(uint8_t x, uint8_t y, uint8_t trim)
{
uint8_t t = keysGetTrimState(trim);
lcdDrawChar(x, y, t+'0', t ? INVERS : 0);
}
static EnumKeys get_ith_key(uint8_t i)
{
auto supported_keys = keysGetSupported();
for (uint8_t k = 0; k < MAX_KEYS; k++) {
if (supported_keys & (1 << k)) {
if (i-- == 0) return (EnumKeys)k;
}
}
// should not get here,
// we assume: i < keysGetMaxKeys()
return (EnumKeys)0;
}
void menuRadioDiagKeys(event_t event)
{
SIMPLE_SUBMENU(STR_MENU_RADIO_SWITCHES, 1);
lcdDrawText(24*FW, MENU_HEADER_HEIGHT + 1, STR_VTRIM);
for (uint8_t i = 0; i < NUM_TRIMS_KEYS; i++) {
for (uint8_t i = 0; i < keysGetMaxTrims() * 2; i++) {
coord_t y = MENU_HEADER_HEIGHT + 1 + FH + FH * (i / 2);
if (i & 1)
lcdDraw1bitBitmap(24 * FW, y, sticks, i / 2, 0);
displayKeyState(i & 1 ? 30 * FW : 28 * FW, y, TRM_BASE + i);
if (i & 1) lcdDraw1bitBitmap(24 * FW, y, sticks, i / 2, 0);
displayTrimState(i & 1 ? 30 * FW : 28 * FW, y, i);
}
for (uint8_t i = 0; i <= KEY_MAX; i++) {
for (uint8_t i = 0; i < keysGetMaxKeys(); i++) {
auto k = get_ith_key(i);
coord_t y = MENU_HEADER_HEIGHT + 1 + FH * i;
lcdDrawTextAtIndex(0, y, STR_VKEYS, (i), 0);
lcdDrawText(0, y, keysGetLabel(k), 0);
displayKeyState(5 * FW + 2, y, i);
}
for (uint8_t i = 0, cnt = 0; i < NUM_SWITCHES; i++) {
for (uint8_t i = 0, cnt = 0; i < switchGetMaxSwitches(); i++) {
if (SWITCH_EXISTS(i)) {
div_t qr = div(cnt++, 6);
coord_t x = 4 * FH * qr.quot;
@ -58,8 +81,8 @@ void menuRadioDiagKeys(event_t event)
}
#if defined(ROTARY_ENCODER_NAVIGATION)
coord_t y = MENU_HEADER_HEIGHT + 1 + FH*KEY_COUNT;
coord_t y = MENU_HEADER_HEIGHT + 1 + FH * MAX_KEYS;
lcdDrawText(0, y, STR_ROTARY_ENCODER);
lcdDrawNumber(5*FW+FWNUM+2, y, rotencValue / ROTARY_ENCODER_GRANULARITY, RIGHT);
lcdDrawNumber(5 * FW + FWNUM + 2, y, rotaryEncoderGetValue(), RIGHT);
#endif
}

View file

@ -19,10 +19,13 @@
* GNU General Public License for more details.
*/
#include "hal/adc_driver.h"
#define LANGUAGE_PACKS_DEFINITION
#include "opentx.h"
#include "tasks/mixer_task.h"
#include "input_mapping.h"
const unsigned char sticks[] = {
#include "sticks.lbm"
@ -608,10 +611,15 @@ void menuRadioSetup(event_t event)
case ITEM_RADIO_SETUP_RX_CHANNEL_ORD:
lcdDrawTextAlignedLeft(y, STR_DEF_CHAN_ORD); // RAET->AETR
for (uint8_t i=1; i<=4; i++) {
putsChnLetter(RADIO_SETUP_2ND_COLUMN - FW + i*FW, y, channelOrder(i), attr);
{
for (uint8_t i = 0; i < adcGetMaxInputs(ADC_INPUT_MAIN); i++) {
putsChnLetter(RADIO_SETUP_2ND_COLUMN - FW + i*FW, y, inputMappingChannelOrder(i), attr);
}
if (attr) {
auto max_order = inputMappingGetMaxChannelOrder() - 1;
CHECK_INCDEC_GENVAR(event, g_eeGeneral.templateSetup, 0, max_order);
}
}
if (attr) CHECK_INCDEC_GENVAR(event, g_eeGeneral.templateSetup, 0, 23);
break;
case ITEM_RADIO_SETUP_STICK_MODE_LABELS:
@ -641,20 +649,24 @@ void menuRadioSetup(event_t event)
#endif
case ITEM_RADIO_SETUP_STICK_MODE:
lcdDrawChar(2*FW, y, '1'+reusableBuffer.generalSettings.stickMode, attr);
{
auto& mode = reusableBuffer.generalSettings.stickMode;
lcdDrawChar(2*FW, y, '1' + mode, attr);
for (uint8_t i=0; i<4; i++) {
drawStickName((6+4*i)*FW, y, *(modn12x3 + 4*reusableBuffer.generalSettings.stickMode + i), 0);
auto ctrl = inputMappingConvertMode(mode, i);
drawMainControlLabel((6+4*i)*FW, y, ctrl, 0);
}
if (attr && s_editMode>0) {
CHECK_INCDEC_GENVAR(event, reusableBuffer.generalSettings.stickMode, 0, 3);
if (attr && s_editMode > 0) {
CHECK_INCDEC_GENVAR(event, mode, 0, 3);
}
else if (reusableBuffer.generalSettings.stickMode != g_eeGeneral.stickMode) {
else if (mode != g_eeGeneral.stickMode) {
mixerTaskStop();
g_eeGeneral.stickMode = reusableBuffer.generalSettings.stickMode;
g_eeGeneral.stickMode = mode;
checkThrottleStick();
mixerTaskStart();
waitKeysReleased();
}
}
break;
case ITEM_VIEW_OPTIONS_LABEL:

View file

@ -40,12 +40,10 @@ void menuChannelsView(event_t event)
popMenu();
break;
case EVT_KEY_FIRST(KEY_RIGHT):
case EVT_KEY_FIRST(KEY_LEFT):
#if defined(ROTARY_ENCODER_NAVIGATION)
case EVT_ROTARY_LEFT:
case EVT_ROTARY_RIGHT:
#endif
case EVT_KEY_FIRST(KEY_PLUS):
case EVT_KEY_FIRST(KEY_MINUS):
reusableBuffer.viewChannels.secondPage = !reusableBuffer.viewChannels.secondPage;
break;

View file

@ -21,6 +21,11 @@
#include "opentx.h"
#include "hal/trainer_driver.h"
#include "hal/adc_driver.h"
#include "hal/switch_driver.h"
#include "switches.h"
#include "input_mapping.h"
#define BIGSIZE MIDSIZE
#define LBOX_CENTERX (BOX_WIDTH/2 + 16)
@ -73,24 +78,24 @@ const unsigned char icons[] = {
void doMainScreenGraphics()
{
int16_t calibStickVert = calibratedAnalogs[CONVERT_MODE(1)];
if (g_model.throttleReversed && CONVERT_MODE(1) == THR_STICK)
int16_t calibStickVert = calibratedAnalogs[ADC_MAIN_LV];
if (g_model.throttleReversed && inputMappingConvertMode(ADC_MAIN_LV) == THR_STICK)
calibStickVert = -calibStickVert;
drawStick(LBOX_CENTERX, calibratedAnalogs[CONVERT_MODE(0)], calibStickVert);
drawStick(LBOX_CENTERX, calibratedAnalogs[ADC_MAIN_LH], calibStickVert);
calibStickVert = calibratedAnalogs[CONVERT_MODE(2)];
if (g_model.throttleReversed && CONVERT_MODE(2) == THR_STICK)
calibStickVert = calibratedAnalogs[ADC_MAIN_RV];
if (g_model.throttleReversed && inputMappingConvertMode(ADC_MAIN_RV) == THR_STICK)
calibStickVert = -calibStickVert;
drawStick(RBOX_CENTERX, calibratedAnalogs[CONVERT_MODE(3)], calibStickVert);
drawStick(RBOX_CENTERX, calibratedAnalogs[ADC_MAIN_RH], calibStickVert);
}
void displayTrims(uint8_t phase)
{
for (unsigned int i=0; i<NUM_STICKS; i++) {
coord_t x[4] = { TRIM_LH_X, TRIM_LV_X, TRIM_RV_X, TRIM_RH_X };
uint8_t vert[4] = { 0, 1, 1, 0 };
for (unsigned int i = 0; i < MAX_STICKS; i++) {
coord_t x[] = { TRIM_LH_X, TRIM_LV_X, TRIM_RV_X, TRIM_RH_X };
uint8_t vert[] = { 0, 1, 1, 0 };
coord_t xm, ym;
unsigned int stickIndex = CONVERT_MODE(i);
unsigned int stickIndex = inputMappingConvertMode(i);
xm = x[stickIndex];
uint32_t att = ROUND;
@ -164,26 +169,45 @@ void displayTrims(uint8_t phase)
}
}
// Pots & sliders
// X9E: only sliders (1 to 4)
// Other: POT1, POT2, SLIDERS1 and SLIDER2
//
static const coord_t _pot_slots[] = {
3, LCD_H / 2 + 1, // SLIDER1 (x,y)
LCD_W - 5, LCD_H / 2 + 1, // SLIDER2 (x,y)
3, 1, // SLIDER3 (x,y)
LCD_W - 5, 1, // SLIDER4 (x,y)
};
void drawSliders()
{
for (uint8_t i = NUM_STICKS; i < NUM_STICKS + NUM_POTS + NUM_SLIDERS; i++) {
uint8_t slot_idx = 0;
uint8_t max_pots = adcGetMaxInputs(ADC_INPUT_POT);
uint8_t offset = adcGetInputOffset(ADC_INPUT_POT);
for (uint8_t i = 0; i < max_pots; i++) {
// TODO: move this into board implementation
#if defined(PCBX9E)
if (i < SLIDER1)
continue; // TODO change and display more values
coord_t x = ((i==SLIDER1 || i==SLIDER3) ? 3 : LCD_W-5);
int8_t y = (i<SLIDER3 ? LCD_H/2+1 : 1);
// Only sliders
if (!IS_SLIDER(i)) continue;
#else
if (i == POT3)
continue;
coord_t x = ((i==POT1 || i==SLIDER1) ? 3 : LCD_W-5);
int8_t y = (i>=SLIDER1 ? LCD_H/2+1 : 1);
// Skip POT3
if (i == 2) continue;
#endif
lcdDrawSolidVerticalLine(x, y, LCD_H/2-2);
lcdDrawSolidVerticalLine(x+1, y, LCD_H/2-2);
coord_t x = _pot_slots[slot_idx++];
coord_t y = _pot_slots[slot_idx++];
lcdDrawSolidVerticalLine(x, y, LCD_H / 2 - 2);
lcdDrawSolidVerticalLine(x + 1, y, LCD_H / 2 - 2);
// calculate once per loop
y += LCD_H / 2 - 4;
y -= ((calibratedAnalogs[i]+RESX)*(LCD_H/2-4)/(RESX*2)); // calculate once per loop
lcdDrawSolidVerticalLine(x-1, y, 2);
lcdDrawSolidVerticalLine(x+2, y, 2);
y -= ((calibratedAnalogs[offset + i] + RESX) * (LCD_H / 2 - 4) / (RESX * 2));
lcdDrawSolidVerticalLine(x - 1, y, 2);
lcdDrawSolidVerticalLine(x + 2, y, 2);
}
}
@ -417,17 +441,6 @@ void displaySwitch(coord_t x, coord_t y, int width, unsigned int index)
}
}
int getSwitchCount()
{
int count = 0;
for (int i=0; i<NUM_SWITCHES; ++i) {
if (SWITCH_EXISTS(i)) {
++count;
}
}
return count;
}
void menuMainView(event_t event)
{
static bool secondPage = false;
@ -435,8 +448,8 @@ void menuMainView(event_t event)
switch(event) {
case EVT_ENTRY:
killEvents(KEY_EXIT);
killEvents(KEY_UP);
killEvents(KEY_DOWN);
killEvents(KEY_PLUS);
killEvents(KEY_MINUS);
// no break
case EVT_ENTRY_UP:
@ -485,8 +498,8 @@ void menuMainView(event_t event)
#endif
break;
case EVT_KEY_FIRST(KEY_RIGHT):
case EVT_KEY_FIRST(KEY_LEFT):
case EVT_KEY_FIRST(KEY_PLUS):
case EVT_KEY_FIRST(KEY_MINUS):
#if defined(ROTARY_ENCODER_NAVIGATION)
case EVT_ROTARY_LEFT:
case EVT_ROTARY_RIGHT:
@ -514,29 +527,47 @@ void menuMainView(event_t event)
lcdDrawBitmap(BITMAP_X, BITMAP_Y, modelBitmap);
// Switches
if (getSwitchCount() > 8) {
for (int i=0; i<NUM_SWITCHES; ++i) {
div_t qr = div(i, 9);
if (g_model.view == VIEW_INPUTS) {
div_t qr2 = div(qr.rem, 5);
if (i >= 14) qr2.rem += 1;
const coord_t x[4] = { 50, 142 };
const coord_t y[4] = { 25, 42, 25, 42 };
displaySwitch(x[qr.quot]+qr2.rem*4, y[qr2.quot], 3, i);
}
else {
displaySwitch(17+qr.rem*6, 25+qr.quot*17, 5, i);
}
}
}
else {
int index = 0;
for (int i=0; i<NUM_SWITCHES; ++i) {
// Regular radio
// -> 2 columns: one for each side
// -> 8 slots on each side (2 columns of 4)
uint8_t switches = switchGetMaxSwitches();
if (getSwitchCount() > 16) { // beware, there is a desired col/row swap in this special mode
for (int i = 0; i < switches; ++i) {
if (SWITCH_EXISTS(i)) {
getvalue_t val = getValue(MIXSRC_FIRST_SWITCH+i);
getvalue_t sw = ((val < 0) ? 3*i+1 : ((val == 0) ? 3*i+2 : 3*i+3));
drawSwitch((g_model.view == VIEW_INPUTS) ? (index<4 ? 8*FW+1 : 23*FW+2) : (index<4 ? 3*FW+1 : 8*FW-2), (index%4)*FH+3*FH, sw, 0, false);
index++;
auto switch_display = switchGetDisplayPosition(i);
if (g_model.view == VIEW_INPUTS) {
coord_t x = 50 + (switch_display.row % 5) * 4 +
(switch_display.col == 0 ? 0 : 93) +
(switch_display.row < 5 ? 0 : 2);
coord_t y = switch_display.row < 5 ? 25 : 40;
displaySwitch(x, y, 3, i);
} else {
displaySwitch(17 + switch_display.row * 6,
25 + switch_display.col * 17, 5, i);
}
}
}
}
else {
coord_t shiftright = switchGetMaxRow(1) < 4 ? 20 : 0;
for (int i = 0; i < switches; ++i) {
if (SWITCH_EXISTS(i)) {
auto switch_display = switchGetDisplayPosition(i);
if (g_model.view == VIEW_INPUTS) {
coord_t x = (switch_display.col == 0 ? 50 : 125) +
(switch_display.row < 4 ? 0 : 20) +
(switch_display.col == 0 ? 0 : shiftright);
coord_t y = 25 + (switch_display.row % 4) * FH;
getvalue_t val = getValue(MIXSRC_FIRST_SWITCH + i);
getvalue_t sw =
((val < 0) ? 3 * i + 1 : ((val == 0) ? 3 * i + 2 : 3 * i + 3));
drawSwitch(x, y, sw, 0, false);
}
else {
displaySwitch(17 + switch_display.row * 6,
25 + switch_display.col * 17, 5, i);
}
}
}
}
@ -566,7 +597,7 @@ void menuMainView(event_t event)
lcdDrawSolidHorizontalLine(x, y+6, 4);
lcdDrawSolidHorizontalLine(x, y+7, 4);
}
else if (getSwitch(SWSRC_SW1+sw)) {
else if (getSwitch(SWSRC_FIRST_LOGICAL_SWITCH+sw)) {
lcdDrawFilledRect(x, y, 4, 8);
}
else {

View file

@ -19,6 +19,7 @@
* GNU General Public License for more details.
*/
#include "hal/adc_driver.h"
#include "opentx.h"
#include "tasks.h"
@ -32,12 +33,12 @@ void menuStatisticsView(event_t event)
title(STR_MENUSTAT);
switch(event) {
case EVT_KEY_FIRST(KEY_UP):
case EVT_KEY_FIRST(KEY_PLUS):
case EVT_KEY_BREAK(KEY_PAGE):
chainMenu(menuStatisticsDebug);
break;
case EVT_KEY_FIRST(KEY_DOWN):
case EVT_KEY_FIRST(KEY_MINUS):
case EVT_KEY_LONG(KEY_PAGE):
killEvents(event);
#if defined(DEBUG_TRACE_BUFFER)
@ -133,13 +134,13 @@ void menuStatisticsDebug(event_t event)
maxMixerDuration = 0;
break;
case EVT_KEY_FIRST(KEY_UP):
case EVT_KEY_FIRST(KEY_PLUS):
case EVT_KEY_BREAK(KEY_PAGE):
disableVBatBridge();
chainMenu(menuStatisticsDebug2);
break;
case EVT_KEY_FIRST(KEY_DOWN):
case EVT_KEY_FIRST(KEY_MINUS):
case EVT_KEY_LONG(KEY_PAGE):
killEvents(event);
disableVBatBridge();
@ -214,7 +215,7 @@ void menuStatisticsDebug2(event_t event)
title(STR_MENUDEBUG);
switch(event) {
case EVT_KEY_FIRST(KEY_UP):
case EVT_KEY_FIRST(KEY_PLUS):
case EVT_KEY_BREAK(KEY_PAGE):
#if defined(DEBUG_TRACE_BUFFER)
chainMenu(menuTraceBuffer);
@ -223,7 +224,7 @@ void menuStatisticsDebug2(event_t event)
#endif
return;
case EVT_KEY_FIRST(KEY_DOWN):
case EVT_KEY_FIRST(KEY_MINUS):
case EVT_KEY_LONG(KEY_PAGE):
killEvents(event);
chainMenu(menuStatisticsDebug);
@ -257,13 +258,13 @@ void menuTraceBuffer(event_t event)
killEvents(event);
break;
case EVT_KEY_FIRST(KEY_DOWN):
case EVT_KEY_FIRST(KEY_MINUS):
case EVT_KEY_LONG(KEY_PAGE):
killEvents(event);
chainMenu(menuStatisticsDebug2);
break;
case EVT_KEY_FIRST(KEY_UP):
case EVT_KEY_FIRST(KEY_PLUS):
case EVT_KEY_BREAK(KEY_PAGE):
chainMenu(menuStatisticsView);
return;

View file

@ -20,6 +20,7 @@
*/
#include "opentx.h"
#include "hal/rotary_encoder.h"
#include "LvglWrapper.h"
#include "themes/etx_lv_theme.h"
@ -121,15 +122,16 @@ static void keyboardDriverRead(lv_indev_drv_t *drv, lv_indev_data_t *data)
data->key = 0;
if (isEvent()) { // event waiting
event_t evt = getEvent(false); // get keyEvent for hard keys other than trim switches
event_t evt = getEvent();
if(evt == EVT_KEY_FIRST(KEY_PGUP) || // generate acoustic/haptic feedback if radio settings allow
evt == EVT_KEY_FIRST(KEY_PGDN) ||
if(evt == EVT_KEY_FIRST(KEY_PAGEUP) ||
evt == EVT_KEY_FIRST(KEY_PAGEDN) ||
evt == EVT_KEY_FIRST(KEY_ENTER) ||
evt == EVT_KEY_FIRST(KEY_MODEL) ||
evt == EVT_KEY_FIRST(KEY_EXIT) ||
evt == EVT_KEY_FIRST(KEY_TELEM) ||
evt == EVT_KEY_FIRST(KEY_RADIO)) {
evt == EVT_KEY_FIRST(KEY_TELE) ||
evt == EVT_KEY_FIRST(KEY_SYS)) {
// generate acoustic/haptic feedback if radio settings allow
audioKeyPress();
}
@ -244,7 +246,7 @@ static void rotaryDriverRead(lv_indev_drv_t *drv, lv_indev_data_t *data)
static int8_t prevDir = 0;
static uint32_t lastDt = 0;
rotenc_t newPos = ROTARY_ENCODER_NAVIGATION_VALUE;
rotenc_t newPos = rotaryEncoderGetRawValue();
rotenc_t diff = (newPos - prevPos) / ROTARY_ENCODER_GRANULARITY;
prevPos += diff * ROTARY_ENCODER_GRANULARITY;
@ -270,9 +272,6 @@ static void rotaryDriverRead(lv_indev_drv_t *drv, lv_indev_data_t *data)
_rotary_enc_accel = 0;
}
// For Lua getRotEncSpeed() function
rotencSpeed = max(_rotary_enc_accel, (int8_t)1);
prevDir = dir;
lastDt = rotencDt;
}
@ -299,7 +298,7 @@ uint32_t makeLvColor32(uint32_t colorFlags)
std::string makeRecolor(std::string value, uint32_t colorFlags)
{
char s[32];
snprintf(s, 32, "#%06x %s#", makeLvColor32(colorFlags), value.c_str());
snprintf(s, 32, "#%06" PRIx32 " %s#", makeLvColor32(colorFlags), value.c_str());
return std::string(s);
}

View file

@ -346,7 +346,8 @@ void CurveEdit::checkEvents()
if (!lockSource) {
int16_t val = getMovedSource(MIXSRC_FIRST_INPUT);
if (val > 0) {
if (val > NUM_STICKS + NUM_POTS + NUM_SLIDERS)
// TODO: this code seems odd
if (val > MAX_STICKS + MAX_POTS)
CurveEdit::currentSource = val + 1 - MIXSRC_FIRST_INPUT;
else {
CurveEdit::currentSource = expoAddress(val - 1)->srcRaw;

View file

@ -239,7 +239,7 @@ FailSafePage::FailSafePage(uint8_t moduleIdx) :
// Channel name
auto line = form->newLine(&grid);
const char* ch_label = getSourceString(MIXSRC_CH1 + ch);
const char* ch_label = getSourceString(MIXSRC_FIRST_CH + ch);
new StaticText(line, rect_t{}, ch_label, 0, COLOR_THEME_PRIMARY1);
// Channel value

View file

@ -24,6 +24,8 @@
#include "theme_manager.h"
#include "libopenui.h"
#include "watchdog_driver.h"
coord_t drawStringWithIndex(BitmapBuffer * dc, coord_t x, coord_t y, const char * str, int idx, LcdFlags flags, const char * prefix, const char * suffix)
{
char s[64];
@ -237,11 +239,6 @@ void drawCurveRef(BitmapBuffer * dc, coord_t x, coord_t y, const CurveRef & curv
}
}
void drawStickName(BitmapBuffer * dc, coord_t x, coord_t y, uint8_t idx, LcdFlags att)
{
dc->drawText(x, y, STR_VSRCRAW[idx]+1, att);
}
void drawModelName(BitmapBuffer * dc, coord_t x, coord_t y, char * name, uint8_t id, LcdFlags att)
{
uint8_t len = sizeof(g_model.header.name);

View file

@ -81,7 +81,7 @@ void drawHexNumber(BitmapBuffer * dc, coord_t x, coord_t y, uint32_t val, LcdFla
void drawTextLines(BitmapBuffer * dc, coord_t left, coord_t top, coord_t width, coord_t height, const char * str, LcdFlags flags);
inline void drawChn(BitmapBuffer * dc, coord_t x, coord_t y, uint8_t idx, LcdFlags flags)
{
drawSource(dc, x, y, MIXSRC_CH1 + idx - 1, flags);
drawSource(dc, x, y, MIXSRC_FIRST_CH + idx - 1, flags);
}
// Screen templates

View file

@ -25,6 +25,8 @@
#include "opentx.h"
#include "libopenui.h"
#include "watchdog_driver.h"
static Window* _get_parent()
{
Window* p = Layer::back();

View file

@ -22,6 +22,11 @@
#include "hw_inputs.h"
#include "opentx.h"
#include "hal/adc_driver.h"
#include "hal/switch_driver.h"
#include "analogs.h"
#include "switches.h"
#define SET_DIRTY() storageDirty(EE_GENERAL)
struct HWInputEdit : public RadioTextEdit {
@ -42,10 +47,13 @@ HWSticks::HWSticks(Window* parent) : FormGroup(parent, rect_t{})
FlexGridLayout grid(col_two_dsc, row_dsc, 2);
setFlexLayout();
for (int i = 0; i < NUM_STICKS; i++) {
auto max_sticks = adcGetMaxInputs(ADC_INPUT_MAIN);
for (int i = 0; i < max_sticks; i++) {
auto line = newLine(&grid);
new StaticText(line, rect_t{}, STR_VSRCRAW[i + 1], 0, COLOR_THEME_PRIMARY1);
new HWInputEdit(line, g_eeGeneral.anaNames[i], LEN_ANA_NAME);
new StaticText(line, rect_t{}, analogGetCanonicalName(ADC_INPUT_MAIN, i),
0, COLOR_THEME_PRIMARY1);
new HWInputEdit(line, (char*)analogGetCustomLabel(ADC_INPUT_MAIN, i),
LEN_ANA_NAME);
}
#if defined(STICK_DEAD_ZONE)
@ -64,13 +72,17 @@ HWPots::HWPots(Window* parent) : FormGroup(parent, rect_t{})
FlexGridLayout grid(col_two_dsc, row_dsc, 2);
setFlexLayout();
for (int i = 0; i < NUM_POTS; i++) {
auto max_pots = adcGetMaxInputs(ADC_INPUT_POT);
for (int i = 0; i < max_pots; i++) {
// TODO: check initialised ADC inputs instead!
// Display EX3 & EX4 (= last two pots) only when FlySky gimbals are present
#if !defined(SIMU) && defined(FLYSKY_GIMBAL)
if (!globalData.flyskygimbals && (i >= (NUM_POTS - 2))) continue;
#endif
// TODO: use input disabled mask instead
// #if !defined(SIMU) && defined(RADIO_FAMILY_T16)
// if (!globalData.flyskygimbals && (i >= (NUM_POTS - 2))) continue;
// #endif
auto line = newLine(&grid);
new StaticText(line, rect_t{}, STR_VSRCRAW[i + NUM_STICKS + 1], 0,
new StaticText(line, rect_t{}, analogGetCanonicalName(ADC_INPUT_POT, i), 0,
COLOR_THEME_PRIMARY1);
auto box = new FormGroup(line, rect_t{});
@ -79,56 +91,21 @@ HWPots::HWPots(Window* parent) : FormGroup(parent, rect_t{})
auto box_obj = box->getLvObj();
lv_obj_set_style_flex_cross_place(box_obj, LV_FLEX_ALIGN_CENTER, 0);
new HWInputEdit(box, g_eeGeneral.anaNames[i + NUM_STICKS], LEN_ANA_NAME);
new HWInputEdit(box, (char*)analogGetCustomLabel(ADC_INPUT_POT, i), LEN_ANA_NAME);
new Choice(
box, rect_t{}, STR_POTTYPES, POT_NONE, POT_WITHOUT_DETENT,
box, rect_t{}, STR_POTTYPES, POT_NONE, POT_SLIDER_WITH_DETENT,
[=]() -> int {
return bfGet<uint32_t>(g_eeGeneral.potsConfig, 2 * i, 2);
return bfGet<potconfig_t>(g_eeGeneral.potsConfig, POT_CFG_BITS * i,
POT_CFG_BITS);
},
[=](int newValue) {
g_eeGeneral.potsConfig =
bfSet<uint32_t>(g_eeGeneral.potsConfig, newValue, 2 * i, 2);
g_eeGeneral.potsConfig = bfSet<potconfig_t>(
g_eeGeneral.potsConfig, newValue, POT_CFG_BITS * i, POT_CFG_BITS);
SET_DIRTY();
});
}
}
HWSliders::HWSliders(Window* parent) : FormGroup(parent, rect_t{})
{
FlexGridLayout grid(col_two_dsc, row_dsc, 2);
setFlexLayout();
#if (NUM_SLIDERS > 0)
for (int i = 0; i < NUM_SLIDERS; i++) {
const int idx = i + NUM_STICKS + NUM_POTS;
auto line = newLine(&grid);
new StaticText(line, rect_t{}, STR_VSRCRAW[idx + 1], 0,
COLOR_THEME_PRIMARY1);
auto box = new FormGroup(line, rect_t{});
box->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(4));
auto box_obj = box->getLvObj();
lv_obj_set_style_flex_cross_place(box_obj, LV_FLEX_ALIGN_CENTER, 0);
new HWInputEdit(box, g_eeGeneral.anaNames[idx], LEN_ANA_NAME);
new Choice(
box, rect_t{}, STR_SLIDERTYPES, SLIDER_NONE, SLIDER_WITH_DETENT,
[=]() -> int {
uint8_t mask = (0x01 << i);
return (g_eeGeneral.slidersConfig & mask) >> i;
},
[=](int newValue) {
uint8_t mask = (0x01 << i);
g_eeGeneral.slidersConfig &= ~mask;
g_eeGeneral.slidersConfig |= (newValue << i);
SET_DIRTY();
});
}
#endif
}
class SwitchDynamicLabel : public StaticText
{
public:
@ -141,7 +118,7 @@ class SwitchDynamicLabel : public StaticText
std::string label()
{
std::string str(STR_VSRCRAW[index + MIXSRC_FIRST_SWITCH - MIXSRC_Rud + 1]);
std::string str(switchGetName(index));
return str + getSwitchPositionSymbol(lastpos);
}
@ -170,22 +147,12 @@ class SwitchDynamicLabel : public StaticText
uint8_t lastpos = 0xff;
};
#if defined(PCBHORUS)
#define SWITCH_TYPE_MAX(sw) \
((MIXSRC_SF - MIXSRC_FIRST_SWITCH == sw || \
MIXSRC_SH - MIXSRC_FIRST_SWITCH == sw) \
? SWITCH_2POS \
: SWITCH_3POS)
#else
#define SWITCH_TYPE_MAX(sw) (SWITCH_3POS)
#endif
HWSwitches::HWSwitches(Window* parent) : FormGroup(parent, rect_t{})
{
FlexGridLayout grid(col_two_dsc, row_dsc, 2);
setFlexLayout();
for (int i = 0; i < NUM_SWITCHES; i++) {
for (int i = 0; i < switchGetMaxSwitches(); i++) {
auto line = newLine(&grid);
new SwitchDynamicLabel(line, i);
@ -195,14 +162,15 @@ HWSwitches::HWSwitches(Window* parent) : FormGroup(parent, rect_t{})
auto box_obj = box->getLvObj();
lv_obj_set_style_flex_cross_place(box_obj, LV_FLEX_ALIGN_CENTER, 0);
new HWInputEdit(box, g_eeGeneral.switchNames[i], LEN_SWITCH_NAME);
new HWInputEdit(box, (char*)switchGetCustomName(i), LEN_SWITCH_NAME);
new Choice(
box, rect_t{}, STR_SWTYPES, SWITCH_NONE, SWITCH_TYPE_MAX(i),
box, rect_t{}, STR_SWTYPES, SWITCH_NONE, switchGetMaxType(i),
[=]() -> int { return SWITCH_CONFIG(i); },
[=](int newValue) {
swconfig_t mask = (swconfig_t)0x03 << (2 * i);
g_eeGeneral.switchConfig = (g_eeGeneral.switchConfig & ~mask) |
((swconfig_t(newValue) & 0x03) << (2 * i));
swconfig_t mask = (swconfig_t)SWITCH_CONFIG_MASK(i);
g_eeGeneral.switchConfig =
(g_eeGeneral.switchConfig & ~mask) |
((swconfig_t(newValue) & SW_CFG_MASK) << (SW_CFG_BITS * i));
SET_DIRTY();
});
}
@ -221,5 +189,4 @@ HWInputDialog<T>::HWInputDialog(const char* title) :
template struct HWInputDialog<HWSticks>;
template struct HWInputDialog<HWPots>;
template struct HWInputDialog<HWSliders>;
template struct HWInputDialog<HWSwitches>;

View file

@ -33,9 +33,6 @@ struct HWPots : public FormGroup {
HWPots(Window* parent);
};
struct HWSliders : public FormGroup {
HWSliders(Window* parent);
};
struct HWSwitches : public FormGroup {
HWSwitches(Window* parent);

View file

@ -59,11 +59,16 @@ InputEditAdvanced::InputEditAdvanced(uint8_t input_n, uint8_t index) :
// Trim
line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_TRIM, 0, COLOR_THEME_PRIMARY1);
auto c = new Choice(line, rect_t{}, STR_VMIXTRIMS, -TRIM_OFF,
-TRIM_LAST, GET_VALUE(-input->trimSource),
auto c = new Choice(line, rect_t{}, -TRIM_OFF, -TRIM_LAST,
GET_VALUE(-input->trimSource),
SET_VALUE(input->trimSource, -newValue));
uint16_t srcRaw = input->srcRaw;
c->setAvailableHandler([=](int value) {
return value != TRIM_ON || input->srcRaw <= MIXSRC_Ail;
return value != TRIM_ON || srcRaw <= MIXSRC_LAST_STICK;
});
c->setTextHandler([=](int value) -> std::string {
return getTrimSourceLabel(srcRaw, -value);
});
// Flight modes

View file

@ -55,9 +55,9 @@ InputMixGroup::InputMixGroup(Window* parent, mixsrc_t idx) :
lv_obj_t* chText = nullptr;
if (idx >= MIXSRC_FIRST_CH && idx <= MIXSRC_LAST_CH
&& g_model.limitData[idx - MIXSRC_CH1].name[0] != '\0') {
&& g_model.limitData[idx - MIXSRC_FIRST_CH].name[0] != '\0') {
chText = lv_label_create(lvobj);
lv_label_set_text_fmt(chText, TR_CH "%zu", (size_t)(idx - MIXSRC_CH1 + 1));
lv_label_set_text_fmt(chText, TR_CH "%zu", (size_t)(idx - MIXSRC_FIRST_CH + 1));
lv_obj_set_style_text_font(chText, getFont(FONT(XS)), 0);
#if LCD_H > LCD_W
lv_obj_set_style_pad_bottom(chText, -2, 0);

View file

@ -32,24 +32,6 @@ class SensorValue : public StaticText
{
}
// void paint(BitmapBuffer *dc) override
// {
// if (isTelemetryValue()) {
// uint8_t sensorIndex = (input->srcRaw - MIXSRC_FIRST_TELEM) / 3;
// #if defined(SIMU)
// if (true) {
// #else
// TelemetryItem &telemetryItem = telemetryItems[sensorIndex];
// if (telemetryItem.isAvailable()) {
// #endif
// LcdFlags flags = LEFT | COLOR_THEME_PRIMARY1;
// drawSensorCustomValue(dc, 3, 2, sensorIndex, lastSensorVal, flags);
// } else {
// dc->drawText(3, 2, "---", COLOR_THEME_PRIMARY1);
// }
// }
// }
bool isTelemetryValue()
{
return input->srcRaw >= MIXSRC_FIRST_TELEM &&
@ -143,7 +125,7 @@ InputSource::InputSource(Window* parent, ExpoData* input) :
void InputSource::update()
{
if (input->srcRaw > MIXSRC_Ail && input->trimSource == TRIM_ON) {
if (input->srcRaw > MIXSRC_LAST_STICK && input->trimSource == TRIM_ON) {
input->trimSource = TRIM_OFF;
}

View file

@ -21,6 +21,9 @@
#include "sliders.h"
#include "opentx.h"
#include "switches.h"
#include "hal/adc_driver.h"
enum slider_type {
SLIDER_HORIZ,
@ -43,6 +46,23 @@ static void slider_self_size(lv_event_t* e)
}
}
MainViewSlider::MainViewSlider(Window* parent, const rect_t& rect,
uint8_t idx) :
Window(parent, rect), idx(idx)
{
}
void MainViewSlider::checkEvents()
{
Window::checkEvents();
auto pot_idx = adcGetInputOffset(ADC_INPUT_POT) + idx;
int16_t newValue = calibratedAnalogs[pot_idx];
if (value != newValue) {
value = newValue;
invalidate();
}
}
MainViewHorizontalSlider::MainViewHorizontalSlider(Window* parent,
uint8_t idx) :
MainViewSlider(parent, rect_t{}, idx)
@ -86,7 +106,6 @@ MainView6POS::MainView6POS(Window* parent, uint8_t idx) :
void MainView6POS::paint(BitmapBuffer * dc)
{
#if NUM_XPOTS > 0 // prevent compiler warning
coord_t x = MULTIPOS_W_SPACING/4;
for (uint8_t value = 0; value < XPOTS_MULTIPOS_COUNT; value++) {
dc->drawNumber(x+TRIM_SQUARE_SIZE/4, 0, value+1, FONT(XS) | COLOR_THEME_SECONDARY1);
@ -94,23 +113,20 @@ void MainView6POS::paint(BitmapBuffer * dc)
}
// The square
value = (potsPos[idx] & 0x0f);
x = MULTIPOS_W_SPACING/4+MULTIPOS_W_SPACING*value;
value = getXPotPosition(idx);
x = MULTIPOS_W_SPACING / 4 + MULTIPOS_W_SPACING * value;
drawTrimSquare(dc, x, 0, COLOR_THEME_FOCUS);
dc->drawNumber(x+MULTIPOS_W_SPACING/4, -2, value+1, FONT(BOLD) | COLOR_THEME_PRIMARY2);
#endif
}
void MainView6POS::checkEvents()
{
Window::checkEvents();
#if NUM_XPOTS > 0 // prevent compiler warning
int16_t newValue = (potsPos[idx] & 0x0f);
int16_t newValue = getXPotPosition(idx);
if (value != newValue) {
value = newValue;
invalidate();
}
#endif
}
MainViewVerticalSlider::MainViewVerticalSlider(Window* parent, uint8_t idx) :

View file

@ -39,21 +39,8 @@ constexpr coord_t VERTICAL_SLIDERS_HEIGHT = SLIDER_TICKS_COUNT * 4 + TRIM_SQUARE
class MainViewSlider : public Window
{
public:
MainViewSlider(Window * parent, const rect_t & rect, uint8_t idx):
Window(parent, rect),
idx(idx)
{
}
void checkEvents() override
{
Window::checkEvents();
int16_t newValue = calibratedAnalogs[idx];
if (value != newValue) {
value = newValue;
invalidate();
}
}
MainViewSlider(Window* parent, const rect_t& rect, uint8_t idx);
void checkEvents() override;
protected:
uint8_t idx;
@ -65,7 +52,7 @@ class MainViewHorizontalSlider : public MainViewSlider
public:
using MainViewSlider::MainViewSlider;
MainViewHorizontalSlider(Window* parent, uint8_t idx);
void paint(BitmapBuffer * dc) override;
void paint(BitmapBuffer* dc) override;
};
class MainView6POS : public MainViewSlider

View file

@ -21,6 +21,7 @@
#include "trims.h"
#include "sliders.h"
#include "input_mapping.h"
#include "opentx.h"
@ -67,7 +68,7 @@ void MainViewTrim::setRange()
void MainViewTrim::checkEvents()
{
Window::checkEvents();
int8_t stickIndex = CONVERT_MODE(idx);
int8_t stickIndex = inputMappingConvertMode(idx);
int newValue = getTrimValue(mixerCurrentFlightMode, stickIndex);
setRange();

View file

@ -72,7 +72,7 @@ MixEditWindow::MixEditWindow(int8_t channel, uint8_t index) :
void MixEditWindow::buildHeader(Window *window)
{
std::string title2(getSourceString(MIXSRC_CH1 + channel));
std::string title2(getSourceString(MIXSRC_FIRST_CH + channel));
header.setTitle(STR_MIXES);
header.setTitle2(title2);

View file

@ -32,7 +32,7 @@ MixEditAdvanced::MixEditAdvanced(int8_t channel, uint8_t index) :
{
std::string title(STR_MIXES);
title += "\n";
title += getSourceString(MIXSRC_CH1 + channel);
title += getSourceString(MIXSRC_FIRST_CH + channel);
header.setTitle(title);
auto form = new FormWindow(&body, rect_t{});

View file

@ -23,6 +23,7 @@
#include "opentx.h"
#include "libopenui.h"
#include "lvgl_widgets/input_mix_line.h"
#include "hal/key_driver.h"
#define SET_DIRTY() storageDirty(EE_MODEL)
@ -107,7 +108,7 @@ class FlightModeEdit : public Page
FlexGridLayout trim_grid(trims_col_dsc, line_row_dsc);
for (int t = 0; t < NUM_TRIMS; t++) {
for (int t = 0; t < MAX_TRIMS; t++) {
lastTrim[t] = p_fm->trim[t].value;
if ((t % TRIMS_PER_LINE) == 0) {
@ -160,7 +161,7 @@ class FlightModeEdit : public Page
void checkEvents() override
{
for (int i = 0; i < NUM_TRIMS; i += 1) {
for (int i = 0; i < keysGetMaxTrims(); i += 1) {
const auto& fm = g_model.flightModeData[index];
if (lastTrim[i] != fm.trim[i].value) {
lastTrim[i] = fm.trim[i].value;
@ -171,9 +172,9 @@ class FlightModeEdit : public Page
protected:
uint8_t index;
Choice* tr_mode[NUM_TRIMS] = {nullptr};
NumberEdit* tr_value[NUM_TRIMS] = {nullptr};
int lastTrim[NUM_TRIMS];
Choice* tr_mode[MAX_TRIMS] = {nullptr};
NumberEdit* tr_value[MAX_TRIMS] = {nullptr};
int lastTrim[MAX_TRIMS];
void showControls(int trim, uint8_t mode)
{
@ -413,7 +414,7 @@ class FlightModeBtn : public Button
lv_obj_t* trims_cont = fmStyle.newTrimCont(container);
lv_obj_set_user_data(trims_cont, this);
for (int i = 0; i < NUM_TRIMS; i += 1) {
for (int i = 0; i < keysGetMaxTrims(); i += 1) {
fmTrimMode[i] = fmStyle.newTrimMode(trims_cont, i);
fmTrimValue[i] = fmStyle.newTrimValue(trims_cont, i);
}
@ -446,7 +447,7 @@ class FlightModeBtn : public Button
if (!refreshing && init) {
refreshing = true;
const auto& fm = g_model.flightModeData[index];
for (int t = 0; t < NUM_TRIMS; t += 1) {
for (int t = 0; t < keysGetMaxTrims(); t += 1) {
if (lastTrim[t] != fm.trim[t].value) {
lastTrim[t] = fm.trim[t].value;
@ -485,7 +486,7 @@ class FlightModeBtn : public Button
lv_label_set_text(fmSwitch, "");
}
for (int i = 0; i < NUM_TRIMS; i += 1) {
for (int i = 0; i < keysGetMaxTrims(); i += 1) {
uint8_t mode = fm.trim[i].mode;
bool checked = (mode != TRIM_MODE_NONE);
bool showValue = (index == 0) || ((mode & 1) || (mode >> 1 == index));
@ -510,11 +511,11 @@ class FlightModeBtn : public Button
lv_obj_t* fmID = nullptr;
lv_obj_t* fmName = nullptr;
lv_obj_t* fmSwitch = nullptr;
lv_obj_t* fmTrimMode[NUM_TRIMS] = {nullptr};
lv_obj_t* fmTrimValue[NUM_TRIMS] = {nullptr};
lv_obj_t* fmTrimMode[MAX_TRIMS] = {nullptr};
lv_obj_t* fmTrimValue[MAX_TRIMS] = {nullptr};
lv_obj_t* fmFadeIn = nullptr;
lv_obj_t* fmFadeOut = nullptr;
int lastTrim[NUM_TRIMS];
int lastTrim[MAX_TRIMS];
};
ModelFlightModesPage::ModelFlightModesPage():

View file

@ -28,8 +28,11 @@
#include "input_edit.h"
#include "input_mix_group.h"
#include "input_mix_button.h"
#include "input_mapping.h"
#include "tasks/mixer_task.h"
#include "hal/adc_driver.h"
#include <algorithm>
#define SET_DIRTY() storageDirty(EE_MODEL)
@ -90,7 +93,11 @@ void insertExpo(uint8_t idx, uint8_t input)
ExpoData * expo = expoAddress(idx);
memmove(expo+1, expo, (MAX_EXPOS-(idx+1))*sizeof(ExpoData));
memclear(expo, sizeof(ExpoData));
expo->srcRaw = (input >= 4 ? MIXSRC_Rud + input : MIXSRC_Rud + channelOrder(input + 1) - 1);
if (input >= adcGetMaxInputs(ADC_INPUT_MAIN)) {
expo->srcRaw = MIXSRC_FIRST_STICK + input;
} else {
expo->srcRaw = MIXSRC_FIRST_STICK + inputMappingChannelOrder(input);
}
expo->curve.type = CURVE_REF_EXPO;
expo->mode = 3; // pos+neg
expo->chn = input;

View file

@ -72,7 +72,8 @@ class LogicalSwitchEditPage : public Page
void buildHeader(Window* window)
{
header.setTitle(STR_MENULOGICALSWITCHES);
headerSwitchName = header.setTitle2(getSwitchPositionName(SWSRC_SW1 + index));
headerSwitchName = header.setTitle2(
getSwitchPositionName(SWSRC_FIRST_LOGICAL_SWITCH + index));
lv_obj_set_style_text_color(headerSwitchName->getLvObj(),
makeLvColor(COLOR_THEME_ACTIVE),
@ -413,7 +414,7 @@ class LogicalSwitchButton : public Button
LogicalSwitchData* ls = lswAddress(lsIndex);
uint8_t lsFamily = lswFamily(ls->func);
lv_label_set_text(lsName, getSwitchPositionName(SWSRC_SW1 + lsIndex));
lv_label_set_text(lsName, getSwitchPositionName(SWSRC_FIRST_LOGICAL_SWITCH + lsIndex));
lv_label_set_text(lsFunc, STR_VCSWFUNC[ls->func]);
// CSW params - V1
@ -528,7 +529,7 @@ void ModelLogicalSwitchesPage::newLS(FormWindow* window, bool pasteLS)
for (uint8_t i = 0; i < MAX_LOGICAL_SWITCHES; i++) {
LogicalSwitchData* ls = lswAddress(i);
if (ls->func == LS_FUNC_NONE) {
std::string ch_name(getSwitchPositionName(SWSRC_SW1 + i));
std::string ch_name(getSwitchPositionName(SWSRC_FIRST_LOGICAL_SWITCH + i));
menu->addLineBuffered(ch_name.c_str(), [=]() {
if (pasteLS) {
*ls = clipboard.data.csw;

View file

@ -30,8 +30,10 @@
#include "input_mix_group.h"
#include "input_mix_button.h"
#include "mixer_edit.h"
#include "input_mapping.h"
#include "tasks/mixer_task.h"
#include "hal/adc_driver.h"
#define SET_DIRTY() storageDirty(EE_MODEL)
#define PASTE_BEFORE -2
@ -75,8 +77,11 @@ void insertMix(uint8_t idx, uint8_t channel)
mix->destCh = channel;
mix->srcRaw = channel + 1;
if (!isSourceAvailable(mix->srcRaw)) {
mix->srcRaw = (channel > 3 ? MIXSRC_Rud - 1 + channel
: MIXSRC_Rud - 1 + channelOrder(channel));
if (channel >= adcGetMaxInputs(ADC_INPUT_MAIN)) {
mix->srcRaw = MIXSRC_FIRST_STICK + channel;
} else {
mix->srcRaw = MIXSRC_FIRST_STICK + inputMappingChannelOrder(channel);
}
while (!isSourceAvailable(mix->srcRaw)) {
mix->srcRaw += 1;
}
@ -320,13 +325,13 @@ InputMixGroup* ModelMixesPage::getGroupByIndex(uint8_t index)
if (is_memclear(mix, sizeof(MixData))) return nullptr;
int ch = mix->destCh;
return getGroupBySrc(MIXSRC_CH1 + ch);
return getGroupBySrc(MIXSRC_FIRST_CH + ch);
}
InputMixGroup* ModelMixesPage::createGroup(FormWindow* form, mixsrc_t src)
{
auto group = new InputMixGroup(form, src);
if (showMonitors) group->enableMixerMonitor(src - MIXSRC_CH1);
if (showMonitors) group->enableMixerMonitor(src - MIXSRC_FIRST_CH);
return group;
}
@ -338,7 +343,7 @@ InputMixButton* ModelMixesPage::createLineButton(InputMixGroup *group, uint8_t i
lines.emplace_back(button);
group->addLine(button);
uint8_t ch = group->getMixSrc() - MIXSRC_CH1;
uint8_t ch = group->getMixSrc() - MIXSRC_FIRST_CH;
button->setPressHandler([=]() -> uint8_t {
Menu *menu = new Menu(form);
menu->addLine(STR_EDIT, [=]() {
@ -394,7 +399,7 @@ void ModelMixesPage::addLineButton(uint8_t index)
if (is_memclear(mix, sizeof(MixData))) return;
int channel = mix->destCh;
addLineButton(MIXSRC_CH1 + channel, index);
addLineButton(MIXSRC_FIRST_CH + channel, index);
}
void ModelMixesPage::newMix()
@ -416,7 +421,7 @@ void ModelMixesPage::newMix()
skip_mix = (ch == 0 && is_memclear(line, sizeof(MixData)));
}
} else {
std::string ch_name(getSourceString(MIXSRC_CH1 + ch));
std::string ch_name(getSourceString(MIXSRC_FIRST_CH + ch));
menu->addLineBuffered(ch_name.c_str(), [=]() { insertMix(ch, index); });
}
}
@ -447,7 +452,7 @@ void ModelMixesPage::insertMix(uint8_t channel, uint8_t index)
_copyMode = 0;
::insertMix(index, channel);
addLineButton(MIXSRC_CH1 + channel, index);
addLineButton(MIXSRC_FIRST_CH + channel, index);
editMix(channel, index);
}
@ -531,7 +536,7 @@ void ModelMixesPage::build(FormWindow * window)
if (line->destCh == ch && !skip_mix) {
// one group for the complete mixer channel
auto group = createGroup(form, MIXSRC_CH1 + ch);
auto group = createGroup(form, MIXSRC_FIRST_CH + ch);
groups.emplace_back(group);
while (index < MAX_MIXERS && (line->destCh == ch) && !skip_mix) {
// one button per input line
@ -573,7 +578,7 @@ void ModelMixesPage::enableMonitors(bool enabled)
auto h = lv_obj_get_height(form_obj);
for(auto* group : groups) {
if (enabled) {
group->enableMixerMonitor(group->getMixSrc() - MIXSRC_CH1);
group->enableMixerMonitor(group->getMixSrc() - MIXSRC_FIRST_CH);
} else {
group->disableMixerMonitor();
}

View file

@ -191,10 +191,10 @@ class OutputLineButton : public ListLineButton
lv_obj_set_style_pad_top(source, -7, 0);
lv_obj_set_style_pad_bottom(source, -7, 0);
#endif
lv_label_set_text_fmt(source, "%s\n" TR_CH "%u", getSourceString(MIXSRC_CH1 + index), index + 1);
lv_label_set_text_fmt(source, "%s\n" TR_CH "%u", getSourceString(MIXSRC_FIRST_CH + index), index + 1);
} else {
lv_obj_set_style_text_font(source, getFont(FONT(STD)), 0);
lv_label_set_text(source, getSourceString(MIXSRC_CH1 + index));
lv_label_set_text(source, getSourceString(MIXSRC_FIRST_CH + index));
}
if (output->revert) {
lv_obj_clear_flag(revert, LV_OBJ_FLAG_HIDDEN);

View file

@ -667,18 +667,18 @@ ModelLabelsWindow::ModelLabelsWindow() : Page(ICON_MODEL)
void ModelLabelsWindow::onEvent(event_t event)
{
#if defined(KEYS_GPIO_REG_PGUP)
if (event == EVT_KEY_BREAK(KEY_PGUP) ||
event == EVT_KEY_BREAK(KEY_PGDN)) {
if (event == EVT_KEY_BREAK(KEY_PAGEUP) ||
event == EVT_KEY_BREAK(KEY_PAGEDN)) {
#else
if (event == EVT_KEY_LONG(KEY_PGDN) ||
event == EVT_KEY_BREAK(KEY_PGDN)) {
if (event == EVT_KEY_LONG(KEY_PAGEDN) ||
event == EVT_KEY_BREAK(KEY_PAGEDN)) {
#endif
std::set<uint32_t> curSel = lblselector->getSelection();
std::set<uint32_t> sellist;
int select = 0;
int rowcount = lblselector->getRowCount();
if (event == EVT_KEY_BREAK(KEY_PGDN)) {
if (event == EVT_KEY_BREAK(KEY_PAGEDN)) {
if(curSel.size())
select = (*curSel.rbegin() + 1) % rowcount;
} else {

View file

@ -280,7 +280,7 @@ class USBChannelEditWindow : public Page
void buildHeader(Window *window)
{
header.setTitle(STR_USBJOYSTICK_LABEL);
header.setTitle2(getSourceString(MIXSRC_CH1 + channel));
header.setTitle2(getSourceString(MIXSRC_FIRST_CH + channel));
statusBar = new USBChannelEditStatusBar(
window,
@ -418,7 +418,7 @@ class USBChannelLineButton : public Button
lv_obj_set_grid_cell(m_btns, LV_GRID_ALIGN_START, USBCH_BTN_MODE_COL+1, 1,
LV_GRID_ALIGN_CENTER, USBCH_BTN_MODE_ROW, 1);
lv_label_set_text(m_chn, getSourceString(MIXSRC_CH1 + index));
lv_label_set_text(m_chn, getSourceString(MIXSRC_FIRST_CH + index));
lv_label_set_text(m_mode, "");
lv_label_set_text(m_param, "");
lv_label_set_text(m_btn_mode, "");

View file

@ -62,7 +62,7 @@ class OutputEditStatusBar : public Window
OutputEditWindow::OutputEditWindow(uint8_t channel) :
Page(ICON_MODEL_OUTPUTS), channel(channel)
{
std::string title2(getSourceString(MIXSRC_CH1 + channel));
std::string title2(getSourceString(MIXSRC_FIRST_CH + channel));
header.setTitle(STR_MENULIMITS);
header.setTitle2(title2);

View file

@ -23,6 +23,8 @@
#include "libopenui.h"
#include "pwr.h"
#include "watchdog_driver.h"
static void _run_popup_dialog(const char* title, const char* msg,
const char* info = nullptr)
{

View file

@ -23,6 +23,10 @@
#include "button_matrix.h"
#include "opentx.h"
#include "hal/adc_driver.h"
#include "hal/switch_driver.h"
#include "strhelpers.h"
#define SET_DIRTY() storageDirty(EE_MODEL)
static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1),
@ -79,7 +83,7 @@ struct SwitchWarnMatrix : public ButtonMatrix {
bool isActive(uint8_t btn_id);
void setTextWithColor(uint8_t btn_id);
private:
uint8_t sw_idx[NUM_SWITCHES];
uint8_t sw_idx[MAX_SWITCHES];
};
struct PotWarnMatrix : public ButtonMatrix {
@ -88,7 +92,7 @@ struct PotWarnMatrix : public ButtonMatrix {
bool isActive(uint8_t btn_id);
void setTextWithColor(uint8_t btn_id);
private:
uint8_t pot_idx[NUM_POTS + NUM_SLIDERS];
uint8_t pot_idx[MAX_POTS];
};
struct CenterBeepsMatrix : public ButtonMatrix {
@ -97,7 +101,8 @@ struct CenterBeepsMatrix : public ButtonMatrix {
bool isActive(uint8_t btn_id);
void setTextWithColor(uint8_t btn_id);
private:
uint8_t ana_idx[NUM_STICKS + NUM_POTS + NUM_SLIDERS];
uint8_t max_analogs;
uint8_t ana_idx[MAX_ANALOG_INPUTS];
};
PreflightChecks::PreflightChecks() : Page(ICON_MODEL_SETUP)
@ -145,19 +150,18 @@ PreflightChecks::PreflightChecks() : Page(ICON_MODEL_SETUP)
new SwitchWarnMatrix(line, rect_t{});
// Pots and sliders warning
#if NUM_POTS + NUM_SLIDERS
if (adcGetMaxInputs(ADC_INPUT_POT) > 0) {
line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_POTWARNINGSTATE, 0, COLOR_THEME_PRIMARY1);
auto pots_wm = new Choice(line, rect_t{}, STR_PREFLIGHT_POTSLIDER_CHECK, 0, 2,
auto pots_wm = new Choice(line, rect_t{}, {STR_PREFLIGHT_POTSLIDER_CHECK}, 0, 2,
GET_SET_DEFAULT(g_model.potsWarnMode));
#if (NUM_POTS)
// Pot warnings
line = form->newLine(&grid);
line->padTop(0);
auto pwm = new PotWarnMatrix(line, rect_t{});
make_conditional(pwm, pots_wm);
#endif
#endif
}
// Center beeps
line = form->newLine(&grid);
@ -170,8 +174,7 @@ PreflightChecks::PreflightChecks() : Page(ICON_MODEL_SETUP)
static std::string switchWarninglabel(swsrc_t index)
{
auto warn_pos = g_model.switchWarningState >> (3 * index) & 0x07;
return TEXT_AT_INDEX(STR_VSRCRAW,
(index + MIXSRC_FIRST_SWITCH - MIXSRC_Rud + 1)) +
return std::string(switchGetName(index)) +
std::string(getSwitchWarnSymbol(warn_pos));
}
@ -187,7 +190,7 @@ SwitchWarnMatrix::SwitchWarnMatrix(Window* parent, const rect_t& r) :
{
// Setup button layout & texts
uint8_t btn_cnt = 0;
for (uint8_t i = 0; i < NUM_SWITCHES; i++) {
for (uint8_t i = 0; i < MAX_SWITCHES; i++) {
if (SWITCH_EXISTS(i)) {
sw_idx[btn_cnt] = i;
btn_cnt++;
@ -198,7 +201,7 @@ SwitchWarnMatrix::SwitchWarnMatrix(Window* parent, const rect_t& r) :
update();
uint8_t btn_id = 0;
for (uint8_t i = 0; i < NUM_SWITCHES; i++) {
for (uint8_t i = 0; i < MAX_SWITCHES; i++) {
if (SWITCH_EXISTS(i)) {
lv_btnmatrix_set_btn_ctrl(lvobj, btn_id, LV_BTNMATRIX_CTRL_RECOLOR);
setTextWithColor(i);
@ -225,12 +228,13 @@ SwitchWarnMatrix::SwitchWarnMatrix(Window* parent, const rect_t& r) :
void SwitchWarnMatrix::setTextWithColor(uint8_t btn_id)
{
setText(btn_id, makeRecolor(switchWarninglabel(sw_idx[btn_id]), isActive(btn_id) ? COLOR_THEME_PRIMARY1 : COLOR_THEME_SECONDARY1).c_str());
auto color = isActive(btn_id) ? COLOR_THEME_PRIMARY1 : COLOR_THEME_SECONDARY1;
setText(btn_id, makeRecolor(switchWarninglabel(sw_idx[btn_id]), color).c_str());
}
void SwitchWarnMatrix::onPress(uint8_t btn_id)
{
if (btn_id >= NUM_SWITCHES) return;
if (btn_id >= MAX_SWITCHES) return;
auto sw = sw_idx[btn_id];
swarnstate_t newstate = bfGet(g_model.switchWarningState, 3 * sw, 3);
@ -249,7 +253,7 @@ void SwitchWarnMatrix::onPress(uint8_t btn_id)
bool SwitchWarnMatrix::isActive(uint8_t btn_id)
{
if (btn_id >= NUM_SWITCHES) return false;
if (btn_id >= MAX_SWITCHES) return false;
return bfGet(g_model.switchWarningState, 3 * sw_idx[btn_id], 3) != 0;
}
@ -258,16 +262,9 @@ PotWarnMatrix::PotWarnMatrix(Window* parent, const rect_t& r) :
{
// Setup button layout & texts
uint8_t btn_cnt = 0;
for (uint8_t i = POT_FIRST; i <= POT_LAST; i++) {
if ((IS_POT(i) || IS_POT_MULTIPOS(i)) && IS_POT_AVAILABLE(i)) {
pot_idx[btn_cnt] = i - POT_FIRST;
btn_cnt++;
}
}
for (int8_t i = SLIDER_FIRST; i <= SLIDER_LAST; i++) {
if (IS_SLIDER(i)) {
pot_idx[btn_cnt] = i - POT_FIRST;
for (uint8_t i = 0; i <= MAX_POTS; i++) {
if (IS_POT_AVAILABLE(i)) {
pot_idx[btn_cnt] = i;
btn_cnt++;
}
}
@ -276,15 +273,8 @@ PotWarnMatrix::PotWarnMatrix(Window* parent, const rect_t& r) :
update();
uint8_t btn_id = 0;
for (uint16_t i = POT_FIRST; i <= POT_LAST; i++) {
if ((IS_POT(i) || IS_POT_MULTIPOS(i)) && IS_POT_AVAILABLE(i)) {
lv_btnmatrix_set_btn_ctrl(lvobj, btn_id, LV_BTNMATRIX_CTRL_RECOLOR);
setTextWithColor(btn_id);
btn_id++;
}
}
for (int8_t i = SLIDER_FIRST; i <= SLIDER_LAST; i++) {
if (IS_SLIDER(i)) {
for (uint16_t i = 0; i <= MAX_POTS; i++) {
if (IS_POT_AVAILABLE(i)) {
lv_btnmatrix_set_btn_ctrl(lvobj, btn_id, LV_BTNMATRIX_CTRL_RECOLOR);
setTextWithColor(btn_id);
btn_id++;
@ -310,12 +300,14 @@ PotWarnMatrix::PotWarnMatrix(Window* parent, const rect_t& r) :
void PotWarnMatrix::setTextWithColor(uint8_t btn_id)
{
setText(btn_id, makeRecolor(STR_VSRCRAW[pot_idx[btn_id] + POT_FIRST + 1], isActive(btn_id) ? COLOR_THEME_PRIMARY1 : COLOR_THEME_SECONDARY1).c_str());
auto idx = pot_idx[btn_id];
auto color = isActive(btn_id) ? COLOR_THEME_PRIMARY1 : COLOR_THEME_SECONDARY1;
setText(btn_id, makeRecolor(getPotLabel(idx), color).c_str());
}
void PotWarnMatrix::onPress(uint8_t btn_id)
{
if (btn_id >= NUM_POTS + NUM_SLIDERS) return;
if (btn_id >= MAX_POTS) return;
auto pot = pot_idx[btn_id];
g_model.potsWarnEnabled ^= (1 << pot);
@ -329,7 +321,7 @@ void PotWarnMatrix::onPress(uint8_t btn_id)
bool PotWarnMatrix::isActive(uint8_t btn_id)
{
if (btn_id >= NUM_POTS + NUM_SLIDERS) return false;
if (btn_id >= MAX_POTS) return false;
return (g_model.potsWarnEnabled & (1 << pot_idx[btn_id])) != 0;
}
@ -338,9 +330,15 @@ CenterBeepsMatrix::CenterBeepsMatrix(Window* parent, const rect_t& r) :
{
// Setup button layout & texts
uint8_t btn_cnt = 0;
for (uint8_t i = 0; i < NUM_STICKS + NUM_POTS + NUM_SLIDERS; i++) {
auto max_sticks = adcGetMaxInputs(ADC_INPUT_MAIN);
auto max_pots = adcGetMaxInputs(ADC_INPUT_POT);
max_analogs = max_sticks + max_pots;
for (uint8_t i = 0; i < max_analogs; i++) {
// multipos cannot be centered
if (i < NUM_STICKS || (IS_POT_SLIDER_AVAILABLE(i) && !IS_POT_MULTIPOS(i))) {
if (i < max_sticks || (IS_POT_SLIDER_AVAILABLE(i - max_sticks) &&
!IS_POT_MULTIPOS(i - max_sticks))) {
ana_idx[btn_cnt] = i;
btn_cnt++;
}
@ -350,8 +348,9 @@ CenterBeepsMatrix::CenterBeepsMatrix(Window* parent, const rect_t& r) :
update();
uint8_t btn_id = 0;
for (uint8_t i = 0; i < NUM_STICKS + NUM_POTS + NUM_SLIDERS; i++) {
if (i < NUM_STICKS || (IS_POT_SLIDER_AVAILABLE(i) && !IS_POT_MULTIPOS(i))) {
for (uint8_t i = 0; i < max_analogs; i++) {
if (i < max_sticks || (IS_POT_SLIDER_AVAILABLE(i - max_sticks) &&
!IS_POT_MULTIPOS(i - max_sticks))) {
lv_btnmatrix_set_btn_ctrl(lvobj, btn_id, LV_BTNMATRIX_CTRL_RECOLOR);
setTextWithColor(btn_id);
btn_id++;
@ -377,15 +376,15 @@ CenterBeepsMatrix::CenterBeepsMatrix(Window* parent, const rect_t& r) :
void CenterBeepsMatrix::setTextWithColor(uint8_t btn_id)
{
if (btn_id < NUM_STICKS)
setText(btn_id, makeRecolor(STR_RETA123[ana_idx[btn_id]], isActive(btn_id) ? COLOR_THEME_PRIMARY1 : COLOR_THEME_SECONDARY1).c_str());
else
setText(btn_id, makeRecolor(STR_VSRCRAW[ana_idx[btn_id] + 1], isActive(btn_id) ? COLOR_THEME_PRIMARY1 : COLOR_THEME_SECONDARY1).c_str());
setText(btn_id, makeRecolor(getAnalogShortLabel(ana_idx[btn_id]),
isActive(btn_id) ? COLOR_THEME_PRIMARY1
: COLOR_THEME_SECONDARY1)
.c_str());
}
void CenterBeepsMatrix::onPress(uint8_t btn_id)
{
if (btn_id >= NUM_STICKS + NUM_POTS + NUM_SLIDERS) return;
if (btn_id >= max_analogs) return;
uint8_t i = ana_idx[btn_id];
BFBIT_FLIP(g_model.beepANACenter, bfBit<BeepANACenter>(i));
setTextWithColor(btn_id);
@ -394,7 +393,7 @@ void CenterBeepsMatrix::onPress(uint8_t btn_id)
bool CenterBeepsMatrix::isActive(uint8_t btn_id)
{
if (btn_id >= NUM_STICKS + NUM_POTS + NUM_SLIDERS) return false;
if (btn_id >= max_analogs) return false;
uint8_t i = ana_idx[btn_id];
return bfSingleBitGet<BeepANACenter>(g_model.beepANACenter, i) != 0;
}

View file

@ -45,8 +45,8 @@ class StickCalibrationWindow: public Window {
void paint(BitmapBuffer * dc) override
{
dc->drawBitmap(0, 0, calibStickBackground);
int16_t x = calibratedAnalogs[CONVERT_MODE(stickX)];
int16_t y = calibratedAnalogs[CONVERT_MODE(stickY)];
int16_t x = calibratedAnalogs[stickX];
int16_t y = calibratedAnalogs[stickY];
dc->drawBitmap(width() / 2 - 9 + (bitmapSize / 2 * x) / RESX,
height() / 2 - 9 - (bitmapSize / 2 * y) / RESX,
calibStick);
@ -78,13 +78,15 @@ void RadioCalibrationPage::buildBody(FormWindow * window)
// The two sticks
//TODO: dynamic placing
new StickCalibrationWindow(window,
{window->width() / 3, window->height() / 2, 0, 0},
STICK1, STICK2);
new StickCalibrationWindow(
window, {window->width() / 3, window->height() / 2, 0, 0}, 0, 1);
new StickCalibrationWindow(window,
{(2 * window->width()) / 3, window->height() / 2, 0, 0},
STICK4, STICK3);
auto max_sticks = adcGetMaxInputs(ADC_INPUT_MAIN);
if (max_sticks > 2) {
new StickCalibrationWindow(
window, {(2 * window->width()) / 3, window->height() / 2, 0, 0}, 3,
2);
}
std::unique_ptr<ViewMainDecoration> deco(new ViewMainDecoration(window));
deco->setTrimsVisible(false);
@ -104,100 +106,15 @@ void RadioCalibrationPage::checkEvents()
{
Page::checkEvents();
for (uint8_t i = 0; i < NUM_STICKS + NUM_POTS + NUM_SLIDERS + NUM_MOUSE_ANALOGS; i++) { // get low and high vals for sticks and trims
int16_t vt = i < TX_VOLTAGE ? anaIn(i) : anaIn(i + 1);
reusableBuffer.calib.loVals[i] = min(vt, reusableBuffer.calib.loVals[i]);
reusableBuffer.calib.hiVals[i] = max(vt, reusableBuffer.calib.hiVals[i]);
if (i >= POT1 && i <= POT_LAST) {
if (IS_POT_WITHOUT_DETENT(i)) {
reusableBuffer.calib.midVals[i] = (reusableBuffer.calib.hiVals[i] + reusableBuffer.calib.loVals[i]) / 2;
}
#if NUM_XPOTS > 0
uint8_t idx = i - POT1;
int count = reusableBuffer.calib.xpotsCalib[idx].stepsCount;
if (IS_POT_MULTIPOS(i) && count <= XPOTS_MULTIPOS_COUNT) {
// use raw analog value for multipos calibraton, anaIn() already has multipos decoded value
vt = getAnalogValue(i) >> 1;
if (reusableBuffer.calib.xpotsCalib[idx].lastCount == 0 || vt < reusableBuffer.calib.xpotsCalib[idx].lastPosition - XPOT_DELTA ||
vt > reusableBuffer.calib.xpotsCalib[idx].lastPosition + XPOT_DELTA) {
reusableBuffer.calib.xpotsCalib[idx].lastPosition = vt;
reusableBuffer.calib.xpotsCalib[idx].lastCount = 1;
}
else {
if (reusableBuffer.calib.xpotsCalib[idx].lastCount < 255) {
reusableBuffer.calib.xpotsCalib[idx].lastCount++;
}
}
if (reusableBuffer.calib.xpotsCalib[idx].lastCount == XPOT_DELAY) {
int16_t position = reusableBuffer.calib.xpotsCalib[idx].lastPosition;
bool found = false;
for (int j = 0; j < count; j++) {
int16_t step = reusableBuffer.calib.xpotsCalib[idx].steps[j];
if (position >= step - XPOT_DELTA && position <= step + XPOT_DELTA) {
found = true;
break;
}
}
if (!found) {
if (count < XPOTS_MULTIPOS_COUNT) {
reusableBuffer.calib.xpotsCalib[idx].steps[count] = position;
}
reusableBuffer.calib.xpotsCalib[idx].stepsCount += 1;
}
}
}
#endif
}
}
// Get min / max values
adcCalibMinMax();
if (menuCalibrationState == CALIB_SET_MIDPOINT) {
for (uint8_t i = 0; i < NUM_STICKS + NUM_POTS + NUM_SLIDERS + NUM_MOUSE_ANALOGS; i++) {
reusableBuffer.calib.loVals[i] = 15000;
reusableBuffer.calib.hiVals[i] = -15000;
reusableBuffer.calib.midVals[i] = i < TX_VOLTAGE ? anaIn(i) : anaIn(i + 1);
#if NUM_XPOTS > 0
if (i < NUM_XPOTS) {
reusableBuffer.calib.xpotsCalib[i].stepsCount = 0;
reusableBuffer.calib.xpotsCalib[i].lastCount = 0;
}
#endif
}
adcCalibSetMidPoint();
}
else if (menuCalibrationState == CALIB_MOVE_STICKS) {
for (uint8_t i = 0; i < NUM_STICKS + NUM_POTS + NUM_SLIDERS + NUM_MOUSE_ANALOGS; i++) {
if (abs(reusableBuffer.calib.loVals[i] - reusableBuffer.calib.hiVals[i]) > 50) {
g_eeGeneral.calib[i].mid = reusableBuffer.calib.midVals[i];
int16_t v = reusableBuffer.calib.midVals[i] - reusableBuffer.calib.loVals[i];
g_eeGeneral.calib[i].spanNeg = v - v / STICK_TOLERANCE;
v = reusableBuffer.calib.hiVals[i] - reusableBuffer.calib.midVals[i];
g_eeGeneral.calib[i].spanPos = v - v / STICK_TOLERANCE;
}
}
#if NUM_XPOTS > 0
for (int i = POT1; i <= POT_LAST; i++) {
int idx = i - POT1;
int count = reusableBuffer.calib.xpotsCalib[idx].stepsCount;
if (IS_POT_MULTIPOS(i)) {
if (count > 1 && count <= XPOTS_MULTIPOS_COUNT) {
for (int j = 0; j < count; j++) {
for (int k = j + 1; k < count; k++) {
if (reusableBuffer.calib.xpotsCalib[idx].steps[k] < reusableBuffer.calib.xpotsCalib[idx].steps[j]) {
SWAP(reusableBuffer.calib.xpotsCalib[idx].steps[j], reusableBuffer.calib.xpotsCalib[idx].steps[k]);
}
}
}
StepsCalibData * calib = (StepsCalibData *) &g_eeGeneral.calib[i];
calib->count = count - 1;
for (int j = 0; j < calib->count; j++) {
calib->steps[j] = (reusableBuffer.calib.xpotsCalib[idx].steps[j + 1] + reusableBuffer.calib.xpotsCalib[idx].steps[j]) >> 5;
}
}
else {
// g_eeGeneral.potsConfig &= ~(0x03<<(2*idx));
}
}
}
#endif
adcCalibSetMinMax();
adcCalibSetXPot();
}
}
@ -235,8 +152,7 @@ void RadioCalibrationPage::nextStep()
case CALIB_STORE:
text->setText(STR_CALIB_DONE);
g_eeGeneral.chkSum = evalChkSum();
storageDirty(EE_GENERAL);
adcCalibStore();
menuCalibrationState = CALIB_FINISHED;
// initial calibration completed

View file

@ -22,16 +22,12 @@
#include "opentx.h"
#include "radio_diaganas.h"
#include "libopenui.h"
#include "../../hal/adc_driver.h"
#include "hal/adc_driver.h"
// #if defined(IMU_LSM6DS33)
// #include "imu_lsm6ds33.h"
// #endif
#if defined(FLYSKY_GIMBAL)
#include "flysky_gimbal_driver.h"
#endif
#define STATSDEPTH 8 // ideally a value of power of 2
#if LCD_W > LCD_H
@ -74,7 +70,10 @@ class AnaViewWindow: public FormWindow {
{
char s[10];
for (uint8_t i = 0; i < NUM_STICKS + NUM_POTS + NUM_SLIDERS; i++) {
auto max_inputs = adcGetMaxInputs(ADC_INPUT_MAIN)
+ adcGetMaxInputs(ADC_INPUT_POT);
for (uint8_t i = 0; i < max_inputs; i++) {
#if LCD_W > LCD_H
if ((i & 1) == 0)
line = newLine(grid);
@ -88,7 +87,7 @@ class AnaViewWindow: public FormWindow {
new StaticText(line, rect_t{}, s, COLOR_THEME_PRIMARY1);
auto lbl = new DynamicText(line, rect_t{}, [=]() {
return std::to_string((int16_t)calibratedAnalogs[CONVERT_MODE(i)] * 25 / 256);
return std::to_string((int16_t)calibratedAnalogs[i] * 25 / 256);
}, COLOR_THEME_PRIMARY1);
lv_obj_set_style_text_align(lbl->getLvObj(), LV_TEXT_ALIGN_RIGHT, 0);
@ -209,14 +208,7 @@ class AnaCalibratedViewWindow: public AnaViewWindow {
protected:
int16_t column3(int i) override
{
#if !defined(SIMU) && defined(FLYSKY_GIMBAL)
if (globalData.flyskygimbals && (i < FLYSKY_HALL_CHANNEL_COUNT))
return hall_raw_values[i];
else
return anaIn(i);
#else
return anaIn(i);
#endif
}
};
@ -301,24 +293,11 @@ class AnaFilteredDevViewWindow: public AnaViewWindow {
}
};
Stats stats[NUM_STICKS+NUM_POTS+NUM_SLIDERS];
Stats stats[MAX_CALIB_ANALOG_INPUTS];
int16_t column3(int i) override
{
extern uint32_t s_anaFilt[NUM_ANALOGS];
#if !defined(SIMU) && defined(FLYSKY_GIMBAL)
if (globalData.flyskygimbals && (i < FLYSKY_HALL_CHANNEL_COUNT))
return hall_raw_values[i];
else
return s_anaFilt[i]/JITTER_ALPHA;
#else
#if !defined(SIMU)
return s_anaFilt[i]/JITTER_ALPHA;
#else
return anaIn(i);
#endif
#endif
return anaIn_diag(i);
}
const char* column4prefix() override { return "+/- "; }
@ -333,21 +312,20 @@ class AnaFilteredDevViewWindow: public AnaViewWindow {
AnaFilteredDevViewWindow(Window * parent):
AnaViewWindow(parent)
{
for (uint8_t i = 0; i < NUM_STICKS + NUM_POTS + NUM_SLIDERS; i++)
auto max_inputs = adcGetMaxInputs(ADC_INPUT_MAIN)
+ adcGetMaxInputs(ADC_INPUT_POT);
for (uint8_t i = 0; i < max_inputs; i++)
stats[i].clear();
}
void checkEvents() override
{
for (uint8_t i = 0; i < NUM_STICKS + NUM_POTS + NUM_SLIDERS; i++) {
#if !defined(SIMU) && defined(FLYSKY_GIMBAL)
if (globalData.flyskygimbals && (i < FLYSKY_HALL_CHANNEL_COUNT))
stats[i].write(hall_raw_values[i]);
else
auto max_inputs = adcGetMaxInputs(ADC_INPUT_MAIN)
+ adcGetMaxInputs(ADC_INPUT_POT);
for (uint8_t i = 0; i < max_inputs; i++) {
stats[i].write(getAnalogValue(i));
#else
stats[i].write(getAnalogValue(i));
#endif
}
AnaViewWindow::checkEvents();
}
@ -363,14 +341,7 @@ class AnaUnfilteredRawViewWindow: public AnaViewWindow {
protected:
int16_t column3(int i) override
{
#if !defined(SIMU) && defined(FLYSKY_GIMBAL)
if (globalData.flyskygimbals && (i < FLYSKY_HALL_CHANNEL_COUNT))
return hall_raw_values[i];
else
return getAnalogValue(i);
#else
return getAnalogValue(i);
#endif
}
};
@ -419,7 +390,7 @@ class AnaMinMaxViewWindow: public AnaViewWindow {
}
};
MinMax minmax[NUM_STICKS+NUM_POTS+NUM_SLIDERS];
MinMax minmax[MAX_CALIB_ANALOG_INPUTS];
int16_t column3(int i) override
{
@ -444,7 +415,10 @@ class AnaMinMaxViewWindow: public AnaViewWindow {
AnaMinMaxViewWindow(Window * parent):
AnaViewWindow(parent)
{
for (uint8_t i = 0; i < NUM_STICKS + NUM_POTS + NUM_SLIDERS; i++)
auto max_inputs = adcGetMaxInputs(ADC_INPUT_MAIN)
+ adcGetMaxInputs(ADC_INPUT_POT);
for (uint8_t i = 0; i < max_inputs; i++)
minmax[i].clear();
}
@ -459,15 +433,11 @@ class AnaMinMaxViewWindow: public AnaViewWindow {
void checkEvents() override
{
for (uint8_t i = 0; i < NUM_STICKS + NUM_POTS + NUM_SLIDERS; i++) {
#if !defined(SIMU) && defined(FLYSKY_GIMBAL)
if (globalData.flyskygimbals && (i < FLYSKY_HALL_CHANNEL_COUNT))
minmax[i].write(hall_raw_values[i]);
else
auto max_inputs = adcGetMaxInputs(ADC_INPUT_MAIN)
+ adcGetMaxInputs(ADC_INPUT_POT);
for (uint8_t i = 0; i < max_inputs; i++) {
minmax[i].write(getAnalogValue(i));
#else
minmax[i].write(getAnalogValue(i));
#endif
}
AnaViewWindow::checkEvents();
}

View file

@ -23,11 +23,21 @@
#include "radio_diagkeys.h"
#include "libopenui.h"
#if defined(KEYS_GPIO_PIN_PGUP)
constexpr uint8_t KEY_START = 0;
#else
constexpr uint8_t KEY_START = 1;
#endif
#include "hal/rotary_encoder.h"
static EnumKeys get_ith_key(uint8_t i)
{
auto supported_keys = keysGetSupported();
for (uint8_t k = 0; k < MAX_KEYS; k++) {
if (supported_keys & (1 << k)) {
if (i-- == 0) return (EnumKeys)k;
}
}
// should not get here,
// we assume: i < keysGetMaxKeys()
return (EnumKeys)0;
}
class RadioKeyDiagsWindow : public Window
{
@ -45,7 +55,7 @@ class RadioKeyDiagsWindow : public Window
void displayKeyState(BitmapBuffer * dc, coord_t x, coord_t y, uint8_t key)
{
uint8_t t = keys[key].state();
uint8_t t = keysGetState(key);
// TODO use drawChar when done
char status[2];
status[0] = t + '0';
@ -73,29 +83,31 @@ class RadioKeyDiagsWindow : public Window
#if !defined(PCBNV14)
// KEYS
for (uint8_t i = KEY_START; i <= 6; i++) {
coord_t y = 1 + FH * (i - KEY_START);
dc->drawTextAtIndex(KEY_COLUMN, y, STR_VKEYS, i, COLOR_THEME_PRIMARY1);
coord_t y = 1;
for (uint8_t i = 0; i < keysGetMaxKeys(); i++) {
auto k = get_ith_key(i);
y += FH;
dc->drawText(KEY_COLUMN, y, keysGetLabel(k), COLOR_THEME_PRIMARY1);
displayKeyState(dc, 70, y, i);
}
#if defined(ROTARY_ENCODER_NAVIGATION)
coord_t y = FH * (8 - KEY_START);
y += FH;
dc->drawText(KEY_COLUMN, y, STR_ROTARY_ENCODER, COLOR_THEME_PRIMARY1);
dc->drawNumber(70, y, rotencValue, COLOR_THEME_PRIMARY1);
dc->drawNumber(70, y, rotaryEncoderGetValue(), COLOR_THEME_PRIMARY1);
#endif
#else // defined(PCBNV14)
// KEYS
{
coord_t y = 1;
dc->drawTextAtIndex(KEY_COLUMN, y, STR_VKEYS, KEY_ENTER, COLOR_THEME_PRIMARY1);
dc->drawText(KEY_COLUMN, y, keysGetLabel(KEY_ENTER), COLOR_THEME_PRIMARY1);
displayKeyState(dc, 70, y, KEY_ENTER);
y += FH;
dc->drawTextAtIndex(KEY_COLUMN, y, STR_VKEYS, KEY_EXIT, COLOR_THEME_PRIMARY1);
dc->drawText(KEY_COLUMN, y, keysGetLabel(KEY_EXIT), COLOR_THEME_PRIMARY1);
displayKeyState(dc, 70, y, KEY_EXIT);
}
#endif
// SWITCHES
for (uint8_t i = 0; i < NUM_SWITCHES; i++) {
for (uint8_t i = 0; i < MAX_SWITCHES; i++) {
if (SWITCH_EXISTS(i)) {
coord_t y = 1 + FH * i;
getvalue_t val = getValue(MIXSRC_FIRST_SWITCH + i);
@ -105,18 +117,18 @@ class RadioKeyDiagsWindow : public Window
}
// TRIMS
for (uint8_t i = 0; i < NUM_TRIMS_KEYS; i++) {
#if NUM_TRIMS_KEYS == 12
const uint8_t trimMap[NUM_TRIMS_KEYS] = {6, 7, 4, 5, 2, 3, 0, 1, 8, 9, 10, 11};
for (uint8_t i = 0; i < MAX_TRIMS * 2; i++) {
#if MAX_TRIMS * 2 == 12
const uint8_t trimMap[MAX_TRIMS * 2] = {6, 7, 4, 5, 2, 3, 0, 1, 8, 9, 10, 11};
#else
const uint8_t trimMap[NUM_TRIMS_KEYS] = {6, 7, 4, 5, 2, 3, 0, 1};
const uint8_t trimMap[MAX_TRIMS * 2] = {6, 7, 4, 5, 2, 3, 0, 1};
#endif
coord_t y = 1 + FH + FH * (i / 2);
if (i & 1) {
dc->drawText(TRIM_COLUMN, y, "T", COLOR_THEME_PRIMARY1);
dc->drawNumber(TRIM_COLUMN + 10, y, i / 2 + 1, COLOR_THEME_PRIMARY1);
}
displayKeyState(dc, i & 1 ? TRIM_PLUS_COLUMN : TRIM_MINUS_COLUMN, y, TRM_BASE + trimMap[i]);
// displayKeyState(dc, i & 1 ? TRIM_PLUS_COLUMN : TRIM_MINUS_COLUMN, y, TRM_BASE + trimMap[i]);
}
};

View file

@ -48,6 +48,11 @@ RadioHardwarePage::RadioHardwarePage():
{
}
void RadioHardwarePage::checkEvents()
{
enableVBatBridge();
}
void RadioHardwarePage::build(FormWindow * window)
{
window->setFlexLayout(LV_FLEX_FLOW_COLUMN, 0);
@ -163,16 +168,10 @@ void RadioHardwarePage::build(FormWindow * window)
auto btn = makeHWInputButton<HWSticks>(box, STR_STICKS);
lv_obj_set_style_min_width(btn->getLvObj(), LV_DPI_DEF, 0);
// Pots
// Pots & Sliders
btn = makeHWInputButton<HWPots>(box, STR_POTS);
lv_obj_set_style_min_width(btn->getLvObj(), LV_DPI_DEF, 0);
// Sliders
#if (NUM_SLIDERS > 0)
btn = makeHWInputButton<HWSliders>(box, STR_SLIDERS);
lv_obj_set_style_min_width(btn->getLvObj(), LV_DPI_DEF, 0);
#endif
// Switches
btn = makeHWInputButton<HWSwitches>(box, STR_SWITCHES);
lv_obj_set_style_min_width(btn->getLvObj(), LV_DPI_DEF, 0);

View file

@ -24,11 +24,14 @@
#include "tabsgroup.h"
class RadioHardwarePage: public PageTab {
class RadioHardwarePage : public PageTab
{
void checkEvents() override;
public:
RadioHardwarePage();
void build(FormWindow * window) override;
void build(FormWindow* window) override;
};
#endif //_RADIO_HARDWARE_H_

View file

@ -24,8 +24,10 @@
#include "radio_setup.h"
#include "opentx.h"
#include "libopenui.h"
#include "input_mapping.h"
#include "tasks/mixer_task.h"
#include "hal/adc_driver.h"
#define SET_DIRTY() storageDirty(EE_GENERAL)
@ -781,12 +783,16 @@ void RadioSetupPage::build(FormWindow * window)
line = window->newLine(&grid);
new StaticText(line, rect_t{}, STR_DEF_CHAN_ORD, 0,
COLOR_THEME_PRIMARY1); // RAET->AETR
choice = new Choice(line, rect_t{}, 0, 4 * 3 * 2 - 1,
uint8_t mains = adcGetMaxInputs(ADC_INPUT_MAIN);
auto max_order = inputMappingGetMaxChannelOrder() - 1;
choice = new Choice(line, rect_t{}, 0, max_order,
GET_SET_DEFAULT(g_eeGeneral.templateSetup));
choice->setTextHandler([](uint8_t value) {
choice->setTextHandler([=](uint8_t value) {
std::string s;
for (uint8_t i = 0; i < 4; i++) {
s += STR_RETA123[channelOrder(value, i + 1) - 1];
for (uint8_t i = 0; i < mains; i++) {
s += getAnalogShortLabel(inputMappingChannelOrder(value, i));
}
return s;
});
@ -803,11 +809,11 @@ void RadioSetupPage::build(FormWindow * window)
mixerTaskStart();
});
choice->setTextHandler([](uint8_t value) {
auto stick0 = inputMappingConvertMode(value, 0);
auto stick1 = inputMappingConvertMode(value, 1);
return std::to_string(1 + value) + ": " + STR_LEFT_STICK + " = " +
std::string(&getSourceString(MIXSRC_Rud + modn12x3[4 * value])[1]) +
"+" +
std::string(
&getSourceString(MIXSRC_Rud + modn12x3[4 * value + 1])[1]);
std::string(getMainControlLabel(stick0)) + "+" +
std::string(getMainControlLabel(stick1));
});
// Model quick select

View file

@ -22,6 +22,10 @@
#include "radio_trainer.h"
#include "opentx.h"
#include "libopenui.h"
#include "input_mapping.h"
#include "hal/adc_driver.h"
#include "strhelpers.h"
#define SET_DIRTY() storageDirty(EE_GENERAL)
@ -59,13 +63,13 @@ void RadioTrainerPage::build(FormWindow * form)
form->padRight(8);
#endif
for (uint8_t i = 0; i < NUM_STICKS; i++) {
uint8_t chan = channelOrder(i + 1);
TrainerMix* td = &g_eeGeneral.trainer.mix[chan - 1];
auto max_sticks = adcGetMaxInputs(ADC_INPUT_MAIN);
for (uint8_t i = 0; i < max_sticks; i++) {
uint8_t chan = inputMappingChannelOrder(i);
TrainerMix* td = &g_eeGeneral.trainer.mix[chan];
auto line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_VSRCRAW[chan], 0, COLOR_THEME_PRIMARY1);
new StaticText(line, rect_t{}, getMainControlLabel(chan), 0, COLOR_THEME_PRIMARY1);
new Choice(line, rect_t{}, STR_TRNMODE, 0, 2, GET_SET_DEFAULT(td->mode));
new Choice(line, rect_t{}, STR_TRNCHN, 0, 3, GET_SET_DEFAULT(td->srcChn));

View file

@ -28,6 +28,7 @@
#include "strhelpers.h"
#include "draw_functions.h"
#include "opentx.h"
#include "switches.h"
class SourceChoiceMenuToolbar : public MenuToolbar
{

View file

@ -25,6 +25,9 @@
#include "view_main.h"
#include "lvgl_widgets/input_mix_line.h"
#include "hal/adc_driver.h"
#include "strhelpers.h"
#define SET_DIRTY() storageDirty(functions == g_model.customFn ? EE_MODEL : EE_GENERAL)
static const lv_coord_t col_dsc[] = {LV_GRID_FR(2), LV_GRID_FR(3),
@ -125,17 +128,16 @@ class SpecialFunctionEditPage : public Page
case FUNC_TRAINER: {
new StaticText(line, rect_t{}, STR_VALUE, 0, COLOR_THEME_PRIMARY1);
auto choice =
new Choice(line, rect_t{}, 0,
NUM_STICKS + 1, GET_SET_DEFAULT(CFN_CH_INDEX(cfn)));
auto max_sticks = adcGetMaxInputs(ADC_INPUT_MAIN);
auto choice = new Choice(line, rect_t{}, 0, max_sticks + 1,
GET_SET_DEFAULT(CFN_CH_INDEX(cfn)));
choice->setTextHandler([=](int32_t value) {
if (value == 0)
return std::string(STR_STICKS);
else if (value == NUM_STICKS + 1)
else if (value == MAX_STICKS + 1)
return std::string(STR_CHANS);
else
return TEXT_AT_INDEX(STR_VSRCRAW, value);
;
return std::string(getMainControlLabel(value));
});
break;
}
@ -398,9 +400,11 @@ class SpecialFunctionEditPage : public Page
line = form->newLine(&grid);
new StaticText(line, rect_t{}, STR_FUNC, 0, COLOR_THEME_PRIMARY1);
auto functionChoice =
new Choice(line, rect_t{}, STR_VFSWFUNC,
0, FUNC_MAX - 1,
new Choice(line, rect_t{}, 0, FUNC_MAX - 1,
GET_DEFAULT(CFN_FUNC(cfn)));
functionChoice->setTextHandler([=](int val) {
return funcGetLabel(val);
});
functionChoice->setSetValueHandler([=](int32_t newValue) {
CFN_FUNC(cfn) = newValue;
CFN_RESET(cfn);
@ -560,22 +564,22 @@ class SpecialFunctionButton : public Button
lv_label_set_text(sfName, s);
lv_label_set_text(sfSwitch, getSwitchPositionName(CFN_SWITCH(cfn)));
strcpy(s, STR_VFSWFUNC[func]);
strcpy(s, funcGetLabel(func));
strcat(s, " - ");
switch (func) {
case FUNC_OVERRIDE_CHANNEL:
sprintf(s+strlen(s), "%s = %s", getSourceString(MIXSRC_CH1 + CFN_CH_INDEX(cfn)), formatNumberAsString(CFN_PARAM(cfn)).c_str());
sprintf(s+strlen(s), "%s = %s", getSourceString(MIXSRC_FIRST_CH + CFN_CH_INDEX(cfn)), formatNumberAsString(CFN_PARAM(cfn)).c_str());
break;
case FUNC_TRAINER: {
int16_t value = CFN_CH_INDEX(cfn);
if (value == 0)
strcat(s, STR_STICKS);
else if (value == NUM_STICKS + 1)
else if (value == MAX_STICKS + 1)
strcat(s, STR_CHANS);
else
strcat(s, STR_VSRCRAW[value]);
strcat(s, getMainControlLabel(value - 1));
break;
}
@ -646,7 +650,7 @@ class SpecialFunctionButton : public Button
break;
default:
strcpy(s, STR_VFSWFUNC[func]);
strcpy(s, funcGetLabel(func));
break;
}

Some files were not shown because too many files have changed in this diff Show more