From 2902ae1887ed645830f363c71679f6adf01bd9a7 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Wed, 7 Oct 2015 21:02:17 +0200 Subject: [PATCH] Horus simulator should now be OK --- radio/src/Makefile | 373 ++++++- radio/src/audio_arm.cpp | 7 +- radio/src/buzzer.h | 2 +- radio/src/cli.cpp | 107 +- radio/src/cli.h | 2 + radio/src/eeprom_raw.cpp | 12 +- radio/src/eeprom_raw.h | 2 +- radio/src/eeprom_rlc.cpp | 2 +- radio/src/fifo.h | 5 + radio/src/fonts.h | 9 + radio/src/functions.cpp | 2 +- radio/src/gui/Horus/fonts.cpp | 88 ++ radio/src/gui/Horus/gui.h | 70 ++ radio/src/gui/Horus/helpers.cpp | 341 ++++++ radio/src/gui/Horus/lcd.cpp | 964 +++++++++++++++++ radio/src/gui/Horus/lcd.h | 325 ++++++ radio/src/gui/Horus/menu_general.cpp | 96 ++ radio/src/gui/Horus/menu_general_calib.cpp | 216 ++++ .../src/gui/Horus/menu_general_sdmanager.cpp | 358 +++++++ radio/src/gui/Horus/menu_general_setup.cpp | 521 ++++++++++ radio/src/gui/Horus/menu_general_trainer.cpp | 121 +++ radio/src/gui/Horus/menu_general_version.cpp | 53 + radio/src/gui/Horus/menu_model.cpp | 203 ++++ radio/src/gui/Horus/menu_model_curves.cpp | 325 ++++++ .../gui/Horus/menu_model_custom_functions.cpp | 372 +++++++ .../src/gui/Horus/menu_model_flightmodes.cpp | 149 +++ radio/src/gui/Horus/menu_model_gvars.cpp | 123 +++ radio/src/gui/Horus/menu_model_heli.cpp | 113 ++ .../src/gui/Horus/menu_model_inputs_mixes.cpp | 971 ++++++++++++++++++ radio/src/gui/Horus/menu_model_limits.cpp | 290 ++++++ .../gui/Horus/menu_model_logical_switches.cpp | 275 +++++ radio/src/gui/Horus/menu_model_select.cpp | 293 ++++++ radio/src/gui/Horus/menu_model_setup.cpp | 741 +++++++++++++ radio/src/gui/Horus/menu_model_telemetry.cpp | 728 +++++++++++++ radio/src/gui/Horus/menus.cpp | 93 ++ radio/src/gui/Horus/menus.h | 377 +++++++ radio/src/gui/Horus/navigation.cpp | 468 +++++++++ radio/src/gui/Horus/popups.cpp | 236 +++++ radio/src/gui/Horus/splash.cpp | 57 + radio/src/gui/Horus/view_about.cpp | 159 +++ radio/src/gui/Horus/view_channels.cpp | 122 +++ radio/src/gui/Horus/view_main.cpp | 374 +++++++ radio/src/gui/Horus/view_statistics.cpp | 213 ++++ radio/src/gui/Horus/view_telemetry.cpp | 202 ++++ radio/src/gui/Horus/view_text.cpp | 161 +++ radio/src/gui/Horus/widgets.cpp | 315 ++++++ radio/src/gui/gui.h | 6 +- radio/src/haptic.cpp | 3 +- radio/src/keys.cpp | 21 +- radio/src/keys.h | 101 +- radio/src/logs.cpp | 13 +- radio/src/lua_api.cpp | 60 +- radio/src/main_arm.cpp | 148 ++- radio/src/main_avr.cpp | 4 +- radio/src/mixer.cpp | 9 +- radio/src/myeeprom.h | 218 +++- radio/src/opentx.cpp | 73 +- radio/src/opentx.h | 97 +- radio/src/pulses/dsm2_arm.cpp | 8 +- radio/src/pulses/pulses.h | 2 +- radio/src/pulses/pxx_arm.cpp | 2 +- radio/src/serial.cpp | 2 +- radio/src/simu.cpp | 219 ++-- radio/src/switches.cpp | 232 ++++- radio/src/targets/simu/simpgmspace.cpp | 58 +- radio/src/targets/simu/simpgmspace.h | 25 +- radio/src/tasks_arm.cpp | 3 + radio/src/telemetry/frsky.cpp | 6 +- radio/src/telemetry/frsky.h | 2 +- radio/src/thirdparty/CoOS/OsConfig.h | 4 +- .../message_definitions_v1.0/matrixpilot.xml | 2 +- .../Class/audio/inc/usbd_audio_core.h | 2 +- .../Class/cdc/inc/usbd_cdc_if_template.h | 4 +- .../Class/cdc/src/usbd_cdc_core.c | 3 +- .../Class/dfu/inc/usbd_dfu_mal.h | 4 +- .../Class/dfu/inc/usbd_mem_if_template.h | 3 +- .../Class/dfu/src/usbd_dfu_core.c | 3 +- .../Class/hid/src/usbd_hid_core.c | 3 +- .../Class/msc/inc/usbd_msc_data.h | 2 +- .../Core/inc/usbd_conf_template.h | 2 +- .../Core/inc/usbd_core.h | 2 +- .../Core/inc/usbd_req.h | 2 +- .../Core/src/usbd_req.c | 3 +- .../inc/usb_conf_template.h | 2 +- .../STM32_USB_OTG_Driver/inc/usb_defines.h | 2 +- .../STM32_USB_OTG_Driver/inc/usb_regs.h | 2 +- .../STM32_USB_OTG_Driver/src/usb_hcd.c | 3 +- radio/src/translations.cpp | 2 +- radio/src/translations.h | 2 +- radio/src/translations/en.h.txt | 43 +- 90 files changed, 12075 insertions(+), 368 deletions(-) create mode 100644 radio/src/gui/Horus/fonts.cpp create mode 100644 radio/src/gui/Horus/gui.h create mode 100644 radio/src/gui/Horus/helpers.cpp create mode 100644 radio/src/gui/Horus/lcd.cpp create mode 100644 radio/src/gui/Horus/lcd.h create mode 100644 radio/src/gui/Horus/menu_general.cpp create mode 100644 radio/src/gui/Horus/menu_general_calib.cpp create mode 100644 radio/src/gui/Horus/menu_general_sdmanager.cpp create mode 100644 radio/src/gui/Horus/menu_general_setup.cpp create mode 100644 radio/src/gui/Horus/menu_general_trainer.cpp create mode 100644 radio/src/gui/Horus/menu_general_version.cpp create mode 100644 radio/src/gui/Horus/menu_model.cpp create mode 100644 radio/src/gui/Horus/menu_model_curves.cpp create mode 100644 radio/src/gui/Horus/menu_model_custom_functions.cpp create mode 100644 radio/src/gui/Horus/menu_model_flightmodes.cpp create mode 100644 radio/src/gui/Horus/menu_model_gvars.cpp create mode 100644 radio/src/gui/Horus/menu_model_heli.cpp create mode 100644 radio/src/gui/Horus/menu_model_inputs_mixes.cpp create mode 100644 radio/src/gui/Horus/menu_model_limits.cpp create mode 100644 radio/src/gui/Horus/menu_model_logical_switches.cpp create mode 100644 radio/src/gui/Horus/menu_model_select.cpp create mode 100644 radio/src/gui/Horus/menu_model_setup.cpp create mode 100644 radio/src/gui/Horus/menu_model_telemetry.cpp create mode 100644 radio/src/gui/Horus/menus.cpp create mode 100644 radio/src/gui/Horus/menus.h create mode 100644 radio/src/gui/Horus/navigation.cpp create mode 100644 radio/src/gui/Horus/popups.cpp create mode 100644 radio/src/gui/Horus/splash.cpp create mode 100644 radio/src/gui/Horus/view_about.cpp create mode 100644 radio/src/gui/Horus/view_channels.cpp create mode 100644 radio/src/gui/Horus/view_main.cpp create mode 100644 radio/src/gui/Horus/view_statistics.cpp create mode 100644 radio/src/gui/Horus/view_telemetry.cpp create mode 100644 radio/src/gui/Horus/view_text.cpp create mode 100644 radio/src/gui/Horus/widgets.cpp diff --git a/radio/src/Makefile b/radio/src/Makefile index 35469abcb..aff9aa9ec 100644 --- a/radio/src/Makefile +++ b/radio/src/Makefile @@ -409,7 +409,7 @@ LUADEP = DEBUG_TRACE_BUFFER = NO # MCU name -ifneq ($(PCB), $(filter $(PCB), STD 9X 9XR STD128 9X128 9XR128 9X2561 9XR2561 GRUVIN9X MEGA2560 SKY9X 9XRPRO AR9X TARANIS)) +ifneq ($(PCB), $(filter $(PCB), STD 9X 9XR STD128 9X128 9XR128 9X2561 9XR2561 GRUVIN9X MEGA2560 SKY9X 9XRPRO AR9X TARANIS FLAMENCO HORUS)) $(error Sorry, the PCB $(PCB) is not supported yet in OpenTX) endif @@ -424,7 +424,7 @@ EEPROM_VARIANT = 0 GUIMODELSRC = gui/$(GUIDIRECTORY)/menu_model.cpp gui/$(GUIDIRECTORY)/menu_model_select.cpp gui/$(GUIDIRECTORY)/menu_model_setup.cpp gui/$(GUIDIRECTORY)/menu_model_inputs_mixes.cpp gui/$(GUIDIRECTORY)/menu_model_limits.cpp gui/$(GUIDIRECTORY)/menu_model_logical_switches.cpp gui/$(GUIDIRECTORY)/menu_model_custom_functions.cpp gui/$(GUIDIRECTORY)/menu_model_telemetry.cpp GUIGENERALSRC = gui/$(GUIDIRECTORY)/menu_general.cpp gui/$(GUIDIRECTORY)/menu_general_setup.cpp gui/$(GUIDIRECTORY)/menu_general_trainer.cpp gui/$(GUIDIRECTORY)/menu_general_version.cpp gui/$(GUIDIRECTORY)/menu_general_calib.cpp -BITMAPS = bitmaps/sticks.lbm +BITMAPS = bitmaps/sticks.lbm FONTS = $(patsubst %.png,%.lbm,$(wildcard fonts/std/*.png)) @@ -439,7 +439,7 @@ ifeq ($(PCB), $(filter $(PCB), STD 9X 9XR)) SDCARD = NO THR_TRACE = NO INCDIRS += targets/stock - CPPDEFS = -DF_CPU=$(F_CPU)UL -DPCBSTD -DCPUM64 -DEEPROM_RLC -DEEPROM_VARIANT=$(shell echo ${EEPROM_VARIANT} | bc) + CPPDEFS = -DF_CPU=$(F_CPU)UL -DPCBSTD -DCPUM64 -DEEPROM -DEEPROM_RLC -DEEPROM_VARIANT=$(shell echo ${EEPROM_VARIANT} | bc) BOARDSRC = main_avr.cpp targets/stock/board_stock.cpp EXTRABOARDSRC = targets/common_avr/adc_driver.cpp targets/common_avr/telemetry_driver.cpp ifeq ($(GUI), YES) @@ -520,7 +520,7 @@ ifeq ($(PCB), $(filter $(PCB), STD128 9X128 9XR128)) SDCARD = NO THR_TRACE = NO EEPROM_VARIANT += ${M128_VARIANT} - CPPDEFS = -DF_CPU=$(F_CPU)UL -DPCBSTD -DCPUM128 -DEEPROM_RLC -DEEPROM_VARIANT=$(shell echo ${EEPROM_VARIANT} | bc) + CPPDEFS = -DF_CPU=$(F_CPU)UL -DPCBSTD -DCPUM128 -DEEPROM -DEEPROM_RLC -DEEPROM_VARIANT=$(shell echo ${EEPROM_VARIANT} | bc) INCDIRS += targets/stock BOARDSRC = main_avr.cpp targets/stock/board_stock.cpp EXTRABOARDSRC = targets/common_avr/adc_driver.cpp targets/stock/lcd_driver.cpp targets/common_avr/telemetry_driver.cpp @@ -595,7 +595,7 @@ ifeq ($(PCB), $(filter $(PCB), 9X2561)) SDCARD = NO THR_TRACE = YES EEPROM_VARIANT += ${M2561_VARIANT} - CPPDEFS = -DF_CPU=$(F_CPU)UL -DPCBSTD -DCPUM2561 -DEEPROM_RLC -DEEPROM_VARIANT=$(shell echo ${EEPROM_VARIANT} | bc) + CPPDEFS = -DF_CPU=$(F_CPU)UL -DPCBSTD -DCPUM2561 -DEEPROM -DEEPROM_RLC -DEEPROM_VARIANT=$(shell echo ${EEPROM_VARIANT} | bc) INCDIRS += targets/stock BOARDSRC = main_avr.cpp targets/stock/board_stock.cpp EXTRABOARDSRC = targets/common_avr/adc_driver.cpp targets/stock/lcd_driver.cpp targets/common_avr/telemetry_driver.cpp @@ -665,7 +665,7 @@ ifeq ($(PCB), GRUVIN9X) TRGT = avr- MCU = atmega2560 OPT = s - CPPDEFS += -DF_CPU=$(F_CPU)UL -DPCBGRUVIN9X -DCPUM2560 -DEEPROM_RLC -DEEPROM_VARIANT=0 -DAUDIO -DHAPTIC + CPPDEFS += -DF_CPU=$(F_CPU)UL -DPCBGRUVIN9X -DCPUM2560 -DEEPROM -DEEPROM_RLC -DEEPROM_VARIANT=0 -DAUDIO -DHAPTIC SDCARD = NO BUZZER = NO THR_TRACE = YES @@ -710,7 +710,7 @@ ifeq ($(PCB), MEGA2560) TRGT = avr- MCU = atmega2560 OPT = s - CPPDEFS = -DF_CPU=$(F_CPU)UL -DPCBMEGA2560 -DCPUM2560 -DEEPROM_RLC -DEEPROM_VARIANT=0 -DAUDIO + CPPDEFS = -DF_CPU=$(F_CPU)UL -DPCBMEGA2560 -DCPUM2560 -DEEPROM -DEEPROM_RLC -DEEPROM_VARIANT=0 -DAUDIO SDCARD = NO BUZZER = YES THR_TRACE = YES @@ -769,7 +769,7 @@ ifeq ($(PCB), $(filter $(PCB), SKY9X 9XRPRO AR9X)) GUIDIRECTORY = 9X ARCH = ARM LCDSIZE = 128 - CPPDEFS = -Dat91sam3s4 + CPPDEFS = -Dat91sam3s4 -DPPM_PIN_HW_SERIAL ifeq ($(PCB), 9XRPRO) CPPDEFS = -Dat91sam3s8 FLAVOUR = 9xrpro @@ -803,7 +803,7 @@ ifeq ($(PCB), $(filter $(PCB), SKY9X 9XRPRO AR9X)) BUZZER = NO THR_TRACE = YES EXT = FRSKY_SPORT - CPPDEFS += -DPCBSKY9X -DCPUARM -DEEPROM_VARIANT=0 -DAUDIO -DHAPTIC -DDSM2 -DDSM2_PPM -DPXX + CPPDEFS += -DPCBSKY9X -DCPUARM -DEEPROM -DEEPROM_VARIANT=0 -DAUDIO -DHAPTIC -DDSM2 -DDSM2_PPM -DPXX ifeq ($(PCB), SKY9X) CPPDEFS += -DROTARY_ENCODERS=1 CPPSRC += targets/sky9x/rotenc_driver.cpp @@ -926,7 +926,7 @@ ifeq ($(PCB), TARANIS) PPM_LIMITS_SYMETRICAL = YES PPM_CENTER_ADJUSTABLE = YES DSM2 = PPM - CPPDEFS += -DPCBTARANIS -DCPUARM -DCPUSTM32 -DVIRTUALINPUTS -DLUAINPUTS -DXCURVES -DEEPROM_RLC -DAUDIO -DPXX + CPPDEFS += -DPCBTARANIS -DCPUARM -DCPUSTM32 -DVIRTUALINPUTS -DLUAINPUTS -DXCURVES -DEEPROM -DEEPROM_RLC -DAUDIO -DPXX INCDIRS += targets/taranis $(THIRDPARTY) $(COOSDIR) $(COOSDIR)/kernel $(COOSDIR)/portable CPPDEFS += -DHSE_VALUE=12000000 ifeq ($(PCBREV), REV9E) @@ -1029,7 +1029,7 @@ ifeq ($(PCB), TARANIS) $(LUADIR)/lobject.c $(LUADIR)/lopcodes.c $(LUADIR)/lparser.c $(LUADIR)/lstate.c $(LUADIR)/lstring.c $(LUADIR)/ltable.c $(LUADIR)/lrotable.c $(LUADIR)/ltm.c $(LUADIR)/lundump.c $(LUADIR)/lvm.c $(LUADIR)/lzio.c \ $(LUADIR)/lbaselib.c $(LUADIR)/linit.c $(LUADIR)/lmathlib.c $(LUADIR)/lbitlib.c $(LUADIR)/loadlib.c $(LUADIR)/lauxlib.c $(LUADIR)/ltablib.c $(LUADIR)/lcorolib.c $(LUADIR)/liolib.c SRC += $(LUASRC) - LUADEP = lua_exports.inc + LUADEP = lua_exports_taranis.inc ifeq ($(USE_BIN_ALLOCATOR), YES) CPPDEFS += -DUSE_BIN_ALLOCATOR CPPSRC += bin_allocator.cpp @@ -1061,6 +1061,257 @@ ifeq ($(PCB), TARANIS) endif endif +ifeq ($(PCB), FLAMENCO) + # FLAMENCO radio + ARCH = ARM + LCDSIZE = 320 + GUIDIRECTORY = Flamenco + FLAVOUR = FLAMENCO + LDSCRIPT = targets/Flamenco/stm32f4_flash.ld + STM32LIBPATH = $(THIRDPARTY)/STM32F4xx_DSP_StdPeriph_Lib_V1.4.0/Libraries + STM32USBPATH = $(THIRDPARTY)/STM32_USB-Host-Device_Lib_V2.1.0/Libraries + TRGT = arm-none-eabi- + MCU = cortex-m4 + OPT = 2 + CPPDEFS += -DHSE_VALUE=12000000 -DCOLORLCD -DSTM32F40_41xxx + BITMAPS += $(patsubst %.png,%.lbm,$(wildcard bitmaps/Flamenco/*.png)) + FONTS = fonts/font_stdsize.lbm fonts/font_tinsize.lbm fonts/font_smlsize.lbm fonts/font_midsize.lbm fonts/font_dblsize.lbm fonts/font_xxlsize.lbm + SDCARD = YES + THR_TRACE = YES + EXT = FRSKY_SPORT + AUTOSWITCH = YES + AUTOSOURCE = YES + DBLKEYS = YES + PPM_LIMITS_SYMETRICAL = YES + PPM_CENTER_ADJUSTABLE = YES + DSM2 = PPM + TIMERS = 2 + CPPDEFS += -DTIMERS=$(TIMERS) + CPPDEFS += -DPCBFLAMENCO -DCPUARM -DCPUSTM32 -DEEPROM -DVIRTUALINPUTS -DLUAINPUTS -DXCURVES -DEEPROM_VARIANT=0 -DAUDIO -DPXX + INCDIRS += targets/Flamenco $(THIRDPARTY) $(COOSDIR) $(COOSDIR)/kernel $(COOSDIR)/portable + INCDIRS += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/inc $(STM32LIBPATH)/CMSIS/Device/ST/STM32F4xx/Include $(STM32LIBPATH)/CMSIS/include + STM32USBPATH = $(THIRDPARTY)/STM32_USB-Host-Device_Lib_V2.1.0/Libraries + INCDIRS += $(STM32USBPATH)/STM32_USB_OTG_Driver/inc + INCDIRS += $(STM32USBPATH)/STM32_USB_Device_Library/Core/inc + INCDIRS += $(STM32USBPATH)/STM32_USB_Device_Library/Class/msc/inc + INCDIRS += $(STM32USBPATH)/STM32_USB_Device_Library/Class/hid/inc + INCDIRS += $(STM32USBPATH)/STM32_USB_Device_Library/Class/cdc/inc + BOARDSRC = main_arm.cpp targets/Flamenco/board_flamenco.cpp + EXTRABOARDSRC += targets/Flamenco/lcd_driver.cpp targets/Flamenco/delays.c targets/Flamenco/i2c_driver.cpp targets/taranis/configure_pins.cpp serial.cpp # targets/taranis/flash_driver.cpp + SRC += $(COOSDIR)/kernel/core.c $(COOSDIR)/kernel/hook.c $(COOSDIR)/kernel/task.c $(COOSDIR)/kernel/event.c $(COOSDIR)/kernel/time.c $(COOSDIR)/kernel/timer.c $(COOSDIR)/kernel/flag.c $(COOSDIR)/kernel/mutex.c $(COOSDIR)/kernel/serviceReq.c $(COOSDIR)/portable/GCC/port.c $(COOSDIR)/portable/arch.c + SRC += targets/Flamenco/pwr_driver.c targets/Flamenco/usb_driver.c + EEPROMSRC = eeprom_common.cpp eeprom_raw.cpp + PULSESSRC = pulses/pulses_arm.cpp pulses/ppm_arm.cpp pulses/pxx_arm.cpp + CPPSRC += tasks_arm.cpp audio_arm.cpp sbus.cpp telemetry/telemetry.cpp + CPPSRC += targets/Flamenco/tw8823_driver.cpp targets/Flamenco/pulses_driver.cpp targets/Flamenco/keys_driver.cpp targets/Flamenco/adc_driver.cpp targets/Flamenco/eeprom_driver.cpp targets/Flamenco/trainer_driver.cpp targets/Flamenco/audio_driver.cpp targets/Flamenco/serial2_driver.cpp targets/Flamenco/telemetry_driver.cpp + CPPSRC += gui/$(GUIDIRECTORY)/view_channels.cpp gui/$(GUIDIRECTORY)/view_about.cpp gui/$(GUIDIRECTORY)/view_text.cpp debug.cpp + SRC += targets/Flamenco/system_stm32f4xx.c + SRC += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/src/misc.c + SRC += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_gpio.c + SRC += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_dbgmcu.c + SRC += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_rcc.c + SRC += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_spi.c + SRC += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_i2c.c + SRC += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_dma.c + SRC += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_rtc.c + SRC += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_pwr.c + SRC += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_usart.c + SRC += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_sdio.c + SRC += $(STM32LIBPATH)/CMSIS/Device/ST/STM32F4xx/Source/Templates/gcc_ride7/startup_stm32f40_41xxx.s + SRC += targets/Flamenco/sdio_sd.c targets/Flamenco/usb_bsp.c targets/Flamenco/usbd_desc.c + SRC += $(STM32USBPATH)/STM32_USB_OTG_Driver/src/usb_core.c + SRC += $(STM32USBPATH)/STM32_USB_OTG_Driver/src/usb_dcd.c + SRC += $(STM32USBPATH)/STM32_USB_OTG_Driver/src/usb_dcd_int.c + SRC += $(STM32USBPATH)/STM32_USB_Device_Library/Core/src/usbd_core.c + SRC += $(STM32USBPATH)/STM32_USB_Device_Library/Core/src/usbd_ioreq.c + SRC += $(STM32USBPATH)/STM32_USB_Device_Library/Core/src/usbd_req.c + EXTRABOARDSRC += targets/Flamenco/usbd_usr.cpp + SRC += syscalls.c + ifeq ($(USB), JOYSTICK) + CPPDEFS += -DUSB_JOYSTICK + SRC += targets/Flamenco/usbd_hid_joystick.c + else + CPPDEFS += -DUSB_MASS_STORAGE + SRC += $(STM32USBPATH)/STM32_USB_Device_Library/Class/msc/src/usbd_msc_data.c + SRC += $(STM32USBPATH)/STM32_USB_Device_Library/Class/msc/src/usbd_msc_scsi.c + SRC += $(STM32USBPATH)/STM32_USB_Device_Library/Class/msc/src/usbd_msc_bot.c + SRC += $(STM32USBPATH)/STM32_USB_Device_Library/Class/msc/src/usbd_msc_core.c + EXTRABOARDSRC += targets/Flamenco/usbd_storage_msd.cpp + endif + ifeq ($(GVARS), YES) + GUIMODELSRC += gui/$(GUIDIRECTORY)/menu_model_gvars.cpp + endif + ifneq ($(LUA), NO) + ifeq ($(LUA), YES) + CPPDEFS += -DLUA_MODEL_SCRIPTS + endif + CPPDEFS += -DLUA + INCDIRS += $(LUADIR) + CPPSRC += lua_api.cpp + LUASRC = $(LUADIR)/lapi.c $(LUADIR)/lcode.c $(LUADIR)/lctype.c $(LUADIR)/ldebug.c $(LUADIR)/ldo.c $(LUADIR)/ldump.c $(LUADIR)/lfunc.c $(LUADIR)/lgc.c $(LUADIR)/llex.c $(LUADIR)/lmem.c \ + $(LUADIR)/lobject.c $(LUADIR)/lopcodes.c $(LUADIR)/lparser.c $(LUADIR)/lstate.c $(LUADIR)/lstring.c $(LUADIR)/ltable.c $(LUADIR)/lrotable.c $(LUADIR)/ltm.c $(LUADIR)/lundump.c $(LUADIR)/lvm.c $(LUADIR)/lzio.c \ + $(LUADIR)/lbaselib.c $(LUADIR)/linit.c $(LUADIR)/lmathlib.c $(LUADIR)/lbitlib.c $(LUADIR)/loadlib.c $(LUADIR)/lauxlib.c $(LUADIR)/ltablib.c $(LUADIR)/lcorolib.c $(LUADIR)/liolib.c + SRC += $(LUASRC) + LUADEP = lua_exports_flamenco.inc + endif + + EXTRABOARDSRC += $(FATFSDIR)/ff.c $(FATFSDIR)/fattime.c $(FATFSDIR)/option/ccsbcs.c targets/Flamenco/diskio.cpp + CPPDEFS += -DSDCARD -DVOICE -DRTCLOCK + CPPSRC += sdcard.cpp rtc.cpp logs.cpp targets/taranis/rtc_driver.cpp + GUIGENERALSRC += gui/$(GUIDIRECTORY)/menu_general_sdmanager.cpp + INCDIRS += $(FATFSDIR) $(FATFSDIR)/option + + ifeq ($(DSM2), PPM) + CPPSRC += pulses/dsm2_arm.cpp + endif + + CPPDEFS += -DHAPTIC + CPPSRC += haptic.cpp + CPPSRC += targets/Flamenco/haptic_driver.cpp + EXTRABOARDSRC += + + ifeq ($(TW8823_TRACES), YES) + CPPDEFS += -DTW8823_TRACES + endif + + ifeq ($(TW8823_BITMAPS), YES) + CPPDEFS += -DTW8823_BITMAPS + endif + + ifeq ($(TW8823_SERIAL), YES) + CPPDEFS += -DTW8823_SERIAL + endif +endif + +ifeq ($(PCB), HORUS) + # HORUS radio + ARCH = ARM + LCDSIZE = 320 + GUIDIRECTORY = Horus + FLAVOUR = HORUS + LDSCRIPT = targets/Horus/stm32f4_flash.ld + STM32LIBPATH = $(THIRDPARTY)/STM32F4xx_DSP_StdPeriph_Lib_V1.4.0/Libraries + STM32USBPATH = $(THIRDPARTY)/STM32_USB-Host-Device_Lib_V2.1.0/Libraries + TRGT = arm-none-eabi- + MCU = cortex-m4 + OPT = 2 + CPPDEFS += -DHSE_VALUE=12000000 -DCOLORLCD -DSTM32F429_439xx + BITMAPS += $(patsubst %.png,%.lbm,$(wildcard bitmaps/Horus/*.png)) + FONTS = fonts/font_stdsize.lbm fonts/font_tinsize.lbm fonts/font_smlsize.lbm fonts/font_midsize.lbm fonts/font_dblsize.lbm fonts/font_xxlsize.lbm + SDCARD = YES + THR_TRACE = YES + EXT = FRSKY_SPORT + AUTOSWITCH = YES + AUTOSOURCE = YES + DBLKEYS = YES + PPM_LIMITS_SYMETRICAL = YES + PPM_CENTER_ADJUSTABLE = YES + DSM2 = PPM + TIMERS = 2 + CPPDEFS += -DTIMERS=$(TIMERS) + CPPDEFS += -DPCBHORUS -DCPUARM -DCPUSTM32 -DVIRTUALINPUTS -DLUAINPUTS -DXCURVES -DEEPROM_VARIANT=0 -DAUDIO -DPXX + INCDIRS += targets/Horus $(THIRDPARTY) $(COOSDIR) $(COOSDIR)/kernel $(COOSDIR)/portable + INCDIRS += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/inc $(STM32LIBPATH)/CMSIS/Device/ST/STM32F4xx/Include $(STM32LIBPATH)/CMSIS/include + STM32USBPATH = $(THIRDPARTY)/STM32_USB-Host-Device_Lib_V2.1.0/Libraries + INCDIRS += $(STM32USBPATH)/STM32_USB_OTG_Driver/inc + INCDIRS += $(STM32USBPATH)/STM32_USB_Device_Library/Core/inc + INCDIRS += $(STM32USBPATH)/STM32_USB_Device_Library/Class/msc/inc + INCDIRS += $(STM32USBPATH)/STM32_USB_Device_Library/Class/hid/inc + INCDIRS += $(STM32USBPATH)/STM32_USB_Device_Library/Class/cdc/inc + BOARDSRC = main_arm.cpp targets/Horus/board_horus.cpp targets/Horus/led_driver.cpp + EXTRABOARDSRC += targets/Horus/lcd_driver.cpp targets/Horus/delays.c targets/Horus/i2c_driver.cpp targets/taranis/configure_pins.cpp serial.cpp # targets/taranis/flash_driver.cpp + SRC += $(COOSDIR)/kernel/core.c $(COOSDIR)/kernel/hook.c $(COOSDIR)/kernel/task.c $(COOSDIR)/kernel/event.c $(COOSDIR)/kernel/time.c $(COOSDIR)/kernel/timer.c $(COOSDIR)/kernel/flag.c $(COOSDIR)/kernel/mutex.c $(COOSDIR)/kernel/serviceReq.c $(COOSDIR)/portable/GCC/port.c $(COOSDIR)/portable/arch.c + SRC += targets/Horus/pwr_driver.c targets/Horus/usb_driver.c targets/Horus/sdram_driver.c + PULSESSRC = pulses/pulses_arm.cpp pulses/ppm_arm.cpp pulses/pxx_arm.cpp + CPPSRC += tasks_arm.cpp audio_arm.cpp sbus.cpp telemetry/telemetry.cpp + CPPSRC += targets/Horus/pulses_driver.cpp targets/Horus/keys_driver.cpp targets/Horus/adc_driver.cpp targets/Horus/trainer_driver.cpp targets/Horus/audio_driver.cpp targets/Horus/serial2_driver.cpp targets/Horus/telemetry_driver.cpp + CPPSRC += gui/$(GUIDIRECTORY)/view_channels.cpp gui/$(GUIDIRECTORY)/view_about.cpp gui/$(GUIDIRECTORY)/view_text.cpp debug.cpp + SRC += targets/Horus/system_stm32f4xx.c + SRC += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/src/misc.c + SRC += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_gpio.c + SRC += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_dbgmcu.c + SRC += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_rcc.c + SRC += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_spi.c + SRC += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_i2c.c + SRC += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_dma.c + SRC += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_rtc.c + SRC += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_pwr.c + SRC += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_usart.c + SRC += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_sdio.c + SRC += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_fmc.c + SRC += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_ltdc.c + SRC += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_tim.c + SRC += $(STM32LIBPATH)/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_dma2d.c + SRC += $(STM32LIBPATH)/CMSIS/Device/ST/STM32F4xx/Source/Templates/gcc_ride7/startup_stm32f40_41xxx.s + SRC += targets/Horus/sdio_sd.c targets/Horus/usb_bsp.c targets/Horus/usbd_desc.c + SRC += $(STM32USBPATH)/STM32_USB_OTG_Driver/src/usb_core.c + SRC += $(STM32USBPATH)/STM32_USB_OTG_Driver/src/usb_dcd.c + SRC += $(STM32USBPATH)/STM32_USB_OTG_Driver/src/usb_dcd_int.c + SRC += $(STM32USBPATH)/STM32_USB_Device_Library/Core/src/usbd_core.c + SRC += $(STM32USBPATH)/STM32_USB_Device_Library/Core/src/usbd_ioreq.c + SRC += $(STM32USBPATH)/STM32_USB_Device_Library/Core/src/usbd_req.c + EXTRABOARDSRC += targets/Horus/usbd_usr.cpp + SRC += syscalls.c + ifeq ($(USB), JOYSTICK) + CPPDEFS += -DUSB_JOYSTICK + SRC += targets/Horus/usbd_hid_joystick.c + else ifeq ($(USB), SERIAL) + CPPDEFS += -DUSB_SERIAL + SRC += $(STM32USBPATH)/STM32_USB_Device_Library/Class/cdc/src/usbd_cdc_core.c + EXTRABOARDSRC += targets/Horus/usbd_cdc.cpp + else + CPPDEFS += -DUSB_MASS_STORAGE + SRC += $(STM32USBPATH)/STM32_USB_Device_Library/Class/msc/src/usbd_msc_data.c + SRC += $(STM32USBPATH)/STM32_USB_Device_Library/Class/msc/src/usbd_msc_scsi.c + SRC += $(STM32USBPATH)/STM32_USB_Device_Library/Class/msc/src/usbd_msc_bot.c + SRC += $(STM32USBPATH)/STM32_USB_Device_Library/Class/msc/src/usbd_msc_core.c + EXTRABOARDSRC += targets/Horus/usbd_storage_msd.cpp + endif + ifeq ($(GVARS), YES) + GUIMODELSRC += gui/$(GUIDIRECTORY)/menu_model_gvars.cpp + endif + ifneq ($(LUA), NO) + ifeq ($(LUA), YES) + CPPDEFS += -DLUA_MODEL_SCRIPTS + endif + CPPDEFS += -DLUA + INCDIRS += $(LUADIR) + CPPSRC += lua_api.cpp + LUASRC = $(LUADIR)/lapi.c $(LUADIR)/lcode.c $(LUADIR)/lctype.c $(LUADIR)/ldebug.c $(LUADIR)/ldo.c $(LUADIR)/ldump.c $(LUADIR)/lfunc.c $(LUADIR)/lgc.c $(LUADIR)/llex.c $(LUADIR)/lmem.c \ + $(LUADIR)/lobject.c $(LUADIR)/lopcodes.c $(LUADIR)/lparser.c $(LUADIR)/lstate.c $(LUADIR)/lstring.c $(LUADIR)/ltable.c $(LUADIR)/lrotable.c $(LUADIR)/ltm.c $(LUADIR)/lundump.c $(LUADIR)/lvm.c $(LUADIR)/lzio.c \ + $(LUADIR)/lbaselib.c $(LUADIR)/linit.c $(LUADIR)/lmathlib.c $(LUADIR)/lbitlib.c $(LUADIR)/loadlib.c $(LUADIR)/lauxlib.c $(LUADIR)/ltablib.c $(LUADIR)/lcorolib.c $(LUADIR)/liolib.c + SRC += $(LUASRC) + LUADEP = lua_exports_flamenco.inc + endif + + EXTRABOARDSRC += $(FATFSDIR)/ff.c $(FATFSDIR)/fattime.c $(FATFSDIR)/option/ccsbcs.c targets/Horus/diskio.cpp + CPPDEFS += -DSDCARD -DVOICE -DRTCLOCK + CPPSRC += sdcard.cpp rtc.cpp logs.cpp targets/taranis/rtc_driver.cpp + GUIGENERALSRC += gui/$(GUIDIRECTORY)/menu_general_sdmanager.cpp + INCDIRS += $(FATFSDIR) $(FATFSDIR)/option + + ifeq ($(DSM2), PPM) + CPPSRC += pulses/dsm2_arm.cpp + endif + + CPPDEFS += -DHAPTIC + CPPSRC += haptic.cpp + CPPSRC += targets/Horus/haptic_driver.cpp + EXTRABOARDSRC += + + ifeq ($(TW8823_TRACES), YES) + CPPDEFS += -DTW8823_TRACES + endif + + ifeq ($(TW8823_BITMAPS), YES) + CPPDEFS += -DTW8823_BITMAPS + endif + + ifeq ($(TW8823_SERIAL), YES) + CPPDEFS += -DTW8823_SERIAL + endif +endif + CC = $(TRGT)gcc CPP = $(TRGT)cpp AS = $(TRGT)as @@ -1084,7 +1335,7 @@ FORMAT = ihex TARGET = opentx # List C++ source files here. (C dependencies are automatically generated.) -ifeq ($(PCB), $(filter $(PCB), SKY9X 9XRPRO AR9X TARANIS)) +ifeq ($(PCB), $(filter $(PCB), SKY9X 9XRPRO AR9X TARANIS FLAMENCO HORUS)) TTS_SRC = translations/tts_cz.cpp translations/tts_de.cpp translations/tts_en.cpp translations/tts_es.cpp translations/tts_fr.cpp translations/tts_it.cpp translations/tts_nl.cpp translations/tts_pt.cpp translations/tts_sk.cpp translations/tts_se.cpp translations/tts_pl.cpp translations/tts_hu.cpp else STD_TTS_SRC = translations/tts_$(shell sh -c "echo $(TTS) | tr '[:upper:]' '[:lower:]'").cpp @@ -1144,7 +1395,7 @@ ifeq ($(NAVIGATION), ROTENC) endif ifeq ($(TURNIGY_TRANSMITTER_FIX), YES) - ifeq ($(PCB), $(filter $(PCB), TARANIS)) + ifeq ($(PCB), $(filter $(PCB), TARANIS FLAMENCO HORUS)) $(warning TURNIGY_TRANSMITTER_FIX is not available on this radio) else CPPDEFS += -DMODULE_ALWAYS_SEND_PULSES @@ -1195,7 +1446,7 @@ ifeq ($(BOLD), YES) CPPDEFS += -DBOLD_FONT endif -ifneq ($(PCB), $(filter $(PCB), TARANIS)) +ifneq ($(PCB), $(filter $(PCB), TARANIS FLAMENCO HORUS)) ifeq ($(BATTGRAPH), YES) CPPDEFS += -DBATTGRAPH endif @@ -1389,7 +1640,7 @@ ifeq ($(HELI), YES) endif ifeq ($(TEMPLATES), YES) - ifneq ($(PCB), $(filter $(PCB), TARANIS)) + ifneq ($(PCB), $(filter $(PCB), TARANIS FLAMENCO HORUS)) CPPDEFS += -DTEMPLATES CPPSRC += templates.cpp GUIMODELSRC += gui/$(GUIDIRECTORY)/menu_model_templates.cpp @@ -1592,30 +1843,51 @@ translations/se.h: translations/se.h.txt @echo "Create Swedish language specific header files" $(TRANSLATE) translations/se.h.txt translations/se.h se -FONTNAME = Roboto +ifeq ($(PCB), $(filter $(PCB), HORUS)) + FONTNAME = DejaVu\ Sans + TINSIZE = 5 + SMLSIZE = 7 + STDSIZE = 16 + MIDSIZE = 16 + DBLSIZE = 20 + XXLSIZE = 38 +else + FONTNAME = Roboto + TINSIZE = 5 + SMLSIZE = 7 + STDSIZE = 8 + MIDSIZE = 11 + DBLSIZE = 14 + XXLSIZE = 38 +endif .PHONY: fonts fonts: $(FONTS) +fonts/font_%size.lbm: fonts/font_%size.png + $(IMG2LBM) $^ $@ $(LCDSIZE) 8bits + +fonts/font_tinsize.png: + $(FONT2PNG) $(FONTNAME) $(TINSIZE) fonts/font_tinsize + +fonts/font_smlsize.png: + $(FONT2PNG) $(FONTNAME) $(SMLSIZE) fonts/font_smlsize + +fonts/font_stdsize.png: + $(FONT2PNG) $(FONTNAME) $(STDSIZE) fonts/font_stdsize + +fonts/font_midsize.png: + $(FONT2PNG) $(FONTNAME) $(MIDSIZE) fonts/font_midsize + +fonts/font_dblsize.png: + $(FONT2PNG) $(FONTNAME) $(DBLSIZE) fonts/font_dblsize + +fonts/font_xxlsize.png: + $(FONT2PNG) $(FONTNAME) $(XXLSIZE) fonts/font_xxlsize + fonts/%.lbm: fonts/%.png $(IMG2LBM) $^ $@ $(LCDSIZE) -fonts/font_tinsize.lbm: - $(FONT2PNG) $(FONTNAME) 5 fonts/font_tinsize.png - $(IMG2LBM) fonts/font_tinsize.png $@ $(LCDSIZE) 4bits - -fonts/font_stdsize.lbm: - $(FONT2PNG) $(FONTNAME) 8 fonts/font_stdsize.png - $(IMG2LBM) fonts/font_stdsize.png $@ $(LCDSIZE) 4bits - -fonts/font_midsize.lbm: - $(FONT2PNG) $(FONTNAME) 10 fonts/font_midsize.png - $(IMG2LBM) fonts/font_midsize.png $@ $(LCDSIZE) 4bits - -fonts/font_dblsize.lbm: - $(FONT2PNG) $(FONTNAME) 14 fonts/font_dblsize.png - $(IMG2LBM) fonts/font_dblsize.png $@ $(LCDSIZE) 4bits - .PHONY: bitmaps bitmaps: $(BITMAPS) @@ -1631,18 +1903,41 @@ bitmaps/Taranis/%.lbm: bitmaps/Taranis/%.png bitmaps/Taranis/mainmenu.png: ../util/taranisicons.py $(wildcard bitmaps/Taranis/std/*.png) @$(PYTHON) ../util/taranisicons.py +bitmaps/Flamenco/%.lbm: bitmaps/Flamenco/%.png + $(IMG2LBM) $^ $@ $(LCDSIZE) 4/4/4/4 + +bitmaps/Horus/mask_%.lbm: bitmaps/Horus/mask_%.png + $(IMG2LBM) $^ $@ $(LCDSIZE) 8bits + +bitmaps/Horus/%.lbm: bitmaps/Horus/%.png + $(IMG2LBM) $^ $@ $(LCDSIZE) 5/6/5 + ifeq ($(OS),Windows_NT) PARSER = avr-cpp else PARSER = gcc -E -x c++ endif -lua_exports.inc: myeeprom.h ../util/luaexport.py - @echo "Generating a list of Lua exported constants in lua_exports.txt" - @$(PARSER) -DPCBTARANIS -DCPUARM -DCPUSTM32 -DLUA -DEXPORT myeeprom.h | grep LEXP > lua_exports.txt - @echo "Parsing and generating C Lua exports in lua_exports.inc" - @$(PYTHON) ../util/luaexport.py $(VERSION) lua_exports.txt lua_exports.inc lua_fields.txt - @rm lua_exports.txt +lua_exports_taranis.inc: myeeprom.h ../util/luaexport.py + @echo "Generating a list of Lua exported constants in lua_exports_taranis.txt" + @$(PARSER) -DPCBTARANIS -DCPUARM -DCPUSTM32 -DLUA -DEXPORT myeeprom.h | grep LEXP > lua_exports_taranis.txt + @echo "Parsing and generating C Lua exports in lua_exports_taranis.inc" + @$(PYTHON) ../util/luaexport.py $(VERSION) lua_exports_taranis.txt lua_exports_taranis.inc lua_fields_taranis.txt + @rm lua_exports_taranis.txt + +lua_exports_horus.inc: myeeprom.h ../util/luaexport.py + @echo "Generating a list of Lua exported constants in lua_exports_horus.txt" + @$(PARSER) -DPCBFLAMENCO -DCPUARM -DCPUSTM32 -DLUA -DEXPORT myeeprom.h | grep LEXP > lua_exports_horus.txt + @echo "Parsing and generating C Lua exports in lua_exports_horus.inc" + @$(PYTHON) ../util/luaexport.py $(VERSION) lua_exports_horus.txt lua_exports_horus.inc lua_fields_horus.txt + @rm lua_exports_horus.txt + +lua_exports_flamenco.inc: myeeprom.h ../util/luaexport.py + @echo "Generating a list of Lua exported constants in lua_exports_flamenco.txt" + @$(PARSER) -DPCBFLAMENCO -DCPUARM -DCPUSTM32 -DLUA -DEXPORT myeeprom.h | grep LEXP > lua_exports_flamenco.txt + @echo "Parsing and generating C Lua exports in lua_exports_flamenco.inc" + @$(PYTHON) ../util/luaexport.py $(VERSION) lua_exports_flamenco.txt lua_exports_flamenco.inc lua_fields_flamenco.txt + @rm lua_exports_flamenco.txt # Eye candy. # AVR Studio 3.x does not check make's exit code but relies on @@ -1803,7 +2098,7 @@ clean_list : $(REMOVE) bitmaps/*/*/*.lbm $(REMOVE) fonts/*.lbm $(REMOVE) fonts/*/*.lbm - $(REMOVE) lua_exports.txt lua_exports.inc lua_fields.txt + $(REMOVE) lua_exports* lua_fields.txt $(MAKE) -C targets/taranis/bootloader clean #### Install diff --git a/radio/src/audio_arm.cpp b/radio/src/audio_arm.cpp index 23b9b4c39..58962c696 100644 --- a/radio/src/audio_arm.cpp +++ b/radio/src/audio_arm.cpp @@ -189,7 +189,7 @@ const char * const audioFilenames[] = { "midstck2", "midstck3", "midstck4", -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) "midpot1", "midpot2", "midslid1", @@ -265,6 +265,8 @@ void referenceSystemAudioFiles() fn = *fno.lfname ? fno.lfname : fno.fname; uint8_t len = strlen(fn); + TRACE("%s", fn); + // Eliminates directories / non wav files if (len < 5 || strcasecmp(fn+len-4, SOUNDS_EXT) || (fno.fattrib & AM_DIR)) continue; @@ -520,6 +522,7 @@ void audioTask(void* pdata) setSampleRate(AUDIO_SAMPLE_RATE); #if defined(SDCARD) + TRACE("unexpectedShutdown = %d", unexpectedShutdown); if (!unexpectedShutdown) { sdInit(); AUDIO_TADA(); @@ -1096,7 +1099,7 @@ void audioEvent(unsigned int index, unsigned int freq) case AU_STICK4_MIDDLE: case AU_POT1_MIDDLE: case AU_POT2_MIDDLE: -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) case AU_SLIDER1_MIDDLE: case AU_SLIDER2_MIDDLE: #else diff --git a/radio/src/buzzer.h b/radio/src/buzzer.h index 2a451b6fa..8bb0b8463 100644 --- a/radio/src/buzzer.h +++ b/radio/src/buzzer.h @@ -65,7 +65,7 @@ inline void _beep(uint8_t b) void beep(uint8_t val); #else /* BUZZER */ -#define beep(...) +inline void beep(uint8_t) { } #endif /* BUZZER */ #if !defined(AUDIO) diff --git a/radio/src/cli.cpp b/radio/src/cli.cpp index 23f911a4c..78003b42d 100644 --- a/radio/src/cli.cpp +++ b/radio/src/cli.cpp @@ -43,7 +43,7 @@ OS_TID cliTaskId; TaskStack cliStack; Fifo<256> cliRxFifo; -uint8_t cliTracesEnabled = false; +uint8_t cliTracesEnabled = true; typedef int (* CliFunction) (const char ** args); @@ -66,7 +66,7 @@ void cliPrompt() serialPutc('>'); } -int toInt(const char ** argv, int index, int * val) +int toLongLongInt(const char ** argv, int index, long long int * val) { if (*argv[index] == '\0') { return 0; @@ -79,7 +79,7 @@ int toInt(const char ** argv, int index, int * val) s = &argv[index][2]; } char * endptr = NULL; - *val = strtol(s, &endptr, base); + *val = strtoll(s, &endptr, base); if (*endptr == '\0') return 1; else { @@ -89,6 +89,14 @@ int toInt(const char ** argv, int index, int * val) } } +int toInt(const char ** argv, int index, int * val) +{ + long long int lval = 0; + int result = toLongLongInt(argv, index, &lval); + *val = (int)lval; + return result; +} + int cliBeep(const char ** argv) { int freq = BEEP_DEFAULT_FREQ; @@ -200,6 +208,33 @@ int cliVolume(const char ** argv) return 0; } +#if defined(PCBFLAMENCO) +int cliReadBQ24195(const char ** argv) +{ + int index = 0; + if (toInt(argv, 1, &index) > 0) { + serialPrint("BQ24195[%d] = 0x%02x", index, i2cReadBQ24195(index)); + } + else { + serialPrint("%s: Invalid arguments \"%s\" \"%s\"", argv[0], argv[1]); + } + return 0; +} + +int cliWriteBQ24195(const char ** argv) +{ + int index = 0; + int data = 0; + if (toInt(argv, 1, &index) > 0 && toInt(argv, 2, &data) > 0) { + i2cWriteBQ24195(index, data); + } + else { + serialPrint("%s: Invalid arguments \"%s\" \"%s\"", argv[0], argv[1], argv[2]); + } + return 0; +} +#endif + const MemArea memAreas[] = { { "RCC", RCC, sizeof(RCC_TypeDef) }, { "GPIOA", GPIOA, sizeof(GPIO_TypeDef) }, @@ -210,13 +245,14 @@ const MemArea memAreas[] = { { "GPIOF", GPIOF, sizeof(GPIO_TypeDef) }, { "GPIOG", GPIOG, sizeof(GPIO_TypeDef) }, { "USART1", USART1, sizeof(USART_TypeDef) }, + { "USART2", USART2, sizeof(USART_TypeDef) }, { "USART3", USART3, sizeof(USART_TypeDef) }, { NULL, NULL, 0 }, }; int cliDisplay(const char ** argv) { - int address = 0; + long long int address = 0; for (const MemArea * area = memAreas; area->name != NULL; area++) { if (!strcmp(area->name, argv[1])) { @@ -225,7 +261,26 @@ int cliDisplay(const char ** argv) } } - if (!strcmp(argv[1], "adc")) { + if (!strcmp(argv[1], "keys")) { + for (int i=0; i 0) { +#if defined(PCBFLAMENCO) + else if (!strcmp(argv[1], "bq24195")) { + { + uint8_t reg = i2cReadBQ24195(0x00); + serialPrint(reg & 0x80 ? "HIZ enable" : "HIZ disable"); + } + { + uint8_t reg = i2cReadBQ24195(0x08); + serialPrint(reg & 0x01 ? "VBatt < VSysMin" : "VBatt > VSysMin"); + serialPrint(reg & 0x02 ? "Thermal sensor bad" : "Thermal sensor ok"); + serialPrint(reg & 0x04 ? "Power ok" : "Power bad"); + serialPrint(reg & 0x08 ? "Connected to charger" : "Not connected to charger"); + const char * CHARGE_STATUS[] = { "Not Charging", "Precharge", "Fast Charging", "Charge done" }; + serialPrint(CHARGE_STATUS[(reg & 0x30) >> 4]); + const char * INPUT_STATUS[] = { "Unknown input", "USB host input", "USB adapter port input", "OTG input" }; + serialPrint(INPUT_STATUS[(reg & 0xC0) >> 6]); + } + { + uint8_t reg = i2cReadBQ24195(0x09); + if (reg & 0x80) serialPrint("Watchdog timer expiration"); + uint8_t chargerFault = (reg & 0x30) >> 4; + if (chargerFault == 0x01) + serialPrint("Input fault"); + else if (chargerFault == 0x02) + serialPrint("Thermal shutdown"); + else if (chargerFault == 0x03) + serialPrint("Charge safety timer expiration"); + if (reg & 0x08) serialPrint("Battery over voltage fault"); + uint8_t ntcFault = (reg & 0x07); + if (ntcFault == 0x05) + serialPrint("NTC cold"); + else if (ntcFault == 0x06) + serialPrint("NTC hot"); + } + } +#endif + else if (toLongLongInt(argv, 1, &address) > 0) { int size = 256; if (toInt(argv, 2, &size) >= 0) { dump((uint8_t *)address, size); @@ -259,6 +350,10 @@ const CliCommand cliCommands[] = { { "stackinfo", cliStackInfo, "" }, { "trace", cliTrace, "on | off" }, { "volume", cliVolume, "" }, +#if defined(PCBFLAMENCO) + { "read_bq24195", cliReadBQ24195, "" }, + { "write_bq24195", cliWriteBQ24195, " " }, +#endif { "help", cliHelp, "[]" }, { NULL, NULL, NULL } /* sentinel */ }; diff --git a/radio/src/cli.h b/radio/src/cli.h index 83836eeef..5a57f7755 100644 --- a/radio/src/cli.h +++ b/radio/src/cli.h @@ -50,5 +50,7 @@ extern TaskStack cliStack; #endif void cliStart(); +void cliStackPaint(); +uint32_t cliStackFree(); #endif // _CLI_H_ diff --git a/radio/src/eeprom_raw.cpp b/radio/src/eeprom_raw.cpp index 1b801f0a7..cbb792218 100644 --- a/radio/src/eeprom_raw.cpp +++ b/radio/src/eeprom_raw.cpp @@ -69,15 +69,15 @@ PACK(struct EepromFileHeader uint16_t size; }); -EepromHeader eepromHeader; -EepromWriteState eepromWriteState = EEPROM_IDLE; +EepromHeader eepromHeader __DMA; +volatile EepromWriteState eepromWriteState = EEPROM_IDLE; uint8_t eepromWriteZoneIndex = FIRST_FILE_AVAILABLE; uint8_t eepromWriteFileIndex; uint16_t eepromWriteSize; uint8_t * eepromWriteSourceAddr; uint32_t eepromWriteDestinationAddr; uint16_t eepromFatAddr = 0; -uint8_t eepromWriteBuffer[EEPROM_BUFFER_SIZE]; +uint8_t eepromWriteBuffer[EEPROM_BUFFER_SIZE] __DMA; void eepromWaitSpiComplete() { @@ -424,6 +424,8 @@ void eepromFormat() void eeErase(bool warn) { + TRACE("eeErase()"); + generalDefault(); modelDefault(0); @@ -442,6 +444,10 @@ void eeErase(bool warn) void eepromWriteWait(EepromWriteState state/* = EEPROM_IDLE*/) { while (eepromWriteState != state) { +#if defined(CPUSTM32) + // Waits a little bit for CS transitions + CoTickDelay(1/*2ms*/); +#endif eepromWriteProcess(); #ifdef SIMU sleep(5/*ms*/); diff --git a/radio/src/eeprom_raw.h b/radio/src/eeprom_raw.h index 8a73d74eb..28223337c 100644 --- a/radio/src/eeprom_raw.h +++ b/radio/src/eeprom_raw.h @@ -75,7 +75,7 @@ enum EepromWriteState { EEPROM_END_WRITE }; -extern EepromWriteState eepromWriteState; +extern volatile EepromWriteState eepromWriteState; inline bool eepromIsWriting() { return (eepromWriteState != EEPROM_IDLE); diff --git a/radio/src/eeprom_rlc.cpp b/radio/src/eeprom_rlc.cpp index f7271f4bb..bc7b6d897 100644 --- a/radio/src/eeprom_rlc.cpp +++ b/radio/src/eeprom_rlc.cpp @@ -933,7 +933,7 @@ void eeLoadModelName(uint8_t id, char *name) bool eeModelExists(uint8_t id) { - return EFile::exists(FILE_MODEL(id)); + return EFile::exists(FILE_MODEL(id)); } // TODO Now the 2 functions in eeprom_rlc.cpp and eeprom_raw.cpp are really close, should be merged. diff --git a/radio/src/fifo.h b/radio/src/fifo.h index 18a1d478a..312877bda 100644 --- a/radio/src/fifo.h +++ b/radio/src/fifo.h @@ -47,6 +47,11 @@ class Fifo { } + void clear() + { + widx = ridx = 0; + } + void push(uint8_t byte) { uint32_t next = (widx+1) & (N-1); if (next != ridx) { diff --git a/radio/src/fonts.h b/radio/src/fonts.h index bb7bd0b18..6bba1021a 100644 --- a/radio/src/fonts.h +++ b/radio/src/fonts.h @@ -37,6 +37,13 @@ #ifndef fonts_h #define fonts_h +#if defined(COLORLCD) + +extern const uint16_t *fontspecsTable[16]; +extern const pm_uchar *fontsTable[16]; + +#else + extern const pm_uchar font_5x7[]; extern const pm_uchar font_10x14[]; @@ -56,3 +63,5 @@ extern const pm_uchar font_4x6_extra[]; #endif #endif + +#endif diff --git a/radio/src/functions.cpp b/radio/src/functions.cpp index 99516aef6..c75648b2b 100644 --- a/radio/src/functions.cpp +++ b/radio/src/functions.cpp @@ -324,7 +324,7 @@ void evalFunctions() if (!isFunctionActive(FUNCTION_INSTANT_TRIM)) { #if defined(GUI) if (g_menuStack[0] == menuMainView -#if defined(FRSKY) +#if defined(FRSKY) && !defined(PCBFLAMENCO) && !defined(PCBHORUS) || g_menuStack[0] == menuTelemetryFrsky #endif #if defined(PCBTARANIS) diff --git a/radio/src/gui/Horus/fonts.cpp b/radio/src/gui/Horus/fonts.cpp new file mode 100644 index 000000000..2854108b8 --- /dev/null +++ b/radio/src/gui/Horus/fonts.cpp @@ -0,0 +1,88 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +const uint16_t font_tinsize_specs[] PROGMEM = +#include "fonts/font_tinsize.specs" +; + +const pm_uchar font_tinsize[] PROGMEM = { +#include "fonts/font_tinsize.lbm" +}; + +const uint16_t font_smlsize_specs[] PROGMEM = +#include "fonts/font_smlsize.specs" +; + +const pm_uchar font_smlsize[] PROGMEM = { +#include "fonts/font_smlsize.lbm" +}; + +const uint16_t font_stdsize_specs[] PROGMEM = +#include "fonts/font_stdsize.specs" +; + +const pm_uchar font_stdsize[] PROGMEM = { +#include "fonts/font_stdsize.lbm" +}; + +const uint16_t font_midsize_specs[] PROGMEM = +#include "fonts/font_midsize.specs" +; + +const pm_uchar font_midsize[] PROGMEM = { +#include "fonts/font_midsize.lbm" +}; + +const uint16_t font_dblsize_specs[] PROGMEM = +#include "fonts/font_dblsize.specs" +; + +const pm_uchar font_dblsize[] PROGMEM = { +#include "fonts/font_dblsize.lbm" +}; + +const uint16_t font_xxlsize_specs[] PROGMEM = +#include "fonts/font_xxlsize.specs" +; + +const pm_uchar font_xxlsize[] PROGMEM = { +#include "fonts/font_xxlsize.lbm" +}; + +const uint16_t *fontspecsTable[16] = { font_stdsize_specs, font_tinsize_specs, font_smlsize_specs, font_midsize_specs, font_dblsize_specs, font_xxlsize_specs }; +const pm_uchar *fontsTable[16] = { font_stdsize, font_tinsize, font_smlsize, font_midsize, font_dblsize, font_xxlsize }; diff --git a/radio/src/gui/Horus/gui.h b/radio/src/gui/Horus/gui.h new file mode 100644 index 000000000..3e94f521a --- /dev/null +++ b/radio/src/gui/Horus/gui.h @@ -0,0 +1,70 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * 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 "lcd.h" +#include "menus.h" + +#define MENU_HEADER_HEIGHT 45 +#define MENU_TITLE_TOP 48 +#define MENU_TITLE_HEIGHT 21 +#define MENU_BODY_TOP 70 +#define MENU_CONTENT_TOP 72 +#define MENU_BODY_HEIGHT 182 +#define MENU_FOOTER_TOP 251 +#define MENU_FOOTER_HEIGHT 21 + +#define MENU_TITLE_LEFT 6 + +#define DEFAULT_SCROLLBAR_X LCD_W-10 +#define DEFAULT_SCROLLBAR_Y MENU_CONTENT_TOP +#define DEFAULT_SCROLLBAR_H (MENU_FOOTER_TOP - DEFAULT_SCROLLBAR_Y - 6) + +#define NUM_BODY_LINES 9 +#define FH 20 + +#define INVERT_HORZ_MARGIN 3 +#define INVERT_VERT_MARGIN 1 +#define INVERT_LINE_HEIGHT 18 + +void displaySplash(); +void displayScreenIndex(uint8_t index, uint8_t count); +void displayScrollbar(coord_t x, coord_t y, coord_t h, uint16_t offset, uint16_t count, uint8_t visible); +void drawHeader(int index); +void drawFooter(); +#define drawStatusLine(...) +void displayProgressBar(const char *label); +void updateProgressBar(int num, int den); + diff --git a/radio/src/gui/Horus/helpers.cpp b/radio/src/gui/Horus/helpers.cpp new file mode 100644 index 000000000..30eb04045 --- /dev/null +++ b/radio/src/gui/Horus/helpers.cpp @@ -0,0 +1,341 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +uint8_t switchToMix(uint8_t source) +{ + #warning en double ! + return 0; +} + +int circularIncDec(int current, int incr, int min, int max, IsValueAvailable isValueAvailable) +{ + do { + current += incr; + if (current < min) + current = max; + else if (current > max) + current = min; + if (!isValueAvailable || isValueAvailable(current)) + return current; + } while(1); + return 0; +} + +bool isInputAvailable(int input) +{ + for (int i=0; ichn == input) + return true; + } + return false; +} + +bool isChannelUsed(int channel) +{ + for (int i=0; isrcRaw == 0) return false; + if (md->destCh == channel) return true; + if (md->destCh > channel) return false; + } + return false; +} + +int getChannelsUsed() +{ + int result = 0; + int lastCh = -1; + for (int i=0; isrcRaw == 0) return result; + if (md->destCh != lastCh) { ++result; lastCh = md->destCh; } + } + return result; +} + +bool isSourceAvailable(int source) +{ + if (source>=MIXSRC_FIRST_INPUT && source<=MIXSRC_LAST_INPUT) { + return isInputAvailable(source - MIXSRC_FIRST_INPUT); + } + +#if defined(LUA_MODEL_SCRIPTS) + if (source>=MIXSRC_FIRST_LUA && source<=MIXSRC_LAST_LUA) { + div_t qr = div(source-MIXSRC_FIRST_LUA, MAX_SCRIPT_OUTPUTS); + return (qr.rem=MIXSRC_FIRST_LUA && source<=MIXSRC_LAST_LUA) + return false; +#endif + + if (source>=MIXSRC_FIRST_POT && source<=MIXSRC_LAST_POT) { + return IS_POT_AVAILABLE(POT1+source-MIXSRC_FIRST_POT); + } + +#if !defined(HELI) + if (source>=MIXSRC_CYC1 && source<=MIXSRC_CYC3) + return false; +#endif + + if (source>=MIXSRC_CH1 && source<=MIXSRC_LAST_CH) { + return isChannelUsed(source-MIXSRC_CH1); + } + + if (source>=MIXSRC_FIRST_LOGICAL_SWITCH && source<=MIXSRC_LAST_LOGICAL_SWITCH) { + LogicalSwitchData * cs = lswAddress(source-MIXSRC_FIRST_LOGICAL_SWITCH); + return (cs->func != LS_FUNC_NONE); + } + +#if !defined(GVARS) + if (source>=MIXSRC_GVAR1 && source<=MIXSRC_LAST_GVAR) + return false; +#endif + + if (source>=MIXSRC_RESERVE1 && source<=MIXSRC_RESERVE5) + return false; + + if (source>=MIXSRC_FIRST_TELEM && source<=MIXSRC_LAST_TELEM) { + div_t qr = div(source-MIXSRC_FIRST_TELEM, 3); + if (qr.rem == 0) + return isTelemetryFieldAvailable(qr.quot); + else + return isTelemetryFieldComparisonAvailable(qr.quot); + } + + return true; +} + +bool isSourceAvailableInCustomSwitches(int source) +{ + bool result = isSourceAvailable(source); + +#if defined(FRSKY) + if (result && source>=MIXSRC_FIRST_TELEM && source<=MIXSRC_LAST_TELEM) { + div_t qr = div(source-MIXSRC_FIRST_TELEM, 3); + result = isTelemetryFieldComparisonAvailable(qr.quot); + } +#endif + + return result; +} + +bool isInputSourceAvailable(int source) +{ + if (source>=MIXSRC_Rud && source<=MIXSRC_MAX) + return true; + + if (source>=MIXSRC_Rud && source<=MIXSRC_MAX) + return true; + + if (source>=MIXSRC_TrimRud && source=MIXSRC_FIRST_CH && source<=MIXSRC_LAST_CH) + return true; + + if (source>=MIXSRC_FIRST_TRAINER && source<=MIXSRC_LAST_TRAINER) + return true; + + if (source>=MIXSRC_FIRST_TELEM && source<=MIXSRC_LAST_TELEM) + return isTelemetryFieldAvailable(source-MIXSRC_FIRST_TELEM); + + return false; +} + +enum SwitchContext +{ + LogicalSwitchesContext, + ModelCustomFunctionsContext, + GeneralCustomFunctionsContext, + TimersContext, + MixesContext +}; + +bool isSwitchAvailable(int swtch, SwitchContext context) +{ + uint32_t index = switchInfo(abs(swtch)).quot; + + if (swtch < 0) { + if (!IS_3POS(index)) + return false; + if (swtch == -SWSRC_ON || swtch == -SWSRC_ONE) { + return false; + } + swtch = -swtch; + } + + if (swtch <= SWSRC_FIRST_SWITCH) { + return true; + } + + if (swtch >= SWSRC_FIRST_LOGICAL_SWITCH && swtch <= SWSRC_LAST_LOGICAL_SWITCH) { + if (context == GeneralCustomFunctionsContext) { + return false; + } + else if (context != LogicalSwitchesContext) { + LogicalSwitchData * cs = lswAddress(swtch-SWSRC_FIRST_LOGICAL_SWITCH); + return (cs->func != LS_FUNC_NONE); + } + } + + if (context != ModelCustomFunctionsContext && context != GeneralCustomFunctionsContext && (swtch == SWSRC_ON || swtch == SWSRC_ONE)) { + return false; + } + + if (swtch >= SWSRC_FIRST_FLIGHT_MODE && swtch <= SWSRC_LAST_FLIGHT_MODE) { + if (context == MixesContext || context == GeneralCustomFunctionsContext) { + return false; + } + else { + swtch -= SWSRC_FIRST_FLIGHT_MODE; + if (swtch == 0) { + return true; + } + FlightModeData * fm = flightModeAddress(swtch); + return (fm->swtch != SWSRC_NONE); + } + } + + return true; +} + +bool isSwitchAvailableInLogicalSwitches(int swtch) +{ + return isSwitchAvailable(swtch, LogicalSwitchesContext); +} + +bool isSwitchAvailableInCustomFunctions(int swtch) +{ + if (g_menuStack[g_menuStackPtr] == menuModelCustomFunctions) + return isSwitchAvailable(swtch, ModelCustomFunctionsContext); + else + return isSwitchAvailable(swtch, GeneralCustomFunctionsContext); +} + +bool isSwitchAvailableInMixes(int swtch) +{ + return isSwitchAvailable(swtch, MixesContext); +} + +bool isSwitchAvailableInTimers(int swtch) +{ + if (swtch >= 0) { + if (swtch < TMRMODE_COUNT) + return true; + else + swtch -= TMRMODE_COUNT-1; + } + else { + if (swtch > -TMRMODE_COUNT) + return false; + else + swtch += TMRMODE_COUNT-1; + } + + return isSwitchAvailable(swtch, TimersContext); +} + +bool isLogicalSwitchFunctionAvailable(int function) +{ + return function != LS_FUNC_RANGE; +} + +bool isAssignableFunctionAvailable(int function) +{ +#if defined(OVERRIDE_CHANNEL_FUNCTION) || defined(GVARS) + bool modelFunctions = (g_menuStack[g_menuStackPtr] == menuModelCustomFunctions); +#endif + + switch (function) { + case FUNC_OVERRIDE_CHANNEL: +#if defined(OVERRIDE_CHANNEL_FUNCTION) + return modelFunctions; +#else + return false; +#endif + case FUNC_ADJUST_GVAR: +#if defined(GVARS) + return modelFunctions; +#else + return false; +#endif +#if !defined(HAPTIC) + case FUNC_HAPTIC: +#endif +#if !defined(DANGEROUS_MODULE_FUNCTIONS) + case FUNC_RANGECHECK: + case FUNC_BIND: +// case FUNC_MODULE_OFF: +#endif +#if !defined(LUA) + case FUNC_PLAY_SCRIPT: +#endif + case FUNC_RESERVE4: + case FUNC_RESERVE5: + return false; + + default: + return true; + } +} + +bool isModuleAvailable(int module) +{ + if (module == MODULE_TYPE_NONE) + return false; + +#if !defined(PXX) + if (module == MODULE_TYPE_XJT) + return false; +#endif + + return true; +} + + +bool modelHasNotes() +{ + char filename[sizeof(MODELS_PATH)+1+sizeof(g_model.header.name)+sizeof(TEXT_EXT)] = MODELS_PATH "/"; + char *buf = strcat_modelname(&filename[sizeof(MODELS_PATH)], g_eeGeneral.currModel); + strcpy(buf, TEXT_EXT); + return isFileAvailable(filename); +} diff --git a/radio/src/gui/Horus/lcd.cpp b/radio/src/gui/Horus/lcd.cpp new file mode 100644 index 000000000..c65c059a6 --- /dev/null +++ b/radio/src/gui/Horus/lcd.cpp @@ -0,0 +1,964 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +#if defined(SIMU) +display_t displayBuf[DISPLAY_BUF_SIZE]; +#endif + +uint16_t lcdColorTable[LCD_COLOR_COUNT]; + +#define PIXEL_PTR(x, y) &displayBuf[(y)*LCD_W + (x)] + +void lcdColorsInit() +{ + lcdColorTable[TEXT_COLOR_INDEX] = BLACK; + lcdColorTable[TEXT_BGCOLOR_INDEX] = WHITE; + lcdColorTable[TEXT_INVERTED_COLOR_INDEX] = WHITE; + lcdColorTable[TEXT_INVERTED_BGCOLOR_INDEX] = RED; + lcdColorTable[LINE_COLOR_INDEX] = RGB(88, 88, 90); + lcdColorTable[SCROLLBOX_COLOR_INDEX] = RED; + lcdColorTable[MENU_TITLE_BGCOLOR_INDEX] = DARKGREY; + lcdColorTable[MENU_TITLE_COLOR_INDEX] = WHITE; + lcdColorTable[HEADER_COLOR_INDEX] = DARKGREY; + lcdColorTable[ALARM_COLOR_INDEX] = RED; + lcdColorTable[WARNING_COLOR_INDEX] = YELLOW; + lcdColorTable[TEXT_DISABLE_COLOR_INDEX] = RGB(0x60, 0x60, 0x60); + lcdColorTable[CURVE_AXIS_COLOR_INDEX] = BLUE; + lcdColorTable[TITLE_BGCOLOR_INDEX] = RED; + lcdColorTable[HEADER_BGCOLOR_INDEX] = DARKRED; +} + +coord_t lcdLastPos; +coord_t lcdNextPos; + +#define FONT_CHARS_COUNT 103 + +char getMappedChar(unsigned char c) +{ + if (c == 0) + return 0; + else if (c < 0xC0) + return c - 0x20; + else + return c - 0xC0 + 96; +} + +int getFontPatternWidth(const uint16_t *spec, int index) +{ + return spec[index+1] - spec[index]; +} + +int getCharWidth(char c, const uint16_t *spec) +{ + return getFontPatternWidth(spec, getMappedChar(c)); +} + +void lcdDrawBitmapPattern(coord_t x, coord_t y, const uint8_t * img, LcdFlags flags, coord_t offset, coord_t width) +{ + coord_t w = *((uint16_t *)img); + coord_t height = *(((uint16_t *)img)+1); + + if (!width || width > w) { + width = w; + } + + if (x+width > LCD_W) { + width = LCD_W-x; + } + + display_t color = lcdColorTable[COLOR_IDX(flags)]; + + for (coord_t row=0; row> 8; + const pm_uchar * font = fontsTable[fontindex]; + const uint16_t * fontspecs = fontspecsTable[fontindex]; + lcdPutFontPattern(x, y, font, fontspecs, getMappedChar(c), flags); +} + +void lcd_putc(coord_t x, coord_t y, const unsigned char c) +{ + lcd_putcAtt(x, y, c, 0); +} + +uint8_t getStringInfo(const char *s) +{ + uint8_t result = 0; + for (int i=0; s[i]; i++) { + result += s[i]; + } + return result; +} + +int getFontHeight(LcdFlags flags) +{ + static const int heightTable[16] = { 12, 10, 11, 14, 18, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 }; + return heightTable[FONTSIZE(flags) >> 8]; +} + +int getTextWidth(const pm_char *s, int len, LcdFlags flags) +{ + const uint16_t *specs = fontspecsTable[FONTSIZE(flags) >> 8]; + int result = 0; + for (int i=0; (len==0 || i= 0x20) { + lcd_putcAtt(x, y, c, flags); + x = lcdNextPos; + } + else if (c == 0x1F) { // X-coord prefix + setx = true; + } + else if (c == 0x1E) { + x = orig_x; + y += height; + } + else if (c == 1) { + x += 1; + } + else { + x += 2*(c-1); + } + s++; + } + lcdLastPos = x; + lcdNextPos = x; +} + +void lcd_putsn(coord_t x, coord_t y, const pm_char * s, uint8_t len) +{ + lcd_putsnAtt(x, y, s, len, TEXT_COLOR); +} + +void lcd_putsAtt(coord_t x, coord_t y, const pm_char * s, LcdFlags flags) +{ + lcd_putsnAtt(x, y, s, 255, flags); +} + +void lcd_puts(coord_t x, coord_t y, const pm_char * s) +{ + lcd_putsAtt(x, y, s, 0); +} + +void lcd_putsLeft(coord_t y, const pm_char * s) +{ + lcd_puts(MENU_TITLE_LEFT, y, s); +} + +void lcd_putsCenter(coord_t y, const pm_char * s, LcdFlags attr) +{ + int x = (LCD_W - getTextWidth(s)) / 2; + lcd_putsAtt(x, y, s, attr); +} + +void lcd_putsiAtt(coord_t x, coord_t y, const pm_char * s,uint8_t idx, LcdFlags flags) +{ + uint8_t length; + length = pgm_read_byte(s++); + lcd_putsnAtt(x, y, s+length*idx, length, flags & ~ZCHAR); +} + +void lcd_outhex4(coord_t x, coord_t y, uint32_t val, LcdFlags flags) +{ + char s[5]; + for (int i=0; i<4; i++) { + char c = val & 0xf; + s[3-i] = c>9 ? c+'A'-10 : c+'0'; + val >>= 4; + } + s[4] = '\0'; + if (!(flags & LEFT)) + x -= getTextWidth(s); + else + flags -= LEFT; + lcd_putsAtt(x, y, s, flags); +} + +void lcd_outdez8(coord_t x, coord_t y, int8_t val) +{ + lcd_outdezAtt(x, y, val); +} + +void lcd_outdezAtt(coord_t x, coord_t y, lcdint_t val, LcdFlags flags, const char *suffix, const char *prefix) +{ + lcd_outdezNAtt(x, y, val, flags, 0, suffix, prefix); +} + +void lcd_outdezNAtt(coord_t x, coord_t y, lcdint_t val, LcdFlags flags, int len, const char *suffix, const char *prefix) +{ + char str[48+1]; // max=16 for the prefix, 16 chars for the number, 16 chars for the suffix + char *s = str+32; + *s = '\0'; + int idx = 0; + int mode = MODE(flags); + bool neg = false; + if (val < 0) { + val = -val; + neg = true; + } + do { + *--s = '0' + (val % 10); + ++idx; + val /= 10; + if (mode!=0 && idx==mode) { + mode = 0; + *--s = '.'; + if (val==0) + *--s = '0'; + } + } while (val!=0 || mode>0 || (mode==MODE(LEADING0) && idx>1; + int y = dxabs>>1; + int px = x1; + int py = y1; + + if (dxabs >= dyabs) { + /* the line is more horizontal than vertical */ + for (int i=0; i<=dxabs; i++) { + y += dyabs; + if (y>=dxabs) { + y -= dxabs; + py += sdy; + } + if ((1<<(px%8)) & pat) { + lcdDrawPoint(px, py, att); + } + px += sdx; + } + } + else { + /* the line is more vertical than horizontal */ + for (int i=0; i<=dyabs; i++) { + x += dxabs; + if (x >= dyabs) { + x -= dyabs; + px += sdx; + } + if ((1<<(py%8)) & pat) { + lcdDrawPoint(px, py, att); + } + py += sdy; + } + } +} +#endif + +void lcd_vline(coord_t x, scoord_t y, scoord_t h) +{ + lcd_vlineStip(x, y, h, SOLID); +} + +void lcd_rect(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t pat, LcdFlags att) +{ + if (att & ROUND) { + lcd_vlineStip(x, y+1, h-2, pat, att); + lcd_vlineStip(x+w-1, y+1, h-2, pat, att); + lcd_hlineStip(x+1, y+h-1, w-2, pat, att); + lcd_hlineStip(x+1, y, w-2, pat, att); + } + else { + lcd_vlineStip(x, y, h, pat, att); + lcd_vlineStip(x+w-1, y, h, pat, att); + lcd_hlineStip(x+1, y+h-1, w-2, pat, att); + lcd_hlineStip(x+1, y, w-2, pat, att); + } +} + +#if defined(SIMU) +void lcdDrawFilledRect(coord_t x, scoord_t y, coord_t w, coord_t h, LcdFlags att) +{ + for (scoord_t i=y; i> 1) + ((pat & 1) << 7); + } +} +#endif + +void putsRtcTime(coord_t x, coord_t y, LcdFlags att) +{ + putsTimer(x, y, getValue(MIXSRC_TX_TIME), att); +} + +void putsTimer(coord_t x, coord_t y, putstime_t tme, LcdFlags att) +{ + div_t qr; + + char str[10]; // "-00:00:00" + char *s = str; + + att &= ~LEFT; + + if (tme < 0) { + // TODO lcd_putcAtt(x - ((att & DBLSIZE) ? FW+2 : ((att & MIDSIZE) ? FW+0 : FWNUM)), y, '-', att); + tme = -tme; + *s++ = '-'; + } + + qr = div(tme, 60); + + if (att & TIMEHOUR) { + div_t qr2 = div(qr.quot, 60); + *s++ = '0' + (qr2.quot/10); + *s++ = '0' + (qr2.quot%10); + *s++ = ':'; + qr.quot = qr2.rem; + } + + *s++ = '0' + (qr.quot/10); + *s++ = '0' + (qr.quot%10); + *s++ = ':'; + *s++ = '0' + (qr.rem/10); + *s++ = '0' + (qr.rem%10); + *s = '\0'; + + lcd_putsAtt(x, y, str, att); +} + +// TODO to be optimized with putsValueWithUnit +void putsVolts(coord_t x, coord_t y, uint16_t volts, LcdFlags att) +{ + lcd_outdezAtt(x, y, (int16_t)volts, (~NO_UNIT) & (att | ((att&PREC2)==PREC2 ? 0 : PREC1)), (~att & NO_UNIT) ? "v" : NULL); +} + +void putsVBat(coord_t x, coord_t y, LcdFlags att) +{ + putsVolts(x, y, g_vbat100mV, att); +} + +void putsStrIdx(coord_t x, coord_t y, const pm_char *str, int idx, LcdFlags att, const char *prefix) +{ + // TODO quick & dirty, dangerous + char s[32]; + sprintf(s, "%s%s%d", prefix, str, abs(idx)); + lcd_putsAtt(x, y, s, att); +} + +void putsMixerSource(coord_t x, coord_t y, uint8_t idx, LcdFlags att) +{ + if (idx == 0) { + lcd_putsiAtt(x, y, STR_VSRCRAW, 0, att); // TODO macro + } + else if (idx <= MIXSRC_LAST_INPUT) { + char s[32] = "\307"; + if (ZEXIST(g_model.inputNames[idx-MIXSRC_FIRST_INPUT])) { + zchar2str(s+1, g_model.inputNames[idx-MIXSRC_FIRST_INPUT], LEN_INPUT_NAME); + s[1+LEN_INPUT_NAME] = '\0'; + } + else { + sprintf(s+1, "%02d", idx); + } + lcd_putsAtt(x, y, s, att); + } + + else if (idx <= MIXSRC_LAST_LUA) { + div_t qr = div(idx-MIXSRC_FIRST_LUA, MAX_SCRIPT_OUTPUTS); +#if defined(LUA_MODEL_SCRIPTS) + if (qr.quot < MAX_SCRIPTS && qr.rem < scriptInputsOutputs[qr.quot].outputsCount) { + lcd_putcAtt(x+2, y+1, '1'+qr.quot, TINSIZE); + lcdDrawFilledRect(x, y, 7, 7); + lcd_putsnAtt(x+8, y, scriptInputsOutputs[qr.quot].outputs[qr.rem].name, att & STREXPANDED ? 9 : 4, att); + } + else +#endif + { + putsStrIdx(x, y, "LUA", qr.quot+1, att); + lcd_putcAtt(x+20, y, 'a'+qr.rem, att); + } + } + + else if (idx < MIXSRC_LAST_POT) { + idx = idx-MIXSRC_Rud; + if (ZEXIST(g_eeGeneral.anaNames[idx])) + lcd_putsnAtt(x, y, g_eeGeneral.anaNames[idx], LEN_ANA_NAME, ZCHAR|att); + else + lcd_putsiAtt(x, y, STR_VSRCRAW, idx+1, att); + } + else if (idx >= MIXSRC_FIRST_SWITCH && idx < MIXSRC_FIRST_LOGICAL_SWITCH) { + idx = idx-MIXSRC_FIRST_SWITCH; + if (ZEXIST(g_eeGeneral.switchNames[idx])) + lcd_putsnAtt(x, y, g_eeGeneral.switchNames[idx], LEN_SWITCH_NAME, ZCHAR|att); + else + lcd_putsiAtt(x, y, STR_VSRCRAW, idx+MIXSRC_FIRST_SWITCH-MIXSRC_Rud+1, att); + } + else if (idx < MIXSRC_SW1) + lcd_putsiAtt(x, y, STR_VSRCRAW, idx-MIXSRC_Rud+1, att); + else if (idx <= MIXSRC_LAST_LOGICAL_SWITCH) + putsSwitches(x, y, SWSRC_SW1+idx-MIXSRC_SW1, att); + else if (idx < MIXSRC_CH1) + putsStrIdx(x, y, STR_PPM_TRAINER, idx-MIXSRC_FIRST_TRAINER+1, att); + else if (idx <= MIXSRC_LAST_CH) { + putsStrIdx(x, y, STR_CH, idx-MIXSRC_CH1+1, att); +#if 0 + if (ZEXIST(g_model.limitData[idx-MIXSRC_CH1].name) && (att & STREXPANDED)) { + lcd_putcAtt(lcdLastPos, y, ' ', att); + lcd_putsnAtt(lcdLastPos+3, y, g_model.limitData[idx-MIXSRC_CH1].name, LEN_CHANNEL_NAME, ZCHAR|att); + } +#endif + } + else if (idx <= MIXSRC_LAST_GVAR) + putsStrIdx(x, y, STR_GV, idx-MIXSRC_GVAR1+1, att); + else if (idx < MIXSRC_FIRST_TELEM) { + lcd_putsiAtt(x, y, STR_VSRCRAW, idx-MIXSRC_Rud+1-NUM_LOGICAL_SWITCH-NUM_TRAINER-NUM_CHNOUT-MAX_GVARS, att); + } + else { + idx -= MIXSRC_FIRST_TELEM; + div_t qr = div(idx, 3); + char s[sizeof(g_model.telemetrySensors[qr.quot].label)+2]; + int pos = zchar2str(s, g_model.telemetrySensors[qr.quot].label, sizeof(g_model.telemetrySensors[qr.quot].label)); + if (qr.rem) s[pos++] = (qr.rem==2 ? '+' : '-'); + s[pos] = '\0'; + lcd_putsAtt(x, y, s, att); + } +} + +void putsChnLetter(coord_t x, coord_t y, uint8_t idx, LcdFlags att) +{ + lcd_putsiAtt(x, y, STR_RETA123, idx-1, att); +} + +void putsModelName(coord_t x, coord_t y, char *name, uint8_t id, LcdFlags att) +{ + uint8_t len = sizeof(g_model.header.name); + while (len>0 && !name[len-1]) --len; + if (len==0) { + putsStrIdx(x, y, STR_MODEL, id+1, att|LEADING0); + } + else { + lcd_putsnAtt(x, y, name, sizeof(g_model.header.name), ZCHAR|att); + } +} + +void putsSwitches(coord_t x, coord_t y, int8_t idx, LcdFlags att) +{ + if (idx == SWSRC_OFF) + return lcd_putsiAtt(x, y, STR_OFFON, 0, att); + + char s[8]; + int pos = 0; + if (idx < 0) { + s[pos++] = '!'; + } + + int absidx = abs(idx); + +#if defined(FLIGHT_MODES) + if (absidx >= SWSRC_FIRST_FLIGHT_MODE) { + return putsStrIdx(x, y, STR_FP, absidx-SWSRC_FIRST_FLIGHT_MODE, att, idx < 0 ? "!" : ""); + } + else +#endif + if (absidx >= SWSRC_FIRST_SWITCH && absidx <= SWSRC_LAST_SWITCH) { + div_t swinfo = switchInfo(absidx); + if (ZEXIST(g_eeGeneral.switchNames[swinfo.quot])) { + pos = zchar2str(&s[pos], g_eeGeneral.switchNames[swinfo.quot], LEN_SWITCH_NAME); + s[pos++] = "\300-\301"[swinfo.rem]; + s[pos] = '\0'; + lcd_putsAtt(x, y, s, att); + return; + } + } + + strAppend(&s[pos], STR_VSWITCHES+1+absidx*STR_VSWITCHES[0], STR_VSWITCHES[0]); + lcd_putsAtt(x, y, s, att); +} + +#if defined(FLIGHT_MODES) +void putsFlightMode(coord_t x, coord_t y, int8_t idx, LcdFlags att) +{ + if (idx==0) { + lcd_putsiAtt(x, y, STR_MMMINV, 0, att); + } + else { + putsStrIdx(x, y, STR_FP, abs(idx)-1, att); + } +} +#endif + +void putsCurveRef(coord_t x, coord_t y, CurveRef &curve, LcdFlags att) +{ + if (curve.value != 0) { + switch (curve.type) { + case CURVE_REF_DIFF: + lcd_putsAtt(x, y, "D", att); + GVAR_MENU_ITEM(x+8, y, curve.value, -100, 100, LEFT|att, 0, 0); + break; + + case CURVE_REF_EXPO: + lcd_putsAtt(x, y, "E", att); + GVAR_MENU_ITEM(x+8, y, curve.value, -100, 100, LEFT|att, 0, 0); + break; + + case CURVE_REF_FUNC: + lcd_putsiAtt(x, y, STR_VCURVEFUNC, curve.value, att); + break; + + case CURVE_REF_CUSTOM: + putsCurve(x, y, curve.value, att); + break; + } + } +} + +void putsCurve(coord_t x, coord_t y, int8_t idx, LcdFlags att) +{ + if (idx == 0) { + return lcd_putsiAtt(x, y, STR_MMMINV, 0, att); + } + bool neg = false; + if (idx < 0) { + idx = -idx; + neg = true; + } + putsStrIdx(x, y, STR_CV, idx, att); + if (neg) { + if ((att&INVERS) && ((~att&BLINK) || BLINK_ON_PHASE)) + att &= ~(INVERS|BLINK); + lcd_putcAtt(x-3, y, '!', att); + } +} + +void putsTimerMode(coord_t x, coord_t y, int8_t mode, LcdFlags att) +{ + if (mode >= 0) { + if (mode < TMRMODE_COUNT) + return lcd_putsiAtt(x, y, STR_VTMRMODES, mode, att); + else + mode -= (TMRMODE_COUNT-1); + } + putsSwitches(x, y, mode, att); +} + +void putsTrimMode(coord_t x, coord_t y, uint8_t phase, uint8_t idx, LcdFlags att) +{ + trim_t v = getRawTrimValue(phase, idx); + unsigned int mode = v.mode; + unsigned int p = mode >> 1; + + if (mode == TRIM_MODE_NONE) { + lcd_putsAtt(x, y, "--", att); + } + else { + char s[2]; + s[0] = (mode % 2 == 0) ? ':' : '+'; + s[1] = '0'+p; + lcd_putsnAtt(x, y, s, 2, att); + } +} + +const pm_uint8_t bchunit_ar[] PROGMEM = { + UNIT_DIST, // Alt + UNIT_RAW, // Rpm + UNIT_PERCENT, // Fuel + UNIT_TEMPERATURE, // T1 + UNIT_TEMPERATURE, // T2 + UNIT_KTS, // Speed + UNIT_DIST, // Dist + UNIT_DIST, // GPS Alt +}; + +void putsValueWithUnit(coord_t x, coord_t y, lcdint_t val, uint8_t unit, LcdFlags att) +{ + // convertUnit(val, unit); + if (!(att & NO_UNIT) && unit != UNIT_RAW) { + char unitStr[8]; + strAppend(unitStr, STR_VTELEMUNIT+1+unit*STR_VTELEMUNIT[0], STR_VTELEMUNIT[0]); + lcd_outdezAtt(x, y, val, att, unitStr); + } + else { + lcd_outdezAtt(x, y, val, att); + } +} + +void displayDate(coord_t x, coord_t y, TelemetryItem & telemetryItem, LcdFlags att) +{ +} + +void displayGpsCoords(coord_t x, coord_t y, TelemetryItem & telemetryItem, LcdFlags att) +{ +} + +void putsTelemetryChannelValue(coord_t x, coord_t y, uint8_t channel, lcdint_t value, LcdFlags att) +{ + TelemetryItem & telemetryItem = telemetryItems[channel]; + TelemetrySensor & telemetrySensor = g_model.telemetrySensors[channel]; + + if (telemetrySensor.unit == UNIT_DATETIME) { + displayDate(x, y, telemetryItem, att); + } + else if (telemetrySensor.unit == UNIT_GPS) { + displayGpsCoords(x, y, telemetryItem, att); + } + else { + LcdFlags flags = att; + if (telemetrySensor.prec==2) + flags |= PREC2; + else if (telemetrySensor.prec==1) + flags |= PREC1; + putsValueWithUnit(x, y, value, telemetrySensor.unit == UNIT_CELLS ? UNIT_VOLTS : telemetrySensor.unit, flags); + } +} + +void putsChannelValue(coord_t x, coord_t y, source_t channel, lcdint_t value, LcdFlags att) +{ + if (channel >= MIXSRC_FIRST_TELEM) { + channel = (channel-MIXSRC_FIRST_TELEM) / 3; + putsTelemetryChannelValue(x, y, channel, value, att); + } + else if (channel >= MIXSRC_FIRST_TIMER || channel == MIXSRC_TX_TIME) { + putsTimer(x, y, value, att); + } + else if (channel == MIXSRC_TX_VOLTAGE) { + lcd_outdezAtt(x, y, value, att|PREC1); + } + else if (channel < MIXSRC_FIRST_CH) { + lcd_outdezAtt(x, y, calcRESXto100(value), att); + } + else if (channel <= MIXSRC_LAST_CH) { +#if defined(PPM_UNIT_PERCENT_PREC1) + lcd_outdezAtt(x, y, calcRESXto1000(value), att|PREC1); +#else + lcd_outdezAtt(x, y, calcRESXto100(value), att); +#endif + } + else { + lcd_outdezAtt(x, y, value, att); + } +} + +void putsChannel(coord_t x, coord_t y, source_t channel, LcdFlags att) +{ + getvalue_t value = getValue(channel); + putsChannelValue(x, y, channel, value, att); +} + +void lcdSetContrast() +{ + lcdSetRefVolt(g_eeGeneral.contrast); +} + +void lcdDrawPixel(display_t * p, display_t value) +{ + *p = value; +} + +void lcdDrawTransparentPixel(coord_t x, coord_t y, uint8_t opacity, uint16_t color) +{ + display_t * p = PIXEL_PTR(x, y); + lcdDrawTransparentPixel(p, opacity, color); +} + +void lcdDrawTransparentPixel(display_t * p, uint8_t opacity, uint16_t color) +{ + ASSERT_IN_DISPLAY(p); + + if (opacity != OPACITY_MAX) { + uint8_t bgWeight = OPACITY_MAX - opacity; + COLOR_SPLIT(color, red, green, blue); + COLOR_SPLIT(*p, bgRed, bgGreen, bgBlue); + uint16_t r = (bgRed * bgWeight + red * opacity) / OPACITY_MAX; + uint16_t g = (bgGreen * bgWeight + green * opacity) / OPACITY_MAX; + uint16_t b = (bgBlue * bgWeight + blue * opacity) / OPACITY_MAX; + lcdDrawPixel(p, COLOR_JOIN(r, g, b)); + } + else if (opacity != 0) { + lcdDrawPixel(p, color); + } +} + +void lcdDrawPoint(coord_t x, coord_t y, LcdFlags att) +{ + display_t * p = PIXEL_PTR(x, y); + display_t color = lcdColorTable[COLOR_IDX(att)]; + if (p < DISPLAY_END) { + *p = color; + } +} + +void lcd_hlineStip(coord_t x, coord_t y, coord_t w, uint8_t pat, LcdFlags att) +{ + if (y >= LCD_H) return; + if (x+w > LCD_W) { w = LCD_W - x; } + + display_t * p = PIXEL_PTR(x, y); + display_t color = lcdColorTable[COLOR_IDX(att)]; + + while (w--) { + if (pat&1) { + *p = color; + // lcd_mask(p, mask, 0); + pat = (pat >> 1) | 0x80; + } + else { + pat = pat >> 1; + } + p++; + } +} + +void lcd_vlineStip(coord_t x, coord_t y, coord_t h, uint8_t pat, LcdFlags att) +{ + if (x >= LCD_W) return; + if (y >= LCD_H) return; + if (h<0) { y+=h; h=-h; } + if (y<0) { h+=y; y=0; if (h<=0) return; } + if (y+h > LCD_H) { h = LCD_H - y; } + + if (pat==DOTTED && !(y%2)) { + pat = ~pat; + } + + while (h--) { + if (pat & 1) { + lcdDrawPoint(x, y, att); + pat = (pat >> 1) | 0x80; + } + else { + pat = pat >> 1; + } + y++; + } +} + +#if !defined(BOOT) +void lcdDrawBitmap(coord_t x, coord_t y, const uint16_t * img, coord_t offset, coord_t width) +{ + const uint16_t * q = img; + coord_t w = *q++; + coord_t height = *q++; + + if (!width || width > w) { + width = w; + } + + if (x+width > LCD_W) { + width = LCD_W-x; + } + + for (coord_t row=0; row + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _LCD_H_ +#define _LCD_H_ + +#define LCD_W 480 +#define LCD_H 272 + +#define BOX_WIDTH 61 +#define coord_t int +#define scoord_t int +#define CENTER +#define CENTER_OFS 0 +#define CONTRAST_MIN 0 +#define CONTRAST_MAX 45 + +#define lcdint_t int32_t +#define lcduint_t uint32_t + +#define LCD_LINES 17 // TODO change this constant which has no sense here, the header uses more than one line +#define LCD_COLS 30 + +#define BSS 0x00 +#define ERASE 0x00 +#define FORCE 0x00 +#define FIXEDWIDTH 0x00 +#define FILLWHITE 0x00 +#define BOLD 0x00 + +/* lcd common flags */ +#define BLINK 0x01 + +/* lcd text flags */ +#define INVERS 0x02 +#define LEFT 0x08 /* align left */ + +/* lcd puts flags */ +#define ZCHAR 0x04 + +/* lcd outdez flags */ +#define LEADING0 0x10 +#define PREC1 0x20 +#define PREC2 0x30 +#define MODE(flags) ((((int8_t)(flags) & 0x30) - 0x10) >> 4) + +/* rect, square flags */ +#define ROUND 0x02 + +/* telemetry flags */ +#define NO_UNIT 0x40 + +#define FONTSIZE(x) ((x) & 0x0700) +#define TINSIZE 0x0100 +#define SMLSIZE 0x0200 +#define MIDSIZE 0x0300 +#define DBLSIZE 0x0400 +#define XXLSIZE 0x0500 +#define ERASEBG 0x8000 +#define VERTICAL 0x0800 + +#define TIMEBLINK 0x1000 +#define TIMEHOUR 0x2000 +#define STREXPANDED 0x4000 + +// remove windows default definitions +#undef OPAQUE +#undef RGB + +#define TO5BITS(x) ((x) >> 3) +#define TO6BITS(x) ((x) >> 2) +#define RGB(r, g, b) ((TO5BITS(r) << 11) + (TO6BITS(g) << 5) + (TO5BITS(b) << 0)) +#define WHITE RGB(0xF0, 0xF0, 0xF0) +#define BLACK RGB(0, 0, 0) +#define YELLOW RGB(0xF0, 0xD0, 0x10) +#define BLUE RGB(0x30, 0xA0, 0xE0) +#define DARKGREY RGB(0x40, 0x40, 0x40) +#define RED RGB(229, 32, 30) +#define DARKRED RGB(160, 0, 6) + +#define LcdFlags uint32_t + +enum LcdColorIndex +{ + TEXT_COLOR_INDEX, + TEXT_BGCOLOR_INDEX, + TEXT_INVERTED_COLOR_INDEX, + TEXT_INVERTED_BGCOLOR_INDEX, + LINE_COLOR_INDEX, + SCROLLBOX_COLOR_INDEX, + MENU_TITLE_BGCOLOR_INDEX, + MENU_TITLE_COLOR_INDEX, + HEADER_COLOR_INDEX, + ALARM_COLOR_INDEX, + WARNING_COLOR_INDEX, + TEXT_DISABLE_COLOR_INDEX, + CURVE_AXIS_COLOR_INDEX, + HEADER_BGCOLOR_INDEX, + TITLE_BGCOLOR_INDEX, + LCD_COLOR_COUNT +}; + +extern uint16_t lcdColorTable[LCD_COLOR_COUNT]; +void lcdColorsInit(); + +#define OPACITY_MAX 0x0F + +#define COLOR(index) ((index) << 16) +#define TEXT_COLOR COLOR(TEXT_COLOR_INDEX) +#define TEXT_BGCOLOR COLOR(TEXT_BGCOLOR_INDEX) +#define TEXT_INVERTED_COLOR COLOR(TEXT_INVERTED_COLOR_INDEX) +#define TEXT_INVERTED_BGCOLOR COLOR(TEXT_INVERTED_BGCOLOR_INDEX) +#define LINE_COLOR COLOR(LINE_COLOR_INDEX) +#define SCROLLBOX_COLOR COLOR(SCROLLBOX_COLOR_INDEX) +#define HEADER_SEPARATOR_COLOR COLOR(HEADER_SEPARATOR_COLOR_INDEX) +#define MENU_TITLE_BGCOLOR COLOR(MENU_TITLE_BGCOLOR_INDEX) +#define MENU_TITLE_COLOR COLOR(MENU_TITLE_COLOR_INDEX) +#define HEADER_COLOR COLOR(HEADER_COLOR_INDEX) +#define ALARM_COLOR COLOR(ALARM_COLOR_INDEX) +#define WARNING_COLOR COLOR(WARNING_COLOR_INDEX) +#define TEXT_DISABLE_COLOR COLOR(TEXT_DISABLE_COLOR_INDEX) +#define CURVE_AXIS_COLOR COLOR(CURVE_AXIS_COLOR_INDEX) +#define TITLE_BGCOLOR COLOR(TITLE_BGCOLOR_INDEX) +#define HEADER_BGCOLOR COLOR(HEADER_BGCOLOR_INDEX) + +#define COLOR_IDX(att) uint8_t((att) >> 16) + +#define COLOR_SPLIT(color, r, g, b) \ + uint16_t r = ((color) & 0xF800) >> 11; \ + uint16_t g = ((color) & 0x07E0) >> 5; \ + uint16_t b = ((color) & 0x001F) + +#define COLOR_JOIN(r, g, b) \ + (((r) << 11) + ((g) << 5) + (b)) + +#define display_t uint16_t +#define DISPLAY_BUF_SIZE (LCD_W*LCD_H) + +#if defined(SIMU) +extern display_t displayBuf[DISPLAY_BUF_SIZE]; +#else +extern uint32_t CurrentFrameBuffer; +#define displayBuf ((uint16_t *)CurrentFrameBuffer) +#endif + +#define lcdRefreshWait() + +#define DISPLAY_BUFFER_SIZE (sizeof(display_t)*DISPLAY_BUF_SIZE) +#define DISPLAY_END (displayBuf + DISPLAY_BUF_SIZE) +#define ASSERT_IN_DISPLAY(p) assert((p) >= displayBuf && (p) < DISPLAY_END) + +void lcdStartScreen(); +void lcd_putc(coord_t x, coord_t y, const unsigned char c); +void lcd_putcAtt(coord_t x, coord_t y, const unsigned char c, LcdFlags attr=TEXT_COLOR); +void lcd_putsAtt(coord_t x, coord_t y, const pm_char * s, LcdFlags attr=TEXT_COLOR); +void lcd_putsiAtt(coord_t x, coord_t y, const pm_char * s, uint8_t idx, LcdFlags attr=TEXT_COLOR); +void lcd_putsnAtt(coord_t x, coord_t y, const pm_char * s, unsigned char len, LcdFlags attr=TEXT_COLOR); +void lcd_puts(coord_t x, coord_t y, const pm_char * s); +void lcd_putsn(coord_t x, coord_t y, const pm_char * s, unsigned char len); +void lcd_putsLeft(coord_t y, const pm_char * s); +void lcd_putsCenter(coord_t y, const pm_char * s, LcdFlags attr=0); +void lcd_outhex4(coord_t x, coord_t y, uint32_t val, LcdFlags mode=0); +void lcd_outdezNAtt(coord_t x, coord_t y, lcdint_t val, LcdFlags flags, int len, const char *suffix=NULL, const char *prefix=NULL); +void lcd_outdezAtt(coord_t x, coord_t y, lcdint_t val, LcdFlags mode=0, const char *suffix=NULL, const char *prefix=NULL); +void lcd_outdez8(coord_t x, coord_t y, int8_t val); + +void putsStrIdx(coord_t x, coord_t y, const pm_char *str, int idx, LcdFlags att=0, const char *prefix=""); +void putsModelName(coord_t x, coord_t y, char *name, uint8_t id, LcdFlags att); +void putsSwitches(coord_t x, coord_t y, int8_t swtch, LcdFlags att=0); +void putsMixerSource(coord_t x, coord_t y, uint8_t idx, LcdFlags att=0); +void putsFlightMode(coord_t x, coord_t y, int8_t idx, LcdFlags att=0); +void putsCurveRef(coord_t x, coord_t y, CurveRef &curve, LcdFlags att=0); +void putsCurve(coord_t x, coord_t y, int8_t idx, LcdFlags att=0); +void putsTimerMode(coord_t x, coord_t y, int8_t mode, LcdFlags att=0); +void putsTrimMode(coord_t x, coord_t y, uint8_t phase, uint8_t idx, LcdFlags att); + +#define putsChn(x, y, idx, att) putsMixerSource(x, y, MIXSRC_CH1+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); +void putsVBat(coord_t x, coord_t y, LcdFlags att); + +void putsChannelValue(coord_t x, coord_t y, source_t channel, lcdint_t val, LcdFlags att=0); +void putsChannel(coord_t x, coord_t y, source_t channel, LcdFlags att=0); +void putsTelemetryChannelValue(coord_t x, coord_t y, uint8_t channel, lcdint_t val, LcdFlags att=0); + +#define putstime_t int32_t + +void putsRtcTime(coord_t x, coord_t y, LcdFlags att=0); +void putsTimer(coord_t x, coord_t y, putstime_t tme, LcdFlags att=0); + +#define SOLID 0xff +#define DOTTED 0x55 + +void lcdDrawTransparentPixel(coord_t x, coord_t y, uint8_t opacity, uint16_t color); +void lcdDrawTransparentPixel(display_t * p, uint8_t opacity, uint16_t color); +void lcdDrawPoint(coord_t x, coord_t y, LcdFlags att=0); +void lcd_mask(uint8_t *p, uint8_t mask, LcdFlags att=0); +void lcd_hline(coord_t x, coord_t y, coord_t w, LcdFlags att=0); +void lcd_hlineStip(coord_t x, coord_t y, coord_t w, uint8_t pat, LcdFlags att=0); +void lcd_vline(coord_t x, scoord_t y, scoord_t h); +void lcd_vlineStip(coord_t x, scoord_t y, scoord_t h, uint8_t pat, LcdFlags att=0); +void lcd_line(coord_t x1, coord_t y1, coord_t x2, coord_t y2, uint8_t pat=SOLID, LcdFlags att=0); + +#if !defined(SIMU) +inline void lcdDrawFilledRect(coord_t x, scoord_t y, coord_t w, coord_t h, LcdFlags att) +{ + lcdFillRectangle(x, y, w, h, lcdColorTable[COLOR_IDX(att)]); +} +#else +void lcdDrawFilledRect(coord_t x, scoord_t y, coord_t w, coord_t h, LcdFlags att); +#endif + +inline void lcdDrawHorizontalLine(coord_t x, scoord_t y, coord_t w, LcdFlags att) +{ + lcdDrawFilledRect(x, y, w, 1, att); +} + +inline void lcdDrawVerticalLine(coord_t x, scoord_t y, coord_t h, LcdFlags att) +{ + lcdDrawFilledRect(x, y, 1, h, att); +} + +inline void lcdDrawRect(coord_t x, scoord_t y, coord_t w, coord_t h, LcdFlags att) +{ + lcdDrawVerticalLine(x, y, h, att); + lcdDrawVerticalLine(x+w-1, y, h, att); + lcdDrawHorizontalLine(x, y, w, att); + lcdDrawHorizontalLine(x, y+h-1, w, att); +} + +void lcdDrawFilledRectWithAttributes(coord_t x, scoord_t y, coord_t w, coord_t h, uint8_t pat, LcdFlags att); +void drawBlackOverlay(); +void lcd_rect(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t pat=SOLID, LcdFlags att=0); + +inline void lcd_square(coord_t x, coord_t y, coord_t w, LcdFlags att=0) { lcd_rect(x, y, w, w, SOLID, att); } + +void lcdDrawTelemetryTopBar(); + +#define V_BAR(xx, yy, ll) \ + lcd_vline(xx-1,yy-ll,ll); \ + lcd_vline(xx ,yy-ll,ll); \ + lcd_vline(xx+1,yy-ll,ll); + +void lcd_img(coord_t x, coord_t y, const pm_uchar * img, uint8_t idx, LcdFlags att=0); + +int getTextWidth(const pm_char *s, int len=0, LcdFlags flags=0); +void lcdDrawBitmap(coord_t x, coord_t y, const uint16_t * img, coord_t offset=0, coord_t width=0); +void lcdDrawBitmapPattern(coord_t x, coord_t y, const uint8_t * img, LcdFlags flags=0, coord_t offset=0, coord_t width=0); + +#define lcdSetRefVolt(...) +void lcdSetContrast(); +void lcdInit(); +#define lcdOff(...) + +void lcdRefresh(); +void lcdSendByte(uint8_t data); +void lcdSend(const uint8_t * data, uint32_t size); +void lcdSendString(const char * s); +uint32_t lcdReceive(uint8_t * data, uint32_t len); +void lcdClearRxBuffer(); + +const pm_char * bmpLoad(uint8_t *dest, const char *filename, const unsigned int width, const unsigned int height); + +#if defined(BOOT) + #define BLINK_ON_PHASE (0) +#else + #define BLINK_ON_PHASE (g_blinkTmr10ms & (1<<6)) +#endif + +#ifdef SIMU + extern bool lcd_refresh; + extern display_t lcd_buf[DISPLAY_BUF_SIZE]; +#endif + +char *strAppend(char * dest, const char * source, int len=0); +char *strSetCursor(char *dest, int position); +char *strAppendDate(char * str, bool time=false); +char *strAppendFilename(char * dest, const char * filename, const int size); + +#define BITMAP_IDX_SPLASH 0x00 +#define BITMAP_IDX_ALERT 0x01 +#define BITMAP_IDX_WARNING 0x02 +#define BITMAP_IDX_MESSAGE 0x03 +#define BITMAP_IDX_USB 0x04 +#define BITMAP_IDX_STICKS_FIRST 0x05 // 4 bitmaps +#define BITMAP_IDX_BATTERY_FIRST 0x09 // 5 bitmaps +#define BITMAP_IDX_RSSI_FIRST 0x0E // 6 bitmaps +#define BITMAP_IDX_CHECKBOX_FIRST 0x14 // 4 bitmaps +#define BITMAP_IDX_MODEL_FIRST 0x80 + +#endif // _LCD_H_ diff --git a/radio/src/gui/Horus/menu_general.cpp b/radio/src/gui/Horus/menu_general.cpp new file mode 100644 index 000000000..ac98ffe5c --- /dev/null +++ b/radio/src/gui/Horus/menu_general.cpp @@ -0,0 +1,96 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +extern LP_CONST LanguagePack czLanguagePack; +extern LP_CONST LanguagePack enLanguagePack; +extern LP_CONST LanguagePack esLanguagePack; +extern LP_CONST LanguagePack frLanguagePack; +extern LP_CONST LanguagePack deLanguagePack; +extern LP_CONST LanguagePack itLanguagePack; +extern LP_CONST LanguagePack plLanguagePack; +extern LP_CONST LanguagePack ptLanguagePack; +extern LP_CONST LanguagePack skLanguagePack; +extern LP_CONST LanguagePack seLanguagePack; +extern LP_CONST LanguagePack huLanguagePack; + +const LanguagePack * LP_CONST languagePacks[] = { + // alphabetical order + &czLanguagePack, + &deLanguagePack, + &enLanguagePack, + &esLanguagePack, + &frLanguagePack, + &huLanguagePack, + &itLanguagePack, + &plLanguagePack, + &ptLanguagePack, + &seLanguagePack, + &skLanguagePack, + NULL +}; + +void menuGeneralSetup(evt_t event); +void menuGeneralSdManager(evt_t event); +void menuGeneralCustomFunctions(evt_t event); +void menuGeneralTrainer(evt_t event); +void menuGeneralVersion(evt_t event); +void menuGeneralCalib(evt_t event); + +enum EnumTabDiag { + e_Setup, + e_Sd, + e_GeneralCustomFunctions, + e_Trainer, + e_Calib, + e_Vers, +}; + +const MenuFuncP_PROGMEM menuTabGeneral[] PROGMEM = { + menuGeneralSetup, + CASE_SDCARD(menuGeneralSdManager) + CASE_CPUARM(menuGeneralCustomFunctions) + menuGeneralTrainer, + menuGeneralCalib, + menuGeneralVersion, +}; + +void menuGeneralCustomFunctions(evt_t event) +{ + MENU(STR_MENUGLOBALFUNCS, menuTabGeneral, e_GeneralCustomFunctions, NUM_CFN, DEFAULT_SCROLLBAR_X, { NAVIGATION_LINE_BY_LINE|4/*repeated*/ }); + return menuCustomFunctions(event, g_eeGeneral.customFn, globalFunctionsContext); +} diff --git a/radio/src/gui/Horus/menu_general_calib.cpp b/radio/src/gui/Horus/menu_general_calib.cpp new file mode 100644 index 000000000..0b491d187 --- /dev/null +++ b/radio/src/gui/Horus/menu_general_calib.cpp @@ -0,0 +1,216 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +#define XPOT_DELTA 10 +#define XPOT_DELAY 10 /* cycles */ + +void menuCommonCalib(evt_t event) +{ + for (uint8_t i=0; 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 0 + uint8_t idx = i - POT1; + int count = reusableBuffer.calib.xpotsCalib[idx].stepsCount; + if (IS_POT_MULTIPOS(i) && count <= XPOTS_MULTIPOS_COUNT) { + 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= 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 + } + } + + calibrationState = reusableBuffer.calib.state; // make sure we don't scroll while calibrating + + switch (event) + { + case EVT_ENTRY: + reusableBuffer.calib.state = 0; + break; + + case EVT_KEY_BREAK(KEY_ENTER): + reusableBuffer.calib.state++; + break; + } + + switch (reusableBuffer.calib.state) { + case 0: + // START CALIBRATION + if (!READ_ONLY()) { + lcd_putsCenter(MENU_HEADER_HEIGHT+FH, STR_MENUTOSTART); + } + break; + + case 1: + // SET MIDPOINT + lcd_putsCenter(MENU_HEADER_HEIGHT+FH, STR_SETMIDPOINT, INVERS); + lcd_putsCenter(MENU_HEADER_HEIGHT+2*FH, STR_MENUWHENDONE); + + for (int i=0; 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 3: +#if 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; jcount = count - 1; + for (int j=0; jcount; j++) { + calib->steps[j] = (reusableBuffer.calib.xpotsCalib[idx].steps[j+1] + reusableBuffer.calib.xpotsCalib[idx].steps[j]) >> 5; + } + } + else { + g_eeGeneral.potsType &= ~(0x03<<(2*idx)); + } + } + } +#endif + g_eeGeneral.chkSum = evalChkSum(); + eeDirty(EE_GENERAL); + reusableBuffer.calib.state = 4; + break; + + default: + reusableBuffer.calib.state = 0; + break; + } + + doMainScreenGraphics(); + drawPotsBars(); + +#if 0 + for (int i=POT1; i<=POT_LAST; i++) { + uint8_t steps = 0; + if (reusableBuffer.calib.state == 2) { + 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) { + lcd_outdezAtt(LCD_W/2-2+(i-POT1)*5, LCD_H-6, steps, TINSIZE); + } + } +#endif +} + +void menuGeneralCalib(evt_t event) +{ + SIMPLE_MENU(STR_MENUCALIBRATION, menuTabGeneral, e_Calib, 0, DEFAULT_SCROLLBAR_X); + + if (menuEvent) { + calibrationState = 0; + } + + menuCommonCalib(READ_ONLY() ? 0 : event); +} + +void menuFirstCalib(evt_t event) +{ + if (event == EVT_KEY_BREAK(KEY_EXIT) || reusableBuffer.calib.state == 4) { + calibrationState = 0; + chainMenu(menuMainView); + } + else { + drawMenuTemplate(STR_MENUCALIBRATION, event); + menuCommonCalib(event); + } +} diff --git a/radio/src/gui/Horus/menu_general_sdmanager.cpp b/radio/src/gui/Horus/menu_general_sdmanager.cpp new file mode 100644 index 000000000..24890cf56 --- /dev/null +++ b/radio/src/gui/Horus/menu_general_sdmanager.cpp @@ -0,0 +1,358 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +#define REFRESH_FILES() reusableBuffer.sdmanager.offset = 65535 + +void menuGeneralSdManagerInfo(evt_t event) +{ + SIMPLE_SUBMENU(STR_SD_INFO_TITLE, 1, DEFAULT_SCROLLBAR_X); + + lcd_putsLeft(2*FH, STR_SD_TYPE); + lcd_puts(100, 2*FH, SD_IS_HC() ? STR_SDHC_CARD : STR_SD_CARD); + + lcd_putsLeft(3*FH, STR_SD_SIZE); + lcd_outdezAtt(100, 3*FH, sdGetSize(), LEFT, "M"); + + lcd_putsLeft(4*FH, STR_SD_SECTORS); +#if defined(SD_GET_FREE_BLOCKNR) + lcd_outdezAtt(100, 4*FH, SD_GET_FREE_BLOCKNR()/1000, LEFT, "/"); + lcd_outdezAtt(150, 4*FH, sdGetNoSectors()/1000, LEFT); +#else + lcd_outdezAtt(100, 4*FH, sdGetNoSectors()/1000, LEFT, "k"); +#endif + + lcd_putsLeft(5*FH, STR_SD_SPEED); + lcd_outdezAtt(100, 5*FH, SD_GET_SPEED()/1000, LEFT, "kb/s"); +} + +inline bool isFilenameGreater(bool isfile, const char * fn, const char * line) +{ + return (isfile && !line[SD_SCREEN_FILE_LENGTH+1]) || (isfile==(bool)line[SD_SCREEN_FILE_LENGTH+1] && strcasecmp(fn, line) > 0); +} + +inline bool isFilenameLower(bool isfile, const char * fn, const char * line) +{ + return (!isfile && line[SD_SCREEN_FILE_LENGTH+1]) || (isfile==(bool)line[SD_SCREEN_FILE_LENGTH+1] && strcasecmp(fn, line) < 0); +} + +void onSdManagerMenu(const char *result) +{ + TCHAR lfn[_MAX_LFN+1]; + + // TODO possible buffer overflows here! + + uint8_t index = m_posVert-s_pgOfs; + char *line = reusableBuffer.sdmanager.lines[index]; + + if (result == STR_SD_INFO) { + pushMenu(menuGeneralSdManagerInfo); + } + else if (result == STR_SD_FORMAT) { + POPUP_CONFIRMATION(STR_CONFIRM_FORMAT); + } + else if (result == STR_COPY_FILE) { + clipboard.type = CLIPBOARD_TYPE_SD_FILE; + f_getcwd(clipboard.data.sd.directory, CLIPBOARD_PATH_LEN); + strncpy(clipboard.data.sd.filename, line, CLIPBOARD_PATH_LEN-1); + } + else if (result == STR_PASTE) { + f_getcwd(lfn, _MAX_LFN); + POPUP_WARNING(fileCopy(clipboard.data.sd.filename, clipboard.data.sd.directory, lfn)); + REFRESH_FILES(); + } + else if (result == STR_RENAME_FILE) { + char *ext = getFileExtension(line, SD_SCREEN_FILE_LENGTH+1); + if (ext) { + memcpy(reusableBuffer.sdmanager.originalName, line, sizeof(reusableBuffer.sdmanager.originalName)); + // write spaces to allow a longer filename + memset(ext, ' ', SD_SCREEN_FILE_LENGTH-LEN_FILE_EXTENSION-(ext-line)); + line[SD_SCREEN_FILE_LENGTH-LEN_FILE_EXTENSION] = '\0'; + s_editMode = EDIT_MODIFY_STRING; + editNameCursorPos = 0; + } + } + else if (result == STR_DELETE_FILE) { + f_getcwd(lfn, _MAX_LFN); + strcat(lfn, PSTR("/")); + strcat(lfn, line); + f_unlink(lfn); + REFRESH_FILES(); + if (m_posVert == reusableBuffer.sdmanager.count-1) + m_posVert--; + } + /* TODO else if (result == STR_LOAD_FILE) { + f_getcwd(lfn, _MAX_LFN); + strcat(lfn, "/"); + strcat(lfn, line); + POPUP_WARNING(eeLoadModelSD(lfn)); + } */ + else if (result == STR_PLAY_FILE) { + f_getcwd(lfn, _MAX_LFN); + strcat(lfn, "/"); + strcat(lfn, line); + audioQueue.stopAll(); + audioQueue.playFile(lfn, 0, ID_PLAY_FROM_SD_MANAGER); + } +#if 0 + else if (result == STR_ASSIGN_BITMAP) { + strAppendFilename(g_model.header.bitmap, line, sizeof(g_model.header.bitmap)); + memcpy(modelHeaders[g_eeGeneral.currModel].bitmap, g_model.header.bitmap, sizeof(g_model.header.bitmap)); + eeDirty(EE_MODEL); + } +#endif + else if (result == STR_VIEW_TEXT) { + f_getcwd(lfn, _MAX_LFN); + strcat(lfn, "/"); + strcat(lfn, line); + pushMenuTextView(lfn); + } +#if 0 + else if (result == STR_FLASH_BOOTLOADER) { + f_getcwd(lfn, _MAX_LFN); + strcat(lfn, "/"); + strcat(lfn, line); + flashBootloader(lfn); + } +#endif +#if defined(LUA) + else if (result == STR_EXECUTE_FILE) { + f_getcwd(lfn, _MAX_LFN); + strcat(lfn, "/"); + strcat(lfn, line); + luaExec(lfn); + } +#endif +} + +void menuGeneralSdManager(evt_t _event) +{ + FILINFO fno; + DIR dir; + char *fn; /* This function is assuming non-Unicode cfg. */ + TCHAR lfn[_MAX_LFN + 1]; + fno.lfname = lfn; + fno.lfsize = sizeof(lfn); + + if (s_warning_result) { + s_warning_result = 0; + displayPopup(STR_FORMATTING); + closeLogs(); + audioQueue.stopSD(); + if (f_mkfs(0, 1, 0) == FR_OK) { + f_chdir("/"); + REFRESH_FILES(); + } + else { + POPUP_WARNING(STR_SDCARD_ERROR); + } + } + + evt_t event = (EVT_KEY_MASK(_event) == KEY_ENTER ? 0 : _event); + SIMPLE_MENU(SD_IS_HC() ? STR_SDHC_CARD : STR_SD_CARD, menuTabGeneral, e_Sd, reusableBuffer.sdmanager.count, DEFAULT_SCROLLBAR_X); + + int index = m_posVert-s_pgOfs; + + switch(_event) { + case EVT_ENTRY: + f_chdir(ROOT_PATH); + REFRESH_FILES(); + break; + +#if 0 + case EVT_KEY_LONG(KEY_MENU): + if (!READ_ONLY() && s_editMode == 0) { + killEvents(_event); + MENU_ADD_ITEM(STR_SD_INFO); TODO: Implement + MENU_ADD_ITEM(STR_SD_FORMAT); + menuHandler = onSdManagerMenu; + } + break; +#endif + + case EVT_KEY_BREAK(KEY_EXIT): + REFRESH_FILES(); + break; + + case EVT_KEY_BREAK(KEY_ENTER): + if (s_editMode > 0) { + break; + } + else { + if (!reusableBuffer.sdmanager.lines[index][SD_SCREEN_FILE_LENGTH+1]) { + f_chdir(reusableBuffer.sdmanager.lines[index]); + s_pgOfs = 0; + m_posVert = 1; + index = 1; + REFRESH_FILES(); + killEvents(_event); + return; + } + } + // no break + + case EVT_KEY_LONG(KEY_ENTER): + killEvents(_event); + if (s_editMode == 0) { + char *line = reusableBuffer.sdmanager.lines[index]; + char *ext = getFileExtension(line, SD_SCREEN_FILE_LENGTH+1); + if (ext) { + if (!strcasecmp(ext, SOUNDS_EXT)) { + MENU_ADD_ITEM(STR_PLAY_FILE); + } + else if (!strcasecmp(ext, TEXT_EXT)) { + MENU_ADD_ITEM(STR_VIEW_TEXT); + } + else if (!strcasecmp(ext, FIRMWARE_EXT) && !READ_ONLY()) { + MENU_ADD_ITEM(STR_FLASH_BOOTLOADER); + } +#if defined(LUA) + else if (!strcasecmp(ext, SCRIPTS_EXT)) { + MENU_ADD_ITEM(STR_EXECUTE_FILE); + } +#endif + } + if (!READ_ONLY()) { + if (line[SD_SCREEN_FILE_LENGTH+1]) // it's a file + MENU_ADD_ITEM(STR_COPY_FILE); + if (clipboard.type == CLIPBOARD_TYPE_SD_FILE) + MENU_ADD_ITEM(STR_PASTE); + // MENU_ADD_ITEM(STR_RENAME_FILE); + MENU_ADD_ITEM(STR_DELETE_FILE); + } + } + menuHandler = onSdManagerMenu; + break; + } + + if (reusableBuffer.sdmanager.offset != s_pgOfs) { + if (s_pgOfs == 0) { + reusableBuffer.sdmanager.offset = 0; + memset(reusableBuffer.sdmanager.lines, 0, sizeof(reusableBuffer.sdmanager.lines)); + } + else if (s_pgOfs == reusableBuffer.sdmanager.count-NUM_BODY_LINES) { + reusableBuffer.sdmanager.offset = s_pgOfs; + memset(reusableBuffer.sdmanager.lines, 0, sizeof(reusableBuffer.sdmanager.lines)); + } + else if (s_pgOfs > reusableBuffer.sdmanager.offset) { + memmove(reusableBuffer.sdmanager.lines[0], reusableBuffer.sdmanager.lines[1], (NUM_BODY_LINES-1)*sizeof(reusableBuffer.sdmanager.lines[0])); + memset(reusableBuffer.sdmanager.lines[NUM_BODY_LINES-1], 0xff, SD_SCREEN_FILE_LENGTH); + reusableBuffer.sdmanager.lines[NUM_BODY_LINES-1][SD_SCREEN_FILE_LENGTH+1] = 1; + } + else { + memmove(reusableBuffer.sdmanager.lines[1], reusableBuffer.sdmanager.lines[0], (NUM_BODY_LINES-1)*sizeof(reusableBuffer.sdmanager.lines[0])); + memset(reusableBuffer.sdmanager.lines[0], 0, sizeof(reusableBuffer.sdmanager.lines[0])); + } + + reusableBuffer.sdmanager.count = 0; + + FRESULT res = f_opendir(&dir, "."); /* Open the directory */ + if (res == FR_OK) { + for (;;) { + res = f_readdir(&dir, &fno); /* Read a directory item */ + if (res != FR_OK || fno.fname[0] == 0) break; /* Break on error or end of dir */ + if (fno.fname[0] == '.' && fno.fname[1] == '\0') continue; /* Ignore dot entry */ +#if _USE_LFN + fn = *fno.lfname ? fno.lfname : fno.fname; +#else + fn = fno.fname; +#endif + if (strlen(fn) > SD_SCREEN_FILE_LENGTH) continue; + + reusableBuffer.sdmanager.count++; + + bool isfile = !(fno.fattrib & AM_DIR); + + if (s_pgOfs == 0) { + for (int i=0; i=0; i--) { + char *line = reusableBuffer.sdmanager.lines[i]; + if (line[0] == '\0' || isFilenameGreater(isfile, fn, line)) { + if (i > 0) memmove(reusableBuffer.sdmanager.lines[0], reusableBuffer.sdmanager.lines[1], sizeof(reusableBuffer.sdmanager.lines[0]) * i); + memset(line, 0, sizeof(reusableBuffer.sdmanager.lines[i])); + strcpy(line, fn); + line[SD_SCREEN_FILE_LENGTH+1] = isfile; + break; + } + } + } + else if (s_pgOfs > reusableBuffer.sdmanager.offset) { + if (isFilenameGreater(isfile, fn, reusableBuffer.sdmanager.lines[NUM_BODY_LINES-2]) && isFilenameLower(isfile, fn, reusableBuffer.sdmanager.lines[NUM_BODY_LINES-1])) { + memset(reusableBuffer.sdmanager.lines[NUM_BODY_LINES-1], 0, sizeof(reusableBuffer.sdmanager.lines[0])); + strcpy(reusableBuffer.sdmanager.lines[NUM_BODY_LINES-1], fn); + reusableBuffer.sdmanager.lines[NUM_BODY_LINES-1][SD_SCREEN_FILE_LENGTH+1] = isfile; + } + } + else { + if (isFilenameLower(isfile, fn, reusableBuffer.sdmanager.lines[1]) && isFilenameGreater(isfile, fn, reusableBuffer.sdmanager.lines[0])) { + memset(reusableBuffer.sdmanager.lines[0], 0, sizeof(reusableBuffer.sdmanager.lines[0])); + strcpy(reusableBuffer.sdmanager.lines[0], fn); + reusableBuffer.sdmanager.lines[0][SD_SCREEN_FILE_LENGTH+1] = isfile; + } + } + } + } + } + + reusableBuffer.sdmanager.offset = s_pgOfs; + + for (int i=0; i + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +#define RADIO_SETUP_2ND_COLUMN 220 + +#define SLIDER_5POS(y, value, label, event, attr) { \ + int8_t tmp = value; \ + displaySlider(RADIO_SETUP_2ND_COLUMN, y, 2+tmp, 4, attr); \ + value = selectMenuItem(RADIO_SETUP_2ND_COLUMN, y, label, NULL, tmp, -2, +2, attr, event); \ +} + +#if defined(SPLASH) && !defined(FSPLASH) + #define CASE_SPLASH_PARAM(x) x, +#else + #define CASE_SPLASH_PARAM(x) +#endif + +enum menuGeneralSetupItems { + CASE_RTCLOCK(ITEM_SETUP_DATE) + CASE_RTCLOCK(ITEM_SETUP_TIME) + // ITEM_SETUP_BATT_RANGE, + ITEM_SETUP_SOUND_LABEL, + ITEM_SETUP_BEEP_MODE, + ITEM_SETUP_SPEAKER_VOLUME, + ITEM_SETUP_BEEP_VOLUME, + ITEM_SETUP_BEEP_LENGTH, + ITEM_SETUP_SPEAKER_PITCH, + ITEM_SETUP_WAV_VOLUME, + ITEM_SETUP_BACKGROUND_VOLUME, + CASE_VARIO_CPUARM(ITEM_SETUP_VARIO_LABEL) + CASE_VARIO_CPUARM(ITEM_SETUP_VARIO_VOLUME) + CASE_VARIO_CPUARM(ITEM_SETUP_VARIO_PITCH) + CASE_VARIO_CPUARM(ITEM_SETUP_VARIO_RANGE) + CASE_VARIO_CPUARM(ITEM_SETUP_VARIO_REPEAT) + CASE_HAPTIC(ITEM_SETUP_HAPTIC_LABEL) + CASE_HAPTIC(ITEM_SETUP_HAPTIC_MODE) + CASE_HAPTIC(ITEM_SETUP_HAPTIC_LENGTH) + CASE_HAPTIC(ITEM_SETUP_HAPTIC_STRENGTH) + // ITEM_SETUP_CONTRAST, + ITEM_SETUP_ALARMS_LABEL, + ITEM_SETUP_BATTERY_WARNING, + ITEM_SETUP_INACTIVITY_ALARM, + // ITEM_SETUP_MEMORY_WARNING, + ITEM_SETUP_ALARM_WARNING, + // ITEM_SETUP_BACKLIGHT_LABEL, + // ITEM_SETUP_BACKLIGHT_MODE, + // ITEM_SETUP_BACKLIGHT_DELAY, + // ITEM_SETUP_BRIGHTNESS, + // ITEM_SETUP_FLASH_BEEP, + // CASE_SPLASH_PARAM(ITEM_SETUP_DISABLE_SPLASH) + CASE_GPS(ITEM_SETUP_TIMEZONE) + CASE_GPS(ITEM_SETUP_GPSFORMAT) + CASE_PXX(ITEM_SETUP_COUNTRYCODE) + ITEM_SETUP_LANGUAGE, + ITEM_SETUP_IMPERIAL, + // IF_FAI_CHOICE(ITEM_SETUP_FAI) + // CASE_MAVLINK(ITEM_MAVLINK_BAUD) + ITEM_SETUP_SWITCHES_DELAY, + ITEM_SETUP_RX_CHANNEL_ORD, + ITEM_SETUP_STICK_MODE_LABELS, + ITEM_SETUP_STICK_MODE, + ITEM_SETUP_MAX +}; + +void menuGeneralSetup(evt_t event) +{ +#if defined(RTCLOCK) + struct gtm t; + gettime(&t); + + if ((m_posVert==ITEM_SETUP_DATE || m_posVert==ITEM_SETUP_TIME) && + (s_editMode>0) && + (event==EVT_KEY_FIRST(KEY_ENTER) || event==EVT_KEY_FIRST(KEY_EXIT) || IS_ROTARY_BREAK(event) || IS_ROTARY_LONG(event))) { + // set the date and time into RTC chip + rtcSetTime(&t); + } +#endif + +#if defined(FAI_CHOICE) + if (s_warning_result) { + s_warning_result = 0; + g_eeGeneral.fai = true; + eeDirty(EE_GENERAL); + } +#endif + + MENU(STR_MENURADIOSETUP, menuTabGeneral, e_Setup, ITEM_SETUP_MAX, DEFAULT_SCROLLBAR_X, { 2|NAVIGATION_LINE_BY_LINE, 2|NAVIGATION_LINE_BY_LINE, LABEL(SOUND), 0, 0, 0, 0, 0, 0, 0, CASE_VARIO_CPUARM(LABEL(VARIO)) CASE_VARIO_CPUARM(0) CASE_VARIO_CPUARM(0) CASE_VARIO_CPUARM(0) CASE_VARIO_CPUARM(0) CASE_HAPTIC(LABEL(HAPTIC)) CASE_HAPTIC(0) CASE_HAPTIC(0) CASE_HAPTIC(0) LABEL(ALARMS), 0, 0, 0, CASE_GPS(0) CASE_GPS(0) CASE_PXX(0) 0, 0, CASE_MAVLINK(0) 0, 0, LABEL(TX_MODE), 0, 1/*to force edit mode*/ }); + + int sub = m_posVert; + + for (int i=0; i0) ? BLINK|INVERS : INVERS); + LcdFlags attr = (sub == k ? blink : 0); + + switch(k) { + case ITEM_SETUP_DATE: + { + lcd_putsLeft(y, STR_DATE); + LcdFlags flags = 0; + if (attr && m_posHorz < 0) { + flags |= INVERS; + lcdDrawFilledRect(RADIO_SETUP_2ND_COLUMN-INVERT_HORZ_MARGIN, y-INVERT_VERT_MARGIN, 85, INVERT_LINE_HEIGHT, TEXT_INVERTED_BGCOLOR); + } + lcd_putsAtt(RADIO_SETUP_2ND_COLUMN+28, y, "-", flags); + lcd_putsAtt(RADIO_SETUP_2ND_COLUMN+53, y, "-", flags); + for (uint8_t j=0; j<3; j++) { + uint8_t rowattr = (m_posHorz==j ? attr : 0); + switch (j) { + case 0: + lcd_outdezAtt(RADIO_SETUP_2ND_COLUMN, y, t.tm_year+1900, LEFT|flags|rowattr); + if (rowattr && s_editMode>0) t.tm_year = checkIncDec(event, t.tm_year, 112, 200, 0); + break; + case 1: + lcd_outdezNAtt(RADIO_SETUP_2ND_COLUMN+36, y, t.tm_mon+1, LEFT|flags|rowattr|LEADING0, 2); + if (rowattr && s_editMode>0) t.tm_mon = checkIncDec(event, t.tm_mon, 0, 11, 0); + break; + case 2: + { + int16_t year = 1900 + t.tm_year; + int8_t dlim = (((((year%4==0) && (year%100!=0)) || (year%400==0)) && (t.tm_mon==1)) ? 1 : 0); + static const pm_uint8_t dmon[] PROGMEM = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + dlim += pgm_read_byte(&dmon[t.tm_mon]); + lcd_outdezNAtt(RADIO_SETUP_2ND_COLUMN+61, y, t.tm_mday, LEFT|flags|rowattr|LEADING0, 2); + if (rowattr && s_editMode>0) t.tm_mday = checkIncDec(event, t.tm_mday, 1, dlim, 0); + break; + } + } + } + if (attr && checkIncDec_Ret) { + g_rtcTime = gmktime(&t); // update local timestamp and get wday calculated + } + break; + } + + case ITEM_SETUP_TIME: + { + lcd_putsLeft(y, STR_TIME); + LcdFlags flags = 0; + if (attr && m_posHorz < 0) { + flags |= INVERS; + lcdDrawFilledRect(RADIO_SETUP_2ND_COLUMN-INVERT_HORZ_MARGIN, y-INVERT_VERT_MARGIN, 85, INVERT_LINE_HEIGHT, TEXT_INVERTED_BGCOLOR); + } + lcd_putsAtt(RADIO_SETUP_2ND_COLUMN+15, y, ":", flags); + lcd_putsAtt(RADIO_SETUP_2ND_COLUMN+35, y, ":", flags); + for (uint8_t j=0; j<3; j++) { + uint8_t rowattr = (m_posHorz==j ? attr : 0); + switch (j) { + case 0: + lcd_outdezNAtt(RADIO_SETUP_2ND_COLUMN, y, t.tm_hour, flags|rowattr|LEFT|LEADING0, 2); + if (rowattr && s_editMode>0) t.tm_hour = checkIncDec(event, t.tm_hour, 0, 23, 0); + break; + case 1: + lcd_outdezNAtt(RADIO_SETUP_2ND_COLUMN+20, y, t.tm_min, flags|rowattr|LEFT|LEADING0, 2); + if (rowattr && s_editMode>0) t.tm_min = checkIncDec(event, t.tm_min, 0, 59, 0); + break; + case 2: + lcd_outdezNAtt(RADIO_SETUP_2ND_COLUMN+40, y, t.tm_sec, flags|rowattr|LEFT|LEADING0, 2); + if (rowattr && s_editMode>0) t.tm_sec = checkIncDec(event, t.tm_sec, 0, 59, 0); + break; + } + } + if (attr && checkIncDec_Ret) + g_rtcTime = gmktime(&t); // update local timestamp and get wday calculated + break; + } + +#if 0 + case ITEM_SETUP_BATT_RANGE: + { + lcd_putsLeft(y, STR_BATTERY_RANGE); + LcdFlags color = WHITE; + if (attr && m_posHorz < 0) { + color = BLACK; + lcdDrawFilledRect(RADIO_SETUP_2ND_COLUMN-INVERT_HORZ_MARGIN, y-INVERT_VERT_MARGIN, 90, INVERT_LINE_HEIGHT, TEXT_INVERTED_BGCOLOR); + } + putsVolts(RADIO_SETUP_2ND_COLUMN, y, 90+g_eeGeneral.vBatMin, color|(m_posHorz==0 ? attr : 0)|LEFT|NO_UNIT); + lcd_puts(RADIO_SETUP_2ND_COLUMN+20, y, "-"); + putsVolts(RADIO_SETUP_2ND_COLUMN+28, y, 120+g_eeGeneral.vBatMax, color|(m_posHorz>0 ? attr : 0)|LEFT|NO_UNIT); + if (attr && s_editMode>0) { + if (m_posHorz==0) + CHECK_INCDEC_GENVAR(event, g_eeGeneral.vBatMin, -50, g_eeGeneral.vBatMax+29); // min=4.0V + else + CHECK_INCDEC_GENVAR(event, g_eeGeneral.vBatMax, g_eeGeneral.vBatMin-29, +40); // max=16.0V + } + break; + } +#endif + + case ITEM_SETUP_SOUND_LABEL: + lcd_putsLeft(y, STR_SOUND_LABEL); + break; + + case ITEM_SETUP_BEEP_MODE: + g_eeGeneral.beepMode = selectMenuItem(RADIO_SETUP_2ND_COLUMN, y, STR_SPEAKER, STR_VBEEPMODE, g_eeGeneral.beepMode, -2, 1, attr, event); +#if defined(FRSKY) + if (attr && checkIncDec_Ret) frskySendAlarms(); +#endif + break; + + case ITEM_SETUP_SPEAKER_VOLUME: + { + lcd_putsLeft(y, STR_SPEAKER_VOLUME); + uint8_t b = g_eeGeneral.speakerVolume+VOLUME_LEVEL_DEF; + displaySlider(RADIO_SETUP_2ND_COLUMN, y, b, VOLUME_LEVEL_MAX, attr); + if (attr) { + CHECK_INCDEC_GENVAR(event, b, 0, VOLUME_LEVEL_MAX); + if (checkIncDec_Ret) { + g_eeGeneral.speakerVolume = (int8_t)b-VOLUME_LEVEL_DEF; + } + } + break; + } + + case ITEM_SETUP_BEEP_VOLUME: + SLIDER_5POS(y, g_eeGeneral.beepVolume, STR_BEEP_VOLUME, event, attr); + break; + case ITEM_SETUP_WAV_VOLUME: + SLIDER_5POS(y, g_eeGeneral.wavVolume, STR_WAV_VOLUME, event, attr); + break; + case ITEM_SETUP_BACKGROUND_VOLUME: + SLIDER_5POS(y, g_eeGeneral.backgroundVolume, STR_BG_VOLUME, event, attr); + break; + + case ITEM_SETUP_BEEP_LENGTH: + SLIDER_5POS(y, g_eeGeneral.beepLength, STR_BEEP_LENGTH, event, attr); + break; + + case ITEM_SETUP_SPEAKER_PITCH: + lcd_putsLeft( y, STR_SPKRPITCH); + lcd_outdezAtt(RADIO_SETUP_2ND_COLUMN, y, g_eeGeneral.speakerPitch*15, attr|LEFT, "Hz", "+"); + if (attr) { + CHECK_INCDEC_GENVAR(event, g_eeGeneral.speakerPitch, 0, 20); + } + break; + +#if defined(VARIO) + case ITEM_SETUP_VARIO_LABEL: + lcd_putsLeft(y, STR_VARIO); + break; + case ITEM_SETUP_VARIO_VOLUME: + SLIDER_5POS(y, g_eeGeneral.varioVolume, TR_SPEAKER_VOLUME, event, attr); + break; + case ITEM_SETUP_VARIO_PITCH: + lcd_putsLeft(y, STR_PITCH_AT_ZERO); + lcd_outdezAtt(RADIO_SETUP_2ND_COLUMN, y, VARIO_FREQUENCY_ZERO+(g_eeGeneral.varioPitch*10), attr|LEFT, "Hz"); + if (attr) CHECK_INCDEC_GENVAR(event, g_eeGeneral.varioPitch, -40, 40); + break; + case ITEM_SETUP_VARIO_RANGE: + lcd_putsLeft(y, STR_PITCH_AT_MAX); + lcd_outdezAtt(RADIO_SETUP_2ND_COLUMN, y, VARIO_FREQUENCY_ZERO+(g_eeGeneral.varioPitch*10)+VARIO_FREQUENCY_RANGE+(g_eeGeneral.varioRange*10), attr|LEFT, "Hz"); + if (attr) CHECK_INCDEC_GENVAR(event, g_eeGeneral.varioRange, -80, 80); + break; + case ITEM_SETUP_VARIO_REPEAT: + lcd_putsLeft(y, STR_REPEAT_AT_ZERO); + lcd_outdezAtt(RADIO_SETUP_2ND_COLUMN, y, VARIO_REPEAT_ZERO+(g_eeGeneral.varioRepeat*10), attr|LEFT, STR_MS); + if (attr) CHECK_INCDEC_GENVAR(event, g_eeGeneral.varioRepeat, -30, 50); + break; +#endif + +#if defined(HAPTIC) + case ITEM_SETUP_HAPTIC_LABEL: + lcd_putsLeft(y, STR_HAPTIC_LABEL); + break; + + case ITEM_SETUP_HAPTIC_MODE: + g_eeGeneral.hapticMode = selectMenuItem(RADIO_SETUP_2ND_COLUMN, y, STR_MODE, STR_VBEEPMODE, g_eeGeneral.hapticMode, -2, 1, attr, event); + break; + + case ITEM_SETUP_HAPTIC_LENGTH: + SLIDER_5POS(y, g_eeGeneral.hapticLength, STR_LENGTH, event, attr); + break; + + case ITEM_SETUP_HAPTIC_STRENGTH: + SLIDER_5POS(y, g_eeGeneral.hapticStrength, STR_HAPTICSTRENGTH, event, attr); + break; +#endif + +#if 0 + case ITEM_SETUP_CONTRAST: + lcd_putsLeft(y, STR_CONTRAST); + lcd_outdezAtt(RADIO_SETUP_2ND_COLUMN, y, g_eeGeneral.contrast, attr|LEFT); + if (attr) { + CHECK_INCDEC_GENVAR(event, g_eeGeneral.contrast, CONTRAST_MIN, CONTRAST_MAX); + lcdSetContrast(); + } + break; +#endif + + case ITEM_SETUP_ALARMS_LABEL: + lcd_putsLeft(y, STR_ALARMS_LABEL); + break; + + case ITEM_SETUP_BATTERY_WARNING: + lcd_putsLeft(y, STR_BATTERYWARNING); + putsVolts(RADIO_SETUP_2ND_COLUMN, y, g_eeGeneral.vBatWarn, attr|LEFT); + if (attr) CHECK_INCDEC_GENVAR(event, g_eeGeneral.vBatWarn, 27, 42); // 2.7-4.2V + break; + +#if 0 + case ITEM_SETUP_MEMORY_WARNING: + { + uint8_t b = 1-g_eeGeneral.disableMemoryWarning; + g_eeGeneral.disableMemoryWarning = 1 - onoffMenuItem(b, RADIO_SETUP_2ND_COLUMN, y, STR_MEMORYWARNING, attr, event); + break; + } +#endif + + case ITEM_SETUP_ALARM_WARNING: + { + uint8_t b = 1-g_eeGeneral.disableAlarmWarning; + g_eeGeneral.disableAlarmWarning = 1 - onoffMenuItem(b, RADIO_SETUP_2ND_COLUMN, y, STR_ALARMWARNING, attr, event); + break; + } + +#if defined(PCBSKY9X) + case ITEM_SETUP_CAPACITY_WARNING: + lcd_putsLeft(y, STR_CAPAWARNING); + putsValueWithUnit(RADIO_SETUP_2ND_COLUMN, y, g_eeGeneral.mAhWarn*50, UNIT_MAH, attr|LEFT) ; + if(attr) CHECK_INCDEC_GENVAR(event, g_eeGeneral.mAhWarn, 0, 100); + break; +#endif + +#if defined(PCBSKY9X) + case ITEM_SETUP_TEMPERATURE_WARNING: + lcd_putsLeft(y, STR_TEMPWARNING); + putsValueWithUnit(RADIO_SETUP_2ND_COLUMN, y, g_eeGeneral.temperatureWarn, UNIT_TEMPERATURE, attr|LEFT) ; + if(attr) CHECK_INCDEC_GENVAR(event, g_eeGeneral.temperatureWarn, 0, 120); // 0 means no alarm + break; +#endif + + case ITEM_SETUP_INACTIVITY_ALARM: + lcd_putsLeft( y,STR_INACTIVITYALARM); + lcd_outdezAtt(RADIO_SETUP_2ND_COLUMN, y, g_eeGeneral.inactivityTimer, attr|LEFT, "m"); + if (attr) g_eeGeneral.inactivityTimer = checkIncDec(event, g_eeGeneral.inactivityTimer, 0, 250, EE_GENERAL); //0..250minutes + break; + +#if 0 + case ITEM_SETUP_BACKLIGHT_LABEL: + lcd_putsLeft(y, STR_BACKLIGHT_LABEL); + break; + + case ITEM_SETUP_BACKLIGHT_MODE: + g_eeGeneral.backlightMode = selectMenuItem(RADIO_SETUP_2ND_COLUMN, y, STR_MODE, STR_VBLMODE, g_eeGeneral.backlightMode, e_backlight_mode_off, e_backlight_mode_on, attr, event); + break; + + case ITEM_SETUP_FLASH_BEEP: + g_eeGeneral.alarmsFlash = onoffMenuItem(g_eeGeneral.alarmsFlash, RADIO_SETUP_2ND_COLUMN, y, STR_ALARM, attr, event ) ; + break; + + case ITEM_SETUP_BACKLIGHT_DELAY: + lcd_putsLeft(y, STR_BLDELAY); + lcd_outdezAtt(RADIO_SETUP_2ND_COLUMN, y, g_eeGeneral.lightAutoOff*5, attr|LEFT, "s"); + if (attr) CHECK_INCDEC_GENVAR(event, g_eeGeneral.lightAutoOff, 0, 600/5); + break; + + case ITEM_SETUP_BRIGHTNESS: + lcd_putsLeft(y, STR_BRIGHTNESS); + lcd_outdezAtt(RADIO_SETUP_2ND_COLUMN, y, 100-g_eeGeneral.backlightBright, attr|LEFT) ; + if (attr) { + uint8_t b = 100 - g_eeGeneral.backlightBright; + CHECK_INCDEC_GENVAR(event, b, 0, 100); + g_eeGeneral.backlightBright = 100 - b; + } + break; + + case ITEM_SETUP_BACKLIGHT_COLOR: + lcd_putsLeft(y, STR_BLCOLOR); + displaySlider(RADIO_SETUP_2ND_COLUMN, y, g_eeGeneral.backlightColor, 20, attr); + if (attr) g_eeGeneral.backlightColor = checkIncDec(event, g_eeGeneral.backlightColor, 0, 20, EE_GENERAL | NO_INCDEC_MARKS); + break; +#endif + +#if 0 + case ITEM_SETUP_DISABLE_SPLASH: + { + lcd_putsLeft(y, STR_SPLASHSCREEN); + if (SPLASH_NEEDED()) { + lcd_outdezAtt(RADIO_SETUP_2ND_COLUMN, y, SPLASH_TIMEOUT/100, attr|LEFT, "s"); + } + else { + lcd_putsiAtt(RADIO_SETUP_2ND_COLUMN, y, STR_MMMINV, 0, attr); // TODO define + } + if (attr) g_eeGeneral.splashMode = -checkIncDecGen(event, -g_eeGeneral.splashMode, -3, 4); + break; + } +#endif + + case ITEM_SETUP_TIMEZONE: + lcd_putsLeft(y, STR_TIMEZONE); + lcd_outdezAtt(RADIO_SETUP_2ND_COLUMN, y, g_eeGeneral.timezone, attr|LEFT); + if (attr) CHECK_INCDEC_GENVAR(event, g_eeGeneral.timezone, -12, 12); + break; + + case ITEM_SETUP_GPSFORMAT: + g_eeGeneral.gpsFormat = selectMenuItem(RADIO_SETUP_2ND_COLUMN, y, STR_GPSCOORD, STR_GPSFORMAT, g_eeGeneral.gpsFormat, 0, 1, attr, event); + break; + + case ITEM_SETUP_COUNTRYCODE: + g_eeGeneral.countryCode = selectMenuItem(RADIO_SETUP_2ND_COLUMN, y, STR_COUNTRYCODE, STR_COUNTRYCODES, g_eeGeneral.countryCode, 0, 2, attr, event); + break; + + case ITEM_SETUP_LANGUAGE: + lcd_putsLeft(y, STR_VOICELANG); + lcd_putsAtt(RADIO_SETUP_2ND_COLUMN, y, currentLanguagePack->name, attr); + if (attr) { + currentLanguagePackIdx = checkIncDec(event, currentLanguagePackIdx, 0, DIM(languagePacks)-2, EE_GENERAL); + if (checkIncDec_Ret) { + currentLanguagePack = languagePacks[currentLanguagePackIdx]; + strncpy(g_eeGeneral.ttsLanguage, currentLanguagePack->id, 2); + } + } + break; + + case ITEM_SETUP_IMPERIAL: + g_eeGeneral.imperial = selectMenuItem(RADIO_SETUP_2ND_COLUMN, y, STR_UNITSSYSTEM, STR_VUNITSSYSTEM, g_eeGeneral.imperial, 0, 1, attr, event); + break; + +#if 0 + case ITEM_SETUP_FAI: + onoffMenuItem(g_eeGeneral.fai, RADIO_SETUP_2ND_COLUMN, y, PSTR("FAI Mode"), attr, event); + if (attr && checkIncDec_Ret) { + if (g_eeGeneral.fai) + POPUP_WARNING(PSTR("FAI\001mode blocked!")); + else + POPUP_CONFIRMATION(PSTR("FAI mode?")); + } + break; +#endif + +#if defined(MAVLINK) + case ITEM_MAVLINK_BAUD: + g_eeGeneral.mavbaud = selectMenuItem(RADIO_SETUP_2ND_COLUMN, y, STR_MAVLINK_BAUD_LABEL, STR_MAVLINK_BAUDS, g_eeGeneral.mavbaud, 0, 7, attr, event); + break; +#endif + + case ITEM_SETUP_SWITCHES_DELAY: + lcd_putsLeft(y, STR_SWITCHES_DELAY); + lcd_outdezAtt(RADIO_SETUP_2ND_COLUMN, y, 10*SWITCHES_DELAY(), attr|LEFT, STR_MS); + if (attr) CHECK_INCDEC_GENVAR(event, g_eeGeneral.switchesDelay, -15, +15); + break; + + case ITEM_SETUP_RX_CHANNEL_ORD: + { + lcd_putsLeft(y, STR_RXCHANNELORD); // RAET->AETR + char s[5]; + for (uint8_t i=0; i<4; i++) { + s[i] = STR_RETA123[channel_order(i+1)]; + } + s[4] = '\0'; + lcd_putsAtt(RADIO_SETUP_2ND_COLUMN, y, s, attr); + if (attr) CHECK_INCDEC_GENVAR(event, g_eeGeneral.templateSetup, 0, 23); + break; + } + + case ITEM_SETUP_STICK_MODE_LABELS: + lcd_putsLeft(y, NO_INDENT(STR_MODE)); + for (int i=0; i<4; i++) { + // lcdDrawBitmap((6+4*i)*12, y, ...); + } + break; + + case ITEM_SETUP_STICK_MODE: + { + char s[2] = " "; + s[0] = '1'+g_eeGeneral.stickMode; + lcd_putsAtt(INDENT_WIDTH, y, s, attr); + for (uint8_t i=0; i<4; i++) { + putsMixerSource((6+4*i)*12, y, MIXSRC_Rud + pgm_read_byte(modn12x3 + 4*g_eeGeneral.stickMode + i)); + } + if (attr && s_editMode>0) { + CHECK_INCDEC_GENVAR(event, g_eeGeneral.stickMode, 0, 3); + } + else if (stickMode != g_eeGeneral.stickMode) { + pausePulses(); + stickMode = g_eeGeneral.stickMode; + checkTHR(); + resumePulses(); + clearKeyEvents(); + } + break; + } + } + } +} diff --git a/radio/src/gui/Horus/menu_general_trainer.cpp b/radio/src/gui/Horus/menu_general_trainer.cpp new file mode 100644 index 000000000..6fdfbc63b --- /dev/null +++ b/radio/src/gui/Horus/menu_general_trainer.cpp @@ -0,0 +1,121 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +#define TRAINER_COLUMN_WIDTH 60 +#define TRAINER_COLUMN_1 MENU_TITLE_LEFT+80 +#define TRAINER_COLUMN_2 TRAINER_COLUMN_1+TRAINER_COLUMN_WIDTH +#define TRAINER_COLUMN_3 TRAINER_COLUMN_2+TRAINER_COLUMN_WIDTH + +#define TRAINER_CALIB_POS 12 + +void menuGeneralTrainer(evt_t event) +{ + uint8_t y; + bool slave = SLAVE_MODE(); + + MENU(STR_MENUTRAINER, menuTabGeneral, e_Trainer, (slave ? 0 : 6), DEFAULT_SCROLLBAR_X, { 2, 2, 2, 2, 0/*, 0*/ }); + + if (slave) { + lcd_putsCenter(5*FH, STR_SLAVE, TEXT_COLOR); + return; + } + + uint8_t attr; + uint8_t blink = ((s_editMode>0) ? BLINK|INVERS : INVERS); + + lcd_putsAtt(TRAINER_COLUMN_1, MENU_HEADER_HEIGHT+1, "Mode", HEADER_COLOR); + lcd_putsAtt(TRAINER_COLUMN_2, MENU_HEADER_HEIGHT+1, "Weight", HEADER_COLOR); + lcd_putsAtt(TRAINER_COLUMN_3, MENU_HEADER_HEIGHT+1, "Source", HEADER_COLOR); + + y = MENU_CONTENT_TOP + FH; + int sub = m_posVert + 1; + + for (int i=1; i<=NUM_STICKS; i++) { + uint8_t chan = channel_order(i); + volatile TrainerMix *td = &g_eeGeneral.trainer.mix[chan-1]; + + putsMixerSource(MENU_TITLE_LEFT, y, MIXSRC_Rud-1+chan, ((sub==i && CURSOR_ON_LINE()) ? INVERS : 0)); + + for (int j=0; j<3; j++) { + + attr = ((sub==i && m_posHorz==j) ? blink : 0); + + switch(j) { + case 0: + lcd_putsiAtt(TRAINER_COLUMN_1, y, STR_TRNMODE, td->mode, attr); + if (attr&BLINK) CHECK_INCDEC_GENVAR(event, td->mode, 0, 2); + break; + + case 1: + lcd_outdezAtt(TRAINER_COLUMN_2, y, td->studWeight, LEFT|attr, "%"); + if (attr&BLINK) CHECK_INCDEC_GENVAR(event, td->studWeight, -125, 125); + break; + + case 2: + lcd_putsiAtt(TRAINER_COLUMN_3, y, STR_TRNCHN, td->srcChn, attr); + if (attr&BLINK) CHECK_INCDEC_GENVAR(event, td->srcChn, 0, 3); + break; + } + } + y += FH; + } + + attr = (sub==5) ? blink : 0; + lcd_putsLeft(MENU_CONTENT_TOP + 5*FH, STR_MULTIPLIER); + lcd_outdezAtt(TRAINER_COLUMN_1, MENU_CONTENT_TOP + 5*FH, g_eeGeneral.PPM_Multiplier+10, LEFT|attr|PREC1); + if (attr) CHECK_INCDEC_GENVAR(event, g_eeGeneral.PPM_Multiplier, -10, 40); + + attr = (sub==6) ? INVERS : 0; + if (attr) s_editMode = 0; + lcd_putsAtt(MENU_TITLE_LEFT, MENU_CONTENT_TOP + 6*FH, STR_CAL, attr); + for (int i=0; i<4; i++) { +#if defined (PPM_UNIT_PERCENT_PREC1) + lcd_outdezAtt(TRAINER_COLUMN_1+i*TRAINER_COLUMN_WIDTH, MENU_CONTENT_TOP + 6*FH, (ppmInput[i]-g_eeGeneral.trainer.calib[i])*2, LEFT|PREC1); +#else + lcd_outdezAtt(TRAINER_COLUMN_1+i*TRAINER_COLUMN_WIDTH, MENU_CONTENT_TOP + 6*FH, (ppmInput[i]-g_eeGeneral.trainer.calib[i])/5, LEFT); +#endif + } + + if (attr) { + if (event==EVT_KEY_LONG(KEY_ENTER)){ + memcpy(g_eeGeneral.trainer.calib, ppmInput, sizeof(g_eeGeneral.trainer.calib)); + eeDirty(EE_GENERAL); + AUDIO_WARNING1(); + } + } +} diff --git a/radio/src/gui/Horus/menu_general_version.cpp b/radio/src/gui/Horus/menu_general_version.cpp new file mode 100644 index 000000000..7b01ba41e --- /dev/null +++ b/radio/src/gui/Horus/menu_general_version.cpp @@ -0,0 +1,53 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +void menuGeneralVersion(evt_t event) +{ + SIMPLE_MENU(STR_MENUVERSION, menuTabGeneral, e_Vers, 1, DEFAULT_SCROLLBAR_X); + + lcd_putsLeft(MENU_CONTENT_TOP + FH, vers_stamp); + lcd_putsLeft(MENU_CONTENT_TOP + 2*FH, date_stamp); + lcd_putsLeft(MENU_CONTENT_TOP + 3*FH, time_stamp); + lcd_putsLeft(MENU_CONTENT_TOP + 4*FH, eeprom_stamp); + + // TODO EEPROM erase + backup + // lcd_putsCenter(MENU_HEADER_HEIGHT+6*FH, STR_EEBACKUP); + // if (event == EVT_KEY_LONG(KEY_ENTER)) { + // backupEeprom(); + // } +} diff --git a/radio/src/gui/Horus/menu_model.cpp b/radio/src/gui/Horus/menu_model.cpp new file mode 100644 index 000000000..24f910706 --- /dev/null +++ b/radio/src/gui/Horus/menu_model.cpp @@ -0,0 +1,203 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +// TODO elsewhere! +#define WCHART 64 +#define X0 (LCD_W-WCHART-8) +#define Y0 118 + +enum EnumTabModel { + // e_ModelSelect, + e_ModelSetup, + CASE_HELI(e_Heli) + CASE_FLIGHT_MODES(e_FlightModesAll) + e_InputsAll, + e_MixAll, + e_Limits, + CASE_CURVES(e_CurvesAll) + CASE_GVARS(e_GVars) + e_LogicalSwitches, + e_CustomFunctions, +#if defined(LUA_MODEL_SCRIPTS) + e_CustomScripts, +#endif + CASE_FRSKY(e_Telemetry) +}; + +void menuModelSelect(evt_t event); +void menuModelSetup(evt_t event); +void menuModelHeli(evt_t event); +void menuModelFlightModesAll(evt_t event); +void menuModelExposAll(evt_t event); +void menuModelMixAll(evt_t event); +void menuModelLimits(evt_t event); +void menuModelCurvesAll(evt_t event); +void menuModelCurveOne(evt_t event); +void menuModelGVars(evt_t event); +void menuModelLogicalSwitches(evt_t event); +void menuModelCustomFunctions(evt_t event); +void menuModelCustomScripts(evt_t event); +void menuModelTelemetry(evt_t event); +void menuModelExpoOne(evt_t event); + +extern uint8_t s_curveChan; + +#define FlightModesType uint16_t + +void editCurveRef(coord_t x, coord_t y, CurveRef & curve, evt_t event, uint8_t attr); + +#define MIXES_2ND_COLUMN 80 + +uint8_t editDelay(const coord_t x, const coord_t y, const evt_t event, const uint8_t attr, const pm_char *str, uint8_t delay) +{ + lcd_putsAtt(x+MENU_TITLE_LEFT, y, str, TEXT_COLOR); + lcd_outdezAtt(x+MIXES_2ND_COLUMN, y, (10/DELAY_STEP)*delay, attr|PREC1|LEFT); + if (attr) CHECK_INCDEC_MODELVAR_ZERO(event, delay, DELAY_MAX); + return delay; +} +#define EDIT_DELAY(x, y, event, attr, str, delay) editDelay(x, y, event, attr, str, delay) + +const MenuFuncP_PROGMEM menuTabModel[] PROGMEM = { +// menuModelSelect, + menuModelSetup, + CASE_HELI(menuModelHeli) + CASE_FLIGHT_MODES(menuModelFlightModesAll) + menuModelExposAll, + menuModelMixAll, + menuModelLimits, + CASE_CURVES(menuModelCurvesAll) +#if defined(GVARS) && defined(FLIGHT_MODES) + CASE_GVARS(menuModelGVars) +#endif + menuModelLogicalSwitches, + menuModelCustomFunctions, +#if defined(LUA_MODEL_SCRIPTS) + menuModelCustomScripts, +#endif + CASE_FRSKY(menuModelTelemetry) + CASE_MAVLINK(menuTelemetryMavlinkSetup) + CASE_TEMPLATES(menuModelTemplates) +}; + +#define COPY_MODE 1 +#define MOVE_MODE 2 +static uint8_t s_copyMode = 0; +static int8_t s_copySrcRow; +static int8_t s_copyTgtOfs; + +static uint8_t editNameCursorPos = 0; + +void editName(coord_t x, coord_t y, char *name, uint8_t size, evt_t event, uint8_t active) +{ + uint8_t mode = 0; + if (active && s_editMode <= 0) { + mode = INVERS; + } + + if (!active || s_editMode <= 0) { + if (zlen(name, size) == 0) { + char tmp[] = "---"; + lcd_putsnAtt(x, y, tmp, size, mode); + } + else { + lcd_putsnAtt(x, y, name, size, ZCHAR | mode); + } + } + + if (active) { + uint8_t cur = editNameCursorPos; + if (s_editMode > 0) { + int8_t c = name[cur]; + int8_t v = c; + + if (IS_ROTARY_RIGHT(event) || IS_ROTARY_LEFT(event) || event==EVT_KEY_FIRST(KEY_DOWN) || event==EVT_KEY_FIRST(KEY_UP) + || event==EVT_KEY_REPT(KEY_DOWN) || event==EVT_KEY_REPT(KEY_UP)) { + v = checkIncDec(event, abs(v), 0, ZCHAR_MAX, 0); + if (c <= 0) v = -v; + } + + switch (event) { + case EVT_ROTARY_BREAK: + if (s_editMode == EDIT_MODIFY_FIELD) { + s_editMode = EDIT_MODIFY_STRING; + cur = 0; + } + else if (cur=-26 && v<=26) { + v = -v; // toggle case + if (event==EVT_KEY_LONG(KEY_LEFT)) + killEvents(KEY_LEFT); + } + break; + } + + if (c != v) { + name[cur] = v; + eeDirty(g_menuPos[0] == 0 ? EE_MODEL : EE_GENERAL); + } + + lcd_putsnAtt(x, y, name, size, ZCHAR | mode); + coord_t w = (editNameCursorPos == 0 ? 0 : getTextWidth(name, editNameCursorPos, ZCHAR)); + char s[] = { idx2char(v), '\0' }; + lcdDrawFilledRect(x+w, y-1, getTextWidth(s, 1)-1, 12, TEXT_INVERTED_BGCOLOR); + lcd_putsAtt(x+w, y, s, TEXT_INVERTED_COLOR); + } + else { + cur = 0; + } + editNameCursorPos = cur; + } +} + +void editSingleName(coord_t x, coord_t y, const pm_char *label, char *name, uint8_t size, evt_t event, uint8_t active) +{ + lcd_putsLeft(y, label); + editName(x, y, name, size, event, active); +} + +static uint8_t s_currIdx; diff --git a/radio/src/gui/Horus/menu_model_curves.cpp b/radio/src/gui/Horus/menu_model_curves.cpp new file mode 100644 index 000000000..6a407f670 --- /dev/null +++ b/radio/src/gui/Horus/menu_model_curves.cpp @@ -0,0 +1,325 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +uint8_t s_curveChan; + +int curveFn(int x) +{ + return applyCustomCurve(x, s_curveChan); +} + +struct point_t { + coord_t x; + coord_t y; +}; + +point_t getPoint(uint8_t i) +{ + point_t result = {0, 0}; + CurveInfo &crv = g_model.curves[s_curveChan]; + int8_t *points = curveAddress(s_curveChan); + bool custom = (crv.type == CURVE_TYPE_CUSTOM); + uint8_t count = 5+crv.points; + if (i < count) { + result.x = X0-1-WCHART+i*WCHART*2/(count-1); + result.y = Y0 - (points[i]) * (WCHART-1) / 100; + if (custom && i>0 && i g_model.points + sizeof(g_model.points)) { + AUDIO_WARNING2(); + return false; + } + + int8_t *nextCrv = curveAddress(index+1); + memmove(nextCrv+shift, nextCrv, 5*(MAX_CURVES-index-1)+curveEnd[MAX_CURVES-1]-curveEnd[index]); + if (shift < 0) memclear(&g_model.points[NUM_POINTS-1] + shift, -shift); + while (index0 ? INVERS|BLINK : INVERS) : 0); + lcd_putsLeft(MENU_CONTENT_TOP + 2*FH, "Type"); + lcd_putsiAtt(MENU_TITLE_LEFT+INDENT_WIDTH, MENU_CONTENT_TOP + 3*FH, STR_CURVE_TYPES, crv.type, attr); + if (attr) { + uint8_t newType = checkIncDecModelZero(event, crv.type, CURVE_TYPE_LAST); + if (newType != crv.type) { + for (int i=1; i<4+crv.points; i++) + points[i] = calcRESXto100(applyCustomCurve(calc100toRESX(-100 + i*200/(4+crv.points)), s_curveChan)); + moveCurve(s_curveChan, checkIncDec_Ret > 0 ? 3+crv.points : -3-crv.points); + if (newType == CURVE_TYPE_CUSTOM) { + for (int i=0; i<3+crv.points; i++) + points[5+crv.points+i] = -100 + ((i+1)*200) / (4+crv.points); + } + crv.type = newType; + } + } + + attr = (m_posVert==2 ? (s_editMode>0 ? INVERS|BLINK : INVERS) : 0); + lcd_putsLeft(MENU_CONTENT_TOP + 4*FH, STR_COUNT); + lcd_outdezAtt(MENU_TITLE_LEFT+INDENT_WIDTH, MENU_CONTENT_TOP + 5*FH, 5+crv.points, LEFT|attr, STR_PTS); + if (attr) { + int count = checkIncDecModel(event, crv.points, -3, 12); // 2pts - 17pts + if (checkIncDec_Ret) { + int newPoints[MAX_POINTS]; + newPoints[0] = points[0]; + newPoints[4+count] = points[4+crv.points]; + for (int i=1; i<4+count; i++) + newPoints[i] = calcRESXto100(applyCustomCurve(calc100toRESX(-100 + (i*200) / (4+count)), s_curveChan)); + moveCurve(s_curveChan, checkIncDec_Ret*(crv.type==CURVE_TYPE_CUSTOM?2:1)); + for (int i=0; i<5+count; i++) { + points[i] = newPoints[i]; + if (crv.type == CURVE_TYPE_CUSTOM && i!=0 && i!=4+count) + points[5+count+i-1] = -100 + (i*200) / (4+count); + } + crv.points = count; + } + } + + lcd_putsLeft(MENU_CONTENT_TOP + 6*FH, STR_SMOOTH); + lcdDrawCheckBox(70, MENU_CONTENT_TOP + 6*FH, crv.smooth, m_posVert==3 ? INVERS : 0); + if (m_posVert==3) crv.smooth = checkIncDecModel(event, crv.smooth, 0, 1); + + switch(event) { + case EVT_ENTRY: + pointsOfs = 0; + break; + case EVT_KEY_LONG(KEY_ENTER): + if (m_posVert > 1) { + killEvents(event); + MENU_ADD_ITEM(STR_CURVE_PRESET); + MENU_ADD_ITEM(STR_MIRROR); + MENU_ADD_ITEM(STR_CLEAR); + menuHandler = onCurveOneMenu; + } + break; + case EVT_KEY_LONG(KEY_MENU): + pushMenu(menuChannelsView); + killEvents(event); + } + + if (m_posVert >= 0) { + DrawCurve(6); + } + + lcd_putsAtt(115, MENU_FOOTER_TOP, "X", HEADER_COLOR); + lcd_putsAtt(145, MENU_FOOTER_TOP, "Y", HEADER_COLOR); + + coord_t posY = MENU_HEADER_HEIGHT+1; + attr = (s_editMode > 0 ? INVERS|BLINK : INVERS); + for (int i=0; i<5+crv.points; i++) { + point_t point = getPoint(i); + uint8_t selectionMode = 0; + if (crv.type==CURVE_TYPE_CUSTOM) { + if (m_posVert==4+2*i || (i==5+crv.points-1 && m_posVert==4+5+crv.points+5+crv.points-2-1)) + selectionMode = 2; + else if (i>0 && m_posVert==3+2*i) + selectionMode = 1; + } + else if (m_posVert == 4+i) { + selectionMode = 2; + } + + if (i>=pointsOfs && i0 && i<5+crv.points-1) x = points[5+crv.points+i-1]; + lcd_outdezAtt(100, posY, i+1, LEFT); + lcd_outdezAtt(115, posY, x, LEFT|(selectionMode==1?attr:0)); + lcd_outdezAtt(145, posY, points[i], LEFT|(selectionMode==2?attr:0)); + posY += FH; + } + + if (selectionMode > 0) { + // do selection square + lcdDrawFilledRect(point.x-7, point.y-2, 5, 5, TEXT_INVERTED_BGCOLOR); + if (s_editMode > 0) { + if (selectionMode == 1) + CHECK_INCDEC_MODELVAR(event, points[5+crv.points+i-1], i==1 ? -100 : points[5+crv.points+i-2], i==5+crv.points-2 ? 100 : points[5+crv.points+i]); // edit X + else if (selectionMode == 2) + CHECK_INCDEC_MODELVAR(event, points[i], -100, 100); + } + if (i < pointsOfs) + pointsOfs = i; + else if (i > pointsOfs+NUM_BODY_LINES-1) + pointsOfs = i-NUM_BODY_LINES+1; + } + } + + if (5+crv.points > NUM_BODY_LINES) { + displayScrollbar(167, DEFAULT_SCROLLBAR_Y, DEFAULT_SCROLLBAR_H, pointsOfs, 5+crv.points, NUM_BODY_LINES); + } +} + +void editCurveRef(coord_t x, coord_t y, CurveRef & curve, evt_t event, uint8_t attr) +{ + lcd_putsiAtt(x, y, "\004DiffExpoFuncCstm", curve.type, (m_posHorz==0 ? attr : 0)); + if (attr && m_posHorz==0) { + CHECK_INCDEC_MODELVAR_ZERO(event, curve.type, CURVE_REF_CUSTOM); + if (checkIncDec_Ret) curve.value = 0; + } + switch (curve.type) { + case CURVE_REF_DIFF: + case CURVE_REF_EXPO: + curve.value = GVAR_MENU_ITEM(x+40, y, curve.value, -100, 100, m_posHorz==1 ? LEFT|attr : LEFT, 0, event); + break; + case CURVE_REF_FUNC: + lcd_putsiAtt(x+40, y, STR_VCURVEFUNC, curve.value, (m_posHorz==1 ? attr : 0)); + if (attr && m_posHorz==1) CHECK_INCDEC_MODELVAR_ZERO(event, curve.value, CURVE_BASE-1); + break; + case CURVE_REF_CUSTOM: + putsCurve(x+40, y, curve.value, (m_posHorz==1 ? attr : 0)); + if (attr && m_posHorz==1) { + if (event==EVT_KEY_LONG(KEY_ENTER) && curve.value!=0) { + s_curveChan = (curve.value<0 ? -curve.value-1 : curve.value-1); + pushMenu(menuModelCurveOne); + } + else { + CHECK_INCDEC_MODELVAR(event, curve.value, -MAX_CURVES, MAX_CURVES); + } + } + break; + } +} + +void menuModelCurvesAll(evt_t event) +{ + SIMPLE_MENU(STR_MENUCURVES, menuTabModel, e_CurvesAll, MAX_CURVES, DEFAULT_SCROLLBAR_X); + + int8_t sub = m_posVert; + + switch (event) { + case EVT_KEY_BREAK(KEY_ENTER): + if (!READ_ONLY()) { + s_curveChan = sub; + pushMenu(menuModelCurveOne); + } + break; + } + + for (int i=0; i= 0) { + s_curveChan = sub; + DrawCurve(23); + } +} diff --git a/radio/src/gui/Horus/menu_model_custom_functions.cpp b/radio/src/gui/Horus/menu_model_custom_functions.cpp new file mode 100644 index 000000000..a4b91c558 --- /dev/null +++ b/radio/src/gui/Horus/menu_model_custom_functions.cpp @@ -0,0 +1,372 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +#define MODEL_CUSTOM_FUNC_1ST_COLUMN 50 +#define MODEL_CUSTOM_FUNC_2ND_COLUMN 100 +#define MODEL_CUSTOM_FUNC_2ND_COLUMN_EXT 150 +#define MODEL_CUSTOM_FUNC_3RD_COLUMN 200 +#define MODEL_CUSTOM_FUNC_4TH_COLUMN 286 +#define MODEL_CUSTOM_FUNC_4TH_COLUMN_ONOFF 290 + +void onCustomFunctionsFileSelectionMenu(const char *result) +{ + int sub = m_posVert; + CustomFunctionData * cf = &g_model.customFn[sub]; + uint8_t func = CFN_FUNC(cf); + + if (result == STR_UPDATE_LIST) { + char directory[256]; + if (func == FUNC_PLAY_SCRIPT) { + strcpy(directory, SCRIPTS_FUNCS_PATH); + } + else { + strcpy(directory, SOUNDS_PATH); + strncpy(directory+SOUNDS_PATH_LNG_OFS, currentLanguagePack->id, 2); + } + if (!listSdFiles(directory, func==FUNC_PLAY_SCRIPT ? SCRIPTS_EXT : SOUNDS_EXT, sizeof(cf->play.name), NULL)) { + POPUP_WARNING(func==FUNC_PLAY_SCRIPT ? STR_NO_SCRIPTS_ON_SD : STR_NO_SOUNDS_ON_SD); + s_menu_flags = 0; + } + } + else { + // The user choosed a file in the list + memcpy(cf->play.name, result, sizeof(cf->play.name)); + eeDirty(EE_MODEL); + if (func == FUNC_PLAY_SCRIPT) { + LUA_LOAD_MODEL_SCRIPTS(); + } + } +} + +void onCustomFunctionsMenu(const char *result) +{ + int sub = m_posVert; + CustomFunctionData * cfn; + uint8_t eeFlags; + + if (g_menuStack[g_menuStackPtr] == menuModelCustomFunctions) { + cfn = &g_model.customFn[sub]; + eeFlags = EE_MODEL; + } + else { + cfn = &g_eeGeneral.customFn[sub]; + eeFlags = EE_GENERAL; + } + + if (result == STR_COPY) { + clipboard.type = CLIPBOARD_TYPE_CUSTOM_FUNCTION; + clipboard.data.cfn = *cfn; + } + else if (result == STR_PASTE) { + *cfn = clipboard.data.cfn; + eeDirty(eeFlags); + } + else if (result == STR_CLEAR) { + memset(cfn, 0, sizeof(CustomFunctionData)); + eeDirty(eeFlags); + } + else if (result == STR_INSERT) { + memmove(cfn+1, cfn, (NUM_CFN-sub-1)*sizeof(CustomFunctionData)); + memset(cfn, 0, sizeof(CustomFunctionData)); + eeDirty(eeFlags); + } + else if (result == STR_DELETE) { + memmove(cfn, cfn+1, (NUM_CFN-sub-1)*sizeof(CustomFunctionData)); + memset(&g_model.customFn[NUM_CFN-1], 0, sizeof(CustomFunctionData)); + eeDirty(eeFlags); + } +} + +void menuCustomFunctions(evt_t event, CustomFunctionData * functions, CustomFunctionsContext & functionsContext) +{ + uint32_t sub = m_posVert; + + uint8_t eeFlags = (functions == g_model.customFn) ? EE_MODEL : EE_GENERAL; + + if (m_posHorz<0 && event==EVT_KEY_LONG(KEY_ENTER) && !READ_ONLY()) { + killEvents(event); + CustomFunctionData *cfn = &functions[sub]; + if (!CFN_EMPTY(cfn)) + MENU_ADD_ITEM(STR_COPY); + if (clipboard.type == CLIPBOARD_TYPE_CUSTOM_FUNCTION) + MENU_ADD_ITEM(STR_PASTE); + if (!CFN_EMPTY(cfn) && CFN_EMPTY(&functions[NUM_CFN-1])) + MENU_ADD_ITEM(STR_INSERT); + if (!CFN_EMPTY(cfn)) + MENU_ADD_ITEM(STR_CLEAR); + for (int i=sub+1; i0) ? BLINK|INVERS : INVERS) : 0); + LcdFlags active = (attr && s_editMode>0); + switch (j) { + case 0: + putsSwitches(MODEL_CUSTOM_FUNC_1ST_COLUMN, y, CFN_SWITCH(cfn), attr | ((functionsContext.activeSwitches & ((MASK_CFN_TYPE)1 << k)) ? BOLD : 0)); + if (active || AUTOSWITCH_ENTER_LONG()) CHECK_INCDEC_SWITCH(event, CFN_SWITCH(cfn), SWSRC_FIRST, SWSRC_LAST, eeFlags, isSwitchAvailableInCustomFunctions); + break; + + case 1: + if (CFN_SWITCH(cfn)) { + lcd_putsiAtt(MODEL_CUSTOM_FUNC_2ND_COLUMN, y, STR_VFSWFUNC, 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); + } + } + else { + j = 4; // skip other fields + if (sub==k && m_posHorz > 0) { + REPEAT_LAST_CURSOR_MOVE(); + } + } + break; + + case 2: + { + int8_t maxParam = NUM_CHNOUT-1; +#if defined(OVERRIDE_CHANNEL_FUNCTION) + if (func == FUNC_OVERRIDE_CHANNEL) { + putsChn(MODEL_CUSTOM_FUNC_2ND_COLUMN_EXT, y, CFN_CH_INDEX(cfn)+1, attr); + } + else +#endif + if (func == FUNC_TRAINER) { + maxParam = 4; + putsMixerSource(MODEL_CUSTOM_FUNC_2ND_COLUMN_EXT, y, CFN_CH_INDEX(cfn)==0 ? 0 : MIXSRC_Rud+CFN_CH_INDEX(cfn)-1, attr); + } +#if defined(GVARS) + else if (func == FUNC_ADJUST_GVAR) { + maxParam = MAX_GVARS-1; + putsStrIdx(MODEL_CUSTOM_FUNC_2ND_COLUMN_EXT, 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 + else if (func == FUNC_SET_TIMER) { + maxParam = MAX_TIMERS-1; + putsStrIdx(MODEL_CUSTOM_FUNC_2ND_COLUMN_EXT, y, STR_TIMER, CFN_TIMER_INDEX(cfn)+1, attr); + if (active) CFN_TIMER_INDEX(cfn) = checkIncDec(event, CFN_TIMER_INDEX(cfn), 0, maxParam, eeFlags); + break; + } + else if (attr) { + REPEAT_LAST_CURSOR_MOVE(); + } + if (active) CHECK_INCDEC_MODELVAR_ZERO(event, CFN_CH_INDEX(cfn), maxParam); + break; + } + + case 3: + { + INCDEC_DECLARE_VARS(eeFlags); + int16_t val_displayed = CFN_PARAM(cfn); + int16_t val_min = 0; + int16_t val_max = 255; + if (func == FUNC_RESET) { + val_max = FUNC_RESET_PARAM_LAST; + lcd_putsiAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, STR_VFSWRESET, CFN_PARAM(cfn), attr); + } +#if defined(OVERRIDE_CHANNEL_FUNCTION) + else if (func == FUNC_OVERRIDE_CHANNEL) { + val_min = -LIMIT_EXT_PERCENT; val_max = +LIMIT_EXT_PERCENT; + lcd_outdezAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT); + } +#endif +#if defined(DANGEROUS_MODULE_FUNCTIONS) + else if (func >= FUNC_RANGECHECK && func <= FUNC_MODULE_OFF) { + val_max = NUM_MODULES-1; + lcd_putsiAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, "\004Int.Ext.", CFN_PARAM(cfn), attr); + } +#endif + else if (func == FUNC_SET_TIMER) { + val_max = 59*60+59; + putsTimer(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT); + } + else if (func == FUNC_PLAY_SOUND) { + val_max = AU_FRSKY_LAST-AU_FRSKY_FIRST-1; + lcd_putsiAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, STR_FUNCSOUNDS, val_displayed, attr); + } +#if defined(HAPTIC) + else if (func == FUNC_HAPTIC) { + val_max = 3; + lcd_outdezAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT); + } +#endif +#if defined(SDCARD) + else if (func == FUNC_PLAY_TRACK || func == FUNC_BACKGND_MUSIC || func == FUNC_PLAY_SCRIPT) { + coord_t x = MODEL_CUSTOM_FUNC_3RD_COLUMN; + if (ZEXIST(cfn->play.name)) + lcd_putsnAtt(x, y, cfn->play.name, sizeof(cfn->play.name), attr); + else + lcd_putsiAtt(x, y, STR_VCSWFUNC, 0, attr); + if (active && event==EVT_KEY_BREAK(KEY_ENTER)) { + s_editMode = 0; + char directory[256]; + if (func==FUNC_PLAY_SCRIPT) { + strcpy(directory, SCRIPTS_FUNCS_PATH); + } + else { + strcpy(directory, SOUNDS_PATH); + strncpy(directory+SOUNDS_PATH_LNG_OFS, currentLanguagePack->id, 2); + } + if (listSdFiles(directory, func==FUNC_PLAY_SCRIPT ? SCRIPTS_EXT : SOUNDS_EXT, sizeof(cfn->play.name), cfn->play.name)) { + menuHandler = onCustomFunctionsFileSelectionMenu; + } + else { + POPUP_WARNING(func==FUNC_PLAY_SCRIPT ? STR_NO_SCRIPTS_ON_SD : STR_NO_SOUNDS_ON_SD); + s_menu_flags = 0; + } + } + break; + } + else if (func == FUNC_PLAY_VALUE) { + val_max = MIXSRC_LAST_TELEM; + putsMixerSource(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr); + INCDEC_ENABLE_CHECK(isSourceAvailable); + } +#endif + else if (func == FUNC_VOLUME) { + val_max = MIXSRC_LAST_CH; + putsMixerSource(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr); + INCDEC_SET_FLAG(eeFlags | INCDEC_SOURCE); + INCDEC_ENABLE_CHECK(isSourceAvailable); + } + else if (func == FUNC_LOGS) { + if (val_displayed) { + lcd_outdezAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr|PREC1|LEFT, "s"); + } + else { + lcd_putsiAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, STR_MMMINV, 0, attr); + } + } +#if defined(REVPLUS) + else if (func == FUNC_BACKLIGHT) { + displaySlider(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, CFN_PARAM(cfn), 100, attr); + INCDEC_SET_FLAG(eeFlags | NO_INCDEC_MARKS); + val_min = 0; + val_max = 100; + } +#endif +#if defined(GVARS) + else if (func == FUNC_ADJUST_GVAR) { + switch (CFN_GVAR_MODE(cfn)) { + case FUNC_ADJUST_GVAR_CONSTANT: + val_displayed = (int16_t)CFN_PARAM(cfn); + val_min = -CFN_GVAR_CST_MAX; val_max = +CFN_GVAR_CST_MAX; + lcd_outdezAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr|LEFT); + break; + case FUNC_ADJUST_GVAR_SOURCE: + val_max = MIXSRC_LAST_CH; + putsMixerSource(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, val_displayed, attr); + INCDEC_SET_FLAG(eeFlags | INCDEC_SOURCE); + INCDEC_ENABLE_CHECK(isSourceAvailable); + break; + case FUNC_ADJUST_GVAR_GVAR: + val_max = MAX_GVARS-1; + putsStrIdx(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, STR_GV, val_displayed+1, attr); + break; + default: // FUNC_ADJUST_GVAR_INC + val_max = 1; + lcd_putsiAtt(MODEL_CUSTOM_FUNC_3RD_COLUMN, y, PSTR("\003-=1+=1"), val_displayed, attr); + break; + } + + if (attr && event==EVT_KEY_LONG(KEY_ENTER)) { + killEvents(event); + s_editMode = !s_editMode; + active = true; + CFN_GVAR_MODE(cfn) += 1; + CFN_GVAR_MODE(cfn) &= 0x03; + val_displayed = 0; + } + } +#endif + else if (attr) { + REPEAT_LAST_CURSOR_MOVE(); + } + + if (active) { + CFN_PARAM(cfn) = CHECK_INCDEC_PARAM(event, val_displayed, val_min, val_max); + } + break; + } + + case 4: + if (HAS_ENABLE_PARAM(func)) { + lcdDrawCheckBox(MODEL_CUSTOM_FUNC_4TH_COLUMN_ONOFF, y, CFN_ACTIVE(cfn), attr); + if (active) CFN_ACTIVE(cfn) = checkIncDec(event, CFN_ACTIVE(cfn), 0, 1, eeFlags); + } + else if (HAS_REPEAT_PARAM(func)) { + if (CFN_PLAY_REPEAT(cfn) == 0) { + lcd_putsAtt(MODEL_CUSTOM_FUNC_4TH_COLUMN+2, y, "1x", attr); + } + else if (CFN_PLAY_REPEAT(cfn) == CFN_PLAY_REPEAT_NOSTART) { + lcd_putsAtt(MODEL_CUSTOM_FUNC_4TH_COLUMN-1, y, "!1x", attr); + } + else { + lcd_outdezAtt(MODEL_CUSTOM_FUNC_4TH_COLUMN+12, y, CFN_PLAY_REPEAT(cfn)*CFN_PLAY_REPEAT_MUL, attr, "s"); + } + if (active) CFN_PLAY_REPEAT(cfn) = checkIncDec(event, CFN_PLAY_REPEAT(cfn)==CFN_PLAY_REPEAT_NOSTART?-1:CFN_PLAY_REPEAT(cfn), -1, 60/CFN_PLAY_REPEAT_MUL, eeFlags); + } + else if (attr) { + REPEAT_LAST_CURSOR_MOVE(); + } + break; + } + } + } +} + +void menuModelCustomFunctions(evt_t event) +{ + MENU(STR_MENUCUSTOMFUNC, menuTabModel, e_CustomFunctions, NUM_CFN, DEFAULT_SCROLLBAR_X, { NAVIGATION_LINE_BY_LINE|4/*repeated*/ }); + return menuCustomFunctions(event, g_model.customFn, modelFunctionsContext); +} diff --git a/radio/src/gui/Horus/menu_model_flightmodes.cpp b/radio/src/gui/Horus/menu_model_flightmodes.cpp new file mode 100644 index 000000000..508407830 --- /dev/null +++ b/radio/src/gui/Horus/menu_model_flightmodes.cpp @@ -0,0 +1,149 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +enum FlightModesItems { + ITEM_FLIGHT_MODES_NAME, + ITEM_FLIGHT_MODES_SWITCH, + ITEM_FLIGHT_MODES_TRIM_RUD, + ITEM_FLIGHT_MODES_TRIM_ELE, + ITEM_FLIGHT_MODES_TRIM_THR, + ITEM_FLIGHT_MODES_TRIM_AIL, + ITEM_FLIGHT_MODES_FADE_IN, + ITEM_FLIGHT_MODES_FADE_OUT, + ITEM_FLIGHT_MODES_COUNT, + ITEM_FLIGHT_MODES_LAST = ITEM_FLIGHT_MODES_COUNT-1 +}; + +bool isTrimModeAvailable(int mode) +{ + return (mode < 0 || (mode%2) == 0 || (mode/2) != m_posVert); +} + +void menuModelFlightModesAll(evt_t event) +{ + MENU(STR_MENUFLIGHTPHASES, menuTabModel, e_FlightModesAll, MAX_FLIGHT_MODES+1, DEFAULT_SCROLLBAR_X, { NAVIGATION_LINE_BY_LINE|(ITEM_FLIGHT_MODES_LAST-1), NAVIGATION_LINE_BY_LINE|ITEM_FLIGHT_MODES_LAST, NAVIGATION_LINE_BY_LINE|ITEM_FLIGHT_MODES_LAST, NAVIGATION_LINE_BY_LINE|NAVIGATION_LINE_BY_LINE|ITEM_FLIGHT_MODES_LAST, NAVIGATION_LINE_BY_LINE|ITEM_FLIGHT_MODES_LAST, NAVIGATION_LINE_BY_LINE|ITEM_FLIGHT_MODES_LAST, NAVIGATION_LINE_BY_LINE|ITEM_FLIGHT_MODES_LAST, NAVIGATION_LINE_BY_LINE|ITEM_FLIGHT_MODES_LAST, NAVIGATION_LINE_BY_LINE|ITEM_FLIGHT_MODES_LAST, 0}); + + int sub = m_posVert; + + horzpos_t posHorz = m_posHorz; + if (sub==0 && posHorz > 0) { posHorz += 1; } + + if (sub=0) { + displayColumnHeader(STR_PHASES_HEADERS, posHorz); + } + + for (int i=0; i0) ? BLINK|INVERS : INVERS) : 0); + LcdFlags active = (attr && s_editMode>0) ; + switch (j) { + case ITEM_FLIGHT_MODES_NAME: + editName(45, y, p->name, sizeof(p->name), event, attr); + break; + + case ITEM_FLIGHT_MODES_SWITCH: + if (k == 0) + lcd_puts(145, y, "N/A"); + else + putsSwitches(145, y, p->swtch, attr); + if (active) CHECK_INCDEC_MODELSWITCH(event, p->swtch, SWSRC_FIRST_IN_MIXES, SWSRC_LAST_IN_MIXES, isSwitchAvailableInMixes); + break; + + case ITEM_FLIGHT_MODES_TRIM_RUD: + case ITEM_FLIGHT_MODES_TRIM_ELE: + case ITEM_FLIGHT_MODES_TRIM_THR: + case ITEM_FLIGHT_MODES_TRIM_AIL: + { + uint8_t t = j-ITEM_FLIGHT_MODES_TRIM_RUD; + putsTrimMode(155+j*15, y, k, t, attr); + if (active) { + trim_t & v = p->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_FLIGHT_MODES_FADE_IN: + lcd_outdezAtt(272, y, (10/DELAY_STEP)*p->fadeIn, attr|PREC1); + if (active) p->fadeIn = checkIncDec(event, p->fadeIn, 0, DELAY_MAX, EE_MODEL|NO_INCDEC_MARKS); + break; + + case ITEM_FLIGHT_MODES_FADE_OUT: + lcd_outdezAtt(300, y, (10/DELAY_STEP)*p->fadeOut, attr|PREC1); + if (active) p->fadeOut = checkIncDec(event, p->fadeOut, 0, DELAY_MAX, EE_MODEL|NO_INCDEC_MARKS); + break; + + } + } + } +} diff --git a/radio/src/gui/Horus/menu_model_gvars.cpp b/radio/src/gui/Horus/menu_model_gvars.cpp new file mode 100644 index 000000000..bb3d82a0e --- /dev/null +++ b/radio/src/gui/Horus/menu_model_gvars.cpp @@ -0,0 +1,123 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +void onGVARSMenu(const char *result) +{ + int8_t sub = m_posVert; + + if (result == STR_ENABLE_POPUP) { + g_model.gvars[sub].popup = true; + eeDirty(EE_MODEL); + } + else if (result == STR_DISABLE_POPUP) { + g_model.gvars[sub].popup = false; + eeDirty(EE_MODEL); + } + else if (result == STR_CLEAR) { + for (int i=0; i0) ? BLINK|INVERS : INVERS) : 0); + coord_t x = GVARS_FM_COLUMN(j-1); + switch(j) + { + case 0: + editName(MENU_TITLE_LEFT+30, y, g_model.gvars[i].name, LEN_GVAR_NAME, event, attr); + break; + + default: + { + FlightModeData *fm = &g_model.flightModeData[j-1]; + int16_t & v = fm->gvars[i]; + int16_t vmin, vmax; + if (v > GVAR_MAX) { + uint8_t p = v - GVAR_MAX - 1; + if (p >= j-1) p++; + putsFlightMode(x-21, y, p+1, attr); + vmin = GVAR_MAX+1; vmax = GVAR_MAX+MAX_FLIGHT_MODES-1; + } + else { + if (abs(v) >= 1000) + lcd_outdezAtt(x, y+1, v, TINSIZE|attr); + else + lcd_outdezAtt(x, y, v, attr); + vmin = -GVAR_MAX; vmax = GVAR_MAX; + } + if (attr) { + if (event == EVT_KEY_LONG(KEY_ENTER)) { + v = (v > GVAR_MAX ? 0 : GVAR_MAX+1); + eeDirty(EE_MODEL); + } + else if (s_editMode>0) { + v = checkIncDec(event, v, vmin, vmax, EE_MODEL); + } + } + break; + } + } + } + } + + if (m_posHorz < 0 && event==EVT_KEY_LONG(KEY_ENTER)) { + killEvents(event); + if (g_model.gvars[sub].popup) + MENU_ADD_ITEM(STR_DISABLE_POPUP); + else + MENU_ADD_ITEM(STR_ENABLE_POPUP); + MENU_ADD_ITEM(STR_CLEAR); + menuHandler = onGVARSMenu; + } +} diff --git a/radio/src/gui/Horus/menu_model_heli.cpp b/radio/src/gui/Horus/menu_model_heli.cpp new file mode 100644 index 000000000..b5e6c864a --- /dev/null +++ b/radio/src/gui/Horus/menu_model_heli.cpp @@ -0,0 +1,113 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +enum menuModelHeliItems { + ITEM_HELI_SWASHTYPE, + ITEM_HELI_SWASHRING, + ITEM_HELI_ELE, + ITEM_HELI_ELE_WEIGHT, + ITEM_HELI_AIL, + ITEM_HELI_AIL_WEIGHT, + ITEM_HELI_COL, + ITEM_HELI_COL_WEIGHT, + ITEM_HELI_MAX +}; + +#define MODEL_HELI_2ND_COLUMN (230) + +void menuModelHeli(evt_t event) +{ + SIMPLE_MENU(STR_MENUHELISETUP, menuTabModel, e_Heli, ITEM_HELI_MAX, DEFAULT_SCROLLBAR_X); + + int sub = m_posVert; + + for (unsigned int i=0; i0) ? BLINK|INVERS : INVERS); + LcdFlags attr = (sub == k ? blink : 0); + + switch(k) { + case ITEM_HELI_SWASHTYPE: + g_model.swashR.type = selectMenuItem(MODEL_HELI_2ND_COLUMN, y, STR_SWASHTYPE, STR_VSWASHTYPE, g_model.swashR.type, 0, SWASH_TYPE_MAX, attr, event); + break; + + case ITEM_HELI_SWASHRING: + lcd_putsLeft(y, STR_SWASHRING); + lcd_outdezAtt(MODEL_HELI_2ND_COLUMN, y, g_model.swashR.value, LEFT|attr); + if (attr) CHECK_INCDEC_MODELVAR_ZERO(event, g_model.swashR.value, 100); + break; + + case ITEM_HELI_ELE: + lcd_putsLeft(y, STR_ELEVATOR); + putsMixerSource(MODEL_HELI_2ND_COLUMN, y, g_model.swashR.elevatorSource, attr); + if (attr) CHECK_INCDEC_MODELSOURCE(event, g_model.swashR.elevatorSource, 0, MIXSRC_LAST_CH); + break; + + case ITEM_HELI_ELE_WEIGHT: + lcd_puts(MENU_TITLE_LEFT+INDENT_WIDTH, y, STR_WEIGHT); + lcd_outdezAtt(MODEL_HELI_2ND_COLUMN, y, g_model.swashR.elevatorWeight, LEFT|attr); + if (attr) CHECK_INCDEC_MODELVAR(event, g_model.swashR.elevatorWeight, -100, 100); + break; + + case ITEM_HELI_AIL: + lcd_putsLeft(y, STR_AILERON); + putsMixerSource(MODEL_HELI_2ND_COLUMN, y, g_model.swashR.aileronSource, attr); + if (attr) CHECK_INCDEC_MODELSOURCE(event, g_model.swashR.aileronSource, 0, MIXSRC_LAST_CH); + break; + + case ITEM_HELI_AIL_WEIGHT: + lcd_puts(MENU_TITLE_LEFT+INDENT_WIDTH, y, STR_WEIGHT); + lcd_outdezAtt(MODEL_HELI_2ND_COLUMN, y, g_model.swashR.aileronWeight, LEFT|attr); + if (attr) CHECK_INCDEC_MODELVAR(event, g_model.swashR.aileronWeight, -100, 100); + break; + + case ITEM_HELI_COL: + lcd_putsLeft(y, STR_COLLECTIVE); + putsMixerSource(MODEL_HELI_2ND_COLUMN, y, g_model.swashR.collectiveSource, attr); + if (attr) CHECK_INCDEC_MODELSOURCE(event, g_model.swashR.collectiveSource, 0, MIXSRC_LAST_CH); + break; + + case ITEM_HELI_COL_WEIGHT: + lcd_puts(MENU_TITLE_LEFT+INDENT_WIDTH, y, STR_WEIGHT); + lcd_outdezAtt(MODEL_HELI_2ND_COLUMN, y, g_model.swashR.collectiveWeight, LEFT|attr); + if (attr) CHECK_INCDEC_MODELVAR(event, g_model.swashR.collectiveWeight, -100, 100); + break; + + } + } +} diff --git a/radio/src/gui/Horus/menu_model_inputs_mixes.cpp b/radio/src/gui/Horus/menu_model_inputs_mixes.cpp new file mode 100644 index 000000000..a460f88e5 --- /dev/null +++ b/radio/src/gui/Horus/menu_model_inputs_mixes.cpp @@ -0,0 +1,971 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +#define EXPO_ONE_2ND_COLUMN 80 + +#if defined(FLIGHT_MODES) +void displayFlightModes(coord_t x, coord_t y, FlightModesType value, uint8_t attr) +{ + for (int i=0; isrcRaw, x); + return anas[ed->chn]; +} + +coord_t getYCoord(FnFuncP fn, coord_t x) +{ + return limit(0, Y0 - (fn(x * (RESX/WCHART)) * WCHART / RESX), LCD_H-1); +} + +void DrawFunction(FnFuncP fn, int offset) +{ + lcd_vlineStip(X0-offset, Y0-WCHART, WCHART*2, 0xee, CURVE_AXIS_COLOR); + lcd_hlineStip(X0-WCHART-offset, Y0, WCHART*2, 0xee, CURVE_AXIS_COLOR); + + coord_t ymin=0, ymax=0, info=0; + for (int xv=-WCHART; xv<=WCHART; xv++) { + coord_t yv = getYCoord(fn, xv); + + if (ymin == 0 || yv < ymin) + ymin = yv; + if (ymax == 0 || yv > ymax) + ymax = yv; + info += yv*xv; + } +} + +int getLinesCount(uint8_t expo) +{ + int lastch = -1; + uint8_t count = (expo ? MAX_INPUTS : NUM_CHNOUT); + for (int i=0; i<(expo ? MAX_EXPOS : MAX_MIXERS); i++) { + bool valid = (expo ? EXPO_VALID(expoAddress(i)) : mixAddress(i)->srcRaw); + if (!valid) + break; + int ch = (expo ? expoAddress(i)->chn : mixAddress(i)->destCh); + if (ch == lastch) { + count++; + } + else { + lastch = ch; + } + } + return count; +} + +uint8_t getExpoMixCount(uint8_t expo) +{ + uint8_t count = 0; + uint8_t ch ; + + for(int8_t i=(expo ? MAX_EXPOS-1 : MAX_MIXERS-1); i>=0; i--) { + ch = (expo ? EXPO_VALID(expoAddress(i)) : mixAddress(i)->srcRaw); + if (ch != 0) { + count++; + } + } + return count; +} + +bool reachExpoMixCountLimit(uint8_t expo) +{ + // check mixers count limit + if (getExpoMixCount(expo) >= (expo ? MAX_EXPOS : MAX_MIXERS)) { + POPUP_WARNING(expo ? STR_NOFREEEXPO : STR_NOFREEMIXER); + return true; + } + return false; +} + +void deleteExpoMix(uint8_t expo, uint8_t idx) +{ + pauseMixerCalculations(); + if (expo) { + ExpoData *expo = expoAddress(idx); + int input = expo->chn; + memmove(expo, expo+1, (MAX_EXPOS-(idx+1))*sizeof(ExpoData)); + memclear(&g_model.expoData[MAX_EXPOS-1], sizeof(ExpoData)); + if (!isInputAvailable(input)) { + memclear(&g_model.inputNames[input], LEN_INPUT_NAME); + } + } + else { + MixData *mix = mixAddress(idx); + memmove(mix, mix+1, (MAX_MIXERS-(idx+1))*sizeof(MixData)); + memclear(&g_model.mixData[MAX_MIXERS-1], sizeof(MixData)); + } + resumeMixerCalculations(); + eeDirty(EE_MODEL); +} + +// TODO avoid this global s_currCh on ARM boards ... +int8_t s_currCh; +void insertExpoMix(uint8_t expo, uint8_t idx) +{ + pauseMixerCalculations(); + if (expo) { + ExpoData *expo = expoAddress(idx); + memmove(expo+1, expo, (MAX_EXPOS-(idx+1))*sizeof(ExpoData)); + memclear(expo, sizeof(ExpoData)); + expo->srcRaw = (s_currCh > 4 ? MIXSRC_Rud - 1 + s_currCh : MIXSRC_Rud - 1 + channel_order(s_currCh)); + expo->curve.type = CURVE_REF_EXPO; + expo->mode = 3; // pos&neg + expo->chn = s_currCh - 1; + expo->weight = 100; + } + else { + MixData *mix = mixAddress(idx); + memmove(mix+1, mix, (MAX_MIXERS-(idx+1))*sizeof(MixData)); + memclear(mix, sizeof(MixData)); + mix->destCh = s_currCh-1; + mix->srcRaw = s_currCh; + if (!isSourceAvailable(mix->srcRaw)) { + mix->srcRaw = (s_currCh > 4 ? MIXSRC_Rud - 1 + s_currCh : MIXSRC_Rud - 1 + channel_order(s_currCh)); + while (!isSourceAvailable(mix->srcRaw)) { + mix->srcRaw += 1; + } + } + mix->weight = 100; + } + resumeMixerCalculations(); + eeDirty(EE_MODEL); +} + +void copyExpoMix(uint8_t expo, uint8_t idx) +{ + pauseMixerCalculations(); + if (expo) { + ExpoData *expo = expoAddress(idx); + memmove(expo+1, expo, (MAX_EXPOS-(idx+1))*sizeof(ExpoData)); + } + else { + MixData *mix = mixAddress(idx); + memmove(mix+1, mix, (MAX_MIXERS-(idx+1))*sizeof(MixData)); + } + resumeMixerCalculations(); + eeDirty(EE_MODEL); +} + +void memswap(void *a, void *b, uint8_t size) +{ + uint8_t *x = (uint8_t*)a; + uint8_t *y = (uint8_t*)b; + uint8_t temp ; + + while (size--) { + temp = *x; + *x++ = *y; + *y++ = temp; + } +} + +bool swapExpoMix(uint8_t expo, uint8_t &idx, uint8_t up) +{ + void *x, *y; + uint8_t size; + int8_t tgt_idx = (up ? idx-1 : idx+1); + + if (expo) { + x = (ExpoData *)expoAddress(idx); + + if (tgt_idx < 0) { + if (((ExpoData *)x)->chn == 0) + return false; + ((ExpoData *)x)->chn--; + return true; + } + + if (tgt_idx == MAX_EXPOS) { + if (((ExpoData *)x)->chn == NUM_INPUTS-1) + return false; + ((ExpoData *)x)->chn++; + return true; + } + + y = (ExpoData *)expoAddress(tgt_idx); + if(((ExpoData *)x)->chn != ((ExpoData *)y)->chn || !EXPO_VALID((ExpoData *)y)) { + if (up) { + if (((ExpoData *)x)->chn>0) ((ExpoData *)x)->chn--; + else return false; + } + else { + if (((ExpoData *)x)->chnchn++; + else return false; + } + return true; + } + + size = sizeof(ExpoData); + } + else { + x = (MixData *)mixAddress(idx); + + if (tgt_idx < 0) { + if (((MixData *)x)->destCh == 0) + return false; + ((MixData *)x)->destCh--; + return true; + } + + if (tgt_idx == MAX_MIXERS) { + if (((MixData *)x)->destCh == NUM_CHNOUT-1) + return false; + ((MixData *)x)->destCh++; + return true; + } + + y = (MixData *)mixAddress(tgt_idx); + uint8_t destCh = ((MixData *)x)->destCh; + if(!((MixData *)y)->srcRaw || destCh != ((MixData *)y)->destCh) { + if (up) { + if (destCh>0) ((MixData *)x)->destCh--; + else return false; + } + else { + if (destChdestCh++; + else return false; + } + return true; + } + + size = sizeof(MixData); + } + + pauseMixerCalculations(); + memswap(x, y, size); + resumeMixerCalculations(); + + idx = tgt_idx; + return true; +} + +enum ExposFields { + EXPO_FIELD_INPUT_NAME, + EXPO_FIELD_NAME, + EXPO_FIELD_SOURCE, + EXPO_FIELD_SCALE, + EXPO_FIELD_WEIGHT, + EXPO_FIELD_OFFSET, + CASE_CURVES(EXPO_FIELD_CURVE) + CASE_FLIGHT_MODES(EXPO_FIELD_FLIGHT_MODES) + EXPO_FIELD_SWITCH, + EXPO_FIELD_SIDE, + EXPO_FIELD_TRIM, + EXPO_FIELD_MAX +}; + +#define CURVE_ROWS 1 + +void menuModelExpoOne(evt_t event) +{ + ExpoData *ed = expoAddress(s_currIdx); + + SUBMENU(STR_MENUINPUTS, EXPO_FIELD_MAX, EXPO_ONE_2ND_COLUMN+85, { 0, 0, 0, (ed->srcRaw >= MIXSRC_FIRST_TELEM ? (uint8_t)0 : (uint8_t)HIDDEN_ROW), 0, 0, CASE_CURVES(CURVE_ROWS) CASE_FLIGHT_MODES((MAX_FLIGHT_MODES-1) | NAVIGATION_LINE_BY_LINE) 0 /*, ...*/}); + + putsMixerSource(60, MENU_FOOTER_TOP, MIXSRC_FIRST_INPUT+ed->chn, HEADER_COLOR); + + int8_t sub = m_posVert; + + coord_t y = MENU_CONTENT_TOP; + + DrawFunction(expoFn); + + { + int x = getValue(ed->srcRaw); + if (ed->srcRaw >= MIXSRC_FIRST_TELEM) { + putsTelemetryChannelValue(LCD_W-8, 6*FH, ed->srcRaw - MIXSRC_FIRST_TELEM, x); + if (ed->scale > 0) x = (x * 1024) / convertTelemValue(ed->srcRaw - MIXSRC_FIRST_TELEM + 1, ed->scale); + } + else { + lcd_outdezAtt(X0+WCHART, MENU_HEADER_HEIGHT+6*FH, calcRESXto1000(x), PREC1); + } + + x = limit(-1024, x, 1024); + int y = limit(-1024, expoFn(x), 1024); + lcd_outdezAtt(X0-WCHART, MENU_HEADER_HEIGHT+1, calcRESXto1000(y), LEFT|PREC1); + + x = x / (RESX/WCHART); + y = getYCoord(expoFn, x); + + lcd_vlineStip(X0+x, y-3, 7, SOLID, TEXT_INVERTED_BGCOLOR); + lcd_hlineStip(X0+x-3, y, 7, SOLID, TEXT_INVERTED_BGCOLOR); + } + + for (unsigned int k=0; k0 ? BLINK|INVERS : INVERS) : 0); + switch(i) + { + case EXPO_FIELD_INPUT_NAME: + editSingleName(EXPO_ONE_2ND_COLUMN, y, STR_INPUTNAME, g_model.inputNames[ed->chn], sizeof(g_model.inputNames[ed->chn]), event, attr); + break; + + case EXPO_FIELD_NAME: + editSingleName(EXPO_ONE_2ND_COLUMN, y, STR_EXPONAME, ed->name, sizeof(ed->name), event, attr); + break; + + case EXPO_FIELD_SOURCE: + lcd_putsLeft(y, NO_INDENT(STR_SOURCE)); + putsMixerSource(EXPO_ONE_2ND_COLUMN, y, ed->srcRaw, STREXPANDED|attr); + if (attr) ed->srcRaw = checkIncDec(event, ed->srcRaw, INPUTSRC_FIRST, INPUTSRC_LAST, EE_MODEL|INCDEC_SOURCE|NO_INCDEC_MARKS, isInputSourceAvailable); + break; + + case EXPO_FIELD_SCALE: + lcd_putsLeft(y, STR_SCALE); + putsTelemetryChannelValue(EXPO_ONE_2ND_COLUMN, y, (ed->srcRaw - MIXSRC_FIRST_TELEM)/3, convertTelemValue(ed->srcRaw - MIXSRC_FIRST_TELEM + 1, ed->scale), LEFT|attr); + if (attr) ed->scale = checkIncDec(event, ed->scale, 0, maxTelemValue(ed->srcRaw - MIXSRC_FIRST_TELEM + 1), EE_MODEL); + break; + + case EXPO_FIELD_WEIGHT: + lcd_putsLeft(y, STR_WEIGHT); + ed->weight = GVAR_MENU_ITEM(EXPO_ONE_2ND_COLUMN, y, ed->weight, MIN_EXPO_WEIGHT, 100, LEFT|attr, 0, event); + break; + + case EXPO_FIELD_OFFSET: + lcd_putsLeft(y, NO_INDENT(STR_OFFSET)); + ed->offset = GVAR_MENU_ITEM(EXPO_ONE_2ND_COLUMN, y, ed->offset, -100, 100, LEFT|attr, 0, event); + break; + +#if defined(CURVES) + case EXPO_FIELD_CURVE: + lcd_putsLeft(y, STR_CURVE); + editCurveRef(EXPO_ONE_2ND_COLUMN, y, ed->curve, event, attr); + break; +#endif + +#if defined(FLIGHT_MODES) + case EXPO_FIELD_FLIGHT_MODES: + ed->flightModes = editFlightModes(EXPO_ONE_2ND_COLUMN, y, event, ed->flightModes, attr); + break; +#endif + + case EXPO_FIELD_SWITCH: + ed->swtch = switchMenuItem(EXPO_ONE_2ND_COLUMN, y, ed->swtch, attr, event); + break; + + case EXPO_FIELD_SIDE: + ed->mode = 4 - selectMenuItem(EXPO_ONE_2ND_COLUMN, y, STR_SIDE, STR_VSIDE, 4-ed->mode, 1, 3, attr, event); + break; + + case EXPO_FIELD_TRIM: + uint8_t not_stick = (ed->srcRaw > MIXSRC_Ail); + int8_t carryTrim = -ed->carryTrim; + lcd_putsLeft(y, STR_TRIM); + lcd_putsiAtt(EXPO_ONE_2ND_COLUMN, y, STR_VMIXTRIMS, (not_stick && carryTrim == 0) ? 0 : carryTrim+1, m_posHorz==0 ? attr : 0); + if (attr) ed->carryTrim = -checkIncDecModel(event, carryTrim, not_stick ? TRIM_ON : -TRIM_OFF, -TRIM_AIL); + break; + } + y += FH; + } +} + +enum MixFields { + MIX_FIELD_NAME, + MIX_FIELD_SOURCE, + MIX_FIELD_WEIGHT, + MIX_FIELD_OFFSET, + MIX_FIELD_TRIM, + CASE_CURVES(MIX_FIELD_CURVE) + CASE_FLIGHT_MODES(MIX_FIELD_FLIGHT_PHASE) + MIX_FIELD_SWITCH, + // MIX_FIELD_WARNING, + MIX_FIELD_MLTPX, + MIX_FIELD_DELAY_UP, + MIX_FIELD_DELAY_DOWN, + MIX_FIELD_SLOW_UP, + MIX_FIELD_SLOW_DOWN, + MIX_FIELD_COUNT +}; + +void gvarWeightItem(coord_t x, coord_t y, MixData *md, uint8_t attr, evt_t event) +{ + u_int8int16_t weight; + MD_WEIGHT_TO_UNION(md, weight); + weight.word = GVAR_MENU_ITEM(x, y, weight.word, GV_RANGELARGE_WEIGHT_NEG, GV_RANGELARGE_WEIGHT, attr, 0, event); + MD_UNION_TO_WEIGHT(weight, md); +} + +#define GAUGE_WIDTH 33 +#define GAUGE_HEIGHT 6 +void drawOffsetBar(uint8_t x, uint8_t y, MixData * md) +{ + int offset = GET_GVAR(MD_OFFSET(md), GV_RANGELARGE_NEG, GV_RANGELARGE, mixerCurrentFlightMode); + int weight = abs(GET_GVAR(MD_WEIGHT(md), GV_RANGELARGE_NEG, GV_RANGELARGE, mixerCurrentFlightMode)); + int barMin = offset - weight; + int barMax = offset + weight; + if (y > 15) { + lcd_outdezAtt(x-((barMin >= 0) ? 2 : 3), y-6, barMin, TINSIZE|LEFT); + lcd_outdezAtt(x+GAUGE_WIDTH+1, y-6, barMax, TINSIZE); + } + if (barMin < -101) + barMin = -101; + if (barMax > 101) + barMax = 101; + lcd_hlineStip(x-2, y, GAUGE_WIDTH+2, DOTTED); + lcd_hlineStip(x-2, y+GAUGE_HEIGHT, GAUGE_WIDTH+2, DOTTED); + lcd_vline(x-2, y+1, GAUGE_HEIGHT-1); + lcd_vline(x+GAUGE_WIDTH-1, y+1, GAUGE_HEIGHT-1); + if (barMin <= barMax) { + int8_t right = (barMax * GAUGE_WIDTH) / 200; + int8_t left = ((barMin * GAUGE_WIDTH) / 200)-1; + // TODO lcdDrawFilledRect(x+GAUGE_WIDTH/2+left, y+2, right-left, GAUGE_HEIGHT-3); + } + lcd_vline(x+GAUGE_WIDTH/2-1, y, GAUGE_HEIGHT+1); +#if 0 // TODO + if (barMin == -101) { + for (uint8_t i=0; i<3; ++i) { + lcdDrawPoint(x+i, y+4-i); + lcdDrawPoint(x+3+i, y+4-i); + } + } + if (barMax == 101) { + for (uint8_t i=0; i<3; ++i) { + lcdDrawPoint(x+GAUGE_WIDTH-8+i, y+4-i); + lcdDrawPoint(x+GAUGE_WIDTH-5+i, y+4-i); + } + } +#endif +} +#undef GAUGE_WIDTH +#undef GAUGE_HEIGHT + +void menuModelMixOne(evt_t event) +{ + MixData *md2 = mixAddress(s_currIdx) ; + + SUBMENU(s_currCh ? STR_INSERTMIX : STR_EDITMIX, MIX_FIELD_COUNT, 0, { 0, 0, 0, 0, 0, CASE_CURVES(1) CASE_FLIGHT_MODES((MAX_FLIGHT_MODES-1) | NAVIGATION_LINE_BY_LINE) 0 /*, ...*/ }); + + putsChn(80, MENU_FOOTER_TOP, md2->destCh+1, HEADER_COLOR); + + // The separation line between 2 columns + lcd_vlineStip(MENU_COLUMN2_X, DEFAULT_SCROLLBAR_Y, DEFAULT_SCROLLBAR_H, SOLID, HEADER_COLOR); + + int8_t sub = m_posVert; + int8_t editMode = s_editMode; + + for (int k=0; k<2*NUM_BODY_LINES; k++) { + coord_t y; + coord_t x; + if (k >= NUM_BODY_LINES) { + y = MENU_CONTENT_TOP + (k-NUM_BODY_LINES)*FH; + x = MENU_COLUMN2_X; + } + else { + y = MENU_CONTENT_TOP + k*FH; + x = 0; + } + int8_t i = k; + + LcdFlags attr = (sub==i ? (editMode>0 ? BLINK|INVERS : INVERS) : 0); + switch(i) { + case MIX_FIELD_NAME: + editSingleName(x+MIXES_2ND_COLUMN, y, STR_MIXNAME, md2->name, sizeof(md2->name), event, attr); + break; + case MIX_FIELD_SOURCE: + lcd_putsLeft(y, NO_INDENT(STR_SOURCE)); + putsMixerSource(x+MIXES_2ND_COLUMN, y, md2->srcRaw, STREXPANDED|attr); + if (attr) CHECK_INCDEC_MODELSOURCE(event, md2->srcRaw, 1, MIXSRC_LAST); + break; + case MIX_FIELD_WEIGHT: + lcd_putsColumnLeft(x, y, STR_WEIGHT); + gvarWeightItem(x+MIXES_2ND_COLUMN, y, md2, attr|LEFT, event); + break; + case MIX_FIELD_OFFSET: + { + lcd_putsColumnLeft(x, y, NO_INDENT(STR_OFFSET)); + u_int8int16_t offset; + MD_OFFSET_TO_UNION(md2, offset); + offset.word = GVAR_MENU_ITEM(x+MIXES_2ND_COLUMN, y, offset.word, GV_RANGELARGE_OFFSET_NEG, GV_RANGELARGE_OFFSET, attr|LEFT, 0, event); + MD_UNION_TO_OFFSET(offset, md2); +#if 0 + drawOffsetBar(x+MIXES_2ND_COLUMN+22, y, md2); +#endif + break; + } + case MIX_FIELD_TRIM: + lcd_putsColumnLeft(x, y, STR_TRIM); + lcdDrawCheckBox(x+MIXES_2ND_COLUMN, y, !md2->carryTrim, attr); + if (attr) md2->carryTrim = !checkIncDecModel(event, !md2->carryTrim, 0, 1); + break; +#if defined(CURVES) + case MIX_FIELD_CURVE: + { + lcd_putsColumnLeft(x, y, STR_CURVE); + editCurveRef(x+MIXES_2ND_COLUMN, y, md2->curve, event, attr); + break; + } +#endif +#if defined(FLIGHT_MODES) + case MIX_FIELD_FLIGHT_PHASE: + md2->flightModes = editFlightModes(x+MIXES_2ND_COLUMN, y, event, md2->flightModes, attr); + break; +#endif + case MIX_FIELD_SWITCH: + md2->swtch = switchMenuItem(x+MIXES_2ND_COLUMN, y, md2->swtch, attr, event); + break; +#if 0 + case MIX_FIELD_WARNING: + lcd_putsColumnLeft(x+MIXES_2ND_COLUMN, y, STR_MIXWARNING); + if (md2->mixWarn) + lcd_outdezAtt(x+MIXES_2ND_COLUMN, y, md2->mixWarn, attr|LEFT); + else + lcd_putsAtt(x+MIXES_2ND_COLUMN, y, STR_OFF, attr); + if (attr) CHECK_INCDEC_MODELVAR_ZERO(event, md2->mixWarn, 3); + break; +#endif + case MIX_FIELD_MLTPX: + md2->mltpx = selectMenuItem(x+MIXES_2ND_COLUMN, y, STR_MULTPX, STR_VMLTPX, md2->mltpx, 0, 2, attr, event); + break; + case MIX_FIELD_DELAY_UP: + md2->delayUp = EDIT_DELAY(x, y, event, attr, STR_DELAYUP, md2->delayUp); + break; + case MIX_FIELD_DELAY_DOWN: + md2->delayDown = EDIT_DELAY(x, y, event, attr, STR_DELAYDOWN, md2->delayDown); + break; + case MIX_FIELD_SLOW_UP: + md2->speedUp = EDIT_DELAY(x, y, event, attr, STR_SLOWUP, md2->speedUp); + break; + case MIX_FIELD_SLOW_DOWN: + md2->speedDown = EDIT_DELAY(x, y, event, attr, STR_SLOWDOWN, md2->speedDown); + break; + } + } +} + +static uint8_t s_copySrcIdx; +static uint8_t s_copySrcCh; + +#define _STR_MAX(x) PSTR("/" #x) +#define STR_MAX(x) _STR_MAX(x) + +#define EXPO_LINE_WEIGHT_POS 89 +#define EXPO_LINE_SRC_POS 102 +#define EXPO_LINE_FM_POS 138 +#define EXPO_LINE_CURVE_POS 138 +#define EXPO_LINE_SWITCH_POS 182 +#define EXPO_LINE_SIDE_POS 215 +#define EXPO_LINE_SELECT_POS 61 +#define EXPO_LINE_SELECT_WIDTH 244 +#define EXPO_LINE_NAME_POS 238 + +#define MIX_LINE_WEIGHT_POS 69 +#define MIX_LINE_SRC_POS 83 +#define MIX_LINE_FM_POS 142 +#define MIX_LINE_CURVE_POS 142 +#define MIX_LINE_SWITCH_POS 190 +#define MIX_LINE_DELAY_POS 225 +#define MIX_LINE_SELECT_POS 40 +#define MIX_LINE_SELECT_WIDTH 265 + +void lineSurround(bool expo, coord_t y, LcdFlags flags=CURVE_AXIS_COLOR) +{ + lcd_rect(expo ? EXPO_LINE_SELECT_POS : MIX_LINE_SELECT_POS, y-INVERT_VERT_MARGIN, expo ? EXPO_LINE_SELECT_WIDTH : MIX_LINE_SELECT_WIDTH, INVERT_LINE_HEIGHT, WARNING_COLOR|(s_copyMode == COPY_MODE ? SOLID : DOTTED), flags); +} + +void onExpoMixMenu(const char *result) +{ + bool expo = (g_menuStack[g_menuStackPtr] == menuModelExposAll); + uint8_t chn = (expo ? expoAddress(s_currIdx)->chn+1 : mixAddress(s_currIdx)->destCh+1); + + if (result == STR_EDIT) { + pushMenu(expo ? menuModelExpoOne : menuModelMixOne); + } + else if (result == STR_INSERT_BEFORE || result == STR_INSERT_AFTER) { + if (!reachExpoMixCountLimit(expo)) { + s_currCh = chn; + if (result == STR_INSERT_AFTER) { s_currIdx++; m_posVert++; } + insertExpoMix(expo, s_currIdx); + pushMenu(expo ? menuModelExpoOne : menuModelMixOne); + } + } + else if (result == STR_COPY || result == STR_MOVE) { + s_copyMode = (result == STR_COPY ? COPY_MODE : MOVE_MODE); + s_copySrcIdx = s_currIdx; + s_copySrcCh = chn; + s_copySrcRow = m_posVert; + } + else if (result == STR_DELETE) { + deleteExpoMix(expo, s_currIdx); + } +} + +void displayHeaderChannelName(uint8_t ch) +{ + uint8_t len = zlen(g_model.limitData[ch-1].name, sizeof(g_model.limitData[ch-1].name)); + if (len) { + lcd_putsnAtt(COLUMN_HEADER_X, MENU_FOOTER_TOP, g_model.limitData[ch-1].name, len, HEADER_COLOR|ZCHAR); + } +} + +void displayMixInfos(coord_t y, MixData *md) +{ + putsCurveRef(MIX_LINE_CURVE_POS, y, md->curve); + + if (md->swtch) { + putsSwitches(MIX_LINE_SWITCH_POS, y, md->swtch); + } +} + +void displayMixLine(coord_t y, MixData *md) +{ + if (md->name[0]) + lcd_putsnAtt(EXPO_LINE_NAME_POS, y, md->name, sizeof(md->name), ZCHAR); + if (!md->flightModes || ((md->curve.value || md->swtch) && ((get_tmr10ms() / 200) & 1))) + displayMixInfos(y, md); + else + displayFlightModes(MIX_LINE_FM_POS, y, md->flightModes, 0); +} + +void displayExpoInfos(coord_t y, ExpoData *ed) +{ + putsCurveRef(EXPO_LINE_CURVE_POS, y, ed->curve); + if (ed->swtch) { + putsSwitches(EXPO_LINE_SWITCH_POS, y, ed->swtch); + } + if (ed->mode != 3) { + lcd_puts(EXPO_LINE_SIDE_POS, y, ed->mode == 2 ? "\176" : "\177"); + } +} + +void displayExpoLine(coord_t y, ExpoData *ed) +{ + putsMixerSource(EXPO_LINE_SRC_POS, y, ed->srcRaw); + + if (!ed->flightModes || ((ed->curve.value || ed->swtch) && ((get_tmr10ms() / 200) & 1))) + displayExpoInfos(y, ed); + else + displayFlightModes(EXPO_LINE_FM_POS, y, ed->flightModes, 0); + + if (ed->name[0]) { + lcd_putsnAtt(EXPO_LINE_NAME_POS, y, ed->name, sizeof(ed->name), ZCHAR); + } +} + +void menuModelExpoMix(uint8_t expo, evt_t event) +{ + int sub = m_posVert; + + if (s_editMode > 0) + s_editMode = 0; + + uint8_t chn = (expo ? expoAddress(s_currIdx)->chn+1 : mixAddress(s_currIdx)->destCh+1); + + switch (event) + { + case EVT_ENTRY: + case EVT_ENTRY_UP: + s_copyMode = 0; + s_copyTgtOfs = 0; + break; + case EVT_KEY_LONG(KEY_EXIT): + if (s_copyMode && s_copyTgtOfs == 0) { + deleteExpoMix(expo, s_currIdx); + killEvents(event); + event = 0; + } + // no break + case EVT_KEY_BREAK(KEY_EXIT): + if (s_copyMode) { + if (s_copyTgtOfs) { + // cancel the current copy / move operation + if (s_copyMode == COPY_MODE) { + deleteExpoMix(expo, s_currIdx); + } + else { + do { + swapExpoMix(expo, s_currIdx, s_copyTgtOfs > 0); + s_copyTgtOfs += (s_copyTgtOfs < 0 ? +1 : -1); + } while (s_copyTgtOfs != 0); + eeDirty(EE_MODEL); + } + m_posVert = s_copySrcRow; + s_copyTgtOfs = 0; + } + s_copyMode = 0; + event = 0; + } + break; + case EVT_KEY_BREAK(KEY_ENTER): + if ((!s_currCh || (s_copyMode && !s_copyTgtOfs)) && !READ_ONLY()) { + s_copyMode = (s_copyMode == COPY_MODE ? MOVE_MODE : COPY_MODE); + s_copySrcIdx = s_currIdx; + s_copySrcCh = chn; + s_copySrcRow = sub; + break; + } + // no break + + CASE_EVT_ROTARY_BREAK + case EVT_KEY_LONG(KEY_ENTER): + killEvents(event); + if (s_copyTgtOfs) { + s_copyMode = 0; + s_copyTgtOfs = 0; + } + else { + if (READ_ONLY()) { + if (!s_currCh) { + pushMenu(expo ? menuModelExpoOne : menuModelMixOne); + } + } + else { + if (s_copyMode) s_currCh = 0; + if (s_currCh) { + if (reachExpoMixCountLimit(expo)) break; + insertExpoMix(expo, s_currIdx); + pushMenu(expo ? menuModelExpoOne : menuModelMixOne); + s_copyMode = 0; + } + else { + event = 0; + s_copyMode = 0; + MENU_ADD_ITEM(STR_EDIT); + MENU_ADD_ITEM(STR_INSERT_BEFORE); + MENU_ADD_ITEM(STR_INSERT_AFTER); + MENU_ADD_ITEM(STR_COPY); + MENU_ADD_ITEM(STR_MOVE); + MENU_ADD_ITEM(STR_DELETE); + menuHandler = onExpoMixMenu; + } + } + } + break; + case EVT_KEY_LONG(KEY_LEFT): + case EVT_KEY_LONG(KEY_RIGHT): + if (s_copyMode && !s_copyTgtOfs) { + if (reachExpoMixCountLimit(expo)) break; + s_currCh = chn; + if (event == EVT_KEY_LONG(KEY_RIGHT)) { s_currIdx++; m_posVert++; } + insertExpoMix(expo, s_currIdx); + pushMenu(expo ? menuModelExpoOne : menuModelMixOne); + s_copyMode = 0; + killEvents(event); + } + break; + case EVT_KEY_FIRST(KEY_MOVE_UP): + case EVT_KEY_REPT(KEY_MOVE_UP): + case EVT_KEY_FIRST(KEY_MOVE_DOWN): + case EVT_KEY_REPT(KEY_MOVE_DOWN): + if (s_copyMode) { + uint8_t key = (event & 0x1f); + uint8_t next_ofs = ((IS_ROTARY_UP(event) || key==KEY_MOVE_UP) ? s_copyTgtOfs - 1 : s_copyTgtOfs + 1); + + if (s_copyTgtOfs==0 && s_copyMode==COPY_MODE) { + // insert a mix on the same channel (just above / just below) + if (reachExpoMixCountLimit(expo)) break; + copyExpoMix(expo, s_currIdx); + if (IS_ROTARY_DOWN(event) || key==KEY_MOVE_DOWN) s_currIdx++; + else if (sub-s_pgOfs >= 6) s_pgOfs++; + } + else if (next_ofs==0 && s_copyMode==COPY_MODE) { + // delete the mix + deleteExpoMix(expo, s_currIdx); + if (IS_ROTARY_UP(event) || key==KEY_MOVE_UP) s_currIdx--; + } + else { + // only swap the mix with its neighbor + if (!swapExpoMix(expo, s_currIdx, IS_ROTARY_UP(event) || key==KEY_MOVE_UP)) break; + eeDirty(EE_MODEL); + } + + s_copyTgtOfs = next_ofs; + } + break; + } + + int linesCount = getLinesCount(expo); + SIMPLE_MENU(expo ? STR_MENUINPUTS : STR_MIXER, menuTabModel, expo ? e_InputsAll : e_MixAll, linesCount, DEFAULT_SCROLLBAR_X); + + char str[6]; + sprintf(str, "%d/%d", getExpoMixCount(expo), expo ? MAX_EXPOS : MAX_MIXERS); + lcd_putsAtt(60, MENU_FOOTER_TOP, str, HEADER_COLOR); + + sub = m_posVert; + s_currCh = 0; + int cur = 0; + int i = 0; + + for (int ch=1; ch<=(expo ? NUM_INPUTS : NUM_CHNOUT); ch++) { + void *pointer = NULL; MixData * &md = (MixData * &)pointer; ExpoData * &ed = (ExpoData * &)pointer; + coord_t y = MENU_CONTENT_TOP + (cur-s_pgOfs)*FH; + if (expo ? (ichn+1 == ch && EXPO_VALID(ed)) : (isrcRaw && md->destCh+1 == ch)) { + if (cur-s_pgOfs >= 0 && cur-s_pgOfs < NUM_BODY_LINES) { + if (expo) { + putsMixerSource(MENU_TITLE_LEFT, y, ch); + } + else { + putsChn(MENU_TITLE_LEFT, y, ch, 0); // show CHx + } + } + uint8_t mixCnt = 0; + do { + if (s_copyMode) { + if (s_copyMode == MOVE_MODE && cur-s_pgOfs >= 0 && cur-s_pgOfs < NUM_BODY_LINES && s_copySrcCh == ch && s_copyTgtOfs != 0 && i == (s_copySrcIdx + (s_copyTgtOfs<0))) { + lineSurround(expo, y); + cur++; y+=FH; + } + if (s_currIdx == i) { + sub = m_posVert = cur; + s_currCh = ch; + } + } + else if (sub == cur) { + s_currIdx = i; + } + if (cur-s_pgOfs >= 0 && cur-s_pgOfs < NUM_BODY_LINES) { + LcdFlags attr = ((s_copyMode || sub != cur) ? 0 : INVERS); + if (expo) { + ed->weight = GVAR_MENU_ITEM(EXPO_LINE_WEIGHT_POS, y, ed->weight, MIN_EXPO_WEIGHT, 100, attr | (isExpoActive(i) ? BOLD : 0), 0, 0); + displayExpoLine(y, ed); + } + else { + if (attr) { + displayHeaderChannelName(ch); + } + + if (mixCnt > 0) lcd_putsiAtt(6, y, STR_VMLTPX2, md->mltpx, 0); + + putsMixerSource(MIX_LINE_SRC_POS, y, md->srcRaw); + + gvarWeightItem(MIX_LINE_WEIGHT_POS, y, md, attr | (isMixActive(i) ? BOLD : 0), event); + + displayMixLine(y, md); + + char cs[] = " "; + if (md->speedDown || md->speedUp) + cs[0] = 'S'; + if (md->delayUp || md->delayDown) + cs[0] = (cs[0] =='S' ? '*' : 'D'); + lcd_puts(MIX_LINE_DELAY_POS, y, cs); + } + if (s_copyMode) { + if ((s_copyMode==COPY_MODE || s_copyTgtOfs == 0) && s_copySrcCh == ch && i == (s_copySrcIdx + (s_copyTgtOfs<0))) { + /* draw a border around the raw on selection mode (copy/move) */ + lineSurround(expo, y); + } + if (cur == sub) { + /* invert the raw when it's the current one */ + lineSurround(expo, y, WARNING_COLOR); + } + } + } + cur++; y+=FH; mixCnt++; i++; if (expo) ed++; else md++; + } while (expo ? (ichn+1 == ch && EXPO_VALID(ed)) : (isrcRaw && md->destCh+1 == ch)); + if (s_copyMode == MOVE_MODE && cur-s_pgOfs >= 0 && cur-s_pgOfs < NUM_BODY_LINES && s_copySrcCh == ch && i == (s_copySrcIdx + (s_copyTgtOfs<0))) { + lineSurround(expo, y); + cur++; y+=FH; + } + } + else { + uint8_t attr = 0; + if (sub == cur) { + s_currIdx = i; + s_currCh = ch; + if (!s_copyMode) { + attr = INVERS; + } + } + if (cur-s_pgOfs >= 0 && cur-s_pgOfs < NUM_BODY_LINES) { + if (expo) { + putsMixerSource(MENU_TITLE_LEFT, y, ch, attr); + } + else { + putsChn(MENU_TITLE_LEFT, y, ch, attr); // show CHx + if (attr) { + displayHeaderChannelName(ch); + } + } + if (s_copyMode == MOVE_MODE && s_copySrcCh == ch) { + lineSurround(expo, y); + } + } + cur++; y+=FH; + } + } + + if (sub >= linesCount-1) m_posVert = linesCount-1; +} + +void menuModelExposAll(evt_t event) +{ + return menuModelExpoMix(1, event); +} + +void menuModelMixAll(evt_t event) +{ + return menuModelExpoMix(0, event); +} diff --git a/radio/src/gui/Horus/menu_model_limits.cpp b/radio/src/gui/Horus/menu_model_limits.cpp new file mode 100644 index 000000000..2d9c11bee --- /dev/null +++ b/radio/src/gui/Horus/menu_model_limits.cpp @@ -0,0 +1,290 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +bool isThrottleOutput(uint8_t ch) +{ + for (uint8_t i=0; idestCh==ch && mix->srcRaw==MIXSRC_Thr) + return true; + } + return false; +} + +enum LimitsItems { + ITEM_LIMITS_CH_NAME, + ITEM_LIMITS_OFFSET, + ITEM_LIMITS_MIN, + ITEM_LIMITS_MAX, + ITEM_LIMITS_DIRECTION, +#if defined(CURVES) + ITEM_LIMITS_CURVE, +#endif +#if defined(PPM_CENTER_ADJUSTABLE) + ITEM_LIMITS_PPM_CENTER, +#endif +#if defined(PPM_LIMITS_SYMETRICAL) + ITEM_LIMITS_SYMETRICAL, +#endif + ITEM_LIMITS_COUNT, + ITEM_LIMITS_MAXROW = ITEM_LIMITS_COUNT-1 +}; + +#if defined(PPM_CENTER_ADJUSTABLE) + #define LIMITS_NAME_POS 44 + #define LIMITS_OFFSET_POS 136 + #define LIMITS_MIN_POS 175 + #define LIMITS_DIRECTION_POS 177 + #define LIMITS_MAX_POS 214 + #define LIMITS_REVERT_POS 218 + #define LIMITS_CURVE_POS 232 + #define LIMITS_PPM_CENTER_POS 292 + #define LIMITS_SYMETRICAL_POS 298 +#else + #define LIMITS_NAME_POS 44 + #define LIMITS_OFFSET_POS 136 + #define LIMITS_MIN_POS 178 + #define LIMITS_DIRECTION_POS 181 + #define LIMITS_MAX_POS 218 + #define LIMITS_REVERT_POS 228 + #define LIMITS_CURVE_POS 258 + #define LIMITS_SYMETRICAL_POS 294 +#endif + +#define LIMITS_MIN_MAX_OFFSET 1000 +#define CONVERT_US_MIN_MAX(x) (((x)*1280)/250) + +#if defined(PPM_UNIT_US) + #define SET_MIN_MAX(x, val) x = ((val)*250)/128 + #define MIN_MAX_DISPLAY(x) CONVERT_US_MIN_MAX(x) +#else + #define MIN_MAX_DISPLAY(x) (x) + #define SET_MIN_MAX(x, val) x = (val) +#endif + +void onLimitsMenu(const char *result) +{ + uint8_t ch = m_posVert - 1; + + if (result == STR_RESET) { + LimitData *ld = limitAddress(ch); + ld->min = 0; + ld->max = 0; + ld->offset = 0; + ld->ppmCenter = 0; + ld->revert = false; + ld->curve = 0; + } + else if (result == STR_COPY_STICKS_TO_OFS) { + copySticksToOffset(ch); + } + else if (result == STR_COPY_TRIMS_TO_OFS) { + copyTrimsToOffset(ch); + } +} + +void menuModelLimits(evt_t event) +{ + MENU(STR_MENULIMITS, menuTabModel, e_Limits, NUM_CHNOUT+1, DEFAULT_SCROLLBAR_X, + { NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, + NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, + NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, + NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, NAVIGATION_LINE_BY_LINE|ITEM_LIMITS_MAXROW, + 0 }); + + uint32_t sub = m_posVert; + + if (sub < NUM_CHNOUT) { +#if defined(PPM_CENTER_ADJUSTABLE) || defined(PPM_UNIT_US) + lcd_outdezAtt(100, MENU_FOOTER_TOP, PPM_CH_CENTER(sub)+channelOutputs[sub]/2, HEADER_COLOR, STR_US); +#else + lcd_outdezAtt(100, MENU_FOOTER_TOP, calcRESXto1000(channelOutputs[sub]), HEADER_COLOR|PREC1); +#endif + } + + if (sub=0) { + displayColumnHeader(STR_LIMITS_HEADERS, m_posHorz); + } + + if (s_warning_result) { + s_warning_result = 0; + LimitData *ld = limitAddress(sub); + ld->revert = !ld->revert; + eeDirty(EE_MODEL); + } + + for (int i=0; irevert) ? -LIMIT_OFS(ld) : LIMIT_OFS(ld); + char swVal[2] = "-"; // '-', '<', '>' + if ((channelOutputs[k] - v) > 50) swVal[0] = (ld->revert ? 127 : 126); // Switch to raw inputs? - remove trim! + if ((channelOutputs[k] - v) < -50) swVal[0] = (ld->revert ? 126 : 127); + lcd_puts(LIMITS_DIRECTION_POS, y, swVal); + + int limit = (g_model.extendedLimits ? LIMIT_EXT_MAX : 1000); + + putsChn(MENU_TITLE_LEFT, y, k+1, (sub==k && m_posHorz < 0) ? INVERS : 0); + if (sub==k && m_posHorz < 0 && event==EVT_KEY_LONG(KEY_ENTER) && !READ_ONLY()) { + killEvents(event); + MENU_ADD_ITEM(STR_RESET); + MENU_ADD_ITEM(STR_COPY_TRIMS_TO_OFS); + MENU_ADD_ITEM(STR_COPY_STICKS_TO_OFS); + menuHandler = onLimitsMenu; + } + + for (uint8_t j=0; j0) ? BLINK|INVERS : INVERS) : 0); + uint8_t active = (attr && s_editMode>0) ; + if (active) STICK_SCROLL_DISABLE(); + switch(j) + { + case ITEM_LIMITS_CH_NAME: + editName(LIMITS_NAME_POS, y, ld->name, sizeof(ld->name), event, attr); + break; + + case ITEM_LIMITS_OFFSET: + if (GV_IS_GV_VALUE(ld->offset, -1000, 1000) || (attr && event == EVT_KEY_LONG(KEY_ENTER))) { + ld->offset = GVAR_MENU_ITEM(LIMITS_OFFSET_POS, y, ld->offset, -1000, 1000, attr|PREC1, 0, event); + break; + } + +#if defined(PPM_UNIT_US) + lcd_outdezAtt(LIMITS_OFFSET_POS, y, ((int32_t)ld->offset*128) / 25, attr|PREC1); +#else + lcd_outdezAtt(LIMITS_OFFSET_POS, y, ld->offset, attr|PREC1); +#endif + if (active) { + ld->offset = checkIncDec(event, ld->offset, -1000, 1000, EE_MODEL, NULL, stops1000); + } + else if (attr && event==EVT_KEY_LONG(KEY_MENU)) { + copySticksToOffset(k); + s_editMode = 0; + } + break; + + case ITEM_LIMITS_MIN: + if (GV_IS_GV_VALUE(ld->min, -GV_RANGELARGE, GV_RANGELARGE) || (attr && event == EVT_KEY_LONG(KEY_ENTER))) { + ld->min = GVAR_MENU_ITEM(LIMITS_MIN_POS, y, ld->min, -LIMIT_EXT_MAX, LIMIT_EXT_MAX, attr|PREC1, 0, event); + break; + } + lcd_outdezAtt(LIMITS_MIN_POS, y, MIN_MAX_DISPLAY(ld->min-LIMITS_MIN_MAX_OFFSET), attr|PREC1); + if (active) ld->min = LIMITS_MIN_MAX_OFFSET + checkIncDec(event, ld->min-LIMITS_MIN_MAX_OFFSET, -limit, 0, EE_MODEL, NULL, stops1000); + break; + + case ITEM_LIMITS_MAX: + if (GV_IS_GV_VALUE(ld->max, -GV_RANGELARGE, GV_RANGELARGE) || (attr && event == EVT_KEY_LONG(KEY_ENTER))) { + ld->max = GVAR_MENU_ITEM(LIMITS_MAX_POS, y, ld->max, -LIMIT_EXT_MAX, LIMIT_EXT_MAX, attr|PREC1, 0, event); + break; + } + lcd_outdezAtt(LIMITS_MAX_POS, y, MIN_MAX_DISPLAY(ld->max+LIMITS_MIN_MAX_OFFSET), attr|PREC1); + if (active) ld->max = -LIMITS_MIN_MAX_OFFSET + checkIncDec(event, ld->max+LIMITS_MIN_MAX_OFFSET, 0, +limit, EE_MODEL, NULL, stops1000); + break; + + case ITEM_LIMITS_DIRECTION: + { + uint8_t revert = ld->revert; +#if defined(PPM_CENTER_ADJUSTABLE) + lcd_putsAtt(LIMITS_REVERT_POS, y, revert ? "\177" : "\176", attr); +#else + lcd_putsiAtt(LIMITS_REVERT_POS, y, STR_MMMINV, revert, attr); +#endif + if (active) { + uint8_t revert_new = checkIncDecModel(event, revert, 0, 1); + if (checkIncDec_Ret && isThrottleOutput(k)) { + POPUP_CONFIRMATION(STR_INVERT_THR); + } + else { + ld->revert = revert_new; + } + } + break; + } + +#if defined(CURVES) + case ITEM_LIMITS_CURVE: + putsCurve(LIMITS_CURVE_POS, y, ld->curve, attr); + if (attr && event==EVT_KEY_LONG(KEY_ENTER) && ld->curve>0) { + s_curveChan = (ld->curve<0 ? -ld->curve-1 : ld->curve-1); + pushMenu(menuModelCurveOne); + } + if (active) { + CHECK_INCDEC_MODELVAR(event, ld->curve, -MAX_CURVES, +MAX_CURVES); + } + break; +#endif + +#if defined(PPM_CENTER_ADJUSTABLE) + case ITEM_LIMITS_PPM_CENTER: + lcd_outdezAtt(LIMITS_PPM_CENTER_POS, y, PPM_CENTER+ld->ppmCenter, attr); + if (active) { + CHECK_INCDEC_MODELVAR(event, ld->ppmCenter, -PPM_CENTER_MAX, +PPM_CENTER_MAX); + } + break; +#endif + +#if defined(PPM_LIMITS_SYMETRICAL) + case ITEM_LIMITS_SYMETRICAL: + lcd_putsAtt(LIMITS_SYMETRICAL_POS, y, ld->symetrical ? "=" : "\306", attr); + if (active) { + CHECK_INCDEC_MODELVAR_ZERO(event, ld->symetrical, 1); + } + break; +#endif + } + } + } +} diff --git a/radio/src/gui/Horus/menu_model_logical_switches.cpp b/radio/src/gui/Horus/menu_model_logical_switches.cpp new file mode 100644 index 000000000..7d20c6eef --- /dev/null +++ b/radio/src/gui/Horus/menu_model_logical_switches.cpp @@ -0,0 +1,275 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +enum LogicalSwitchFields { + LS_FIELD_FUNCTION, + LS_FIELD_V1, + LS_FIELD_V2, + LS_FIELD_V3, + LS_FIELD_ANDSW, + LS_FIELD_DURATION, + LS_FIELD_DELAY, + LS_FIELD_COUNT, + LS_FIELD_LAST = LS_FIELD_COUNT-1 +}; + +#define CSW_1ST_COLUMN 40 +#define CSW_2ND_COLUMN 85 +#define CSW_3RD_COLUMN 130 +#define CSW_4TH_COLUMN 185 +#define CSW_5TH_COLUMN 225 +#define CSW_6TH_COLUMN 270 + +#define INCDEC_DECLARE_VARS(f) uint8_t incdecFlag = (f); IsValueAvailable isValueAvailable = NULL +#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) + +void putsEdgeDelayParam(coord_t x, coord_t y, LogicalSwitchData *cs, uint8_t lattr, uint8_t rattr) +{ + char s[32]; + div_t left = div(lswTimerValue(cs->v2), 10); + char sleft[10]; + sprintf(sleft, "%d.%d", left.quot, left.rem); + div_t right = div(lswTimerValue(cs->v2+cs->v3), 10); + char sright[10]; + sprintf(sright, "%d.%d", right.quot, right.rem); + sprintf(s, "[%s:%s]", sleft, sright); + lcd_puts(x-4, y, s); + /* if (cs->v3 < 0) + lcd_putsAtt(lcdLastPos+3, y, "<<", rattr); + else if (cs->v3 == 0) + lcd_putsAtt(lcdLastPos+3, y, "--", rattr); */ +} + +void onLogicalSwitchesMenu(const char *result) +{ + int8_t sub = m_posVert; + LogicalSwitchData * cs = lswAddress(sub); + + if (result == STR_COPY) { + clipboard.type = CLIPBOARD_TYPE_CUSTOM_SWITCH; + clipboard.data.csw = *cs; + } + else if (result == STR_PASTE) { + *cs = clipboard.data.csw; + eeDirty(EE_MODEL); + } + else if (result == STR_CLEAR) { + memset(cs, 0, sizeof(LogicalSwitchData)); + eeDirty(EE_MODEL); + } +} + +void menuModelLogicalSwitches(evt_t event) +{ + INCDEC_DECLARE_VARS(EE_MODEL); + + MENU(STR_MENULOGICALSWITCHES, menuTabModel, e_LogicalSwitches, NUM_LOGICAL_SWITCH, DEFAULT_SCROLLBAR_X, { NAVIGATION_LINE_BY_LINE|LS_FIELD_LAST/*repeated...*/} ); + + int k = 0; + int sub = m_posVert; + horzpos_t horz = m_posHorz; + + if (horz>=0) { + displayColumnHeader(STR_CSW_HEADERS, horz); + } + + if (horz<0 && event==EVT_KEY_LONG(KEY_ENTER) && !READ_ONLY()) { + killEvents(event); + LogicalSwitchData * cs = lswAddress(sub); + if (cs->func) + MENU_ADD_ITEM(STR_COPY); + if (clipboard.type == CLIPBOARD_TYPE_CUSTOM_SWITCH) + MENU_ADD_ITEM(STR_PASTE); + if (cs->func || cs->v1 || cs->v2 || cs->delay || cs->duration || cs->andsw) + MENU_ADD_ITEM(STR_CLEAR); + menuHandler = onLogicalSwitchesMenu; + } + + for (int i=0; i0) ? BLINK|INVERS : INVERS) : 0); + LcdFlags attr1 = (horz==1 ? attr : 0); + LcdFlags attr2 = (horz==2 ? attr : 0); + LogicalSwitchData * cs = lswAddress(k); + + // CSW name + unsigned int sw = SWSRC_SW1+k; + putsSwitches(MENU_TITLE_LEFT, y, sw, (getSwitch(sw) ? 0/*BOLD*/ : 0) | ((sub==k && CURSOR_ON_LINE()) ? INVERS : 0)); + + // CSW func + lcd_putsiAtt(CSW_1ST_COLUMN, y, STR_VCSWFUNC, cs->func, horz==0 ? attr : 0); + + // CSW params + unsigned int cstate = lswFamily(cs->func); + int v1_val=cs->v1, v1_min=0, v1_max=MIXSRC_LAST_TELEM; + int v2_min=0, v2_max=MIXSRC_LAST_TELEM; + int v3_min=-1, v3_max=100; + + if (cstate == LS_FAMILY_BOOL || cstate == LS_FAMILY_STICKY) { + putsSwitches(CSW_2ND_COLUMN, y, cs->v1, attr1); + putsSwitches(CSW_3RD_COLUMN, y, cs->v2, attr2); + v1_min = SWSRC_FIRST_IN_LOGICAL_SWITCHES; v1_max = SWSRC_LAST_IN_LOGICAL_SWITCHES; + v2_min = SWSRC_FIRST_IN_LOGICAL_SWITCHES; v2_max = SWSRC_LAST_IN_LOGICAL_SWITCHES; + INCDEC_SET_FLAG(EE_MODEL | INCDEC_SWITCH); + INCDEC_ENABLE_CHECK(isSwitchAvailableInLogicalSwitches); + } + else if (cstate == LS_FAMILY_EDGE) { + putsSwitches(CSW_2ND_COLUMN, y, cs->v1, attr1); + putsEdgeDelayParam(CSW_3RD_COLUMN, y, cs, attr2, (horz==LS_FIELD_V3 ? attr : 0)); + v1_min = SWSRC_FIRST_IN_LOGICAL_SWITCHES; v1_max = SWSRC_LAST_IN_LOGICAL_SWITCHES; + v2_min=-129; v2_max = 122; + v3_max = 222 - cs->v2; + if (horz == 1) { + INCDEC_SET_FLAG(EE_MODEL | INCDEC_SWITCH); + INCDEC_ENABLE_CHECK(isSwitchAvailableInLogicalSwitches); + } + else { + INCDEC_SET_FLAG(EE_MODEL); + INCDEC_ENABLE_CHECK(NULL); + } + } + else if (cstate == LS_FAMILY_COMP) { + v1_val = (uint8_t)cs->v1; + putsMixerSource(CSW_2ND_COLUMN, y, v1_val, attr1); + putsMixerSource(CSW_3RD_COLUMN, y, cs->v2, attr2); + INCDEC_SET_FLAG(EE_MODEL | INCDEC_SOURCE); + INCDEC_ENABLE_CHECK(isSourceAvailable); + } + else if (cstate == LS_FAMILY_TIMER) { + lcd_outdezAtt(CSW_2ND_COLUMN, y, lswTimerValue(cs->v1), LEFT|PREC1|attr1); + lcd_outdezAtt(CSW_3RD_COLUMN, y, lswTimerValue(cs->v2), LEFT|PREC1|attr2); + v1_min = v2_min = -128; + v1_max = v2_max = 122; + INCDEC_SET_FLAG(EE_MODEL); + INCDEC_ENABLE_CHECK(NULL); + } + else { + v1_val = (uint8_t)cs->v1; + putsMixerSource(CSW_2ND_COLUMN, y, v1_val, attr1); + if (horz == 1) { + INCDEC_SET_FLAG(EE_MODEL | INCDEC_SOURCE); + INCDEC_ENABLE_CHECK(isSourceAvailableInCustomSwitches); + } + else { + INCDEC_SET_FLAG(EE_MODEL); + INCDEC_ENABLE_CHECK(NULL); + } + v2_max = getMaximumValue(v1_val); + v2_min = - v2_min; + putsChannelValue(CSW_3RD_COLUMN, y, v1_val, v1_val <= MIXSRC_LAST_CH ? calc100toRESX(cs->v2) : cs->v2, LEFT|attr2); + } + + // CSW AND switch + putsSwitches(CSW_4TH_COLUMN, y, cs->andsw, horz==LS_FIELD_ANDSW ? attr : 0); + + // CSW duration + if (cs->duration > 0) + lcd_outdezAtt(CSW_5TH_COLUMN, y, cs->duration, (horz==LS_FIELD_DURATION ? attr : 0)|PREC1|LEFT); + else + lcd_putsiAtt(CSW_5TH_COLUMN, y, STR_MMMINV, 0, horz==LS_FIELD_DURATION ? attr : 0); + + // CSW delay + if (cstate == LS_FAMILY_EDGE) { + lcd_puts(CSW_6TH_COLUMN, y, STR_NA); + if (attr && horz == LS_FIELD_DELAY) { + REPEAT_LAST_CURSOR_MOVE(); + } + } + else if (cs->delay > 0) { + lcd_outdezAtt(CSW_6TH_COLUMN, y, cs->delay, (horz==LS_FIELD_DELAY ? attr : 0)|PREC1|LEFT); + } + else { + lcd_putsiAtt(CSW_6TH_COLUMN, y, STR_MMMINV, 0, horz==LS_FIELD_DELAY ? attr : 0); + } + + if (attr && horz == LS_FIELD_V3 && cstate != LS_FAMILY_EDGE) { + REPEAT_LAST_CURSOR_MOVE(); + } + + if (s_editMode>0 && attr) { + switch (horz) { + case LS_FIELD_FUNCTION: + { + cs->func = checkIncDec(event, cs->func, 0, LS_FUNC_MAX, EE_MODEL, isLogicalSwitchFunctionAvailable); + uint8_t new_cstate = lswFamily(cs->func); + if (cstate != new_cstate) { + if (new_cstate == LS_FAMILY_TIMER) { + cs->v1 = cs->v2 = -119; + } + else if (new_cstate == LS_FAMILY_EDGE) { + cs->v1 = 0; cs->v2 = -129; cs->v3 = 0; + } + else { + cs->v1 = cs->v2 = 0; + } + } + break; + } + case LS_FIELD_V1: + cs->v1 = CHECK_INCDEC_PARAM(event, v1_val, v1_min, v1_max); + break; + case LS_FIELD_V2: + cs->v2 = CHECK_INCDEC_PARAM(event, cs->v2, v2_min, v2_max); + if (cstate==LS_FAMILY_OFS && cs->v1!=0 && event==EVT_KEY_LONG(KEY_ENTER)) { + killEvents(event); + getvalue_t x = getValue(v1_val); + if (v1_val <= MIXSRC_LAST_CH) + cs->v2 = calcRESXto100(x); + eeDirty(EE_MODEL); + } + break; + case LS_FIELD_V3: + cs->v3 = CHECK_INCDEC_PARAM(event, cs->v3, v3_min, v3_max); + break; + case LS_FIELD_ANDSW: + INCDEC_SET_FLAG(EE_MODEL | INCDEC_SWITCH); + INCDEC_ENABLE_CHECK(isSwitchAvailableInLogicalSwitches); + cs->andsw = CHECK_INCDEC_PARAM(event, cs->andsw, -MAX_LS_ANDSW, MAX_LS_ANDSW); + break; + case LS_FIELD_DURATION: + CHECK_INCDEC_MODELVAR_ZERO(event, cs->duration, MAX_LS_DURATION); + break; + case LS_FIELD_DELAY: + CHECK_INCDEC_MODELVAR_ZERO(event, cs->delay, MAX_LS_DELAY); + break; + } + } + } +} diff --git a/radio/src/gui/Horus/menu_model_select.cpp b/radio/src/gui/Horus/menu_model_select.cpp new file mode 100644 index 000000000..82d604c65 --- /dev/null +++ b/radio/src/gui/Horus/menu_model_select.cpp @@ -0,0 +1,293 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +#define POS_MODEL_NAME 35 +#define POS_MODEL_SIZE 170 + +void onModelSelectMenu(const char *result) +{ + int sub = m_posVert; + + if (result == STR_SELECT_MODEL || result == STR_CREATE_MODEL) { + selectModel(sub); + } + else if (result == STR_COPY_MODEL) { + s_copyMode = COPY_MODE; + s_copyTgtOfs = 0; + s_copySrcRow = -1; + } + else if (result == STR_MOVE_MODEL) { + s_copyMode = MOVE_MODE; + s_copyTgtOfs = 0; + s_copySrcRow = -1; + } + else if (result == STR_BACKUP_MODEL) { + eeCheck(true); // force writing of current model data before this is changed + POPUP_WARNING(eeBackupModel(sub)); + } + else if (result == STR_RESTORE_MODEL || result == STR_UPDATE_LIST) { + if (!listSdFiles(MODELS_PATH, MODELS_EXT, MENU_LINE_LENGTH-1, NULL)) { + POPUP_WARNING(STR_NO_MODELS_ON_SD); + s_menu_flags = 0; + } + } + else if (result == STR_DELETE_MODEL) { + POPUP_CONFIRMATION(STR_DELETEMODEL); + SET_WARNING_INFO(modelHeaders[sub].name, sizeof(g_model.header.name), ZCHAR); + } + else { + // The user choosed a file on SD to restore + POPUP_WARNING(eeRestoreModel(sub, (char *)result)); + if (!s_warning && g_eeGeneral.currModel == sub) + eeLoadModel(sub); + } +} + +char *strAppendModelSize(char *dest, int size) +{ + char s[8] = "---"; + if (size) sprintf(s, "%d", size); + dest = strSetCursor(dest, POS_MODEL_SIZE-getTextWidth(s)); + return strAppend(dest, s); +} + +void menuModelSelect(evt_t event) +{ + if (s_warning_result) { + s_warning_result = 0; + eeDeleteModel(m_posVert); // delete file + s_copyMode = 0; + event = EVT_ENTRY_UP; + } + + evt_t _event_ = event; + event = (IS_ROTARY_BREAK(event) || IS_ROTARY_LONG(event) ? 0 : event); + if ((s_copyMode && EVT_KEY_MASK(event) == KEY_EXIT) || event == EVT_KEY_BREAK(KEY_EXIT)) { + event = 0; + } + + int8_t oldSub = m_posVert; + + // TODO SIMPLE_MENU(STR_MENUMODELSEL, menuTabModel, e_ModelSelect, MAX_MODELS, DEFAULT_SCROLLBAR_X); + + if (s_editMode > 0) s_editMode = 0; + + int8_t sub = m_posVert; + + switch (_event_) + { + case EVT_ENTRY: + m_posVert = sub = g_eeGeneral.currModel; + if (sub >= NUM_BODY_LINES) s_pgOfs = sub-(NUM_BODY_LINES-1); + s_copyMode = 0; + s_editMode = EDIT_MODE_INIT; + eeCheck(true); + break; + case EVT_KEY_LONG(KEY_EXIT): + if (s_copyMode && s_copyTgtOfs == 0 && g_eeGeneral.currModel != sub && eeModelExists(sub)) { + POPUP_CONFIRMATION(STR_DELETEMODEL); + SET_WARNING_INFO(modelHeaders[sub].name, sizeof(g_model.header.name), ZCHAR); + killEvents(_event_); + break; + } + // no break + case EVT_KEY_BREAK(KEY_EXIT): + if (s_copyMode) { + sub = m_posVert = (s_copyMode == MOVE_MODE || s_copySrcRow<0) ? (MAX_MODELS+sub+s_copyTgtOfs) % MAX_MODELS : s_copySrcRow; + s_copyMode = 0; + } + else { + if (m_posVert != g_eeGeneral.currModel) { + m_posVert = g_eeGeneral.currModel; + s_pgOfs = 0; + } + else if (_event_ != EVT_KEY_LONG(KEY_EXIT)) { + popMenu(); + } + } + break; + case EVT_KEY_LONG(KEY_ENTER): + case EVT_KEY_BREAK(KEY_ENTER): + s_editMode = 0; + if (READ_ONLY()) { + if (g_eeGeneral.currModel != sub && eeModelExists(sub)) { + selectModel(sub); + } + } + else if (s_copyMode && (s_copyTgtOfs || s_copySrcRow>=0)) { + eeCheck(true); // force writing of current model data before this is changed + uint8_t cur = (MAX_MODELS + sub + s_copyTgtOfs) % MAX_MODELS; + if (s_copyMode == COPY_MODE) { + if (!eeCopyModel(cur, s_copySrcRow)) { + cur = sub; + } + } + + s_copySrcRow = g_eeGeneral.currModel; // to update the currModel value + while (sub != cur) { + uint8_t src = cur; + cur = (s_copyTgtOfs > 0 ? cur+MAX_MODELS-1 : cur+1) % MAX_MODELS; + eeSwapModels(src, cur); + if (src == s_copySrcRow) + s_copySrcRow = cur; + else if (cur == s_copySrcRow) + s_copySrcRow = src; + } + + if (s_copySrcRow != g_eeGeneral.currModel) { + g_eeGeneral.currModel = s_copySrcRow; + eeDirty(EE_GENERAL); + } + + s_copyMode = 0; + _event_ = EVT_ENTRY_UP; + } + else if (_event_ == EVT_KEY_LONG(KEY_ENTER)) { + s_copyMode = 0; + killEvents(_event_); + if (g_eeGeneral.currModel != sub) { + if (eeModelExists(sub)) { + MENU_ADD_ITEM(STR_SELECT_MODEL); + MENU_ADD_SD_ITEM(STR_BACKUP_MODEL); + MENU_ADD_ITEM(STR_COPY_MODEL); + MENU_ADD_ITEM(STR_MOVE_MODEL); + MENU_ADD_ITEM(STR_DELETE_MODEL); + } + else { + MENU_ADD_ITEM(STR_CREATE_MODEL); + MENU_ADD_ITEM(STR_RESTORE_MODEL); + } + } + else { + MENU_ADD_SD_ITEM(STR_BACKUP_MODEL); + MENU_ADD_ITEM(STR_COPY_MODEL); + MENU_ADD_ITEM(STR_MOVE_MODEL); + } + menuHandler = onModelSelectMenu; + } + else if (eeModelExists(sub)) { + s_copyMode = (s_copyMode == COPY_MODE ? MOVE_MODE : COPY_MODE); + s_copyTgtOfs = 0; + s_copySrcRow = -1; + } + break; + +#if 0 + case EVT_KEY_BREAK(KEY_PAGE): + case EVT_KEY_LONG(KEY_PAGE): + chainMenu(_event_ == EVT_KEY_BREAK(KEY_PAGE) ? menuModelSetup : menuTabModel[DIM(menuTabModel)-1]); + killEvents(_event_); + break; +#endif + + case EVT_KEY_FIRST(KEY_MOVE_UP): + case EVT_KEY_REPT(KEY_MOVE_UP): + case EVT_KEY_FIRST(KEY_MOVE_DOWN): + case EVT_KEY_REPT(KEY_MOVE_DOWN): + if (s_copyMode) { + int8_t next_ofs = s_copyTgtOfs + oldSub - m_posVert; + 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 = eeFindEmptyModel(s_copySrcRow, IS_ROTARY_DOWN(_event_) || _event_==EVT_KEY_FIRST(KEY_MOVE_DOWN)); + if (sub < 0) { + // no free room for duplicating the model + AUDIO_ERROR(); + sub = oldSub; + s_copyMode = 0; + } + next_ofs = 0; + m_posVert = sub; + } + s_copyTgtOfs = next_ofs; + } + break; + } + + for (int i=0; i= 0)) { + if (k == sub) { + if (s_copyMode == COPY_MODE) { + k = s_copySrcRow; + // lcd_rect(MENU_TITLE_LEFT-5, y-3, 170, 16, SOLID, YELLOW); + } + else { + k = sub + s_copyTgtOfs; + } + } + else if (s_copyTgtOfs < 0 && ((k < sub && k >= sub+s_copyTgtOfs) || (k-MAX_MODELS < sub && k-MAX_MODELS >= sub+s_copyTgtOfs))) + k += 1; + else if (s_copyTgtOfs > 0 && ((k > sub && k <= sub+s_copyTgtOfs) || (k+MAX_MODELS > sub && k+MAX_MODELS <= sub+s_copyTgtOfs))) + k += MAX_MODELS-1; + } + + k %= MAX_MODELS; + + if (eeModelExists(k)) { + strcat_modelname(str, k); + lcd_putsAtt(POS_MODEL_NAME, y, str, flags); + if (k==g_eeGeneral.currModel && (s_copyMode!=COPY_MODE || s_copySrcRow<0 || i+s_pgOfs!=(vertpos_t)sub)) { + lcd_puts(1, y, "*"); + } + } + else { + lcd_putsAtt(POS_MODEL_NAME, y, "---", flags); + } + + if (s_copyMode && (vertpos_t)sub==i+s_pgOfs) { + lcd_rect(MENU_TITLE_LEFT-INVERT_HORZ_MARGIN, y-INVERT_VERT_MARGIN, 150, INVERT_LINE_HEIGHT, s_copyMode == COPY_MODE ? SOLID : DOTTED, WARNING_COLOR); + } + } + + // TODO lcdDrawBitmap(200, 67, logos, 60*g_model.header.bitmap, 60); +} diff --git a/radio/src/gui/Horus/menu_model_setup.cpp b/radio/src/gui/Horus/menu_model_setup.cpp new file mode 100644 index 000000000..a322b6e38 --- /dev/null +++ b/radio/src/gui/Horus/menu_model_setup.cpp @@ -0,0 +1,741 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +uint8_t g_moduleIdx; +void menuModelFailsafe(evt_t event); + +enum menuModelSetupItems { + ITEM_MODEL_NAME, + ITEM_MODEL_BITMAP, + ITEM_MODEL_TIMER1, + ITEM_MODEL_TIMER1_NAME, + ITEM_MODEL_TIMER1_PERSISTENT, + ITEM_MODEL_TIMER1_MINUTE_BEEP, + ITEM_MODEL_TIMER1_COUNTDOWN_BEEP, +#if TIMERS > 1 + ITEM_MODEL_TIMER2, + ITEM_MODEL_TIMER2_NAME, + ITEM_MODEL_TIMER2_PERSISTENT, + ITEM_MODEL_TIMER2_MINUTE_BEEP, + ITEM_MODEL_TIMER2_COUNTDOWN_BEEP, +#endif +#if TIMERS > 2 + ITEM_MODEL_TIMER3, + ITEM_MODEL_TIMER3_NAME, + ITEM_MODEL_TIMER3_PERSISTENT, + ITEM_MODEL_TIMER3_MINUTE_BEEP, + ITEM_MODEL_TIMER3_COUNTDOWN_BEEP, +#endif + ITEM_MODEL_EXTENDED_LIMITS, + ITEM_MODEL_EXTENDED_TRIMS, + ITEM_MODEL_DISPLAY_TRIMS, + ITEM_MODEL_TRIM_INC, + ITEM_MODEL_THROTTLE_LABEL, + // ITEM_MODEL_THROTTLE_REVERSED, + ITEM_MODEL_THROTTLE_TRACE, + ITEM_MODEL_THROTTLE_TRIM, + ITEM_MODEL_PREFLIGHT_LABEL, + ITEM_MODEL_CHECKLIST_DISPLAY, + ITEM_MODEL_THROTTLE_WARNING, + ITEM_MODEL_SWITCHES_WARNING, + ITEM_MODEL_POT_WARNING, + ITEM_MODEL_BEEP_CENTER, + ITEM_MODEL_USE_GLOBAL_FUNCTIONS, + ITEM_MODEL_EXTERNAL_MODULE_LABEL, + ITEM_MODEL_EXTERNAL_MODULE_MODE, + ITEM_MODEL_EXTERNAL_MODULE_CHANNELS, + ITEM_MODEL_EXTERNAL_MODULE_BIND, + ITEM_MODEL_EXTERNAL_MODULE_FAILSAFE, + ITEM_MODEL_TRAINER_LABEL, + ITEM_MODEL_TRAINER_MODE, + ITEM_MODEL_TRAINER_CHANNELS, + ITEM_MODEL_TRAINER_SETTINGS, + ITEM_MODEL_SETUP_MAX +}; + +#define FIELD_PROTOCOL_MAX 1 + +#define MODEL_SETUP_2ND_COLUMN 200 +#define MODEL_SETUP_BIND_OFS 20 +#define MODEL_SETUP_RANGE_OFS 40 +#define MODEL_SETUP_SET_FAILSAFE_OFS 60 + +void copySelection(char *dst, const char *src, uint8_t size) +{ + if (memcmp(src, "---", 3) == 0) + memset(dst, 0, size); + else + memcpy(dst, src, size); +} + +void editTimerMode(int timerIdx, coord_t y, LcdFlags attr, evt_t event) +{ + TimerData * timer = &g_model.timers[timerIdx]; + if (attr && m_posHorz < 0) { + lcdDrawFilledRect(MODEL_SETUP_2ND_COLUMN-INVERT_HORZ_MARGIN, y-INVERT_VERT_MARGIN, 80+2*INVERT_HORZ_MARGIN, INVERT_LINE_HEIGHT, TEXT_INVERTED_BGCOLOR); + } + putsStrIdx(MENU_TITLE_LEFT, y, STR_TIMER, timerIdx+1); + putsTimerMode(MODEL_SETUP_2ND_COLUMN, y, timer->mode, (m_posHorz<=0 ? attr : 0)); + putsTimer(MODEL_SETUP_2ND_COLUMN+50, y, timer->start, (m_posHorz!=0 ? attr : 0)); + if (attr && s_editMode>0) { + switch (m_posHorz) { + case 0: + { + int8_t timerMode = timer->mode; + if (timerMode < 0) timerMode -= TMRMODE_COUNT-1; + CHECK_INCDEC_MODELVAR_CHECK(event, timerMode, -TMRMODE_COUNT-SWSRC_LAST+1, TMRMODE_COUNT+SWSRC_LAST-1, isSwitchAvailableInTimers); + if (timerMode < 0) timerMode += TMRMODE_COUNT-1; + timer->mode = timerMode; +#if defined(AUTOSWITCH) + if (s_editMode>0) { + int8_t val = timer->mode - (TMRMODE_COUNT-1); + int8_t switchVal = checkIncDecMovedSwitch(val); + if (val != switchVal) { + timer->mode = switchVal + (TMRMODE_COUNT-1); + eeDirty(EE_MODEL); + } + } +#endif + break; + } + case 1: + { + const int stopsMinutes[] = { 8, 60, 120, 180, 240, 300, 600, 900, 1200 }; + timer->start = checkIncDec(event, timer->start, 0, 60*60, EE_MODEL, NULL, (const CheckIncDecStops&)stopsMinutes); + break; + } + } + } +} + +#define CURRENT_MODULE_EDITED(k) (k>=ITEM_MODEL_TRAINER_LABEL ? TRAINER_MODULE : EXTERNAL_MODULE) + +int getSwitchWarningsCount() +{ + int count = 0; + for (int i=0; i> 6) ? (uint8_t)NUM_POTS : (uint8_t)0) + #define TIMER_ROWS NAVIGATION_LINE_BY_LINE|1, 0, CASE_PERSISTENT_TIMERS(0) 0, 0 + #if TIMERS == 1 + #define TIMERS_ROWS TIMER_ROWS + #elif TIMERS == 2 + #define TIMERS_ROWS TIMER_ROWS, TIMER_ROWS + #elif TIMERS == 3 + #define TIMERS_ROWS TIMER_ROWS, TIMER_ROWS, TIMER_ROWS + #endif + bool CURSOR_ON_CELL = (m_posHorz >= 0); + + MENU(STR_MENUSETUP, menuTabModel, e_ModelSetup, ITEM_MODEL_SETUP_MAX, DEFAULT_SCROLLBAR_X, { 0, 0, TIMERS_ROWS, 0, 1, 0, 0, LABEL(Throttle), 0, 0, LABEL(PreflightCheck), 0, 0, uint8_t(NAVIGATION_LINE_BY_LINE|(getSwitchWarningsCount()-1)), POT_WARN_ITEMS(), NAVIGATION_LINE_BY_LINE|(NUM_STICKS+NUM_POTS+NUM_ROTARY_ENCODERS-1), 0, LABEL(ExternalModule), (IS_MODULE_XJT(EXTERNAL_MODULE) || IS_MODULE_DSM2(EXTERNAL_MODULE)) ? (uint8_t)1 : (uint8_t)0, EXTERNAL_MODULE_CHANNELS_ROWS(), (IS_MODULE_XJT(EXTERNAL_MODULE) && IS_D8_RX(EXTERNAL_MODULE)) ? (uint8_t)1 : (IS_MODULE_PPM(EXTERNAL_MODULE) || IS_MODULE_XJT(EXTERNAL_MODULE) || IS_MODULE_DSM2(EXTERNAL_MODULE)) ? (uint8_t)2 : HIDDEN_ROW, IF_EXTERNAL_MODULE_XJT(FAILSAFE_ROWS(EXTERNAL_MODULE)), LABEL(Trainer), 0, TRAINER_CHANNELS_ROWS(), IF_TRAINER_ON(2) }); + +#if (defined(DSM2) || defined(PXX)) + if (menuEvent) { + moduleFlag[0] = 0; +#if NUM_MODULES > 1 + moduleFlag[1] = 0; +#endif + } +#endif + + int sub = m_posVert; + + for (int i=0; i0) ? BLINK|INVERS : INVERS); + LcdFlags attr = (sub == k ? blink : 0); + + switch(k) { + case ITEM_MODEL_NAME: + editSingleName(MODEL_SETUP_2ND_COLUMN, y, STR_MODELNAME, g_model.header.name, sizeof(g_model.header.name), event, attr); + memcpy(modelHeaders[g_eeGeneral.currModel].name, g_model.header.name, sizeof(g_model.header.name)); + break; + + case ITEM_MODEL_BITMAP: + lcd_putsLeft(y, STR_BITMAP); + lcd_outdezAtt(MODEL_SETUP_2ND_COLUMN, y, g_model.header.bitmap, LEFT|attr); + if (attr) CHECK_INCDEC_MODELVAR_ZERO(event, g_model.header.bitmap, 3); + break; + + case ITEM_MODEL_TIMER1: + editTimerMode(0, y, attr, event); + break; + + case ITEM_MODEL_TIMER1_NAME: + editSingleName(MODEL_SETUP_2ND_COLUMN, y, STR_TIMER_NAME, g_model.timers[0].name, LEN_TIMER_NAME, event, attr); + break; + + case ITEM_MODEL_TIMER1_MINUTE_BEEP: + g_model.timers[0].minuteBeep = onoffMenuItem(g_model.timers[0].minuteBeep, MODEL_SETUP_2ND_COLUMN, y, STR_MINUTEBEEP, attr, event); + break; + + case ITEM_MODEL_TIMER1_COUNTDOWN_BEEP: + g_model.timers[0].countdownBeep = selectMenuItem(MODEL_SETUP_2ND_COLUMN, y, STR_BEEPCOUNTDOWN, STR_VBEEPCOUNTDOWN, g_model.timers[0].countdownBeep, 0, 2, attr, event); + break; + + case ITEM_MODEL_TIMER1_PERSISTENT: + g_model.timers[0].persistent = selectMenuItem(MODEL_SETUP_2ND_COLUMN, y, STR_PERSISTENT, STR_VPERSISTENT, g_model.timers[0].persistent, 0, 2, attr, event); + break; + +#if TIMERS > 1 + case ITEM_MODEL_TIMER2: + editTimerMode(1, y, attr, event); + break; + + case ITEM_MODEL_TIMER2_NAME: + editSingleName(MODEL_SETUP_2ND_COLUMN, y, STR_TIMER_NAME, g_model.timers[1].name, LEN_TIMER_NAME, event, attr); + break; + + case ITEM_MODEL_TIMER2_MINUTE_BEEP: + g_model.timers[1].minuteBeep = onoffMenuItem(g_model.timers[1].minuteBeep, MODEL_SETUP_2ND_COLUMN, y, STR_MINUTEBEEP, attr, event); + break; + + case ITEM_MODEL_TIMER2_COUNTDOWN_BEEP: + g_model.timers[1].countdownBeep = selectMenuItem(MODEL_SETUP_2ND_COLUMN, y, STR_BEEPCOUNTDOWN, STR_VBEEPCOUNTDOWN, g_model.timers[1].countdownBeep, 0, 2, attr, event); + break; + + case ITEM_MODEL_TIMER2_PERSISTENT: + g_model.timers[1].persistent = selectMenuItem(MODEL_SETUP_2ND_COLUMN, y, STR_PERSISTENT, STR_VPERSISTENT, g_model.timers[1].persistent, 0, 2, attr, event); + break; +#endif + +#if TIMERS > 2 + case ITEM_MODEL_TIMER3: + editTimerMode(2, y, attr, event); + break; + + case ITEM_MODEL_TIMER3_NAME: + editSingleName(MODEL_SETUP_2ND_COLUMN, y, STR_TIMER_NAME, g_model.timers[2].name, LEN_TIMER_NAME, event, attr); + break; + + case ITEM_MODEL_TIMER3_MINUTE_BEEP: + g_model.timers[2].minuteBeep = onoffMenuItem(g_model.timers[2].minuteBeep, MODEL_SETUP_2ND_COLUMN, y, STR_MINUTEBEEP, attr, event); + break; + + case ITEM_MODEL_TIMER3_COUNTDOWN_BEEP: + g_model.timers[2].countdownBeep = selectMenuItem(MODEL_SETUP_2ND_COLUMN, y, STR_BEEPCOUNTDOWN, STR_VBEEPCOUNTDOWN, g_model.timers[2].countdownBeep, 0, 2, attr, event); + break; + + case ITEM_MODEL_TIMER3_PERSISTENT: + g_model.timers[2].persistent = selectMenuItem(MODEL_SETUP_2ND_COLUMN, y, STR_PERSISTENT, STR_VPERSISTENT, g_model.timers[2].persistent, 0, 2, attr, event); + break; +#endif + + case ITEM_MODEL_EXTENDED_LIMITS: + ON_OFF_MENU_ITEM(g_model.extendedLimits, MODEL_SETUP_2ND_COLUMN, y, STR_ELIMITS, attr, event); + break; + + case ITEM_MODEL_EXTENDED_TRIMS: + ON_OFF_MENU_ITEM(g_model.extendedTrims, MODEL_SETUP_2ND_COLUMN, y, STR_ETRIMS, m_posHorz<=0 ? attr : 0, event==EVT_KEY_BREAK(KEY_ENTER) ? event : 0); + lcd_putsAtt(MODEL_SETUP_2ND_COLUMN+18, y, STR_RESET_BTN, m_posHorz>0 && !s_noHi ? attr : 0); + if (attr && m_posHorz>0) { + s_editMode = 0; + if (event==EVT_KEY_LONG(KEY_ENTER)) { + s_noHi = NO_HI_LEN; + for (uint8_t i=0; i MIXSRC_Thr) + idx += 1; + if (idx >= MIXSRC_FIRST_POT+NUM_POTS) + idx += MIXSRC_CH1 - MIXSRC_FIRST_POT - NUM_POTS; + putsMixerSource(MODEL_SETUP_2ND_COLUMN, y, idx, attr); + break; + } + + case ITEM_MODEL_THROTTLE_TRIM: + ON_OFF_MENU_ITEM(g_model.thrTrim, MODEL_SETUP_2ND_COLUMN, y, STR_TTRIM, attr, event); + break; + + case ITEM_MODEL_PREFLIGHT_LABEL: + lcd_putsLeft(y, STR_PREFLIGHT); + break; + + case ITEM_MODEL_CHECKLIST_DISPLAY: + ON_OFF_MENU_ITEM(g_model.displayChecklist, MODEL_SETUP_2ND_COLUMN, y, STR_CHECKLIST, attr, event); + break; + + case ITEM_MODEL_THROTTLE_WARNING: + g_model.disableThrottleWarning = !onoffMenuItem(!g_model.disableThrottleWarning, MODEL_SETUP_2ND_COLUMN, y, STR_THROTTLEWARNING, attr, event); + break; + + case ITEM_MODEL_SWITCHES_WARNING: + { + lcd_putsLeft(y, STR_SWITCHWARNING); + if (!READ_ONLY() && attr && m_posHorz<0 && event==EVT_KEY_LONG(KEY_ENTER)) { + killEvents(event); + s_noHi = NO_HI_LEN; + getMovedSwitch(); + g_model.switchWarningState = switches_states; + AUDIO_WARNING1(); + eeDirty(EE_MODEL); + } + + if (attr && m_posHorz < 0) { + lcdDrawFilledRect(MODEL_SETUP_2ND_COLUMN-INVERT_HORZ_MARGIN, y-INVERT_VERT_MARGIN, NUM_SWITCHES*18+INVERT_HORZ_MARGIN, INVERT_LINE_HEIGHT, TEXT_INVERTED_BGCOLOR); + } + + unsigned int newStates = 0; + for (int i=0, current=0; i> (3*i)) & 0x07); + LcdFlags color = (state > 0 ? TEXT_COLOR : TEXT_DISABLE_COLOR); + if (attr && m_posHorz < 0) { + color |= INVERS; + } + char s[3]; + s[0] = 'A' + i + (i >= 3 ? 1 : 0 /* skip SD which is a POT*/); + int max; + if (state == 0) { + s[1] = 'x'; + max = 2; + } + else if (i == 2) { + s[1] = '0' + state; + max = 6; + } + else if (IS_3POS(i)) { + s[1] = "\300-\301"[state-1]; + max = 3; + } + else { + s[1] = "\300\301"[state-1]; + max = 2; + } + s[2] = '\0'; + lcd_putsAtt(MODEL_SETUP_2ND_COLUMN+i*18, y, s, color|(m_posHorz==current ? attr : 0)); + if (attr && m_posHorz==current) CHECK_INCDEC_MODELVAR_ZERO(event, state, max); + newStates |= (state << (3*i)); + ++current; + } + } + g_model.switchWarningState = newStates; + break; + } + + case ITEM_MODEL_POT_WARNING: + { + lcd_putsLeft(y, STR_POTWARNING); + if (attr) { + if (m_posHorz) s_editMode = 0; + if (!READ_ONLY() && m_posHorz) { + switch (event) { + case EVT_KEY_LONG(KEY_ENTER): + killEvents(event); + if (g_model.potsWarnMode == POTS_WARN_MANUAL) { + SAVE_POT_POSITION(m_posHorz-1); + AUDIO_WARNING1(); + eeDirty(EE_MODEL); + } + break; + case EVT_KEY_BREAK(KEY_ENTER): + g_model.potsWarnEnabled ^= (1 << (m_posHorz-1)); + eeDirty(EE_MODEL); + break; + } + } + } + lcd_putsiAtt(MODEL_SETUP_2ND_COLUMN, y, PSTR("\004""OFF\0""Man\0""Auto"), g_model.potsWarnMode, (m_posHorz == 0) ? attr : 0); + if (g_model.potsWarnMode) { + coord_t x = MODEL_SETUP_2ND_COLUMN+30; + for (int i=0; i0) { + switch (m_posHorz) { + case 0: + g_model.externalModule = checkIncDec(event, g_model.externalModule, MODULE_TYPE_NONE, MODULE_TYPE_COUNT-1, EE_MODEL, isModuleAvailable); + if (checkIncDec_Ret) { + g_model.moduleData[EXTERNAL_MODULE].rfProtocol = 0; + g_model.moduleData[EXTERNAL_MODULE].channelsStart = 0; + if (g_model.externalModule == MODULE_TYPE_PPM) + g_model.moduleData[EXTERNAL_MODULE].channelsCount = 0; + else + g_model.moduleData[EXTERNAL_MODULE].channelsCount = MAX_EXTERNAL_MODULE_CHANNELS(); + } + break; + case 1: + if (IS_MODULE_DSM2(EXTERNAL_MODULE)) + CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].rfProtocol, DSM2_PROTO_LP45, DSM2_PROTO_DSMX); + else + CHECK_INCDEC_MODELVAR(event, g_model.moduleData[EXTERNAL_MODULE].rfProtocol, RF_PROTO_X16, RF_PROTO_LAST); + if (checkIncDec_Ret) { + g_model.moduleData[EXTERNAL_MODULE].channelsStart = 0; + g_model.moduleData[EXTERNAL_MODULE].channelsCount = MAX_EXTERNAL_MODULE_CHANNELS(); + } + } + } + break; + + case ITEM_MODEL_TRAINER_LABEL: + lcd_putsLeft(y, STR_TRAINER); + break; + + case ITEM_MODEL_EXTERNAL_MODULE_CHANNELS: + case ITEM_MODEL_TRAINER_CHANNELS: + { + uint8_t moduleIdx = CURRENT_MODULE_EDITED(k); + ModuleData & moduleData = g_model.moduleData[moduleIdx]; + lcd_putsLeft(y, STR_CHANNELRANGE); + if ((int8_t)PORT_CHANNELS_ROWS(moduleIdx) >= 0) { + putsStrIdx(MODEL_SETUP_2ND_COLUMN, y, STR_CH, moduleData.channelsStart+1, m_posHorz==0 ? attr : 0); + lcd_puts(MODEL_SETUP_2ND_COLUMN+30, y, "-"); + putsStrIdx(MODEL_SETUP_2ND_COLUMN+40, y, STR_CH, moduleData.channelsStart+NUM_CHANNELS(moduleIdx), m_posHorz==1 ? attr : 0); + if (attr && s_editMode>0) { + switch (m_posHorz) { + case 0: + CHECK_INCDEC_MODELVAR_ZERO(event, moduleData.channelsStart, 32-8-moduleData.channelsCount); + break; + case 1: + CHECK_INCDEC_MODELVAR(event, moduleData.channelsCount, -4, min(MAX_CHANNELS(moduleIdx), 32-8-moduleData.channelsStart)); + if ((k == ITEM_MODEL_EXTERNAL_MODULE_CHANNELS && g_model.externalModule == MODULE_TYPE_PPM) + || (k == ITEM_MODEL_TRAINER_CHANNELS) + ) + SET_DEFAULT_PPM_FRAME_LENGTH(moduleIdx); + break; + } + } + } + break; + } + + case ITEM_MODEL_EXTERNAL_MODULE_BIND: + case ITEM_MODEL_TRAINER_SETTINGS: + { + uint8_t moduleIdx = CURRENT_MODULE_EDITED(k); + ModuleData & moduleData = g_model.moduleData[moduleIdx]; + if (IS_MODULE_PPM(moduleIdx)) { + lcd_putsLeft(y, STR_PPMFRAME); + lcd_outdezAtt(MODEL_SETUP_2ND_COLUMN, y, (int16_t)moduleData.ppmFrameLength*5 + 225, (m_posHorz<=0 ? attr : 0) | PREC1|LEFT, STR_MS); + lcd_outdezAtt(MODEL_SETUP_2ND_COLUMN+70, y, (moduleData.ppmDelay*50)+300, (CURSOR_ON_LINE() || m_posHorz==1) ? attr : 0, "us"); + lcd_putsAtt(MODEL_SETUP_2ND_COLUMN+90, y, moduleData.ppmPulsePol ? "+" : "-", (CURSOR_ON_LINE() || m_posHorz==2) ? attr : 0); + + if (attr && s_editMode>0) { + switch (m_posHorz) { + case 0: + CHECK_INCDEC_MODELVAR(event, moduleData.ppmFrameLength, -20, 35); + break; + case 1: + CHECK_INCDEC_MODELVAR(event, moduleData.ppmDelay, -4, 10); + break; + case 2: + CHECK_INCDEC_MODELVAR_ZERO(event, moduleData.ppmPulsePol, 1); + break; + } + } + } + else { + horzpos_t l_posHorz = m_posHorz; + coord_t xOffsetBind = MODEL_SETUP_BIND_OFS; + if (IS_MODULE_XJT(moduleIdx) && IS_D8_RX(moduleIdx)) { + xOffsetBind = 0; + lcd_putsLeft(y, INDENT "Receiver"); + if (attr) l_posHorz += 1; + } + else { + lcd_putsLeft(y, STR_RXNUM); + } + if (IS_MODULE_XJT(moduleIdx) || IS_MODULE_DSM2(moduleIdx)) { + if (xOffsetBind) lcd_outdezNAtt(MODEL_SETUP_2ND_COLUMN, y, g_model.header.modelId[moduleIdx], (l_posHorz==0 ? attr : 0) | LEADING0|LEFT, 2); + if (attr && l_posHorz==0) { + if (s_editMode>0) { + CHECK_INCDEC_MODELVAR_ZERO(event, g_model.header.modelId[moduleIdx], IS_MODULE_DSM2(moduleIdx) ? 20 : 63); + if (checkIncDec_Ret) { + modelHeaders[g_eeGeneral.currModel].modelId[moduleIdx] = g_model.header.modelId[moduleIdx]; + } + } + if (s_editMode==0 && event==EVT_KEY_BREAK(KEY_ENTER)) { + checkModelIdUnique(g_eeGeneral.currModel, moduleIdx); + } + } + lcd_putsAtt(MODEL_SETUP_2ND_COLUMN+xOffsetBind, y, STR_MODULE_BIND, l_posHorz==1 ? attr : 0); + lcd_putsAtt(MODEL_SETUP_2ND_COLUMN+MODEL_SETUP_RANGE_OFS+xOffsetBind, y, STR_MODULE_RANGE, l_posHorz==2 ? attr : 0); + uint8_t newFlag = 0; + if (attr && l_posHorz>0 && s_editMode>0) { + if (l_posHorz == 1) + newFlag = MODULE_BIND; + else if (l_posHorz == 2) { + newFlag = MODULE_RANGECHECK; + } + } + moduleFlag[moduleIdx] = newFlag; + } + } + break; + } + + case ITEM_MODEL_EXTERNAL_MODULE_FAILSAFE: + { + uint8_t moduleIdx = CURRENT_MODULE_EDITED(k); + ModuleData & moduleData = g_model.moduleData[moduleIdx]; + lcd_putsLeft(y, TR_FAILSAFE); + if (IS_MODULE_XJT(moduleIdx)) { + lcd_putsiAtt(MODEL_SETUP_2ND_COLUMN, y, STR_VFAILSAFE, moduleData.failsafeMode, m_posHorz==0 ? attr : 0); + if (moduleData.failsafeMode == FAILSAFE_CUSTOM) lcd_putsAtt(MODEL_SETUP_2ND_COLUMN + MODEL_SETUP_SET_FAILSAFE_OFS, y, STR_SET, m_posHorz==1 ? attr : 0); + if (attr) { + if (moduleData.failsafeMode != FAILSAFE_CUSTOM) + m_posHorz = 0; + if (m_posHorz==0) { + if (s_editMode>0) { + CHECK_INCDEC_MODELVAR_ZERO(event, moduleData.failsafeMode, FAILSAFE_LAST); + if (checkIncDec_Ret) SEND_FAILSAFE_NOW(moduleIdx); + } + } + else if (m_posHorz==1) { + s_editMode = 0; + if (moduleData.failsafeMode==FAILSAFE_CUSTOM && event==EVT_KEY_FIRST(KEY_ENTER)) { + g_moduleIdx = moduleIdx; + pushMenu(menuModelFailsafe); + } + } + else { + lcdDrawFilledRect(MODEL_SETUP_2ND_COLUMN, y, LCD_W-MODEL_SETUP_2ND_COLUMN-MENUS_SCROLLBAR_WIDTH, 8, TEXT_COLOR); + } + } + } + break; + } + } + } + + if (IS_RANGECHECK_ENABLE()) { + displayPopup("RSSI :"); + lcd_outdezAtt(WARNING_LINE_X, WARNING_INFOLINE_Y, TELEMETRY_RSSI(), DBLSIZE|LEFT); + } +} + +void menuModelFailsafe(evt_t event) +{ + static bool longNames = false; + bool newLongNames = false; + uint8_t ch = 0; + + if (event == EVT_KEY_LONG(KEY_ENTER) && s_editMode) { + s_noHi = NO_HI_LEN; + g_model.moduleData[g_moduleIdx].failsafeChannels[m_posVert] = channelOutputs[m_posVert]; + eeDirty(EE_MODEL); + AUDIO_WARNING1(); + SEND_FAILSAFE_NOW(g_moduleIdx); + } + + SIMPLE_SUBMENU_NOTITLE(NUM_CHNOUT, 0); + + #define COL_W (LCD_W/2) + const uint8_t SLIDER_W = 64; + // Column separator + lcd_vline(LCD_W/2, FH, LCD_H-FH); + + if (m_posVert >= 16) { + ch = 16; + } + + // TODO lcd_putsCenter(0, FAILSAFESET); + // TODO lcd_invert_line(0); + + for (int col=0; col<2; col++) { + coord_t x = col*COL_W+1; + + // Channels + for (int line=0; line<8; line++) { + coord_t y = 9+line*7; + int32_t val; + int ofs = (col ? 0 : 1); + + if (ch < g_model.moduleData[g_moduleIdx].channelsStart || ch >= NUM_CHANNELS(g_moduleIdx) + g_model.moduleData[g_moduleIdx].channelsStart) + val = 0; + else if (s_editMode && m_posVert == ch) + val = channelOutputs[ch]; + else + val = g_model.moduleData[g_moduleIdx].failsafeChannels[8*col+line]; + + // Channel name if present, number if not + uint8_t lenLabel = ZLEN(g_model.limitData[ch].name); + if (lenLabel > 4) { + newLongNames = longNames = true; + } + + if (lenLabel > 0) + lcd_putsnAtt(x+1-ofs, y, g_model.limitData[ch].name, sizeof(g_model.limitData[ch].name), ZCHAR | SMLSIZE); + else + putsChn(x+1-ofs, y, ch+1, SMLSIZE); + + // Value + LcdFlags flags = TINSIZE; + if (m_posVert == ch && !s_noHi) { + flags |= INVERS; + if (s_editMode) + flags |= BLINK; + } +#if defined(PPM_UNIT_US) + uint8_t wbar = (longNames ? SLIDER_W-10 : SLIDER_W); + lcd_outdezAtt(x+COL_W-4-wbar-ofs, y, PPM_CH_CENTER(ch)+val/2, flags); +#elif defined(PPM_UNIT_PERCENT_PREC1) + uint8_t wbar = (longNames ? SLIDER_W-16 : SLIDER_W-6); + lcd_outdezAtt(x+COL_W-4-wbar-ofs, y, calcRESXto1000(val), PREC1|flags); +#else + uint8_t wbar = (longNames ? SLIDER_W-10 : SLIDER_W); + lcd_outdezAtt(x+COL_W-4-wbar-ofs, y, calcRESXto1000(val)/10, flags); +#endif + + // Gauge + lcd_rect(x+COL_W-3-wbar-ofs, y, wbar+1, 6); + uint16_t lim = g_model.extendedLimits ? 640*2 : 512*2; + uint8_t len = limit((uint8_t)1, uint8_t((abs(val) * wbar/2 + lim/2) / lim), uint8_t(wbar/2)); + coord_t x0 = (val>0) ? x+COL_W-ofs-3-wbar/2 : x+COL_W-ofs-2-wbar/2-len; + lcd_hline(x0, y+1, len); + lcd_hline(x0, y+2, len); + lcd_hline(x0, y+3, len); + lcd_hline(x0, y+4, len); + + ch++; + } + } + + longNames = newLongNames; +} diff --git a/radio/src/gui/Horus/menu_model_telemetry.cpp b/radio/src/gui/Horus/menu_model_telemetry.cpp new file mode 100644 index 000000000..f05412ca5 --- /dev/null +++ b/radio/src/gui/Horus/menu_model_telemetry.cpp @@ -0,0 +1,728 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +enum menuModelTelemetryItems { + ITEM_TELEMETRY_PROTOCOL_TYPE, + ITEM_TELEMETRY_RSSI_LABEL, + ITEM_TELEMETRY_RSSI_ALARM1, + ITEM_TELEMETRY_RSSI_ALARM2, + ITEM_TELEMETRY_SENSORS_LABEL, + ITEM_TELEMETRY_SENSOR1, + ITEM_TELEMETRY_SENSOR2, + ITEM_TELEMETRY_SENSOR3, + ITEM_TELEMETRY_SENSOR4, + ITEM_TELEMETRY_SENSOR5, + ITEM_TELEMETRY_SENSOR6, + ITEM_TELEMETRY_SENSOR7, + ITEM_TELEMETRY_SENSOR8, + ITEM_TELEMETRY_SENSOR9, + ITEM_TELEMETRY_SENSOR10, + ITEM_TELEMETRY_SENSOR11, + ITEM_TELEMETRY_SENSOR12, + ITEM_TELEMETRY_SENSOR13, + ITEM_TELEMETRY_SENSOR14, + ITEM_TELEMETRY_SENSOR15, + ITEM_TELEMETRY_SENSOR16, + ITEM_TELEMETRY_SENSOR17, + ITEM_TELEMETRY_SENSOR18, + ITEM_TELEMETRY_SENSOR19, + ITEM_TELEMETRY_SENSOR20, + ITEM_TELEMETRY_SENSOR21, + ITEM_TELEMETRY_SENSOR22, + ITEM_TELEMETRY_SENSOR23, + ITEM_TELEMETRY_SENSOR24, + ITEM_TELEMETRY_SENSOR25, + ITEM_TELEMETRY_SENSOR26, + ITEM_TELEMETRY_SENSOR27, + ITEM_TELEMETRY_SENSOR28, + ITEM_TELEMETRY_SENSOR29, + ITEM_TELEMETRY_SENSOR30, + ITEM_TELEMETRY_SENSOR31, + ITEM_TELEMETRY_SENSOR32, + ITEM_TELEMETRY_NEWSENSOR, + CASE_VARIO(ITEM_TELEMETRY_VARIO_LABEL) +#if defined(VARIO) + ITEM_TELEMETRY_VARIO_SOURCE, +#endif + CASE_VARIO(ITEM_TELEMETRY_VARIO_RANGE) + ITEM_TELEMETRY_TOP_BAR_LABEL, + ITEM_TELEMETRY_TOP_BAR_VOLTAGE, + ITEM_TELEMETRY_TOP_BAR_ALTITUDE, + ITEM_TELEMETRY_SCREEN_LABEL1, + ITEM_TELEMETRY_SCREEN_LINE1, + ITEM_TELEMETRY_SCREEN_LINE2, + ITEM_TELEMETRY_SCREEN_LINE3, + ITEM_TELEMETRY_SCREEN_LINE4, + ITEM_TELEMETRY_SCREEN_LABEL2, + ITEM_TELEMETRY_SCREEN_LINE5, + ITEM_TELEMETRY_SCREEN_LINE6, + ITEM_TELEMETRY_SCREEN_LINE7, + ITEM_TELEMETRY_SCREEN_LINE8, + ITEM_TELEMETRY_SCREEN_LABEL3, + ITEM_TELEMETRY_SCREEN_LINE9, + ITEM_TELEMETRY_SCREEN_LINE10, + ITEM_TELEMETRY_SCREEN_LINE11, + ITEM_TELEMETRY_SCREEN_LINE12, + ITEM_TELEMETRY_SCREEN_LABEL4, + ITEM_TELEMETRY_SCREEN_LINE13, + ITEM_TELEMETRY_SCREEN_LINE14, + ITEM_TELEMETRY_SCREEN_LINE15, + ITEM_TELEMETRY_SCREEN_LINE16, + ITEM_TELEMETRY_MAX +}; + +#define TELEM_COL1 10 +#define TELEM_COL2 150 +#define TELEM_COL3 200 +#define TELEM_SCRTYPE_COL TELEM_COL2 + +#define IF_FAS_OFFSET(x) x, +#define IS_RANGE_DEFINED(k) (g_model.frsky.channels[k].ratio > 0) + +#define SENSOR_ROWS(x) (isTelemetryFieldAvailable(x) ? (uint8_t)0 : HIDDEN_ROW) +#define SENSORS_ROWS LABEL(Sensors), SENSOR_ROWS(0), SENSOR_ROWS(1), SENSOR_ROWS(2), SENSOR_ROWS(3), SENSOR_ROWS(4), SENSOR_ROWS(5), SENSOR_ROWS(6), SENSOR_ROWS(7), SENSOR_ROWS(8), SENSOR_ROWS(9), SENSOR_ROWS(10), SENSOR_ROWS(11), SENSOR_ROWS(12), SENSOR_ROWS(13), SENSOR_ROWS(14), SENSOR_ROWS(15), SENSOR_ROWS(16), SENSOR_ROWS(17), SENSOR_ROWS(18), SENSOR_ROWS(19), SENSOR_ROWS(20), SENSOR_ROWS(21), SENSOR_ROWS(22), SENSOR_ROWS(23), SENSOR_ROWS(24), SENSOR_ROWS(25), SENSOR_ROWS(26), SENSOR_ROWS(27), SENSOR_ROWS(28), SENSOR_ROWS(29), SENSOR_ROWS(30), SENSOR_ROWS(31), 0, +#define USRDATA_ROWS +#define RSSI_ROWS LABEL(RSSI), 0, 0, +#if defined(LUA) + #define SCREEN_TYPE_ROWS 1 +#else + #define SCREEN_TYPE_ROWS 0 +#endif +#define VARIO_RANGE_ROWS 3 + +#define TELEMETRY_TYPE_ROWS (g_model.externalModule == MODULE_TYPE_PPM ? (uint8_t)0 : HIDDEN_ROW), + +#if defined(LUA) + #define TELEMETRY_SCREEN_LINE(x) ((TELEMETRY_SCREEN_TYPE(x) == TELEMETRY_SCREEN_TYPE_NONE || TELEMETRY_SCREEN_TYPE(x) == TELEMETRY_SCREEN_TYPE_SCRIPT) ? HIDDEN_ROW : (uint8_t)2) +#else + #define TELEMETRY_SCREEN_LINE(x) (TELEMETRY_SCREEN_TYPE(x) == TELEMETRY_SCREEN_TYPE_NONE ? HIDDEN_ROW : (uint8_t)2) +#endif +#define TELEMETRY_SCREEN_ROWS(x) SCREEN_TYPE_ROWS, TELEMETRY_SCREEN_LINE(x), TELEMETRY_SCREEN_LINE(x), TELEMETRY_SCREEN_LINE(x), TELEMETRY_SCREEN_LINE(x) +#define TELEMETRY_CURRENT_EDIT_SCREEN(k) (k < ITEM_TELEMETRY_SCREEN_LABEL2 ? 0 : (k < ITEM_TELEMETRY_SCREEN_LABEL3 ? 1 : (k < ITEM_TELEMETRY_SCREEN_LABEL4 ? 2 : 3))) + +enum SensorFields { + SENSOR_FIELD_NAME, + SENSOR_FIELD_TYPE, + SENSOR_FIELD_ID, + SENSOR_FIELD_FORMULA=SENSOR_FIELD_ID, + SENSOR_FIELD_UNIT, + SENSOR_FIELD_PRECISION, + SENSOR_FIELD_PARAM1, + SENSOR_FIELD_PARAM2, + SENSOR_FIELD_PARAM3, + SENSOR_FIELD_PARAM4, + SENSOR_FIELD_AUTOOFFSET, + SENSOR_FIELD_FILTER, + SENSOR_FIELD_PERSISTENT, + SENSOR_FIELD_LOGS, + SENSOR_FIELD_MAX +}; + +bool isSensorUnit(int sensor, uint8_t unit) +{ + if (sensor == 0) + return true; + + sensor -= 1; + + return g_model.telemetrySensors[sensor].unit == unit; +} + +bool isCellsSensor(int sensor) +{ + return isSensorUnit(sensor, UNIT_CELLS); +} + +bool isGPSSensor(int sensor) +{ + return isSensorUnit(sensor, UNIT_GPS); +} + +bool isAltSensor(int sensor) +{ + return isSensorUnit(sensor, UNIT_DIST); +} + +bool isVoltsSensor(int sensor) +{ + return isSensorUnit(sensor, UNIT_VOLTS) || isSensorUnit(sensor, UNIT_CELLS); +} + +bool isCurrentSensor(int sensor) +{ + return isSensorUnit(sensor, UNIT_AMPS); +} + +bool isSensorAvailable(int sensor) +{ + if (sensor == 0) + return true; + else + return isTelemetryFieldAvailable(abs(sensor) - 1); +} + +#define SENSOR_2ND_COLUMN 80 +#define SENSOR_3RD_COLUMN 120 + +#define SENSOR_UNIT_ROWS (sensor->isConfigurable() ? (uint8_t)0 : HIDDEN_ROW) +#define SENSOR_PREC_ROWS (sensor->isConfigurable() ? (uint8_t)0 : HIDDEN_ROW) +#define SENSOR_PARAM1_ROWS (sensor->unit >= UNIT_FIRST_VIRTUAL ? HIDDEN_ROW : (uint8_t)0) +#define SENSOR_PARAM2_ROWS (sensor->unit == UNIT_RPMS || sensor->unit == UNIT_GPS || sensor->unit == UNIT_DATETIME || sensor->unit == UNIT_CELLS || (sensor->type==TELEM_TYPE_CALCULATED && (sensor->formula==TELEM_FORMULA_CONSUMPTION || sensor->formula==TELEM_FORMULA_TOTALIZE)) ? HIDDEN_ROW : (uint8_t)0) +#define SENSOR_PARAM3_ROWS (sensor->type == TELEM_TYPE_CALCULATED && sensor->formula < TELEM_FORMULA_MULTIPLY) ? (uint8_t)0 : HIDDEN_ROW +#define SENSOR_PARAM4_ROWS (sensor->type == TELEM_TYPE_CALCULATED && sensor->formula < TELEM_FORMULA_MULTIPLY) ? (uint8_t)0 : HIDDEN_ROW +#define SENSOR_AUTOOFFSET_ROWS (sensor->isConfigurable() ? (uint8_t)0 : HIDDEN_ROW) +#define SENSOR_FILTER_ROWS (sensor->isConfigurable() ? (uint8_t)0 : HIDDEN_ROW) +#define SENSOR_PERSISTENT_ROWS (sensor->isConfigurable() ? (uint8_t)0 : HIDDEN_ROW) + +void menuModelSensor(evt_t event) +{ + TelemetrySensor *sensor = &g_model.telemetrySensors[s_currIdx]; + + SUBMENU(STR_MENUSENSOR, SENSOR_FIELD_MAX, DEFAULT_SCROLLBAR_X, { 0, 0, sensor->type == TELEM_TYPE_CALCULATED ? (uint8_t)0 : (uint8_t)1, SENSOR_UNIT_ROWS, SENSOR_PREC_ROWS, SENSOR_PARAM1_ROWS, SENSOR_PARAM2_ROWS, SENSOR_PARAM3_ROWS, SENSOR_PARAM4_ROWS, 0 }); + + lcd_outdezAtt(MENU_TITLE_LEFT+getTextWidth(TR_MENUSENSOR)+5, MENU_FOOTER_TOP, s_currIdx+1, HEADER_COLOR|LEFT); + putsTelemetryChannelValue(SENSOR_2ND_COLUMN, MENU_FOOTER_TOP, s_currIdx, getValue(MIXSRC_FIRST_TELEM+3*s_currIdx), HEADER_COLOR|LEFT); + + int sub = m_posVert; + + for (unsigned int i=0; i0 ? BLINK|INVERS : INVERS) : 0); + + switch (k) { + + case SENSOR_FIELD_NAME: + editSingleName(SENSOR_2ND_COLUMN, y, STR_NAME, sensor->label, TELEM_LABEL_LEN, event, attr); + break; + + case SENSOR_FIELD_TYPE: + sensor->type = selectMenuItem(SENSOR_2ND_COLUMN, y, NO_INDENT(STR_TYPE), STR_VSENSORTYPES, sensor->type, 0, 1, attr, event); + if (attr && checkIncDec_Ret) { + sensor->instance = 0; + if (sensor->type == TELEM_TYPE_CALCULATED) { + sensor->param = 0; + sensor->filter = 0; + sensor->autoOffset = 0; + } + } + break; + + case SENSOR_FIELD_ID: + if (sensor->type == TELEM_TYPE_CUSTOM) { + lcd_putsLeft(y, STR_ID); + lcd_outhex4(SENSOR_2ND_COLUMN, y, sensor->id, LEFT|(m_posHorz==0 ? attr : 0)); + lcd_outdezAtt(SENSOR_3RD_COLUMN, y, sensor->instance, LEFT|(m_posHorz==1 ? attr : 0)); + if (attr) { + switch (m_posHorz) { + case 0: + CHECK_INCDEC_MODELVAR_ZERO(event, sensor->id, 0xffff); + break; + + case 1: + CHECK_INCDEC_MODELVAR_ZERO(event, sensor->instance, 0xff); + break; + } + } + } + else { + sensor->formula = selectMenuItem(SENSOR_2ND_COLUMN, y, STR_FORMULA, STR_VFORMULAS, sensor->formula, 0, TELEM_FORMULA_LAST, attr, event); + if (attr && checkIncDec_Ret) { + sensor->param = 0; + if (sensor->formula == TELEM_FORMULA_CELL) { + sensor->unit = UNIT_VOLTS; + sensor->prec = 2; + } + else if (sensor->formula == TELEM_FORMULA_DIST) { + sensor->unit = UNIT_DIST; + sensor->prec = 0; + } + else if (sensor->formula == TELEM_FORMULA_CONSUMPTION) { + sensor->unit = UNIT_MAH; + sensor->prec = 0; + } + } + } + break; + + case SENSOR_FIELD_UNIT: + lcd_putsLeft(y, STR_UNIT); + // TODO flash saving with selectMenuItem where I copied those 2 lines? + lcd_putsiAtt(SENSOR_2ND_COLUMN, y, STR_VTELEMUNIT, sensor->unit, attr); + if (attr) { + CHECK_INCDEC_MODELVAR_ZERO(event, sensor->unit, UNIT_MAX); + if (checkIncDec_Ret) { + telemetryItems[s_currIdx].clear(); + } + } + break; + + case SENSOR_FIELD_PRECISION: + sensor->prec = selectMenuItem(SENSOR_2ND_COLUMN, y, STR_PRECISION, STR_VPREC, sensor->prec, 0, 2, attr, event); + if (attr && checkIncDec_Ret) { + telemetryItems[s_currIdx].clear(); + } + break; + + case SENSOR_FIELD_PARAM1: + if (sensor->type == TELEM_TYPE_CALCULATED) { + if (sensor->formula == TELEM_FORMULA_CELL) { + lcd_putsLeft(y, STR_CELLSENSOR); + putsMixerSource(SENSOR_2ND_COLUMN, y, sensor->cell.source ? MIXSRC_FIRST_TELEM+3*(sensor->cell.source-1) : 0, attr); + if (attr) { + sensor->cell.source = checkIncDec(event, sensor->cell.source, 0, MAX_SENSORS, EE_MODEL|NO_INCDEC_MARKS, isCellsSensor); + } + break; + } + else if (sensor->formula == TELEM_FORMULA_DIST) { + lcd_putsLeft(y, "GPS sensor"); + putsMixerSource(SENSOR_2ND_COLUMN, y, sensor->dist.gps ? MIXSRC_FIRST_TELEM+3*(sensor->dist.gps-1) : 0, attr); + if (attr) { + sensor->dist.gps = checkIncDec(event, sensor->dist.gps, 0, MAX_SENSORS, EE_MODEL|NO_INCDEC_MARKS, isGPSSensor); + } + break; + } + else if (sensor->formula == TELEM_FORMULA_CONSUMPTION) { + lcd_putsLeft(y, "Amps sensor"); + putsMixerSource(SENSOR_2ND_COLUMN, y, sensor->consumption.source ? MIXSRC_FIRST_TELEM+3*(sensor->consumption.source-1) : 0, attr); + if (attr) { + sensor->consumption.source = checkIncDec(event, sensor->consumption.source, 0, MAX_SENSORS, EE_MODEL|NO_INCDEC_MARKS, isCurrentSensor); + } + break; + } + } + else { + lcd_putsLeft(y, "Ratio"); + if (attr) CHECK_INCDEC_MODELVAR(event, sensor->custom.ratio, 0, 30000); + if (sensor->custom.ratio == 0) + lcd_putsAtt(SENSOR_2ND_COLUMN, y, "-", attr); + else + lcd_outdezAtt(SENSOR_2ND_COLUMN, y, sensor->custom.ratio, LEFT|attr|PREC1); + break; + } + // no break + + case SENSOR_FIELD_PARAM2: + if (sensor->type == TELEM_TYPE_CALCULATED) { + if (sensor->formula == TELEM_FORMULA_CELL) { + sensor->cell.index = selectMenuItem(SENSOR_2ND_COLUMN, y, "Cell index", "\007Lowest\0001\0 2\0 3\0 4\0 5\0 6\0 HighestDelta\0", sensor->cell.index, 0, 8, attr, event); + break; + } + else if (sensor->formula == TELEM_FORMULA_DIST) { + lcd_putsLeft(y, "Alt sensor"); + putsMixerSource(SENSOR_2ND_COLUMN, y, sensor->dist.alt ? MIXSRC_FIRST_TELEM+3*(sensor->dist.alt-1) : 0, attr); + if (attr) { + sensor->dist.alt = checkIncDec(event, sensor->dist.alt, 0, MAX_SENSORS, EE_MODEL|NO_INCDEC_MARKS, isAltSensor); + } + break; + } + } + else { + lcd_putsLeft(y, NO_INDENT(STR_OFFSET)); + if (attr) CHECK_INCDEC_MODELVAR(event, sensor->custom.offset, -30000, +30000); + if (sensor->prec > 0) attr |= (sensor->prec == 2 ? PREC2 : PREC1); + lcd_outdezAtt(SENSOR_2ND_COLUMN, y, sensor->custom.offset, LEFT|attr); + break; + } + // no break + + case SENSOR_FIELD_PARAM3: + // no break + + case SENSOR_FIELD_PARAM4: + { + putsStrIdx(MENU_TITLE_LEFT, y, NO_INDENT(STR_SOURCE), k-SENSOR_FIELD_PARAM1+1); + int8_t & source = sensor->calc.sources[k-SENSOR_FIELD_PARAM1]; + if (attr) { + source = checkIncDec(event, source, -MAX_SENSORS, MAX_SENSORS, EE_MODEL|NO_INCDEC_MARKS, isSensorAvailable); + } + if (source < 0) { + lcd_putsAtt(SENSOR_2ND_COLUMN, y, "-", attr); + putsMixerSource(SENSOR_2ND_COLUMN+5, y, MIXSRC_FIRST_TELEM+3*(-1-source), attr); + } + else { + putsMixerSource(SENSOR_2ND_COLUMN, y, source ? MIXSRC_FIRST_TELEM+3*(source-1) : 0, attr); + } + break; + } + + case SENSOR_FIELD_AUTOOFFSET: + ON_OFF_MENU_ITEM(sensor->autoOffset, SENSOR_2ND_COLUMN, y, STR_AUTOOFFSET, attr, event); + break; + + case SENSOR_FIELD_FILTER: + ON_OFF_MENU_ITEM(sensor->filter, SENSOR_2ND_COLUMN, y, STR_FILTER, attr, event); + break; + + case SENSOR_FIELD_PERSISTENT: + ON_OFF_MENU_ITEM(sensor->persistent, SENSOR_2ND_COLUMN, y, NO_INDENT(STR_PERSISTENT), attr, event); + break; + + } + } +} + +void onSensorMenu(const char *result) +{ + uint8_t index = m_posVert - ITEM_TELEMETRY_SENSOR1; + + if (index < MAX_SENSORS) { + if (result == STR_EDIT) { + pushMenu(menuModelSensor); + } + else if (result == STR_DELETE) { + delTelemetryIndex(index); + index += 1; + if (index0) ? BLINK|INVERS : INVERS); + LcdFlags attr = (sub == k ? blink : 0); + + if (k>=ITEM_TELEMETRY_SENSOR1 && k= 0) { + s_currIdx = res; + pushMenu(menuModelSensor); + } + } + break; + + case ITEM_TELEMETRY_RSSI_LABEL: + lcd_putsLeft(y, PSTR("RSSI")); + break; + + case ITEM_TELEMETRY_RSSI_ALARM1: + case ITEM_TELEMETRY_RSSI_ALARM2: { + uint8_t alarm = k-ITEM_TELEMETRY_RSSI_ALARM1; + lcd_putsLeft(y, (alarm==0 ? STR_LOWALARM : STR_CRITICALALARM)); + lcd_outdezNAtt(TELEM_COL2, y, getRssiAlarmValue(alarm), LEFT|attr, 3); + if (attr && s_editMode>0) { + CHECK_INCDEC_MODELVAR(event, g_model.frsky.rssiAlarms[alarm].value, -30, 30); + } + break; + } + +#if defined(VARIO) + case ITEM_TELEMETRY_VARIO_LABEL: + lcd_putsLeft(y, STR_VARIO); + break; + + case ITEM_TELEMETRY_VARIO_SOURCE: + lcd_putsLeft(y, STR_SOURCE); + putsMixerSource(TELEM_COL2, y, g_model.frsky.varioSource ? MIXSRC_FIRST_TELEM+3*(g_model.frsky.varioSource-1) : 0, attr); + if (attr) { + g_model.frsky.varioSource = checkIncDec(event, g_model.frsky.varioSource, 0, MAX_SENSORS, EE_MODEL|NO_INCDEC_MARKS, isSensorAvailable); + } + break; + + case ITEM_TELEMETRY_VARIO_RANGE: + lcd_putsLeft(y, STR_LIMIT); + lcd_outdezAtt(TELEM_COL2, y, -10+g_model.frsky.varioMin, (m_posHorz<=0 ? attr : 0)|LEFT); + lcd_outdezAtt(TELEM_COL2+50, y, -5+g_model.frsky.varioCenterMin, ((CURSOR_ON_LINE() || m_posHorz==1) ? attr : 0)|PREC1); + lcd_outdezAtt(TELEM_COL2+75, y, 5+g_model.frsky.varioCenterMax, ((CURSOR_ON_LINE() || m_posHorz==2) ? attr : 0)|PREC1); + lcd_outdezAtt(TELEM_COL2+100, y, 10+g_model.frsky.varioMax, ((CURSOR_ON_LINE() || m_posHorz==3) ? attr : 0)); + if (attr && s_editMode>0) { + switch (m_posHorz) { + case 0: + CHECK_INCDEC_MODELVAR(event, g_model.frsky.varioMin, -7, 7); + break; + case 1: + CHECK_INCDEC_MODELVAR(event, g_model.frsky.varioCenterMin, -16, 5+min(10, g_model.frsky.varioCenterMax+5)); + break; + case 2: + CHECK_INCDEC_MODELVAR(event, g_model.frsky.varioCenterMax, -5+max(-10, g_model.frsky.varioCenterMin-5), +15); + break; + case 3: + CHECK_INCDEC_MODELVAR(event, g_model.frsky.varioMax, -7, 7); + break; + } + } + break; +#endif + + case ITEM_TELEMETRY_TOP_BAR_LABEL: + lcd_putsLeft(y, "Main Telemetry Fields"); + break; + + case ITEM_TELEMETRY_TOP_BAR_VOLTAGE: + lcd_putsLeft(y, STR_VOLTAGE); + putsMixerSource(TELEM_COL2, y, g_model.frsky.voltsSource ? MIXSRC_FIRST_TELEM+3*(g_model.frsky.voltsSource-1) : 0, attr); + if (attr) { + g_model.frsky.voltsSource = checkIncDec(event, g_model.frsky.voltsSource, 0, MAX_SENSORS, EE_MODEL|NO_INCDEC_MARKS, isVoltsSensor); + } + break; + + case ITEM_TELEMETRY_TOP_BAR_ALTITUDE: + lcd_putsLeft(y, INDENT "Altitude Source"); + putsMixerSource(TELEM_COL2, y, g_model.frsky.altitudeSource ? MIXSRC_FIRST_TELEM+3*(g_model.frsky.altitudeSource-1) : 0, attr); + if (attr) { + g_model.frsky.altitudeSource = checkIncDec(event, g_model.frsky.altitudeSource, 0, MAX_SENSORS, EE_MODEL|NO_INCDEC_MARKS, isAltSensor); + } + break; + + case ITEM_TELEMETRY_SCREEN_LABEL1: + case ITEM_TELEMETRY_SCREEN_LABEL2: + case ITEM_TELEMETRY_SCREEN_LABEL3: + case ITEM_TELEMETRY_SCREEN_LABEL4: + { + uint8_t screenIndex = TELEMETRY_CURRENT_EDIT_SCREEN(k); + putsStrIdx(MENU_TITLE_LEFT, y, STR_SCREEN, screenIndex+1); + TelemetryScreenType oldScreenType = TELEMETRY_SCREEN_TYPE(screenIndex); + TelemetryScreenType newScreenType = (TelemetryScreenType)selectMenuItem(TELEM_SCRTYPE_COL, y, PSTR(""), STR_VTELEMSCREENTYPE, oldScreenType, 0, TELEMETRY_SCREEN_TYPE_MAX, (m_posHorz==0 ? attr : 0), event); + if (newScreenType != oldScreenType) { + g_model.frsky.screensType = (g_model.frsky.screensType & (~(0x03 << (2*screenIndex)))) | (newScreenType << (2*screenIndex)); + memset(&g_model.frsky.screens[screenIndex], 0, sizeof(g_model.frsky.screens[screenIndex])); + } +#if defined(LUA) + if (newScreenType == TELEMETRY_SCREEN_TYPE_SCRIPT) { + TelemetryScriptData & scriptData = g_model.frsky.screens[screenIndex].script; + + // TODO better function name for --- + // TODO function for these lines + if (ZEXIST(scriptData.file)) + lcd_putsnAtt(TELEM_SCRTYPE_COL+70, y, scriptData.file, sizeof(scriptData.file), (m_posHorz==1 ? attr : 0)); + else + lcd_putsiAtt(TELEM_SCRTYPE_COL+70, y, STR_VCSWFUNC, 0, (m_posHorz==1 ? attr : 0)); + + if (m_posHorz==1 && attr && event==EVT_KEY_BREAK(KEY_ENTER) && READ_ONLY_UNLOCKED()) { + s_editMode = 0; + if (listSdFiles(SCRIPTS_TELEM_PATH, SCRIPTS_EXT, sizeof(g_model.frsky.screens[screenIndex].script.file), g_model.frsky.screens[screenIndex].script.file)) { + menuHandler = onTelemetryScriptFileSelectionMenu; + } + else { + POPUP_WARNING(STR_NO_SCRIPTS_ON_SD); + s_menu_flags = 0; + } + } + } + else if (attr) { + MOVE_CURSOR_FROM_HERE(); + } +#endif + break; + } + + case ITEM_TELEMETRY_SCREEN_LINE1: + case ITEM_TELEMETRY_SCREEN_LINE2: + case ITEM_TELEMETRY_SCREEN_LINE3: + case ITEM_TELEMETRY_SCREEN_LINE4: + case ITEM_TELEMETRY_SCREEN_LINE5: + case ITEM_TELEMETRY_SCREEN_LINE6: + case ITEM_TELEMETRY_SCREEN_LINE7: + case ITEM_TELEMETRY_SCREEN_LINE8: + case ITEM_TELEMETRY_SCREEN_LINE9: + case ITEM_TELEMETRY_SCREEN_LINE10: + case ITEM_TELEMETRY_SCREEN_LINE11: + case ITEM_TELEMETRY_SCREEN_LINE12: + case ITEM_TELEMETRY_SCREEN_LINE13: + case ITEM_TELEMETRY_SCREEN_LINE14: + case ITEM_TELEMETRY_SCREEN_LINE15: + case ITEM_TELEMETRY_SCREEN_LINE16: + { + uint8_t screenIndex, lineIndex; + if (k < ITEM_TELEMETRY_SCREEN_LABEL2) { + screenIndex = 0; + lineIndex = k-ITEM_TELEMETRY_SCREEN_LINE1; + } + else if (k >= ITEM_TELEMETRY_SCREEN_LABEL4) { + screenIndex = 3; + lineIndex = k-ITEM_TELEMETRY_SCREEN_LINE13; + } + else if (k >= ITEM_TELEMETRY_SCREEN_LABEL3) { + screenIndex = 2; + lineIndex = k-ITEM_TELEMETRY_SCREEN_LINE9; + } + else { + screenIndex = 1; + lineIndex = k-ITEM_TELEMETRY_SCREEN_LINE5; + } + +#if defined(GAUGES) + if (IS_BARS_SCREEN(screenIndex)) { + FrSkyBarData & bar = g_model.frsky.screens[screenIndex].bars[lineIndex]; + source_t barSource = bar.source; + putsMixerSource(MENU_TITLE_LEFT+INDENT_WIDTH, y, barSource, (m_posHorz==0 ? attr : 0)); + int barMax = getMaximumValue(barSource); + int barMin = -barMax; + if (barSource) { + if (barSource <= MIXSRC_LAST_CH) { + putsChannelValue(MENU_TITLE_LEFT+INDENT_WIDTH+100, y, barSource, calc100toRESX(bar.barMin), (m_posHorz==1 ? attr : 0) | LEFT); + putsChannelValue(MENU_TITLE_LEFT+INDENT_WIDTH+200, y, barSource, calc100toRESX(bar.barMax), (m_posHorz==2 ? attr : 0) | LEFT); + } + else { + putsChannelValue(MENU_TITLE_LEFT+INDENT_WIDTH+100, y, barSource, bar.barMin, (m_posHorz==1 ? attr : 0) | LEFT); + putsChannelValue(MENU_TITLE_LEFT+INDENT_WIDTH+200, y, barSource, bar.barMax, (m_posHorz==2 ? attr : 0) | LEFT); + } + } + else if (attr) { + MOVE_CURSOR_FROM_HERE(); + } + if (attr && s_editMode>0) { + switch (m_posHorz) { + case 0: + bar.source = CHECK_INCDEC_MODELVAR_ZERO_CHECK(event, barSource, MIXSRC_LAST_TELEM, isSourceAvailable); + if (checkIncDec_Ret) { + if (barSource <= MIXSRC_LAST_CH) { + bar.barMin = -100; + bar.barMax = 100; + } + else { + bar.barMin = 0; + bar.barMax = 0; + } + } + break; + case 1: + bar.barMin = checkIncDec(event, bar.barMin, barMin, bar.barMax, EE_MODEL|NO_INCDEC_MARKS); + break; + case 2: + bar.barMax = checkIncDec(event, bar.barMax, bar.barMin, barMax, EE_MODEL|NO_INCDEC_MARKS); + break; + } + } + } + else +#endif + { + for (int c=0; c0) { + CHECK_INCDEC_MODELVAR_ZERO_CHECK(event, value, MIXSRC_LAST_TELEM, isSourceAvailable); + } + } + if (attr && m_posHorz == NUM_LINE_ITEMS) { + REPEAT_LAST_CURSOR_MOVE(); + } + } + break; + } + } + } +} diff --git a/radio/src/gui/Horus/menus.cpp b/radio/src/gui/Horus/menus.cpp new file mode 100644 index 000000000..ecffd63b1 --- /dev/null +++ b/radio/src/gui/Horus/menus.cpp @@ -0,0 +1,93 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +MenuFuncP g_menuStack[5]; +evt_t menuEvent = 0; +uint8_t g_menuPos[4]; +uint8_t g_menuStackPtr = 0; + +void popMenu() +{ + assert(g_menuStackPtr>0); + g_menuStackPtr = g_menuStackPtr-1; + menuEvent = EVT_ENTRY_UP; +} + +void chainMenu(MenuFuncP newMenu) +{ + g_menuStack[g_menuStackPtr] = newMenu; + menuEvent = EVT_ENTRY; +} + +void pushMenu(MenuFuncP newMenu) +{ + killEvents(KEY_ENTER); + + if (g_menuStackPtr == 0) { + if (newMenu == menuGeneralSetup) + g_menuPos[0] = 1; + if (newMenu == menuModelSelect) + g_menuPos[0] = 0; + } + else { + g_menuPos[g_menuStackPtr] = m_posVert; + } + + g_menuStackPtr++; + + assert(g_menuStackPtr < DIM(g_menuStack)); + + g_menuStack[g_menuStackPtr] = newMenu; + menuEvent = EVT_ENTRY; +} + +void menuModelNotes(evt_t event) +{ + if (event == EVT_ENTRY) { + strcpy(s_text_file, MODELS_PATH "/"); + char *buf = strcat_modelname(&s_text_file[sizeof(MODELS_PATH)], g_eeGeneral.currModel); + strcpy(buf, TEXT_EXT); + } + + menuTextView(event); +} + +void pushModelNotes() +{ + pushMenu(menuModelNotes); +} diff --git a/radio/src/gui/Horus/menus.h b/radio/src/gui/Horus/menus.h new file mode 100644 index 000000000..b8164a04d --- /dev/null +++ b/radio/src/gui/Horus/menus.h @@ -0,0 +1,377 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _MENUS_H_ +#define _MENUS_H_ + +#include "../../keys.h" + +#define NO_HI_LEN 25 + +#if defined(TRANSLATIONS_FR) + #define MENU_COLUMNS 1 + #define COLUMN_X 0 +#else + #define MENU_COLUMNS 2 +#endif + +#define MENUS_SCROLLBAR_WIDTH 2 +#define MENU_COLUMN2_X 180 +#define lcd_putsColumnLeft(x, y, str) lcd_puts((x > MENU_COLUMN2_X+MENU_TITLE_LEFT+68) ? MENU_COLUMN2_X+MENU_TITLE_LEFT : MENU_TITLE_LEFT, y, str) + +typedef int16_t vertpos_t; + +typedef evt_t & check_event_t; +#define horzpos_t int8_t + +extern vertpos_t m_posVert; +extern horzpos_t m_posHorz; +extern vertpos_t s_pgOfs; +extern uint8_t s_noHi; +extern uint8_t calibrationState; + +void lcdDrawCheckBox(coord_t x, coord_t y, uint8_t value, LcdFlags attr); + +typedef void (*MenuFuncP)(evt_t event); +typedef void (*MenuFuncP_PROGMEM)(evt_t event); +extern const MenuFuncP_PROGMEM menuTabModel[]; +extern const MenuFuncP_PROGMEM menuTabGeneral[]; +extern const MenuFuncP_PROGMEM menuTabTelemetry[]; + +extern MenuFuncP g_menuStack[5]; +extern uint8_t g_menuPos[4]; +extern uint8_t g_menuStackPtr; +extern evt_t menuEvent; + +/// goto given Menu, but substitute current menu in menuStack +void chainMenu(MenuFuncP newMenu); +/// goto given Menu, store current menu in menuStack +void pushMenu(MenuFuncP newMenu); +/// return to last menu in menustack +void popMenu(); +///deliver address of last menu which was popped from +inline MenuFuncP lastPopMenu() +{ + return g_menuStack[g_menuStackPtr+1]; +} + +void drawPotsBars(); +void doMainScreenGraphics(); +void menuFirstCalib(evt_t event); + +void onMainViewMenu(const char *result); +void menuMainView(evt_t event); +void menuGeneralDiagAna(evt_t event); + +void menuTelemetryFrsky(evt_t event); +void menuGeneralSetup(evt_t event); +void menuGeneralCalib(evt_t event); +void menuCustomFunctions(evt_t event, CustomFunctionData * functions, CustomFunctionsContext & functionsContext); + +void menuModelSelect(evt_t event); +void menuModelCustomFunctions(evt_t event); +void menuStatisticsView(evt_t event); +void menuStatisticsDebug(evt_t event); +void menuAboutView(evt_t event); + +#if defined(DEBUG_TRACE_BUFFER) +void menuTraceBuffer(evt_t event); +#endif + +void displaySlider(coord_t x, coord_t y, uint8_t value, uint8_t max, uint8_t attr); + +void menuMainViewChannelsMonitor(evt_t event); +void menuChannelsView(evt_t event); + +extern int8_t checkIncDec_Ret; // global helper vars + +#define EDIT_SELECT_MENU -1 +#define EDIT_SELECT_FIELD 0 +#define EDIT_MODIFY_FIELD 1 +#define EDIT_MODIFY_STRING 2 +extern int8_t s_editMode; // global editmode + +// checkIncDec flags +#define EE_GENERAL 0x01 +#define EE_MODEL 0x02 +#define NO_INCDEC_MARKS 0x04 +#define INCDEC_SWITCH 0x08 +#define INCDEC_SOURCE 0x10 +#define INCDEC_REP10 0x40 +#define NO_DBLKEYS 0x80 + +// mawrow special values +#define TITLE_ROW ((uint8_t)-1) +#define HIDDEN_ROW ((uint8_t)-2) + +typedef bool (*IsValueAvailable)(int); +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 0) REPEAT_LAST_CURSOR_MOVE() + +#define POS_VERT_INIT (MAXCOL((uint16_t)0) >= HIDDEN_ROW ? (MAXCOL((uint16_t)1) >= HIDDEN_ROW ? 2 : 1) : 0) +#define POS_HORZ_INIT(posVert) ((COLATTR(posVert) & NAVIGATION_LINE_BY_LINE) ? -1 : 0) +#define EDIT_MODE_INIT 0 // TODO enum + +typedef int (*FnFuncP) (int x); +void DrawFunction(FnFuncP fn, int offset=0); + +#endif // _MENUS_H_ diff --git a/radio/src/gui/Horus/navigation.cpp b/radio/src/gui/Horus/navigation.cpp new file mode 100644 index 000000000..8ec6c69e0 --- /dev/null +++ b/radio/src/gui/Horus/navigation.cpp @@ -0,0 +1,468 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +vertpos_t s_pgOfs; +vertpos_t m_posVert; +horzpos_t m_posHorz; +int8_t s_editMode; +uint8_t s_noHi; +uint8_t calibrationState; // TODO rename this variable + +#if defined(AUTOSWITCH) +int8_t checkIncDecMovedSwitch(int8_t val) +{ + if (s_editMode>0) { + int8_t swtch = getMovedSwitch(); + if (swtch) { + div_t info = switchInfo(swtch); + if (IS_TOGGLE(info.quot)) { + if (info.rem != 0) { + val = (val == swtch ? swtch+2 : swtch); + } + } + else { + val = swtch; + } + } + } + return val; +} +#endif + +int8_t checkIncDec_Ret; + +INIT_STOPS(stops100, 3, -100, 0, 100) +INIT_STOPS(stops1000, 3, -1000, 0, 1000) +INIT_STOPS(stopsSwitch, 15, SWSRC_FIRST, CATEGORY_END(-SWSRC_FIRST_LOGICAL_SWITCH), CATEGORY_END(-SWSRC_FIRST_TRIM), CATEGORY_END(-SWSRC_LAST_SWITCH+1), 0, CATEGORY_END(SWSRC_LAST_SWITCH), CATEGORY_END(SWSRC_FIRST_TRIM-1), CATEGORY_END(SWSRC_FIRST_LOGICAL_SWITCH-1), SWSRC_LAST) + +int checkIncDec(evt_t event, int val, int i_min, int i_max, unsigned int i_flags, IsValueAvailable isValueAvailable, const CheckIncDecStops &stops) +{ + int newval = val; + +#if defined(DBLKEYS) + uint32_t in = KEYS_PRESSED(); + if (!(i_flags & NO_DBLKEYS) && (EVT_KEY_MASK(event))) { + bool dblkey = true; + if (DBLKEYS_PRESSED_RGT_LFT(in)) { + if (!isValueAvailable || isValueAvailable(-val)) + newval = -val; + } + else if (DBLKEYS_PRESSED_RGT_UP(in)) { + newval = (i_max > stops.max() ? stops.max() : i_max); + while (isValueAvailable && !isValueAvailable(newval) && newval>i_min) { + --newval; + } + } + else if (DBLKEYS_PRESSED_LFT_DWN(in)) { + newval = (i_min < stops.min() ? stops.min() : i_min); + while (isValueAvailable && !isValueAvailable(newval) && newval0 && (IS_ROTARY_RIGHT(event) || event==EVT_KEY_FIRST(KEY_UP) || event==EVT_KEY_REPT(KEY_UP))) { + do { + if (IS_KEY_REPT(event) && (i_flags & INCDEC_REP10)) { + newval += min(10, i_max-val); + } + else { + newval++; + } + } while (isValueAvailable && !isValueAvailable(newval) && newval<=i_max); + + if (newval > i_max) { + newval = val; + killEvents(event); + AUDIO_WARNING2(); + } + else { + AUDIO_KEYPAD_UP(); + } + } + else if (s_editMode>0 && (IS_ROTARY_LEFT(event) || event==EVT_KEY_FIRST(KEY_DOWN) || event==EVT_KEY_REPT(KEY_DOWN))) { + do { + if (IS_KEY_REPT(event) && (i_flags & INCDEC_REP10)) { + newval -= min(10, val-i_min); + } + else { + newval--; + } + } while (isValueAvailable && !isValueAvailable(newval) && newval>=i_min); + + if (newval < i_min) { + newval = val; + killEvents(event); + AUDIO_WARNING2(); + } + else { + AUDIO_KEYPAD_DOWN(); + } + } + + if (!READ_ONLY() && i_min==0 && i_max==1 && (event==EVT_KEY_BREAK(KEY_ENTER) || IS_ROTARY_BREAK(event))) { + s_editMode = 0; + newval = !val; + } + +#if defined(AUTOSWITCH) + if (i_flags & INCDEC_SWITCH) { + newval = checkIncDecMovedSwitch(newval); + } +#endif + +#if defined(AUTOSOURCE) + if (i_flags & INCDEC_SOURCE) { + if (s_editMode>0) { + int source = GET_MOVED_SOURCE(i_min, i_max); + if (source) { + newval = source; + } +#if defined(AUTOSWITCH) + else { + unsigned int swtch = abs(getMovedSwitch()); + if (swtch) { + newval = switchToMix(swtch); + } + } +#endif + } + } +#endif + + if (newval > i_max || newval < i_min) { + newval = (newval > i_max ? i_max : i_min); + killEvents(event); + AUDIO_WARNING2(); + } + + if (newval != val) { + if (!(i_flags & NO_INCDEC_MARKS) && (newval != i_max) && (newval != i_min) && stops.contains(newval) && !IS_ROTARY_EVENT(event)) { + bool pause = (newval > val ? !stops.contains(newval+1) : !stops.contains(newval-1)); + if (pause) { + pauseEvents(event); // delay before auto-repeat continues + if (newval>val) // without AUDIO it's optimized, because the 2 sounds are the same + AUDIO_KEYPAD_UP(); + else + AUDIO_KEYPAD_DOWN(); + } + } + eeDirty(i_flags & (EE_GENERAL|EE_MODEL)); + checkIncDec_Ret = (newval > val ? 1 : -1); + } + else { + checkIncDec_Ret = 0; + } + return newval; +} + +#define CURSOR_NOT_ALLOWED_IN_ROW(row) ((int8_t)MAXCOL(row) < 0) +#define MAXCOL_RAW(row) (horTab ? pgm_read_byte(horTab+min(row, (vertpos_t)horTabMax)) : (const uint8_t)0) +#define MAXCOL(row) (MAXCOL_RAW(row) >= HIDDEN_ROW ? MAXCOL_RAW(row) : (const uint8_t)(MAXCOL_RAW(row) & (~NAVIGATION_LINE_BY_LINE))) +#define COLATTR(row) (MAXCOL_RAW(row) == (uint8_t)-1 ? (const uint8_t)0 : (const uint8_t)(MAXCOL_RAW(row) & NAVIGATION_LINE_BY_LINE)) +#define INC(val, min, max) if (valmin) {val--;} else {val=max;} + +void check(check_event_t event, uint8_t curr, const MenuFuncP *menuTab, uint8_t menuTabSize, const pm_uint8_t *horTab, uint8_t horTabMax, vertpos_t rowcount, uint16_t scrollbar_X, uint8_t flags) +{ + vertpos_t l_posVert = m_posVert; + horzpos_t l_posHorz = m_posHorz; + + uint8_t maxcol = MAXCOL(l_posVert); + + if (menuTab && !calibrationState && l_posVert<0) { + int cc = curr; + switch (event) { + case EVT_KEY_BREAK(KEY_RIGHT): + case EVT_ROTARY_RIGHT: + if (++cc == menuTabSize) + cc = 0; + break; + + case EVT_KEY_BREAK(KEY_LEFT): + case EVT_ROTARY_LEFT: + if (cc-- == 0) + cc = menuTabSize-1; + break; + + case EVT_KEY_BREAK(KEY_ENTER): + l_posVert = POS_VERT_INIT; + event = 0; + break; + } + + if (cc != curr) { + chainMenu((MenuFuncP)pgm_read_adr(&menuTab[cc])); + return; + } + } + + switch(event) + { + case EVT_ENTRY: + l_posVert = -1; + l_posHorz = POS_HORZ_INIT(l_posVert); + s_editMode = EDIT_MODE_INIT; + break; + + case EVT_ENTRY_UP: + s_editMode = 0; + l_posHorz = POS_HORZ_INIT(l_posVert); + break; + + case EVT_ROTARY_BREAK: + if (s_editMode > 1) break; + if (m_posHorz < 0 && maxcol > 0 && READ_ONLY_UNLOCKED()) { + l_posHorz = 0; + break; + } + if (READ_ONLY_UNLOCKED()) { + s_editMode = (s_editMode<=0); + } + break; + + case EVT_KEY_LONG(KEY_EXIT): + s_editMode = 0; // TODO needed? we call ENTRY_UP after which does the same + popMenu(); + break; + + case EVT_KEY_BREAK(KEY_EXIT): + if (s_editMode>0) { + s_editMode = 0; + break; + } + + if (l_posHorz >= 0 && (COLATTR(l_posVert) & NAVIGATION_LINE_BY_LINE)) { + l_posHorz = -1; + } + else if (l_posVert >= 0) { + l_posVert = -1; + l_posHorz = 0; +#if 0 + int posVertInit = -1; + if (s_pgOfs != 0 || l_posVert != posVertInit) { + s_pgOfs = 0; + l_posVert = posVertInit; + l_posHorz = POS_HORZ_INIT(l_posVert); + } +#endif + } + else { + popMenu(); + } + break; + + case EVT_KEY_FIRST(KEY_RIGHT): + case EVT_KEY_REPT(KEY_RIGHT): + if (s_editMode != 0) break; + INC(l_posHorz, 0, maxcol); + break; + + case EVT_KEY_FIRST(KEY_LEFT): + case EVT_KEY_REPT(KEY_LEFT): + DEC(l_posHorz, 0, maxcol); + break; + break; + + case EVT_ROTARY_RIGHT: + if (s_editMode != 0) break; + if ((COLATTR(l_posVert) & NAVIGATION_LINE_BY_LINE)) { + if (l_posHorz >= 0) { + INC(l_posHorz, 0, maxcol); + break; + } + } + else + { + if (l_posHorz < maxcol) { + l_posHorz++; + break; + } + else { + l_posHorz = 0; + } + } + // no break + + case EVT_KEY_FIRST(KEY_DOWN): + case EVT_KEY_REPT(KEY_DOWN): + do { + INC(l_posVert, POS_VERT_INIT, rowcount-1); + } while (CURSOR_NOT_ALLOWED_IN_ROW(l_posVert)); + s_editMode = 0; // if we go down, we must be in this mode + l_posHorz = POS_HORZ_INIT(l_posVert); + break; + + case EVT_ROTARY_LEFT: + if (s_editMode != 0) break; + if ((COLATTR(l_posVert) & NAVIGATION_LINE_BY_LINE)) { + if (l_posHorz >= 0) { + DEC(l_posHorz, 0, maxcol); + break; + } + } + else + { + if (l_posHorz > 0) { + l_posHorz--; + break; + } + else { + l_posHorz = 0xff; + } + } + // no break + + case EVT_KEY_FIRST(KEY_UP): + case EVT_KEY_REPT(KEY_UP): + do { + DEC(l_posVert, POS_VERT_INIT, rowcount-1); + } while (CURSOR_NOT_ALLOWED_IN_ROW(l_posVert)); + + s_editMode = 0; // if we go up, we must be in this mode + + if ((COLATTR(l_posVert) & NAVIGATION_LINE_BY_LINE)) + l_posHorz = -1; + else + l_posHorz = min((uint8_t)l_posHorz, MAXCOL(l_posVert)); + + break; + } + + int linesCount = rowcount; + + if (l_posVert <= 0 || (l_posVert==1 && MAXCOL(vertpos_t(0)) >= HIDDEN_ROW) || (l_posVert==2 && MAXCOL(vertpos_t(0)) >= HIDDEN_ROW && MAXCOL(vertpos_t(1)) >= HIDDEN_ROW)) { + s_pgOfs = 0; + if (horTab) { + linesCount = 0; + for (int i=0; i=horTabMax || horTab[i] != HIDDEN_ROW) { + linesCount++; + } + } + } + } + else if (horTab) { + if (rowcount > NUM_BODY_LINES) { + while (1) { + vertpos_t firstLine = 0; + for (int numLines=0; firstLine=horTabMax || horTab[firstLine] != HIDDEN_ROW) { + numLines++; + } + } + if (l_posVert < firstLine) { + s_pgOfs--; + } + else { + vertpos_t lastLine = firstLine; + for (int numLines=0; lastLine=horTabMax || horTab[lastLine] != HIDDEN_ROW) { + numLines++; + } + } + if (l_posVert >= lastLine) { + s_pgOfs++; + } + else { + linesCount = s_pgOfs + NUM_BODY_LINES; + for (int i=lastLine; i=horTabMax || horTab[i] != HIDDEN_ROW) { + linesCount++; + } + } + break; + } + } + } + } + } + else { + if (l_posVert>=NUM_BODY_LINES+s_pgOfs) { + s_pgOfs = l_posVert-NUM_BODY_LINES+1; + } + else if (l_posVert NUM_BODY_LINES) { + displayScrollbar(scrollbar_X, DEFAULT_SCROLLBAR_Y, DEFAULT_SCROLLBAR_H, s_pgOfs, linesCount, NUM_BODY_LINES); + } + + m_posVert = l_posVert; + m_posHorz = l_posHorz; +} + +void check_simple(check_event_t event, uint8_t curr, const MenuFuncP *menuTab, uint8_t menuTabSize, vertpos_t rowcount, uint16_t scrollbar_X) +{ + check(event, curr, menuTab, menuTabSize, 0, 0, rowcount, scrollbar_X); +} + +void check_submenu_simple(check_event_t event, uint8_t rowcount, uint16_t scrollbar_X) +{ + check_simple(event, 0, 0, 0, rowcount, scrollbar_X); +} + +void repeatLastCursorMove(evt_t event) +{ + if (CURSOR_MOVED_LEFT(event) || CURSOR_MOVED_RIGHT(event)) { + putEvent(event); + } + else { + m_posHorz = 0; + } +} diff --git a/radio/src/gui/Horus/popups.cpp b/radio/src/gui/Horus/popups.cpp new file mode 100644 index 000000000..9705d796b --- /dev/null +++ b/radio/src/gui/Horus/popups.cpp @@ -0,0 +1,236 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +const char *s_warning = NULL; +const char *s_warning_info; +uint8_t s_warning_info_len; +uint8_t s_warning_type; +uint8_t s_warning_result = 0; +uint8_t s_warning_info_flags = ZCHAR; +int16_t s_warning_input_value; +int16_t s_warning_input_min; +int16_t s_warning_input_max; + +void displayAlertBox() +{ + drawBlackOverlay(); + lcdDrawFilledRect(POPUP_X, POPUP_Y, POPUP_W, POPUP_H, TEXT_BGCOLOR); + lcd_rect(POPUP_X, POPUP_Y, POPUP_W, POPUP_H, SOLID, ALARM_COLOR); + lcd_rect(POPUP_X+1, POPUP_Y+1, POPUP_W-2, POPUP_H-2, SOLID, ALARM_COLOR); + // lcdDrawBitmap(POPUP_X+15, POPUP_Y+20, LBM_ALERT); +} + +void displayWarningBox() +{ + drawBlackOverlay(); + lcdDrawFilledRect(POPUP_X, POPUP_Y, POPUP_W, POPUP_H, TEXT_BGCOLOR); + lcd_rect(POPUP_X, POPUP_Y, POPUP_W, POPUP_H, SOLID, ALARM_COLOR); + lcd_rect(POPUP_X+1, POPUP_Y+1, POPUP_W-2, POPUP_H-2, SOLID, ALARM_COLOR); + // lcdDrawBitmap(POPUP_X+15, POPUP_Y+20, LBM_WARNING); +} + +void displayMessageBox() +{ + drawBlackOverlay(); + lcdDrawFilledRect(POPUP_X, POPUP_Y, POPUP_W, POPUP_H, TEXT_BGCOLOR); + lcd_rect(POPUP_X, POPUP_Y, POPUP_W, POPUP_H, SOLID, WARNING_COLOR); + lcd_rect(POPUP_X+1, POPUP_Y+1, POPUP_W-2, POPUP_H-2, SOLID, WARNING_COLOR); + // lcdDrawBitmap(POPUP_X+15, POPUP_Y+20, LBM_MESSAGE); +} + +void message(const pm_char *title, const pm_char *t, const char *last MESSAGE_SOUND_ARG) +{ + displayAlertBox(); + +#if defined(TRANSLATIONS_FR) || defined(TRANSLATIONS_IT) || defined(TRANSLATIONS_CZ) + lcd_putsAtt(WARNING_LINE_X, WARNING_LINE_Y, STR_WARNING, ALARM_COLOR|DBLSIZE); + lcd_putsAtt(WARNING_LINE_X, WARNING_LINE_Y+15, title, ALARM_COLOR|DBLSIZE); +#else + lcd_putsAtt(WARNING_LINE_X, WARNING_LINE_Y, title, ALARM_COLOR|DBLSIZE); + lcd_putsAtt(WARNING_LINE_X, WARNING_LINE_Y+15, STR_WARNING, ALARM_COLOR|DBLSIZE); +#endif + + if (t) lcd_puts(WARNING_LINE_X, WARNING_INFOLINE_Y, t); + if (last) { + lcd_puts(WARNING_LINE_X, WARNING_INFOLINE_Y+12, last); + AUDIO_ERROR_MESSAGE(sound); + } + + lcdRefresh(); + lcdSetContrast(); + clearKeyEvents(); +} + +void displayPopup(const char *title) +{ + displayMessageBox(); + lcd_putsnAtt(WARNING_LINE_X, WARNING_LINE_Y, title, WARNING_LINE_LEN, DBLSIZE|WARNING_COLOR); + lcdRefresh(); +} + +void displayWarning(evt_t event) +{ + s_warning_result = false; + if (s_warning_type == WARNING_TYPE_INPUT) + displayMessageBox(); + else + displayWarningBox(); + lcd_putsnAtt(WARNING_LINE_X, WARNING_LINE_Y, s_warning, WARNING_LINE_LEN, DBLSIZE | (s_warning_type == WARNING_TYPE_INPUT ? WARNING_COLOR : ALARM_COLOR)); + if (s_warning_info) { + lcd_putsnAtt(WARNING_LINE_X, WARNING_INFOLINE_Y, s_warning_info, s_warning_info_len, WARNING_INFO_FLAGS); + } + lcd_puts(WARNING_LINE_X, WARNING_INFOLINE_Y+12, s_warning_type == WARNING_TYPE_ASTERISK ? STR_EXIT : STR_POPUPS); + switch (event) { +#if defined(ROTARY_ENCODER_NAVIGATION) + case EVT_ROTARY_BREAK: +#endif + case EVT_KEY_BREAK(KEY_ENTER): + if (s_warning_type == WARNING_TYPE_ASTERISK) + break; + s_warning_result = true; + // no break +#if defined(ROTARY_ENCODER_NAVIGATION) + case EVT_ROTARY_LONG: + killEvents(event); +#endif + case EVT_KEY_BREAK(KEY_EXIT): + s_warning = NULL; + s_warning_type = WARNING_TYPE_ASTERISK; + break; + default: + if (s_warning_type != WARNING_TYPE_INPUT) break; + s_editMode = EDIT_MODIFY_FIELD; + s_warning_input_value = checkIncDec(event, s_warning_input_value, s_warning_input_min, s_warning_input_max); + s_editMode = EDIT_SELECT_FIELD; + break; + } +} + +void (*popupFunc)(evt_t event) = NULL; + +const char *s_menu[MENU_MAX_LINES]; +uint8_t s_menu_item = 0; +uint16_t s_menu_count = 0; +uint8_t s_menu_flags = 0; +uint16_t s_menu_offset = 0; +void (*menuHandler)(const char *result); +const char * displayMenu(evt_t event) +{ + const char * result = NULL; + + uint8_t display_count = min(s_menu_count, (uint16_t)MENU_MAX_LINES); + + int y = (LCD_H - (display_count*(FH+1))) / 2; + drawBlackOverlay(); + lcdDrawFilledRect(MENU_X, y, MENU_W, display_count * (FH+1), TEXT_BGCOLOR); + lcd_rect(MENU_X, y, MENU_W, display_count * (FH+1), SOLID, WARNING_COLOR); + + for (uint8_t i=0; i display_count) { + displayScrollbar(MENU_X+MENU_W-1, y+1, MENU_MAX_LINES * (FH+1), s_menu_offset, s_menu_count, MENU_MAX_LINES); + } + + switch(event) { +#if defined(ROTARY_ENCODER_NAVIGATION) + CASE_EVT_ROTARY_LEFT +#endif + case EVT_KEY_FIRST(KEY_MOVE_UP): + case EVT_KEY_REPT(KEY_MOVE_UP): + if (s_menu_item > 0) { + s_menu_item--; + } + else if (s_menu_offset > 0) { + s_menu_offset--; + result = STR_UPDATE_LIST; + } + else { + s_menu_item = display_count - 1; + if (s_menu_count > MENU_MAX_LINES) { + s_menu_offset = s_menu_count - display_count; + result = STR_UPDATE_LIST; + } + } + break; + +#if defined(ROTARY_ENCODER_NAVIGATION) + CASE_EVT_ROTARY_RIGHT +#endif + case EVT_KEY_FIRST(KEY_MOVE_DOWN): + case EVT_KEY_REPT(KEY_MOVE_DOWN): + if (s_menu_item < display_count - 1 && s_menu_offset + s_menu_item + 1 < s_menu_count) { + s_menu_item++; + } + else if (s_menu_count > s_menu_offset + display_count) { + s_menu_offset++; + result = STR_UPDATE_LIST; + } + else { + s_menu_item = 0; + if (s_menu_offset) { + s_menu_offset = 0; + result = STR_UPDATE_LIST; + } + } + break; + CASE_EVT_ROTARY_BREAK + case EVT_KEY_BREAK(KEY_ENTER): + result = s_menu[s_menu_item]; + // no break +#if defined(ROTARY_ENCODER_NAVIGATION) + CASE_EVT_ROTARY_LONG + killEvents(event); +#endif + case EVT_KEY_BREAK(KEY_EXIT): + s_menu_count = 0; + s_menu_item = 0; + s_menu_flags = 0; + s_menu_offset = 0; + break; + } + + return result; +} diff --git a/radio/src/gui/Horus/splash.cpp b/radio/src/gui/Horus/splash.cpp new file mode 100644 index 000000000..b439781dc --- /dev/null +++ b/radio/src/gui/Horus/splash.cpp @@ -0,0 +1,57 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +const uint16_t LBM_SPLASH[] = { +#include "../../bitmaps/Horus/splash.lbm" +}; + +#if defined(SPLASH) +void displaySplash() +{ + lcdDrawBitmap((LCD_W-256)/2, (LCD_H-256)/2, LBM_SPLASH); + +#if MENUS_LOCK == 1 + if (readonly == false) { + lcdDrawFilledRect((LCD_W-(sizeof(TR_UNLOCKED)-1)*FW)/2 - 9, 50, (sizeof(TR_UNLOCKED)-1)*FW+16, 11, SOLID, ERASE|ROUND); + lcd_puts((LCD_W-(sizeof(TR_UNLOCKED)-1)*FW)/2 , 53, STR_UNLOCKED); + } +#endif + + lcdRefresh(); +} +#endif diff --git a/radio/src/gui/Horus/view_about.cpp b/radio/src/gui/Horus/view_about.cpp new file mode 100644 index 000000000..2ac6ad383 --- /dev/null +++ b/radio/src/gui/Horus/view_about.cpp @@ -0,0 +1,159 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +enum AboutScreens { + ABOUT_OPENTX, + ABOUT_BERTRAND, + ABOUT_ANDRE, + ABOUT_MIKE, + ABOUT_KJELL, + ABOUT_MARTIN, + ABOUT_ROMOLO, + ABOUT_ROB, + ABOUT_HARDWARE, + ABOUT_PARENTS, + ABOUT_END, + ABOUT_COUNT, +}; + +#define ABOUT_X 62 +#define ABOUT_INDENT 16 + +void menuAboutView(evt_t event) +{ + static uint8_t screenIndex = 0; + static uint8_t greyIndex = 0; + + switch(event) + { + case EVT_ENTRY: + screenIndex = 0; + greyIndex = 0; + break; + case EVT_KEY_FIRST(KEY_DOWN): + screenIndex < ABOUT_PARENTS ? screenIndex++ : screenIndex = ABOUT_OPENTX; + greyIndex = 0; + break; + case EVT_KEY_FIRST(KEY_UP): + screenIndex > ABOUT_OPENTX ? screenIndex-- : screenIndex = ABOUT_PARENTS; + greyIndex = 0; + break; + case EVT_KEY_FIRST(KEY_EXIT): + chainMenu(menuMainView); + break; + } + + drawMenuTemplate("About", event); + + uint8_t screenDuration = 150; + + switch (screenIndex) { + case ABOUT_OPENTX: + case ABOUT_END: + lcd_puts(ABOUT_X, MENU_HEADER_HEIGHT+1, STR_ABOUT_OPENTX_1); + lcd_puts(ABOUT_X, MENU_CONTENT_TOP + FH, STR_ABOUT_OPENTX_2); + lcd_puts(ABOUT_X, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_OPENTX_3); + lcd_puts(ABOUT_X, MENU_CONTENT_TOP + 3*FH, STR_ABOUT_OPENTX_4); + lcd_puts(ABOUT_X, MENU_CONTENT_TOP + 4*FH, STR_ABOUT_OPENTX_5); + screenDuration = 255; + break; + + case ABOUT_BERTRAND: + lcd_putsAtt(ABOUT_X, MENU_HEADER_HEIGHT+1, STR_ABOUT_BERTRAND_1, INVERS); + lcd_puts(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_BERTRAND_2); + lcd_puts(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_BERTRAND_3); + break; + + case ABOUT_ANDRE: + lcd_putsAtt(ABOUT_X, MENU_HEADER_HEIGHT+1, STR_ABOUT_ANDRE_1, INVERS); + lcd_puts(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_ANDRE_2); + lcd_puts(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_ANDRE_3); + break; + + case ABOUT_MIKE: + lcd_putsAtt(ABOUT_X, MENU_HEADER_HEIGHT+1, STR_ABOUT_MIKE_1, INVERS); + lcd_puts(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_MIKE_2); + lcd_puts(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_MIKE_3); + lcd_puts(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 3*FH, STR_ABOUT_MIKE_4); + break; + + case ABOUT_KJELL: + lcd_putsAtt(ABOUT_X, MENU_HEADER_HEIGHT+1, STR_ABOUT_KJELL_1, INVERS); + lcd_puts(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_KJELL_2); + lcd_puts(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_KJELL_3); + lcd_puts(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 3*FH, STR_ABOUT_KJELL_4); + break; + + case ABOUT_MARTIN: + lcd_putsAtt(ABOUT_X, MENU_HEADER_HEIGHT+1, STR_ABOUT_MARTIN_1, INVERS); + lcd_puts(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_MARTIN_2); + break; + + case ABOUT_ROMOLO: + lcd_putsAtt(ABOUT_X, MENU_HEADER_HEIGHT+1, STR_ABOUT_ROMOLO_1, INVERS); + lcd_puts(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_ROMOLO_2); + lcd_puts(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_ROMOLO_3); + break; + + case ABOUT_ROB: + lcd_putsAtt(ABOUT_X, MENU_HEADER_HEIGHT+1, STR_ABOUT_ROB_1, INVERS); + lcd_puts(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_ROB_2); + break; + + case ABOUT_HARDWARE: + lcd_putsAtt(ABOUT_X, MENU_HEADER_HEIGHT+1, "FrSky", INVERS); + lcd_puts(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_HARDWARE_2); + lcd_puts(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_HARDWARE_3); + break; + + case ABOUT_PARENTS: + lcd_putsAtt(ABOUT_X, MENU_HEADER_HEIGHT+1, STR_ABOUT_PARENTS_1, INVERS); + lcd_puts(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + FH, STR_ABOUT_PARENTS_2); + lcd_puts(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 2*FH, STR_ABOUT_PARENTS_3); + lcd_puts(ABOUT_X+ABOUT_INDENT, MENU_CONTENT_TOP + 3*FH, STR_ABOUT_PARENTS_4); + screenDuration = 255; + break; + } + + if (++greyIndex == screenDuration) { + greyIndex = 0; + if (++screenIndex == ABOUT_COUNT) { + chainMenu(menuMainView); + } + } +} diff --git a/radio/src/gui/Horus/view_channels.cpp b/radio/src/gui/Horus/view_channels.cpp new file mode 100644 index 000000000..e2a2bb2c0 --- /dev/null +++ b/radio/src/gui/Horus/view_channels.cpp @@ -0,0 +1,122 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +bool isChannelUsed(int channel); +int getChannelsUsed(); + +void menuChannelsView(evt_t event) +{ + const int CHANNEL_MARGIN = 16; + const int CHANNEL_HEIGHT = 25; + const int CHANNEL_WIDTH = (LCD_W - 3*CHANNEL_MARGIN) / 2; + const int CHANNEL_PADDING_HORZ = 4; + const int CHANNEL_PADDING_VERT = 2; + const int BAR_WIDTH = CHANNEL_WIDTH-2*CHANNEL_PADDING_HORZ; + + static int view = 0; + int x=CHANNEL_MARGIN, y=CHANNEL_MARGIN; + + int viewMax = (getChannelsUsed() - 1) / 8; + if (viewMax <= 0 || view > viewMax) { + view = 0; + } + else { + switch (event) { + case EVT_KEY_FIRST(KEY_RIGHT): + if (++view > viewMax) + view = 0; + break; + case EVT_KEY_FIRST(KEY_LEFT): + if (--view < 0) + view = viewMax; + break; + } + } + + int skipCount = view*8; + for (int ch=0, index=0; index skipCount) { + // The black background + lcdDrawFilledRect(x, y, CHANNEL_WIDTH, CHANNEL_HEIGHT, TEXT_BGCOLOR); + + // The label + unsigned int lenLabel = ZLEN(g_model.limitData[ch].name); + if (lenLabel > 0) + lcd_putsnAtt(x+CHANNEL_PADDING_HORZ, y+CHANNEL_PADDING_VERT, g_model.limitData[ch].name, sizeof(g_model.limitData[ch].name), ZCHAR); + else + putsChn(x+CHANNEL_PADDING_HORZ, y+CHANNEL_PADDING_VERT, ch+1, 0); + + int32_t val = channelOutputs[ch]; + + // The bar + lcdDrawFilledRect(x+CHANNEL_PADDING_HORZ, y+15, BAR_WIDTH, 6, TEXT_INVERTED_BGCOLOR); + unsigned int lim = g_model.extendedLimits ? 640*2 : 512*2; + unsigned int len = limit(1, (abs(val) * BAR_WIDTH/2 + lim/2) / lim, BAR_WIDTH/2); + unsigned int x0 = (val>0) ? x+CHANNEL_PADDING_HORZ-1+BAR_WIDTH/2 : x+CHANNEL_PADDING_HORZ+BAR_WIDTH/2+1-len; + lcdDrawFilledRect(x0, y+16, len, 4, TEXT_BGCOLOR); + + y += CHANNEL_HEIGHT + CHANNEL_MARGIN; + if (y >= 4*(CHANNEL_HEIGHT + CHANNEL_MARGIN)) { + x += CHANNEL_WIDTH + CHANNEL_MARGIN; + y = CHANNEL_MARGIN; + } + } + } + } + +#if 0 + +#if defined(CHANNELS_MONITOR_INV_HIDE) + //if channel output is inverted, show it with oposite sign + if (g_model.limitData[ch].revert) val = -val; +#endif + + // Value +#if defined(PPM_UNIT_US) + uint8_t wbar = (longNames ? 54 : 64); + lcd_outdezAtt(x+LCD_W/2-3-wbar-ofs, y+1, PPM_CH_CENTER(ch)+val/2, TINSIZE); +#elif defined(PPM_UNIT_PERCENT_PREC1) + uint8_t wbar = (longNames ? 48 : 58); + lcd_outdezAtt(x+LCD_W/2-3-wbar-ofs, y+1, calcRESXto1000(val), PREC1|TINSIZE); +#else + uint8_t wbar = (longNames ? 54 : 64); + lcd_outdezAtt(x+LCD_W/2-3-wbar-ofs, y+1, calcRESXto1000(val)/10, TINSIZE); // G: Don't like the decimal part* +#endif +#endif +} diff --git a/radio/src/gui/Horus/view_main.cpp b/radio/src/gui/Horus/view_main.cpp new file mode 100644 index 000000000..6d75f4aae --- /dev/null +++ b/radio/src/gui/Horus/view_main.cpp @@ -0,0 +1,374 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +#define BIGSIZE MIDSIZE +#define BAR_HEIGHT (BOX_WIDTH-9) +#define LBOX_CENTERX (BOX_WIDTH/2 + 17) +#define RBOX_CENTERX (LCD_W-LBOX_CENTERX) +#define BITMAP_X ((LCD_W-64)/2) +#define BITMAP_Y (LCD_H/2) +#define TRIM_LH_X (32+9) +#define TRIM_LV_X 10 +#define TRIM_RV_X (LCD_W-11) +#define TRIM_RH_X (LCD_W-32-9) +#define TRIM_LEN 27 + +void drawPotsBars() +{ + // Optimization by Mike Blandford + uint8_t x, i, len ; // declare temporary variables + for (x=LCD_W/2-9, i=NUM_STICKS; i 125) { + exttrim = true; + } + + if (val < -(TRIM_LEN+1)*4) { + val = -(TRIM_LEN+1); + } + else if (val > (TRIM_LEN+1)*4) { + val = TRIM_LEN+1; + } + else { + val /= 4; + } + + if (vert[i]) { + ym = 31; + lcd_vline(xm, ym-TRIM_LEN, TRIM_LEN*2); + if (i!=2 || !g_model.thrTrim) { + lcd_vline(xm-1, ym-1, 3); + lcd_vline(xm+1, ym-1, 3); + } + ym -= val; + + // TODO lcdDrawFilledRect(xm-3, ym-3, 7, 7, SOLID, att); + if (dir >= 0) { + lcd_hline(xm-1, ym-1, 3); + } + if (dir <= 0) { + lcd_hline(xm-1, ym+1, 3); + } + if (exttrim) { + lcd_hline(xm-1, ym, 3); + } + } + else { + ym = 60; + lcd_hline(xm-TRIM_LEN, ym, TRIM_LEN*2); + lcd_hline(xm-1, ym-1, 3); + lcd_hline(xm-1, ym+1, 3); + xm += val; + + // TODO lcdDrawFilledRect(xm-3, ym-3, 7, 7, SOLID, att); + if (dir >= 0) { + lcd_vline(xm+1, ym-1, 3); + } + if (dir <= 0) { + lcd_vline(xm-1, ym-1, 3); + } + if (exttrim) { + lcd_vline(xm, ym-1, 3); + } + } + lcd_square(xm-3, ym-3, 7, att); + } +} + +void displayTimers() +{ + // const int TIMERS_W = 56; + const int TIMERS_H = 30; + const int TIMERS_MARGIN = 16; + const int TIMERS_PADDING = 4; + + for (int i=0; i 0) + lcd_putsnAtt(TIMERS_MARGIN+TIMERS_PADDING, y+2, timerData.name, LEN_TIMER_NAME, color|ZCHAR); + else + putsTimerMode(TIMERS_MARGIN+TIMERS_PADDING, y+2, timerData.mode, color); + } + } +} + +void displayMainTelemetryFields() +{ + const int ALTITUDE_Y = 16; + const int VOLTS_Y = 16+16+30; + const int ALTITUDE_W = 56; + const int ALTITUDE_X = LCD_W-ALTITUDE_Y-ALTITUDE_W; + const int ALTITUDE_H = 30; + const int PADDING = 4; + + if (g_model.frsky.voltsSource) { + TelemetryItem & item = telemetryItems[g_model.frsky.voltsSource-1]; + if (item.isAvailable()) { + int32_t value = item.value; + TelemetrySensor & sensor = g_model.telemetrySensors[g_model.frsky.altitudeSource-1]; + LcdFlags att = 0; + if (sensor.prec == 2) { + att |= PREC1; + value /= 10; + } + else if (sensor.prec == 1) { + att |= PREC1; + } + att |= (item.isOld() ? ALARM_COLOR : TEXT_COLOR); + lcdDrawFilledRect(ALTITUDE_X, VOLTS_Y, ALTITUDE_W, ALTITUDE_H, TEXT_BGCOLOR); + lcd_putsAtt(ALTITUDE_X+PADDING, VOLTS_Y+2, "Voltage", att); + putsValueWithUnit(ALTITUDE_X+PADDING, VOLTS_Y+12, value, UNIT_VOLTS, DBLSIZE|LEFT|att); + } + } + + if (g_model.frsky.altitudeSource) { + TelemetryItem & item = telemetryItems[g_model.frsky.altitudeSource-1]; + if (item.isAvailable()) { + int32_t value = item.value; + TelemetrySensor & sensor = g_model.telemetrySensors[g_model.frsky.altitudeSource-1]; + if (sensor.prec) value /= sensor.prec == 2 ? 100 : 10; + LcdFlags att = (item.isOld() ? ALARM_COLOR : TEXT_COLOR); + lcdDrawFilledRect(ALTITUDE_X, ALTITUDE_Y, ALTITUDE_W, ALTITUDE_H, TEXT_BGCOLOR); + lcd_putsAtt(ALTITUDE_X+PADDING, ALTITUDE_Y+2, "Alt", att); + putsValueWithUnit(ALTITUDE_X+PADDING, ALTITUDE_Y+12, value, UNIT_METERS, DBLSIZE|LEFT|att); + } + } +} + +bool isViewAvailable(int index) +{ + if (index <= VIEW_CHANNELS) + return true; + else + return TELEMETRY_SCREEN_TYPE(index-VIEW_TELEM1) != TELEMETRY_SCREEN_TYPE_NONE; +} + +void displayMainViewIndex() +{ + int x = LCD_W - 14; + + for (int i=VIEW_COUNT; i>=0; --i) { + if (isViewAvailable(i)) { + if (g_eeGeneral.view == i) { + lcdDrawFilledRect(x, MENU_FOOTER_TOP+17, 9, 9, TEXT_INVERTED_BGCOLOR); + } + else { + lcdDrawRect(x+1, MENU_FOOTER_TOP+18, 7, 7, TEXT_COLOR); + } + x -= 11; + } + } +} + +void onMainViewMenu(const char *result) +{ + if (result == STR_RESET_TIMER1) { + timerReset(0); + } + else if (result == STR_RESET_TIMER2) { + timerReset(1); + } +#if defined(CPUARM) + else if (result == STR_RESET_TIMER3) { + timerReset(2); + } + else if (result == STR_VIEW_NOTES) { + pushModelNotes(); + } + else if (result == STR_RESET_SUBMENU) { + MENU_ADD_ITEM(STR_RESET_FLIGHT); + MENU_ADD_ITEM(STR_RESET_TIMER1); + MENU_ADD_ITEM(STR_RESET_TIMER2); + MENU_ADD_ITEM(STR_RESET_TIMER3); +#if defined(FRSKY) + MENU_ADD_ITEM(STR_RESET_TELEMETRY); +#endif + } +#endif +#if defined(FRSKY) + else if (result == STR_RESET_TELEMETRY) { + telemetryReset(); + } +#endif + else if (result == STR_RESET_FLIGHT) { + flightReset(); + } + else if (result == STR_STATISTICS) { + chainMenu(menuStatisticsView); + } +#if defined(CPUARM) + else if (result == STR_ABOUT_US) { + chainMenu(menuAboutView); + } +#endif +} + +void displayTelemetryScreen(int index, unsigned int evt); + +void menuMainView(evt_t event) +{ + // clear the screen + lcdDrawFilledRect(0, 0, LCD_W, LCD_H, TEXT_BGCOLOR); + + switch (event) { + case EVT_ENTRY: + killEvents(KEY_EXIT); + killEvents(KEY_UP); + killEvents(KEY_DOWN); + break; + + case EVT_KEY_LONG(KEY_ENTER): + killEvents(event); + if (modelHasNotes()) { + MENU_ADD_ITEM(STR_VIEW_NOTES); + } + MENU_ADD_ITEM(STR_RESET_SUBMENU); + MENU_ADD_ITEM(STR_STATISTICS); + MENU_ADD_ITEM(STR_ABOUT_US); + menuHandler = onMainViewMenu; + break; + + case EVT_KEY_BREAK(KEY_MENU): + pushMenu(menuModelSetup); + break; + + case EVT_KEY_LONG(KEY_MENU): + killEvents(event); + pushMenu(menuGeneralSetup); + break; + + case EVT_KEY_BREAK(KEY_DOWN): + eeDirty(EE_GENERAL); + g_eeGeneral.view = circularIncDec(g_eeGeneral.view, +1, 0, VIEW_COUNT-1, isViewAvailable); + break; + + case EVT_KEY_BREAK(KEY_UP): + killEvents(event); + eeDirty(EE_GENERAL); + g_eeGeneral.view = circularIncDec(g_eeGeneral.view, -1, 0, VIEW_COUNT-1, isViewAvailable); + break; + + case EVT_KEY_FIRST(KEY_EXIT): +#if defined(GVARS) + if (s_gvar_timer > 0) { + s_gvar_timer = 0; + } +#endif + AUDIO_KEYPAD_UP(); + break; + } + +#if 0 + displayMainViewIndex(); + + if (g_eeGeneral.view == VIEW_TIMERS_ALTITUDE) { + displayTimers(); + displayMainTelemetryFields(); + } + else if (g_eeGeneral.view == VIEW_CHANNELS) { + menuChannelsView(event); + } + else { + displayTelemetryScreen(g_eeGeneral.view - VIEW_TELEM1, event); + } +#endif + +#if defined(GVARS) + if (s_gvar_timer > 0) { + s_gvar_timer--; + displayMessageBox(); + putsStrIdx(WARNING_LINE_X, WARNING_LINE_Y, STR_GV, s_gvar_last+1, DBLSIZE|YELLOW); + lcd_putsnAtt(WARNING_LINE_X+45, WARNING_LINE_Y, g_model.gvars[s_gvar_last].name, LEN_GVAR_NAME, DBLSIZE|YELLOW|ZCHAR); + lcd_outdezAtt(WARNING_LINE_X, WARNING_INFOLINE_Y, GVAR_VALUE(s_gvar_last, getGVarFlightPhase(mixerCurrentFlightMode, s_gvar_last)), DBLSIZE|LEFT); + } +#endif +} + +void menuMainViewChannelsMonitor(evt_t event) +{ + switch(event) { + case EVT_KEY_BREAK(KEY_EXIT): + chainMenu(menuMainView); + event = 0; + break; + } + + return menuChannelsView(event); +} diff --git a/radio/src/gui/Horus/view_statistics.cpp b/radio/src/gui/Horus/view_statistics.cpp new file mode 100644 index 000000000..c0fc2965a --- /dev/null +++ b/radio/src/gui/Horus/view_statistics.cpp @@ -0,0 +1,213 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +void menuStatisticsView(evt_t event) +{ + drawMenuTemplate("Statistics", event); + + switch(event) + { + case EVT_KEY_FIRST(KEY_UP): + chainMenu(menuStatisticsDebug); + break; + + case EVT_KEY_LONG(KEY_MENU): + g_eeGeneral.globalTimer = 0; + eeDirty(EE_GENERAL); + sessionTimer = 0; + break; + + case EVT_KEY_FIRST(KEY_EXIT): + chainMenu(menuMainView); + break; + } + + lcd_putsAtt( 10, MENU_CONTENT_TOP + FH*0, "\037\145TOT:\037\317BATT:", HEADER_COLOR); + lcd_putsAtt( 10, MENU_CONTENT_TOP + FH*1, "TM1:\037\145TM2:", HEADER_COLOR); + lcd_putsAtt( 10, MENU_CONTENT_TOP + FH*2, "THR:\037\145TH%:", HEADER_COLOR); + + putsTimer( 45, MENU_CONTENT_TOP + FH*1, timersStates[0].val); + putsTimer( 140, MENU_CONTENT_TOP + FH*1, timersStates[1].val); + putsTimer( 45, MENU_CONTENT_TOP + FH*2, s_timeCumThr); + putsTimer( 140, MENU_CONTENT_TOP + FH*2, s_timeCum16ThrP/16); + putsTimer( 140, MENU_CONTENT_TOP + FH*0, sessionTimer); + putsTimer( 250, MENU_CONTENT_TOP + 0*FH, g_eeGeneral.globalTimer+sessionTimer, TIMEHOUR); + +#if defined(THRTRACE) + coord_t traceRd = (s_traceCnt < 0 ? s_traceWr : 0); + const coord_t x = 4; + const coord_t y = 200; + lcd_hlineStip(x-3, y, MAXTRACE+3+3, SOLID, TEXT_COLOR); + lcd_vlineStip(x, y-96, 96+3, SOLID, TEXT_COLOR); + + for (coord_t i=0; i=MAXTRACE) traceRd = 0; + if (traceRd==s_traceWr) break; + } +#endif +} + +#define MENU_DEBUG_COL1_OFS (11*10-2) +#define MENU_DEBUG_Y_MIXMAX (MENU_CONTENT_TOP + 2*FH) +#define MENU_DEBUG_Y_LUA (MENU_CONTENT_TOP + 3*FH) +#define MENU_DEBUG_Y_FREE_RAM (MENU_CONTENT_TOP + 4*FH) +#define MENU_DEBUG_Y_STACK (MENU_CONTENT_TOP + 5*FH) +#define MENU_DEBUG_Y_RTOS (MENU_CONTENT_TOP + 6*FH) + +void menuStatisticsDebug(evt_t event) +{ + drawMenuTemplate(STR_MENUDEBUG, event); + + switch(event) + { + case EVT_KEY_LONG(KEY_ENTER): + g_eeGeneral.mAhUsed = 0; + g_eeGeneral.globalTimer = 0; + eeDirty(EE_GENERAL); + sessionTimer = 0; + killEvents(event); + AUDIO_KEYPAD_UP(); + break; + case EVT_KEY_FIRST(KEY_ENTER): +#if defined(LUA) + maxLuaInterval = 0; + maxLuaDuration = 0; +#endif + maxMixerDuration = 0; + AUDIO_KEYPAD_UP(); + break; + +#if defined(DEBUG_TRACE_BUFFER) + case EVT_KEY_FIRST(KEY_UP): + pushMenu(menuTraceBuffer); + return; +#endif + + case EVT_KEY_FIRST(KEY_DOWN): + chainMenu(menuStatisticsView); + break; + case EVT_KEY_FIRST(KEY_EXIT): + chainMenu(menuMainView); + break; + } + + lcd_putsLeft(MENU_DEBUG_Y_FREE_RAM, "Free Mem"); + lcd_outdezAtt(MENU_DEBUG_COL1_OFS, MENU_DEBUG_Y_FREE_RAM, availableMemory(), LEFT, "b"); + +#if defined(LUA) + lcd_putsLeft(MENU_DEBUG_Y_LUA, "Lua scripts"); + lcd_putsAtt(MENU_DEBUG_COL1_OFS, MENU_DEBUG_Y_LUA+1, "[Duration]", HEADER_COLOR|SMLSIZE); + lcd_outdezAtt(MENU_DEBUG_COL1_OFS+30, MENU_DEBUG_Y_LUA, 10*maxLuaDuration, LEFT); + lcd_putsAtt(MENU_DEBUG_COL1_OFS+60, MENU_DEBUG_Y_LUA+1, "[Interval]", HEADER_COLOR|SMLSIZE); + lcd_outdezAtt(MENU_DEBUG_COL1_OFS+90, MENU_DEBUG_Y_LUA, 10*maxLuaInterval, LEFT); +#endif + + lcd_putsLeft(MENU_DEBUG_Y_MIXMAX, STR_TMIXMAXMS); + lcd_outdezAtt(MENU_DEBUG_COL1_OFS, MENU_DEBUG_Y_MIXMAX, DURATION_MS_PREC2(maxMixerDuration), PREC2|LEFT, "ms"); + + lcd_putsLeft(MENU_DEBUG_Y_RTOS, STR_FREESTACKMINB); + lcd_putsAtt(MENU_DEBUG_COL1_OFS, MENU_DEBUG_Y_RTOS+1, "[Menus]", HEADER_COLOR|SMLSIZE); + lcd_outdezAtt(MENU_DEBUG_COL1_OFS+30, MENU_DEBUG_Y_RTOS, menusStack.available(), LEFT); + lcd_putsAtt(MENU_DEBUG_COL1_OFS+60, MENU_DEBUG_Y_RTOS+1, "[Mix]", HEADER_COLOR|SMLSIZE); + lcd_outdezAtt(MENU_DEBUG_COL1_OFS+90, MENU_DEBUG_Y_RTOS, mixerStack.available(), LEFT); + lcd_putsAtt(MENU_DEBUG_COL1_OFS+120, MENU_DEBUG_Y_RTOS+1, "[Audio]", HEADER_COLOR|SMLSIZE); + lcd_outdezAtt(MENU_DEBUG_COL1_OFS+150, MENU_DEBUG_Y_RTOS, audioStack.available(), LEFT); + + lcd_putsCenter(7*FH+1, STR_MENUTORESET); + // lcd_status_line(); +} + + +#if defined(DEBUG_TRACE_BUFFER) +#include "stamp-opentx.h" + +void menuTraceBuffer(evt_t event) +{ + switch(event) + { + case EVT_KEY_LONG(KEY_ENTER): + dumpTraceBuffer(); + killEvents(event); + break; + } + + SIMPLE_SUBMENU("Trace Buffer " VERS_STR, TRACE_BUFFER_LEN); + /* RTC time */ + struct gtm t; + gettime(&t); + putsTime(LCD_W+1, 0, t, TIMEBLINK); + + uint8_t y = 0; + uint8_t k = 0; + int8_t sub = m_posVert; + + lcd_putc(0, FH, '#'); + lcd_puts(4*10, FH, "Time"); + lcd_puts(14*10, FH, "Event"); + lcd_puts(20*10, FH, "Data"); + + for (uint8_t i=0; itime % SECS_PER_DAY; + putsTimer(4*10, y, tme, TIMEHOUR|LEFT); + //event + lcd_outdezNAtt(14*10, y, te->event, LEADING0|LEFT, 3); + //data + lcd_putsn (20*10, y, "0x", 2); + lcd_outhex4(22*10-2, y, (uint16_t)(te->data >> 16)); + lcd_outhex4(25*10, y, (uint16_t)(te->data & 0xFFFF)); + } + + } + + +} +#endif //#if defined(DEBUG_TRACE_BUFFER) diff --git a/radio/src/gui/Horus/view_telemetry.cpp b/radio/src/gui/Horus/view_telemetry.cpp new file mode 100644 index 000000000..2e76051b0 --- /dev/null +++ b/radio/src/gui/Horus/view_telemetry.cpp @@ -0,0 +1,202 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +#define STATUS_BAR_Y (7*FH+1) +#define TELEM_2ND_COLUMN (11*10) + +#if defined(FRSKY_HUB) && defined(GAUGES) +bar_threshold_t barsThresholds[THLD_MAX]; +#endif + +NOINLINE uint8_t getRssiAlarmValue(uint8_t alarm) +{ + return (45 - 3*alarm + g_model.frsky.rssiAlarms[alarm].value); +} + +int barCoord(int value, int min, int max, int width) +{ + if (value <= min) + return 0; + else if (value >= max) + return width; + else + return (width * (value - min) + (max - min)/2) / (max - min); +} + +void displayGaugesTelemetryScreen(FrSkyScreenData & screen) +{ + const int GAUGE_MARGIN = 16; + const int GAUGE_HEIGHT = 25; + const int GAUGE_WIDTH = LCD_W - 2*GAUGE_MARGIN; + const int GAUGE_PADDING_HORZ = 4; + const int GAUGE_PADDING_VERT = 2; + const int VAL_WIDTH = 50; + const int BAR_WIDTH = GAUGE_WIDTH-2*GAUGE_PADDING_HORZ-VAL_WIDTH; + + for (int i=0; i<4; ++i) { + FrSkyBarData & bar = screen.bars[i]; + source_t source = bar.source; + getvalue_t barMin = bar.barMin; + getvalue_t barMax = bar.barMax; + if (source <= MIXSRC_LAST_CH) { + barMin = calc100toRESX(barMin); + barMax = calc100toRESX(barMax); + } + if (source && barMax > barMin) { + int y = GAUGE_MARGIN + i*(GAUGE_HEIGHT+GAUGE_MARGIN); + + // The black background + lcdDrawFilledRect(GAUGE_MARGIN, y, GAUGE_WIDTH, GAUGE_HEIGHT, TEXT_BGCOLOR); + + getvalue_t value = getValue(source); + LcdFlags color = TEXT_COLOR; + if (source >= MIXSRC_FIRST_TELEM) { + TelemetryItem & telemetryItem = telemetryItems[(source-MIXSRC_FIRST_TELEM)/3]; // TODO macro to convert a source to a telemetry index + if (!telemetryItem.isAvailable()) { + continue; + } + else if (telemetryItem.isOld()) { + color = ALARM_COLOR; + } + } + else if (source >= MIXSRC_FIRST_TIMER && source <= MIXSRC_LAST_TIMER) { + if (value < 0) { + putsMixerSource(GAUGE_MARGIN+GAUGE_PADDING_HORZ, y+GAUGE_PADDING_VERT, source, ALARM_COLOR); + putsTimer(GAUGE_MARGIN+GAUGE_WIDTH-VAL_WIDTH, y+GAUGE_PADDING_VERT+3, -value, LEFT|DBLSIZE|ALARM_COLOR); + // TODO lcdDrawFilledRect(GAUGE_MARGIN+GAUGE_PADDING_HORZ, y+15, BAR_WIDTH, 6, ALARM_BGCOLOR); + continue; + } + } + + // The label + putsMixerSource(GAUGE_MARGIN+GAUGE_PADDING_HORZ, y+GAUGE_PADDING_VERT, source, color); + + // The value + putsChannel(GAUGE_MARGIN+GAUGE_WIDTH-VAL_WIDTH, y+GAUGE_PADDING_VERT+3, source, LEFT|DBLSIZE|NO_UNIT|color); + + // The bar + // TODO lcdDrawFilledRect(GAUGE_MARGIN+GAUGE_PADDING_HORZ, y+15, BAR_WIDTH, 6, SOLID, color); + //uint8_t thresholdX = 0; + int width = barCoord(value, barMin, barMax, BAR_WIDTH-2); + //uint8_t barShade = SOLID; + lcdDrawFilledRect(GAUGE_MARGIN+GAUGE_PADDING_HORZ+1, y+16, width, 4, TEXT_BGCOLOR); +/* for (uint8_t j=24; j<99; j+=25) { + if (j>thresholdX || j>width) { + lcd_vline(j*BAR_WIDTH/100+BAR_LEFT+1, y+1, barHeight); + } + } + if (thresholdX) { + lcd_vlineStip(BAR_LEFT+1+thresholdX, y-2, barHeight+3, DOTTED); + lcd_hline(BAR_LEFT+thresholdX, y-2, 3); + } + */ + } + } +} + +void displayNumbersTelemetryScreen(FrSkyScreenData & screen) +{ + const int NUMBERS_W = 56; + const int NUMBERS_H = 30; + const int NUMBERS_MARGIN = 16; + const int NUMBERS_PADDING = 4; + + for (int i=0; i<4; i++) { + for (int j=0; j= MIXSRC_FIRST_TELEM) { + TelemetryItem & telemetryItem = telemetryItems[(field-MIXSRC_FIRST_TELEM)/3]; // TODO macro to convert a source to a telemetry index + if (!telemetryItem.isAvailable()) { + continue; + } + else if (telemetryItem.isOld()) { + color = RED; + } + } + else if (field >= MIXSRC_FIRST_TIMER && field <= MIXSRC_LAST_TIMER) { + TimerState & timerState = timersStates[field-MIXSRC_FIRST_TIMER]; + if (timerState.val < 0) { + color = RED; + } + putsMixerSource(x+NUMBERS_PADDING, y+2, field, color); + putsTimer(x+NUMBERS_PADDING, y+12, abs(timerState.val), LEFT|DBLSIZE|color); + continue; + } + putsMixerSource(x+NUMBERS_PADDING, y+2, field, color); + putsChannel(x+NUMBERS_PADDING, y+12, field, LEFT|DBLSIZE|NO_UNIT|color); + } + } + } +} + +void displayCustomTelemetryScreen(uint8_t index) +{ + FrSkyScreenData & screen = g_model.frsky.screens[index]; + +#if defined(GAUGES) + if (IS_BARS_SCREEN(index)) { + return displayGaugesTelemetryScreen(screen); + } +#endif + + displayNumbersTelemetryScreen(screen); +} + +void displayTelemetryScreen(int index, unsigned int evt) +{ +#if defined(LUA) + if (TELEMETRY_SCREEN_TYPE(index) == TELEMETRY_SCREEN_TYPE_SCRIPT) { + luaTask(evt, RUN_TELEM_FG_SCRIPT, true); + return; + } +#endif + + if (TELEMETRY_SCREEN_TYPE(index) == TELEMETRY_SCREEN_TYPE_NONE) { + return; + } + + if (index < MAX_TELEMETRY_SCREENS) { + return displayCustomTelemetryScreen(index); + } +} diff --git a/radio/src/gui/Horus/view_text.cpp b/radio/src/gui/Horus/view_text.cpp new file mode 100644 index 000000000..b7381d019 --- /dev/null +++ b/radio/src/gui/Horus/view_text.cpp @@ -0,0 +1,161 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" + +#define TEXT_FILE_MAXSIZE 2048 + +char s_text_file[TEXT_FILENAME_MAXLEN]; +char s_text_screen[LCD_LINES-1][LCD_COLS+1]; + +void readTextFile(int & lines_count) +{ + FIL file; + int result; + char c; + unsigned int sz; + int line_length = 0; + int escape = 0; + char escape_chars[2]; + int current_line = 0; + + memset(s_text_screen, 0, sizeof(s_text_screen)); + + result = f_open(&file, s_text_file, FA_OPEN_EXISTING | FA_READ); + if (result == FR_OK) { + for (int i=0; i=s_pgOfs && current_line-s_pgOfs0 && escape<3) { + escape_chars[escape-1] = c; + if (escape == 2 && !strncmp(escape_chars, "up", 2)) { + c = '\300'; + escape = 0; + } + else if (escape == 2 && !strncmp(escape_chars, "dn", 2)) { + c = '\301'; + escape = 0; + } + else { + escape++; + continue; + } + } + else if (c=='~') { + c = 'z'+1; + } + else if (c=='\t') { + c = 0x1D; //tab + } + escape = 0; + s_text_screen[current_line-s_pgOfs][line_length++] = c; + } + } + if (c != '\n') { + current_line += 1; + } + f_close(&file); + } + + if (lines_count == 0) { + lines_count = current_line; + } +} + +void menuTextView(evt_t event) +{ + static int lines_count; + + drawMenuTemplate("TEXT VIEWER", event); + + switch (event) { + case EVT_ENTRY: + s_pgOfs = 0; + lines_count = 0; + readTextFile(lines_count); + break; + + case EVT_KEY_FIRST(KEY_UP): + if (s_pgOfs == 0) + break; + else + s_pgOfs--; + readTextFile(lines_count); + break; + + case EVT_KEY_FIRST(KEY_DOWN): + if (s_pgOfs+NUM_BODY_LINES >= lines_count) + break; + else + ++s_pgOfs; + readTextFile(lines_count); + break; + + case EVT_KEY_BREAK(KEY_EXIT): + popMenu(); + break; + } + + for (int i=0; i NUM_BODY_LINES) { + displayScrollbar(LCD_W-5, 30, MENU_FOOTER_TOP-34, s_pgOfs, lines_count, NUM_BODY_LINES); + } +} + +void pushMenuTextView(const char *filename) +{ + if (strlen(filename) < TEXT_FILENAME_MAXLEN) { + strcpy(s_text_file, filename); + pushMenu(menuTextView); + } +} diff --git a/radio/src/gui/Horus/widgets.cpp b/radio/src/gui/Horus/widgets.cpp new file mode 100644 index 000000000..de9846e35 --- /dev/null +++ b/radio/src/gui/Horus/widgets.cpp @@ -0,0 +1,315 @@ +/* + * Authors (alphabetical order) + * - Andre Bernet + * - Andreas Weitl + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Gabriel Birkus + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - Thomas Husterer + * + * opentx is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../../opentx.h" +#include + +#define COLUMN_HEADER_X 150 +void displayHeader(const char *header) +{ + lcd_putsAtt(COLUMN_HEADER_X, MENU_FOOTER_TOP, header, HEADER_COLOR); +} + +void displayColumnHeader(const char * const *headers, uint8_t index) +{ + displayHeader(headers[index]); +} + +void drawStick(coord_t centrex, int16_t xval, int16_t yval) +{ +#define BOX_CENTERY (170 - FH - BOX_WIDTH/2) +#define MARKER_WIDTH 5 + + lcd_square(centrex-BOX_WIDTH/2, BOX_CENTERY-BOX_WIDTH/2, BOX_WIDTH, TEXT_COLOR); + lcd_vlineStip(centrex, BOX_CENTERY-1, 3, SOLID, TEXT_COLOR); + lcd_hlineStip(centrex-1, BOX_CENTERY, 3, SOLID, TEXT_COLOR); + lcd_square(centrex + (xval/((2*RESX)/(BOX_WIDTH-MARKER_WIDTH))) - MARKER_WIDTH/2, BOX_CENTERY - (yval/((2*RESX)/(BOX_WIDTH-MARKER_WIDTH))) - MARKER_WIDTH/2, MARKER_WIDTH, ROUND|TEXT_COLOR); + +#undef BOX_CENTERY +#undef MARKER_WIDTH +} + +void lcdDrawCheckBox(coord_t x, coord_t y, uint8_t value, LcdFlags attr) +{ + if (attr) { + lcdDrawFilledRect(x-1, y+2, 13, 13, TEXT_INVERTED_BGCOLOR); + lcdDrawFilledRect(x+1, y+4, 9, 9, TEXT_BGCOLOR); + if (value) { + lcdDrawFilledRect(x+2, y+5, 7, 7, TEXT_INVERTED_BGCOLOR); + } + } + else { + if (value) { + lcdDrawFilledRect(x+2, y+5, 7, 7, SCROLLBOX_COLOR); + lcdDrawRect(x, y+3, 11, 11, LINE_COLOR); + } + else { + lcdDrawRect(x, y+3, 11, 11, LINE_COLOR); + } + } +} + +void displayScreenIndex(uint8_t index, uint8_t count) +{ + // char str[10]; + // sprintf(str, "%d/%d", index+1, count); + // lcd_putsAtt(LCD_W-8-getTextWidth(str), MENU_FOOTER_TOP, str, m_posVert < 0 ? INVERS : TEXT_COLOR); +} + +void displayScrollbar(coord_t x, coord_t y, coord_t h, uint16_t offset, uint16_t count, uint8_t visible) +{ + lcdDrawVerticalLine(x, y, h, LINE_COLOR); + coord_t yofs = (h*offset + count/2) / count; + coord_t yhgt = (h*visible + count/2) / count; + if (yhgt + yofs > h) + yhgt = h - yofs; + lcdDrawFilledRect(x-1, y + yofs, 3, yhgt, SCROLLBOX_COLOR); +} + +void displayProgressBar(const char *label) +{ + lcd_putsLeft(4*FH, label); + lcd_rect(3, 6*FH+4, 204, 7); + lcdRefresh(); +} + +void updateProgressBar(int num, int den) +{ + if (num > 0 && den > 0) { + int width = (200*num)/den; + lcd_hline(5, 6*FH+6, width, FORCE); + lcd_hline(5, 6*FH+7, width, FORCE); + lcd_hline(5, 6*FH+8, width, FORCE); + lcdRefresh(); + } +} + +void title(const pm_char * s) +{ + int width = getTextWidth(s); + lcd_putsAtt(MENU_TITLE_LEFT, MENU_TITLE_TOP+2, s, MENU_TITLE_COLOR); +} + +const uint8_t LBM_MODEL_SETUP_ICON[] = { +#include "../../bitmaps/Horus/mask_model_setup.lbm" +}; + +const uint8_t LBM_HELI_ICON[] = { +#include "../../bitmaps/Horus/mask_heli.lbm" +}; + +const uint8_t LBM_FLIGHT_MODES_ICON[] = { +#include "../../bitmaps/Horus/mask_flight_modes.lbm" +}; + +const uint8_t LBM_INPUTS_ICON[] = { +#include "../../bitmaps/Horus/mask_inputs.lbm" +}; + +const uint8_t LBM_MIXER_ICON[] = { +#include "../../bitmaps/Horus/mask_mixer.lbm" +}; + +const uint8_t LBM_OUTPUTS_ICON[] = { +#include "../../bitmaps/Horus/mask_outputs.lbm" +}; + +const uint8_t LBM_CURVES_ICON[] = { +#include "../../bitmaps/Horus/mask_curves.lbm" +}; + +const uint8_t LBM_GVARS_ICON[] = { +#include "../../bitmaps/Horus/mask_gvars.lbm" +}; + +const uint8_t LBM_LOGICAL_SWITCHES_ICON[] = { +#include "../../bitmaps/Horus/mask_logical_switches.lbm" +}; + +const uint8_t LBM_SPECIAL_FUNCTIONS_ICON[] = { +#include "../../bitmaps/Horus/mask_special_functions.lbm" +}; + +const uint8_t LBM_LUA_SCRIPTS_ICON[] = { +#include "../../bitmaps/Horus/mask_lua_scripts.lbm" +}; + +const uint8_t LBM_TELEMETRY_ICON[] = { +#include "../../bitmaps/Horus/mask_telemetry.lbm" +}; +const uint8_t * const LBM_MODEL_ICONS[] = { + LBM_MODEL_SETUP_ICON, + CASE_HELI(LBM_HELI_ICON) + CASE_FLIGHT_MODES(LBM_FLIGHT_MODES_ICON) + LBM_INPUTS_ICON, + LBM_MIXER_ICON, + LBM_OUTPUTS_ICON, + CASE_CURVES(LBM_CURVES_ICON) + CASE_GVARS(LBM_GVARS_ICON) + LBM_LOGICAL_SWITCHES_ICON, + LBM_SPECIAL_FUNCTIONS_ICON, +#if defined(LUA_MODEL_SCRIPTS) + LBM_LUA_SCRIPTS_ICON, +#endif + LBM_TELEMETRY_ICON +}; + +const uint8_t LBM_BALL[] = { +#include "../../bitmaps/Horus/mask_ball.lbm" +}; + +#define MENU_ICONS_SPACING 34 + +void drawMenuTemplate(const char *name, evt_t event, int pageIndex, int pageCount) +{ + // clear the screen + lcdDrawFilledRect(0, 0, LCD_W, MENU_HEADER_HEIGHT, HEADER_BGCOLOR); + lcdDrawFilledRect(0, MENU_TITLE_TOP, LCD_W, MENU_TITLE_HEIGHT, TITLE_BGCOLOR); + lcdDrawFilledRect(0, MENU_BODY_TOP, LCD_W, MENU_BODY_HEIGHT, TEXT_BGCOLOR); + lcdDrawFilledRect(0, MENU_FOOTER_TOP, LCD_W, MENU_FOOTER_HEIGHT, HEADER_BGCOLOR); + + lcdDrawFilledRect(58+pageIndex*MENU_ICONS_SPACING-11, 0, 36, MENU_HEADER_HEIGHT, TITLE_BGCOLOR); + + for (int i=0; i 0) { + displayScreenIndex(pageIndex, pageCount); + } +} + +select_menu_value_t selectMenuItem(coord_t x, coord_t y, const pm_char *label, const pm_char *values, select_menu_value_t value, select_menu_value_t min, select_menu_value_t max, LcdFlags attr, evt_t event) +{ + lcd_putsColumnLeft(x, y, label); + if (values) lcd_putsiAtt(x, y, values, value-min, attr); + if (attr) value = checkIncDec(event, value, min, max, (g_menuPos[0] == 0) ? EE_MODEL : EE_GENERAL); + return value; +} + +uint8_t onoffMenuItem(uint8_t value, coord_t x, coord_t y, const pm_char *label, LcdFlags attr, evt_t event ) +{ + lcdDrawCheckBox(x, y, value, attr); + return selectMenuItem(x, y, label, NULL, value, 0, 1, attr, event); +} + +int8_t switchMenuItem(coord_t x, coord_t y, int8_t value, LcdFlags attr, evt_t event) +{ + lcd_putsColumnLeft(x, y, STR_SWITCH); + putsSwitches(x, y, value, attr); + if (attr) CHECK_INCDEC_MODELSWITCH(event, value, SWSRC_FIRST_IN_MIXES, SWSRC_LAST_IN_MIXES, isSwitchAvailableInMixes); + return value; +} + +void displaySlider(coord_t x, coord_t y, uint8_t value, uint8_t max, uint8_t attr) +{ + const int width = 50; + lcd_hlineStip(x, y+5, width, SOLID, TEXT_COLOR); + if (attr && (!(attr & BLINK) || !BLINK_ON_PHASE)) { + lcdDrawFilledRect(x+value*(width-5)/max, y, 5, 11, TEXT_INVERTED_BGCOLOR); + } + else { + lcdDrawFilledRect(x+value*(width-5)/max, y, 5, 11, LINE_COLOR); + } +} + +#if defined(GVARS) +bool noZero(int val) +{ + return val != 0; +} + +int16_t gvarMenuItem(coord_t x, coord_t y, int16_t value, int16_t min, int16_t max, LcdFlags attr, uint8_t editflags, evt_t event) +{ + uint16_t delta = GV_GET_GV1_VALUE(max); + bool invers = (attr & INVERS); + + // TRACE("gvarMenuItem(val=%d min=%d max=%d)", value, min, max); + + if (invers && event == EVT_KEY_LONG(KEY_ENTER)) { + s_editMode = !s_editMode; + if (attr & PREC1) + value = (GV_IS_GV_VALUE(value, min, max) ? GET_GVAR(value, min, max, mixerCurrentFlightMode)*10 : delta); + else + value = (GV_IS_GV_VALUE(value, min, max) ? GET_GVAR(value, min, max, mixerCurrentFlightMode) : delta); + eeDirty(EE_MODEL); + } + + if (GV_IS_GV_VALUE(value, min, max)) { + if (attr & LEFT) + attr -= LEFT; /* because of ZCHAR */ + else + x -= 20; + + attr &= ~PREC1; + + int8_t idx = (int16_t) GV_INDEX_CALC_DELTA(value, delta); + if (idx >= 0) ++idx; // transform form idx=0=GV1 to idx=1=GV1 in order to handle double keys invert + if (invers) { + CHECK_INCDEC_MODELVAR_CHECK(event, idx, -MAX_GVARS, MAX_GVARS, noZero); + if (idx == 0) idx = 1; // handle reset to zero, map to GV1 + } + if (idx < 0) { + value = (int16_t) GV_CALC_VALUE_IDX_NEG(idx, delta); + idx = -idx; + putsStrIdx(x, y, STR_GV, idx, attr, "-"); + } + else { + putsStrIdx(x, y, STR_GV, idx, attr); + value = (int16_t) GV_CALC_VALUE_IDX_POS(idx-1, delta); + } + } + else { + lcd_outdezAtt(x, y, value, attr, "%"); + if (invers) value = checkIncDec(event, value, min, max, EE_MODEL | editflags); + } + return value; +} +#else +int16_t gvarMenuItem(coord_t x, coord_t y, int16_t value, int16_t min, int16_t max, LcdFlags attr, evt_t event) +{ + lcd_outdezAtt(x, y, value, attr, "%"); + if (attr&INVERS) value = checkIncDec(event, value, min, max, EE_MODEL); + return value; +} +#endif diff --git a/radio/src/gui/gui.h b/radio/src/gui/gui.h index 6b2f02df6..0d9baa30c 100644 --- a/radio/src/gui/gui.h +++ b/radio/src/gui/gui.h @@ -37,7 +37,11 @@ #ifndef _GUI_H_ #define _GUI_H_ -#if defined(PCBTARANIS) +#if defined(PCBHORUS) + #include "Horus/gui.h" +#elif defined(PCBFLAMENCO) + #include "Flamenco/gui.h" +#elif defined(PCBTARANIS) #include "Taranis/gui.h" #else #include "9X/gui.h" diff --git a/radio/src/haptic.cpp b/radio/src/haptic.cpp index 2a8e661bd..3856f0d9a 100644 --- a/radio/src/haptic.cpp +++ b/radio/src/haptic.cpp @@ -54,7 +54,8 @@ void hapticQueue::heartbeat() #else if (buzzTimeLeft > 0) { buzzTimeLeft--; // time gets counted down -#if defined(PCBSKY9X) || (defined(PCBTARANIS) && defined(REVPLUS)) +#if defined(PCBSKY9X) || (defined(PCBTARANIS) && defined(REVPLUS)) || defined(PCBFLAMENCO) || defined(PCBHORUS) + // TODO define HAPTIC_PWM option hapticOn(HAPTIC_STRENGTH() * 20); #else if (hapticTick-- > 0) { diff --git a/radio/src/keys.cpp b/radio/src/keys.cpp index a6adb6e91..f4bfa790a 100644 --- a/radio/src/keys.cpp +++ b/radio/src/keys.cpp @@ -36,15 +36,15 @@ #include "opentx.h" -uint8_t s_evt; +evt_t s_evt; struct t_inactivity inactivity = {0}; #if defined(CPUARM) -uint8_t getEvent(bool trim) +evt_t getEvent(bool trim) { - uint8_t evt = s_evt; + evt_t evt = s_evt; int8_t k = EVT_KEY_MASK(s_evt) - TRM_BASE; - bool trim_evt = (k>=0 && k<8); + bool trim_evt = (k>=0 && k 0 || defined(ROTARY_ENCODER_NAVIGATION) BTN_REa, #endif @@ -72,7 +92,24 @@ enum EnumKeys { NUM_KEYS, SW_BASE=NUM_KEYS, -#if defined(PCBTARANIS) +#if defined(PCBFLAMENCO) + SW_SA0=SW_BASE, + SW_SA1, + SW_SA2, + SW_SB0, + SW_SB2, + SW_SC0, + SW_SC1, + SW_SC2, + SW_SC3, + SW_SC4, + SW_SC5, + SW_SE0, + SW_SE2, + SW_SF0, + SW_SF1, + SW_SF2, +#elif defined(PCBTARANIS) || defined(PCBHORUS) SW_SA0=SW_BASE, SW_SA1, SW_SA2, @@ -145,26 +182,42 @@ enum EnumKeys { #define EVT_KEY_MASK(e) ((e) & 0x1f) +#if defined(PCBHORUS) +#define _MSK_KEY_BREAK 0x0200 +#define _MSK_KEY_REPT 0x0400 +#define _MSK_KEY_FIRST 0x0600 +#define _MSK_KEY_LONG 0x0800 +#define _MSK_KEY_FLAGS 0x0e00 +#define EVT_ENTRY 0x1000 +#define EVT_ENTRY_UP 0x2000 +#define EVT_MENU_UP 0x4000 +#else #define _MSK_KEY_BREAK 0x20 #define _MSK_KEY_REPT 0x40 #define _MSK_KEY_FIRST 0x60 #define _MSK_KEY_LONG 0x80 +#define _MSK_KEY_FLAGS 0xe0 +#define EVT_ENTRY 0xbf +#define EVT_ENTRY_UP 0xbe +#define EVT_MENU_UP 0xbd +#endif #define EVT_KEY_BREAK(key) ((key)|_MSK_KEY_BREAK) #define EVT_KEY_FIRST(key) ((key)|_MSK_KEY_FIRST) #define EVT_KEY_REPT(key) ((key)|_MSK_KEY_REPT) #define EVT_KEY_LONG(key) ((key)|_MSK_KEY_LONG) -#define IS_KEY_BREAK(evt) (((evt)&0xe0) == _MSK_KEY_BREAK) -#define IS_KEY_FIRST(evt) (((evt)&0xe0) == _MSK_KEY_FIRST) -#define IS_KEY_LONG(evt) (((evt)&0xe0) == _MSK_KEY_LONG) -#define IS_KEY_REPT(evt) (((evt)&0xe0) == _MSK_KEY_REPT) +#define IS_KEY_BREAK(evt) (((evt) & _MSK_KEY_FLAGS) == _MSK_KEY_BREAK) +#define IS_KEY_FIRST(evt) (((evt) & _MSK_KEY_FLAGS) == _MSK_KEY_FIRST) +#define IS_KEY_LONG(evt) (((evt) & _MSK_KEY_FLAGS) == _MSK_KEY_LONG) +#define IS_KEY_REPT(evt) (((evt) & _MSK_KEY_FLAGS) == _MSK_KEY_REPT) -#define EVT_ENTRY 0xbf -#define EVT_ENTRY_UP 0xbe -#define EVT_MENU_UP 0xbd - -#if defined(PCBTARANIS) +#if defined(PCBHORUS) + #define EVT_ROTARY_BREAK EVT_KEY_BREAK(KEY_ENTER) + #define EVT_ROTARY_LONG EVT_KEY_LONG(KEY_ENTER) + #define EVT_ROTARY_LEFT 0xDF00 + #define EVT_ROTARY_RIGHT 0xDE00 +#elif defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) #define EVT_ROTARY_BREAK EVT_KEY_BREAK(KEY_ENTER) #define EVT_ROTARY_LONG EVT_KEY_LONG(KEY_ENTER) #else @@ -174,7 +227,19 @@ enum EnumKeys { #define EVT_ROTARY_RIGHT 0xde #endif -#if defined(PCBTARANIS) +#if defined(PCBHORUS) + #define IS_ROTARY_LEFT(evt) (evt==EVT_KEY_FIRST(KEY_MINUS) || evt==EVT_KEY_REPT(KEY_MINUS)) + #define IS_ROTARY_RIGHT(evt) (evt==EVT_KEY_FIRST(KEY_PLUS) || evt==EVT_KEY_REPT(KEY_PLUS)) + #define IS_ROTARY_UP(evt) (evt==EVT_KEY_FIRST(KEY_PLUS) || evt==EVT_KEY_REPT(KEY_PLUS)) + #define IS_ROTARY_DOWN(evt) (evt==EVT_KEY_FIRST(KEY_MINUS) || evt==EVT_KEY_REPT(KEY_MINUS)) + #define IS_ROTARY_BREAK(evt) (evt==EVT_KEY_BREAK(KEY_ENTER)) + #define IS_ROTARY_LONG(evt) (evt==EVT_KEY_LONG(KEY_ENTER)) + #define IS_ROTARY_EVENT(evt) (0) + #define CASE_EVT_ROTARY_BREAK /*case EVT_KEY_BREAK(KEY_ENTER):*/ + #define CASE_EVT_ROTARY_LONG /*case EVT_KEY_LONG(KEY_ENTER):*/ + #define CASE_EVT_ROTARY_LEFT case EVT_KEY_FIRST(KEY_MOVE_UP): case EVT_KEY_REPT(KEY_MOVE_UP): + #define CASE_EVT_ROTARY_RIGHT case EVT_KEY_FIRST(KEY_MOVE_DOWN): case EVT_KEY_REPT(KEY_MOVE_DOWN): +#elif defined(PCBTARANIS) || defined(PCBFLAMENCO) #define IS_ROTARY_LEFT(evt) (evt==EVT_KEY_FIRST(KEY_MINUS) || evt==EVT_KEY_REPT(KEY_MINUS)) #define IS_ROTARY_RIGHT(evt) (evt==EVT_KEY_FIRST(KEY_PLUS) || evt==EVT_KEY_REPT(KEY_PLUS)) #define IS_ROTARY_UP(evt) (evt==EVT_KEY_FIRST(KEY_PLUS) || evt==EVT_KEY_REPT(KEY_PLUS)) @@ -247,7 +312,13 @@ class Key extern Key keys[NUM_KEYS]; -extern uint8_t s_evt; +#if defined(PCBHORUS) +typedef uint16_t evt_t; +#else +typedef uint8_t evt_t; +#endif + +extern evt_t s_evt; #define putEvent(evt) s_evt = evt @@ -256,10 +327,10 @@ void killEvents(uint8_t enuk); #if defined(CPUARM) bool clearKeyEvents(); - uint8_t getEvent(bool trim=false); + evt_t getEvent(bool trim=false); #else void clearKeyEvents(); - uint8_t getEvent(); + evt_t getEvent(); #endif uint8_t keyDown(); diff --git a/radio/src/logs.cpp b/radio/src/logs.cpp index 6d0ee2aac..075350856 100644 --- a/radio/src/logs.cpp +++ b/radio/src/logs.cpp @@ -41,7 +41,7 @@ FIL g_oLogFile = {0}; const pm_char * g_logError = NULL; uint8_t logDelay; -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) #define get2PosState(sw) (switchState(SW_ ## sw ## 0) ? -1 : 1) #else #define get2PosState(sw) (switchState(SW_ ## sw) ? -1 : 1) @@ -49,7 +49,7 @@ uint8_t logDelay; #define get3PosState(sw) (switchState(SW_ ## sw ## 0) ? -1 : (switchState(SW_ ## sw ## 2) ? 1 : 0)) -const pm_char *openLogs() +const pm_char * openLogs() { // Determine and set log file filename FRESULT result; @@ -330,7 +330,14 @@ void writeLogs() f_printf(&g_oLogFile, "%d,", calibratedStick[i]); } -#if defined(PCBTARANIS) +#if defined(PCBFLAMENCO) + int result = f_printf(&g_oLogFile, "%d,%d,%d,%d\n", + get3PosState(SA), + get3PosState(SB), + // get3PosState(SC), + get2PosState(SE), + get3PosState(SF)); +#elif defined(PCBTARANIS) || defined(PCBHORUS) int result = f_printf(&g_oLogFile, "%d,%d,%d,%d,%d,%d,%d,%d\n", get3PosState(SA), get3PosState(SB), diff --git a/radio/src/lua_api.cpp b/radio/src/lua_api.cpp index 4b2d99839..7cd53d466 100644 --- a/radio/src/lua_api.cpp +++ b/radio/src/lua_api.cpp @@ -52,7 +52,11 @@ extern "C" { } #endif -#include "lua_exports.inc" // this line must be after lua headers +#if defined(PCBFLAMENCO) + #include "lua_exports_flamenco.inc" // this line must be after lua headers +#elif defined(PCBTARANIS) + #include "lua_exports_taranis.inc" // this line must be after lua headers +#endif #define lua_registernumber(L, n, i) (lua_pushnumber(L, (i)), lua_setglobal(L, (n))) #define lua_registerint(L, n, i) (lua_pushinteger(L, (i)), lua_setglobal(L, (n))) @@ -463,7 +467,11 @@ static int luaLcdDrawTimer(lua_State *L) int y = luaL_checkinteger(L, 2); int seconds = luaL_checkinteger(L, 3); unsigned int att = luaL_optunsigned(L, 4, 0); +#if defined(PCBFLAMENCO) + putsTimer(x, y, seconds, att|LEFT); +#else putsTimer(x, y, seconds, att|LEFT, att); +#endif return 0; } @@ -530,6 +538,7 @@ static int luaLcdDrawSource(lua_State *L) return 0; } +#if !defined(PCBFLAMENCO) static int luaLcdDrawPixmap(lua_State *L) { if (!luaLcdAllowed) return 0; @@ -543,6 +552,7 @@ static int luaLcdDrawPixmap(lua_State *L) } return 0; } +#endif static int luaLcdDrawRectangle(lua_State *L) { @@ -586,6 +596,7 @@ static int luaLcdDrawGauge(lua_State *L) return 0; } +#if !defined(PCBFLAMENCO) static int luaLcdDrawScreenTitle(lua_State *L) { if (!luaLcdAllowed) return 0; @@ -599,6 +610,7 @@ static int luaLcdDrawScreenTitle(lua_State *L) return 0; } +#endif static int luaLcdDrawCombobox(lua_State *L) { @@ -652,7 +664,11 @@ static int luaModelGetInfo(lua_State *L) { lua_newtable(L); lua_pushtablezstring(L, "name", g_model.header.name); +#if defined(PCBFLAMENCO) + lua_pushtableinteger(L, "bitmap", g_model.header.bitmap); +#else lua_pushtablenzstring(L, "bitmap", g_model.header.bitmap); +#endif return 1; } @@ -668,8 +684,12 @@ static int luaModelSetInfo(lua_State *L) memcpy(modelHeaders[g_eeGeneral.currModel].name, g_model.header.name, sizeof(g_model.header.name)); } else if (!strcmp(key, "bitmap")) { +#if defined(PCBFLAMENCO) + g_model.header.bitmap = luaL_checkinteger(L, -1); +#else const char * name = luaL_checkstring(L, -1); strncpy(g_model.header.bitmap, name, sizeof(g_model.header.bitmap)); +#endif } } eeDirty(EE_MODEL); @@ -1456,6 +1476,26 @@ const luaR_value_entry opentxConstants[] = { { "MIDSIZE", MIDSIZE }, { "SMLSIZE", SMLSIZE }, { "INVERS", INVERS }, +#if defined(PCBFLAMENCO) + { "WHITE", WHITE }, + { "BLACK", BLACK }, + { "YELLOW", YELLOW }, + { "BLUE", BLUE }, + { "GREY_DEFAULT", GREY_DEFAULT }, + { "DARKGREY", DARKGREY }, + { "RED", RED }, + { "LIGHTGREY", LIGHTGREY }, + { "WHITE_ON_BLACK", WHITE_ON_BLACK }, + { "RED_ON_BLACK", RED_ON_BLACK }, + { "BLUE_ON_BLACK", BLUE_ON_BLACK }, + { "GREY_ON_BLACK", GREY_ON_BLACK }, + { "LIGHTGREY_ON_BLACK", LIGHTGREY_ON_BLACK }, + { "YELLOW_ON_BLACK", YELLOW_ON_BLACK }, + { "WHITE_ON_DARKGREY", WHITE_ON_DARKGREY }, + { "WHITE_ON_BLUE", WHITE_ON_BLUE }, + { "BLACK_ON_YELLOW", BLACK_ON_YELLOW }, + { "LIGHTGREY_ON_YELLOW", LIGHTGREY_ON_YELLOW }, +#endif { "BOLD", BOLD }, { "BLINK", BLINK }, { "FIXEDWIDTH", FIXEDWIDTH }, @@ -1473,11 +1513,15 @@ const luaR_value_entry opentxConstants[] = { { "MIXSRC_SA", MIXSRC_SA }, { "MIXSRC_SB", MIXSRC_SB }, { "MIXSRC_SC", MIXSRC_SC }, +#if defined(PCBTARANIS) { "MIXSRC_SD", MIXSRC_SD }, +#endif { "MIXSRC_SE", MIXSRC_SE }, { "MIXSRC_SF", MIXSRC_SF }, +#if defined(PCBTARANIS) { "MIXSRC_SG", MIXSRC_SG }, { "MIXSRC_SH", MIXSRC_SH }, +#endif { "MIXSRC_CH1", MIXSRC_CH1 }, { "SWSRC_LAST", SWSRC_LAST_LOGICAL_SWITCH }, { "EVT_MENU_BREAK", EVT_KEY_BREAK(KEY_MENU) }, @@ -1553,8 +1597,10 @@ const luaL_Reg lcdLib[] = { { "drawChannel", luaLcdDrawChannel }, { "drawSwitch", luaLcdDrawSwitch }, { "drawSource", luaLcdDrawSource }, +#if !defined(PCBFLAMENCO) { "drawPixmap", luaLcdDrawPixmap }, { "drawScreenTitle", luaLcdDrawScreenTitle }, +#endif { "drawCombobox", luaLcdDrawCombobox }, { NULL, NULL } /* sentinel */ }; @@ -1945,12 +1991,12 @@ void luaDoOneRunStandalone(uint8_t evt) return; } else if (luaDisplayStatistics) { - lcd_hline(0, 7*FH-1, lcdLastPos+FW, ERASE); + lcd_hline(0, 7*FH-1, lcdLastPos+6, ERASE); lcd_puts(0, 7*FH, "GV Use: "); lcd_outdezAtt(lcdLastPos, 7*FH, luaGetMemUsed(), LEFT); lcd_putc(lcdLastPos, 7*FH, 'b'); - lcd_hline(0, 7*FH-2, lcdLastPos+FW, FORCE); - lcd_vlineStip(lcdLastPos+FW, 7*FH-2, FH+2, SOLID, FORCE); + lcd_hline(0, 7*FH-2, lcdLastPos+6, FORCE); + lcd_vlineStip(lcdLastPos+6, 7*FH-2, FH+2, SOLID, FORCE); } } } @@ -2021,8 +2067,12 @@ bool luaDoOneRunPermanentScript(uint8_t evt, int i, uint32_t scriptType) TelemetryScriptData & script = g_model.frsky.screens[sid.reference-SCRIPT_TELEMETRY_FIRST].script; filename = script.file; #endif - if ((scriptType & RUN_TELEM_FG_SCRIPT) && + if ((scriptType & RUN_TELEM_FG_SCRIPT) && +#if defined(PCBFLAMENCO) + (g_menuStack[0]==menuMainView && sid.reference==SCRIPT_TELEMETRY_FIRST+g_eeGeneral.view-VIEW_TELEM1)) { +#else (g_menuStack[0]==menuTelemetryFrsky && sid.reference==SCRIPT_TELEMETRY_FIRST+s_frsky_view)) { +#endif lua_rawgeti(L, LUA_REGISTRYINDEX, sid.run); lua_pushinteger(L, evt); inputsCount = 1; diff --git a/radio/src/main_arm.cpp b/radio/src/main_arm.cpp index bed1ce257..c692ba244 100644 --- a/radio/src/main_arm.cpp +++ b/radio/src/main_arm.cpp @@ -89,6 +89,7 @@ void checkSpeakerVolume() } } +#if defined(EEPROM) void checkEeprom() { if (!usbPlugged()) { @@ -98,38 +99,70 @@ void checkEeprom() eeCheck(false); } } +#endif -void perMain() +#if defined(PCBFLAMENCO) +void guiMain(evt_t evt) { -#if defined(PCBSKY9X) && !defined(REVA) - calcConsumption(); -#endif - checkSpeakerVolume(); - checkEeprom(); - sdMountPoll(); - writeLogs(); - handleUsbConnection(); - checkTrainerSettings(); - checkBattery(); + lcd_clear(); - uint8_t evt = getEvent(false); - if (evt && (g_eeGeneral.backlightMode & e_backlight_mode_keys)) backlightOn(); // on keypress turn the light on - checkBacklight(); -#if defined(NAVIGATION_STICKS) - uint8_t sticks_evt = getSticksNavigationEvent(); - if (sticks_evt) evt = sticks_evt; -#endif - -#if defined(USB_MASS_STORAGE) - if (usbPlugged()) { - // disable access to menus - lcd_clear(); - menuMainView(0); - lcdRefresh(); - return; +#if defined(LUA) + uint32_t t0 = get_tmr10ms(); + static uint32_t lastLuaTime = 0; + uint16_t interval = (lastLuaTime == 0 ? 0 : (t0 - lastLuaTime)); + lastLuaTime = t0; + if (interval > maxLuaInterval) { + maxLuaInterval = interval; } + + // run Lua scripts that don't use LCD (to use CPU time while LCD DMA is running) + luaTask(0, RUN_MIX_SCRIPT | RUN_FUNC_SCRIPT | RUN_TELEM_BG_SCRIPT, false); + + // wait for LCD DMA to finish before continuing, because code from this point + // is allowed to change the contents of LCD buffer + // + // WARNING: make sure no code above this line does any change to the LCD display buffer! + // + + bool scriptWasRun = luaTask(evt, RUN_STNDAL_SCRIPT, true); + + t0 = get_tmr10ms() - t0; + if (t0 > maxLuaDuration) { + maxLuaDuration = t0; + } + + if (!scriptWasRun) #endif + { + // normal GUI from menus + const char *warn = s_warning; + uint8_t menu = s_menu_count; + // lcd_clear(); + if (menuEvent) { + m_posVert = menuEvent == EVT_ENTRY_UP ? g_menuPos[g_menuStackPtr] : 0; + m_posHorz = 0; + evt = menuEvent; + menuEvent = 0; + AUDIO_MENUS(); + } + g_menuStack[g_menuStackPtr]((warn || menu) ? 0 : evt); + if (warn) DISPLAY_WARNING(evt); + if (menu) { + const char * result = displayMenu(evt); + if (result) { + menuHandler(result); + putEvent(EVT_MENU_UP); + } + } + drawStatusLine(); + } + + lcdRefresh(); +} +#else +void guiMain(evt_t evt) +{ #if defined(LUA) uint32_t t0 = get_tmr10ms(); static uint32_t lastLuaTime = 0; @@ -172,9 +205,11 @@ void perMain() // normal GUI from menus const char *warn = s_warning; uint8_t menu = s_menu_count; +#if !defined(COLORLCD) if (refreshScreen) { lcd_clear(); } +#endif if (menuEvent) { m_posVert = menuEvent == EVT_ENTRY_UP ? g_menuPos[g_menuStackPtr] : 0; m_posHorz = 0; @@ -195,19 +230,44 @@ void perMain() } lcdRefresh(); - -#if defined(REV9E) && !defined(SIMU) - topLcdRefreshStart(); - setTopFirstTimer(getValue(MIXSRC_FIRST_TIMER+g_model.topLcdTimer)); - setTopSecondTimer(g_eeGeneral.globalTimer + sessionTimer); - setTopRssi(TELEMETRY_RSSI()); - setTopBatteryValue(g_vbat100mV); - setTopBatteryState(GET_TXBATT_BARS(), IS_TXBATT_WARNING()); - topLcdRefreshEnd(); +} #endif -#if defined(REV9E) && !defined(SIMU) - bluetoothWakeup(); +void perMain() +{ +#if defined(PCBSKY9X) && !defined(REVA) + calcConsumption(); +#endif + checkSpeakerVolume(); +#if defined(EEPROM) + checkEeprom(); +#endif + sdMountPoll(); + writeLogs(); + handleUsbConnection(); + checkTrainerSettings(); + checkBattery(); + + evt_t evt = getEvent(false); + if (evt && (g_eeGeneral.backlightMode & e_backlight_mode_keys)) backlightOn(); // on keypress turn the light on + doLoopCommonActions(); +#if defined(NAVIGATION_STICKS) + uint8_t sticks_evt = getSticksNavigationEvent(); + if (sticks_evt) evt = sticks_evt; +#endif + +#if defined(USB_MASS_STORAGE) + if (usbPlugged()) { + // disable access to menus + lcd_clear(); + menuMainView(0); + lcdRefresh(); + return; + } +#endif + +#if defined(GUI) + guiMain(evt); #endif #if defined(PCBTARANIS) @@ -217,4 +277,18 @@ void perMain() } #endif +#if defined(PCBTARANIS) && defined(REV9E) && !defined(SIMU) + topLcdRefreshStart(); + setTopFirstTimer(getValue(MIXSRC_FIRST_TIMER+g_model.topLcdTimer)); + setTopSecondTimer(g_eeGeneral.globalTimer + sessionTimer); + setTopRssi(TELEMETRY_RSSI()); + setTopBatteryValue(g_vbat100mV); + setTopBatteryState(GET_TXBATT_BARS(), IS_TXBATT_WARNING()); + topLcdRefreshEnd(); +#endif + +#if defined(PCBTARANIS) && defined(REV9E) && !defined(SIMU) + bluetoothWakeup(); +#endif + } diff --git a/radio/src/main_avr.cpp b/radio/src/main_avr.cpp index ac8f0385c..2d2daa8ad 100644 --- a/radio/src/main_avr.cpp +++ b/radio/src/main_avr.cpp @@ -110,11 +110,11 @@ void perMain() writeLogs(); #endif - uint8_t evt = getEvent(); + evt_t evt = getEvent(); evt = checkTrim(evt); if (evt && (g_eeGeneral.backlightMode & e_backlight_mode_keys)) backlightOn(); // on keypress turn the light on - checkBacklight(); + doLoopCommonActions(); #if defined(FRSKY) || defined(MAVLINK) telemetryWakeup(); diff --git a/radio/src/mixer.cpp b/radio/src/mixer.cpp index 6185447e8..a6dad5ffb 100644 --- a/radio/src/mixer.cpp +++ b/radio/src/mixer.cpp @@ -281,7 +281,14 @@ getvalue_t getValue(mixsrc_t i) else if (i<=MIXSRC_TrimAil) return calc1000toRESX((int16_t)8 * getTrimValue(mixerCurrentFlightMode, i-MIXSRC_TrimRud)); -#if defined(PCBTARANIS) +#if defined(PCBFLAMENCO) + else if (i==MIXSRC_SA) return (switchState(SW_SA0) ? -1024 : (switchState(SW_SA1) ? 0 : 1024)); + else if (i==MIXSRC_SB) return (switchState(SW_SB0) ? -1024 : 1024); + else if (i==MIXSRC_SC) return (switchState(SW_SC0) ? -1024 : (switchState(SW_SC1) ? 0 : 1024)); + // else if (i==MIXSRC_SD) return (switchState(SW_SD0) ? -1024 : 1024); + else if (i==MIXSRC_SE) return (switchState(SW_SE0) ? -1024 : 1024); + else if (i==MIXSRC_SF) return (switchState(SW_SF0) ? -1024 : (switchState(SW_SF1) ? 0 : 1024)); +#elif defined(PCBTARANIS) || defined(PCBHORUS) else if ((i >= MIXSRC_FIRST_SWITCH) && (i <= MIXSRC_LAST_SWITCH)) { mixsrc_t sw = i-MIXSRC_FIRST_SWITCH; if (SWITCH_EXISTS(sw)) { diff --git a/radio/src/myeeprom.h b/radio/src/myeeprom.h index 389fd66e7..bef3ff4ff 100644 --- a/radio/src/myeeprom.h +++ b/radio/src/myeeprom.h @@ -61,10 +61,7 @@ #define WARN_MEM (!(g_eeGeneral.warnOpts & WARN_MEM_BIT)) #define BEEP_VAL ( (g_eeGeneral.warnOpts & WARN_BVAL_BIT) >>3 ) -#if defined(PCBTARANIS) - #define EEPROM_VER 218 - #define FIRST_CONV_EEPROM_VER 216 -#elif defined(PCBSKY9X) +#if defined(CPUARM) #define EEPROM_VER 218 #define FIRST_CONV_EEPROM_VER 216 #elif defined(CPUM2560) || defined(CPUM2561) @@ -110,7 +107,35 @@ #define NUM_STICKS 4 -#if defined(PCBTARANIS) +#if defined(PCBHORUS) + #define MAX_MODELS 60 + #define NUM_CHNOUT 32 // number of real output channels CH1-CH32 + #define MAX_FLIGHT_MODES 9 + #define MAX_MIXERS 64 + #define MAX_EXPOS 64 + #define NUM_LOGICAL_SWITCH 32 // number of custom switches + #define NUM_CFN 64 // number of functions assigned to switches + #define MAX_SCRIPTS 7 + #define MAX_INPUTS 32 + #define NUM_TRAINER 16 + #define NUM_POTS 3 + #define NUM_XPOTS 0 + #define MAX_SENSORS 32 +#elif defined(PCBFLAMENCO) + #define MAX_MODELS 60 + #define NUM_CHNOUT 32 // number of real output channels CH1-CH32 + #define MAX_FLIGHT_MODES 9 + #define MAX_MIXERS 64 + #define MAX_EXPOS 64 + #define NUM_LOGICAL_SWITCH 32 // number of custom switches + #define NUM_CFN 64 // number of functions assigned to switches + #define MAX_SCRIPTS 7 + #define MAX_INPUTS 32 + #define NUM_TRAINER 16 + #define NUM_POTS 3 + #define NUM_XPOTS 0 + #define MAX_SENSORS 32 +#elif defined(PCBTARANIS) #define MAX_MODELS 60 #define NUM_CHNOUT 32 // number of real output channels CH1-CH32 #define MAX_FLIGHT_MODES 9 @@ -210,7 +235,27 @@ struct CurveInfo { extern CurveInfo curveInfo(uint8_t idx); #endif -#if defined(PCBTARANIS) +#if defined(PCBHORUS) + #define LEN_MODEL_NAME 12 + #define LEN_TIMER_NAME 8 + #define LEN_FLIGHT_MODE_NAME 10 + #define LEN_EXPOMIX_NAME 6 + #define LEN_CHANNEL_NAME 6 + #define LEN_INPUT_NAME 4 + #define MAX_CURVES 32 + #define NUM_POINTS 512 + #define CURVDATA CurveInfo +#elif defined(PCBFLAMENCO) + #define LEN_MODEL_NAME 12 + #define LEN_TIMER_NAME 8 + #define LEN_FLIGHT_MODE_NAME 10 + #define LEN_EXPOMIX_NAME 6 + #define LEN_CHANNEL_NAME 6 + #define LEN_INPUT_NAME 4 + #define MAX_CURVES 32 + #define NUM_POINTS 512 + #define CURVDATA CurveInfo +#elif defined(PCBTARANIS) #define LEN_MODEL_NAME 12 #define LEN_TIMER_NAME 8 #define LEN_FLIGHT_MODE_NAME 10 @@ -301,7 +346,18 @@ PACK(typedef struct { int8_t value:6; }) FrSkyRSSIAlarm; -#if defined(PCBTARANIS) +#if defined(PCBFLAMENCO) || defined(PCBHORUS) +enum MainViews { + VIEW_BLANK, + VIEW_TIMERS_ALTITUDE, + VIEW_CHANNELS, + VIEW_TELEM1, + VIEW_TELEM2, + VIEW_TELEM3, + VIEW_TELEM4, + VIEW_COUNT +}; +#elif defined(PCBTARANIS) enum MainViews { VIEW_TIMERS, VIEW_INPUTS, @@ -365,20 +421,45 @@ enum BeeperMode { #define swarnenable_t uint8_t #endif -#if defined(PCBTARANIS) - enum UartModes { - UART_MODE_NONE, - UART_MODE_TELEMETRY_MIRROR, - UART_MODE_TELEMETRY, - UART_MODE_SBUS_TRAINER, - // UART_MODE_CPPM_TRAINER, - #if defined(DEBUG) - UART_MODE_DEBUG, - #endif - UART_MODE_COUNT, - UART_MODE_MAX = UART_MODE_COUNT-1 - }; +enum UartModes { +#if defined(CLI) || defined(DEBUG) + UART_MODE_DEBUG, +#else + UART_MODE_NONE, +#endif + UART_MODE_TELEMETRY_MIRROR, + UART_MODE_TELEMETRY, + UART_MODE_SBUS_TRAINER, + // UART_MODE_CPPM_TRAINER, + UART_MODE_COUNT, + UART_MODE_MAX = UART_MODE_COUNT-1 +}; +#if defined(PCBHORUS) + #define LEN_SWITCH_NAME 3 + #define LEN_ANA_NAME 3 + #define EXTRA_GENERAL_FIELDS \ + EXTRA_GENERAL_FIELDS_ARM \ + uint8_t serial2Mode:6; \ + uint8_t spare:2; \ + CustomFunctionData customFn[NUM_CFN]; \ + uint32_t switchConfig; \ + uint8_t potsType; /*two bits for every pot*/\ + char switchNames[NUM_SWITCHES][LEN_SWITCH_NAME]; \ + char anaNames[NUM_STICKS+NUM_POTS][LEN_ANA_NAME]; +#elif defined(PCBFLAMENCO) + #define LEN_SWITCH_NAME 3 + #define LEN_ANA_NAME 3 + #define EXTRA_GENERAL_FIELDS \ + EXTRA_GENERAL_FIELDS_ARM \ + uint8_t serial2Mode:6; \ + uint8_t spare:2; \ + CustomFunctionData customFn[NUM_CFN]; \ + uint32_t switchConfig; \ + uint8_t potsType; /*two bits for every pot*/\ + char switchNames[NUM_SWITCHES][LEN_SWITCH_NAME]; \ + char anaNames[NUM_STICKS+NUM_POTS][LEN_ANA_NAME]; +#elif defined(PCBTARANIS) #define LEN_SWITCH_NAME 3 #define LEN_ANA_NAME 3 #define LEN_BLUETOOTH_NAME 10 @@ -391,7 +472,6 @@ enum BeeperMode { #else #define BLUETOOTH_FIELDS #endif - #define EXTRA_GENERAL_FIELDS \ EXTRA_GENERAL_FIELDS_ARM \ uint8_t serial2Mode:6; \ @@ -442,7 +522,35 @@ PACK(typedef struct { int8_t inputs[MAX_SCRIPT_INPUTS]; }) ScriptData; -#if defined(PCBTARANIS) +enum PotsWarnMode { + POTS_WARN_OFF, + POTS_WARN_MANUAL, + POTS_WARN_AUTO +}; + +#if defined(PCBHORUS) + enum ModuleIndex { + EXTERNAL_MODULE, + TRAINER_MODULE, + }; + enum TrainerMode { + TRAINER_MODE_MASTER, + TRAINER_MODE_SLAVE + }; + #define MODELDATA_BITMAP uint8_t bitmap; + #define MODELDATA_EXTRA uint8_t externalModule:3; uint8_t trainerMode:3; uint8_t potsWarnMode:2; ModuleData moduleData[NUM_MODULES+1]; char curveNames[MAX_CURVES][6]; ScriptData scriptsData[MAX_SCRIPTS]; char inputNames[MAX_INPUTS][LEN_INPUT_NAME]; uint8_t potsWarnEnabled; int8_t potsWarnPosition[NUM_POTS]; +#elif defined(PCBFLAMENCO) + enum ModuleIndex { + EXTERNAL_MODULE, + TRAINER_MODULE, + }; + enum TrainerMode { + TRAINER_MODE_MASTER, + TRAINER_MODE_SLAVE + }; + #define MODELDATA_BITMAP uint8_t bitmap; + #define MODELDATA_EXTRA uint8_t externalModule:3; uint8_t trainerMode:3; uint8_t potsWarnMode:2; ModuleData moduleData[NUM_MODULES+1]; char curveNames[MAX_CURVES][6]; ScriptData scriptsData[MAX_SCRIPTS]; char inputNames[MAX_INPUTS][LEN_INPUT_NAME]; uint8_t potsWarnEnabled; int8_t potsWarnPosition[NUM_POTS]; +#elif defined(PCBTARANIS) enum ModuleIndex { INTERNAL_MODULE, EXTERNAL_MODULE, @@ -455,11 +563,6 @@ PACK(typedef struct { TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE, TRAINER_MODE_MASTER_BATTERY_COMPARTMENT, }; - enum PotsWarnMode { - POTS_WARN_OFF, - POTS_WARN_MANUAL, - POTS_WARN_AUTO - }; #define IS_TRAINER_EXTERNAL_MODULE() (g_model.trainerMode == TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE || g_model.trainerMode == TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE) #define MODELDATA_BITMAP char bitmap[LEN_BITMAP_NAME]; #define MODELDATA_EXTRA uint8_t spare:3; uint8_t trainerMode:3; uint8_t potsWarnMode:2; ModuleData moduleData[NUM_MODULES+1]; char curveNames[MAX_CURVES][6]; ScriptData scriptsData[MAX_SCRIPTS]; char inputNames[MAX_INPUTS][LEN_INPUT_NAME]; uint8_t potsWarnEnabled; int8_t potsWarnPosition[NUM_POTS]; @@ -494,7 +597,7 @@ enum BacklightMode { #define XPOTS_MULTIPOS_COUNT 6 -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) PACK(typedef struct { uint8_t count; uint8_t steps[XPOTS_MULTIPOS_COUNT-1]; @@ -720,7 +823,7 @@ PACK(typedef struct { #define CFN_GVAR_CST_MAX 125 #endif -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) enum SwitchConfig { SWITCH_NONE, SWITCH_TOGGLE, @@ -815,7 +918,7 @@ PACK(typedef struct { #define MODE_CURVE 1 #endif -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) PACK(typedef struct { uint16_t mode:2; uint16_t scale:14; @@ -876,7 +979,7 @@ PACK(typedef struct { #define EXPO_MODE_ENABLE(ed, v) (((v)<0 && ((ed)->mode&1)) || ((v)>=0 && ((ed)->mode&2))) #endif -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) #define limit_min_max_t int16_t #define LIMIT_EXT_PERCENT 150 #define LIMIT_EXT_MAX (LIMIT_EXT_PERCENT*10) @@ -900,7 +1003,7 @@ PACK(typedef struct { #define LIMIT_OFS_RESX(lim) calc1000toRESX(LIMIT_OFS(lim)) #endif -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) PACK(typedef struct { int32_t min:11; int32_t max:11; @@ -943,7 +1046,7 @@ PACK(typedef struct { #define SLOW_STEP 10 #define DELAY_MAX (25*DELAY_STEP) /* 25 seconds */ #define SLOW_MAX (25*SLOW_STEP) /* 25 seconds */ -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) PACK(typedef struct { int16_t weight:11; // GV1=-1024, -GV1=1023 uint16_t destCh:5; @@ -1422,7 +1525,7 @@ PACK(typedef struct { ls_telemetry_value_t barMax; // ditto for max display (would usually = ratio) }) FrSkyBarData; -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) #define NUM_LINE_ITEMS 3 #else #define NUM_LINE_ITEMS 2 @@ -1432,7 +1535,7 @@ PACK(typedef struct { source_t sources[NUM_LINE_ITEMS]; }) FrSkyLineData; -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) #define MAX_TELEM_SCRIPT_INPUTS 8 PACK(typedef struct { char file[LEN_SCRIPT_FILENAME]; @@ -1443,7 +1546,7 @@ PACK(typedef struct { typedef union { FrSkyBarData bars[4]; FrSkyLineData lines[4]; -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) TelemetryScriptData script; #endif } FrSkyScreenData; @@ -1602,7 +1705,7 @@ PACK(typedef struct { #define TRIMS_ARRAY_SIZE 5 #define trim_t int16_t #else - #if defined(PCBTARANIS) + #if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) PACK(typedef struct { int16_t value:11; uint16_t mode:5; @@ -1643,7 +1746,25 @@ enum SwitchSources { SWSRC_FIRST_SWITCH, -#if defined(PCBTARANIS) +#if defined(PCBFLAMENCO) + SWSRC_SA0 = SWSRC_FIRST_SWITCH, + SWSRC_SA1, + SWSRC_SA2, + SWSRC_SB0, + SWSRC_SB2, + SWSRC_SC0, + SWSRC_SC1, + SWSRC_SC2, + SWSRC_SC3, + SWSRC_SC4, + SWSRC_SC5, + SWSRC_SE0, + SWSRC_SE2, + SWSRC_SF0, + SWSRC_SF1, + SWSRC_SF2, + SWSRC_LAST_SWITCH = SWSRC_SF2, +#elif defined(PCBTARANIS) SWSRC_SA0 = SWSRC_FIRST_SWITCH, SWSRC_SA1, SWSRC_SA2, @@ -1809,7 +1930,12 @@ enum MixSources { MIXSRC_Ail, LUA_EXPORT("ail", "Aileron") MIXSRC_FIRST_POT, -#if defined(PCBTARANIS) +#if defined(PCBFLAMENCO) + MIXSRC_POT1 = MIXSRC_FIRST_POT, LUA_EXPORT("sd", "Potentiometer D") + MIXSRC_SLIDER1, LUA_EXPORT("ls", "Left slider") + MIXSRC_SLIDER2, LUA_EXPORT("rs", "Right slider") + MIXSRC_LAST_POT = MIXSRC_SLIDER2, +#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") @@ -1864,7 +1990,13 @@ enum MixSources { MIXSRC_FIRST_SWITCH, -#if defined(PCBTARANIS) +#if defined(PCBFLAMENCO) + MIXSRC_SA = MIXSRC_FIRST_SWITCH, LUA_EXPORT("sa", "Switch A") + MIXSRC_SB, LUA_EXPORT("sb", "Switch B") + MIXSRC_SC, LUA_EXPORT("sc", "Switch C") + MIXSRC_SE, LUA_EXPORT("se", "Switch E") + MIXSRC_SF, LUA_EXPORT("sf", "Switch F") +#elif defined(PCBTARANIS) || defined(PCBHORUS) MIXSRC_SA = MIXSRC_FIRST_SWITCH, LUA_EXPORT("sa", "Switch A") MIXSRC_SB, LUA_EXPORT("sb", "Switch B") MIXSRC_SC, LUA_EXPORT("sc", "Switch C") @@ -2109,7 +2241,11 @@ PACK(typedef struct { enum ThrottleSources { THROTTLE_SOURCE_THR, THROTTLE_SOURCE_FIRST_POT, -#if defined(PCBTARANIS) && defined(REV9E) +#if defined(PCBFLAMENCO) + THROTTLE_SOURCE_SD, + THROTTLE_SOURCE_LS, + THROTTLE_SOURCE_RS, +#elif defined(PCBTARANIS) && defined(REV9E) THROTTLE_SOURCE_F1 = THROTTLE_SOURCE_FIRST_POT, THROTTLE_SOURCE_F2, THROTTLE_SOURCE_F3, diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp index 2e24f5b99..2e0a493d2 100644 --- a/radio/src/opentx.cpp +++ b/radio/src/opentx.cpp @@ -262,7 +262,11 @@ void generalDefault() g_eeGeneral.variant = EEPROM_VARIANT; g_eeGeneral.contrast = 25; -#if defined(PCBTARANIS) +#if defined(PCBFLAMENCO) + g_eeGeneral.vBatWarn = 33; + g_eeGeneral.vBatMin = -60; // 0 is 9.0V + g_eeGeneral.vBatMax = -78; // 0 is 12.0V +#elif defined(PCBTARANIS) g_eeGeneral.potsConfig = 0x05; // S1 and S2 = pots with detent g_eeGeneral.slidersConfig = 0x03; // LS and RS = sliders with detent #endif @@ -289,11 +293,15 @@ void generalDefault() g_eeGeneral.stickMode = DEFAULT_MODE-1; #endif -#if defined(PCBTARANIS) +#if defined(PCBFLAMENCO) + g_eeGeneral.templateSetup = 21; /* AETR */ +#elif defined(PCBTARANIS) g_eeGeneral.templateSetup = 17; /* TAER */ #endif -#if !defined(CPUM64) +#if defined(PCBFLAMENCO) + g_eeGeneral.inactivityTimer = 50; +#elif !defined(CPUM64) g_eeGeneral.backlightMode = e_backlight_mode_all; g_eeGeneral.lightAutoOff = 2; g_eeGeneral.inactivityTimer = 10; @@ -963,6 +971,25 @@ void checkBacklight() } } +#if defined(PCBFLAMENCO) +void checkUsbChip() +{ + uint8_t reg = i2cReadBQ24195(0x00); + if (reg & 0x80) { + i2cWriteBQ24195(0x00, reg & 0x7F); + } +} +#endif + +void doLoopCommonActions() +{ + checkBacklight(); + +#if defined(PCBFLAMENCO) + checkUsbChip(); +#endif +} + void backlightOn() { lightOffCounter = ((uint16_t)g_eeGeneral.lightAutoOff*250) << 1; @@ -1058,7 +1085,7 @@ void doSplash() } #endif - checkBacklight(); + doLoopCommonActions(); } } } @@ -1223,7 +1250,7 @@ void checkTHR() break; } - checkBacklight(); + doLoopCommonActions(); wdt_reset(); } @@ -1255,7 +1282,7 @@ void alert(const pm_char * t, const pm_char *s MESSAGE_SOUND_ARG) if (keyDown()) return; // wait for key release - checkBacklight(); + doLoopCommonActions(); wdt_reset(); @@ -1286,7 +1313,7 @@ int8_t trimGvar[NUM_STICKS] = { -1, -1, -1, -1 }; #if defined(CPUARM) void checkTrims() { - uint8_t event = getEvent(true); + evt_t event = getEvent(true); if (event && !IS_KEY_BREAK(event)) { int8_t k = EVT_KEY_MASK(event) - TRM_BASE; #else @@ -2009,7 +2036,7 @@ void checkBattery() if (counter-- == 0) { counter = 10; int32_t instant_vbat = anaIn(TX_VOLTAGE); -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) instant_vbat = (instant_vbat + instant_vbat*(g_eeGeneral.txVoltageCalibration)/128) * BATT_SCALE; instant_vbat >>= 11; instant_vbat += 2; // because of the diode @@ -2382,7 +2409,11 @@ uint16_t stackAvailable() void opentxInit(OPENTX_INIT_ARGS) { + TRACE("opentxInit()"); + +#if defined(EEPROM) eeReadAll(); +#endif #if defined(CPUARM) if (UNEXPECTED_SHUTDOWN()) { @@ -2401,10 +2432,14 @@ void opentxInit(OPENTX_INIT_ARGS) } #endif + TRACE("setVolume()"); + #if defined(VOICE) setVolume(g_eeGeneral.speakerVolume+VOLUME_LEVEL_DEF); #endif + TRACE("audioQueue.start()"); + #if defined(CPUARM) audioQueue.start(); setBacklight(g_eeGeneral.backlightBright); @@ -2431,10 +2466,12 @@ void opentxInit(OPENTX_INIT_ARGS) unexpectedShutdown = 1; #endif #if defined(CPUARM) + TRACE("eeLoadModel(g_eeGeneral.currModel)"); eeLoadModel(g_eeGeneral.currModel); #endif } else { + TRACE("opentxStart()"); opentxStart(); } @@ -2450,7 +2487,7 @@ void opentxInit(OPENTX_INIT_ARGS) #endif backlightOn(); -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) serial2Init(g_eeGeneral.serial2Mode, MODEL_TELEMETRY_PROTOCOL()); #endif @@ -2462,9 +2499,12 @@ void opentxInit(OPENTX_INIT_ARGS) doMixerCalculations(); #endif + TRACE("startPulses()"); startPulses(); wdt_enable(WDTO_500MS); + + TRACE("opentxInit() end!"); } #if !defined(SIMU) @@ -2488,10 +2528,15 @@ int main(void) boardInit(); -#if defined(GUI) && !defined(PCBTARANIS) +#if defined(GUI) && !defined(PCBTARANIS) && !defined(PCBFLAMENCO) && !defined(PCBHORUS) + // TODO remove this lcdInit(); #endif +#if defined(COLORLCD) + lcdColorsInit(); +#endif + stackPaint(); #if defined(GUI) @@ -2502,7 +2547,7 @@ int main(void) #endif #if defined(GUI) && !defined(PCBTARANIS) - lcdSetRefVolt(25); + // lcdSetRefVolt(25); #endif #if defined(PCBTARANIS) @@ -2550,6 +2595,10 @@ int main(void) uint8_t shutdown_state = 0; #endif +#if defined(PCBFLAMENCO) + menuEntryTime = get_tmr10ms() - 200; +#endif + while (1) { #if defined(CPUM2560) if ((shutdown_state=pwrCheck()) > e_power_trainer) @@ -2625,7 +2674,7 @@ uint32_t pwrCheck() lcdRefreshWait(); lcd_clear(); POPUP_CONFIRMATION("Confirm Shutdown"); - uint8_t evt = getEvent(false); + evt_t evt = getEvent(false); DISPLAY_WARNING(evt); lcdRefresh(); if (s_warning_result == true) { diff --git a/radio/src/opentx.h b/radio/src/opentx.h index 8badd74a6..f9c2eb077 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -283,7 +283,11 @@ #define RESXul 1024ul #define RESXl 1024l -#if defined(PCBTARANIS) +#if defined(PCBHORUS) + #include "targets/Horus/board_horus.h" +#elif defined(PCBFLAMENCO) + #include "targets/Flamenco/board_flamenco.h" +#elif defined(PCBTARANIS) #include "targets/taranis/board_taranis.h" #elif defined(PCBSKY9X) #include "targets/sky9x/board_sky9x.h" @@ -333,7 +337,25 @@ #include #endif -#if defined(PCBTARANIS) +#if defined(PCBHORUS) + #define NUM_SWITCHES 5 // 8 physical switches + 6 possible from 3POS + #define NUM_SW_SRCRAW 8 + // #define SWSRC_THR SWSRC_SF2 + // #define SWSRC_GEA SWSRC_SG2 + // #define SWSRC_ID0 SWSRC_SA0 + // #define SWSRC_ID1 SWSRC_SA1 + // #define SWSRC_ID2 SWSRC_SA2 + // #define SW_DSM2_BIND SW_SH2 +#elif defined(PCBFLAMENCO) + #define NUM_SWITCHES 5 // 8 physical switches + 6 possible from 3POS + #define NUM_SW_SRCRAW 8 + // #define SWSRC_THR SWSRC_SF2 + // #define SWSRC_GEA SWSRC_SG2 + // #define SWSRC_ID0 SWSRC_SA0 + // #define SWSRC_ID1 SWSRC_SA1 + // #define SWSRC_ID2 SWSRC_SA2 + // #define SW_DSM2_BIND SW_SH2 +#elif defined(PCBTARANIS) #if defined(REV9E) #define NUM_SWITCHES 18 // yes, it's a lot! #else @@ -357,7 +379,11 @@ #define NUM_PSWITCH (SWSRC_LAST_SWITCH-SWSRC_FIRST_SWITCH+1) #define NUM_POTSSW (NUM_XPOTS*6) -#if defined(PCBTARANIS) +// TODO in keys.h! +#if defined(PCBHORUS) + #define KEY_PLUS KEY_RIGHT + #define KEY_MINUS KEY_LEFT +#elif defined(PCBTARANIS) || defined(PCBFLAMENCO) #define KEY_RIGHT KEY_PLUS #define KEY_LEFT KEY_MINUS #define KEY_UP KEY_PLUS @@ -376,7 +402,15 @@ #define memclear(p, s) memset(p, 0, s) #endif -#if defined(PCBTARANIS) && defined(REV9E) +#if defined(PCBHORUS) + #define IS_POT_AVAILABLE(x) (true) + #define IS_POT_MULTIPOS(x) (x==0) + #define IS_POT_WITHOUT_DETENT(x) (x==0) +#elif defined(PCBFLAMENCO) + #define IS_POT_AVAILABLE(x) (true) + #define IS_POT_MULTIPOS(x) (x==0) + #define IS_POT_WITHOUT_DETENT(x) (x==0) +#elif defined(PCBTARANIS) && defined(REV9E) #define IS_SLIDER_AVAILABLE(x) ((x)==SLIDER1 || (x)==SLIDER2 || (g_eeGeneral.slidersConfig & (0x01 << ((x)-SLIDER3)))) #define IS_POT_AVAILABLE(x) ((x)=SLIDER1 && IS_SLIDER_AVAILABLE(x))) #define IS_POT_MULTIPOS(x) ((x)>=POT1 && (x)<=POT_LAST && ((g_eeGeneral.potsConfig>>(2*((x)-POT1)))&0x03)==POT_MULTIPOS_SWITCH) @@ -450,6 +484,10 @@ #define STICK_SCROLL_DISABLE() #endif +#if defined(CLI) +#include "cli.h" +#endif + #include "eeprom_common.h" #if defined(EEPROM_RLC) @@ -486,7 +524,17 @@ #define MAX_TRAINER_CHANNELS() (8) #endif -#if defined(PCBTARANIS) +#if defined(PCBFLAMENCO) + #define IS_MODULE_PPM(idx) (idx==TRAINER_MODULE || (idx==EXTERNAL_MODULE && g_model.externalModule==MODULE_TYPE_PPM)) + #define IS_MODULE_XJT(idx) ((g_model.externalModule==MODULE_TYPE_XJT) && (g_model.moduleData[idx].rfProtocol != RF_PROTO_OFF)) + #if defined(DSM2) + #define IS_MODULE_DSM2(idx) (idx==EXTERNAL_MODULE && g_model.externalModule==MODULE_TYPE_DSM2) + #else + #define IS_MODULE_DSM2(idx) (false) + #endif + #define MAX_EXTERNAL_MODULE_CHANNELS() ((g_model.externalModule == MODULE_TYPE_XJT) ? maxChannelsXJT[1+g_model.moduleData[1].rfProtocol] : maxChannelsModules[g_model.externalModule]) + #define MAX_CHANNELS(idx) (idx==EXTERNAL_MODULE ? MAX_EXTERNAL_MODULE_CHANNELS() : MAX_TRAINER_CHANNELS()) +#elif defined(PCBTARANIS) #if defined(TARANIS_INTERNAL_PPM) #define IS_MODULE_PPM(idx) (idx==TRAINER_MODULE || (idx==INTERNAL_MODULE && g_model.moduleData[INTERNAL_MODULE].type==MODULE_TYPE_PPM)|| (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_PPM)) #define IS_MODULE_XJT(idx) (((idx==INTERNAL_MODULE && g_model.moduleData[INTERNAL_MODULE].type==MODULE_TYPE_XJT)|| (idx==EXTERNAL_MODULE && g_model.moduleData[EXTERNAL_MODULE].type==MODULE_TYPE_XJT)) && (g_model.moduleData[idx].rfProtocol != RF_PROTO_OFF)) @@ -589,7 +637,9 @@ enum BaseCurves { #define THRCHK_DEADBAND 16 -#if defined(PCBTARANIS) +#if defined(PCBFLAMENCO) + #define SPLASH_NEEDED() (true) +#elif defined(PCBTARANIS) #define SPLASH_NEEDED() (g_eeGeneral.splashMode != 3) #elif defined(CPUARM) #define SPLASH_NEEDED() (g_model.moduleData[EXTERNAL_MODULE].type != MODULE_TYPE_DSM2 && !g_eeGeneral.splashMode) @@ -599,13 +649,13 @@ enum BaseCurves { #if defined(FSPLASH) #define SPLASH_TIMEOUT (g_eeGeneral.splashMode == 0 ? 60000/*infinite=10mn*/ : ((4*100) * (g_eeGeneral.splashMode & 0x03))) -#elif defined(PCBTARANIS) +#elif defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) #define SPLASH_TIMEOUT (g_eeGeneral.splashMode==-4 ? 1500 : (g_eeGeneral.splashMode<=0 ? (400-g_eeGeneral.splashMode*200) : (400-g_eeGeneral.splashMode*100))) #else #define SPLASH_TIMEOUT (4*100) // 4 seconds #endif -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) #define IS_RE_NAVIGATION_ENABLE() true #define NAVIGATION_RE_IDX() 0 #elif defined(ROTARY_ENCODERS) @@ -618,7 +668,7 @@ enum BaseCurves { #define HEART_TIMER_10MS 1 #define HEART_TIMER_PULSES 2 // when multiple modules this is the first one -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) #define HEART_WDT_CHECK (HEART_TIMER_10MS + (HEART_TIMER_PULSES << 0) + (HEART_TIMER_PULSES << 1)) #else #define HEART_WDT_CHECK (HEART_TIMER_10MS + HEART_TIMER_PULSES) @@ -658,7 +708,7 @@ int zchar2str(char *dest, const char *src, int size); #include "keys.h" #include "pwr.h" -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) div_t switchInfo(int switchPosition); #endif @@ -768,7 +818,7 @@ void logicalSwitchesReset(); #define LS_RECURSIVE_EVALUATION_RESET() s_last_switch_used = 0 #endif -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) void getSwitchesPosition(bool startup); #else #define getSwitchesPosition(...) @@ -777,7 +827,7 @@ void logicalSwitchesReset(); extern swarnstate_t switches_states; swsrc_t getMovedSwitch(); -#if defined(PCBTARANIS) +#if defined(VIRTUALINPUTS) #define GET_MOVED_SOURCE_PARAMS uint8_t min int8_t getMovedSource(GET_MOVED_SOURCE_PARAMS); #define GET_MOVED_SOURCE(min, max) getMovedSource(min) @@ -793,7 +843,7 @@ swsrc_t getMovedSwitch(); #define getFlightMode() 0 #endif -#if !defined(PCBTARANIS) +#if !defined(VIRTUALINPUTS) uint8_t getTrimFlightPhase(uint8_t phase, uint8_t idx); #else #define getTrimFlightPhase(phase, idx) (phase) @@ -809,7 +859,7 @@ swsrc_t getMovedSwitch(); trim_t getRawTrimValue(uint8_t phase, uint8_t idx); int getTrimValue(uint8_t phase, uint8_t idx); -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) bool setTrimValue(uint8_t phase, uint8_t idx, int trim); #else void setTrimValue(uint8_t phase, uint8_t idx, int trim); @@ -988,7 +1038,17 @@ enum Analogs { STICK2, STICK3, STICK4, -#if defined(PCBTARANIS) +#if defined(PCBFLAMENCO) + POT1, + POT2, + POT_LAST = POT2, + SLIDER1, + SLIDER2, + SWITCHES1, + SWITCHES2, + SWITCHES3, + SWITCHES4, +#elif defined(PCBTARANIS) POT1, POT2, POT3, @@ -1027,6 +1087,7 @@ enum Analogs { }; void checkBacklight(); +void doLoopCommonActions(); #if defined(PCBSTD) && defined(VOICE) && !defined(SIMU) #define BACKLIGHT_ON() (Voice.Backlight = 1) @@ -1427,7 +1488,7 @@ enum AUDIO_SOUNDS { #if defined(CPUARM) AU_TRIM_END, #endif -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) AU_STICK1_MIDDLE, AU_STICK2_MIDDLE, AU_STICK3_MIDDLE, @@ -1549,7 +1610,7 @@ union ReusableBuffer int16_t loVals[NUM_STICKS+NUM_POTS]; int16_t hiVals[NUM_STICKS+NUM_POTS]; uint8_t state; -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) struct { uint8_t stepsCount; int16_t steps[XPOTS_MULTIPOS_COUNT]; @@ -1698,7 +1759,7 @@ extern uint8_t s_frsky_view; #define EARTH_RADIUSKM ((uint32_t)6371) #define EARTH_RADIUS ((uint32_t)111194) -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) double gpsToDouble(bool neg, int16_t bp, int16_t ap); #endif void getGpsPilotPosition(); diff --git a/radio/src/pulses/dsm2_arm.cpp b/radio/src/pulses/dsm2_arm.cpp index de4739f27..774a5caf8 100644 --- a/radio/src/pulses/dsm2_arm.cpp +++ b/radio/src/pulses/dsm2_arm.cpp @@ -51,7 +51,7 @@ uint8_t dsm2BindTimer = DSM2_BIND_TIMEOUT; #define BITLEN_DSM2 (8*2) //125000 Baud => 8uS per bit -#if defined(PCBTARANIS) +#if !defined(PPM_PIN_HW_SERIAL) void _send_1(uint8_t v) { if (modulePulsesData[EXTERNAL_MODULE].dsm2.index == 0) @@ -129,7 +129,7 @@ void setupPulsesDSM2(unsigned int port) { static uint8_t dsmDat[2+6*2]={0xFF,0x00, 0x00,0xAA, 0x05,0xFF, 0x09,0xFF, 0x0D,0xFF, 0x13,0x54, 0x14,0xAA}; -#if defined(PCBSKY9X) +#if defined(PPM_PIN_HW_SERIAL) modulePulsesData[EXTERNAL_MODULE].dsm2.serialByte = 0 ; modulePulsesData[EXTERNAL_MODULE].dsm2.serialBitCount = 0 ; #else @@ -139,7 +139,7 @@ void setupPulsesDSM2(unsigned int port) modulePulsesData[EXTERNAL_MODULE].dsm2.ptr = modulePulsesData[EXTERNAL_MODULE].dsm2.pulses; -#if defined(PCBTARANIS) +#if !defined(PPM_PIN_HW_SERIAL) modulePulsesData[EXTERNAL_MODULE].dsm2.value = 100; *modulePulsesData[EXTERNAL_MODULE].dsm2.ptr++ = modulePulsesData[EXTERNAL_MODULE].dsm2.value; #endif @@ -156,7 +156,7 @@ void setupPulsesDSM2(unsigned int port) break; } -#if defined(PCBTARANIS) +#if !defined(PPM_PIN_HW_SERIAL) if (moduleFlag[port] == MODULE_BIND) dsmDat[0] |= DSM2_SEND_BIND; else if (moduleFlag[port] == MODULE_RANGECHECK) diff --git a/radio/src/pulses/pulses.h b/radio/src/pulses/pulses.h index ad88fe702..9c7ef11f2 100644 --- a/radio/src/pulses/pulses.h +++ b/radio/src/pulses/pulses.h @@ -55,7 +55,7 @@ enum ModuleFlag #define IS_RANGECHECK_ENABLE() (moduleFlag[0] == MODULE_RANGECHECK) #endif -#if defined(DSM2) && !defined(PCBTARANIS) +#if defined(DSM2) && !defined(PCBTARANIS) && !defined(PCBFLAMENCO) #define DSM2_BIND_TIMEOUT 255 // 255*11ms extern uint8_t dsm2BindTimer; #endif diff --git a/radio/src/pulses/pxx_arm.cpp b/radio/src/pulses/pxx_arm.cpp index c581a4584..99faa62d5 100644 --- a/radio/src/pulses/pxx_arm.cpp +++ b/radio/src/pulses/pxx_arm.cpp @@ -81,7 +81,7 @@ void crc(uint8_t data, unsigned int port) modulePulsesData[port].pxx.pcmCrc = (modulePulsesData[port].pxx.pcmCrc<<8) ^ (CRCTable[((modulePulsesData[port].pxx.pcmCrc>>8)^data) & 0xFF]); } -#if defined(PCBTARANIS) +#if !defined(PPM_PIN_HW_SERIAL) void putPcmPart(uint8_t value, unsigned int port) { diff --git a/radio/src/serial.cpp b/radio/src/serial.cpp index e64e0ec6d..3e868c20f 100644 --- a/radio/src/serial.cpp +++ b/radio/src/serial.cpp @@ -39,7 +39,7 @@ #include #include -#define PRINTF_BUFFER_SIZE 256 +#define PRINTF_BUFFER_SIZE 128 void serialPutc(char c) { diff --git a/radio/src/simu.cpp b/radio/src/simu.cpp index e8b9a2bf8..76c65aa5b 100644 --- a/radio/src/simu.cpp +++ b/radio/src/simu.cpp @@ -63,8 +63,10 @@ class Open9xSim: public FXMainWindow Open9xSim(){}; Open9xSim(FXApp* a); ~Open9xSim(); + void updateKeysAndSwitches(bool start=false); long onKeypress(FXObject*,FXSelector,void*); long onTimeout(FXObject*,FXSelector,void*); + void createBitmap(int index, uint16_t *data, int x, int y, int w, int h); void makeSnapshot(const FXDrawable* drawable); void doEvents(); void refreshDisplay(); @@ -93,7 +95,7 @@ Open9xSim::Open9xSim(FXApp* a): FXMainWindow(a, "OpenTX Simu", NULL, NULL, DECOR_ALL, 20, 90, 0, 0) { firstTime = true; - memset(displayBuf, 0, DISPLAY_BUFER_SIZE); + memset(displayBuf, 0, DISPLAY_BUFFER_SIZE); bmp = new FXPPMImage(getApp(),NULL,IMAGE_OWNED|IMAGE_KEEP|IMAGE_SHMI|IMAGE_SHMP, W2, H2); #if defined(SIMU_AUDIO) @@ -137,7 +139,9 @@ Open9xSim::Open9xSim(FXApp* a): bmf = new FXImageFrame(this,bmp); - getApp()->addTimeout(this,2,100); + updateKeysAndSwitches(true); + + getApp()->addTimeout(this, 2, 100); } Open9xSim::~Open9xSim() @@ -163,6 +167,31 @@ Open9xSim::~Open9xSim() #endif } +void Open9xSim::createBitmap(int index, uint16_t *data, int x, int y, int w, int h) +{ + FXPNGImage snapshot(getApp(), NULL, IMAGE_OWNED, w, h); + + for (int i=0; i>8)/0x0f, 255*((z&0x0F0)>>4)/0x0f, 255*(z&0x00F)/0x0f); + snapshot.setPixel(i, j, color); + } + } + + FXFileStream stream; + char buf[32]; + sprintf(buf,"%02d.png", index); + if (stream.open(buf, FXStreamSave)) { + snapshot.savePixels(stream); + stream.close(); + TRACE("Bitmap %d (w=%d, h=%d) created", index, w, h); + } + else { + TRACE("Bitmap %d (w=%d, h=%d) error", index, w, h); + } +} + void Open9xSim::makeSnapshot(const FXDrawable* drawable) { // Construct and create an FXImage object @@ -215,30 +244,120 @@ long Open9xSim::onKeypress(FXObject*,FXSelector,void*v) return 0; } -long Open9xSim::onTimeout(FXObject*, FXSelector, void*) +void Open9xSim::updateKeysAndSwitches(bool start) { - if(hasFocus()) { - static int keys1[]={ -#if defined(PCBTARANIS) - KEY_Page_Up, KEY_MENU, - KEY_Page_Down, KEY_PAGE, - KEY_Return, KEY_ENTER, - KEY_BackSpace, KEY_EXIT, - KEY_Up, KEY_PLUS, - KEY_Down, KEY_MINUS, + static int keys1[] = { +#if defined(PCBHORUS) + KEY_Page_Up, KEY_MENU, + KEY_Return, KEY_ENTER, + KEY_BackSpace, KEY_EXIT, + KEY_Up, KEY_UP, + KEY_Down, KEY_DOWN, + KEY_Right, KEY_RIGHT, + KEY_Left, KEY_LEFT, +#elif defined(PCBTARANIS) || defined(PCBFLAMENCO) + KEY_Page_Up, KEY_MENU, + KEY_Page_Down, KEY_PAGE, + KEY_Return, KEY_ENTER, + KEY_BackSpace, KEY_EXIT, + KEY_Up, KEY_PLUS, + KEY_Down, KEY_MINUS, #else - KEY_Return, KEY_MENU, - KEY_BackSpace, KEY_EXIT, - KEY_Right, KEY_RIGHT, - KEY_Left, KEY_LEFT, - KEY_Up, KEY_UP, - KEY_Down, KEY_DOWN, + KEY_Return, KEY_MENU, + KEY_BackSpace, KEY_EXIT, + KEY_Right, KEY_RIGHT, + KEY_Left, KEY_LEFT, + KEY_Up, KEY_UP, + KEY_Down, KEY_DOWN, #endif #if defined(ROTARY_ENCODER_NAVIGATION) - KEY_F, BTN_REa, + KEY_F, BTN_REa, #endif - }; + }; + for (unsigned int i=0; igetKeyState(keys1[i])); + } + +#ifdef __APPLE__ + // gruvin: Can't use Function keys on the Mac -- too many other app conflicts. + // The ordering of these keys, Q/W,E/R,T/Y,U/I matches the on screen + // order of trim sliders + static FXuint trimKeys[] = { KEY_E, KEY_R, KEY_U, KEY_I, KEY_R, KEY_E, KEY_Y, KEY_T, KEY_Q, KEY_W }; +#else + static FXuint trimKeys[] = { KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8 }; +#endif + + for (unsigned i=0; igetKeyState(trimKeys[i])); + } + +#define SWITCH_KEY(key, swtch, states) \ + static bool state##key = 0; \ + static int8_t state_##swtch = 2; \ + static int8_t inc_##swtch = 1; \ + if (getApp()->getKeyState(KEY_##key)) { \ + if (!state##key) { \ + state_##swtch = (state_##swtch+inc_##swtch); \ + if (state_##swtch == 1+states) inc_##swtch = -1; \ + else if (state_##swtch == 2) inc_##swtch = 1; \ + state##key = true; \ + } \ + } \ + else { \ + state##key = false; \ + } \ + simuSetSwitch(swtch, state_##swtch-states); + +#if defined(PCBFLAMENCO) + SWITCH_KEY(A, 0, 3); + SWITCH_KEY(B, 1, 2); + // SWITCH_KEY(C, 2, 3); + // SWITCH_KEY(D, 3, 3); + SWITCH_KEY(E, 4, 2); + SWITCH_KEY(F, 5, 3); +#elif defined(PCBTARANIS) && defined(REV9E) + SWITCH_KEY(A, 0, 3); + SWITCH_KEY(B, 1, 3); + SWITCH_KEY(C, 2, 3); + SWITCH_KEY(D, 3, 3); + SWITCH_KEY(E, 4, 3); + SWITCH_KEY(F, 5, 3); + SWITCH_KEY(G, 6, 3); + SWITCH_KEY(H, 7, 3); + SWITCH_KEY(I, 8, 3); + SWITCH_KEY(J, 9, 3); + SWITCH_KEY(K, 10, 3); + SWITCH_KEY(L, 11, 3); + SWITCH_KEY(M, 12, 3); + SWITCH_KEY(N, 13, 3); + SWITCH_KEY(O, 14, 3); + SWITCH_KEY(P, 15, 3); + SWITCH_KEY(Q, 16, 3); + SWITCH_KEY(R, 17, 3); +#elif defined(PCBTARANIS) + SWITCH_KEY(A, 0, 3); + SWITCH_KEY(B, 1, 3); + SWITCH_KEY(C, 2, 3); + SWITCH_KEY(D, 3, 3); + SWITCH_KEY(E, 4, 3); + SWITCH_KEY(F, 5, 2); + SWITCH_KEY(G, 6, 3); + SWITCH_KEY(H, 7, 2); +#else + SWITCH_KEY(1, 0, 2); + SWITCH_KEY(2, 1, 2); + SWITCH_KEY(3, 2, 2); + SWITCH_KEY(4, 3, 3); + SWITCH_KEY(5, 4, 2); + SWITCH_KEY(6, 5, 2); + SWITCH_KEY(7, 6, 2); +#endif +} + +long Open9xSim::onTimeout(FXObject*, FXSelector, void*) +{ + if (hasFocus()) { #if defined(PCBSKY9X) && !defined(REVX) Coproc_temp = 23; Coproc_maxtemp = 28; @@ -249,23 +368,8 @@ long Open9xSim::onTimeout(FXObject*, FXSelector, void*) maxTemperature = 42; #endif - for (unsigned int i=0; igetKeyState(keys1[i])); - } - -#ifdef __APPLE__ - // gruvin: Can't use Function keys on the Mac -- too many other app conflicts. - // The ordering of these keys, Q/W,E/R,T/Y,U/I matches the on screen - // order of trim sliders - static FXuint trimKeys[] = { KEY_E, KEY_R, KEY_U, KEY_I, KEY_R, KEY_E, KEY_Y, KEY_T, KEY_Q, KEY_W }; -#else - static FXuint trimKeys[] = { KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8 }; -#endif - - for (unsigned i=0; igetKeyState(trimKeys[i])); - } - + updateKeysAndSwitches(); + #if defined(ROTARY_ENCODER_NAVIGATION) static bool rotencAction = false; if (getApp()->getKeyState(KEY_G)) { @@ -281,24 +385,6 @@ long Open9xSim::onTimeout(FXObject*, FXSelector, void*) } #endif -#define SWITCH_KEY(key, swtch, states) \ - static bool state##key = 0; \ - static int8_t state_##swtch = 2; \ - static int8_t inc_##swtch = 1; \ - if (getApp()->getKeyState(KEY_##key)) { \ - if (!state##key) { \ - state_##swtch = (state_##swtch+inc_##swtch); \ - if (state_##swtch >= 1+states) inc_##swtch = -1; \ - else if (state_##swtch <= 2) inc_##swtch = 1; \ - /* TRACE("switch " #swtch ": state: %d, inc: %d", state_##swtch, inc_##swtch); */ \ - state##key = true; \ - } \ - } \ - else { \ - state##key = false; \ - } \ - simuSetSwitch(swtch, state_##swtch-states); - #if defined(PCBTARANIS) && defined(REV9E) SWITCH_KEY(A, 0, 3); SWITCH_KEY(B, 1, 3); @@ -337,7 +423,7 @@ long Open9xSim::onTimeout(FXObject*, FXSelector, void*) SWITCH_KEY(7, 6, 2); #endif } - + per10ms(); refreshDisplay(); getApp()->addTimeout(this, 2, 10); @@ -369,7 +455,19 @@ void Open9xSim::refreshDisplay() #endif for (int x=0; x>11)/0x1f, 255*((z&0x07E0)>>5)/0x3F, 255*(z&0x001F)/0x01F); + setPixel(x, y, color); + } +#elif defined(PCBFLAMENCO) + display_t z = lcd_buf[y * LCD_W + x]; + if (1) { + FXColor color = FXRGB(255*((z&0xF00)>>8)/0x0f, 255*((z&0x0F0)>>4)/0x0f, 255*(z&0x00F)/0x0f); + setPixel(x, y, color); + } +#elif defined(PCBTARANIS) display_t * p = &lcd_buf[y / 2 * LCD_W + x]; uint8_t z = (y & 1) ? (*p >> 4) : (*p & 0x0F); if (z) { @@ -459,7 +557,7 @@ uint16_t anaIn(uint8_t chan) return th9xSim->sliders[chan]->getValue(); else if (chanknobs[chan-NUM_STICKS]->getValue(); -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) else if (chan == TX_VOLTAGE) return 1000; #elif defined(PCBSKY9X) @@ -477,3 +575,8 @@ uint16_t anaIn(uint8_t chan) else return 0; } + +void createBitmap(int index, uint16_t *data, int x, int y, int w, int h) +{ + th9xSim->createBitmap(index, data, x, y, w, h); +} diff --git a/radio/src/switches.cpp b/radio/src/switches.cpp index 8ab5ebf58..0c3988fc4 100644 --- a/radio/src/switches.cpp +++ b/radio/src/switches.cpp @@ -71,6 +71,113 @@ volatile GETSWITCH_RECURSIVE_TYPE s_last_switch_value = 0; #endif +#if defined(PCBFLAMENCO) || defined(PCBHORUS) +tmr10ms_t potsLastposStart[1]; +uint8_t potsPos[1]; +tmr10ms_t switchesMidposStart[2]; +uint64_t switchesPos = 0; +div_t switchInfo(int switchPosition) +{ + const div_t infos[] = { + { 0, 0 }, { 0, 1 }, { 0, 2 }, + { 1, 0 }, { 1, 1 }, + { 2, 0 }, { 2, 1 }, { 2, 2 }, { 2, 3 }, { 2, 4 }, { 2, 5 }, + { 4, 0 }, { 4, 1 }, + { 5, 0 }, { 5, 1 }, { 5, 2 }, + }; + return infos[switchPosition-SWSRC_FIRST_SWITCH]; +} + +uint32_t check2PosSwitchPosition(EnumKeys sw) +{ + uint32_t result; + uint32_t index; + + if (switchState(sw)) + index = sw - SW_SA0; + else + index = sw - SW_SA0 + 1; + + result = ((uint32_t)1 << index); + + if (!(switchesPos & result)) { + PLAY_SWITCH_MOVED(index); + } + + return result; +} + +uint32_t check3PosSwitchPosition(int idx, EnumKeys sw, bool startup) +{ + uint32_t result; + uint32_t index; + + if (switchState(sw)) { + index = sw - SW_SA0; + result = (1 << index); + switchesMidposStart[idx] = 0; + } + else if (switchState(EnumKeys(sw+2))) { + index = sw - SW_SA0 + 2; + result = (1 << index); + switchesMidposStart[idx] = 0; + } + else if (startup || (switchesPos & (1 << (sw - SW_SA0 + 1))) || g_eeGeneral.switchesDelay==SWITCHES_DELAY_NONE || (switchesMidposStart[idx] && (tmr10ms_t)(get_tmr10ms() - switchesMidposStart[idx]) > SWITCHES_DELAY())) { + index = sw - SW_SA0 + 1; + result = (1 << index); + switchesMidposStart[idx] = 0; + } + else { + index = sw - SW_SA0 + 1; + if (!switchesMidposStart[idx]) { + switchesMidposStart[idx] = get_tmr10ms(); + } + result = (switchesPos & (0x7 << (sw - SW_SA0))); + } + + if (!(switchesPos & result)) { + PLAY_SWITCH_MOVED(index); + } + + return result; +} + +#define CHECK_2POS(sw) newPos |= check2PosSwitchPosition(sw ## 0) +#define CHECK_3POS(idx, sw) newPos |= check3PosSwitchPosition(idx, sw ## 0, startup) + +void getSwitchesPosition(bool startup) +{ + uint64_t newPos = 0; + CHECK_3POS(0, SW_SA); + CHECK_2POS(SW_SB); + CHECK_2POS(SW_SE); + CHECK_3POS(1, SW_SF); + switchesPos = newPos; + + int i = 0; + StepsCalibData * calib = (StepsCalibData *) &g_eeGeneral.calib[POT1+i]; + if (calib->count>0 && calib->countcount); + uint8_t previousPos = potsPos[i] >> 4; + uint8_t previousStoredPos = potsPos[i] & 0x0F; + if (startup) { + potsPos[i] = (pos << 4) | pos; + } + else if (pos != previousPos) { + potsLastposStart[i] = get_tmr10ms(); + potsPos[i] = (pos << 4) | previousStoredPos; + } + else if (g_eeGeneral.switchesDelay==SWITCHES_DELAY_NONE || (tmr10ms_t)(get_tmr10ms() - potsLastposStart[i]) > SWITCHES_DELAY()) { + potsLastposStart[i] = 0; + potsPos[i] = (pos << 4) | pos; + if (previousStoredPos != pos) { + PLAY_SWITCH_MOVED(SWSRC_LAST_SWITCH+i*XPOTS_MULTIPOS_COUNT+pos); + } + } + } +} +#endif + #if defined(PCBTARANIS) #if defined(REV9E) tmr10ms_t switchesMidposStart[16]; @@ -200,6 +307,7 @@ void getSwitchesPosition(bool startup) } } + getvalue_t getValueForLogicalSwitch(mixsrc_t i) { getvalue_t result = getValue(i); @@ -462,7 +570,7 @@ bool getSwitch(swsrc_t swtch) result = true; } else if (cs_idx <= SWSRC_LAST_SWITCH) { -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) // TODO || defined(PCBFLAMENCO) if (flags & GETSWITCH_MIDPOS_DELAY) result = SWITCH_POSITION(cs_idx-SWSRC_FIRST_SWITCH); else @@ -486,7 +594,7 @@ bool getSwitch(swsrc_t swtch) } #endif } -#if defined(PCBTARANIS) +#if NUM_XPOTS > 0 else if (cs_idx <= SWSRC_LAST_MULTIPOS_SWITCH) { result = POT_POSITION(cs_idx-SWSRC_FIRST_MULTIPOS_SWITCH); } @@ -568,7 +676,28 @@ swsrc_t getMovedSwitch() static tmr10ms_t s_move_last_time = 0; swsrc_t result = 0; -#if defined(PCBTARANIS) +#if defined(PCBFLAMENCO) +#if 0 + for (int i=0; i> (i*3); + uint8_t next = (1024+getValue(MIXSRC_SA+i)) / 1024; + if (prev != next) { + switches_states = (switches_states & (~mask)) | ((swarnstate_t)next << (i*3)); + if (i == 0) + result = 1+next; + else if (i == 1) + result = 1+(3*1)+(next!=0); + else if (i == 3) + result = 12+(next!=0); + else if (i == 4) + result = 14+next; + else + result = 0; + } + } +#endif +#elif defined(PCBTARANIS) for (int i=0; i 1)) { @@ -692,25 +817,44 @@ void checkSwitches() } // first - display warning -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) +#if defined(COLORLCD) + if ((last_bad_switches != switches_states) || (last_bad_pots != bad_pots)) { + int x = WARNING_LINE_X, y = WARNING_INFOLINE_Y-5; +#elif defined(PCBTARANIS) if ((last_bad_switches != switches_states) || (last_bad_pots != bad_pots)) { MESSAGE(STR_SWITCHWARN, NULL, STR_PRESSANYKEYTOSKIP, ((last_bad_switches == 0xff) || (last_bad_pots == 0xff)) ? AU_SWITCH_ALERT : AU_NONE); int x = 60, y = 4*FH+3; +#endif int numWarnings = 0; for (int i=0; i 5) { - lcd_putsAtt(x, y, "...", 0); - break; + if (++numWarnings < 6) { + putsSwitches(x, y, SWSRC_FIRST_SWITCH+i*3, attr); + x += 20; + } + else if (numWarnings == 6) { + lcd_putsAtt(x, y, "...", ALARM_COLOR); } - char c = "\300-\301"[(states & mask) >> (i*2)]; - putsMixerSource(x, y, MIXSRC_FIRST_SWITCH+i, attr); - lcd_putcAtt(lcdNextPos, y, c, attr); - x = lcdNextPos + 3; } +#else + LcdFlags attr = ((states & mask) == (switches_states & mask)) ? 0 : INVERS; + if (attr) { + if (++numWarnings < 7) { + char c = "\300-\301"[(states & mask) >> (i*2)]; + putsMixerSource(x, y, MIXSRC_FIRST_SWITCH+i, attr); + lcd_putcAtt(lcdNextPos, y, c, attr); + x = lcdNextPos + 3; + } + else if (numWarnings == 7) { + lcd_putsAtt(x, y, "...", 0); + } + } +#endif } } if (g_model.potsWarnMode) { @@ -719,17 +863,34 @@ void checkSwitches() x = 60; } for (int i=0; i 1) { +#if defined(COLORLCD) + char s[8]; + // TODO add an helper + strncpy(s, &STR_VSRCRAW[1+(NUM_STICKS+1+i)*STR_VSRCRAW[0]], STR_VSRCRAW[0]); + s[int(STR_VSRCRAW[0])] = '\0'; +#else lcd_putsiAtt(x, y, STR_VSRCRAW, NUM_STICKS+1+i, INVERS); if (IS_POT(POT1+i)) lcd_putcAtt(lcdNextPos, y, g_model.potsWarnPosition[i] > GET_LOWRES_POT_POSITION(i) ? 126 : 127, INVERS); else lcd_putcAtt(lcdNextPos, y, g_model.potsWarnPosition[i] > GET_LOWRES_POT_POSITION(i) ? '\300' : '\301', INVERS); +#endif +#if defined(COLORLCD) + if (++numWarnings < 6) { + lcd_putsAtt(x, y, s, ALARM_COLOR); + } + else if (numWarnings == 6) { + lcd_putsAtt(x, y, "...", ALARM_COLOR); + } + x += 20; +#else x = lcdNextPos + 3; +#endif } } @@ -761,30 +922,9 @@ void checkSwitches() last_bad_switches = 0xff; } #else + if (pwrCheck()==e_power_off || keyDown()) return; - if (keyDown()) { - return; - } - -#if defined(PCBTARANIS) && defined(REV9E) - uint32_t pwr_check = pwrCheck(); - if (pwr_check == e_power_off) { - return; - } - else if (pwr_check == e_power_press) { - refresh = true; - } - else if (pwr_check == e_power_on && refresh) { - last_bad_switches = 0xff; - refresh = false; - } -#else - if (pwrCheck() == e_power_off) { - return; - } -#endif - - checkBacklight(); + doLoopCommonActions(); wdt_reset(); diff --git a/radio/src/targets/simu/simpgmspace.cpp b/radio/src/targets/simu/simpgmspace.cpp index 74213bdfa..f41d475c2 100644 --- a/radio/src/targets/simu/simpgmspace.cpp +++ b/radio/src/targets/simu/simpgmspace.cpp @@ -64,7 +64,7 @@ int g_snapshot_idx = 0; #if defined(CPUSTM32) uint32_t Peri1_frequency, Peri2_frequency; -GPIO_TypeDef gpioa, gpiob, gpioc, gpiod, gpioe, gpiof, gpiog; +GPIO_TypeDef gpioa, gpiob, gpioc, gpiod, gpioe, gpiof, gpiog, gpioh, gpioi, gpioj; TIM_TypeDef tim1, tim2, tim3, tim4, tim5, tim6, tim7, tim8, tim9, tim10; RCC_TypeDef rcc; DMA_Stream_TypeDef dma2_stream2, dma2_stream6; @@ -152,7 +152,13 @@ void simuSetKey(uint8_t key, bool state) switch (key) { KEY_CASE(KEY_MENU, KEYS_GPIO_REG_MENU, KEYS_GPIO_PIN_MENU) KEY_CASE(KEY_EXIT, KEYS_GPIO_REG_EXIT, KEYS_GPIO_PIN_EXIT) -#if defined(PCBTARANIS) +#if defined(PCBHORUS) + KEY_CASE(KEY_ENTER, KEYS_GPIO_REG_ENTER, KEYS_GPIO_PIN_ENTER) + KEY_CASE(KEY_RIGHT, KEYS_GPIO_REG_RIGHT, KEYS_GPIO_PIN_RIGHT) + KEY_CASE(KEY_LEFT, KEYS_GPIO_REG_LEFT, KEYS_GPIO_PIN_LEFT) + KEY_CASE(KEY_UP, KEYS_GPIO_REG_UP, KEYS_GPIO_PIN_UP) + KEY_CASE(KEY_DOWN, KEYS_GPIO_REG_DOWN, KEYS_GPIO_PIN_DOWN) +#elif defined(PCBTARANIS) || defined(PCBFLAMENCO) KEY_CASE(KEY_ENTER, KEYS_GPIO_REG_ENTER, KEYS_GPIO_PIN_ENTER) KEY_CASE(KEY_PAGE, KEYS_GPIO_REG_PAGE, KEYS_GPIO_PIN_PAGE) KEY_CASE(KEY_MINUS, KEYS_GPIO_REG_MINUS, KEYS_GPIO_PIN_MINUS) @@ -186,6 +192,12 @@ void simuSetTrim(uint8_t trim, bool state) TRIM_CASE(5, TRIMS_GPIO_REG_RVU, TRIMS_GPIO_PIN_RVU) TRIM_CASE(6, TRIMS_GPIO_REG_RHL, TRIMS_GPIO_PIN_RHL) TRIM_CASE(7, TRIMS_GPIO_REG_RHR, TRIMS_GPIO_PIN_RHR) +#if defined(HORUS) + TRIM_CASE(8, TRIMS_GPIO_REG_LSU, TRIMS_GPIO_PIN_LSU) + TRIM_CASE(9, TRIMS_GPIO_REG_LSD, TRIMS_GPIO_PIN_RVU) + TRIM_CASE(10, TRIMS_GPIO_REG_RSU, TRIMS_GPIO_PIN_RHL) + TRIM_CASE(11, TRIMS_GPIO_REG_RSD, TRIMS_GPIO_PIN_RHR) +#endif } } @@ -194,7 +206,14 @@ void simuSetSwitch(uint8_t swtch, int8_t state) { // TRACE("simuSetSwitch(%d, %d)", swtch, state); switch (swtch) { -#if defined(PCBTARANIS) && defined(REV9E) +#if defined(PCBFLAMENCO) + // SWITCH_3_CASE(0, SWITCHES_GPIO_REG_A_L, SWITCHES_GPIO_REG_A_H, SWITCHES_GPIO_PIN_A_L, SWITCHES_GPIO_PIN_A_H) + // SWITCH_CASE(1, SWITCHES_GPIO_REG_B, SWITCHES_GPIO_PIN_B) + // SWITCH_3_CASE(2, SWITCHES_GPIO_REG_C_L, SWITCHES_GPIO_REG_C_H, SWITCHES_GPIO_PIN_C_L, SWITCHES_GPIO_PIN_C_H) + // SWITCH_3_CASE(3, SWITCHES_GPIO_REG_D_L, SWITCHES_GPIO_REG_D_H, SWITCHES_GPIO_PIN_D_L, SWITCHES_GPIO_PIN_D_H) + // SWITCH_CASE(4, SWITCHES_GPIO_REG_E, SWITCHES_GPIO_PIN_E) + // SWITCH_3_CASE(5, SWITCHES_GPIO_REG_F_H, SWITCHES_GPIO_REG_F_L, SWITCHES_GPIO_PIN_F_H, SWITCHES_GPIO_PIN_F_L) +#elif defined(PCBTARANIS) && defined(REV9E) SWITCH_3_CASE(0, SWITCHES_GPIO_REG_A_L, SWITCHES_GPIO_REG_A_H, SWITCHES_GPIO_PIN_A_L, SWITCHES_GPIO_PIN_A_H) SWITCH_3_CASE(1, SWITCHES_GPIO_REG_B_L, SWITCHES_GPIO_REG_B_H, SWITCHES_GPIO_PIN_B_L, SWITCHES_GPIO_PIN_B_H) SWITCH_3_CASE(2, SWITCHES_GPIO_REG_C_L, SWITCHES_GPIO_REG_C_H, SWITCHES_GPIO_PIN_C_L, SWITCHES_GPIO_PIN_C_H) @@ -213,7 +232,7 @@ void simuSetSwitch(uint8_t swtch, int8_t state) SWITCH_3_CASE(15, SWITCHES_GPIO_REG_P_L, SWITCHES_GPIO_REG_P_H, SWITCHES_GPIO_PIN_P_L, SWITCHES_GPIO_PIN_P_H) SWITCH_3_CASE(16, SWITCHES_GPIO_REG_Q_L, SWITCHES_GPIO_REG_Q_H, SWITCHES_GPIO_PIN_Q_L, SWITCHES_GPIO_PIN_Q_H) SWITCH_3_CASE(17, SWITCHES_GPIO_REG_R_L, SWITCHES_GPIO_REG_R_H, SWITCHES_GPIO_PIN_R_L, SWITCHES_GPIO_PIN_R_H) -#elif defined(PCBTARANIS) +#elif defined(PCBTARANIS) || defined(PCBHORUS) SWITCH_3_CASE(0, SWITCHES_GPIO_REG_A_L, SWITCHES_GPIO_REG_A_H, SWITCHES_GPIO_PIN_A_L, SWITCHES_GPIO_PIN_A_H) SWITCH_3_CASE(1, SWITCHES_GPIO_REG_B_L, SWITCHES_GPIO_REG_B_H, SWITCHES_GPIO_PIN_B_L, SWITCHES_GPIO_PIN_B_H) SWITCH_3_CASE(2, SWITCHES_GPIO_REG_C_L, SWITCHES_GPIO_REG_C_H, SWITCHES_GPIO_PIN_C_L, SWITCHES_GPIO_PIN_C_H) @@ -271,7 +290,7 @@ uint16_t getTmr16KHz() return get_tmr10ms() * 160; } -#if !defined(PCBTARANIS) +#if !defined(PCBTARANIS) && !defined(PCBHORUS) bool eeprom_thread_running = true; void *eeprom_write_function(void *) { @@ -329,6 +348,10 @@ void *main_thread(void *) try { #endif +#if defined(COLORLCD) + lcdColorsInit(); +#endif + #if defined(CPUARM) stackPaint(); #endif @@ -339,7 +362,9 @@ void *main_thread(void *) g_menuStack[0] = menuMainView; g_menuStack[1] = menuModelSelect; +#if defined(EEPROM) eeReadAll(); // load general setup and selected model +#endif #if defined(SIMU_DISKIO) f_mount(&g_FATFS_Obj, "", 1); @@ -364,6 +389,10 @@ void *main_thread(void *) s_current_protocol[0] = 0; +#if defined(PCBFLAMENCO) + menuEntryTime = get_tmr10ms() - 200; +#endif + while (main_thread_running) { #if defined(CPUARM) doMixerCalculations(); @@ -603,7 +632,7 @@ void StartEepromThread(const char *filename) sem_init(eeprom_write_sem, 0, 0); #endif -#if !defined(PCBTARANIS) +#if !defined(PCBTARANIS) && !defined(PCBHORUS) eeprom_thread_running = true; assert(!pthread_create(&eeprom_thread_pid, NULL, &eeprom_write_function, NULL)); #endif @@ -611,7 +640,7 @@ void StartEepromThread(const char *filename) void StopEepromThread() { -#if !defined(PCBTARANIS) +#if !defined(PCBTARANIS) && !defined(PCBFLAMENCO) && !defined(PCBHORUS) eeprom_thread_running = false; sem_post(eeprom_write_sem); pthread_join(eeprom_thread_pid, NULL); @@ -640,7 +669,7 @@ void eepromReadBlock (uint8_t * pointer_ram, uint32_t pointer_eeprom, uint32_t s } } -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) void eepromWriteBlock(uint8_t * pointer_ram, uint32_t pointer_eeprom, uint32_t size) { assert(size); @@ -1198,9 +1227,11 @@ uint32_t sdGetSpeed() bool lcd_refresh = true; display_t lcd_buf[DISPLAY_BUF_SIZE]; +#if !defined(PCBFLAMENCO) && !defined(PCBHORUS) void lcdSetRefVolt(uint8_t val) { } +#endif void adcPrepareBandgap() { @@ -1214,11 +1245,15 @@ void lcdOff() void lcdRefresh() { +#if defined(PCBFLAMENCO) + TW8823_SendScreen(); +#endif + memcpy(lcd_buf, displayBuf, sizeof(lcd_buf)); lcd_refresh = true; } -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) void pwrInit() { } void pwrOff() { } #if defined(REV9E) @@ -1275,3 +1310,8 @@ void turnBacklightOff(void) #endif // #if defined(PCBTARANIS) +#if defined(PCBFLAMENCO) +void i2cWriteTW8823(unsigned char, unsigned char) { } +uint8_t i2cReadBQ24195(uint8_t) { return 0; } +void i2cWriteBQ24195(uint8_t, uint8_t) { } +#endif diff --git a/radio/src/targets/simu/simpgmspace.h b/radio/src/targets/simu/simpgmspace.h index 0b7523494..936ff29cd 100644 --- a/radio/src/targets/simu/simpgmspace.h +++ b/radio/src/targets/simu/simpgmspace.h @@ -101,7 +101,7 @@ typedef const int16_t pm_int16_t; typedef const int8_t pm_int8_t; #if defined(CPUSTM32) -extern GPIO_TypeDef gpioa, gpiob, gpioc, gpiod, gpioe, gpiof, gpiog; +extern GPIO_TypeDef gpioa, gpiob, gpioc, gpiod, gpioe, gpiof, gpiog, gpioh, gpioi, gpioj; extern TIM_TypeDef tim1, tim2, tim3, tim4, tim5, tim6, tim7, tim8, tim9, tim10; extern USART_TypeDef Usart0, Usart1, Usart2, Usart3, Usart4; extern RCC_TypeDef rcc; @@ -114,6 +114,9 @@ extern DMA_TypeDef dma2; #undef GPIOE #undef GPIOF #undef GPIOG +#undef GPIOH +#undef GPIOI +#undef GPIOJ #define GPIOA (&gpioa) #define GPIOB (&gpiob) #define GPIOC (&gpioc) @@ -121,6 +124,9 @@ extern DMA_TypeDef dma2; #define GPIOE (&gpioe) #define GPIOF (&gpiof) #define GPIOG (&gpiog) +#define GPIOH (&gpioh) +#define GPIOI (&gpioi) +#define GPIOJ (&gpioj) #undef TIM1 #undef TIM2 #undef TIM3 @@ -392,23 +398,24 @@ extern OS_MutexID audioMutex; #define CoInitOS(...) #define CoStartOS(...) -#define CoCreateTask(...) (0) -#define CoCreateMutex(...) PTHREAD_MUTEX_INITIALIZER +#define CoCreateTask(...) 0 +#define CoCreateTaskEx(...) 0 +#define CoCreateMutex(...) PTHREAD_MUTEX_INITIALIZER #define CoSetFlag(...) #define CoClearFlag(...) #define CoSetTmrCnt(...) #define CoEnterISR(...) #define CoExitISR(...) #define CoStartTmr(...) -#define CoWaitForSingleFlag(...) 0 -#define CoEnterMutexSection(m) pthread_mutex_lock(&(m)) -#define CoLeaveMutexSection(m) pthread_mutex_unlock(&(m)) +#define CoWaitForSingleFlag(...) 0 +#define CoEnterMutexSection(m) pthread_mutex_lock(&(m)) +#define CoLeaveMutexSection(m) pthread_mutex_unlock(&(m)) #define CoTickDelay(...) -#define CoCreateFlag(...) 0 -#define CoGetOSTime(...) 0 +#define CoCreateFlag(...) 0 +#define CoGetOSTime(...) 0 #define UART_Stop(...) #define UART3_Stop(...) -#define USART_GetITStatus(...) 0 +#define USART_GetITStatus(...) 0 #if defined(CPUSTM32) inline void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct) { } diff --git a/radio/src/tasks_arm.cpp b/radio/src/tasks_arm.cpp index 7b990e387..26442ae0b 100644 --- a/radio/src/tasks_arm.cpp +++ b/radio/src/tasks_arm.cpp @@ -97,6 +97,9 @@ uint16_t getStackAvailable(void * address, uint16_t size) i++; } return i*4; +#if defined(CLI) + cliStackPaint(); +#endif } template diff --git a/radio/src/telemetry/frsky.cpp b/radio/src/telemetry/frsky.cpp index 9dffd4b23..daa122f72 100644 --- a/radio/src/telemetry/frsky.cpp +++ b/radio/src/telemetry/frsky.cpp @@ -47,7 +47,7 @@ uint8_t link_counter = 0; #define FRSKY_RX_PACKET_SIZE 19 uint8_t frskyRxBuffer[FRSKY_RX_PACKET_SIZE]; // Receive buffer. 9 bytes (full packet), worst case 18 bytes with byte-stuffing (+1) -#if !defined(CPUARM) +#if !defined(CPUARM) && !defined(PCBFLAMENCO) uint8_t frskyTxBuffer[FRSKY_TX_PACKET_SIZE]; #endif @@ -59,7 +59,7 @@ uint8_t frskyTxBufferCount = 0; uint8_t telemetryState = TELEMETRY_INIT; #endif -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) Fifo<512> telemetryFifo; // TODO should be in the driver #endif @@ -323,7 +323,7 @@ void telemetryWakeup() } #endif -#if !defined(CPUARM) +#if !defined(CPUARM) && !defined(PCBFLAMENCO) if (IS_FRSKY_D_PROTOCOL()) { // Attempt to transmit any waiting Fr-Sky alarm set packets every 50ms (subject to packet buffer availability) static uint8_t frskyTxDelay = 5; diff --git a/radio/src/telemetry/frsky.h b/radio/src/telemetry/frsky.h index ebb9b14f7..07c9a5c2b 100644 --- a/radio/src/telemetry/frsky.h +++ b/radio/src/telemetry/frsky.h @@ -491,7 +491,7 @@ enum FrSkyDataState { #endif }; -#if defined(CPUARM) +#if defined(CPUARM) || defined(PCBFLAMENCO) #define frskySendAlarms() #else #define SEND_RSSI_ALARMS 6 diff --git a/radio/src/thirdparty/CoOS/OsConfig.h b/radio/src/thirdparty/CoOS/OsConfig.h index 7c1876d37..ffc41ca1a 100644 --- a/radio/src/thirdparty/CoOS/OsConfig.h +++ b/radio/src/thirdparty/CoOS/OsConfig.h @@ -69,9 +69,9 @@ Idle task stack size(word). /*!< System frequency (Hz). */ -#if defined(PCBTARANIS) && defined(REV9E) +#if defined(PCBFLAMENCO) || (defined(PCBTARANIS) && defined(REV9E)) #define CFG_CPU_FREQ (168000000) -#elif defined(PCBTARANIS) +#elif defined(PCBTARANIS) || defined(PCBHORUS) #define CFG_CPU_FREQ (120000000) #else #define CFG_CPU_FREQ (36000000) // TODO check if really correct for sky9x? diff --git a/radio/src/thirdparty/GCS_MAVLink/message_definitions_v1.0/matrixpilot.xml b/radio/src/thirdparty/GCS_MAVLink/message_definitions_v1.0/matrixpilot.xml index 29d368d2a..240c0ed01 100644 --- a/radio/src/thirdparty/GCS_MAVLink/message_definitions_v1.0/matrixpilot.xml +++ b/radio/src/thirdparty/GCS_MAVLink/message_definitions_v1.0/matrixpilot.xml @@ -178,7 +178,7 @@ Serial UDB Extra Current Waypoint Goal X Serial UDB Extra Current Waypoint Goal Y Serial UDB Extra Current Waypoint Goal Z - Serial UDB Extra Stack Memory Free + Serial UDB Extra Stack Memory Free Backwards compatible version of SERIAL_UDB_EXTRA F4: format diff --git a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/audio/inc/usbd_audio_core.h b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/audio/inc/usbd_audio_core.h index eeb90532b..0a0e6f884 100644 --- a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/audio/inc/usbd_audio_core.h +++ b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/audio/inc/usbd_audio_core.h @@ -30,9 +30,9 @@ #ifndef __USB_AUDIO_CORE_H_ #define __USB_AUDIO_CORE_H_ +#include "../../../../../../../targets/Flamenco/usbd_desc.h" #include "usbd_ioreq.h" #include "usbd_req.h" -#include "usbd_desc.h" diff --git a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/cdc/inc/usbd_cdc_if_template.h b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/cdc/inc/usbd_cdc_if_template.h index 1b0c3f048..f3f1af32f 100644 --- a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/cdc/inc/usbd_cdc_if_template.h +++ b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/cdc/inc/usbd_cdc_if_template.h @@ -30,8 +30,8 @@ #define __USBD_CDC_IF_TEMPLATE_H /* Includes ------------------------------------------------------------------*/ -#include "usb_conf.h" -#include "usbd_conf.h" +#include "../../../../../../../targets/Flamenco/usb_conf.h" +#include "../../../../../../../targets/Flamenco/usbd_conf.h" #include "usbd_cdc_core.h" /* Exported types ------------------------------------------------------------*/ diff --git a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/cdc/src/usbd_cdc_core.c b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/cdc/src/usbd_cdc_core.c index 3856f778d..4cce796e7 100644 --- a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/cdc/src/usbd_cdc_core.c +++ b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/cdc/src/usbd_cdc_core.c @@ -64,7 +64,8 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "usbd_cdc_core.h" +#include "../inc/usbd_cdc_core.h" + #include "usbd_desc.h" #include "usbd_req.h" diff --git a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/dfu/inc/usbd_dfu_mal.h b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/dfu/inc/usbd_dfu_mal.h index bf6aae491..740d3b22e 100644 --- a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/dfu/inc/usbd_dfu_mal.h +++ b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/dfu/inc/usbd_dfu_mal.h @@ -30,8 +30,8 @@ #define __DFU_MAL_H /* Includes ------------------------------------------------------------------*/ -#include "usb_conf.h" - +#include "../../../../../../../targets/Flamenco/usb_conf.h" +#include "../../../../../../../targets/Flamenco/usbd_conf.h" #include "usbd_conf.h" #include "usbd_dfu_core.h" diff --git a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/dfu/inc/usbd_mem_if_template.h b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/dfu/inc/usbd_mem_if_template.h index eaae60359..777649e0a 100644 --- a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/dfu/inc/usbd_mem_if_template.h +++ b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/dfu/inc/usbd_mem_if_template.h @@ -30,8 +30,7 @@ #define __MEM_IF_MAL_H /* Includes ------------------------------------------------------------------*/ -#include "usb_conf.h" - +#include "../../../../../../../targets/Flamenco/usb_conf.h" #include "usbd_dfu_mal.h" /* Exported types ------------------------------------------------------------*/ diff --git a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/dfu/src/usbd_dfu_core.c b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/dfu/src/usbd_dfu_core.c index 5f2b3b360..56ef1e662 100644 --- a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/dfu/src/usbd_dfu_core.c +++ b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/dfu/src/usbd_dfu_core.c @@ -63,7 +63,8 @@ /* Includes ------------------------------------------------------------------*/ #include "usbd_dfu_core.h" -#include "usbd_desc.h" + +#include "../../../../../../../targets/Flamenco/usbd_desc.h" #include "usbd_req.h" #include "usb_bsp.h" diff --git a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/hid/src/usbd_hid_core.c b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/hid/src/usbd_hid_core.c index 7cdc52349..99eb14a05 100644 --- a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/hid/src/usbd_hid_core.c +++ b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/hid/src/usbd_hid_core.c @@ -48,7 +48,8 @@ /* Includes ------------------------------------------------------------------*/ #include "usbd_hid_core.h" -#include "../../../../../usbd_desc.h" + +#include "../../../../../../../targets/Flamenco/usbd_desc.h" #include "usbd_req.h" diff --git a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/msc/inc/usbd_msc_data.h b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/msc/inc/usbd_msc_data.h index c8f3a2adf..ef440fbc4 100644 --- a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/msc/inc/usbd_msc_data.h +++ b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Class/msc/inc/usbd_msc_data.h @@ -31,7 +31,7 @@ #define _USBD_MSC_DATA_H_ /* Includes ------------------------------------------------------------------*/ -#include "usbd_conf.h" +#include "../../../../../../../targets/Flamenco/usbd_conf.h" /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ diff --git a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Core/inc/usbd_conf_template.h b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Core/inc/usbd_conf_template.h index b1a20f947..ab10fa7a1 100644 --- a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Core/inc/usbd_conf_template.h +++ b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Core/inc/usbd_conf_template.h @@ -30,7 +30,7 @@ #define __USBD_CONF__H__ /* Includes ------------------------------------------------------------------*/ -#include "usb_conf.h" +#include "../../../../../../targets/Flamenco/usb_conf.h" /** @defgroup USB_CONF_Exported_Defines * @{ diff --git a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Core/inc/usbd_core.h b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Core/inc/usbd_core.h index c01964749..030e35c38 100644 --- a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Core/inc/usbd_core.h +++ b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Core/inc/usbd_core.h @@ -30,9 +30,9 @@ #define __USBD_CORE_H /* Includes ------------------------------------------------------------------*/ +#include "../../../../../../targets/Flamenco/usbd_conf.h" #include "../../../STM32_USB_OTG_Driver/inc/usb_dcd.h" #include "usbd_def.h" -#include "usbd_conf.h" /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @{ diff --git a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Core/inc/usbd_req.h b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Core/inc/usbd_req.h index f88416df3..467f5f822 100644 --- a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Core/inc/usbd_req.h +++ b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Core/inc/usbd_req.h @@ -31,9 +31,9 @@ #define __USB_REQUEST_H_ /* Includes ------------------------------------------------------------------*/ +#include "../../../../../../targets/Flamenco/usbd_conf.h" #include "usbd_def.h" #include "usbd_core.h" -#include "usbd_conf.h" /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY diff --git a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Core/src/usbd_req.c b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Core/src/usbd_req.c index 2659732e6..8a5f8390d 100644 --- a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Core/src/usbd_req.c +++ b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_Device_Library/Core/src/usbd_req.c @@ -27,8 +27,9 @@ /* Includes ------------------------------------------------------------------*/ #include "usbd_req.h" + +#include "../../../../../../targets/Flamenco/usbd_desc.h" #include "usbd_ioreq.h" -#include "usbd_desc.h" /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY diff --git a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_OTG_Driver/inc/usb_conf_template.h b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_OTG_Driver/inc/usb_conf_template.h index 2e415e126..5de0d5143 100644 --- a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_OTG_Driver/inc/usb_conf_template.h +++ b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_OTG_Driver/inc/usb_conf_template.h @@ -30,7 +30,7 @@ #define __USB_CONF__H__ /* Includes ------------------------------------------------------------------*/ -#include "usb_conf.h" +#include "../../../../../targets/Flamenco/usb_conf.h" /** @addtogroup USB_OTG_DRIVER * @{ diff --git a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_OTG_Driver/inc/usb_defines.h b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_OTG_Driver/inc/usb_defines.h index 8e0d264f4..ee651a992 100644 --- a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_OTG_Driver/inc/usb_defines.h +++ b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_OTG_Driver/inc/usb_defines.h @@ -30,7 +30,7 @@ #define __USB_DEF_H__ /* Includes ------------------------------------------------------------------*/ -#include "usb_conf.h" +#include "../../../../../targets/Flamenco/usb_conf.h" /** @addtogroup USB_OTG_DRIVER * @{ diff --git a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_OTG_Driver/inc/usb_regs.h b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_OTG_Driver/inc/usb_regs.h index 323e87056..cc490c0ed 100644 --- a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_OTG_Driver/inc/usb_regs.h +++ b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_OTG_Driver/inc/usb_regs.h @@ -30,7 +30,7 @@ #define __USB_OTG_REGS_H__ /* Includes ------------------------------------------------------------------*/ -#include "usb_conf.h" +#include "../../../../../targets/Flamenco/usb_conf.h" /** @addtogroup USB_OTG_DRIVER diff --git a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_OTG_Driver/src/usb_hcd.c b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_OTG_Driver/src/usb_hcd.c index 56e224418..5ba595dfd 100644 --- a/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_OTG_Driver/src/usb_hcd.c +++ b/radio/src/thirdparty/STM32_USB-Host-Device_Lib_V2.1.0/Libraries/STM32_USB_OTG_Driver/src/usb_hcd.c @@ -28,7 +28,8 @@ /* Includes ------------------------------------------------------------------*/ #include "usb_core.h" #include "usb_hcd.h" -#include "usb_conf.h" + +#include "../../../../../targets/Flamenco/usb_conf.h" #include "usb_bsp.h" diff --git a/radio/src/translations.cpp b/radio/src/translations.cpp index 524d87a55..b02c249ad 100644 --- a/radio/src/translations.cpp +++ b/radio/src/translations.cpp @@ -581,7 +581,7 @@ const pm_char STR_BLCOLOR[] PROGMEM = TR_BLCOLOR; const pm_char STR_CONFIRMDELETE[] PROGMEM = TR_CONFIRMDELETE; #endif -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) const pm_char STR_BYTES[] PROGMEM = TR_BYTES; const pm_char STR_ANTENNAPROBLEM[] PROGMEM = TR_ANTENNAPROBLEM; const pm_char STR_MODULE[] PROGMEM = TR_MODULE; diff --git a/radio/src/translations.h b/radio/src/translations.h index c533a504d..14b28d745 100644 --- a/radio/src/translations.h +++ b/radio/src/translations.h @@ -800,7 +800,7 @@ extern const pm_char STR_BLCOLOR[]; extern const pm_char STR_CONFIRMDELETE[]; #endif -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) || defined(PCBHORUS) extern const pm_char STR_BYTES[]; extern const pm_char STR_ANTENNAPROBLEM[]; extern const pm_char STR_MODULE[]; diff --git a/radio/src/translations/en.h.txt b/radio/src/translations/en.h.txt index 4936d8d44..a7084a450 100644 --- a/radio/src/translations/en.h.txt +++ b/radio/src/translations/en.h.txt @@ -129,7 +129,9 @@ #define LEN_RETA123 "\001" -#if defined(PCBTARANIS) && defined(REV9E) +#if defined(PCBFLAMENCO) + #define TR_RETA123 "RETA123LR" +#elif defined(PCBTARANIS) && defined(REV9E) #define TR_RETA123 "RETA1234LRLR" #elif defined(PCBTARANIS) || defined(REVX) #define TR_RETA123 "RETA123LR" @@ -443,8 +445,16 @@ #define LEN_VSWASHTYPE "\004" #define TR_VSWASHTYPE "---\0""120\0""120X""140\0""90\0" +#if defined(PCBHORUS) +#define LEN_VKEYS "\006" +#define TR_VKEYS "Menu\0 ""Exit\0 ""Enter\0""Up\0 ""Down\0 ""Right\0""Left" +#elif defined(PCBTARANIS) #define LEN_VKEYS "\005" -#define TR_VKEYS TR("Menu\0""Exit\0""Down\0""Up\0 ""Right""Left\0", "Menu\0""Exit\0""Enter""Page\0""Plus\0""Minus") +#define TR_VKEYS "Menu\0""Exit\0""Enter""Page\0""Plus\0""Minus" +#else +#define LEN_VKEYS "\005" +#define TR_VKEYS "Menu\0""Exit\0""Down\0""Up\0 ""Right""Left\0" +#endif #define LEN_VRENCODERS "\003" #define TR_VRENCODERS "REa""REb" @@ -455,7 +465,10 @@ #define TR_STICKS_VSRCRAW TR("Rud\0""Ele\0""Thr\0""Ail\0", "\307Rud""\307Ele""\307Thr""\307Ail") #define TR_TRIMS_VSRCRAW TR("TrmR""TrmE""TrmT""TrmA", "\313Rud""\313Ele""\313Thr""\313Ail") -#if defined(PCBTARANIS) && defined(REV9E) +#if defined(PCBFLAMENCO) + #define TR_POTS_VSRCRAW "SD\0 ""LS\0 ""RS\0 " + #define TR_SW_VSRCRAW "SA\0 ""SB\0 ""SC\0 ""SE\0 ""SF\0 " +#elif defined(PCBTARANIS) && defined(REV9E) #define TR_POTS_VSRCRAW "\310F1\0""\310F2\0""\310F3\0""\310F4\0""\311S1\0""\311S2\0""\311LS\0""\311RS\0" #define TR_SW_VSRCRAW "\312SA\0""\312SB\0""\312SC\0""\312SD\0""\312SE\0""\312SF\0""\312SG\0""\312SH\0""\312SI\0""\312SJ\0""\312SK\0""\312SL\0""\312SM\0""\312SN\0""\312SO\0""\312SP\0""\312SQ\0""\312SR\0" #elif defined(PCBTARANIS) @@ -486,13 +499,17 @@ #define TR_ROTENC_SWITCHES #endif -#if !defined(PCBTARANIS) +#if defined(PCBFLAMENCO) + #define TR_PHYS_SWITCHES "SA\300""SA-""SA\301""SB\300""SB\301""SC1""SC2""SC3""SC4""SC5""SC6""SE\300""SE\301""SF\300""SF-""SF\301" +#elif !defined(PCBTARANIS) #define TR_PHYS_SWITCHES "THR""RUD""ELE""AIL""GEA""TRN" #endif #define TR_ON_ONE_SWITCHES "ON\0""One" -#if defined(PCBTARANIS) +#if defined(PCBFLAMENCO) + #define TR_VSWITCHES "---" TR_PHYS_SWITCHES TR_TRIMS_SWITCHES TR_ROTENC_SWITCHES TR_LOGICALSW "ON\0""One" +#elif defined(PCBTARANIS) // only special switches here #define TR_VSWITCHES "---" TR_TRIMS_SWITCHES TR_ON_ONE_SWITCHES #else @@ -546,8 +563,8 @@ // ZERO TERMINATED STRINGS #if defined(COLORLCD) - #define INDENT "\007" - #define LEN_INDENT 1 + #define INDENT " " + #define LEN_INDENT 3 #define INDENT_WIDTH 12 #define BREAKSPACE "\036" #else @@ -557,7 +574,7 @@ #define BREAKSPACE " " #endif -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBFLAMENCO) #define TR_ENTER "[ENTER]" #else #define TR_ENTER "[MENU]" @@ -565,7 +582,9 @@ #define TR_EXIT "[EXIT]" -#if defined(PCBTARANIS) +#if defined(PCBFLAMENCO) + #define TR_POPUPS TR_EXIT "\010" TR_ENTER +#elif defined(PCBTARANIS) #define TR_POPUPS TR_EXIT "\010" "\010" "\010" "\010" TR_ENTER #else #define TR_POPUPS TR_ENTER "\010" TR_EXIT @@ -1031,7 +1050,11 @@ #define TR_ABOUT_MARTIN_1 "Martin Hotar" #define TR_ABOUT_MARTIN_2 "Graphics designer" -#if defined(PCBTARANIS) +#if defined(PCBFLAMENCO) + #define TR_ABOUT_HARDWARE_1 "XXX" + #define TR_ABOUT_HARDWARE_2 "Hardware designer/producer" + #define TR_ABOUT_HARDWARE_3 "" +#elif defined(PCBTARANIS) || defined(PCBHORUS) #define TR_ABOUT_HARDWARE_1 "FrSky" #define TR_ABOUT_HARDWARE_2 "Hardware designer/producer" #define TR_ABOUT_HARDWARE_3 "Firmware contributor"