mirror of
https://github.com/opentx/opentx.git
synced 2025-07-24 08:45:24 +03:00
Backup before extended trims function merge
This commit is contained in:
parent
4788ea632e
commit
f0fca34b7e
53 changed files with 18727 additions and 0 deletions
850
src/Makefile
Normal file
850
src/Makefile
Normal file
|
@ -0,0 +1,850 @@
|
|||
# !!!! BETA Makefile !!!!
|
||||
# !!!! Use at own risk !!!!
|
||||
#----------------------------------------------------------------------------
|
||||
# On command line:
|
||||
#
|
||||
# make all = Make software.
|
||||
#
|
||||
# make clean = Clean out built project files.
|
||||
#
|
||||
# make coff = Convert ELF to AVR COFF.
|
||||
#
|
||||
# make extcoff = Convert ELF to AVR Extended COFF.
|
||||
#
|
||||
# make program = Download the hex file to the device, using avrdude.
|
||||
# Please customize the avrdude settings below first!
|
||||
#
|
||||
# make debug = Start either simulavr or avarice as specified for debugging,
|
||||
# with avr-gdb or avr-insight as the front end for debugging.
|
||||
#
|
||||
# make filename.s = Just compile filename.c into the assembler code only.
|
||||
#
|
||||
# make filename.i = Create a preprocessed source file for use in submitting
|
||||
# bug reports to the GCC project.
|
||||
#
|
||||
# To rebuild project do "make clean" then "make all".
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
#----------- BUILD OPTIONS ---------------------------
|
||||
|
||||
#gruvin: PCB version -- OVERRIDES the following settings if not STD
|
||||
# Values: STD, V3, V4
|
||||
PCB = V3
|
||||
|
||||
# Following options for PCB=STD only (ignored otherwise) ...
|
||||
|
||||
# Enable JETI-Telemetry or FrSky Telemetry reception on UART0
|
||||
# For this option you need to modify your hardware!
|
||||
# More information at [insertURLhere]
|
||||
# Values = STD, JETI, FRSKY
|
||||
EXT = FRSKY
|
||||
|
||||
# Enable heli menu
|
||||
# Values = YES, NO
|
||||
HELI = NO
|
||||
|
||||
# Enable templates menu
|
||||
# Values = YES, NO
|
||||
TEMPLATES = YES
|
||||
|
||||
# gruvin: BEEPER. Values = BUZZER, BUZZER_MOD or SPEAKER
|
||||
# (without a mod, BUZZER can make PPM jack output switch from output to input at random)
|
||||
BEEPER = SPEAKER
|
||||
|
||||
# gruvin: Legacy support freeing of USART1 TX/RX pins [DEPRECATED]
|
||||
# OPTIONS STD or FREED
|
||||
USART1 = FREED
|
||||
|
||||
# gruvin: PCM-in circuit mod for JR/Spektrum (and others) compatability
|
||||
# Values = STD, MOD1
|
||||
PPMIN = STD
|
||||
|
||||
BATT voltage algorithm. Values = BANDGAP, UNSTABLE_BANDGAP
|
||||
BATT = BANDGAP
|
||||
|
||||
# Decimals display in the main view (PPM calibration,
|
||||
# Values = YES, NO
|
||||
DECIMALS = NO
|
||||
|
||||
# TRANSLATIONS from previous EEPROM formats
|
||||
# Values = YES, NO
|
||||
TRANSLATIONS = YES
|
||||
|
||||
#------- END BUILD OPTIONS ---------------------------
|
||||
|
||||
# MCU name
|
||||
ifeq ($(PCB), STD)
|
||||
MCU = atmega64
|
||||
endif
|
||||
ifeq ($(PCB), V3)
|
||||
MCU = atmega2561
|
||||
endif
|
||||
ifeq ($(PCB), V4)
|
||||
MCU = atmega2560
|
||||
endif
|
||||
|
||||
# Processor frequency.
|
||||
F_CPU = 16000000
|
||||
|
||||
# Output format. (can be srec, ihex, binary)
|
||||
FORMAT = ihex
|
||||
|
||||
# Target file name (without extension).
|
||||
TARGET = gruvin9x
|
||||
|
||||
# Object files directory
|
||||
OBJDIR = obj
|
||||
|
||||
# List C++ source files here. (C dependencies are automatically generated.)
|
||||
CPPSRC = gruvin9x.cpp stamp.cpp menus.cpp model_menus.cpp general_menus.cpp main_views.cpp statistics_views.cpp pers.cpp file.cpp lcd.cpp drivers.cpp templates.cpp
|
||||
|
||||
ifeq ($(EXT), JETI)
|
||||
CPPSRC += jeti.cpp
|
||||
endif
|
||||
|
||||
ifeq ($(EXT), FRSKY)
|
||||
CPPSRC += frsky.cpp
|
||||
endif
|
||||
|
||||
# Disk IO support (PCB V2+ only)
|
||||
ifneq ($(PCB), STD)
|
||||
CPPSRC += time.cpp
|
||||
CPPSRC += rtc.cpp
|
||||
CPPSRC += ff.cpp
|
||||
CPPSRC += diskio.cpp
|
||||
endif
|
||||
|
||||
# List Assembler source files here.
|
||||
# Make them always end in a capital .S. Files ending in a lowercase .s
|
||||
# will not be considered source files but generated files (assembler
|
||||
# output from the compiler), and will be deleted upon "make clean"!
|
||||
# Even though the DOS/Win* filesystem matches both .s and .S the same,
|
||||
# it will preserve the spelling of the filenames, and gcc itself does
|
||||
# care about how the name is spelled on its command-line.
|
||||
ASRC =
|
||||
|
||||
|
||||
# Optimization level, can be [0, 1, 2, 3, s].
|
||||
# 0 = turn off optimization. s = optimize for size.
|
||||
# (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
|
||||
OPT = s
|
||||
|
||||
|
||||
# Debugging format.
|
||||
# Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs.
|
||||
# AVR Studio 4.10 requires dwarf-2.
|
||||
# AVR [Extended] COFF format requires stabs, plus an avr-objcopy run.
|
||||
DEBUG = dwarf-2
|
||||
|
||||
|
||||
# List any extra directories to look for include files here.
|
||||
# Each directory must be seperated by a space.
|
||||
# Use forward slashes for directory separators.
|
||||
# For a directory that has spaces, enclose it in quotes.
|
||||
EXTRAINCDIRS =
|
||||
|
||||
|
||||
# Compiler flag to set the C Standard level.
|
||||
# c89 = "ANSI" C
|
||||
# gnu89 = c89 plus GCC extensions
|
||||
# c99 = ISO C99 standard (not yet fully implemented)
|
||||
# gnu99 = c99 plus GCC extensions
|
||||
CSTANDARD = -std=gnu99
|
||||
|
||||
|
||||
# Place -D or -U options here for C sources
|
||||
CDEFS = -DF_CPU=$(F_CPU)UL
|
||||
|
||||
|
||||
# Place -D or -U options here for C++ sources
|
||||
CPPDEFS = -DF_CPU=$(F_CPU)UL
|
||||
#CPPDEFS += -D__STDC_LIMIT_MACROS
|
||||
#CPPDEFS += -D__STDC_CONSTANT_MACROS
|
||||
|
||||
# NOTE: PCB version now overrides all the earlier individual settings
|
||||
# These individual settings work only for PCB=STD
|
||||
|
||||
ifeq ($(PCB), STD)
|
||||
# STD PCB, so ...
|
||||
|
||||
CPPDEFS += -DPCBSTD
|
||||
|
||||
# If JETI-Support is enabled
|
||||
ifeq ($(EXT), JETI)
|
||||
CPPDEFS += -DJETI
|
||||
endif
|
||||
|
||||
# If FRSKY-Support is enabled
|
||||
ifeq ($(EXT), FRSKY)
|
||||
CPPDEFS += -DFRSKY
|
||||
endif
|
||||
|
||||
# gruvin: If buzzer speaker replacment supported
|
||||
ifeq ($(BEEPER), SPEAKER)
|
||||
CPPDEFS += -DBEEPSPKR
|
||||
endif
|
||||
|
||||
# If buzzer modified (no interference with PPM jack)
|
||||
ifeq ($(BEEPER), BUZZER_MOD)
|
||||
CPPDEFS += -DBUZZER_MOD
|
||||
endif
|
||||
|
||||
# If BandGap is not rock solid
|
||||
ifeq ($(BATT), UNSTABLE_BANDGAP)
|
||||
CPPDEFS += -DBATT_UNSTABLE_BANDGAP
|
||||
endif
|
||||
|
||||
# gruvin: Legacy support for hardware mod freeing USART1 [DEPRECATED]
|
||||
ifeq ($(USART1), FREED)
|
||||
CPPDEFS += -DUSART1FREED
|
||||
endif
|
||||
|
||||
# gruvin: PCM-in circuit mod for JR/Spektrum (and others) compatability
|
||||
ifeq ($(PPMIN), MOD1)
|
||||
CPPDEFS += -DPPMIN_MOD1
|
||||
endif
|
||||
|
||||
else
|
||||
# not PCB=STD, so ...
|
||||
ifeq ($(PCB), V3)
|
||||
CPPDEFS += -DPCBV3 -DFRSKY -DBEEPSPKR
|
||||
endif
|
||||
ifeq ($(PCB), V4)
|
||||
CPPDEFS += -DPCBV4 -DFRSKY -DBEEPSPKR
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
### Global Build-Option Directives ###
|
||||
|
||||
ifeq ($(DECIMALS), YES)
|
||||
CPPDEFS += -DDECIMALS_DISPLAYED
|
||||
endif
|
||||
|
||||
ifeq ($(TRANSLATIONS), YES)
|
||||
CPPDEFS += -DTRANSLATIONS
|
||||
endif
|
||||
|
||||
ifeq ($(HELI), YES)
|
||||
CPPDEFS += -DHELI
|
||||
endif
|
||||
|
||||
ifeq ($(TEMPLATES), YES)
|
||||
CPPDEFS += -DTEMPLATES
|
||||
endif
|
||||
|
||||
|
||||
#---------------- Compiler Options C ----------------
|
||||
# -g*: generate debugging information
|
||||
# -O*: optimization level
|
||||
# -f...: tuning, see GCC manual and avr-libc documentation
|
||||
# -Wall...: warning level
|
||||
# -Wa,...: tell GCC to pass this to the assembler.
|
||||
# -adhlns...: create assembler listing
|
||||
CFLAGS = -g$(DEBUG)
|
||||
CFLAGS += $(CDEFS)
|
||||
CFLAGS += -O$(OPT)
|
||||
#CFLAGS += -mint8
|
||||
#CFLAGS += -mshort-calls
|
||||
CFLAGS += -funsigned-char
|
||||
CFLAGS += -funsigned-bitfields
|
||||
CFLAGS += -fpack-struct
|
||||
CFLAGS += -fshort-enums
|
||||
#CFLAGS += -fno-unit-at-a-time
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wstrict-prototypes
|
||||
CFLAGS += -Wundef
|
||||
#CFLAGS += -Wunreachable-code
|
||||
#CFLAGS += -Wsign-compare
|
||||
CFLAGS += -Wa,-adhlns=$(<:%.c=$(OBJDIR)/%.lst)
|
||||
CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
|
||||
CFLAGS += $(CSTANDARD)
|
||||
|
||||
CFLAGS+= --combine -fwhole-program
|
||||
|
||||
|
||||
#---------------- Compiler Options C++ ----------------
|
||||
# -g*: generate debugging information
|
||||
# -O*: optimization level
|
||||
# -f...: tuning, see GCC manual and avr-libc documentation
|
||||
# -Wall...: warning level
|
||||
# -Wa,...: tell GCC to pass this to the assembler.
|
||||
# -adhlns...: create assembler listing
|
||||
CPPFLAGS = -g$(DEBUG)
|
||||
CPPFLAGS += $(CPPDEFS)
|
||||
CPPFLAGS += -O$(OPT)
|
||||
#CPPFLAGS += -mint8
|
||||
#CPPFLAGS += -mshort-calls
|
||||
#CPPFLAGS += -funsigned-char
|
||||
#CPPFLAGS += -funsigned-bitfields
|
||||
#CPPFLAGS += -fpack-struct
|
||||
#CPPFLAGS += -fshort-enums
|
||||
#CPPFLAGS += -fno-exceptions
|
||||
#CPPFLAGS += -fno-unit-at-a-time
|
||||
#CPPFLAGS += -fno-inline-small-functions
|
||||
CPPFLAGS += -Wall
|
||||
CPPFLAGS += -Wno-strict-aliasing
|
||||
#CPPFLAGS += -Wstrict-prototypes
|
||||
#CFLAGS += -Wundef
|
||||
#CPPFLAGS += -Wunreachable-code
|
||||
#CPPFLAGS += -Wsign-compare
|
||||
#CPPFLAGS += -Wa,-adhlns=$(<:%.cpp=$(OBJDIR)/%.lst)
|
||||
CPPFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
|
||||
#CPPFLAGS += $(CSTANDARD)
|
||||
|
||||
|
||||
|
||||
#---------------- Assembler Options ----------------
|
||||
# -Wa,...: tell GCC to pass this to the assembler.
|
||||
# -ahlms: create listing
|
||||
# -gstabs: have the assembler create line number information; note that
|
||||
# for use in COFF files, additional information about filenames
|
||||
# and function names needs to be present in the assembler source
|
||||
# files -- see avr-libc docs [FIXME: not yet described there]
|
||||
ASFLAGS = -Wa,-adhlns=$(<:%.S=$(OBJDIR)/%.lst),-gstabs
|
||||
|
||||
|
||||
#---------------- Library Options ----------------
|
||||
# Minimalistic printf version
|
||||
PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min
|
||||
|
||||
# Floating point printf version (requires MATH_LIB = -lm below)
|
||||
PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt
|
||||
|
||||
# If this is left blank, then it will use the Standard printf version.
|
||||
PRINTF_LIB =
|
||||
#PRINTF_LIB = $(PRINTF_LIB_MIN)
|
||||
#PRINTF_LIB = $(PRINTF_LIB_FLOAT)
|
||||
|
||||
|
||||
# Minimalistic scanf version
|
||||
SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min
|
||||
|
||||
# Floating point + %[ scanf version (requires MATH_LIB = -lm below)
|
||||
SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt
|
||||
|
||||
# If this is left blank, then it will use the Standard scanf version.
|
||||
SCANF_LIB =
|
||||
#SCANF_LIB = $(SCANF_LIB_MIN)
|
||||
#SCANF_LIB = $(SCANF_LIB_FLOAT)
|
||||
|
||||
|
||||
MATH_LIB = -lm
|
||||
|
||||
|
||||
|
||||
#---------------- External Memory Options ----------------
|
||||
|
||||
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
|
||||
# used for variables (.data/.bss) and heap (malloc()).
|
||||
#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
|
||||
|
||||
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
|
||||
# only used for heap (malloc()).
|
||||
#EXTMEMOPTS = -Wl,--defsym=__heap_start=0x801100,--defsym=__heap_end=0x80ffff
|
||||
|
||||
EXTMEMOPTS =
|
||||
|
||||
|
||||
|
||||
#---------------- Linker Options ----------------
|
||||
# -Wl,...: tell GCC to pass this to linker.
|
||||
# -Map: create map file
|
||||
# --cref: add cross reference to map file
|
||||
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
|
||||
LDFLAGS += $(EXTMEMOPTS)
|
||||
LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
|
||||
#LDFLAGS += -T linker_script.x
|
||||
|
||||
|
||||
|
||||
#---------------- Programming Options (avrdude) ----------------
|
||||
|
||||
# Programming hardware: alf avr910 avrisp bascom bsd
|
||||
# dt006 pavr picoweb pony-stk200 sp12 stk200 stk500
|
||||
#
|
||||
# Type: avrdude -c ?
|
||||
# to get a full listing.
|
||||
#
|
||||
AVRDUDE_PROGRAMMER = usbtiny
|
||||
|
||||
|
||||
# com1 = serial port. Use lpt1 to connect to parallel port.
|
||||
AVRDUDE_PORT = /dev/ttyUSB01
|
||||
|
||||
AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex:a
|
||||
AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).bin:a
|
||||
AVRDUDE_READ_FLASH = -U flash:r:$(TARGET).hex:r
|
||||
AVRDUDE_READ_EEPROM = -U eeprom:r:$(TARGET).bin:r
|
||||
|
||||
|
||||
|
||||
# Uncomment the following if you want avrdude's erase cycle counter.
|
||||
# Note that this counter needs to be initialized first using -Yn,
|
||||
# see avrdude manual.
|
||||
#AVRDUDE_ERASE_COUNTER = -y
|
||||
|
||||
# Uncomment the following if you do /not/ wish a verification to be
|
||||
# performed after programming the device.
|
||||
AVRDUDE_NO_VERIFY = -V
|
||||
|
||||
# Increase verbosity level. Please use this when submitting bug
|
||||
# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude>
|
||||
# to submit bug reports.
|
||||
#AVRDUDE_VERBOSE = -v -v
|
||||
|
||||
#AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
|
||||
AVRDUDE_FLAGS = -B 1 -p $(MCU) -c $(AVRDUDE_PROGRAMMER)
|
||||
AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY)
|
||||
AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE)
|
||||
AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER)
|
||||
|
||||
|
||||
|
||||
#---------------- Debugging Options ----------------
|
||||
|
||||
# For simulavr only - target MCU frequency.
|
||||
DEBUG_MFREQ = $(F_CPU)
|
||||
|
||||
# Set the DEBUG_UI to either gdb or insight.
|
||||
DEBUG_UI = gdb
|
||||
# DEBUG_UI = insight
|
||||
|
||||
# Set the debugging back-end to either avarice, simulavr.
|
||||
#DEBUG_BACKEND = avarice
|
||||
DEBUG_BACKEND = simulavr
|
||||
|
||||
# GDB Init Filename.
|
||||
GDBINIT_FILE = __avr_gdbinit
|
||||
|
||||
# When using avarice settings for the JTAG
|
||||
JTAG_DEV = /dev/com1
|
||||
|
||||
# Debugging port used to communicate between GDB / avarice / simulavr.
|
||||
DEBUG_PORT = 4242
|
||||
|
||||
# Debugging host used to communicate between GDB / avarice / simulavr, normally
|
||||
# just set to localhost unless doing some sort of crazy debugging when
|
||||
# avarice is running on a different computer.
|
||||
DEBUG_HOST = localhost
|
||||
|
||||
|
||||
|
||||
#============================================================================
|
||||
|
||||
|
||||
# Define programs and commands.
|
||||
SHELL = sh
|
||||
CC = avr-gcc
|
||||
OBJCOPY = avr-objcopy
|
||||
OBJDUMP = avr-objdump
|
||||
SIZE = avr-size
|
||||
NM = avr-nm
|
||||
AVRDUDE = avrdude
|
||||
REMOVE = rm -f
|
||||
REMOVEDIR = rm -rf
|
||||
COPY = cp
|
||||
WINSHELL = cmd
|
||||
|
||||
# th9x/gruvin9x-specific
|
||||
XBM2LBM = ruby ../util/xbm2lbm.rb
|
||||
AREV = $(shell sh -c "cat .svn/entries | sed -n '4p'")
|
||||
REV = $(shell echo $$(( $(AREV) + 1 )))
|
||||
|
||||
|
||||
# Define Messages
|
||||
# English
|
||||
MSG_ERRORS_NONE = Errors: none
|
||||
MSG_BEGIN = -------- begin --------
|
||||
MSG_END = -------- end --------
|
||||
MSG_SIZE_BEFORE = Size before:
|
||||
MSG_SIZE_AFTER = Size after:
|
||||
MSG_COFF = Converting to AVR COFF:
|
||||
MSG_EXTENDED_COFF = Converting to AVR Extended COFF:
|
||||
MSG_FLASH = Creating load file for Flash:
|
||||
MSG_EEPROM = Creating load file for EEPROM:
|
||||
MSG_EXTENDED_LISTING = Creating Extended Listing:
|
||||
MSG_SYMBOL_TABLE = Creating Symbol Table:
|
||||
MSG_LINKING = Linking:
|
||||
MSG_COMPILING = Compiling C:
|
||||
MSG_COMPILING_CPP = Compiling C++:
|
||||
MSG_ASSEMBLING = Assembling:
|
||||
MSG_CLEANING = Cleaning project:
|
||||
MSG_CREATING_LIBRARY = Creating library:
|
||||
|
||||
|
||||
|
||||
|
||||
# Define all object files.
|
||||
OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o)
|
||||
|
||||
# Define all listing files.
|
||||
LST = $(SRC:%.c=$(OBJDIR)/%.lst) $(CPPSRC:%.cpp=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst)
|
||||
|
||||
|
||||
# Compiler flags to generate dependency files.
|
||||
GENDEPFLAGS = -MD -MP -MF .dep/$(@F).d
|
||||
|
||||
|
||||
# Combine all necessary flags and optional flags.
|
||||
# Add target processor to flags.
|
||||
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS)
|
||||
ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS)
|
||||
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
|
||||
|
||||
SUB_VER = ${shell sh -c "grep \"SUB_VERS\" gruvin9x.h | cut -d\ -f3 | egrep -o \"[[:digit:]]\""}
|
||||
ABUILD_NUM = ${shell sh -c "grep \"BUILD_NUM\" stamp-gruvin9x.h | egrep -o \"[[:digit:]]+\""}
|
||||
BUILD_NUM = $(shell echo $$(( $(ABUILD_NUM) + 1 )))
|
||||
BUILD_DIR = $(shell pwd | awk -F'/' '{print $$((NF-1))}')
|
||||
ifeq "$(USER)" "bryan"
|
||||
THEUSER=gruvin
|
||||
else
|
||||
THEUSER=$(USER)
|
||||
endif
|
||||
|
||||
# Default target.
|
||||
all: begin gccversion sizebefore build sizeafter end
|
||||
|
||||
# Change the build target to build a HEX file or a library.
|
||||
build: stamp font.lbm font_dblsize.lbm sticks.lbm s9xsplash.lbm elf hex eep lss sym
|
||||
#build: lib
|
||||
|
||||
|
||||
elf: $(TARGET).elf
|
||||
hex: $(TARGET).hex
|
||||
eep: $(TARGET).eep
|
||||
lss: $(TARGET).lss
|
||||
sym: $(TARGET).sym
|
||||
LIBNAME=lib$(TARGET).a
|
||||
lib: $(LIBNAME)
|
||||
|
||||
|
||||
# Build stamp-file
|
||||
stamp:
|
||||
@echo
|
||||
@echo "Generate Version-stamp:"
|
||||
@echo "//Automatically generated file (Makefile) - do not edit" > stamp-gruvin9x.h
|
||||
@echo "#define DATE_STR \"`date +%Y-%m-%d`\"" >> stamp-gruvin9x.h
|
||||
@echo "#define TIME_STR \"`date +%H:%I:%S`\"" >> stamp-gruvin9x.h
|
||||
@echo "#define TAG_VERS $(SUB_VER)-$(THEUSER)" >> stamp-gruvin9x.h
|
||||
@echo "#define SVN_VERS \"$(BUILD_DIR)-r$(REV)\"" >> stamp-gruvin9x.h
|
||||
@echo "#define BUILD_NUM $(BUILD_NUM)" >> stamp-gruvin9x.h
|
||||
@cat stamp-gruvin9x.h
|
||||
|
||||
font.lbm: font_6x1.xbm
|
||||
@echo
|
||||
@echo "Convert font from xbm to lbm:"
|
||||
$(XBM2LBM) $<
|
||||
|
||||
font_dblsize.lbm: font_dblsize.xbm
|
||||
@echo
|
||||
@echo "Convert font from xbm to lbm:"
|
||||
$(XBM2LBM) $<
|
||||
|
||||
sticks.lbm: sticks_4x1.xbm
|
||||
@echo
|
||||
@echo "Convert font from xbm to lbm:"
|
||||
$(XBM2LBM) $<
|
||||
|
||||
s9xsplash.lbm: s9xsplash.xbm
|
||||
@echo
|
||||
@echo "Convert font from xbm to lbm:"
|
||||
$(XBM2LBM) $<
|
||||
|
||||
# Eye candy.
|
||||
# AVR Studio 3.x does not check make's exit code but relies on
|
||||
# the following magic strings to be generated by the compile job.
|
||||
|
||||
begin:
|
||||
@echo
|
||||
@echo $(MSG_BEGIN)
|
||||
|
||||
end:
|
||||
@echo $(MSG_END)
|
||||
@echo
|
||||
|
||||
|
||||
|
||||
# Display size of file.
|
||||
HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex
|
||||
ELFSIZE = $(SIZE) --mcu=$(MCU) --format=avr $(TARGET).elf
|
||||
AVRMEM = avr-mem.sh $(TARGET).elf $(MCU)
|
||||
|
||||
sizebefore:
|
||||
@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \
|
||||
$(AVRMEM) 2>/dev/null; echo; fi
|
||||
|
||||
sizeafter:
|
||||
@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \
|
||||
$(AVRMEM) 2>/dev/null; echo; fi
|
||||
|
||||
|
||||
|
||||
# Display compiler version information.
|
||||
gccversion :
|
||||
@$(CC) --version
|
||||
|
||||
|
||||
|
||||
# Program the device.
|
||||
wflash: $(TARGET).hex
|
||||
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH)
|
||||
|
||||
weeprom: $(TARGET).bin
|
||||
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_EEPROM)
|
||||
|
||||
# Write flash and eeprom
|
||||
wfe: $(TARGET).hex
|
||||
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH)
|
||||
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_EEPROM)
|
||||
|
||||
rflash: $(TARGET).hex
|
||||
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_READ_FLASH)
|
||||
|
||||
reeprom: $(TARGET).bin
|
||||
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_READ_EEPROM)
|
||||
|
||||
|
||||
# Generate avr-gdb config/init file which does the following:
|
||||
# define the reset signal, load the target file, connect to target, and set
|
||||
# a breakpoint at main().
|
||||
gdb-config:
|
||||
@$(REMOVE) $(GDBINIT_FILE)
|
||||
@echo define reset >> $(GDBINIT_FILE)
|
||||
@echo SIGNAL SIGHUP >> $(GDBINIT_FILE)
|
||||
@echo end >> $(GDBINIT_FILE)
|
||||
@echo file $(TARGET).elf >> $(GDBINIT_FILE)
|
||||
@echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE)
|
||||
ifeq ($(DEBUG_BACKEND),simulavr)
|
||||
@echo load >> $(GDBINIT_FILE)
|
||||
endif
|
||||
@echo break main >> $(GDBINIT_FILE)
|
||||
|
||||
# gruvin: added extra include and lib paths to get simu working on my Mac
|
||||
FOXINC=-I/usr/local/include/fox-1.6 -I/usr/include/fox-1.6 \
|
||||
-I$(FOXPATH)/include \
|
||||
-I/opt/local/include/fox-1.6
|
||||
FOXLIB=-L/usr/local/lib \
|
||||
-L$(FOXPATH)/src/.libs \
|
||||
-L/opt/local/lib \
|
||||
-lFOX-1.6 \
|
||||
-Wl,-rpath,$(FOXPATH)/src/.libs
|
||||
|
||||
LBITS := $(shell getconf LONG_BIT)
|
||||
ifeq ($(LBITS),64)
|
||||
ARCH=-arch x86_64
|
||||
else
|
||||
ARCH=
|
||||
endif
|
||||
|
||||
simu: $(CPPSRC) Makefile simu.cpp $(CPPSRC) simpgmspace.cpp *.h *.lbm eeprom.bin
|
||||
g++ simu.cpp $(CPPFLAGS) $(CPPSRC) simpgmspace.cpp $(ARCH) -o simu $(FOXINC) $(FOXLIB) -MD -DSIMU
|
||||
|
||||
eeprom.bin:
|
||||
dd if=/dev/zero of=$@ bs=1 count=2048
|
||||
|
||||
debug: gdb-config $(TARGET).elf
|
||||
ifeq ($(DEBUG_BACKEND),avarice)
|
||||
@echo Starting AVaRICE - Press enter when "waiting to connect" message displays.
|
||||
@$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \
|
||||
$(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT)
|
||||
@$(WINSHELL) /c pause
|
||||
else
|
||||
@$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \
|
||||
$(DEBUG_MFREQ) --port $(DEBUG_PORT)
|
||||
endif
|
||||
@$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE)
|
||||
|
||||
|
||||
|
||||
|
||||
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
|
||||
COFFCONVERT = $(OBJCOPY) --debugging
|
||||
COFFCONVERT += --change-section-address .data-0x800000
|
||||
COFFCONVERT += --change-section-address .bss-0x800000
|
||||
COFFCONVERT += --change-section-address .noinit-0x800000
|
||||
COFFCONVERT += --change-section-address .eeprom-0x810000
|
||||
|
||||
|
||||
coff: $(TARGET).elf
|
||||
@echo
|
||||
@echo $(MSG_COFF) $(TARGET).cof
|
||||
$(COFFCONVERT) -O coff-avr $< $(TARGET).cof
|
||||
|
||||
|
||||
extcoff: $(TARGET).elf
|
||||
@echo
|
||||
@echo $(MSG_EXTENDED_COFF) $(TARGET).cof
|
||||
$(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof
|
||||
|
||||
|
||||
|
||||
# Create final output files (.hex, .eep) from ELF output file.
|
||||
%.hex: %.elf
|
||||
@echo
|
||||
@echo $(MSG_FLASH) $@
|
||||
$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
|
||||
|
||||
%.eep: %.elf
|
||||
@echo
|
||||
@echo $(MSG_EEPROM) $@
|
||||
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
|
||||
--change-section-lma .eeprom=0 -O $(FORMAT) $< $@
|
||||
|
||||
# Create extended listing file from ELF output file.
|
||||
%.lss: %.elf
|
||||
@echo
|
||||
@echo $(MSG_EXTENDED_LISTING) $@
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
# Create a symbol table from ELF output file.
|
||||
%.sym: %.elf
|
||||
@echo
|
||||
@echo $(MSG_SYMBOL_TABLE) $@
|
||||
$(NM) -n $< > $@
|
||||
|
||||
|
||||
|
||||
# Create library from object files.
|
||||
.SECONDARY : $(TARGET).a
|
||||
.PRECIOUS : $(OBJ)
|
||||
%.a: $(OBJ)
|
||||
@echo
|
||||
@echo $(MSG_CREATING_LIBRARY) $@
|
||||
$(AR) $@ $(OBJ)
|
||||
|
||||
|
||||
# Link: create ELF output file from object files.
|
||||
.SECONDARY : $(TARGET).elf
|
||||
.PRECIOUS : $(OBJ)
|
||||
%.elf: $(OBJ)
|
||||
@echo
|
||||
@echo $(MSG_LINKING) $@
|
||||
$(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS)
|
||||
|
||||
|
||||
# Compile: create object files from C source files.
|
||||
$(OBJDIR)/%.o : %.c
|
||||
@echo
|
||||
@echo $(MSG_COMPILING) $<
|
||||
$(CC) -c $(ALL_CFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Compile: create object files from C++ source files.
|
||||
$(OBJDIR)/%.o : %.cpp
|
||||
@echo
|
||||
@echo $(MSG_COMPILING_CPP) $<
|
||||
$(CC) -c $(ALL_CPPFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Compile: create assembler files from C source files.
|
||||
%.s : %.c
|
||||
$(CC) -S $(ALL_CFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Compile: create assembler files from C++ source files.
|
||||
%.s : %.cpp
|
||||
$(CC) -S $(ALL_CPPFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Assemble: create object files from assembler source files.
|
||||
$(OBJDIR)/%.o : %.S
|
||||
@echo
|
||||
@echo $(MSG_ASSEMBLING) $<
|
||||
$(CC) -c $(ALL_ASFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Create preprocessed source for use in sending a bug report.
|
||||
%.i : %.c
|
||||
$(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Target: clean project.
|
||||
clean: begin clean_list end
|
||||
|
||||
clean_list :
|
||||
@echo
|
||||
@echo $(MSG_CLEANING)
|
||||
$(REMOVE) simu
|
||||
$(REMOVE) gtests
|
||||
$(REMOVE) gtest.a
|
||||
$(REMOVE) gtest_main.a
|
||||
$(REMOVE) $(TARGET).hex
|
||||
$(REMOVE) $(TARGET).eep
|
||||
$(REMOVE) $(TARGET).cof
|
||||
$(REMOVE) $(TARGET).elf
|
||||
$(REMOVE) $(TARGET).map
|
||||
$(REMOVE) $(TARGET).sym
|
||||
$(REMOVE) $(TARGET).lss
|
||||
$(REMOVEDIR) $(OBJDIR)
|
||||
$(REMOVE) $(SRC:.c=.s)
|
||||
$(REMOVE) *.o
|
||||
$(REMOVE) *.d
|
||||
$(REMOVEDIR) .dep
|
||||
|
||||
|
||||
# Create object files directory
|
||||
$(shell mkdir $(OBJDIR) 2>/dev/null)
|
||||
|
||||
|
||||
# Include the dependency files.
|
||||
-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)
|
||||
|
||||
|
||||
# Listing of phony targets.
|
||||
.PHONY : all begin finish end sizebefore sizeafter gccversion \
|
||||
build elf hex eep lss sym coff extcoff \
|
||||
clean clean_list program debug gdb-config stamp
|
||||
|
||||
|
||||
#### GOOGLE TESTS
|
||||
|
||||
GTEST_DIR = ../gtest-1.6.0/
|
||||
|
||||
# Where to find user code.
|
||||
USER_DIR = ./
|
||||
|
||||
# Flags passed to the preprocessor.
|
||||
CPPFLAGS += -I$(GTEST_DIR)/include
|
||||
|
||||
# Flags passed to the C++ compiler.
|
||||
CXXFLAGS += -g -Wall -Wextra
|
||||
|
||||
# All Google Test headers. Usually you shouldn't change this
|
||||
# definition.
|
||||
GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.h \
|
||||
$(GTEST_DIR)/include/gtest/internal/*.h
|
||||
|
||||
# House-keeping build targets.
|
||||
|
||||
# Builds gtest.a and gtest_main.a.
|
||||
|
||||
# Usually you shouldn't tweak such internal variables, indicated by a
|
||||
# trailing _.
|
||||
GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS)
|
||||
|
||||
# For simplicity and to avoid depending on Google Test's
|
||||
# implementation details, the dependencies specified below are
|
||||
# conservative and not optimized. This is fine as Google Test
|
||||
# compiles fast and for ordinary users its source rarely changes.
|
||||
gtest-all.o : $(GTEST_SRCS_)
|
||||
$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
|
||||
$(GTEST_DIR)/src/gtest-all.cc
|
||||
|
||||
gtest_main.o : $(GTEST_SRCS_)
|
||||
$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
|
||||
$(GTEST_DIR)/src/gtest_main.cc
|
||||
|
||||
gtest.a : gtest-all.o
|
||||
$(AR) $(ARFLAGS) $@ $^
|
||||
|
||||
gtest_main.a : gtest-all.o gtest_main.o
|
||||
$(AR) $(ARFLAGS) $@ $^
|
||||
|
||||
# Builds a sample test. A test should link with either gtest.a or
|
||||
# gtest_main.a, depending on whether it defines its own main()
|
||||
# function.
|
||||
|
||||
gtests: $(CPPSRC) gtests.cpp simpgmspace.cpp gtest_main.a
|
||||
g++ $(CPPSRC) gtests.cpp simpgmspace.cpp $(CPPFLAGS) -I$(GTEST_DIR) $(ARCH) -o gtests -lpthread -MD -DSIMU gtest_main.a
|
||||
|
62
src/diskio-test.cpp
Normal file
62
src/diskio-test.cpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
I put this in place of the code in the FRSKY first menu page, just as a quick test
|
||||
*/
|
||||
// DISK_IO DEBUG -- XXX DELETE ME
|
||||
|
||||
static uint8_t onceonly = 0;
|
||||
static FRESULT f_err_code;
|
||||
static FATFS FATFS_Obj;
|
||||
static uint8_t result = 0;
|
||||
static TCHAR sBuffer[100] = {0};
|
||||
static TCHAR *myStr = sBuffer;
|
||||
|
||||
if (!onceonly)
|
||||
{
|
||||
// First, let's try to set the RTC date/time
|
||||
RTC rtc;
|
||||
|
||||
rtc.year = 2011;
|
||||
rtc.month = 6;
|
||||
rtc.mday = 23;
|
||||
rtc.wday = 5;
|
||||
rtc.hour = 21;
|
||||
rtc.min = 53;
|
||||
rtc.sec = 0;
|
||||
|
||||
// rtc_settime(&rtc);
|
||||
// IT WORKED! And battery back-up for the RTC chip is working also.
|
||||
//////////////////////
|
||||
|
||||
f_err_code = f_mount(0, &FATFS_Obj);
|
||||
FIL fil_obj;
|
||||
|
||||
// atempt creating and writing to a new file
|
||||
result = f_open(&fil_obj, "/foo.txt", FA_CREATE_ALWAYS | FA_WRITE);
|
||||
f_printf(&fil_obj, "gruvin9x created this file! Yay!\n");
|
||||
f_close(&fil_obj);
|
||||
|
||||
// That worked! Now test reading a line from another file.
|
||||
result = f_open(&fil_obj, "/foo.txt", FA_READ);
|
||||
myStr = f_gets(sBuffer, 100, &fil_obj);
|
||||
|
||||
f_close(&fil_obj);
|
||||
|
||||
onceonly = 1;
|
||||
}
|
||||
|
||||
lcd_outdezAtt(5*FW, 2*FH, f_err_code, 0);
|
||||
lcd_outdezAtt(5*FW, 3*FH, result, 0);
|
||||
lcd_outdezAtt(5*FW, 4*FH, strlen(myStr), 0);
|
||||
lcd_outdezAtt(5*FW, 5*FH, myStr[0], 0);
|
||||
|
||||
// can't use lcd_puts... becasue it specifies prog_char mem space, not SRAM
|
||||
uint8_t x=0;
|
||||
uint8_t j=6;
|
||||
for (uint8_t i=0; i<strlen(myStr); i++)
|
||||
{
|
||||
if (myStr[i]==0) break;
|
||||
if (myStr[i]!='\n') lcd_putc(x, j*FH, myStr[i]);
|
||||
x+=FW;
|
||||
}
|
||||
|
||||
return;
|
631
src/diskio.cpp
Normal file
631
src/diskio.cpp
Normal file
|
@ -0,0 +1,631 @@
|
|||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
*
|
||||
* gruvin9x is based on code named er9x by
|
||||
* Author - Erez Raviv <erezraviv@gmail.com>, which is in turn
|
||||
* was based on 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* MMCv3/SDv1/SDv2 (in SPI mode) control module (C)ChaN, 2010 */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Only rcvr_spi(), xmit_spi(), disk_timerproc() and some macros */
|
||||
/* are platform dependent. */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#include <avr/io.h>
|
||||
#include "diskio.h"
|
||||
|
||||
|
||||
/* Definitions for MMC/SDC command */
|
||||
#define CMD0 (0) /* GO_IDLE_STATE */
|
||||
#define CMD1 (1) /* SEND_OP_COND (MMC) */
|
||||
#define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */
|
||||
#define CMD8 (8) /* SEND_IF_COND */
|
||||
#define CMD9 (9) /* SEND_CSD */
|
||||
#define CMD10 (10) /* SEND_CID */
|
||||
#define CMD12 (12) /* STOP_TRANSMISSION */
|
||||
#define ACMD13 (0x80+13) /* SD_STATUS (SDC) */
|
||||
#define CMD16 (16) /* SET_BLOCKLEN */
|
||||
#define CMD17 (17) /* READ_SINGLE_BLOCK */
|
||||
#define CMD18 (18) /* READ_MULTIPLE_BLOCK */
|
||||
#define CMD23 (23) /* SET_BLOCK_COUNT (MMC) */
|
||||
#define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */
|
||||
#define CMD24 (24) /* WRITE_BLOCK */
|
||||
#define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */
|
||||
#define CMD55 (55) /* APP_CMD */
|
||||
#define CMD58 (58) /* READ_OCR */
|
||||
|
||||
/* Card type flags (CardType) */
|
||||
#define CT_MMC 0x01 /* MMC ver 3 */
|
||||
#define CT_SD1 0x02 /* SD ver 1 */
|
||||
#define CT_SD2 0x04 /* SD ver 2 */
|
||||
#define CT_SDC (CT_SD1|CT_SD2) /* SD */
|
||||
#define CT_BLOCK 0x08 /* Block addressing */
|
||||
|
||||
/* Port Controls (Platform dependent) */
|
||||
// GCC optimisation should result in a single CBI/SBI instructions here
|
||||
#define CS_LOW() PORTB &= ~0x10 /* MMC CS = L */
|
||||
#define CS_HIGH() PORTB |= 0x10 /* MMC CS = H */
|
||||
|
||||
#define SOCKPORT PINB /* Socket contact port */
|
||||
#define SOCKWP 0x00 // not implemented /* Write protect switch */
|
||||
#define SOCKINS 0x00 // not implemented /* Card detect switch */
|
||||
|
||||
#define FCLK_SLOW() SPCR = 0x52 /* Set slow clock (100k-400k) */
|
||||
#define FCLK_FAST() SPCR = 0x50 /* Set fast clock (depends on the CSD) */
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
|
||||
Module Private Functions
|
||||
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
static volatile
|
||||
DSTATUS Stat = STA_NOINIT; /* Disk status */
|
||||
|
||||
volatile BYTE Timer1, Timer2; /* 100Hz decrement timer */
|
||||
|
||||
static
|
||||
BYTE CardType; /* Card type flags */
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Transmit a byte to MMC via SPI (Platform dependent) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
#define xmit_spi(dat) SPDR=(dat); loop_until_bit_is_set(SPSR,SPIF)
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Receive a byte from MMC via SPI (Platform dependent) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static
|
||||
BYTE rcvr_spi (void)
|
||||
{
|
||||
SPDR = 0xFF;
|
||||
loop_until_bit_is_set(SPSR, SPIF);
|
||||
return SPDR;
|
||||
}
|
||||
|
||||
/* Alternative macro to receive data fast */
|
||||
#define rcvr_spi_m(dst) SPDR=0xFF; loop_until_bit_is_set(SPSR,SPIF); *(dst)=SPDR
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Wait for card ready */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static
|
||||
int wait_ready (void) /* 1:OK, 0:Timeout */
|
||||
{
|
||||
Timer2 = 50; /* Wait for ready in timeout of 500ms (G: now 50x16ms) */
|
||||
rcvr_spi();
|
||||
do
|
||||
if (rcvr_spi() == 0xFF) return 1;
|
||||
while (Timer2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Deselect the card and release SPI bus */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static
|
||||
void deselect (void)
|
||||
{
|
||||
CS_HIGH();
|
||||
rcvr_spi();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Select the card and wait for ready */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static
|
||||
int select (void) /* 1:Successful, 0:Timeout */
|
||||
{
|
||||
CS_LOW();
|
||||
if (!wait_ready()) {
|
||||
deselect();
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Power Control (Platform dependent) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* When the target system does not support socket power control, there */
|
||||
/* is nothing to do in these functions and chk_power always returns 1. */
|
||||
|
||||
static
|
||||
int power_status(void) /* Socket power state: 0=off, 1=on */
|
||||
{
|
||||
return (PORTE & 0x80) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void power_on (void)
|
||||
{
|
||||
// PORTE &= ~0x80; // Socket power on
|
||||
for (Timer1 = 2; Timer1; ); // Wait for 20ms
|
||||
//PORTB = 0b10110101; // Enable drivers
|
||||
//DDRB = 0b11000111;
|
||||
|
||||
SPCR = 0x52; // Enable SPI function in mode 0
|
||||
SPSR = 0x00; // G: was 0x01; // SPI 2x mode
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void power_off (void)
|
||||
{
|
||||
SPCR = 0; /* Disable SPI function */
|
||||
// DDRB = 0b11000000; /* Disable drivers */
|
||||
// PORTB = 0b10110000;
|
||||
|
||||
// PORTE |= 0x80; /* Socket power off */
|
||||
Stat |= STA_NOINIT;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Receive a data packet from MMC */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static
|
||||
int rcvr_datablock (
|
||||
BYTE *buff, /* Data buffer to store received data */
|
||||
UINT btr /* Byte count (must be multiple of 4) */
|
||||
)
|
||||
{
|
||||
BYTE token;
|
||||
|
||||
|
||||
Timer1 = 20;
|
||||
do { /* Wait for data packet in timeout of 200ms */
|
||||
token = rcvr_spi();
|
||||
} while ((token == 0xFF) && Timer1);
|
||||
if(token != 0xFE) return 0; /* If not valid data token, retutn with error */
|
||||
|
||||
do { /* Receive the data block into buffer */
|
||||
rcvr_spi_m(buff++);
|
||||
rcvr_spi_m(buff++);
|
||||
rcvr_spi_m(buff++);
|
||||
rcvr_spi_m(buff++);
|
||||
} while (btr -= 4);
|
||||
rcvr_spi(); /* Discard CRC */
|
||||
rcvr_spi();
|
||||
|
||||
return 1; /* Return with success */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Send a data packet to MMC */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static
|
||||
int xmit_datablock (
|
||||
const BYTE *buff, /* 512 byte data block to be transmitted */
|
||||
BYTE token /* Data/Stop token */
|
||||
)
|
||||
{
|
||||
BYTE resp, wc;
|
||||
|
||||
|
||||
if (!wait_ready()) return 0;
|
||||
|
||||
xmit_spi(token); /* Xmit data token */
|
||||
if (token != 0xFD) { /* Is data token */
|
||||
wc = 0;
|
||||
do { /* Xmit the 512 byte data block to MMC */
|
||||
xmit_spi(*buff++);
|
||||
xmit_spi(*buff++);
|
||||
} while (--wc);
|
||||
xmit_spi(0xFF); /* CRC (Dummy) */
|
||||
xmit_spi(0xFF);
|
||||
resp = rcvr_spi(); /* Reveive data response */
|
||||
if ((resp & 0x1F) != 0x05) /* If not accepted, return with error */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Send a command packet to MMC */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static
|
||||
BYTE send_cmd ( /* Returns R1 resp (bit7==1:Send failed) */
|
||||
BYTE cmd, /* Command index */
|
||||
DWORD arg /* Argument */
|
||||
)
|
||||
{
|
||||
BYTE n, res;
|
||||
|
||||
|
||||
if (cmd & 0x80) { /* ACMD<n> is the command sequense of CMD55-CMD<n> */
|
||||
cmd &= 0x7F;
|
||||
res = send_cmd(CMD55, 0);
|
||||
if (res > 1) return res;
|
||||
}
|
||||
|
||||
/* Select the card and wait for ready */
|
||||
deselect();
|
||||
if (!select()) return 0xFF;
|
||||
|
||||
/* Send command packet */
|
||||
xmit_spi(0x40 | cmd); /* Start + Command index */
|
||||
xmit_spi((BYTE)(arg >> 24)); /* Argument[31..24] */
|
||||
xmit_spi((BYTE)(arg >> 16)); /* Argument[23..16] */
|
||||
xmit_spi((BYTE)(arg >> 8)); /* Argument[15..8] */
|
||||
xmit_spi((BYTE)arg); /* Argument[7..0] */
|
||||
n = 0x01; /* Dummy CRC + Stop */
|
||||
if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) */
|
||||
if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) */
|
||||
xmit_spi(n);
|
||||
|
||||
/* Receive command response */
|
||||
if (cmd == CMD12) rcvr_spi(); /* Skip a stuff byte when stop reading */
|
||||
n = 10; /* Wait for a valid response in timeout of 10 attempts */
|
||||
do
|
||||
res = rcvr_spi();
|
||||
while ((res & 0x80) && --n);
|
||||
|
||||
return res; /* Return with the response value */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
|
||||
Public Functions
|
||||
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Initialize Disk Drive */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DSTATUS disk_initialize (
|
||||
BYTE drv /* Physical drive nmuber (0) */
|
||||
)
|
||||
{
|
||||
BYTE n, cmd, ty, ocr[4];
|
||||
|
||||
|
||||
if (drv) return STA_NOINIT; /* Supports only single drive */
|
||||
if (Stat & STA_NODISK) return Stat; /* No card in the socket */
|
||||
|
||||
power_on(); /* Force socket power on */
|
||||
FCLK_SLOW();
|
||||
for (n = 10; n; n--) rcvr_spi(); /* 80 dummy clocks */
|
||||
|
||||
ty = 0;
|
||||
if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */
|
||||
Timer1 = 100; /* Initialization timeout of 1000 msec */
|
||||
if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2? */
|
||||
for (n = 0; n < 4; n++) ocr[n] = rcvr_spi(); /* Get trailing return value of R7 resp */
|
||||
if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */
|
||||
while (Timer1 && send_cmd(ACMD41, 1UL << 30)); /* Wait for leaving idle state (ACMD41 with HCS bit) */
|
||||
if (Timer1 && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */
|
||||
for (n = 0; n < 4; n++) ocr[n] = rcvr_spi();
|
||||
ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 */
|
||||
}
|
||||
}
|
||||
} else { /* SDv1 or MMCv3 */
|
||||
if (send_cmd(ACMD41, 0) <= 1) {
|
||||
ty = CT_SD1; cmd = ACMD41; /* SDv1 */
|
||||
} else {
|
||||
ty = CT_MMC; cmd = CMD1; /* MMCv3 */
|
||||
}
|
||||
while (Timer1 && send_cmd(cmd, 0)); /* Wait for leaving idle state */
|
||||
if (!Timer1 || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */
|
||||
ty = 0;
|
||||
}
|
||||
}
|
||||
CardType = ty;
|
||||
deselect();
|
||||
|
||||
if (ty) { /* Initialization succeded */
|
||||
Stat &= ~STA_NOINIT; /* Clear STA_NOINIT */
|
||||
FCLK_FAST();
|
||||
} else { /* Initialization failed */
|
||||
power_off();
|
||||
}
|
||||
|
||||
return Stat;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Get Disk Status */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DSTATUS disk_status (
|
||||
BYTE drv /* Physical drive nmuber (0) */
|
||||
)
|
||||
{
|
||||
if (drv) return STA_NOINIT; /* Supports only single drive */
|
||||
return Stat;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Read Sector(s) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DRESULT disk_read (
|
||||
BYTE drv, /* Physical drive nmuber (0) */
|
||||
BYTE *buff, /* Pointer to the data buffer to store read data */
|
||||
DWORD sector, /* Start sector number (LBA) */
|
||||
BYTE count /* Sector count (1..255) */
|
||||
)
|
||||
{
|
||||
if (drv || !count) return RES_PARERR;
|
||||
if (Stat & STA_NOINIT) return RES_NOTRDY;
|
||||
|
||||
if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */
|
||||
|
||||
if (count == 1) { /* Single block read */
|
||||
if ((send_cmd(CMD17, sector) == 0) /* READ_SINGLE_BLOCK */
|
||||
&& rcvr_datablock(buff, 512))
|
||||
count = 0;
|
||||
}
|
||||
else { /* Multiple block read */
|
||||
if (send_cmd(CMD18, sector) == 0) { /* READ_MULTIPLE_BLOCK */
|
||||
do {
|
||||
if (!rcvr_datablock(buff, 512)) break;
|
||||
buff += 512;
|
||||
} while (--count);
|
||||
send_cmd(CMD12, 0); /* STOP_TRANSMISSION */
|
||||
}
|
||||
}
|
||||
deselect();
|
||||
|
||||
return count ? RES_ERROR : RES_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Write Sector(s) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DRESULT disk_write (
|
||||
BYTE drv, /* Physical drive nmuber (0) */
|
||||
const BYTE *buff, /* Pointer to the data to be written */
|
||||
DWORD sector, /* Start sector number (LBA) */
|
||||
BYTE count /* Sector count (1..255) */
|
||||
)
|
||||
{
|
||||
if (drv || !count) return RES_PARERR;
|
||||
if (Stat & STA_NOINIT) return RES_NOTRDY;
|
||||
if (Stat & STA_PROTECT) return RES_WRPRT;
|
||||
|
||||
if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */
|
||||
|
||||
if (count == 1) { /* Single block write */
|
||||
if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */
|
||||
&& xmit_datablock(buff, 0xFE))
|
||||
count = 0;
|
||||
}
|
||||
else { /* Multiple block write */
|
||||
if (CardType & CT_SDC) send_cmd(ACMD23, count);
|
||||
if (send_cmd(CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */
|
||||
do {
|
||||
if (!xmit_datablock(buff, 0xFC)) break;
|
||||
buff += 512;
|
||||
} while (--count);
|
||||
if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
deselect();
|
||||
|
||||
return count ? RES_ERROR : RES_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Miscellaneous Functions */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DRESULT disk_ioctl (
|
||||
BYTE drv, /* Physical drive nmuber (0) */
|
||||
BYTE ctrl, /* Control code */
|
||||
BYTE *buff /* Buffer to send/receive control data */
|
||||
)
|
||||
{
|
||||
DRESULT res;
|
||||
BYTE n, csd[16], *ptr = buff;
|
||||
WORD csize;
|
||||
|
||||
|
||||
if (drv) return RES_PARERR;
|
||||
|
||||
res = RES_ERROR;
|
||||
|
||||
if (ctrl == CTRL_POWER) {
|
||||
switch (ptr[0]) {
|
||||
case 0: /* Sub control code (POWER_OFF) */
|
||||
power_off(); /* Power off */
|
||||
res = RES_OK;
|
||||
break;
|
||||
case 1: /* Sub control code (POWER_GET) */
|
||||
ptr[1] = (BYTE)power_status();
|
||||
res = RES_OK;
|
||||
break;
|
||||
default :
|
||||
res = RES_PARERR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (Stat & STA_NOINIT) return RES_NOTRDY;
|
||||
|
||||
switch (ctrl) {
|
||||
case CTRL_SYNC : /* Make sure that no pending write process. Do not remove this or written sector might not left updated. */
|
||||
if (select()) {
|
||||
deselect();
|
||||
res = RES_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */
|
||||
if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {
|
||||
if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */
|
||||
csize = csd[9] + ((WORD)csd[8] << 8) + 1;
|
||||
*(DWORD*)buff = (DWORD)csize << 10;
|
||||
} else { /* SDC ver 1.XX or MMC*/
|
||||
n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
|
||||
csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;
|
||||
*(DWORD*)buff = (DWORD)csize << (n - 9);
|
||||
}
|
||||
res = RES_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case GET_SECTOR_SIZE : /* Get R/W sector size (WORD) */
|
||||
*(WORD*)buff = 512;
|
||||
res = RES_OK;
|
||||
break;
|
||||
|
||||
case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */
|
||||
if (CardType & CT_SD2) { /* SDv2? */
|
||||
if (send_cmd(ACMD13, 0) == 0) { /* Read SD status */
|
||||
rcvr_spi();
|
||||
if (rcvr_datablock(csd, 16)) { /* Read partial block */
|
||||
for (n = 64 - 16; n; n--) rcvr_spi(); /* Purge trailing data */
|
||||
*(DWORD*)buff = 16UL << (csd[10] >> 4);
|
||||
res = RES_OK;
|
||||
}
|
||||
}
|
||||
} else { /* SDv1 or MMCv3 */
|
||||
if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { /* Read CSD */
|
||||
if (CardType & CT_SD1) { /* SDv1 */
|
||||
*(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1);
|
||||
} else { /* MMCv3 */
|
||||
*(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1);
|
||||
}
|
||||
res = RES_OK;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MMC_GET_TYPE : /* Get card type flags (1 byte) */
|
||||
*ptr = CardType;
|
||||
res = RES_OK;
|
||||
break;
|
||||
|
||||
case MMC_GET_CSD : /* Receive CSD as a data block (16 bytes) */
|
||||
if (send_cmd(CMD9, 0) == 0 /* READ_CSD */
|
||||
&& rcvr_datablock(ptr, 16))
|
||||
res = RES_OK;
|
||||
break;
|
||||
|
||||
case MMC_GET_CID : /* Receive CID as a data block (16 bytes) */
|
||||
if (send_cmd(CMD10, 0) == 0 /* READ_CID */
|
||||
&& rcvr_datablock(ptr, 16))
|
||||
res = RES_OK;
|
||||
break;
|
||||
|
||||
case MMC_GET_OCR : /* Receive OCR as an R3 resp (4 bytes) */
|
||||
if (send_cmd(CMD58, 0) == 0) { /* READ_OCR */
|
||||
for (n = 4; n; n--) *ptr++ = rcvr_spi();
|
||||
res = RES_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case MMC_GET_SDSTAT : /* Receive SD statsu as a data block (64 bytes) */
|
||||
if (send_cmd(ACMD13, 0) == 0) { /* SD_STATUS */
|
||||
rcvr_spi();
|
||||
if (rcvr_datablock(ptr, 64))
|
||||
res = RES_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
res = RES_PARERR;
|
||||
}
|
||||
|
||||
deselect();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Device Timer Interrupt Procedure */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* This function must be called in period of 10ms */
|
||||
|
||||
void disk_timerproc (void)
|
||||
{
|
||||
BYTE s;
|
||||
|
||||
/*
|
||||
n = Timer1; // 100Hz decrement timer
|
||||
if (n) Timer1 = --n;
|
||||
n = Timer2;
|
||||
if (n) Timer2 = --n;
|
||||
*/
|
||||
if (Timer1) Timer1--;
|
||||
if (Timer2) Timer2--;
|
||||
|
||||
s = Stat;
|
||||
|
||||
/* G: Not implemented
|
||||
if (SOCKWP) // Write protected
|
||||
s |= STA_PROTECT;
|
||||
else // Write enabled
|
||||
s &= ~STA_PROTECT;
|
||||
if (SOCKINS) // Card inserted
|
||||
s &= ~STA_NODISK;
|
||||
else // Socket empty
|
||||
s |= (STA_NODISK | STA_NOINIT);
|
||||
*/
|
||||
s &= ~STA_NODISK;
|
||||
s &= ~STA_PROTECT;
|
||||
|
||||
Stat = s;
|
||||
}
|
||||
|
103
src/diskio.h
Normal file
103
src/diskio.h
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
*
|
||||
* gruvin9x is based on code named er9x by
|
||||
* Author - Erez Raviv <erezraviv@gmail.com>, which is in turn
|
||||
* was based on 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
/ Low level disk interface modlue include file (C)ChaN, 2010
|
||||
/-----------------------------------------------------------------------*/
|
||||
|
||||
#ifndef DEF_DISKIO
|
||||
#define DEF_DISKIO
|
||||
|
||||
#include "integer.h"
|
||||
|
||||
#define DN_MCI 0 /* Physical drive number for MCI */
|
||||
#define DN_NAND 1 /* Physical drive number for NAND flash */
|
||||
|
||||
|
||||
/* These functions are defined in asmfunc.S */
|
||||
void Copy_al2un (BYTE *dst, const DWORD *src, int count); /* Copy aligned to unaligned. */
|
||||
void Copy_un2al (DWORD *dst, const BYTE *src, int count); /* Copy unaligned to aligned. */
|
||||
|
||||
|
||||
/* Status of Disk Functions */
|
||||
typedef BYTE DSTATUS;
|
||||
|
||||
/* Results of Disk Functions */
|
||||
typedef enum {
|
||||
RES_OK = 0, /* 0: Successful */
|
||||
RES_ERROR, /* 1: R/W Error */
|
||||
RES_WRPRT, /* 2: Write Protected */
|
||||
RES_NOTRDY, /* 3: Not Ready */
|
||||
RES_PARERR /* 4: Invalid Parameter */
|
||||
} DRESULT;
|
||||
|
||||
|
||||
/*---------------------------------------*/
|
||||
/* Prototypes for disk control functions */
|
||||
|
||||
DSTATUS disk_initialize (BYTE);
|
||||
DSTATUS disk_status (BYTE);
|
||||
DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);
|
||||
DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);
|
||||
DRESULT disk_ioctl (BYTE, BYTE, BYTE*);
|
||||
void disk_timerproc (void);
|
||||
|
||||
|
||||
/* Disk Status Bits (DSTATUS) */
|
||||
|
||||
#define STA_NOINIT 0x01 /* Drive not initialized */
|
||||
#define STA_NODISK 0x02 /* No medium in the drive */
|
||||
#define STA_PROTECT 0x04 /* Write protected */
|
||||
|
||||
|
||||
/* Command code for disk_ioctrl fucntion */
|
||||
|
||||
/* Generic ioctl command (defined for FatFs) */
|
||||
#define CTRL_SYNC 0 /* Flush disk cache (for write functions) */
|
||||
#define GET_SECTOR_COUNT 1 /* Get media size (for only f_mkfs()) */
|
||||
#define GET_SECTOR_SIZE 2 /* Get sector size (for multiple sector size (_MAX_SS >= 1024)) */
|
||||
#define GET_BLOCK_SIZE 3 /* Get erase block size (for only f_mkfs()) */
|
||||
#define CTRL_ERASE_SECTOR 4 /* Force erased a block of sectors (for only _USE_ERASE) */
|
||||
|
||||
/* Generic ioctl command */
|
||||
#define CTRL_POWER 5 /* Get/Set power status */
|
||||
#define CTRL_LOCK 6 /* Lock/Unlock media removal */
|
||||
#define CTRL_EJECT 7 /* Eject media */
|
||||
|
||||
/* MMC/SDC specific ioctl command */
|
||||
#define MMC_GET_TYPE 10 /* Get card type */
|
||||
#define MMC_GET_CSD 11 /* Get CSD */
|
||||
#define MMC_GET_CID 12 /* Get CID */
|
||||
#define MMC_GET_OCR 13 /* Get OCR */
|
||||
#define MMC_GET_SDSTAT 14 /* Get SD status */
|
||||
|
||||
/* ATA/CF specific ioctl command */
|
||||
#define ATA_GET_REV 20 /* Get F/W revision */
|
||||
#define ATA_GET_MODEL 21 /* Get model name */
|
||||
#define ATA_GET_SN 22 /* Get serial number */
|
||||
|
||||
/* NAND specific ioctl command */
|
||||
#define NAND_FORMAT 30 /* Create physical format */
|
||||
|
||||
|
||||
volatile extern BYTE Timer1, Timer2; /* 100Hz decrement timer */
|
||||
|
||||
#endif
|
445
src/drivers.cpp
Normal file
445
src/drivers.cpp
Normal file
|
@ -0,0 +1,445 @@
|
|||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
*
|
||||
* gruvin9x is based on code named er9x by
|
||||
* Author - Erez Raviv <erezraviv@gmail.com>, which is in turn
|
||||
* was based on 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 "gruvin9x.h"
|
||||
|
||||
#ifndef SIMU
|
||||
|
||||
#ifdef ASYNC_WRITE
|
||||
|
||||
uint16_t eeprom_pointer;
|
||||
const char* eeprom_buffer_data;
|
||||
volatile size_t eeprom_buffer_size = 0;
|
||||
|
||||
inline void eeprom_write_byte()
|
||||
{
|
||||
EEAR = eeprom_pointer;
|
||||
EEDR = *eeprom_buffer_data;
|
||||
#if defined (PCBV3)
|
||||
EECR |= 1<<EEMPE;
|
||||
EECR |= 1<<EEPE;
|
||||
#else
|
||||
EECR |= 1<<EEMWE;
|
||||
EECR |= 1<<EEWE;
|
||||
#endif
|
||||
eeprom_pointer++;
|
||||
eeprom_buffer_data++;
|
||||
}
|
||||
|
||||
ISR(EE_READY_vect)
|
||||
{
|
||||
if (--eeprom_buffer_size > 0) {
|
||||
eeprom_write_byte();
|
||||
}
|
||||
else {
|
||||
#if defined (PCBV3)
|
||||
EECR &= ~(1<<EERIE);
|
||||
#else
|
||||
EECR &= ~(1<<EERIE);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void eeWriteBlockCmp(const void *i_pointer_ram, void *i_pointer_eeprom, size_t size)
|
||||
{
|
||||
assert(!eeprom_buffer_size);
|
||||
|
||||
eeprom_pointer = (uint16_t)i_pointer_eeprom;
|
||||
eeprom_buffer_data = (const char*)i_pointer_ram;
|
||||
eeprom_buffer_size = size;
|
||||
|
||||
#if defined (PCBV3)
|
||||
EECR |= (1<<EERIE);
|
||||
#else
|
||||
EECR |= (1<<EERIE);
|
||||
#endif
|
||||
|
||||
while (s_sync_write && eeprom_buffer_size > 0);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
///opt/cross/avr/include/avr/eeprom.h
|
||||
static inline void __attribute__ ((always_inline))
|
||||
eeprom_write_byte_cmp (uint8_t dat, uint16_t pointer_eeprom)
|
||||
{
|
||||
//see /home/thus/work/avr/avrsdk4/avr-libc-1.4.4/libc/misc/eeprom.S:98 143
|
||||
#if defined (PCBV3)
|
||||
while(EECR & (1<<EEPE))
|
||||
#else
|
||||
while(EECR & (1<<EEWE))
|
||||
#endif
|
||||
;
|
||||
EEAR = pointer_eeprom;
|
||||
|
||||
EECR |= 1<<EERE;
|
||||
if(dat == EEDR) return;
|
||||
|
||||
EEDR = dat;
|
||||
uint8_t flags=SREG;
|
||||
cli();
|
||||
#if defined (PCBV3)
|
||||
EECR |= 1<<EEMPE;
|
||||
EECR |= 1<<EEPE;
|
||||
#else
|
||||
EECR |= 1<<EEMWE;
|
||||
EECR |= 1<<EEWE;
|
||||
#endif
|
||||
SREG = flags;
|
||||
sei();
|
||||
}
|
||||
|
||||
void eeWriteBlockCmp(const void *i_pointer_ram, void *i_pointer_eeprom, size_t size)
|
||||
{
|
||||
const char* pointer_ram = (const char*)i_pointer_ram;
|
||||
uint16_t pointer_eeprom = (uint16_t)i_pointer_eeprom;
|
||||
while(size){
|
||||
eeprom_write_byte_cmp(*pointer_ram++,pointer_eeprom++);
|
||||
size--;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static uint8_t s_evt;
|
||||
void putEvent(uint8_t evt)
|
||||
{
|
||||
s_evt = evt;
|
||||
}
|
||||
uint8_t getEvent()
|
||||
{
|
||||
uint8_t evt = s_evt;
|
||||
s_evt=0;
|
||||
return evt;
|
||||
}
|
||||
|
||||
class Key
|
||||
{
|
||||
#define FILTERBITS 4
|
||||
#ifdef SIMU
|
||||
#define FFVAL 1
|
||||
#else
|
||||
#define FFVAL ((1<<FILTERBITS)-1)
|
||||
#endif
|
||||
#define KSTATE_OFF 0
|
||||
#define KSTATE_RPTDELAY 95 // gruvin: delay state before key repeating starts
|
||||
//#define KSTATE_SHORT 96
|
||||
#define KSTATE_START 97
|
||||
#define KSTATE_PAUSE 98
|
||||
#define KSTATE_KILLED 99
|
||||
uint8_t m_vals:FILTERBITS; // key debounce? 4 = 40ms
|
||||
uint8_t m_dblcnt:2;
|
||||
uint8_t m_cnt;
|
||||
uint8_t m_state;
|
||||
public:
|
||||
void input(bool val, EnumKeys enuk);
|
||||
bool state() { return m_vals==FFVAL; }
|
||||
void pauseEvents() { m_state = KSTATE_PAUSE; m_cnt = 0;}
|
||||
void killEvents() { m_state = KSTATE_KILLED; m_dblcnt=0; }
|
||||
uint8_t getDbl() { return m_dblcnt; }
|
||||
};
|
||||
|
||||
|
||||
Key keys[NUM_KEYS];
|
||||
void Key::input(bool val, EnumKeys enuk)
|
||||
{
|
||||
// uint8_t old=m_vals;
|
||||
m_vals <<= 1; if(val) m_vals |= 1; //portbit einschieben
|
||||
m_cnt++;
|
||||
|
||||
if(m_state && m_vals==0){ //gerade eben sprung auf 0
|
||||
if(m_state!=KSTATE_KILLED) {
|
||||
putEvent(EVT_KEY_BREAK(enuk));
|
||||
if(!( m_state == 16 && m_cnt<16)){
|
||||
m_dblcnt=0;
|
||||
}
|
||||
// }
|
||||
}
|
||||
m_cnt = 0;
|
||||
m_state = KSTATE_OFF;
|
||||
}
|
||||
switch(m_state){
|
||||
case KSTATE_OFF:
|
||||
if(m_vals==FFVAL){ //gerade eben sprung auf ff
|
||||
m_state = KSTATE_START;
|
||||
if(m_cnt>16) m_dblcnt=0; //pause zu lang fuer double
|
||||
m_cnt = 0;
|
||||
}
|
||||
break;
|
||||
//fallthrough
|
||||
case KSTATE_START:
|
||||
putEvent(EVT_KEY_FIRST(enuk));
|
||||
m_dblcnt++;
|
||||
m_state = KSTATE_RPTDELAY;
|
||||
m_cnt = 0;
|
||||
break;
|
||||
|
||||
case KSTATE_RPTDELAY: // gruvin: delay state before first key repeat
|
||||
if(m_cnt == 24) putEvent(EVT_KEY_LONG(enuk));
|
||||
if (m_cnt == 40) {
|
||||
m_state = 16;
|
||||
m_cnt = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 16:
|
||||
case 8:
|
||||
case 4:
|
||||
case 2:
|
||||
if(m_cnt >= 48) { //3 6 12 24 48 pulses in every 480ms
|
||||
m_state >>= 1;
|
||||
m_cnt = 0;
|
||||
}
|
||||
//fallthrough
|
||||
case 1:
|
||||
if( (m_cnt & (m_state-1)) == 0) putEvent(EVT_KEY_REPT(enuk));
|
||||
break;
|
||||
|
||||
case KSTATE_PAUSE: //pause
|
||||
if(m_cnt >= 64) {
|
||||
m_state = 8;
|
||||
m_cnt = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case KSTATE_KILLED: //killed
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool keyState(EnumKeys enuk)
|
||||
{
|
||||
if(enuk < (int)DIM(keys)) return keys[enuk].state() ? 1 : 0;
|
||||
switch(enuk){
|
||||
case SW_ElevDR : return PINE & (1<<INP_E_ElevDR);
|
||||
|
||||
#if defined(JETI) || defined(FRSKY)
|
||||
case SW_AileDR : return PINC & (1<<INP_C_AileDR); //shad974: rerouted inputs to free up UART0
|
||||
#else
|
||||
case SW_AileDR : return PINE & (1<<INP_E_AileDR);
|
||||
#endif
|
||||
|
||||
case SW_RuddDR : return PING & (1<<INP_G_RuddDR);
|
||||
// INP_G_ID1 INP_E_ID2
|
||||
// id0 0 1
|
||||
// id1 1 1
|
||||
// id2 1 0
|
||||
case SW_ID0 : return !(PING & (1<<INP_G_ID1));
|
||||
case SW_ID1 : return (PING & (1<<INP_G_ID1))&& (PINE & (1<<INP_E_ID2));
|
||||
case SW_ID2 : return !(PINE & (1<<INP_E_ID2));
|
||||
case SW_Gear : return PINE & (1<<INP_E_Gear);
|
||||
//case SW_ThrCt : return PINE & (1<<INP_E_ThrCt);
|
||||
|
||||
#if defined(JETI) || defined(FRSKY)
|
||||
case SW_ThrCt : return PINC & (1<<INP_C_ThrCt); //shad974: rerouted inputs to free up UART0
|
||||
#else
|
||||
case SW_ThrCt : return PINE & (1<<INP_E_ThrCt);
|
||||
#endif
|
||||
|
||||
case SW_Trainer: return PINE & (1<<INP_E_Trainer);
|
||||
default:;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pauseEvents(uint8_t event)
|
||||
{
|
||||
event=event & EVT_KEY_MASK;
|
||||
if(event < (int)DIM(keys)) keys[event].pauseEvents();
|
||||
}
|
||||
void killEvents(uint8_t event)
|
||||
{
|
||||
event=event & EVT_KEY_MASK;
|
||||
if(event < (int)DIM(keys)) keys[event].killEvents();
|
||||
}
|
||||
|
||||
uint8_t getEventDbl(uint8_t event)
|
||||
{
|
||||
event=event & EVT_KEY_MASK;
|
||||
if(event < (int)DIM(keys)) return keys[event].getDbl();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//uint16_t g_anaIns[8];
|
||||
volatile uint16_t g_tmr10ms;
|
||||
volatile uint8_t g_blinkTmr10ms;
|
||||
|
||||
|
||||
#if defined (PCBV3)
|
||||
uint8_t g_ms100 = 0; // global to allow time set function to reset to zero
|
||||
#endif
|
||||
void per10ms()
|
||||
{
|
||||
g_tmr10ms++;
|
||||
g_blinkTmr10ms++;
|
||||
|
||||
#if defined (PCBV3)
|
||||
/* Update gloabal Date/Time every 100 per10ms cycles */
|
||||
if (++g_ms100 == 100)
|
||||
{
|
||||
g_unixTime++; // inc global unix timestamp one second
|
||||
g_ms100 = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**** BEGIN KEY STATE READ ****/
|
||||
uint8_t enuk = KEY_MENU;
|
||||
|
||||
#if defined (PCBV3)
|
||||
|
||||
/* Original keys were connected to PORTB as follows:
|
||||
|
||||
Bit Key
|
||||
7 other use
|
||||
6 LEFT
|
||||
5 RIGHT
|
||||
4 UP
|
||||
3 DOWN
|
||||
2 EXIT
|
||||
1 MENU
|
||||
0 other use
|
||||
*/
|
||||
|
||||
#define KEY_Y0 1 // EXIT / MENU
|
||||
#define KEY_Y1 2 // LEFT / RIGHT / UP / DOWN
|
||||
#define KEY_Y2 4 // LV_Trim_Up / Down / LH_Trim_Up / Down
|
||||
#define KEY_Y3 8 // RV_Trim_Up / Down / RH_Trim_Up / Down
|
||||
#define TRIM_M_LH_DWN 0 // KEY_X0
|
||||
#define TRIM_M_LH_UP 1 // KEY_X1
|
||||
#define TRIM_M_LV_DWN 2 // KEY_X2
|
||||
#define TRIM_M_LV_UP 3 // KEY_X3
|
||||
#define TRIM_M_RV_DWN 4 // KEY_X0
|
||||
#define TRIM_M_RV_UP 5 // KEY_X1
|
||||
#define TRIM_M_RH_DWN 6 // KEY_X2
|
||||
#define TRIM_M_RH_UP 7 // KEY_3X
|
||||
|
||||
uint8_t in, tin;
|
||||
|
||||
in = keyDown(); // in gruvin9x.cpp
|
||||
|
||||
#else
|
||||
uint8_t in = ~PINB;
|
||||
#endif
|
||||
|
||||
for(int i=1; i<7; i++)
|
||||
{
|
||||
//INP_B_KEY_MEN 1 .. INP_B_KEY_LFT 6
|
||||
keys[enuk].input(in & (1<<i),(EnumKeys)enuk);
|
||||
++enuk;
|
||||
}
|
||||
|
||||
#if defined (PCBV3)
|
||||
static prog_uchar APM crossTrim[]={
|
||||
1<<TRIM_M_RV_DWN,
|
||||
1<<TRIM_M_RV_UP,
|
||||
1<<TRIM_M_RH_DWN,
|
||||
1<<TRIM_M_RH_UP,
|
||||
1<<TRIM_M_LH_DWN,
|
||||
1<<TRIM_M_LH_UP,
|
||||
1<<TRIM_M_LV_DWN,
|
||||
1<<TRIM_M_LV_UP
|
||||
};
|
||||
#else
|
||||
static prog_uchar APM crossTrim[]={
|
||||
1<<INP_D_TRM_LH_DWN, // bit 7
|
||||
1<<INP_D_TRM_LH_UP,
|
||||
1<<INP_D_TRM_LV_DWN,
|
||||
1<<INP_D_TRM_LV_UP,
|
||||
1<<INP_D_TRM_RV_DWN,
|
||||
1<<INP_D_TRM_RV_UP,
|
||||
1<<INP_D_TRM_RH_DWN,
|
||||
1<<INP_D_TRM_RH_UP // bit 0
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined (PCBV3)
|
||||
|
||||
PORTD = ~KEY_Y2; // select Y2 row. (Bits 3:0 LVD / LVU / LHU / LHD)
|
||||
_delay_us(1);
|
||||
in = ~PIND & 0xf0; // mask out outputs
|
||||
|
||||
PORTD = ~KEY_Y3; // select Y3 row. (Bits 3:0 RHU / RHD / RVD / RVU)
|
||||
_delay_us(1);
|
||||
in |= ((~PIND & 0xf0) >> 4);
|
||||
|
||||
PORTD = 0xFF;
|
||||
|
||||
#else
|
||||
|
||||
in = ~PIND;
|
||||
|
||||
// Legacy support for USART1 free hardware mod [DEPRECATED]
|
||||
#if defined(USART1FREED)
|
||||
// mask out original INP_D_TRM_LV_UP and INP_D_TRM_LV_DWN bits
|
||||
in &= ~((1<<INP_D_TRM_LV_UP) | (1<<INP_D_TRM_LV_DWN));
|
||||
|
||||
// merge in the two new switch port values
|
||||
in |= (~PINC & (1<<INP_C_TRM_LV_UP)) ? (1<<INP_D_TRM_LV_UP) : 0;
|
||||
in |= (~PING & (1<<INP_G_TRM_LV_DWN)) ? (1<<INP_D_TRM_LV_DWN) : 0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
for(int i=0; i<8; i++)
|
||||
{
|
||||
// INP_D_TRM_RH_UP 0 .. INP_D_TRM_LH_UP 7
|
||||
keys[enuk].input(in & pgm_read_byte(crossTrim+i),(EnumKeys)enuk);
|
||||
++enuk;
|
||||
}
|
||||
|
||||
/**** END KEY STATE READ ****/
|
||||
|
||||
#if defined (FRSKY)
|
||||
// Used to detect presence of valid FrSky telemetry packets inside the
|
||||
// last <FRSKY_TIMEOUT10ms> 10ms intervals
|
||||
if ( FrskyAlarmSendState )
|
||||
FRSKY10mspoll() ;
|
||||
|
||||
if (frskyStreaming > 0)
|
||||
frskyStreaming--;
|
||||
else if (g_eeGeneral.enableTelemetryAlarm && (g_model.frsky.channels[0].ratio || g_model.frsky.channels[1].ratio)) {
|
||||
#if defined (BEEPSPKR)
|
||||
if (!(g_tmr10ms % 30)) beepWarn2Spkr((g_tmr10ms % 60) ? 25 : 20);
|
||||
#else
|
||||
if (!(g_tmr10ms % 30))
|
||||
{
|
||||
warble = !(g_tmr10ms % 60);
|
||||
beepWarn2();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
// These moved here from perOut() [gruvin9x.cpp] to improve beep trigger reliability.
|
||||
#if defined (BEEPSPKR)
|
||||
if(mixWarning & 1) if(((g_tmr10ms&0xFF)== 0)) beepWarn1Spkr(BEEP_DEFAULT_FREQ+7);
|
||||
if(mixWarning & 2) if(((g_tmr10ms&0xFF)== 64)
|
||||
|| ((g_tmr10ms&0xFF)== 72)) beepWarn1Spkr(BEEP_DEFAULT_FREQ+9);
|
||||
if(mixWarning & 4) if(((g_tmr10ms&0xFF)==128) || ((g_tmr10ms&0xFF)==136)
|
||||
|| ((g_tmr10ms&0xFF)==144)) beepWarn1Spkr(BEEP_DEFAULT_FREQ+11);
|
||||
#else
|
||||
if(mixWarning & 1) if(((g_tmr10ms&0xFF)== 0)) beepWarn1();
|
||||
if(mixWarning & 2) if(((g_tmr10ms&0xFF)== 64) || ((g_tmr10ms&0xFF)== 72)) beepWarn1();
|
||||
if(mixWarning & 4) if(((g_tmr10ms&0xFF)==128) || ((g_tmr10ms&0xFF)==136) || ((g_tmr10ms&0xFF)==144)) beepWarn1();
|
||||
#endif
|
||||
}
|
135
src/eeprom_v3.h
Normal file
135
src/eeprom_v3.h
Normal file
|
@ -0,0 +1,135 @@
|
|||
#ifndef eepromv3_h
|
||||
#define eepromv3_h
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
namespace EEPROM_V3 {
|
||||
|
||||
typedef struct t_TrainerMix {
|
||||
uint8_t srcChn:3; //0-7 = ch1-8
|
||||
int8_t swtch:5;
|
||||
int8_t studWeight:6;
|
||||
uint8_t mode:2; //off,add-mode,subst-mode
|
||||
} __attribute__((packed)) TrainerMix; //
|
||||
|
||||
typedef struct t_TrainerData {
|
||||
int16_t calib[4];
|
||||
TrainerMix mix[4];
|
||||
} __attribute__((packed)) TrainerData;
|
||||
|
||||
typedef struct t_EEGeneral {
|
||||
uint8_t myVers;
|
||||
int16_t calibMid[7];
|
||||
int16_t calibSpanNeg[7];
|
||||
int16_t calibSpanPos[7];
|
||||
uint16_t chkSum;
|
||||
uint8_t currModel; //0..15
|
||||
uint8_t contrast;
|
||||
uint8_t vBatWarn;
|
||||
int8_t vBatCalib;
|
||||
int8_t lightSw;
|
||||
TrainerData trainer;
|
||||
uint8_t view; //index of subview in main scrren
|
||||
// uint8_t warnOpts; //bitset for several warnings
|
||||
uint8_t disableThrottleWarning:1;
|
||||
uint8_t disableSwitchWarning:1;
|
||||
uint8_t disableMemoryWarning:1;
|
||||
uint8_t beeperVal:3;
|
||||
uint8_t reserveWarning:1;
|
||||
uint8_t disableAlarmWarning:1;
|
||||
uint8_t stickMode;
|
||||
uint8_t inactivityTimer;
|
||||
uint8_t throttleReversed:1;
|
||||
uint8_t minuteBeep:1;
|
||||
uint8_t preBeep:1;
|
||||
uint8_t flashBeep:1;
|
||||
uint8_t disableSplashScreen:1;
|
||||
uint8_t res1:3;
|
||||
uint8_t filterInput;
|
||||
uint8_t lightAutoOff;
|
||||
uint8_t templateSetup; //RETA order according to chout_ar array
|
||||
int8_t PPM_Multiplier;
|
||||
uint8_t res[1];
|
||||
} __attribute__((packed)) EEGeneral;
|
||||
|
||||
|
||||
|
||||
//eeprom modelspec
|
||||
//expo[3][2][2] //[Norm/Dr][expo/weight][R/L]
|
||||
|
||||
typedef struct t_ExpoData {
|
||||
int8_t expo[3][2][2];
|
||||
int8_t drSw1;
|
||||
int8_t drSw2;
|
||||
} __attribute__((packed)) ExpoData;
|
||||
|
||||
|
||||
typedef struct t_LimitData {
|
||||
int8_t min;
|
||||
int8_t max;
|
||||
bool revert;
|
||||
int16_t offset;
|
||||
} __attribute__((packed)) LimitData;
|
||||
|
||||
|
||||
typedef struct t_MixData {
|
||||
uint8_t destCh; // 1..NUM_CHNOUT
|
||||
uint8_t srcRaw; //
|
||||
int8_t weight;
|
||||
int8_t swtch;
|
||||
uint8_t curve; //0=symmetrisch 1=no neg 2=no pos
|
||||
uint8_t delayUp:4;
|
||||
uint8_t delayDown:4;
|
||||
uint8_t speedUp:4; // Servogeschwindigkeit aus Tabelle (10ms Cycle)
|
||||
uint8_t speedDown:4; // 0 nichts
|
||||
uint8_t carryTrim:1;
|
||||
uint8_t mltpx:3; // multiplex method 0=+ 1=* 2=replace
|
||||
uint8_t mixWarn:4; // mixer warning
|
||||
int8_t sOffset;
|
||||
int8_t res;
|
||||
} __attribute__((packed)) MixData;
|
||||
|
||||
|
||||
typedef struct t_CSwData { // Custom Switches data
|
||||
int8_t v1; //input
|
||||
int8_t v2; //offset
|
||||
uint8_t func;
|
||||
} __attribute__((packed)) CSwData;
|
||||
|
||||
|
||||
typedef struct t_SwashRingData { // Swash Ring data
|
||||
uint8_t lim; // 0 mean off 100 full deflection
|
||||
uint8_t chX; // 2 channels to limit
|
||||
uint8_t chY; // 2 channels to limit
|
||||
} __attribute__((packed)) SwashRingData;
|
||||
|
||||
typedef struct t_ModelData {
|
||||
char name[10]; // 10 must be first for eeLoadModelName
|
||||
uint8_t mdVers;
|
||||
int8_t tmrMode; // timer trigger source -> off, abs, stk, stk%, sw/!sw, !m_sw/!m_sw
|
||||
uint8_t tmrDir; // 0=>Count Down, 1=>Count Up
|
||||
uint16_t tmrVal;
|
||||
uint8_t protocol;
|
||||
int8_t ppmNCH;
|
||||
int8_t thrTrim:4; // Enable Throttle Trim
|
||||
int8_t thrExpo:4; // Enable Throttle Expo
|
||||
int8_t trimInc; // Trim Increments
|
||||
int8_t ppmDelay;
|
||||
int8_t trimSw;
|
||||
uint8_t beepANACenter; // 1<<0->A1.. 1<<6->A7
|
||||
uint8_t pulsePol;
|
||||
char res[3];
|
||||
MixData mixData[32];
|
||||
LimitData limitData[16];
|
||||
ExpoData expoData[4];
|
||||
int8_t trim[4];
|
||||
int8_t curves5[8][5];
|
||||
int8_t curves9[8][9];
|
||||
CSwData customSw[6];
|
||||
SwashRingData swashR;
|
||||
} __attribute__((packed)) ModelData;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
158
src/eeprom_v4.h
Normal file
158
src/eeprom_v4.h
Normal file
|
@ -0,0 +1,158 @@
|
|||
#ifndef eepromv4_h
|
||||
#define eepromv4_h
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
namespace EEPROM_V4 {
|
||||
|
||||
typedef struct t_TrainerMix {
|
||||
uint8_t srcChn:3; //0-7 = ch1-8
|
||||
int8_t swtch:5;
|
||||
int8_t studWeight:6;
|
||||
uint8_t mode:2; //off,add-mode,subst-mode
|
||||
} __attribute__((packed)) TrainerMix; //
|
||||
|
||||
typedef struct t_TrainerData {
|
||||
int16_t calib[4];
|
||||
TrainerMix mix[4];
|
||||
} __attribute__((packed)) TrainerData;
|
||||
|
||||
typedef struct t_EEGeneral {
|
||||
uint8_t myVers;
|
||||
int16_t calibMid[7];
|
||||
int16_t calibSpanNeg[7];
|
||||
int16_t calibSpanPos[7];
|
||||
uint16_t chkSum;
|
||||
uint8_t currModel; //0..15
|
||||
uint8_t contrast;
|
||||
uint8_t vBatWarn;
|
||||
int8_t vBatCalib;
|
||||
int8_t lightSw;
|
||||
TrainerData trainer;
|
||||
uint8_t view; //index of subview in main scrren
|
||||
uint8_t disableThrottleWarning:1;
|
||||
uint8_t disableSwitchWarning:1;
|
||||
uint8_t disableMemoryWarning:1;
|
||||
uint8_t beeperVal:3;
|
||||
uint8_t reserveWarning:1;
|
||||
uint8_t disableAlarmWarning:1;
|
||||
uint8_t stickMode;
|
||||
uint8_t inactivityTimer;
|
||||
uint8_t throttleReversed:1;
|
||||
uint8_t minuteBeep:1;
|
||||
uint8_t preBeep:1;
|
||||
uint8_t flashBeep:1;
|
||||
uint8_t disableSplashScreen:1;
|
||||
uint8_t res1:3;
|
||||
uint8_t filterInput;
|
||||
uint8_t lightAutoOff;
|
||||
uint8_t templateSetup; //RETA order according to chout_ar array
|
||||
int8_t PPM_Multiplier;
|
||||
uint8_t res[1];
|
||||
} __attribute__((packed)) EEGeneral;
|
||||
|
||||
//eeprom modelspec
|
||||
|
||||
typedef struct t_ExpoData {
|
||||
int8_t expo[3][2][2]; //[Norm/Dr][expo/weight][R/L]
|
||||
int8_t drSw1;
|
||||
int8_t drSw2;
|
||||
} __attribute__((packed)) ExpoData;
|
||||
|
||||
typedef struct t_LimitData {
|
||||
int8_t min;
|
||||
int8_t max;
|
||||
bool revert;
|
||||
int16_t offset;
|
||||
} __attribute__((packed)) LimitData;
|
||||
|
||||
typedef struct t_MixData {
|
||||
uint8_t destCh; // 1..NUM_CHNOUT
|
||||
uint8_t srcRaw; //
|
||||
int8_t weight;
|
||||
int8_t swtch;
|
||||
uint8_t curve; //0=symmetrisch 1=no neg 2=no pos
|
||||
uint8_t delayUp:4;
|
||||
uint8_t delayDown:4;
|
||||
uint8_t speedUp:4; // Servogeschwindigkeit aus Tabelle (10ms Cycle)
|
||||
uint8_t speedDown:4; // 0 nichts
|
||||
uint8_t carryTrim:1;
|
||||
uint8_t mltpx:3; // multiplex method 0=+ 1=* 2=replace
|
||||
uint8_t mixWarn:4; // mixer warning
|
||||
int8_t sOffset;
|
||||
int8_t res;
|
||||
} __attribute__((packed)) MixData;
|
||||
|
||||
typedef struct t_CSwData { // Custom Switches data
|
||||
int8_t v1; //input
|
||||
int8_t v2; //offset
|
||||
uint8_t func;
|
||||
} __attribute__((packed)) CSwData;
|
||||
|
||||
|
||||
typedef struct t_SwashRingData { // Swash Ring data
|
||||
uint8_t lim; // 0 mean off 100 full deflection
|
||||
uint8_t chX; // 2 channels to limit
|
||||
uint8_t chY; // 2 channels to limit
|
||||
} __attribute__((packed)) SwashRingData;
|
||||
|
||||
typedef struct t_SafetySwData { // Custom Switches data
|
||||
int8_t swtch;
|
||||
int8_t val;
|
||||
} __attribute__((packed)) SafetySwData;
|
||||
|
||||
typedef struct t_FrSkyChannelData {
|
||||
uint8_t ratio; // 0.0 means not used, 0.1V steps EG. 6.6 Volts = 66. 25.1V = 251, etc.
|
||||
uint8_t alarms_value[2]; // 0.1V steps EG. 6.6 Volts = 66. 25.1V = 251, etc.
|
||||
uint8_t alarms_level:4;
|
||||
uint8_t alarms_greater:2; // 0=LT(<), 1=GT(>)
|
||||
uint8_t type:2; // future use: 0=volts, ...
|
||||
} __attribute__((packed)) FrSkyChannelData;
|
||||
|
||||
typedef struct t_FrSkyData {
|
||||
FrSkyChannelData channels[2];
|
||||
} __attribute__((packed)) FrSkyData;
|
||||
|
||||
typedef struct t_ModelData {
|
||||
char name[10]; // 10 must be first for eeLoadModelName
|
||||
uint8_t mdVers;
|
||||
int8_t tmrMode; // timer trigger source -> off, abs, stk, stk%, sw/!sw, !m_sw/!m_sw
|
||||
uint8_t tmrDir:1; //0=>Count Down, 1=>Count Up
|
||||
uint8_t traineron:1; // 0 disable trainer, 1 allow trainer
|
||||
uint8_t spare:6;
|
||||
uint16_t tmrVal;
|
||||
uint8_t protocol;
|
||||
int8_t ppmNCH;
|
||||
int8_t thrTrim:4; // Enable Throttle Trim
|
||||
int8_t thrExpo:4; // Enable Throttle Expo
|
||||
int8_t trimInc; // Trim Increments
|
||||
int8_t ppmDelay;
|
||||
int8_t trimSw;
|
||||
uint8_t beepANACenter; // 1<<0->A1.. 1<<6->A7
|
||||
uint8_t pulsePol:1;
|
||||
uint8_t extendedLimits:1;
|
||||
uint8_t swashInvertELE:1;
|
||||
uint8_t swashInvertAIL:1;
|
||||
uint8_t swashInvertCOL:1;
|
||||
uint8_t swashType:3;
|
||||
uint8_t swashCollectiveSource;
|
||||
uint8_t swashRingValue;
|
||||
char res1;
|
||||
MixData mixData[32];
|
||||
LimitData limitData[16];
|
||||
ExpoData expoData[4];
|
||||
int8_t trim[4];
|
||||
int8_t curves5[8][5];
|
||||
int8_t curves9[8][9];
|
||||
CSwData customSw[12/*er9x=12, gruvin9x=6*/];
|
||||
/* er9x only */
|
||||
uint8_t a1voltRatio; //FrSky
|
||||
uint8_t a2voltRatio; //FrSky
|
||||
uint8_t res3;
|
||||
SafetySwData safetySw[16];
|
||||
FrSkyData frsky;
|
||||
} __attribute__((packed)) ModelData;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
3736
src/ff.cpp
Normal file
3736
src/ff.cpp
Normal file
File diff suppressed because it is too large
Load diff
541
src/ff.h
Normal file
541
src/ff.h
Normal file
|
@ -0,0 +1,541 @@
|
|||
/*---------------------------------------------------------------------------/
|
||||
/ FatFs - FAT file system module include file R0.08a (C)ChaN, 2010
|
||||
/----------------------------------------------------------------------------/
|
||||
/ FatFs module is a generic FAT file system module for small embedded systems.
|
||||
/ This is a free software that opened for education, research and commercial
|
||||
/ developments under license policy of following trems.
|
||||
/
|
||||
/ Copyright (C) 2010, ChaN, all right reserved.
|
||||
/
|
||||
/ * The FatFs module is a free software and there is NO WARRANTY.
|
||||
/ * No restriction on use. You can use, modify and redistribute it for
|
||||
/ personal, non-profit or commercial product UNDER YOUR RESPONSIBILITY.
|
||||
/ * Redistributions of source code must retain the above copyright notice.
|
||||
/
|
||||
/----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef _FATFS
|
||||
#define _FATFS 8255 /* Revision ID */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "integer.h" /* Basic integer types */
|
||||
#include "ffconf.h" /* FatFs configuration options */
|
||||
|
||||
#if _FATFS != _FFCONF
|
||||
#error Wrong configuration file (ffconf.h).
|
||||
#endif
|
||||
|
||||
|
||||
/* DBCS code ranges and SBCS extend char conversion table */
|
||||
|
||||
#if _CODE_PAGE == 932 /* Japanese Shift-JIS */
|
||||
#define _DF1S 0x81 /* DBC 1st byte range 1 start */
|
||||
#define _DF1E 0x9F /* DBC 1st byte range 1 end */
|
||||
#define _DF2S 0xE0 /* DBC 1st byte range 2 start */
|
||||
#define _DF2E 0xFC /* DBC 1st byte range 2 end */
|
||||
#define _DS1S 0x40 /* DBC 2nd byte range 1 start */
|
||||
#define _DS1E 0x7E /* DBC 2nd byte range 1 end */
|
||||
#define _DS2S 0x80 /* DBC 2nd byte range 2 start */
|
||||
#define _DS2E 0xFC /* DBC 2nd byte range 2 end */
|
||||
|
||||
#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */
|
||||
#define _DF1S 0x81
|
||||
#define _DF1E 0xFE
|
||||
#define _DS1S 0x40
|
||||
#define _DS1E 0x7E
|
||||
#define _DS2S 0x80
|
||||
#define _DS2E 0xFE
|
||||
|
||||
#elif _CODE_PAGE == 949 /* Korean */
|
||||
#define _DF1S 0x81
|
||||
#define _DF1E 0xFE
|
||||
#define _DS1S 0x41
|
||||
#define _DS1E 0x5A
|
||||
#define _DS2S 0x61
|
||||
#define _DS2E 0x7A
|
||||
#define _DS3S 0x81
|
||||
#define _DS3E 0xFE
|
||||
|
||||
#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */
|
||||
#define _DF1S 0x81
|
||||
#define _DF1E 0xFE
|
||||
#define _DS1S 0x40
|
||||
#define _DS1E 0x7E
|
||||
#define _DS2S 0xA1
|
||||
#define _DS2E 0xFE
|
||||
|
||||
#elif _CODE_PAGE == 437 /* U.S. (OEM) */
|
||||
#define _DF1S 0
|
||||
#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F,0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
|
||||
0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
|
||||
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
|
||||
|
||||
#elif _CODE_PAGE == 720 /* Arabic (OEM) */
|
||||
#define _DF1S 0
|
||||
#define _EXCVT {0x80,0x81,0x45,0x41,0x84,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x49,0x49,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
|
||||
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
|
||||
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
|
||||
|
||||
#elif _CODE_PAGE == 737 /* Greek (OEM) */
|
||||
#define _DF1S 0
|
||||
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \
|
||||
0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
|
||||
0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xE7,0xE8,0xF1,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
|
||||
|
||||
#elif _CODE_PAGE == 775 /* Baltic (OEM) */
|
||||
#define _DF1S 0
|
||||
#define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
|
||||
0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
|
||||
0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
|
||||
|
||||
#elif _CODE_PAGE == 850 /* Multilingual Latin 1 (OEM) */
|
||||
#define _DF1S 0
|
||||
#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
|
||||
0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
|
||||
0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
|
||||
|
||||
#elif _CODE_PAGE == 852 /* Latin 2 (OEM) */
|
||||
#define _DF1S 0
|
||||
#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F,0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0x9F, \
|
||||
0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
|
||||
0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF}
|
||||
|
||||
#elif _CODE_PAGE == 855 /* Cyrillic (OEM) */
|
||||
#define _DF1S 0
|
||||
#define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F,0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \
|
||||
0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \
|
||||
0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF}
|
||||
|
||||
#elif _CODE_PAGE == 857 /* Turkish (OEM) */
|
||||
#define _DF1S 0
|
||||
#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x98,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \
|
||||
0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
|
||||
0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0x59,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
|
||||
|
||||
#elif _CODE_PAGE == 858 /* Multilingual Latin 1 + Euro (OEM) */
|
||||
#define _DF1S 0
|
||||
#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
|
||||
0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
|
||||
0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
|
||||
|
||||
#elif _CODE_PAGE == 862 /* Hebrew (OEM) */
|
||||
#define _DF1S 0
|
||||
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
|
||||
0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
|
||||
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
|
||||
|
||||
#elif _CODE_PAGE == 866 /* Russian (OEM) */
|
||||
#define _DF1S 0
|
||||
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
|
||||
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
|
||||
0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
|
||||
|
||||
#elif _CODE_PAGE == 874 /* Thai (OEM, Windows) */
|
||||
#define _DF1S 0
|
||||
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
|
||||
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
|
||||
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
|
||||
|
||||
#elif _CODE_PAGE == 1250 /* Central Europe (Windows) */
|
||||
#define _DF1S 0
|
||||
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \
|
||||
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xA3,0xB4,0xB5,0xB6,0xB7,0xB8,0xA5,0xAA,0xBB,0xBC,0xBD,0xBC,0xAF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF}
|
||||
|
||||
#elif _CODE_PAGE == 1251 /* Cyrillic (Windows) */
|
||||
#define _DF1S 0
|
||||
#define _EXCVT {0x80,0x81,0x82,0x82,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x80,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \
|
||||
0xA0,0xA2,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB2,0xA5,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xA3,0xBD,0xBD,0xAF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF}
|
||||
|
||||
#elif _CODE_PAGE == 1252 /* Latin 1 (Windows) */
|
||||
#define _DF1S 0
|
||||
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0xAd,0x9B,0x8C,0x9D,0xAE,0x9F, \
|
||||
0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F}
|
||||
|
||||
#elif _CODE_PAGE == 1253 /* Greek (Windows) */
|
||||
#define _DF1S 0
|
||||
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
|
||||
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xA2,0xB8,0xB9,0xBA, \
|
||||
0xE0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xFB,0xBC,0xFD,0xBF,0xFF}
|
||||
|
||||
#elif _CODE_PAGE == 1254 /* Turkish (Windows) */
|
||||
#define _DF1S 0
|
||||
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x9D,0x9E,0x9F, \
|
||||
0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F}
|
||||
|
||||
#elif _CODE_PAGE == 1255 /* Hebrew (Windows) */
|
||||
#define _DF1S 0
|
||||
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
|
||||
0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
|
||||
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
|
||||
|
||||
#elif _CODE_PAGE == 1256 /* Arabic (Windows) */
|
||||
#define _DF1S 0
|
||||
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x8C,0x9D,0x9E,0x9F, \
|
||||
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
|
||||
0x41,0xE1,0x41,0xE3,0xE4,0xE5,0xE6,0x43,0x45,0x45,0x45,0x45,0xEC,0xED,0x49,0x49,0xF0,0xF1,0xF2,0xF3,0x4F,0xF5,0xF6,0xF7,0xF8,0x55,0xFA,0x55,0x55,0xFD,0xFE,0xFF}
|
||||
|
||||
#elif _CODE_PAGE == 1257 /* Baltic (Windows) */
|
||||
#define _DF1S 0
|
||||
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
|
||||
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xBC,0xBD,0xBE,0xAF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF}
|
||||
|
||||
#elif _CODE_PAGE == 1258 /* Vietnam (OEM, Windows) */
|
||||
#define _DF1S 0
|
||||
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0xAC,0x9D,0x9E,0x9F, \
|
||||
0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xEC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xFE,0x9F}
|
||||
|
||||
#elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */
|
||||
#define _DF1S 0
|
||||
|
||||
#else
|
||||
#error Unknown code page
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Definitions of volume management */
|
||||
|
||||
#if _MULTI_PARTITION /* Multiple partition configuration */
|
||||
#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive# */
|
||||
#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition# */
|
||||
typedef struct {
|
||||
BYTE pd; /* Physical drive# */
|
||||
BYTE pt; /* Partition # (0-3) */
|
||||
} PARTITION;
|
||||
extern const PARTITION VolToPart[]; /* Volume - Physical location resolution table */
|
||||
|
||||
#else /* Single partition configuration */
|
||||
#define LD2PD(vol) (vol) /* Logical drive# is bound to the same physical drive# */
|
||||
#define LD2PT(vol) 0 /* Always mounts the 1st partition */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Type of path name strings on FatFs API */
|
||||
|
||||
#if _LFN_UNICODE /* Unicode string */
|
||||
#if !_USE_LFN
|
||||
#error _LFN_UNICODE must be 0 in non-LFN cfg.
|
||||
#endif
|
||||
#ifndef _INC_TCHAR
|
||||
typedef WCHAR TCHAR;
|
||||
#define _T(x) L ## x
|
||||
#define _TEXT(x) L ## x
|
||||
#endif
|
||||
|
||||
#else /* ANSI/OEM string */
|
||||
#ifndef _INC_TCHAR
|
||||
typedef char TCHAR;
|
||||
#define _T(x) x
|
||||
#define _TEXT(x) x
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* File system object structure (FATFS) */
|
||||
|
||||
typedef struct {
|
||||
BYTE fs_type; /* FAT sub-type (0:Not mounted) */
|
||||
BYTE drv; /* Physical drive number */
|
||||
BYTE csize; /* Sectors per cluster (1,2,4...128) */
|
||||
BYTE n_fats; /* Number of FAT copies (1,2) */
|
||||
BYTE wflag; /* win[] dirty flag (1:must be written back) */
|
||||
BYTE fsi_flag; /* fsinfo dirty flag (1:must be written back) */
|
||||
WORD id; /* File system mount ID */
|
||||
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
|
||||
#if _MAX_SS != 512
|
||||
WORD ssize; /* Bytes per sector (512,1024,2048,4096) */
|
||||
#endif
|
||||
#if _FS_REENTRANT
|
||||
_SYNC_t sobj; /* Identifier of sync object */
|
||||
#endif
|
||||
#if !_FS_READONLY
|
||||
DWORD last_clust; /* Last allocated cluster */
|
||||
DWORD free_clust; /* Number of free clusters */
|
||||
DWORD fsi_sector; /* fsinfo sector (FAT32) */
|
||||
#endif
|
||||
#if _FS_RPATH
|
||||
DWORD cdir; /* Current directory start cluster (0:root) */
|
||||
#endif
|
||||
DWORD n_fatent; /* Number of FAT entries (= number of clusters + 2) */
|
||||
DWORD fsize; /* Sectors per FAT */
|
||||
DWORD fatbase; /* FAT start sector */
|
||||
DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */
|
||||
DWORD database; /* Data start sector */
|
||||
DWORD winsect; /* Current sector appearing in the win[] */
|
||||
BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and Data on tiny cfg) */
|
||||
} FATFS;
|
||||
|
||||
|
||||
|
||||
/* File object structure (FIL) */
|
||||
|
||||
typedef struct {
|
||||
FATFS* fs; /* Pointer to the owner file system object */
|
||||
WORD id; /* Owner file system mount ID */
|
||||
BYTE flag; /* File status flags */
|
||||
BYTE pad1;
|
||||
DWORD fptr; /* File read/write pointer (0 on file open) */
|
||||
DWORD fsize; /* File size */
|
||||
DWORD org_clust; /* File start cluster (0 when fsize==0) */
|
||||
DWORD curr_clust; /* Current cluster */
|
||||
DWORD dsect; /* Current data sector */
|
||||
#if !_FS_READONLY
|
||||
DWORD dir_sect; /* Sector containing the directory entry */
|
||||
BYTE* dir_ptr; /* Ponter to the directory entry in the window */
|
||||
#endif
|
||||
#if _USE_FASTSEEK
|
||||
DWORD* cltbl; /* Pointer to the cluster link map table (null on file open) */
|
||||
#endif
|
||||
#if _FS_SHARE
|
||||
UINT lockid; /* File lock ID (index of file semaphore table) */
|
||||
#endif
|
||||
#if !_FS_TINY
|
||||
BYTE buf[_MAX_SS]; /* File data read/write buffer */
|
||||
#endif
|
||||
} FIL;
|
||||
|
||||
|
||||
|
||||
/* Directory object structure (DIR) */
|
||||
|
||||
typedef struct {
|
||||
FATFS* fs; /* Pointer to the owner file system object */
|
||||
WORD id; /* Owner file system mount ID */
|
||||
WORD index; /* Current read/write index number */
|
||||
DWORD sclust; /* Table start cluster (0:Root dir) */
|
||||
DWORD clust; /* Current cluster */
|
||||
DWORD sect; /* Current sector */
|
||||
BYTE* dir; /* Pointer to the current SFN entry in the win[] */
|
||||
BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
|
||||
#if _USE_LFN
|
||||
WCHAR* lfn; /* Pointer to the LFN working buffer */
|
||||
WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */
|
||||
#endif
|
||||
} DIR;
|
||||
|
||||
|
||||
|
||||
/* File status structure (FILINFO) */
|
||||
|
||||
typedef struct {
|
||||
DWORD fsize; /* File size */
|
||||
WORD fdate; /* Last modified date */
|
||||
WORD ftime; /* Last modified time */
|
||||
BYTE fattrib; /* Attribute */
|
||||
TCHAR fname[13]; /* Short file name (8.3 format) */
|
||||
#if _USE_LFN
|
||||
TCHAR* lfname; /* Pointer to the LFN buffer */
|
||||
UINT lfsize; /* Size of LFN buffer in TCHAR */
|
||||
#endif
|
||||
} FILINFO;
|
||||
|
||||
|
||||
|
||||
/* File function return code (FRESULT) */
|
||||
|
||||
typedef enum {
|
||||
FR_OK = 0, // (0) Succeeded
|
||||
FR_DISK_ERR, // (1) A hard error occured in the low level disk I/O layer
|
||||
FR_INT_ERR, // (2) Assertion failed
|
||||
FR_NOT_READY, // (3) The physical drive cannot work
|
||||
FR_NO_FILE, // (4) Could not find the file
|
||||
FR_NO_PATH, // (5) Could not find the path
|
||||
FR_INVALID_NAME, // (6) The path name format is invalid
|
||||
FR_DENIED, // (7) Acces denied due to prohibited access or directory full
|
||||
FR_EXIST, // (8) Acces denied due to prohibited access
|
||||
FR_INVALID_OBJECT, // (9) The file/directory object is invalid
|
||||
FR_WRITE_PROTECTED, // (10) The physical drive is write protected
|
||||
FR_INVALID_DRIVE, // (11) The logical drive number is invalid
|
||||
FR_NOT_ENABLED, // (12) The volume has no work area
|
||||
FR_NO_FILESYSTEM, // (13) There is no valid FAT volume on the physical drive
|
||||
FR_MKFS_ABORTED, // (14) The f_mkfs() aborted due to any parameter error
|
||||
FR_TIMEOUT, // (15) Could not get a grant to access the volume within defined period
|
||||
FR_LOCKED, // (16) The operation is rejected according to the file shareing policy
|
||||
FR_NOT_ENOUGH_CORE, // (17) LFN working buffer could not be allocated
|
||||
FR_TOO_MANY_OPEN_FILES // (18) Number of open files > _FS_SHARE
|
||||
} FRESULT;
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* FatFs module application interface */
|
||||
|
||||
FRESULT f_mount (BYTE, FATFS*); /* Mount/Unmount a logical drive */
|
||||
FRESULT f_open (FIL*, const TCHAR*, BYTE); /* Open or create a file */
|
||||
FRESULT f_read (FIL*, void*, UINT, UINT*); /* Read data from a file */
|
||||
FRESULT f_lseek (FIL*, DWORD); /* Move file pointer of a file object */
|
||||
FRESULT f_close (FIL*); /* Close an open file object */
|
||||
FRESULT f_opendir (DIR*, const TCHAR*); /* Open an existing directory */
|
||||
FRESULT f_readdir (DIR*, FILINFO*); /* Read a directory item */
|
||||
FRESULT f_stat (const TCHAR*, FILINFO*); /* Get file status */
|
||||
|
||||
#if !_FS_READONLY
|
||||
FRESULT f_write (FIL*, const void*, UINT, UINT*); /* Write data to a file */
|
||||
FRESULT f_getfree (const TCHAR*, DWORD*, FATFS**); /* Get number of free clusters on the drive */
|
||||
FRESULT f_truncate (FIL*); /* Truncate file */
|
||||
FRESULT f_sync (FIL*); /* Flush cached data of a writing file */
|
||||
FRESULT f_unlink (const TCHAR*); /* Delete an existing file or directory */
|
||||
FRESULT f_mkdir (const TCHAR*); /* Create a new directory */
|
||||
FRESULT f_chmod (const TCHAR*, BYTE, BYTE); /* Change attriburte of the file/dir */
|
||||
FRESULT f_utime (const TCHAR*, const FILINFO*); /* Change timestamp of the file/dir */
|
||||
FRESULT f_rename (const TCHAR*, const TCHAR*); /* Rename/Move a file or directory */
|
||||
#endif
|
||||
|
||||
#if _USE_FORWARD
|
||||
FRESULT f_forward (FIL*, UINT(*)(const BYTE*,UINT), UINT, UINT*); /* Forward data to the stream */
|
||||
#endif
|
||||
|
||||
#if _USE_MKFS
|
||||
FRESULT f_mkfs (BYTE, BYTE, UINT); /* Create a file system on the drive */
|
||||
#endif
|
||||
|
||||
#if _FS_RPATH
|
||||
FRESULT f_chdrive (BYTE); /* Change current drive */
|
||||
FRESULT f_chdir (const TCHAR*); /* Change current directory */
|
||||
FRESULT f_getcwd (TCHAR*, UINT); /* Get current directory */
|
||||
#endif
|
||||
|
||||
#if _USE_STRFUNC
|
||||
int f_putc (TCHAR, FIL*); /* Put a character to the file */
|
||||
int f_puts (const TCHAR*, FIL*); /* Put a string to the file */
|
||||
int f_printf (FIL*, const TCHAR*, ...); /* Put a formatted string to the file */
|
||||
TCHAR* f_gets (TCHAR*, int, FIL*); /* Get a string from the file */
|
||||
#ifndef EOF
|
||||
#define EOF (-1)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define f_eof(fp) (((fp)->fptr == (fp)->fsize) ? 1 : 0)
|
||||
#define f_error(fp) (((fp)->flag & FA__ERROR) ? 1 : 0)
|
||||
#define f_tell(fp) ((fp)->fptr)
|
||||
#define f_size(fp) ((fp)->fsize)
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Additional user defined functions */
|
||||
|
||||
/* RTC function */
|
||||
#if !_FS_READONLY
|
||||
extern DWORD get_fattime (void); /* Returns 32-bit packed date and time */
|
||||
#endif
|
||||
|
||||
/* Unicode support functions */
|
||||
#if _USE_LFN /* Unicode - OEM code conversion */
|
||||
WCHAR ff_convert (WCHAR, UINT); /* OEM-Unicode bidirectional conversion */
|
||||
WCHAR ff_wtoupper (WCHAR); /* Unicode upper-case conversion */
|
||||
#if _USE_LFN == 3 /* Memory functions */
|
||||
void* ff_memalloc (UINT); /* Allocate memory block */
|
||||
void ff_memfree (void*); /* Free memory block */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Sync functions */
|
||||
#if _FS_REENTRANT
|
||||
int ff_cre_syncobj (BYTE, _SYNC_t*);/* Create a sync object */
|
||||
int ff_del_syncobj (_SYNC_t); /* Delete a sync object */
|
||||
int ff_req_grant (_SYNC_t); /* Lock sync object */
|
||||
void ff_rel_grant (_SYNC_t); /* Unlock sync object */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Flags and offset address */
|
||||
|
||||
|
||||
/* File access control and file status flags (FIL.flag) */
|
||||
|
||||
#define FA_READ 0x01
|
||||
#define FA_OPEN_EXISTING 0x00
|
||||
#define FA__ERROR 0x80
|
||||
|
||||
#if !_FS_READONLY
|
||||
#define FA_WRITE 0x02
|
||||
#define FA_CREATE_NEW 0x04
|
||||
#define FA_CREATE_ALWAYS 0x08
|
||||
#define FA_OPEN_ALWAYS 0x10
|
||||
#define FA__WRITTEN 0x20
|
||||
#define FA__DIRTY 0x40
|
||||
#endif
|
||||
|
||||
|
||||
/* FAT sub type (FATFS.fs_type) */
|
||||
|
||||
#define FS_FAT12 1
|
||||
#define FS_FAT16 2
|
||||
#define FS_FAT32 3
|
||||
|
||||
|
||||
/* File attribute bits for directory entry */
|
||||
|
||||
#define AM_RDO 0x01 /* Read only */
|
||||
#define AM_HID 0x02 /* Hidden */
|
||||
#define AM_SYS 0x04 /* System */
|
||||
#define AM_VOL 0x08 /* Volume label */
|
||||
#define AM_LFN 0x0F /* LFN entry */
|
||||
#define AM_DIR 0x10 /* Directory */
|
||||
#define AM_ARC 0x20 /* Archive */
|
||||
#define AM_MASK 0x3F /* Mask of defined bits */
|
||||
|
||||
|
||||
/* Fast seek function */
|
||||
#define CREATE_LINKMAP 0xFFFFFFFF
|
||||
|
||||
|
||||
/*--------------------------------*/
|
||||
/* Multi-byte word access macros */
|
||||
|
||||
#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */
|
||||
#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr))
|
||||
#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr))
|
||||
#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val)
|
||||
#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val)
|
||||
#else /* Use byte-by-byte access to the FAT structure */
|
||||
#define LD_WORD(ptr) (WORD)(((WORD)*(BYTE*)((ptr)+1)<<8)|(WORD)*(BYTE*)(ptr))
|
||||
#define LD_DWORD(ptr) (DWORD)(((DWORD)*(BYTE*)((ptr)+3)<<24)|((DWORD)*(BYTE*)((ptr)+2)<<16)|((WORD)*(BYTE*)((ptr)+1)<<8)|*(BYTE*)(ptr))
|
||||
#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *(BYTE*)((ptr)+1)=(BYTE)((WORD)(val)>>8)
|
||||
#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *(BYTE*)((ptr)+1)=(BYTE)((WORD)(val)>>8); *(BYTE*)((ptr)+2)=(BYTE)((DWORD)(val)>>16); *(BYTE*)((ptr)+3)=(BYTE)((DWORD)(val)>>24)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FATFS */
|
188
src/ffconf.h
Normal file
188
src/ffconf.h
Normal file
|
@ -0,0 +1,188 @@
|
|||
/*---------------------------------------------------------------------------/
|
||||
/ FatFs - FAT file system module configuration file R0.08a (C)ChaN, 2010
|
||||
/----------------------------------------------------------------------------/
|
||||
/
|
||||
/ CAUTION! Do not forget to make clean the project after any changes to
|
||||
/ the configuration options.
|
||||
/
|
||||
/----------------------------------------------------------------------------*/
|
||||
#ifndef _FFCONF
|
||||
#define _FFCONF 8255 /* Revision ID */
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Function and Buffer Configurations
|
||||
/----------------------------------------------------------------------------*/
|
||||
|
||||
#define _FS_TINY 1 /* 0:Normal or 1:Tiny */
|
||||
/* When _FS_TINY is set to 1, FatFs uses the sector buffer in the file system
|
||||
/ object instead of the sector buffer in the individual file object for file
|
||||
/ data transfer. This reduces memory consumption 512 bytes each file object. */
|
||||
|
||||
|
||||
#define _FS_READONLY 0 /* 0:Read/Write or 1:Read only */
|
||||
/* Setting _FS_READONLY to 1 defines read only configuration. This removes
|
||||
/ writing functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename,
|
||||
/ f_truncate and useless f_getfree. */
|
||||
|
||||
|
||||
#define _FS_MINIMIZE 0 /* 0 to 3 */
|
||||
/* The _FS_MINIMIZE option defines minimization level to remove some functions.
|
||||
/
|
||||
/ 0: Full function.
|
||||
/ 1: f_stat, f_getfree, f_unlink, f_mkdir, f_chmod, f_truncate and f_rename
|
||||
/ are removed.
|
||||
/ 2: f_opendir and f_readdir are removed in addition to 1.
|
||||
/ 3: f_lseek is removed in addition to 2. */
|
||||
|
||||
|
||||
#define _USE_STRFUNC 1 /* 0:Disable or 1/2:Enable */
|
||||
/* To enable string functions, set _USE_STRFUNC to 1 or 2. */
|
||||
|
||||
|
||||
#define _USE_MKFS 1 /* 0:Disable or 1:Enable */
|
||||
/* To enable f_mkfs function, set _USE_MKFS to 1 and set _FS_READONLY to 0 */
|
||||
|
||||
|
||||
#define _USE_FORWARD 0 /* 0:Disable or 1:Enable */
|
||||
/* To enable f_forward function, set _USE_FORWARD to 1 and set _FS_TINY to 1. */
|
||||
|
||||
|
||||
#define _USE_FASTSEEK 0 /* 0:Disable or 1:Enable */
|
||||
/* To enable fast seek feature, set _USE_FASTSEEK to 1. */
|
||||
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Locale and Namespace Configurations
|
||||
/----------------------------------------------------------------------------*/
|
||||
|
||||
#define _CODE_PAGE 932
|
||||
/* The _CODE_PAGE specifies the OEM code page to be used on the target system.
|
||||
/ Incorrect setting of the code page can cause a file open failure.
|
||||
/
|
||||
/ 932 - Japanese Shift-JIS (DBCS, OEM, Windows)
|
||||
/ 936 - Simplified Chinese GBK (DBCS, OEM, Windows)
|
||||
/ 949 - Korean (DBCS, OEM, Windows)
|
||||
/ 950 - Traditional Chinese Big5 (DBCS, OEM, Windows)
|
||||
/ 1250 - Central Europe (Windows)
|
||||
/ 1251 - Cyrillic (Windows)
|
||||
/ 1252 - Latin 1 (Windows)
|
||||
/ 1253 - Greek (Windows)
|
||||
/ 1254 - Turkish (Windows)
|
||||
/ 1255 - Hebrew (Windows)
|
||||
/ 1256 - Arabic (Windows)
|
||||
/ 1257 - Baltic (Windows)
|
||||
/ 1258 - Vietnam (OEM, Windows)
|
||||
/ 437 - U.S. (OEM)
|
||||
/ 720 - Arabic (OEM)
|
||||
/ 737 - Greek (OEM)
|
||||
/ 775 - Baltic (OEM)
|
||||
/ 850 - Multilingual Latin 1 (OEM)
|
||||
/ 858 - Multilingual Latin 1 + Euro (OEM)
|
||||
/ 852 - Latin 2 (OEM)
|
||||
/ 855 - Cyrillic (OEM)
|
||||
/ 866 - Russian (OEM)
|
||||
/ 857 - Turkish (OEM)
|
||||
/ 862 - Hebrew (OEM)
|
||||
/ 874 - Thai (OEM, Windows)
|
||||
/ 1 - ASCII only (Valid for non LFN cfg.)
|
||||
*/
|
||||
|
||||
|
||||
#define _USE_LFN 0 /* 0 to 3 */
|
||||
#define _MAX_LFN 255 /* Maximum LFN length to handle (12 to 255) */
|
||||
/* The _USE_LFN option switches the LFN support.
|
||||
/
|
||||
/ 0: Disable LFN feature. _MAX_LFN and _LFN_UNICODE have no effect.
|
||||
/ 1: Enable LFN with static working buffer on the BSS. Always NOT reentrant.
|
||||
/ 2: Enable LFN with dynamic working buffer on the STACK.
|
||||
/ 3: Enable LFN with dynamic working buffer on the HEAP.
|
||||
/
|
||||
/ The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. To enable LFN,
|
||||
/ Unicode handling functions ff_convert() and ff_wtoupper() must be added
|
||||
/ to the project. When enable to use heap, memory control functions
|
||||
/ ff_memalloc() and ff_memfree() must be added to the project. */
|
||||
|
||||
|
||||
#define _LFN_UNICODE 0 /* 0:ANSI/OEM or 1:Unicode */
|
||||
/* To switch the character code set on FatFs API to Unicode,
|
||||
/ enable LFN feature and set _LFN_UNICODE to 1. */
|
||||
|
||||
|
||||
#define _FS_RPATH 2 /* 0 to 2 */
|
||||
/* The _FS_RPATH option configures relative path feature.
|
||||
/
|
||||
/ 0: Disable relative path feature and remove related functions.
|
||||
/ 1: Enable relative path. f_chdrive() and f_chdir() are available.
|
||||
/ 2: f_getcwd() is available in addition to 1.
|
||||
/
|
||||
/ Note that output of the f_readdir fnction is affected by this option. */
|
||||
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Physical Drive Configurations
|
||||
/----------------------------------------------------------------------------*/
|
||||
|
||||
#define _VOLUMES 1
|
||||
/* Number of volumes (logical drives) to be used. */
|
||||
|
||||
|
||||
#define _MAX_SS 512 /* 512, 1024, 2048 or 4096 */
|
||||
/* Maximum sector size to be handled.
|
||||
/ Always set 512 for memory card and hard disk but a larger value may be
|
||||
/ required for floppy disk (512/1024) and optical disk (512/2048).
|
||||
/ When _MAX_SS is larger than 512, GET_SECTOR_SIZE command must be implememted
|
||||
/ to the disk_ioctl function. */
|
||||
|
||||
|
||||
#define _MULTI_PARTITION 0 /* 0:Single partition or 1:Multiple partition */
|
||||
/* When set to 0, each volume is bound to the same physical drive number and
|
||||
/ it can mount only first primaly partition. When it is set to 1, each volume
|
||||
/ is tied to the partitions listed in VolToPart[]. */
|
||||
|
||||
|
||||
#define _USE_ERASE 0 /* 0:Disable or 1:Enable */
|
||||
/* To enable sector erase feature, set _USE_ERASE to 1. */
|
||||
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ System Configurations
|
||||
/----------------------------------------------------------------------------*/
|
||||
|
||||
#define _WORD_ACCESS 0 /* 0 or 1 */
|
||||
/* Set 0 first and it is always compatible with all platforms. The _WORD_ACCESS
|
||||
/ option defines which access method is used to the word data on the FAT volume.
|
||||
/
|
||||
/ 0: Byte-by-byte access.
|
||||
/ 1: Word access. Do not choose this unless following condition is met.
|
||||
/
|
||||
/ When the byte order on the memory is big-endian or address miss-aligned word
|
||||
/ access results incorrect behavior, the _WORD_ACCESS must be set to 0.
|
||||
/ If it is not the case, the value can also be set to 1 to improve the
|
||||
/ performance and code size. */
|
||||
|
||||
|
||||
/* Include a header file here to define sync object types on the O/S */
|
||||
/* #include <windows.h>, <ucos_ii.h.h>, <semphr.h> or ohters. */
|
||||
|
||||
#define _FS_REENTRANT 0 /* 0:Disable or 1:Enable */
|
||||
#define _FS_TIMEOUT 1000 /* Timeout period in unit of time ticks */
|
||||
#define _SYNC_t HANDLE /* O/S dependent type of sync object. e.g. HANDLE, OS_EVENT*, ID and etc.. */
|
||||
|
||||
/* The _FS_REENTRANT option switches the reentrancy of the FatFs module.
|
||||
/
|
||||
/ 0: Disable reentrancy. _SYNC_t and _FS_TIMEOUT have no effect.
|
||||
/ 1: Enable reentrancy. Also user provided synchronization handlers,
|
||||
/ ff_req_grant, ff_rel_grant, ff_del_syncobj and ff_cre_syncobj
|
||||
/ function must be added to the project. */
|
||||
|
||||
|
||||
#define _FS_SHARE 0 /* 0:Disable or >=1:Enable */
|
||||
/* To enable file shareing feature, set _FS_SHARE to 1 or greater. The value
|
||||
defines how many files can be opened simultaneously. */
|
||||
|
||||
|
||||
#endif /* _FFCONFIG */
|
682
src/file.cpp
Normal file
682
src/file.cpp
Normal file
|
@ -0,0 +1,682 @@
|
|||
/*
|
||||
*
|
||||
* gruvin9x Author Bryan J.Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
*
|
||||
* gruvin9x is based on code named er9x by
|
||||
* Author - Erez Raviv <erezraviv@gmail.com>, which is in turn
|
||||
* based on 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 "gruvin9x.h"
|
||||
#include "stdio.h"
|
||||
#include "inttypes.h"
|
||||
#include "string.h"
|
||||
|
||||
uint8_t s_write_err = 0; // error reasons
|
||||
#ifdef ASYNC_WRITE
|
||||
uint8_t s_sync_write = false;
|
||||
#endif
|
||||
|
||||
#define RESV 64 //reserv for eeprom header with directory (eeFs)
|
||||
#define FIRSTBLK (RESV/BS)
|
||||
#define BLOCKS (EESIZE/BS)
|
||||
|
||||
#define EEFS_VERS 4
|
||||
struct DirEnt{
|
||||
uint8_t startBlk;
|
||||
uint16_t size:12;
|
||||
uint16_t typ:4;
|
||||
}__attribute__((packed));
|
||||
#define MAXFILES (1+MAX_MODELS+3)
|
||||
struct EeFs{
|
||||
uint8_t version;
|
||||
uint8_t mySize;
|
||||
uint8_t freeList;
|
||||
uint8_t bs;
|
||||
DirEnt files[MAXFILES];
|
||||
}__attribute__((packed)) eeFs;
|
||||
|
||||
|
||||
static uint8_t EeFsRead(uint8_t blk,uint8_t ofs){
|
||||
uint8_t ret;
|
||||
eeprom_read_block(&ret,(const void*)(blk*BS+ofs),1);
|
||||
return ret;
|
||||
}
|
||||
static void EeFsWrite(uint8_t blk,uint8_t ofs,uint8_t val){
|
||||
eeWriteBlockCmp(&val, (void*)(blk*BS+ofs), 1);
|
||||
}
|
||||
|
||||
static uint8_t EeFsGetLink(uint8_t blk){
|
||||
return EeFsRead( blk,0);
|
||||
}
|
||||
static void EeFsSetLink(uint8_t blk,uint8_t val){
|
||||
EeFsWrite( blk,0,val);
|
||||
}
|
||||
static uint8_t EeFsGetDat(uint8_t blk,uint8_t ofs){
|
||||
return EeFsRead( blk,ofs+1);
|
||||
}
|
||||
static void EeFsSetDat(uint8_t blk,uint8_t ofs,uint8_t*buf,uint8_t len){
|
||||
//EeFsWrite( blk,ofs+1,val);
|
||||
eeWriteBlockCmp(buf, (void*)(blk*BS+ofs+1), len);
|
||||
}
|
||||
static void EeFsFlushFreelist()
|
||||
{
|
||||
eeWriteBlockCmp(&eeFs.freeList,&((EeFs*)0)->freeList ,sizeof(eeFs.freeList));
|
||||
}
|
||||
static void EeFsFlush()
|
||||
{
|
||||
eeWriteBlockCmp(&eeFs, 0,sizeof(eeFs));
|
||||
}
|
||||
|
||||
uint16_t EeFsGetFree()
|
||||
{
|
||||
uint16_t ret = 0;
|
||||
uint8_t i = eeFs.freeList;
|
||||
while( i ){
|
||||
ret += BS-1;
|
||||
i = EeFsGetLink(i);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// #ifndef ASYNC_WRITE TODO because duplicate code
|
||||
static void EeFsFree(uint8_t blk){///free one or more blocks
|
||||
uint8_t i = blk;
|
||||
while( EeFsGetLink(i)) i = EeFsGetLink(i);
|
||||
EeFsSetLink(i,eeFs.freeList);
|
||||
eeFs.freeList = blk; //chain in front
|
||||
EeFsFlushFreelist();
|
||||
}
|
||||
// #endif
|
||||
|
||||
#ifndef ASYNC_WRITE
|
||||
static uint8_t EeFsAlloc(){ ///alloc one block from freelist
|
||||
uint8_t ret=eeFs.freeList;
|
||||
if(ret){
|
||||
eeFs.freeList = EeFsGetLink(ret);
|
||||
EeFsFlushFreelist();
|
||||
EeFsSetLink(ret,0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
int8_t EeFsck()
|
||||
{
|
||||
#ifdef ASYNC_WRITE
|
||||
s_sync_write = true;
|
||||
#endif
|
||||
|
||||
uint8_t *bufp;
|
||||
static uint8_t buffer[BLOCKS];
|
||||
bufp = buffer;
|
||||
memset(bufp,0,BLOCKS);
|
||||
uint8_t blk ;
|
||||
int8_t ret=0;
|
||||
|
||||
for(uint8_t i = 0; i <= MAXFILES; i++){
|
||||
uint8_t *startP = i==MAXFILES ? &eeFs.freeList : &eeFs.files[i].startBlk;
|
||||
uint8_t lastBlk = 0;
|
||||
blk = *startP;
|
||||
while(blk){
|
||||
if( ( blk < FIRSTBLK ) //goto err_1; //bad blk index
|
||||
|| (blk >= BLOCKS ) //goto err_2; //bad blk index
|
||||
|| (bufp[blk] ))//goto err_3; //blk double usage
|
||||
{
|
||||
if(lastBlk){
|
||||
EeFsSetLink(lastBlk,0);
|
||||
}else{
|
||||
*startP = 0; //interrupt chain at startpos
|
||||
EeFsFlush();
|
||||
}
|
||||
blk=0; //abort
|
||||
}else{
|
||||
bufp[blk] = i+1;
|
||||
lastBlk = blk;
|
||||
blk = EeFsGetLink(blk);
|
||||
}
|
||||
}
|
||||
}
|
||||
for(blk = FIRSTBLK; blk < BLOCKS; blk++){
|
||||
if(bufp[blk]==0) { //goto err_4; //unused block
|
||||
EeFsSetLink(blk,eeFs.freeList);
|
||||
eeFs.freeList = blk; //chain in front
|
||||
EeFsFlushFreelist();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ASYNC_WRITE
|
||||
s_sync_write = false;
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void EeFsFormat()
|
||||
{
|
||||
#ifdef ASYNC_WRITE
|
||||
s_sync_write = true;
|
||||
#endif
|
||||
if(sizeof(eeFs) != RESV){
|
||||
extern void eeprom_RESV_mismatch();
|
||||
eeprom_RESV_mismatch();
|
||||
}
|
||||
memset(&eeFs,0, sizeof(eeFs));
|
||||
eeFs.version = EEFS_VERS;
|
||||
eeFs.mySize = sizeof(eeFs);
|
||||
eeFs.freeList = 0;
|
||||
eeFs.bs = BS;
|
||||
for(uint8_t i = FIRSTBLK; i < BLOCKS; i++) EeFsSetLink(i,i+1);
|
||||
EeFsSetLink(BLOCKS-1, 0);
|
||||
eeFs.freeList = FIRSTBLK;
|
||||
EeFsFlush();
|
||||
#ifdef ASYNC_WRITE
|
||||
s_sync_write = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool EeFsOpen()
|
||||
{
|
||||
eeprom_read_block(&eeFs,0,sizeof(eeFs));
|
||||
#ifdef SIMU
|
||||
if(eeFs.version != EEFS_VERS) printf("bad eeFs.version\n");
|
||||
if(eeFs.mySize != sizeof(eeFs)) printf("bad eeFs.mySize\n");
|
||||
#endif
|
||||
|
||||
return eeFs.version == EEFS_VERS && eeFs.mySize == sizeof(eeFs);
|
||||
}
|
||||
|
||||
bool EFile::exists(uint8_t i_fileId)
|
||||
{
|
||||
return eeFs.files[i_fileId].startBlk;
|
||||
}
|
||||
|
||||
void EFile::swap(uint8_t i_fileId1, uint8_t i_fileId2)
|
||||
{
|
||||
DirEnt tmp = eeFs.files[i_fileId1];
|
||||
eeFs.files[i_fileId1] = eeFs.files[i_fileId2];
|
||||
eeFs.files[i_fileId2] = tmp;
|
||||
EeFsFlush();
|
||||
}
|
||||
|
||||
void EFile::rm(uint8_t i_fileId)
|
||||
{
|
||||
#ifdef ASYNC_WRITE
|
||||
s_sync_write = true;
|
||||
#endif
|
||||
uint8_t i = eeFs.files[i_fileId].startBlk;
|
||||
memset(&eeFs.files[i_fileId], 0, sizeof(eeFs.files[i_fileId]));
|
||||
EeFsFlush(); //chained out
|
||||
|
||||
if(i) EeFsFree( i ); //chain in
|
||||
#ifdef ASYNC_WRITE
|
||||
s_sync_write = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t EFile::size(){
|
||||
return eeFs.files[m_fileId].size;
|
||||
}
|
||||
|
||||
|
||||
// G: Open file ID for reading. Return the file's type
|
||||
void EFile::openRd(uint8_t i_fileId){
|
||||
m_fileId = i_fileId;
|
||||
m_pos = 0;
|
||||
m_currBlk = eeFs.files[m_fileId].startBlk;
|
||||
m_ofs = 0;
|
||||
s_write_err = ERR_NONE; // error reasons */
|
||||
}
|
||||
|
||||
void RlcFile::openRlc(uint8_t i_fileId)
|
||||
{
|
||||
EFile::openRd(i_fileId);
|
||||
m_zeroes = 0;
|
||||
m_bRlc = 0;
|
||||
}
|
||||
|
||||
uint8_t EFile::read(uint8_t*buf,uint16_t i_len){
|
||||
uint16_t len = eeFs.files[m_fileId].size - m_pos;
|
||||
if(len < i_len) i_len = len;
|
||||
len = i_len;
|
||||
while(len)
|
||||
{
|
||||
if(!m_currBlk) break;
|
||||
*buf++ = EeFsGetDat(m_currBlk, m_ofs++);
|
||||
if(m_ofs>=(BS-1)){
|
||||
m_ofs=0;
|
||||
m_currBlk=EeFsGetLink(m_currBlk);
|
||||
}
|
||||
len--;
|
||||
}
|
||||
m_pos += i_len - len;
|
||||
return i_len - len;
|
||||
}
|
||||
|
||||
// G: Read runlength (RLE) compressed bytes into buf.
|
||||
#ifdef TRANSLATIONS
|
||||
uint16_t RlcFile::readRlc12(uint8_t*buf,uint16_t i_len, bool rlc2)
|
||||
#else
|
||||
uint16_t RlcFile::readRlc(uint8_t*buf,uint16_t i_len)
|
||||
#endif
|
||||
{
|
||||
uint16_t i=0;
|
||||
for( ; 1; ){
|
||||
uint8_t l=min<uint16_t>(m_zeroes,i_len-i);
|
||||
memset(&buf[i],0,l);
|
||||
i += l;
|
||||
m_zeroes -= l;
|
||||
if(m_zeroes) break;
|
||||
|
||||
l=min<uint16_t>(m_bRlc,i_len-i);
|
||||
uint8_t lr = read(&buf[i],l);
|
||||
i += lr ;
|
||||
m_bRlc -= lr;
|
||||
if(m_bRlc) break;
|
||||
|
||||
if(read(&m_bRlc,1)!=1) break; //read how many bytes to read
|
||||
|
||||
assert(m_bRlc & 0x7f);
|
||||
#ifdef TRANSLATIONS
|
||||
if (rlc2) {
|
||||
#endif
|
||||
if(m_bRlc&0x80){ // if contains high byte
|
||||
m_zeroes =(m_bRlc>>4) & 0x7;
|
||||
m_bRlc = m_bRlc & 0x0f;
|
||||
}
|
||||
else if(m_bRlc&0x40){
|
||||
m_zeroes = m_bRlc & 0x3f;
|
||||
m_bRlc = 0;
|
||||
}
|
||||
//else m_bRlc
|
||||
#ifdef TRANSLATIONS
|
||||
}
|
||||
else {
|
||||
if(m_bRlc&0x80){ // if contains high byte
|
||||
m_zeroes = m_bRlc & 0x7f;
|
||||
m_bRlc = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
#ifdef ASYNC_WRITE
|
||||
|
||||
void RlcFile::write1(uint8_t b)
|
||||
{
|
||||
m_write1_byte = b;
|
||||
write(&m_write1_byte, 1);
|
||||
}
|
||||
|
||||
void RlcFile::write(uint8_t *buf, uint8_t i_len)
|
||||
{
|
||||
m_write_len = i_len;
|
||||
m_write_buf = buf;
|
||||
|
||||
do {
|
||||
nextWriteStep();
|
||||
} while (s_sync_write && m_write_len && !s_write_err);
|
||||
}
|
||||
|
||||
void RlcFile::nextWriteStep()
|
||||
{
|
||||
if(!m_currBlk && m_pos==0)
|
||||
{
|
||||
eeFs.files[FILE_TMP].startBlk = m_currBlk = eeFs.freeList;
|
||||
if (m_currBlk) {
|
||||
eeFs.freeList = EeFsGetLink(m_currBlk);
|
||||
m_write_step = WRITE_START_STEP + WRITE_FIRST_LINK;
|
||||
EeFsFlushFreelist();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (m_write_step == WRITE_START_STEP + WRITE_FIRST_LINK) {
|
||||
m_write_step = WRITE_START_STEP;
|
||||
EeFsSetLink(m_currBlk, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
while (m_write_len) {
|
||||
if (!m_currBlk) {
|
||||
s_write_err = ERR_FULL;
|
||||
break;
|
||||
}
|
||||
if (m_ofs >= (BS-1)) {
|
||||
m_ofs = 0;
|
||||
if (!EeFsGetLink(m_currBlk)) {
|
||||
if (!eeFs.freeList) {
|
||||
s_write_err = ERR_FULL;
|
||||
break;
|
||||
}
|
||||
m_write_step += WRITE_NEXT_LINK_1; // TODO review all these names
|
||||
EeFsSetLink(m_currBlk, eeFs.freeList);
|
||||
return;
|
||||
}
|
||||
m_currBlk = EeFsGetLink(m_currBlk);
|
||||
}
|
||||
switch (m_write_step & 0x0f) {
|
||||
case WRITE_NEXT_LINK_1:
|
||||
m_currBlk = eeFs.freeList;
|
||||
eeFs.freeList = EeFsGetLink(eeFs.freeList);
|
||||
m_write_step += 1;
|
||||
EeFsFlushFreelist();
|
||||
return;
|
||||
case WRITE_NEXT_LINK_2:
|
||||
m_write_step -= WRITE_NEXT_LINK_2;
|
||||
EeFsSetLink(m_currBlk, 0); // TODO needed?
|
||||
return;
|
||||
}
|
||||
if (!m_currBlk) { // TODO needed?
|
||||
s_write_err = ERR_FULL;
|
||||
break;
|
||||
}
|
||||
uint8_t tmp = BS-1-m_ofs; if(tmp>m_write_len) tmp=m_write_len;
|
||||
m_write_buf += tmp;
|
||||
m_write_len -= tmp;
|
||||
m_ofs += tmp;
|
||||
m_pos += tmp;
|
||||
EeFsSetDat(m_currBlk, m_ofs-tmp, m_write_buf-tmp, tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (s_write_err == ERR_FULL) {
|
||||
alert(PSTR("EEPROM overflow"));
|
||||
m_write_step = 0;
|
||||
m_write_len = 0;
|
||||
}
|
||||
|
||||
if (!s_sync_write)
|
||||
nextRlcWriteStep();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
uint8_t RlcFile::write1(uint8_t b)
|
||||
{
|
||||
return write(&b,1);
|
||||
}
|
||||
|
||||
uint8_t RlcFile::write(uint8_t*buf, uint8_t i_len)
|
||||
{
|
||||
uint8_t len=i_len;
|
||||
if(!m_currBlk && m_pos==0)
|
||||
{
|
||||
eeFs.files[m_fileId].startBlk = m_currBlk = EeFsAlloc();
|
||||
}
|
||||
while(len)
|
||||
{
|
||||
#ifndef SIMU
|
||||
if( (int16_t)(m_stopTime10ms - get_tmr10ms()) < 0)
|
||||
{
|
||||
s_write_err = ERR_TMO;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if(!m_currBlk) {
|
||||
s_write_err = ERR_FULL;
|
||||
break;
|
||||
}
|
||||
if(m_ofs>=(BS-1)){
|
||||
m_ofs=0;
|
||||
if( ! EeFsGetLink(m_currBlk) ){
|
||||
EeFsSetLink(m_currBlk, EeFsAlloc());
|
||||
}
|
||||
m_currBlk = EeFsGetLink(m_currBlk);
|
||||
}
|
||||
if(!m_currBlk) {
|
||||
s_write_err = ERR_FULL;
|
||||
break;
|
||||
}
|
||||
uint8_t l = BS-1-m_ofs; if(l>len) l=len;
|
||||
EeFsSetDat(m_currBlk, m_ofs, buf, l);
|
||||
buf +=l;
|
||||
m_ofs +=l;
|
||||
len -=l;
|
||||
}
|
||||
m_pos += i_len - len;
|
||||
return i_len - len;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef ASYNC_WRITE
|
||||
|
||||
void RlcFile::create(uint8_t i_fileId, uint8_t typ, uint8_t sync_write)
|
||||
{
|
||||
// all write operations will be executed on FILE_TMP
|
||||
openRlc(FILE_TMP); // internal use
|
||||
eeFs.files[FILE_TMP].typ = typ;
|
||||
eeFs.files[FILE_TMP].size = 0;
|
||||
m_fileId = i_fileId;
|
||||
s_sync_write = sync_write;
|
||||
}
|
||||
|
||||
void RlcFile::writeRlc(uint8_t i_fileId, uint8_t typ, uint8_t*buf, uint16_t i_len, uint8_t sync_write)
|
||||
{
|
||||
create(i_fileId, typ, sync_write);
|
||||
|
||||
m_write_step = WRITE_START_STEP;
|
||||
m_rlc_buf = buf;
|
||||
m_rlc_len = i_len;
|
||||
m_cur_rlc_len = 0;
|
||||
|
||||
do {
|
||||
nextRlcWriteStep();
|
||||
} while (s_sync_write && m_write_step && !s_write_err);
|
||||
}
|
||||
|
||||
void RlcFile::nextRlcWriteStep()
|
||||
{
|
||||
uint8_t cnt = 1;
|
||||
uint8_t cnt0 = 0;
|
||||
uint16_t i = 0;
|
||||
|
||||
if (m_cur_rlc_len) {
|
||||
uint8_t tmp1 = m_cur_rlc_len;
|
||||
uint8_t *tmp2 = m_rlc_buf;
|
||||
m_rlc_buf += m_cur_rlc_len;
|
||||
m_cur_rlc_len = 0;
|
||||
write(tmp2, tmp1);
|
||||
return;
|
||||
}
|
||||
|
||||
bool run0 = m_rlc_buf[0] == 0;
|
||||
|
||||
if(m_rlc_len==0) goto close;
|
||||
|
||||
for (i=1; 1; i++) // !! laeuft ein byte zu weit !!
|
||||
{
|
||||
bool cur0 = m_rlc_buf[i] == 0;
|
||||
if (cur0 != run0 || cnt==0x3f || (cnt0 && cnt==0xf)|| i==m_rlc_len){
|
||||
if (run0) {
|
||||
assert(cnt0==0);
|
||||
if (cnt<8 && i!=m_rlc_len)
|
||||
cnt0 = cnt; //aufbew fuer spaeter
|
||||
else {
|
||||
m_rlc_buf+=cnt;
|
||||
m_rlc_len-=cnt;
|
||||
write1(cnt|0x40);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else{
|
||||
m_rlc_buf+=cnt0;
|
||||
m_rlc_len-=cnt0+cnt;
|
||||
m_cur_rlc_len=cnt;
|
||||
if(cnt0){
|
||||
write1(0x80 | (cnt0<<4) | cnt);
|
||||
}
|
||||
else{
|
||||
write1(cnt);
|
||||
}
|
||||
return;
|
||||
}
|
||||
cnt=0;
|
||||
if (i==m_rlc_len) break;
|
||||
run0 = cur0;
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
|
||||
close:
|
||||
|
||||
switch(m_write_step) {
|
||||
case WRITE_START_STEP:
|
||||
{
|
||||
uint8_t fri=0;
|
||||
eeFs.files[FILE_TMP].size = m_pos;
|
||||
if (m_currBlk && ( fri = EeFsGetLink(m_currBlk))) {
|
||||
uint8_t prev_freeList = eeFs.freeList;
|
||||
eeFs.freeList = fri;
|
||||
while( EeFsGetLink(fri)) fri = EeFsGetLink(fri);
|
||||
m_write_step = WRITE_FREE_UNUSED_BLOCKS_STEP1;
|
||||
EeFsSetLink(fri, prev_freeList);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
case WRITE_FLUSH_STEP: // TODO could be avoided
|
||||
m_write_step = WRITE_SWAP_STEP;
|
||||
EeFsFlush(); //chained out
|
||||
return;
|
||||
|
||||
case WRITE_FREE_UNUSED_BLOCKS_STEP1:
|
||||
m_write_step = WRITE_FREE_UNUSED_BLOCKS_STEP2;
|
||||
EeFsSetLink(m_currBlk, 0);
|
||||
return;
|
||||
|
||||
case WRITE_FREE_UNUSED_BLOCKS_STEP2:
|
||||
m_write_step = WRITE_FLUSH_STEP;
|
||||
EeFsFlushFreelist();
|
||||
return;
|
||||
|
||||
case WRITE_SWAP_STEP:
|
||||
m_write_step = 0;
|
||||
EFile::swap(m_fileId, FILE_TMP);
|
||||
}
|
||||
}
|
||||
|
||||
void RlcFile::flush()
|
||||
{
|
||||
while (eeprom_buffer_size > 0);
|
||||
s_sync_write = true;
|
||||
while (theFile.m_write_len && !s_write_err)
|
||||
theFile.nextWriteStep();
|
||||
while (theFile.isWriting() && !s_write_err)
|
||||
theFile.nextRlcWriteStep();
|
||||
s_sync_write = false;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void RlcFile::create(uint8_t i_fileId, uint8_t typ, uint16_t maxTme10ms)
|
||||
{
|
||||
openRlc(i_fileId); //internal use
|
||||
eeFs.files[i_fileId].typ = typ;
|
||||
eeFs.files[i_fileId].size = 0;
|
||||
m_stopTime10ms = get_tmr10ms() + maxTme10ms;
|
||||
}
|
||||
|
||||
// G: Write runlength (RLE) compressed bytes
|
||||
uint16_t RlcFile::writeRlc(uint8_t i_fileId, uint8_t typ,uint8_t*buf,uint16_t i_len, uint8_t maxTme10ms){
|
||||
|
||||
create(i_fileId,typ,maxTme10ms);
|
||||
bool run0 = buf[0] == 0;
|
||||
uint8_t cnt = 1;
|
||||
uint8_t cnt0 = 0;
|
||||
uint16_t i = 0;
|
||||
if(i_len==0) goto close;
|
||||
|
||||
//RLE compression:
|
||||
//rb = read byte
|
||||
//if (rb | 0x80) write rb & 0x7F zeros
|
||||
//else write rb bytes
|
||||
for( i=1; 1 ; i++) // !! laeuft ein byte zu weit !!
|
||||
{
|
||||
bool cur0 = buf[i] == 0;
|
||||
if(cur0 != run0 || cnt==0x3f || (cnt0 && cnt==0xf)|| i==i_len){
|
||||
if(run0){
|
||||
assert(cnt0==0);
|
||||
if(cnt<8 && i!=i_len)
|
||||
cnt0 = cnt; //aufbew fuer spaeter
|
||||
else {
|
||||
if( write1(cnt|0x40)!=1) goto error;//-cnt&0x3f
|
||||
}
|
||||
}else{
|
||||
if(cnt0){
|
||||
if( write1(0x80 | (cnt0<<4) | cnt)!=1) goto error;//-cnt0xx-cnt
|
||||
cnt0 = 0;
|
||||
}else{
|
||||
if( write1(cnt) !=1) goto error;//-cnt
|
||||
}
|
||||
uint8_t ret=write(&buf[i-cnt],cnt);
|
||||
if( ret !=cnt) { cnt-=ret; goto error;}//-cnt
|
||||
}
|
||||
cnt=0;
|
||||
if(i==i_len) break;
|
||||
run0 = cur0;
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
if(0){
|
||||
error:
|
||||
i-=cnt+cnt0;
|
||||
#ifdef SIMU
|
||||
switch(s_write_err){
|
||||
default:
|
||||
case ERR_NONE:
|
||||
assert(!"missing errno");
|
||||
break;
|
||||
case ERR_FULL:
|
||||
printf("ERROR filesystem overflow! written: %d missing: %d\n",i,i_len-i);
|
||||
break;
|
||||
case ERR_TMO:
|
||||
printf("ERROR filesystem write timeout %d 0ms\n",(int16_t)(m_stopTime10ms - g_tmr10ms));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
close:
|
||||
close();
|
||||
return i;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// G: Close file and truncate at this blk. Add any remaining blocks to freeList chain
|
||||
void RlcFile::close()
|
||||
{
|
||||
uint8_t fri=0;
|
||||
|
||||
if(m_currBlk && ( fri = EeFsGetLink(m_currBlk))) EeFsSetLink(m_currBlk, 0);
|
||||
|
||||
#ifdef ASYNC_WRITE
|
||||
eeFs.files[FILE_TMP].size = m_pos;
|
||||
EFile::swap(m_fileId, FILE_TMP);
|
||||
#else
|
||||
eeFs.files[m_fileId].size = m_pos;
|
||||
EeFsFlush(); //chained out
|
||||
#endif
|
||||
|
||||
if(fri) EeFsFree( fri ); //chain in
|
||||
|
||||
#ifdef ASYNC_WRITE
|
||||
m_write_step = 0;
|
||||
s_sync_write = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
174
src/file.h
Normal file
174
src/file.h
Normal file
|
@ -0,0 +1,174 @@
|
|||
#ifndef file_h
|
||||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
*
|
||||
* gruvin9x is based on code named er9x by
|
||||
* Author - Erez Raviv <erezraviv@gmail.com>, which is in turn
|
||||
* was based on 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#define file_h
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
//
|
||||
// bs=16 128 blocks verlust link:128 16files:16*8 128 sum 256
|
||||
// bs=32 64 blocks verlust link: 64 16files:16*16 256 sum 320
|
||||
//
|
||||
#if defined(PCBV3)
|
||||
#define EESIZE 4096
|
||||
#define BS 32
|
||||
#else
|
||||
#define EESIZE 2048
|
||||
#define BS 16
|
||||
#endif
|
||||
|
||||
/// fileId of general file
|
||||
#define FILE_GENERAL 0
|
||||
/// convert model number 0..MAX_MODELS-1 int fileId
|
||||
#define FILE_MODEL(n) (1+n)
|
||||
#define FILE_TMP (1+16)
|
||||
|
||||
bool EeFsOpen();
|
||||
int8_t EeFsck();
|
||||
void EeFsFormat();
|
||||
uint16_t EeFsGetFree();
|
||||
|
||||
#ifdef ASYNC_WRITE
|
||||
extern volatile size_t eeprom_buffer_size;
|
||||
#endif
|
||||
|
||||
class EFile
|
||||
{
|
||||
public:
|
||||
|
||||
///remove contents of given file
|
||||
static void rm(uint8_t i_fileId);
|
||||
|
||||
///swap contents of file1 with them of file2
|
||||
static void swap(uint8_t i_fileId1,uint8_t i_fileId2);
|
||||
|
||||
///return true if the file with given fileid exists
|
||||
static bool exists(uint8_t i_fileId);
|
||||
|
||||
///return size of compressed file without block overhead
|
||||
uint16_t size(); // TODO static ?
|
||||
|
||||
///open file for reading, no close necessary
|
||||
void openRd(uint8_t i_fileId);
|
||||
|
||||
uint8_t read(uint8_t*buf, uint16_t i_len);
|
||||
|
||||
protected:
|
||||
|
||||
uint8_t m_fileId; //index of file in directory = filename
|
||||
uint16_t m_pos; //over all filepos
|
||||
uint8_t m_currBlk; //current block.id
|
||||
uint8_t m_ofs; //offset inside of the current block
|
||||
};
|
||||
|
||||
#define ERR_NONE 0
|
||||
#define ERR_FULL 1
|
||||
#ifndef ASYNC_WRITE
|
||||
#define ERR_TMO 2
|
||||
#endif
|
||||
extern uint8_t s_write_err; // error reasons
|
||||
extern uint8_t s_sync_write;
|
||||
|
||||
///deliver current errno, this is reset in open
|
||||
inline uint8_t errno() { return s_write_err; }
|
||||
|
||||
class RlcFile: public EFile
|
||||
{
|
||||
uint8_t m_bRlc; // control byte for run length decoder
|
||||
uint8_t m_zeroes;
|
||||
|
||||
#ifdef ASYNC_WRITE
|
||||
uint8_t m_flags;
|
||||
#define WRITE_FIRST_LINK 0x01
|
||||
#define WRITE_NEXT_LINK_1 0x02
|
||||
#define WRITE_NEXT_LINK_2 0x03
|
||||
#define WRITE_START_STEP 0x10
|
||||
#define WRITE_FREE_UNUSED_BLOCKS_STEP1 0x20
|
||||
#define WRITE_FREE_UNUSED_BLOCKS_STEP2 0x30
|
||||
#define WRITE_FLUSH_STEP 0x40
|
||||
#define WRITE_SWAP_STEP 0x50
|
||||
uint8_t m_write_step;
|
||||
|
||||
uint16_t m_rlc_len;
|
||||
uint8_t * m_rlc_buf;
|
||||
uint8_t m_cur_rlc_len;
|
||||
uint8_t m_write1_byte;
|
||||
uint8_t m_write_len;
|
||||
uint8_t * m_write_buf;
|
||||
#else
|
||||
uint16_t m_stopTime10ms; // maximum point of time for writing
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
void openRlc(uint8_t i_fileId);
|
||||
|
||||
|
||||
#ifdef ASYNC_WRITE
|
||||
void create(uint8_t i_fileId, uint8_t typ, uint8_t sync_write);
|
||||
inline bool isWriting() { return m_write_step != 0; }
|
||||
void write(uint8_t*buf, uint8_t i_len);
|
||||
void write1(uint8_t b);
|
||||
void nextWriteStep();
|
||||
void nextRlcWriteStep();
|
||||
void writeRlc(uint8_t i_fileId, uint8_t typ, uint8_t *buf, uint16_t i_len, uint8_t sync_write);
|
||||
void flush();
|
||||
#else
|
||||
/// create a new file with given fileId,
|
||||
/// !!! if this file already exists, then all blocks are reused
|
||||
/// and all contents will be overwritten.
|
||||
/// after writing close has to be called
|
||||
|
||||
void create(uint8_t i_fileId, uint8_t typ, uint16_t maxTme10ms);
|
||||
|
||||
uint8_t write(uint8_t*buf, uint8_t i_len);
|
||||
uint8_t write1(uint8_t b);
|
||||
///open file, write to file and close it.
|
||||
///If file existed before, then contents is overwritten.
|
||||
///If file was larger before, then unused blocks are freed
|
||||
uint16_t writeRlc(uint8_t i_fileId, uint8_t typ,uint8_t*buf,uint16_t i_len, uint8_t maxTme10ms);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* close file and truncate the blockchain if to long.
|
||||
*/
|
||||
void close();
|
||||
|
||||
///read from opened file and decode rlc-coded data
|
||||
#ifdef TRANSLATIONS
|
||||
uint16_t readRlc12(uint8_t*buf,uint16_t i_len,bool rlc2);
|
||||
inline uint16_t readRlc1(uint8_t*buf,uint16_t i_len)
|
||||
{
|
||||
return readRlc12(buf,i_len,false);
|
||||
}
|
||||
inline uint16_t readRlc(uint8_t*buf, uint16_t i_len)
|
||||
{
|
||||
return readRlc12(buf,i_len,true);
|
||||
}
|
||||
#else
|
||||
uint16_t readRlc(uint8_t*buf, uint16_t i_len); // TODO should be like writeRlc?
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
/*eof*/
|
9
src/font.lbm
Normal file
9
src/font.lbm
Normal file
|
@ -0,0 +1,9 @@
|
|||
prog_uchar APM font[] = {
|
||||
80,8,80,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6f,0x00,0x00,0x07,0x00,0x07,0x00,0x14,0x7f,0x14,0x7f,0x14,0x24,0x2a,0x7f,0x2a,0x12,0x23,0x13,0x08,0x64,0x62,0x36,0x49,0x55,0x22,0x50,0x00,0x05,0x03,0x00,0x00,0x00,0x1c,0x22,0x41,0x00,0x00,0x41,0x22,0x1c,0x00,0x14,0x08,0x3e,0x08,0x14,0x08,0x08,0x3e,0x08,0x08,0x00,0x50,0x30,0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x00,0x60,0x60,0x00,0x00,0x20,0x10,0x08,0x04,0x02,
|
||||
0x00,0x3e,0x41,0x41,0x3e,0x00,0x00,0x42,0x7f,0x40,0x00,0x62,0x51,0x49,0x46,0x00,0x41,0x49,0x49,0x36,0x00,0x18,0x14,0x12,0x7f,0x00,0x27,0x45,0x45,0x39,0x00,0x3e,0x49,0x49,0x32,0x00,0x01,0x79,0x05,0x03,0x00,0x36,0x49,0x49,0x36,0x00,0x06,0x49,0x29,0x1e,0x00,0x00,0x36,0x36,0x00,0x00,0x00,0x56,0x36,0x00,0x00,0x08,0x14,0x22,0x41,0x14,0x14,0x14,0x14,0x14,0x41,0x22,0x14,0x08,0x00,0x02,0x01,0x51,0x09,0x06,
|
||||
0x06,0x09,0x09,0x06,0x00,0x7e,0x09,0x09,0x09,0x7e,0x7f,0x49,0x49,0x49,0x36,0x3e,0x41,0x41,0x41,0x22,0x7f,0x41,0x41,0x22,0x1c,0x7f,0x49,0x49,0x49,0x41,0x7f,0x09,0x09,0x09,0x01,0x3e,0x41,0x49,0x49,0x7a,0x7f,0x08,0x08,0x08,0x7f,0x00,0x41,0x7f,0x41,0x00,0x20,0x40,0x41,0x3f,0x01,0x7f,0x08,0x14,0x22,0x41,0x7f,0x40,0x40,0x40,0x40,0x7f,0x02,0x0c,0x02,0x7f,0x7f,0x04,0x08,0x10,0x7f,0x3e,0x41,0x41,0x41,0x3e,
|
||||
0x7f,0x09,0x09,0x09,0x06,0x3e,0x41,0x51,0x21,0x5e,0x7f,0x09,0x19,0x29,0x46,0x26,0x49,0x49,0x49,0x32,0x01,0x01,0x7f,0x01,0x01,0x3f,0x40,0x40,0x40,0x3f,0x1f,0x20,0x40,0x20,0x1f,0x3f,0x40,0x30,0x40,0x3f,0x63,0x14,0x08,0x14,0x63,0x07,0x08,0x70,0x08,0x07,0x61,0x51,0x49,0x45,0x43,0x00,0x7f,0x41,0x41,0x00,0x02,0x04,0x08,0x10,0x20,0x00,0x41,0x41,0x7f,0x00,0x04,0x02,0x01,0x02,0x04,0x40,0x40,0x40,0x40,0x40,
|
||||
0x00,0x01,0x02,0x04,0x00,0x20,0x54,0x54,0x54,0x78,0x7f,0x48,0x44,0x44,0x38,0x38,0x44,0x44,0x44,0x20,0x38,0x44,0x44,0x48,0x7f,0x38,0x54,0x54,0x54,0x18,0x08,0x7e,0x09,0x01,0x02,0x0c,0x52,0x52,0x52,0x3e,0x7f,0x08,0x04,0x04,0x78,0x00,0x44,0x7d,0x40,0x00,0x20,0x40,0x44,0x3d,0x00,0x7f,0x10,0x28,0x44,0x00,0x00,0x41,0x7f,0x40,0x00,0x7c,0x04,0x18,0x04,0x78,0x7c,0x08,0x04,0x04,0x78,0x38,0x44,0x44,0x44,0x38,
|
||||
0x7c,0x14,0x14,0x14,0x08,0x08,0x14,0x14,0x18,0x7c,0x7c,0x08,0x04,0x04,0x08,0x48,0x54,0x54,0x54,0x20,0x04,0x3f,0x44,0x40,0x20,0x3c,0x40,0x40,0x20,0x7c,0x1c,0x20,0x40,0x20,0x1c,0x3c,0x40,0x20,0x40,0x3c,0x44,0x28,0x10,0x28,0x44,0x0c,0x50,0x50,0x50,0x3c,0x44,0x64,0x54,0x4c,0x44,0x00,0x08,0x36,0x41,0x00,0x00,0x00,0x7f,0x00,0x00,0x00,0x41,0x36,0x08,0x00,0x08,0x08,0x22,0x1c,0x08,0x08,0x1c,0x22,0x08,0x08,
|
||||
};
|
BIN
src/font_6x1.png
Normal file
BIN
src/font_6x1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.6 KiB |
44
src/font_6x1.xbm
Normal file
44
src/font_6x1.xbm
Normal file
|
@ -0,0 +1,44 @@
|
|||
#define font_6x1_width 80
|
||||
#define font_6x1_height 48
|
||||
static unsigned char font_6x1_bits[] = {
|
||||
0x00,0x29,0x45,0x86,0x31,0x48,0x00,0x00,0x00,0x00,0x00,0x29,
|
||||
0xe5,0x67,0x22,0x84,0x10,0x02,0x00,0x80,0x00,0xa9,0x5f,0x50,
|
||||
0x11,0x02,0x55,0x02,0x00,0x40,0x00,0x01,0xe5,0x88,0x00,0x02,
|
||||
0xb9,0x0f,0x3e,0x20,0x00,0x80,0x4f,0x45,0x05,0x02,0x55,0x62,
|
||||
0x00,0x10,0x00,0x01,0xf5,0x72,0x02,0x84,0x10,0x42,0x80,0x09,
|
||||
0x00,0x01,0x45,0xb0,0x05,0x48,0x00,0x20,0x80,0x01,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x31,0x07,0x3d,
|
||||
0xf3,0x8c,0x01,0x00,0x41,0x70,0x92,0x49,0x88,0x85,0x84,0x52,
|
||||
0x32,0x86,0x80,0x88,0x12,0x41,0x48,0x9d,0x40,0x52,0x32,0x46,
|
||||
0x3e,0x81,0x12,0x21,0x26,0xa1,0x23,0x8c,0x03,0x20,0x00,0x42,
|
||||
0x12,0x11,0xe8,0xa1,0x24,0x12,0x32,0x46,0x3e,0x21,0x12,0x09,
|
||||
0x08,0xa5,0x24,0x12,0x31,0x84,0x80,0x00,0x8c,0x7b,0x07,0x19,
|
||||
0x23,0x8c,0x00,0x02,0x41,0x20,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0xc6,0x3d,0x77,0xfe,0x77,0xd1,0xf1,0x18,
|
||||
0x62,0x74,0x29,0xc6,0x98,0x42,0x88,0x91,0xa0,0x14,0x76,0x8c,
|
||||
0x29,0xc6,0x10,0x43,0x08,0x91,0xa0,0x12,0xea,0x8c,0xe6,0xbf,
|
||||
0x10,0xdf,0xeb,0x9f,0xa0,0x11,0x6a,0x8d,0x20,0xc6,0x10,0x43,
|
||||
0x88,0x91,0xa0,0x12,0x62,0x8e,0x20,0xc6,0x98,0x42,0x88,0x91,
|
||||
0xa4,0x14,0x62,0x8c,0x20,0x3e,0x77,0x7e,0xf0,0xd1,0x99,0xf8,
|
||||
0x63,0x74,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0xcf,0x3d,0xf7,0x63,0x8c,0x31,0x7e,0x07,0x1c,0x01,0x31,0xc6,
|
||||
0x48,0x62,0x8c,0x31,0x42,0x11,0x90,0x02,0x31,0xc6,0x40,0x62,
|
||||
0x8c,0x2a,0x22,0x21,0x50,0x04,0x2f,0x3e,0x47,0x62,0x8c,0x44,
|
||||
0x11,0x41,0x10,0x00,0xa1,0x16,0x48,0x62,0xac,0x8a,0x08,0x81,
|
||||
0x10,0x00,0x21,0xa5,0x48,0xa2,0xaa,0x91,0x04,0x01,0x11,0x00,
|
||||
0xc1,0x46,0x47,0x1c,0x51,0x91,0x7c,0x07,0x1c,0xf8,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x04,0x00,0x01,
|
||||
0x03,0x81,0xa0,0x60,0x00,0x00,0x04,0x04,0x00,0x81,0xf4,0x01,
|
||||
0x80,0x40,0x00,0x00,0xc8,0x35,0x67,0x9d,0x88,0xcd,0xb0,0x44,
|
||||
0x56,0x73,0x00,0xce,0x90,0xe3,0x89,0x93,0xa0,0x42,0xea,0x8c,
|
||||
0xc0,0xc7,0x10,0xbf,0xf0,0x91,0xa0,0x41,0x6a,0x8c,0x20,0xc6,
|
||||
0x18,0x83,0x80,0x91,0xa4,0x42,0x62,0x8c,0xc0,0x3f,0xe7,0x9d,
|
||||
0x70,0xd1,0x99,0xe4,0x62,0x74,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x44,
|
||||
0x04,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x42,0x08,0x21,
|
||||
0xcf,0x36,0x77,0x62,0x8c,0x31,0x7e,0x42,0x08,0x12,0x31,0xcf,
|
||||
0x20,0x62,0x8c,0x2a,0x22,0x41,0xd0,0xde,0xcf,0x07,0x27,0x62,
|
||||
0x8c,0xc4,0x13,0x42,0x08,0x12,0x01,0x06,0x28,0xb3,0xaa,0x0a,
|
||||
0x0a,0x42,0x08,0x21,0x01,0x86,0xc7,0x2c,0x51,0xd1,0x7d,0x44,
|
||||
0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00};
|
15
src/font_dblsize.lbm
Normal file
15
src/font_dblsize.lbm
Normal file
|
@ -0,0 +1,15 @@
|
|||
prog_uchar APM font_dblsize[] = {
|
||||
160,96,1920,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x7e,0x00,0x00,0x7e,0x3e,0x00,0x00,0x60,0x60,0xfe,0xfe,0x60,0x60,0xfe,0xfe,0x60,0x60,0x60,0xf0,0x98,0x98,0xfe,0xfe,0x98,0x98,0x18,0x18,0x0c,0x1e,0x1e,0x0c,0x80,0xc0,0xe0,0x70,0x38,0x18,0x78,0xfc,0x8e,0xc6,0xe6,0x76,0x3c,0x18,0x00,0x00,0x00,0x00,0x66,0x76,0x3e,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xf0,0x38,0x1c,0x0e,0x06,0x00,0x00,0x00,0x00,0x06,0x0e,0x1c,0x38,0xf0,0xe0,0x00,0x00,0x60,0x60,0xc0,0x80,0xf8,0xf8,0x80,0xc0,0x60,0x60,0x80,0x80,0x80,0x80,0xf8,0xf8,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xc0,0xe0,0x70,0x38,0x18,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x71,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x06,0x7f,0x7f,0x06,0x06,0x7f,0x7f,0x06,0x06,0x18,0x18,0x19,0x19,0x7f,0x7f,0x19,0x19,0x0f,0x06,0x18,0x1c,0x0e,0x07,0x03,0x01,0x30,0x78,0x78,0x30,0x1e,0x3f,0x71,0x63,0x67,0x66,0x3c,0x3c,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x0f,0x1c,0x38,0x70,0x60,0x00,0x00,0x00,0x00,0x60,0x70,0x38,0x1c,0x0f,0x07,0x00,0x00,0x06,0x06,0x03,0x01,0x1f,0x1f,0x01,0x03,0x06,0x06,0x01,0x01,0x01,0x01,0x1f,0x1f,0x01,0x01,0x01,0x01,0x00,0x00,0x66,0x76,0x3e,0x1e,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x30,0x78,0x78,0x30,0x00,0x00,0x00,0x00,0x18,0x1c,0x0e,0x07,0x03,0x01,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0xf8,0xfc,0x0e,0x06,0x06,0x0e,0xfc,0xf8,0x00,0x00,0x18,0x1c,0xfe,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x1c,0x0e,0x06,0x86,0xce,0xfc,0x78,0x00,0x00,0x06,0x06,0x86,0x86,0x86,0xce,0xfc,0x78,0x00,0x00,0x80,0xc0,0xe0,0x70,0x38,0x1c,0xfe,0xfe,0x00,0x00,0x7e,0x7e,0x66,0x66,0x66,0xe6,0xc6,0x86,0x00,0x00,0xf8,0xfc,0x8e,0x86,0x86,0x8e,0x1c,0x18,0x00,0x00,0x06,0x06,0x86,0xc6,0xe6,0x76,0x3e,0x1e,0x00,0x00,0x78,0xfc,0xce,0x86,0x86,0xce,0xfc,0x78,0x00,0x00,0x78,0xfc,0xce,0x86,0x86,0xce,0xfc,0xf8,0x00,0x00,0x30,0x78,0x78,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x78,0x78,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xc0,0xe0,0x70,0x38,0x1c,0x0e,0x06,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x06,0x0e,0x1c,0x38,0x70,0xe0,0xc0,0x80,0x00,0x00,0x18,0x1c,0x0e,0x06,0x06,0x06,0x86,0xce,0xfc,0x78,
|
||||
0x00,0x00,0x1f,0x3f,0x70,0x60,0x60,0x70,0x3f,0x1f,0x00,0x00,0x60,0x60,0x7f,0x7f,0x60,0x60,0x00,0x00,0x00,0x00,0x78,0x7c,0x6e,0x67,0x63,0x61,0x60,0x60,0x00,0x00,0x60,0x60,0x61,0x61,0x61,0x73,0x3f,0x1e,0x00,0x00,0x07,0x07,0x06,0x06,0x06,0x06,0x7f,0x7f,0x00,0x00,0x18,0x38,0x70,0x60,0x60,0x70,0x3f,0x1f,0x00,0x00,0x1f,0x3f,0x71,0x61,0x61,0x73,0x3f,0x1e,0x00,0x00,0x00,0x00,0x7f,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x1e,0x3f,0x73,0x61,0x61,0x73,0x3f,0x1e,0x00,0x00,0x00,0x00,0x61,0x71,0x39,0x1d,0x0f,0x07,0x00,0x00,0x0c,0x1e,0x1e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x66,0x76,0x3e,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x07,0x0e,0x1c,0x38,0x70,0x60,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x60,0x70,0x38,0x1c,0x0e,0x07,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x66,0x67,0x03,0x01,0x00,0x00,
|
||||
0x78,0xfc,0xce,0x86,0x86,0xce,0xfc,0x78,0x00,0x00,0xe0,0xf0,0xb8,0x9c,0x8e,0x8e,0x9c,0xb8,0xf0,0xe0,0xfe,0xfe,0x86,0x86,0x86,0x86,0x86,0xce,0xfc,0x78,0xf8,0xfc,0x0e,0x06,0x06,0x06,0x06,0x0e,0x1c,0x18,0xfe,0xfe,0x06,0x06,0x06,0x0e,0x1c,0x38,0xf0,0xe0,0xfe,0xfe,0x86,0x86,0x86,0x86,0x86,0x86,0x06,0x06,0xfe,0xfe,0x86,0x86,0x86,0x86,0x86,0x86,0x06,0x06,0xf8,0xfc,0x0e,0x06,0x86,0x86,0x86,0x8e,0x9c,0x98,0xfe,0xfe,0x80,0x80,0x80,0x80,0x80,0x80,0xfe,0xfe,0x00,0x00,0x06,0x06,0xfe,0xfe,0x06,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x06,0xfe,0xfe,0x06,0x06,0xfe,0xfe,0x80,0xc0,0xe0,0x70,0x38,0x1c,0x0e,0x06,0xfe,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xfe,0x1c,0x38,0xf0,0xf0,0x38,0x1c,0xfe,0xfe,0xfe,0xfe,0x70,0xe0,0xc0,0x80,0x00,0x00,0xfe,0xfe,0xf8,0xfc,0x0e,0x06,0x06,0x06,0x06,0x0e,0xfc,0xf8,
|
||||
0x00,0x00,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x7f,0x7f,0x01,0x01,0x01,0x01,0x01,0x01,0x7f,0x7f,0x7f,0x7f,0x61,0x61,0x61,0x61,0x61,0x73,0x3f,0x1e,0x1f,0x3f,0x70,0x60,0x60,0x60,0x60,0x70,0x38,0x18,0x7f,0x7f,0x60,0x60,0x60,0x70,0x38,0x1c,0x0f,0x07,0x7f,0x7f,0x61,0x61,0x61,0x61,0x61,0x61,0x60,0x60,0x7f,0x7f,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x1f,0x3f,0x70,0x60,0x61,0x61,0x61,0x71,0x7f,0x3f,0x7f,0x7f,0x01,0x01,0x01,0x01,0x01,0x01,0x7f,0x7f,0x00,0x00,0x60,0x60,0x7f,0x7f,0x60,0x60,0x00,0x00,0x18,0x38,0x70,0x60,0x60,0x70,0x3f,0x1f,0x00,0x00,0x7f,0x7f,0x01,0x03,0x07,0x0e,0x1c,0x38,0x70,0x60,0x7f,0x7f,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x7f,0x7f,0x00,0x00,0x01,0x01,0x00,0x00,0x7f,0x7f,0x7f,0x7f,0x00,0x00,0x01,0x03,0x07,0x0e,0x7f,0x7f,0x1f,0x3f,0x70,0x60,0x60,0x60,0x60,0x70,0x3f,0x1f,
|
||||
0xfe,0xfe,0x86,0x86,0x86,0x86,0x86,0xce,0xfc,0x78,0xf8,0xfc,0x0e,0x06,0x06,0x06,0x06,0x0e,0xfc,0xf8,0xfe,0xfe,0x86,0x86,0x86,0x86,0x86,0xce,0xfc,0x78,0x78,0xfc,0xce,0x86,0x86,0x86,0x86,0x8e,0x1c,0x18,0x06,0x06,0x06,0x06,0xfe,0xfe,0x06,0x06,0x06,0x06,0xfe,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xfe,0xfe,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xfe,0xfe,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xfe,0x1e,0x3e,0x70,0xe0,0xc0,0xc0,0xe0,0x70,0x3e,0x1e,0x7e,0xfe,0xc0,0x80,0x00,0x00,0x80,0xc0,0xfe,0x7e,0x06,0x06,0x06,0x06,0x86,0xc6,0xe6,0x76,0x3e,0x1e,0x00,0x00,0xfe,0xfe,0x06,0x06,0x06,0x06,0x00,0x00,0x18,0x38,0x70,0xe0,0xc0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0xfe,0xfe,0x00,0x00,0x60,0x70,0x38,0x1c,0x0e,0x0e,0x1c,0x38,0x70,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x7f,0x7f,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x1f,0x3f,0x70,0x60,0x66,0x6e,0x3c,0x38,0x7f,0x67,0x7f,0x7f,0x01,0x01,0x07,0x0f,0x1d,0x39,0x70,0x60,0x18,0x38,0x71,0x61,0x61,0x61,0x61,0x73,0x3f,0x1e,0x00,0x00,0x00,0x00,0x7f,0x7f,0x00,0x00,0x00,0x00,0x1f,0x3f,0x70,0x60,0x60,0x60,0x60,0x70,0x3f,0x1f,0x07,0x0f,0x1c,0x38,0x70,0x70,0x38,0x1c,0x0f,0x07,0x1f,0x3f,0x70,0x70,0x3e,0x3e,0x70,0x70,0x3f,0x1f,0x78,0x7c,0x0e,0x07,0x03,0x03,0x07,0x0e,0x7c,0x78,0x00,0x00,0x01,0x03,0x7f,0x7f,0x03,0x01,0x00,0x00,0x78,0x7c,0x6e,0x67,0x63,0x61,0x60,0x60,0x60,0x60,0x00,0x00,0x7f,0x7f,0x60,0x60,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x07,0x0e,0x1c,0x18,0x00,0x00,0x60,0x60,0x60,0x60,0x7f,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,
|
||||
0x00,0x00,0x06,0x0e,0x1c,0x38,0x70,0x60,0x00,0x00,0x00,0x00,0x60,0x60,0x60,0x60,0x60,0xe0,0xc0,0x80,0xfe,0xfe,0x80,0xc0,0xe0,0x60,0x60,0xe0,0xc0,0x80,0x80,0xc0,0xe0,0x60,0x60,0x60,0x60,0x60,0x00,0x00,0x80,0xc0,0xe0,0x60,0x60,0xe0,0xc0,0x80,0xfe,0xfe,0x80,0xc0,0xe0,0x60,0x60,0x60,0x60,0xe0,0xc0,0x80,0x80,0x80,0xf8,0xfc,0x8e,0x86,0x06,0x0e,0x1c,0x18,0xe0,0xf0,0x38,0x18,0x18,0x18,0x18,0x18,0xf8,0xf8,0xfe,0xfe,0x80,0xc0,0xe0,0x60,0x60,0xe0,0xc0,0x80,0x00,0x00,0x60,0x60,0xe6,0xe6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0xe6,0xe6,0x00,0x00,0xfe,0xfe,0x00,0x00,0x80,0xc0,0xe0,0x60,0x00,0x00,0x00,0x00,0x06,0x06,0xfe,0xfe,0x00,0x00,0x00,0x00,0xe0,0xe0,0x60,0xe0,0xc0,0xc0,0xe0,0xe0,0xc0,0x80,0xe0,0xe0,0x80,0xc0,0xe0,0x60,0x60,0xe0,0xc0,0x80,0x80,0xc0,0xe0,0x60,0x60,0x60,0x60,0xe0,0xc0,0x80,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x3c,0x7e,0x66,0x66,0x66,0x66,0x66,0x7f,0x7f,0x7f,0x7f,0x61,0x61,0x60,0x60,0x60,0x70,0x3f,0x1f,0x1f,0x3f,0x70,0x60,0x60,0x60,0x60,0x70,0x38,0x18,0x1f,0x3f,0x70,0x60,0x60,0x60,0x61,0x61,0x7f,0x7f,0x1f,0x3f,0x76,0x66,0x66,0x66,0x66,0x66,0x07,0x07,0x01,0x01,0x7f,0x7f,0x01,0x01,0x00,0x00,0x00,0x00,0x01,0x03,0x67,0x66,0x66,0x66,0x66,0x76,0x3f,0x1f,0x7f,0x7f,0x01,0x01,0x00,0x00,0x00,0x00,0x7f,0x7f,0x00,0x00,0x60,0x60,0x7f,0x7f,0x60,0x60,0x00,0x00,0x18,0x38,0x70,0x60,0x60,0x70,0x3f,0x1f,0x00,0x00,0x7f,0x7f,0x06,0x0f,0x1f,0x39,0x70,0x60,0x00,0x00,0x00,0x00,0x60,0x60,0x7f,0x7f,0x60,0x60,0x00,0x00,0x7f,0x7f,0x00,0x00,0x07,0x07,0x00,0x00,0x7f,0x7f,0x7f,0x7f,0x01,0x01,0x00,0x00,0x00,0x00,0x7f,0x7f,0x1f,0x3f,0x70,0x60,0x60,0x60,0x60,0x70,0x3f,0x1f,
|
||||
0xe0,0xe0,0x60,0x60,0x60,0x60,0x60,0xe0,0xc0,0x80,0x80,0xc0,0xe0,0x60,0x60,0x60,0xc0,0x80,0xe0,0xe0,0xe0,0xe0,0x80,0xc0,0xe0,0x60,0x60,0xe0,0xc0,0x80,0x80,0xc0,0xe0,0x60,0x60,0x60,0x60,0x60,0x00,0x00,0x60,0x60,0xfe,0xfe,0x60,0x60,0x00,0x00,0x00,0x00,0xe0,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xe0,0xe0,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xe0,0xe0,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xe0,0x60,0xe0,0xc0,0x80,0x00,0x00,0x80,0xc0,0xe0,0x60,0xe0,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xe0,0x60,0x60,0x60,0x60,0x60,0x60,0xe0,0xe0,0xe0,0x60,0x00,0x00,0x80,0xc0,0x78,0x7c,0x0e,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x7c,0x78,0xc0,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x18,0x38,0xf0,0xe0,0xc0,0x80,0x80,0xc0,0xe0,0xf0,0x38,0x18,0x80,0x80,0x80,0x80,
|
||||
0x7f,0x7f,0x06,0x06,0x06,0x06,0x06,0x07,0x03,0x01,0x01,0x03,0x07,0x06,0x06,0x06,0x07,0x07,0x7f,0x7f,0x7f,0x7f,0x01,0x01,0x00,0x00,0x00,0x00,0x01,0x01,0x61,0x63,0x67,0x66,0x66,0x66,0x66,0x7e,0x3c,0x18,0x00,0x00,0x1f,0x3f,0x70,0x60,0x60,0x70,0x38,0x18,0x1f,0x3f,0x70,0x60,0x60,0x70,0x38,0x18,0x7f,0x7f,0x07,0x0f,0x1c,0x38,0x70,0x70,0x38,0x1c,0x0f,0x07,0x1f,0x3f,0x70,0x70,0x38,0x38,0x70,0x70,0x3f,0x1f,0x60,0x70,0x39,0x1f,0x0f,0x0f,0x1f,0x39,0x70,0x60,0x01,0x03,0x67,0x66,0x66,0x66,0x66,0x76,0x3f,0x1f,0x60,0x70,0x78,0x7c,0x6e,0x67,0x63,0x61,0x60,0x60,0x00,0x00,0x01,0x03,0x1e,0x3e,0x70,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x70,0x3e,0x1e,0x03,0x01,0x00,0x00,0x01,0x01,0x01,0x01,0x18,0x1c,0x0f,0x07,0x03,0x01,0x01,0x03,0x07,0x0f,0x1c,0x18,0x01,0x01,0x01,0x01,
|
||||
};
|
BIN
src/font_dblsize.png
Normal file
BIN
src/font_dblsize.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.6 KiB |
164
src/font_dblsize.xbm
Normal file
164
src/font_dblsize.xbm
Normal file
|
@ -0,0 +1,164 @@
|
|||
#define font_dblsize_width 160
|
||||
#define font_dblsize_height 96
|
||||
static unsigned char font_dblsize_bits[]={
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xc0,0x0c,
|
||||
0x33,0x30,0x18,0xc0,0x03,0x0f,0xc0,0x30,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0xc0,0xc0,0x0c,0x33,0x30,0x3c,0xe0,
|
||||
0x07,0x0f,0xe0,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0xc0,0xc0,0x0c,0x33,0xfc,0x3f,0x7c,0x0c,0x0c,0x70,0xe0,
|
||||
0x00,0x03,0x0c,0x00,0x00,0x00,0x00,0xc0,0x00,0xc0,0xc0,0x0c,
|
||||
0x33,0xfe,0x1b,0x3e,0x0e,0x0e,0x38,0xc0,0x01,0x03,0x0c,0x00,
|
||||
0x00,0x00,0x00,0xe0,0x00,0xc0,0xc0,0xcc,0xff,0x33,0x00,0x37,
|
||||
0x07,0x07,0x1c,0x80,0x33,0x33,0x0c,0x00,0x00,0x00,0x00,0x70,
|
||||
0x00,0xc0,0x80,0xc4,0xff,0x33,0x80,0xb3,0x03,0x03,0x0c,0x00,
|
||||
0x73,0x3b,0x0c,0x00,0x00,0x00,0x00,0x38,0x00,0xc0,0x00,0x00,
|
||||
0x33,0xfe,0xc0,0xe1,0x01,0x00,0x0c,0x00,0xc3,0xcf,0xff,0x00,
|
||||
0xfc,0x0f,0x00,0x1c,0x00,0xc0,0x00,0x00,0x33,0xfc,0xe1,0xe0,
|
||||
0x01,0x00,0x0c,0x00,0xc3,0xcf,0xff,0x00,0xfc,0x0f,0x00,0x0e,
|
||||
0x00,0x00,0x00,0xc0,0xff,0x30,0x73,0xb0,0x33,0x00,0x0c,0x00,
|
||||
0x73,0x3b,0x0c,0x3c,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0xc0,
|
||||
0xff,0x30,0x3b,0x30,0x3f,0x00,0x1c,0x80,0x33,0x33,0x0c,0x3c,
|
||||
0x00,0x00,0x80,0x03,0x00,0x00,0x00,0x00,0x33,0xff,0x1d,0x36,
|
||||
0x0c,0x00,0x38,0xc0,0x01,0x03,0x0c,0x30,0x00,0x80,0xc1,0x01,
|
||||
0x00,0xc0,0x00,0x00,0x33,0xff,0x0c,0x7f,0x0c,0x00,0x70,0xe0,
|
||||
0x00,0x03,0x0c,0x38,0x00,0xc0,0xc3,0x00,0x00,0xc0,0x00,0x00,
|
||||
0x33,0x30,0x00,0xef,0x3f,0x00,0xe0,0x70,0x00,0x00,0x00,0x1c,
|
||||
0x00,0xc0,0x03,0x00,0x00,0xc0,0x00,0x00,0x33,0x30,0x00,0xc6,
|
||||
0x33,0x00,0xc0,0x30,0x00,0x00,0x00,0x0c,0x00,0x80,0x01,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0xf0,0xc0,0x00,0x0f,0x3f,0x00,0xf3,0x0f,
|
||||
0x0f,0xff,0xf0,0xc0,0x03,0x00,0x00,0x00,0x03,0x30,0x00,0x3f,
|
||||
0xf8,0xe1,0x80,0x1f,0x7f,0x80,0xf3,0x8f,0x1f,0xff,0xf8,0xe1,
|
||||
0x07,0x00,0x00,0x80,0x03,0x70,0x80,0x7f,0x9c,0xf3,0xc0,0x39,
|
||||
0xe0,0xc0,0x33,0xc0,0x39,0xc0,0x9c,0x73,0x8e,0x01,0x06,0xc0,
|
||||
0x01,0xe0,0xc0,0xe1,0x0c,0xf3,0xc0,0x30,0xc0,0xe0,0x33,0xc0,
|
||||
0x30,0xe0,0x0c,0x33,0xcc,0x03,0x0f,0xe0,0x00,0xc0,0xc1,0xc0,
|
||||
0x0c,0xc3,0x00,0x30,0xc0,0x70,0xf3,0xc3,0x00,0x70,0x0c,0x33,
|
||||
0xcc,0x03,0x0f,0x70,0xfc,0x8f,0x03,0xc0,0x0c,0xc3,0x00,0x38,
|
||||
0xe0,0x38,0xf3,0xc7,0x00,0x38,0x9c,0x73,0x8e,0x01,0x06,0x38,
|
||||
0xfc,0x0f,0x07,0xe0,0x0c,0xc3,0x00,0x1c,0x7c,0x1c,0x03,0xce,
|
||||
0x0f,0x1c,0xf8,0xe1,0x0f,0x00,0x00,0x1c,0x00,0x00,0x0e,0x70,
|
||||
0x0c,0xc3,0x00,0x0e,0x7c,0x0c,0x03,0xcc,0x1f,0x0c,0xf8,0xc1,
|
||||
0x0f,0x00,0x00,0x1c,0x00,0x00,0x0e,0x38,0x0c,0xc3,0x00,0x07,
|
||||
0xe0,0xfc,0x03,0xcc,0x38,0x0c,0x9c,0x03,0x8c,0x01,0x0f,0x38,
|
||||
0xfc,0x0f,0x07,0x1c,0x0c,0xc3,0x80,0x03,0xc0,0xfc,0x03,0xcc,
|
||||
0x30,0x0c,0x0c,0x03,0xce,0x03,0x0f,0x70,0xfc,0x8f,0x03,0x0c,
|
||||
0x0c,0xc3,0xc0,0x01,0xc0,0x00,0x33,0xcc,0x30,0x0c,0x0c,0x03,
|
||||
0xc7,0x03,0x0c,0xe0,0x00,0xc0,0x01,0x00,0x9c,0xc3,0xc0,0x00,
|
||||
0xe0,0x00,0x73,0xce,0x39,0x0c,0x9c,0x83,0x83,0x01,0x0e,0xc0,
|
||||
0x01,0xe0,0x00,0x00,0xf8,0xf1,0xc3,0x3f,0x7f,0x00,0xe3,0x87,
|
||||
0x1f,0x0c,0xf8,0xc1,0x01,0x00,0x07,0x80,0x03,0x70,0x00,0x0c,
|
||||
0xf0,0xf0,0xc3,0x3f,0x3f,0x00,0xc3,0x03,0x0f,0x0c,0xf0,0xc0,
|
||||
0x00,0x00,0x03,0x00,0x03,0x30,0x00,0x0c,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x3c,0xc0,0xf0,0x0f,0x3f,0x3f,0xfc,0xff,0x3f,0x3f,0x03,0xf3,
|
||||
0x03,0xff,0xc0,0x03,0x0c,0x3c,0x30,0x3f,0x7e,0xe0,0xf1,0x9f,
|
||||
0x7f,0x7f,0xfc,0xff,0xbf,0x7f,0x03,0xf3,0x03,0xff,0xe0,0x03,
|
||||
0x1c,0x3e,0xb0,0x7f,0xe7,0xf0,0x33,0xf8,0xe1,0xe3,0x0c,0x30,
|
||||
0xc0,0xe1,0x03,0xc3,0x00,0xcc,0x70,0x03,0x3c,0x3f,0xf0,0xe1,
|
||||
0xc3,0x38,0x37,0xf0,0xc0,0xc3,0x0d,0x30,0xc0,0xc0,0x03,0xc3,
|
||||
0x00,0xcc,0x38,0x03,0xfc,0x7f,0xf0,0xc0,0xc3,0x1c,0x3e,0xf0,
|
||||
0x00,0x83,0x0f,0x30,0xc0,0x00,0x03,0xc3,0x00,0xcc,0x1c,0x03,
|
||||
0xec,0xfd,0xf0,0xc0,0xe7,0x0c,0x3c,0xf8,0x00,0x03,0x0f,0x30,
|
||||
0xc0,0x00,0x03,0xc3,0x00,0xcc,0x0e,0x03,0xcc,0xfc,0xf1,0xc0,
|
||||
0x7e,0xfc,0xff,0xdf,0x00,0x03,0xff,0xf3,0xcf,0xfc,0xff,0xc3,
|
||||
0x00,0xcc,0x07,0x03,0xcc,0xbc,0xf3,0xc0,0x3c,0xfc,0xff,0xdf,
|
||||
0x00,0x03,0xff,0xf3,0xcf,0xfc,0xff,0xc3,0x00,0xcc,0x07,0x03,
|
||||
0xcc,0x3c,0xf7,0xc0,0x00,0x0c,0x3c,0xf8,0x00,0x03,0x0f,0x30,
|
||||
0xc0,0xc0,0x03,0xc3,0x00,0xcc,0x0e,0x03,0x0c,0x3c,0xfe,0xc0,
|
||||
0x00,0x0c,0x3c,0xf0,0x00,0x83,0x0f,0x30,0xc0,0xc0,0x03,0xc3,
|
||||
0x00,0xcc,0x1c,0x03,0x0c,0x3c,0xfc,0xc0,0x00,0x0c,0x3c,0xf0,
|
||||
0xc0,0xc3,0x0d,0x30,0xc0,0xc0,0x03,0xc3,0x30,0xcc,0x38,0x03,
|
||||
0x0c,0x3c,0xf8,0xc0,0x00,0x0c,0x3c,0xf8,0xe1,0xe3,0x0c,0x30,
|
||||
0xc0,0xe1,0x03,0xc3,0x70,0xce,0x70,0x03,0x0c,0x3c,0xf0,0xe1,
|
||||
0x00,0x0c,0xfc,0x9f,0x7f,0x7f,0xfc,0x3f,0x80,0xff,0x03,0xf3,
|
||||
0xe3,0xc7,0xe0,0xff,0x0f,0x3c,0xb0,0x7f,0x00,0x0c,0xfc,0x0f,
|
||||
0x3f,0x3f,0xfc,0x3f,0x00,0x7f,0x03,0xf3,0xc3,0xc3,0xc0,0xff,
|
||||
0x0f,0x3c,0x30,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xf0,0xf3,0x0f,
|
||||
0x3f,0xff,0x0f,0x3c,0xf0,0xc0,0x03,0x0f,0xfc,0x3f,0x3f,0x00,
|
||||
0xf0,0x03,0x03,0x00,0xff,0xf9,0xf7,0x9f,0x7f,0xff,0x0f,0x3c,
|
||||
0xf0,0xc0,0x03,0x0f,0xfc,0x3f,0x3f,0x00,0xf0,0x83,0x07,0x00,
|
||||
0x83,0x1f,0x3e,0xf8,0xe1,0x30,0x0c,0x3c,0xf0,0xc0,0x03,0x0f,
|
||||
0x0c,0x30,0x03,0x03,0x00,0xc3,0x0f,0x00,0x03,0x0f,0x3c,0xf0,
|
||||
0xc0,0x30,0x0c,0x3c,0xf0,0xc0,0x87,0x0f,0x0c,0x38,0x03,0x07,
|
||||
0x00,0xe3,0x1c,0x00,0x03,0x0f,0x3c,0xf0,0x00,0x30,0x0c,0x3c,
|
||||
0xf0,0xc0,0xce,0x0d,0x0c,0x1c,0x03,0x0e,0x00,0x73,0x38,0x00,
|
||||
0x83,0x0f,0x3c,0xf8,0x01,0x30,0x0c,0x3c,0xf0,0xc0,0xfc,0x1c,
|
||||
0x0e,0x0e,0x03,0x1c,0x00,0x33,0x30,0x00,0xff,0x0d,0xfc,0x9f,
|
||||
0x3f,0x30,0x0c,0x3c,0xf0,0xc0,0x78,0x38,0x07,0x07,0x03,0x38,
|
||||
0x00,0x03,0x00,0x00,0xff,0x0c,0xfc,0x0f,0x7f,0x30,0x0c,0x3c,
|
||||
0xf0,0xc0,0x78,0xf0,0x83,0x03,0x03,0x70,0x00,0x03,0x00,0x00,
|
||||
0x03,0xcc,0x3c,0x03,0xe0,0x30,0x0c,0x3c,0xf0,0xcc,0xfc,0xe0,
|
||||
0xc1,0x01,0x03,0xe0,0x00,0x03,0x00,0x00,0x03,0xcc,0x3d,0x07,
|
||||
0xc0,0x30,0x0c,0x7c,0xf8,0xcc,0xce,0xc1,0xe0,0x00,0x03,0xc0,
|
||||
0x01,0x03,0x00,0x00,0x03,0x8c,0x37,0xce,0xc0,0x30,0x0c,0xec,
|
||||
0xdc,0xcc,0x87,0xc3,0x70,0x00,0x03,0x80,0x03,0x03,0x00,0x00,
|
||||
0x03,0x1c,0x37,0xdc,0xe1,0x30,0x1c,0xce,0xcf,0xff,0x03,0xc3,
|
||||
0x30,0x00,0x03,0x00,0x03,0x03,0x00,0x00,0x03,0xf8,0x3f,0xb8,
|
||||
0x7f,0x30,0xf8,0x87,0x87,0x7f,0x03,0xc3,0xf0,0x3f,0x3f,0x00,
|
||||
0xf0,0x03,0xc0,0xff,0x03,0xf0,0x3c,0x30,0x3f,0x30,0xf0,0x03,
|
||||
0x03,0x33,0x03,0xc3,0xf0,0x3f,0x3f,0x00,0xf0,0x03,0xc0,0xff,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x0c,0x00,0x30,0x00,0x00,0x00,0x03,0x00,
|
||||
0x0f,0x00,0x03,0xc0,0x00,0xcc,0x00,0x3c,0x00,0x00,0x00,0x00,
|
||||
0x1c,0x00,0x30,0x00,0x00,0x00,0x03,0x80,0x1f,0x00,0x03,0xc0,
|
||||
0x00,0xcc,0x00,0x3c,0x00,0x00,0x00,0x00,0x38,0x00,0x30,0x00,
|
||||
0x00,0x00,0x03,0xc0,0x39,0xff,0x03,0x00,0x00,0xc0,0x00,0x30,
|
||||
0x00,0x00,0x00,0x00,0x70,0x00,0x30,0x00,0x00,0x00,0x03,0xc0,
|
||||
0xb0,0xff,0x03,0x00,0x00,0xc0,0x00,0x30,0x00,0x00,0x00,0x00,
|
||||
0xe0,0xf0,0x33,0x0f,0x3f,0x3c,0xf3,0xc3,0xc0,0xc1,0xf3,0xf0,
|
||||
0x00,0xcf,0x30,0x30,0x3c,0x33,0x0f,0x3f,0xc0,0xf0,0xb7,0x9f,
|
||||
0x3f,0x7e,0xfb,0xc7,0xc0,0xc0,0xfb,0xf1,0x00,0xcf,0x38,0x30,
|
||||
0xfc,0xb7,0x9f,0x7f,0x00,0x00,0xfe,0xf9,0x01,0xe7,0x1f,0xfe,
|
||||
0xc3,0xc0,0x9f,0xc3,0x00,0xcc,0x1c,0x30,0xec,0xff,0xf9,0xe1,
|
||||
0x00,0x00,0xfc,0xf0,0x00,0xc3,0x0f,0xfc,0xc3,0xc1,0x0f,0xc3,
|
||||
0x00,0xcc,0x0e,0x30,0xcc,0xfc,0xf0,0xc0,0x00,0xf0,0x3f,0xf0,
|
||||
0x00,0x03,0xff,0xcf,0x80,0xff,0x03,0xc3,0x00,0xcc,0x07,0x30,
|
||||
0xcc,0x3c,0xf0,0xc0,0x00,0xf8,0x3f,0xf0,0x00,0x03,0xff,0xcf,
|
||||
0x00,0xff,0x03,0xc3,0x00,0xcc,0x07,0x30,0xcc,0x3c,0xf0,0xc0,
|
||||
0x00,0x1c,0x3c,0xf0,0xc0,0x03,0x0f,0xc0,0x00,0xc0,0x03,0xc3,
|
||||
0x30,0xcc,0x0e,0x30,0x0c,0x3c,0xf0,0xc0,0x00,0x1c,0x3c,0xf8,
|
||||
0xe1,0x07,0x1f,0xc0,0x00,0xe0,0x03,0xc3,0x70,0xce,0x1c,0x30,
|
||||
0x0c,0x3c,0xf0,0xe1,0x00,0xf8,0xff,0x9f,0x7f,0xfe,0xfb,0xc3,
|
||||
0x00,0x7f,0x03,0xf3,0xe3,0xc7,0x38,0xfc,0x0c,0x3c,0xb0,0x7f,
|
||||
0x00,0xf0,0xff,0x0f,0x3f,0xfc,0xf3,0xc3,0x00,0x3f,0x03,0xf3,
|
||||
0xc3,0xc3,0x30,0xfc,0x0c,0x3c,0x30,0x3f,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x30,0x30,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x30,
|
||||
0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x1c,0x30,0xe0,0x00,0x03,0x0c,
|
||||
0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x0c,0x30,0xc0,0x00,0x07,0x0e,0xff,0xf0,0x3c,0x0f,
|
||||
0x3f,0x3f,0x0c,0x3c,0xf0,0xc0,0x03,0x0f,0xfc,0x3f,0x0c,0x30,
|
||||
0xc0,0x00,0x0e,0x07,0xff,0xf9,0xbd,0x9f,0x3f,0x3f,0x0c,0x3c,
|
||||
0xf0,0xc0,0x87,0x0f,0xfc,0x3f,0x0e,0x30,0xc0,0x01,0x9c,0x03,
|
||||
0x83,0x1f,0xff,0xf9,0x01,0x0c,0x0c,0x3c,0xf0,0xc0,0xce,0x0d,
|
||||
0x0c,0x1c,0x03,0x30,0x00,0xf3,0xfc,0xf3,0x83,0x1f,0xff,0xf0,
|
||||
0x01,0x0c,0x0c,0x3c,0xf0,0xc0,0xfc,0x1c,0x0c,0x0e,0x03,0x30,
|
||||
0x00,0xf3,0xfc,0xf3,0xff,0xf9,0x3f,0x80,0x3f,0x0c,0x0c,0x3c,
|
||||
0xf0,0xc0,0x78,0xf8,0x0f,0x07,0x0e,0x30,0xc0,0x01,0x9c,0x03,
|
||||
0xff,0xf0,0x3f,0x00,0x7f,0x0c,0x0c,0x7c,0xf8,0xc0,0x78,0xf0,
|
||||
0x8f,0x03,0x0c,0x30,0xc0,0x00,0x0e,0x07,0x03,0x00,0x3c,0x00,
|
||||
0xe0,0x0c,0x0f,0xef,0xdc,0xcc,0xfc,0x00,0xcc,0x01,0x0c,0x30,
|
||||
0xc0,0x00,0x07,0x0e,0x03,0x00,0x3c,0x00,0xe0,0x9c,0x9f,0xcf,
|
||||
0xcf,0xff,0xce,0x01,0xee,0x00,0x1c,0x30,0xe0,0x00,0x03,0x0c,
|
||||
0x03,0x00,0x3c,0xc0,0x7f,0xf8,0xf9,0x8d,0x87,0x7f,0x87,0xf3,
|
||||
0xf7,0x3f,0x38,0x30,0x70,0x00,0x00,0x00,0x03,0x00,0x3c,0xc0,
|
||||
0x3f,0xf0,0xf0,0x0c,0x03,0x33,0x03,0xf3,0xf3,0x3f,0x30,0x30,
|
||||
0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00};
|
460
src/frsky.cpp
Normal file
460
src/frsky.cpp
Normal file
|
@ -0,0 +1,460 @@
|
|||
/*
|
||||
* Authors (alpahbetical order)
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
*
|
||||
* Original contributors
|
||||
* - Philip Moss Adapted first frsky functions from jeti.cpp code by
|
||||
* - Karl Szmutny <shadow@privy.de>
|
||||
|
||||
* 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 "gruvin9x.h"
|
||||
#include "frsky.h"
|
||||
|
||||
// Enumerate FrSky packet codes
|
||||
#define LINKPKT 0xfe
|
||||
#define USRPKT 0xfd
|
||||
#define A11PKT 0xfc
|
||||
#define A12PKT 0xfb
|
||||
#define A21PKT 0xfa
|
||||
#define A22PKT 0xf9
|
||||
#define ALRM_REQUEST 0xf8
|
||||
#define RSSI1PKT 0xf7
|
||||
#define RSSI2PKT 0xf6
|
||||
|
||||
#define START_STOP 0x7e
|
||||
#define BYTESTUFF 0x7d
|
||||
#define STUFF_MASK 0x20
|
||||
|
||||
uint8_t frskyRxBuffer[19]; // Receive buffer. 9 bytes (full packet), worst case 18 bytes with byte-stuffing (+1)
|
||||
uint8_t frskyTxBuffer[19]; // Ditto for transmit buffer
|
||||
uint8_t frskyTxBufferCount = 0;
|
||||
uint8_t FrskyRxBufferReady = 0;
|
||||
uint8_t frskyStreaming = 0;
|
||||
uint8_t frskyTxISRIndex = 0;
|
||||
|
||||
FrskyData frskyTelemetry[2];
|
||||
FrskyData frskyRSSI[2];
|
||||
|
||||
struct FrskyAlarm {
|
||||
uint8_t level; // The alarm's 'urgency' level. 0=disabled, 1=yellow, 2=orange, 3=red
|
||||
uint8_t greater; // 1 = 'if greater than'. 0 = 'if less than'
|
||||
uint8_t value; // The threshold above or below which the alarm will sound
|
||||
};
|
||||
struct FrskyAlarm frskyAlarms[4];
|
||||
|
||||
void frskyPushValue(uint8_t & i, uint8_t value);
|
||||
|
||||
/*
|
||||
Called from somewhere in the main loop or a low prioirty interrupt
|
||||
routine perhaps. This funtcion processes Fr-Sky telemetry data packets
|
||||
assembled byt he USART0_RX_vect) ISR function (below) and stores
|
||||
extracted data in global variables for use by other parts of the program.
|
||||
|
||||
Packets can be any of the following:
|
||||
|
||||
- A1/A2/RSSI telemtry data
|
||||
- Alarm level/mode/threshold settings for Ch1A, Ch1B, Ch2A, Ch2B
|
||||
- User Data packets
|
||||
|
||||
User Data packets are not yet implementedi (they are simply ignored),
|
||||
but will likely one day contain the likes of GPS long/lat/alt/speed,
|
||||
AoA, airspeed, etc.
|
||||
*/
|
||||
|
||||
void processFrskyPacket(uint8_t *packet)
|
||||
{
|
||||
// What type of packet?
|
||||
switch (packet[0])
|
||||
{
|
||||
case A22PKT:
|
||||
case A21PKT:
|
||||
case A12PKT:
|
||||
case A11PKT:
|
||||
{
|
||||
struct FrskyAlarm *alarmptr ;
|
||||
alarmptr = &frskyAlarms[(packet[0]-A22PKT)] ;
|
||||
alarmptr->value = packet[1];
|
||||
alarmptr->greater = packet[2] & 0x01;
|
||||
alarmptr->level = packet[3] & 0x03;
|
||||
}
|
||||
break;
|
||||
case LINKPKT: // A1/A2/RSSI values
|
||||
frskyTelemetry[0].set(packet[1]);
|
||||
frskyTelemetry[1].set(packet[2]);
|
||||
frskyRSSI[0].set(packet[3]);
|
||||
frskyRSSI[1].set(packet[4] / 2);
|
||||
break;
|
||||
|
||||
case USRPKT: // User Data packet -- not yet implemented
|
||||
break;
|
||||
}
|
||||
|
||||
FrskyRxBufferReady = 0;
|
||||
frskyStreaming = FRSKY_TIMEOUT10ms; // reset counter only if valid frsky packets are being detected
|
||||
}
|
||||
|
||||
// Receive buffer state machine state defs
|
||||
#define frskyDataIdle 0
|
||||
#define frskyDataStart 1
|
||||
#define frskyDataInFrame 2
|
||||
#define frskyDataXOR 3
|
||||
/*
|
||||
Receive serial (RS-232) characters, detecting and storing each Fr-Sky
|
||||
0x7e-framed packet as it arrives. When a complete packet has been
|
||||
received, process its data into storage variables. NOTE: This is an
|
||||
interrupt routine and should not get too lengthy. I originally had
|
||||
the buffer being checked in the perMain function (because per10ms
|
||||
isn't quite often enough for data streaming at 9600baud) but alas
|
||||
that scheme lost packets also. So each packet is parsed as it arrives,
|
||||
directly at the ISR function (through a call to frskyProcessPacket).
|
||||
|
||||
If this proves a problem in the future, then I'll just have to implement
|
||||
a second buffer to receive data while one buffer is being processed (slowly).
|
||||
*/
|
||||
|
||||
#ifndef SIMU
|
||||
ISR(USART0_RX_vect)
|
||||
{
|
||||
uint8_t stat;
|
||||
uint8_t data;
|
||||
|
||||
static uint8_t numPktBytes = 0;
|
||||
static uint8_t dataState = frskyDataIdle;
|
||||
|
||||
UCSR0B &= ~(1 << RXCIE0); // disable Interrupt
|
||||
sei() ;
|
||||
stat = UCSR0A; // USART control and Status Register 0 A
|
||||
|
||||
/*
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
RxC0 TxC0 UDRE0 FE0 DOR0 UPE0 U2X0 MPCM0
|
||||
|
||||
RxC0: Receive complete
|
||||
TXC0: Transmit Complete
|
||||
UDRE0: USART Data Register Empty
|
||||
FE0: Frame Error
|
||||
DOR0: Data OverRun
|
||||
UPE0: USART Parity Error
|
||||
U2X0: Double Tx Speed
|
||||
PCM0: MultiProcessor Comms Mode
|
||||
*/
|
||||
// rh = UCSR0B; //USART control and Status Register 0 B
|
||||
|
||||
/*
|
||||
bit 7 6 5 4 3 2 1 0
|
||||
RXCIE0 TxCIE0 UDRIE0 RXEN0 TXEN0 UCSZ02 RXB80 TXB80
|
||||
|
||||
RxCIE0: Receive Complete int enable
|
||||
TXCIE0: Transmit Complete int enable
|
||||
UDRIE0: USART Data Register Empty int enable
|
||||
RXEN0: Rx Enable
|
||||
TXEN0: Tx Enable
|
||||
UCSZ02: Character Size bit 2
|
||||
RXB80: Rx data bit 8
|
||||
TXB80: Tx data bit 8
|
||||
*/
|
||||
|
||||
data = UDR0; // USART data register 0
|
||||
|
||||
if (stat & ((1 << FE0) | (1 << DOR0) | (1 << UPE0)))
|
||||
{ // discard buffer and start fresh on any comms error
|
||||
FrskyRxBufferReady = 0;
|
||||
numPktBytes = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FrskyRxBufferReady == 0) // can't get more data if the buffer hasn't been cleared
|
||||
{
|
||||
switch (dataState)
|
||||
{
|
||||
case frskyDataStart:
|
||||
if (data == START_STOP) break; // Remain in userDataStart if possible 0x7e,0x7e doublet found.
|
||||
|
||||
if (numPktBytes < 19)
|
||||
frskyRxBuffer[numPktBytes++] = data;
|
||||
dataState = frskyDataInFrame;
|
||||
break;
|
||||
|
||||
case frskyDataInFrame:
|
||||
if (data == BYTESTUFF)
|
||||
{
|
||||
dataState = frskyDataXOR; // XOR next byte
|
||||
break;
|
||||
}
|
||||
if (data == START_STOP) // end of frame detected
|
||||
{
|
||||
processFrskyPacket(frskyRxBuffer); // FrskyRxBufferReady = 1;
|
||||
dataState = frskyDataIdle;
|
||||
break;
|
||||
}
|
||||
frskyRxBuffer[numPktBytes++] = data;
|
||||
break;
|
||||
|
||||
case frskyDataXOR:
|
||||
if (numPktBytes < 19)
|
||||
frskyRxBuffer[numPktBytes++] = data ^ STUFF_MASK;
|
||||
dataState = frskyDataInFrame;
|
||||
break;
|
||||
|
||||
case frskyDataIdle:
|
||||
if (data == START_STOP)
|
||||
{
|
||||
numPktBytes = 0;
|
||||
dataState = frskyDataStart;
|
||||
}
|
||||
break;
|
||||
|
||||
} // switch
|
||||
} // if (FrskyRxBufferReady == 0)
|
||||
}
|
||||
cli() ;
|
||||
UCSR0B |= (1 << RXCIE0); // enable Interrupt
|
||||
}
|
||||
|
||||
/*
|
||||
USART0 (transmit) Data Register Emtpy ISR
|
||||
Usef to transmit FrSky data packets, which are buffered in frskyTXBuffer.
|
||||
*/
|
||||
|
||||
ISR(USART0_UDRE_vect)
|
||||
{
|
||||
if (frskyTxBufferCount > 0) {
|
||||
UDR0 = frskyTxBuffer[frskyTxISRIndex++];
|
||||
frskyTxBufferCount--;
|
||||
}
|
||||
else {
|
||||
UCSR0B &= ~(1 << UDRIE0); // disable UDRE0 interrupt
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/******************************************/
|
||||
|
||||
void frskyTransmitBuffer()
|
||||
{
|
||||
frskyTxISRIndex = 0;
|
||||
UCSR0B |= (1 << UDRIE0); // enable UDRE0 interrupt
|
||||
}
|
||||
|
||||
|
||||
uint8_t FrskyAlarmSendState = 0 ;
|
||||
uint8_t FrskyDelay = 0 ;
|
||||
|
||||
|
||||
void FRSKY10mspoll(void)
|
||||
{
|
||||
if (FrskyDelay)
|
||||
{
|
||||
FrskyDelay -= 1 ;
|
||||
return ;
|
||||
}
|
||||
|
||||
if (frskyTxBufferCount)
|
||||
{
|
||||
return; // we only have one buffer. If it's in use, then we can't send yet.
|
||||
}
|
||||
|
||||
// Now send a packet
|
||||
{
|
||||
FrskyAlarmSendState -= 1 ;
|
||||
uint8_t channel = 1 - (FrskyAlarmSendState / 2);
|
||||
uint8_t alarm = 1 - (FrskyAlarmSendState % 2);
|
||||
|
||||
uint8_t i = 0;
|
||||
frskyTxBuffer[i++] = START_STOP; // Start of packet
|
||||
frskyTxBuffer[i++] = (A22PKT + FrskyAlarmSendState); // fc - fb - fa - f9
|
||||
frskyPushValue(i, g_model.frsky.channels[channel].alarms_value[alarm]);
|
||||
{
|
||||
uint8_t *ptr ;
|
||||
ptr = &frskyTxBuffer[i] ;
|
||||
*ptr++ = ALARM_GREATER(channel, alarm);
|
||||
*ptr++ = ALARM_LEVEL(channel, alarm);
|
||||
*ptr++ = 0x00 ;
|
||||
*ptr++ = 0x00 ;
|
||||
*ptr++ = 0x00 ;
|
||||
*ptr++ = 0x00 ;
|
||||
*ptr++ = 0x00 ;
|
||||
*ptr++ = START_STOP; // End of packet
|
||||
i += 8 ;
|
||||
}
|
||||
FrskyDelay = 5 ; // 50mS
|
||||
frskyTxBufferCount = i;
|
||||
frskyTransmitBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
// Send packet requesting all alarm settings be sent back to us
|
||||
void FRSKY_setRSSIAlarms(void)
|
||||
{
|
||||
if (frskyTxBufferCount) return; // we only have one buffer. If it's in use, then we can't send. Sorry.
|
||||
|
||||
uint8_t i = 0;
|
||||
|
||||
for (int alarm=0; alarm<2; alarm++) {
|
||||
frskyTxBuffer[i++] = START_STOP; // Start of packet
|
||||
frskyTxBuffer[i++] = (RSSI1PKT-alarm); // f7 - f6
|
||||
frskyPushValue(i, g_eeGeneral.frskyRssiAlarms[alarm].value+50-(10*i));
|
||||
{
|
||||
uint8_t *ptr ;
|
||||
ptr = &frskyTxBuffer[i] ;
|
||||
*ptr++ = 0x00 ;
|
||||
*ptr++ = g_eeGeneral.frskyRssiAlarms[alarm].level;
|
||||
*ptr++ = 0x00 ;
|
||||
*ptr++ = 0x00 ;
|
||||
*ptr++ = 0x00 ;
|
||||
*ptr++ = 0x00 ;
|
||||
*ptr++ = 0x00 ;
|
||||
*ptr++ = START_STOP; // End of packet
|
||||
i += 8 ;
|
||||
}
|
||||
}
|
||||
|
||||
frskyTxBufferCount = i;
|
||||
frskyTransmitBuffer();
|
||||
}
|
||||
|
||||
bool FRSKY_alarmRaised(uint8_t idx)
|
||||
{
|
||||
for (int i=0; i<2; i++) {
|
||||
if (ALARM_LEVEL(idx, i) != alarm_off) {
|
||||
if (ALARM_GREATER(idx, i)) {
|
||||
if (frskyTelemetry[idx].value > g_model.frsky.channels[idx].alarms_value[i])
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (frskyTelemetry[idx].value < g_model.frsky.channels[idx].alarms_value[i])
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void FRSKY_EnableTXD(void)
|
||||
{
|
||||
frskyTxBufferCount = 0;
|
||||
UCSR0B |= (1 << TXEN0) | (1 << UDRIE0); // enable TX and TX interrupt
|
||||
}
|
||||
|
||||
inline void FRSKY_EnableRXD(void)
|
||||
{
|
||||
|
||||
UCSR0B |= (1 << RXEN0); // enable RX
|
||||
UCSR0B |= (1 << RXCIE0); // enable Interrupt
|
||||
}
|
||||
|
||||
#if 0
|
||||
void FRSKY_DisableTXD(void)
|
||||
{
|
||||
UCSR0B &= ~((1 << TXEN0) | (1 << UDRIE0)); // disable TX pin and interrupt
|
||||
}
|
||||
|
||||
void FRSKY_DisableRXD(void)
|
||||
{
|
||||
UCSR0B &= ~(1 << RXEN0); // disable RX
|
||||
UCSR0B &= ~(1 << RXCIE0); // disable Interrupt
|
||||
}
|
||||
#endif
|
||||
|
||||
void FRSKY_Init(void)
|
||||
{
|
||||
// clear frsky variables
|
||||
memset(frskyAlarms, 0, sizeof(frskyAlarms));
|
||||
resetTelemetry();
|
||||
|
||||
DDRE &= ~(1 << DDE0); // set RXD0 pin as input
|
||||
PORTE &= ~(1 << PORTE0); // disable pullup on RXD0 pin
|
||||
|
||||
#undef BAUD
|
||||
#define BAUD 9600
|
||||
#ifndef SIMU
|
||||
#include <util/setbaud.h>
|
||||
|
||||
UBRR0H = UBRRH_VALUE;
|
||||
UBRR0L = UBRRL_VALUE;
|
||||
UCSR0A &= ~(1 << U2X0); // disable double speed operation.
|
||||
|
||||
// set 8 N1
|
||||
UCSR0B = 0 | (0 << RXCIE0) | (0 << TXCIE0) | (0 << UDRIE0) | (0 << RXEN0) | (0 << TXEN0) | (0 << UCSZ02);
|
||||
UCSR0C = 0 | (1 << UCSZ01) | (1 << UCSZ00);
|
||||
|
||||
|
||||
while (UCSR0A & (1 << RXC0)) UDR0; // flush receive buffer
|
||||
|
||||
#endif
|
||||
|
||||
// These should be running right from power up on a FrSky enabled '9X.
|
||||
FRSKY_EnableTXD(); // enable FrSky-Telemetry reception
|
||||
FRSKY_EnableRXD(); // enable FrSky-Telemetry reception
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Send packet requesting all alarm settings be sent back to us
|
||||
void frskyAlarmsRefresh()
|
||||
{
|
||||
|
||||
if (frskyTxBufferCount) return; // we only have one buffer. If it's in use, then we can't send. Sorry.
|
||||
|
||||
{
|
||||
uint8_t *ptr ;
|
||||
ptr = &frskyTxBuffer[0] ;
|
||||
*ptr++ = START_STOP; // Start of packet
|
||||
*ptr++ = ALRM_REQUEST;
|
||||
*ptr++ = 0x00 ;
|
||||
*ptr++ = 0x00 ;
|
||||
*ptr++ = 0x00 ;
|
||||
*ptr++ = 0x00 ;
|
||||
*ptr++ = 0x00 ;
|
||||
*ptr++ = 0x00 ;
|
||||
*ptr++ = 0x00 ;
|
||||
*ptr++ = 0x00 ;
|
||||
*ptr++ = START_STOP; // End of packet
|
||||
}
|
||||
|
||||
frskyTxBufferCount = 11;
|
||||
frskyTransmitBuffer();
|
||||
}
|
||||
#endif
|
||||
|
||||
void frskyPushValue(uint8_t & i, uint8_t value)
|
||||
{
|
||||
// byte stuff the only byte than might need it
|
||||
if (value == START_STOP) {
|
||||
frskyTxBuffer[i++] = BYTESTUFF;
|
||||
frskyTxBuffer[i++] = 0x5e;
|
||||
}
|
||||
else if (value == BYTESTUFF) {
|
||||
frskyTxBuffer[i++] = BYTESTUFF;
|
||||
frskyTxBuffer[i++] = 0x5d;
|
||||
}
|
||||
else {
|
||||
frskyTxBuffer[i++] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void FrskyData::set(uint8_t value)
|
||||
{
|
||||
this->value = value;
|
||||
if (!max || max < value)
|
||||
max = value;
|
||||
if (!min || min > value)
|
||||
min = value;
|
||||
}
|
||||
|
||||
void resetTelemetry()
|
||||
{
|
||||
memset(frskyTelemetry, 0, sizeof(frskyTelemetry));
|
||||
memset(frskyRSSI, 0, sizeof(frskyRSSI));
|
||||
}
|
||||
|
62
src/frsky.h
Normal file
62
src/frsky.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Author - Bertrand Songis <bsongis@gmail.com>
|
||||
*
|
||||
* frsky.cpp original authors - Bryan J.Rentoul (Gruvin) <gruvin@gmail.com> and Philip Moss Adapted from jeti.cpp code by Karl
|
||||
* Szmutny <shadow@privy.de>*
|
||||
*
|
||||
* 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 FRSKY_H
|
||||
#define FRSKY_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
// .20 seconds
|
||||
#define FRSKY_TIMEOUT10ms 20
|
||||
|
||||
enum AlarmLevel {
|
||||
alarm_off = 0,
|
||||
alarm_yellow = 1,
|
||||
alarm_orange = 2,
|
||||
alarm_red = 3
|
||||
};
|
||||
|
||||
#define ALARM_GREATER(channel, alarm) ((g_model.frsky.channels[channel].alarms_greater >> alarm) & 1)
|
||||
#define ALARM_LEVEL(channel, alarm) ((g_model.frsky.channels[channel].alarms_level >> (2*alarm)) & 3)
|
||||
|
||||
struct FrskyData {
|
||||
uint8_t value;
|
||||
uint8_t min;
|
||||
uint8_t max;
|
||||
void set(uint8_t value);
|
||||
};
|
||||
|
||||
// Global Fr-Sky telemetry data variables
|
||||
extern uint8_t frskyStreaming; // >0 (true) == data is streaming in. 0 = nodata detected for some time
|
||||
extern uint8_t FrskyAlarmSendState;
|
||||
extern FrskyData frskyTelemetry[2];
|
||||
extern FrskyData frskyRSSI[2];
|
||||
|
||||
void FRSKY_Init(void);
|
||||
void FRSKY10mspoll(void);
|
||||
|
||||
inline void FRSKY_setModelAlarms(void)
|
||||
{
|
||||
FrskyAlarmSendState = 4 ;
|
||||
}
|
||||
|
||||
bool FRSKY_alarmRaised(uint8_t idx);
|
||||
|
||||
void resetTelemetry();
|
||||
|
||||
#endif
|
||||
|
36
src/fuses_2561.txt
Normal file
36
src/fuses_2561.txt
Normal file
|
@ -0,0 +1,36 @@
|
|||
The ATmega2561 uses quite different bit assignment for its option fuses
|
||||
|
||||
|
||||
Fuse defaults for ATmega64A
|
||||
|
||||
Default values for ATmega64 are:
|
||||
hfuse = 0b10011001 (0x99)
|
||||
lfuse = 0b11100001 (0xE1)
|
||||
efuse = 0b11111101 (0xFD)
|
||||
|
||||
Preferred values for ATmega64A are:
|
||||
hfuse = 0x11
|
||||
lfuse = 0x1F
|
||||
efuse = 0xff
|
||||
|
||||
... which includes EESAVE feature, so that the EEPROM model data does NOT get
|
||||
erased during chip erase prior to re-programming ... respectively.
|
||||
|
||||
- - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
Fuse defaults for ATmega2560/1 are:
|
||||
|
||||
hfuse = 0b10011001 (0x99)
|
||||
lfuse = 0b01100010 (0x62)
|
||||
efuse = 0b11111111 (0xFF)
|
||||
|
||||
The bit assignments ae quite different from the AT'64A in all cases.
|
||||
|
||||
Preferred vale es for ATmega2560/1 are:
|
||||
hfuse = 0b10011001 (0x11) [OCD enabled, JTAG enabled, WDT disabled :(,
|
||||
EESAVE enabled, BOOT at 0x0000]
|
||||
lfuse = 0b01101110 (0xd7) [CKDIV8 disabled, CKOUT disabled,
|
||||
Full Swing Xtal Osc, 16K CK + 0ms reset,
|
||||
BOD enabled]
|
||||
efuse = 0b11111111 (0xfc) [ Brown out detector (BOD) = 4.3V ]
|
||||
|
552
src/general_menus.cpp
Normal file
552
src/general_menus.cpp
Normal file
|
@ -0,0 +1,552 @@
|
|||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
*
|
||||
* gruvin9x is based on code named er9x by
|
||||
* Author - Erez Raviv <erezraviv@gmail.com>, which is in turn
|
||||
* was based on 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 "menus.h"
|
||||
#include "sticks.lbm"
|
||||
|
||||
enum EnumTabDiag {
|
||||
e_Setup,
|
||||
#if defined(PCBV3)
|
||||
e_FrskyTime,
|
||||
#endif
|
||||
e_Trainer,
|
||||
e_Vers,
|
||||
e_Keys,
|
||||
e_Ana,
|
||||
e_Calib
|
||||
};
|
||||
|
||||
void menuProcSetup(uint8_t event);
|
||||
#if defined(PCBV3)
|
||||
void menuProcTime(uint8_t event);
|
||||
#endif
|
||||
void menuProcTrainer(uint8_t event);
|
||||
void menuProcDiagVers(uint8_t event);
|
||||
void menuProcDiagKeys(uint8_t event);
|
||||
void menuProcDiagAna(uint8_t event);
|
||||
void menuProcDiagCalib(uint8_t event);
|
||||
|
||||
MenuFuncP_PROGMEM APM menuTabDiag[] = {
|
||||
menuProcSetup,
|
||||
#if defined(PCBV3)
|
||||
menuProcTime,
|
||||
#endif
|
||||
menuProcTrainer,
|
||||
menuProcDiagVers,
|
||||
menuProcDiagKeys,
|
||||
menuProcDiagAna,
|
||||
menuProcDiagCalib
|
||||
};
|
||||
|
||||
void menuProcSetup(uint8_t event)
|
||||
{
|
||||
#define COUNT_ITEMS 19
|
||||
#define PARAM_OFS 17*FW
|
||||
|
||||
SIMPLE_MENU("RADIO SETUP", menuTabDiag, e_Setup, COUNT_ITEMS+1);
|
||||
|
||||
int8_t sub = m_posVert;
|
||||
|
||||
// last 2 lines (radio mode) are non break-able
|
||||
if(s_pgOfs==COUNT_ITEMS-7) s_pgOfs= sub<(COUNT_ITEMS-4) ? COUNT_ITEMS-8 : COUNT_ITEMS-6;
|
||||
|
||||
uint8_t y = 1*FH;
|
||||
|
||||
uint8_t subN = 1;
|
||||
if(s_pgOfs<subN) {
|
||||
lcd_puts_P(0, y,PSTR("Beeper"));
|
||||
lcd_putsnAtt(PARAM_OFS - FW, y, PSTR("Quiet""NoKey""Norm ""Long ""xLong")+5*g_eeGeneral.beeperVal,5,(sub==subN ? INVERS:0));
|
||||
if(sub==subN) CHECK_INCDEC_GENVAR(event, g_eeGeneral.beeperVal, 0, 4);
|
||||
if((y+=FH)>7*FH) return;
|
||||
}subN++;
|
||||
|
||||
if(s_pgOfs<subN) {
|
||||
lcd_puts_P(0, y,PSTR("Contrast"));
|
||||
lcd_outdezAtt(PARAM_OFS,y,g_eeGeneral.contrast,(sub==subN ? INVERS : 0)|LEFT);
|
||||
if(sub==subN) {
|
||||
CHECK_INCDEC_GENVAR(event, g_eeGeneral.contrast, 10, 45);
|
||||
lcdSetRefVolt(g_eeGeneral.contrast);
|
||||
}
|
||||
if((y+=FH)>7*FH) return;
|
||||
}subN++;
|
||||
|
||||
if(s_pgOfs<subN) {
|
||||
lcd_puts_P(0, y,PSTR("Battery warning"));
|
||||
putsVolts(PARAM_OFS, y, g_eeGeneral.vBatWarn, (sub==subN ? INVERS : 0)|LEFT);
|
||||
if(sub==subN) CHECK_INCDEC_GENVAR(event, g_eeGeneral.vBatWarn, 40, 120); //4-12V
|
||||
if((y+=FH)>7*FH) return;
|
||||
}subN++;
|
||||
|
||||
if(s_pgOfs<subN) {
|
||||
lcd_puts_P(0, y,PSTR("Inactivity alarm"));
|
||||
lcd_outdezAtt(PARAM_OFS, y, g_eeGeneral.inactivityTimer, (sub==subN ? INVERS : 0)|LEFT);
|
||||
lcd_putc(lcd_lastPos, y, 'm');
|
||||
if(sub==subN) g_eeGeneral.inactivityTimer = checkIncDec(event, g_eeGeneral.inactivityTimer, 0, 250, EE_GENERAL); //0..250minutes
|
||||
if((y+=FH)>7*FH) return;
|
||||
}subN++;
|
||||
|
||||
if(s_pgOfs<subN) {
|
||||
lcd_puts_P(0, y,PSTR("Filter ADC"));
|
||||
lcd_putsnAtt(PARAM_OFS, y, PSTR("SINGOSMPFILT")+4*g_eeGeneral.filterInput,4,(sub==subN ? INVERS:0));
|
||||
if(sub==subN) CHECK_INCDEC_GENVAR(event, g_eeGeneral.filterInput, 0, 2);
|
||||
if((y+=FH)>7*FH) return;
|
||||
}subN++;
|
||||
|
||||
if(s_pgOfs<subN) {
|
||||
lcd_puts_P(0, y,PSTR("Throttle reverse"));
|
||||
menu_lcd_onoff( PARAM_OFS, y, g_eeGeneral.throttleReversed, sub==subN ) ;
|
||||
if(sub==subN) CHECK_INCDEC_GENVAR(event, g_eeGeneral.throttleReversed, 0, 1);
|
||||
if((y+=FH)>7*FH) return;
|
||||
}subN++;
|
||||
|
||||
if(s_pgOfs<subN) {
|
||||
lcd_puts_P(0, y,PSTR("Minute beep"));
|
||||
menu_lcd_onoff( PARAM_OFS, y, g_eeGeneral.minuteBeep, sub==subN ) ;
|
||||
if(sub==subN) CHECK_INCDEC_GENVAR(event, g_eeGeneral.minuteBeep, 0, 1);
|
||||
if((y+=FH)>7*FH) return;
|
||||
}subN++;
|
||||
|
||||
if(s_pgOfs<subN) {
|
||||
lcd_puts_P(0, y,PSTR("Beep countdown"));
|
||||
menu_lcd_onoff( PARAM_OFS, y, g_eeGeneral.preBeep, sub==subN ) ;
|
||||
if(sub==subN) CHECK_INCDEC_GENVAR(event, g_eeGeneral.preBeep, 0, 1);
|
||||
if((y+=FH)>7*FH) return;
|
||||
}subN++;
|
||||
|
||||
if(s_pgOfs<subN) {
|
||||
lcd_puts_P(0, y,PSTR("Flash on beep"));
|
||||
menu_lcd_onoff( PARAM_OFS, y, g_eeGeneral.flashBeep, sub==subN ) ;
|
||||
if(sub==subN) CHECK_INCDEC_GENVAR(event, g_eeGeneral.flashBeep, 0, 1);
|
||||
if((y+=FH)>7*FH) return;
|
||||
}subN++;
|
||||
|
||||
if(s_pgOfs<subN) {
|
||||
lcd_puts_P(0, y,PSTR("Light switch"));
|
||||
putsSwitches(PARAM_OFS,y,g_eeGeneral.lightSw,sub==subN ? INVERS : 0);
|
||||
if(sub==subN) CHECK_INCDEC_GENVAR(event, g_eeGeneral.lightSw, -MAX_SWITCH, MAX_SWITCH);
|
||||
if((y+=FH)>7*FH) return;
|
||||
}subN++;
|
||||
|
||||
if(s_pgOfs<subN) {
|
||||
lcd_puts_P(0, y,PSTR("Light off after"));
|
||||
if(g_eeGeneral.lightAutoOff) {
|
||||
lcd_outdezAtt(PARAM_OFS, y, g_eeGeneral.lightAutoOff*5,LEFT|(sub==subN ? INVERS : 0));
|
||||
lcd_putc(lcd_lastPos, y, 's');
|
||||
}
|
||||
else
|
||||
lcd_putsnAtt(PARAM_OFS, y, PSTR("OFF"),3,(sub==subN ? INVERS:0));
|
||||
if(sub==subN) CHECK_INCDEC_GENVAR(event, g_eeGeneral.lightAutoOff, 0, 600/5);
|
||||
if((y+=FH)>7*FH) return;
|
||||
}subN++;
|
||||
|
||||
if(s_pgOfs<subN) {
|
||||
uint8_t b = 1-g_eeGeneral.disableSplashScreen;
|
||||
lcd_puts_P(0, y,PSTR("Splash screen"));
|
||||
menu_lcd_onoff( PARAM_OFS, y, b, sub==subN ) ;
|
||||
if(sub==subN)
|
||||
{
|
||||
CHECK_INCDEC_GENVAR(event, b, 0, 1);
|
||||
g_eeGeneral.disableSplashScreen = 1-b;
|
||||
}
|
||||
if((y+=FH)>7*FH) return;
|
||||
}subN++;
|
||||
|
||||
if(s_pgOfs<subN) {
|
||||
uint8_t b = 1-g_eeGeneral.disableThrottleWarning;
|
||||
lcd_puts_P(0, y,PSTR("Throttle Warning"));
|
||||
menu_lcd_onoff( PARAM_OFS, y, b, sub==subN ) ;
|
||||
if(sub==subN)
|
||||
{
|
||||
CHECK_INCDEC_GENVAR(event, b, 0, 1);
|
||||
g_eeGeneral.disableThrottleWarning = 1-b;
|
||||
}
|
||||
if((y+=FH)>7*FH) return;
|
||||
}subN++;
|
||||
|
||||
if(s_pgOfs<subN) {
|
||||
lcd_puts_P(0, y,PSTR("Switch Warning"));
|
||||
lcd_putsnAtt(PARAM_OFS, y, PSTR("Down""OFF ""Up ")+4*(1+g_eeGeneral.switchWarning),4,(sub==subN ? INVERS:0));
|
||||
if(sub==subN)
|
||||
CHECK_INCDEC_GENVAR(event, g_eeGeneral.switchWarning, -1, 1);
|
||||
if((y+=FH)>7*FH) return;
|
||||
}subN++;
|
||||
|
||||
if(s_pgOfs<subN) {
|
||||
uint8_t b = 1-g_eeGeneral.disableMemoryWarning;
|
||||
lcd_puts_P(0, y,PSTR("Memory Warning"));
|
||||
menu_lcd_onoff( PARAM_OFS, y, b, sub==subN ) ;
|
||||
if(sub==subN)
|
||||
{
|
||||
CHECK_INCDEC_GENVAR(event, b, 0, 1);
|
||||
g_eeGeneral.disableMemoryWarning = 1-b;
|
||||
}
|
||||
if((y+=FH)>7*FH) return;
|
||||
}subN++;
|
||||
|
||||
if(s_pgOfs<subN) {
|
||||
uint8_t b = 1-g_eeGeneral.disableAlarmWarning;
|
||||
lcd_puts_P(0, y,PSTR("Alarm Warning"));
|
||||
menu_lcd_onoff( PARAM_OFS, y, b, sub==subN ) ;
|
||||
if(sub==subN)
|
||||
{
|
||||
CHECK_INCDEC_GENVAR(event, b, 0, 1);
|
||||
g_eeGeneral.disableAlarmWarning = 1-b;
|
||||
}
|
||||
if((y+=FH)>7*FH) return;
|
||||
}subN++;
|
||||
|
||||
if(s_pgOfs<subN) {
|
||||
uint8_t b = g_eeGeneral.enableTelemetryAlarm;
|
||||
lcd_puts_P(0, y,PSTR("NO DATA Alarm"));
|
||||
menu_lcd_onoff( PARAM_OFS, y, b, sub==subN ) ;
|
||||
if(sub==subN)
|
||||
{
|
||||
CHECK_INCDEC_GENVAR(event, b, 0, 1);
|
||||
g_eeGeneral.enableTelemetryAlarm = b;
|
||||
}
|
||||
if((y+=FH)>7*FH) return;
|
||||
}subN++;
|
||||
|
||||
if(s_pgOfs<subN) {
|
||||
uint8_t attr = sub==subN?INVERS:0;
|
||||
lcd_puts_P(0, y,PSTR("Rx Channel Ord"));// RAET->AETR
|
||||
for (uint8_t i=1; i<=4; i++)
|
||||
putsChnLetter((16+i)*FW, y, i, attr);
|
||||
if(attr) CHECK_INCDEC_GENVAR(event, g_eeGeneral.templateSetup, 0, 23);
|
||||
if((y+=FH)>7*FH) return;
|
||||
}subN++;
|
||||
|
||||
if(s_pgOfs<subN) {
|
||||
lcd_puts_P( 1*FW, y, PSTR("Mode"));//sub==3?INVERS:0);
|
||||
if(y<7*FH) {for(uint8_t i=0; i<4; i++) lcd_img((6+4*i)*FW, y, sticks,i,0); }
|
||||
if((y+=FH)>7*FH) return;
|
||||
|
||||
lcd_putcAtt( 3*FW, y, '1'+g_eeGeneral.stickMode,sub==subN?INVERS:0);
|
||||
for(uint8_t i=0; i<4; i++) putsChnRaw( (6+4*i)*FW, y,i+1,0);//sub==3?INVERS:0);
|
||||
|
||||
if(sub==subN) CHECK_INCDEC_GENVAR(event,g_eeGeneral.stickMode,0,3);
|
||||
if((y+=FH)>7*FH) return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if defined(PCBV3)
|
||||
// SD card interface contains Real-Time-Clock chip
|
||||
void menuProcTime(uint8_t event)
|
||||
{
|
||||
MENU("DATE AND TIME", menuTabDiag, e_FrskyTime, 3, {0, 2/*, 2*/});
|
||||
|
||||
int8_t sub = m_posVert - 1; // vertical position (1 = page counter, top/right)
|
||||
uint8_t subSub = m_posHorz; // horizontal position
|
||||
static struct tm t;
|
||||
struct tm *at = &t;
|
||||
|
||||
switch(event)
|
||||
{
|
||||
case EVT_KEY_LONG(KEY_MENU):
|
||||
// get data time from RTC chip (may not implement)
|
||||
killEvents(event);
|
||||
break;
|
||||
case EVT_KEY_FIRST(KEY_MENU):
|
||||
if (sub >= 0 && !s_editMode) // set the date and time into RTC chip
|
||||
{
|
||||
g_ms100 = 0; // start of next second begins now
|
||||
g_unixTime = mktime(&t); // update local timestamp and get wday calculated
|
||||
|
||||
RTC rtc;
|
||||
rtc.year = t.tm_year + 1900;
|
||||
rtc.month = t.tm_mon + 1;
|
||||
rtc.mday = t.tm_mday;
|
||||
rtc.hour = t.tm_hour;
|
||||
rtc.min = t.tm_min;
|
||||
rtc.sec = t.tm_sec;
|
||||
rtc.wday = t.tm_wday + 1;
|
||||
|
||||
rtc_settime(&rtc);
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!s_editMode) filltm(&g_unixTime, &t);
|
||||
|
||||
lcd_putc(FW*10+2, FH*2, '-'); lcd_putc(FW*13, FH*2, '-');
|
||||
lcd_putc(FW*10+1, FH*4, ':'); lcd_putc(FW*13-1, FH*4, ':');
|
||||
|
||||
for(uint8_t i=0; i<2; i++) // 2 rows, date then time
|
||||
{
|
||||
uint8_t y=(i*2+2)*FH;
|
||||
|
||||
lcd_putsnAtt(0, y, PSTR("DATE:""TIME:")+i*5, 5, 0);
|
||||
|
||||
for(uint8_t j=0; j<3;j++) // 3 settings each for date and time (YMD and HMS)
|
||||
{
|
||||
uint8_t attr = (sub==i && subSub==j) ? (s_editMode ? BLINK : INVERS) : 0;
|
||||
switch(i)
|
||||
{
|
||||
case 0: // DATE
|
||||
switch(j)
|
||||
{
|
||||
case 0:
|
||||
lcd_outdezAtt(FW*10+2, y, at->tm_year+1900, attr);
|
||||
if(attr && (s_editMode || p1valdiff)) at->tm_year = checkIncDec( event, at->tm_year, 110, 200, 0);
|
||||
break;
|
||||
case 1:
|
||||
lcd_outdezNAtt(FW*13, y, at->tm_mon+1, attr|LEADING0, 2);
|
||||
if(attr && (s_editMode || p1valdiff)) at->tm_mon = checkIncDec( event, at->tm_mon, 0, 11, 0);
|
||||
break;
|
||||
case 2:
|
||||
lcd_outdezNAtt(FW*16-2, y, at->tm_mday, attr|LEADING0, 2);
|
||||
if(attr && (s_editMode || p1valdiff)) at->tm_mday = checkIncDec( event, at->tm_mday, 1, 31, 0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
switch (j)
|
||||
{
|
||||
case 0:
|
||||
lcd_outdezNAtt(FW*10+1, y, at->tm_hour, attr|LEADING0, 2);
|
||||
if(attr && (s_editMode || p1valdiff)) at->tm_hour = checkIncDec( event, at->tm_hour, 0, 23, 0);
|
||||
break;
|
||||
case 1:
|
||||
lcd_outdezNAtt(FW*13-1, y, at->tm_min, attr|LEADING0, 2);
|
||||
if(attr && (s_editMode || p1valdiff)) at->tm_min = checkIncDec( event, at->tm_min, 0, 59, 0);
|
||||
break;
|
||||
case 2:
|
||||
lcd_outdezNAtt(FW*16-2, y, at->tm_sec, attr|LEADING0, 2);
|
||||
if(attr && (s_editMode || p1valdiff)) at->tm_sec = checkIncDec( event, at->tm_sec, 0, 59, 0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void menuProcTrainer(uint8_t event)
|
||||
{
|
||||
MENU("TRAINER", menuTabDiag, e_Trainer, 7, {0, 2, 2, 2, 2/*, 0, 0*/});
|
||||
|
||||
int8_t sub = m_posVert;
|
||||
uint8_t subSub = m_posHorz;
|
||||
uint8_t y;
|
||||
bool edit;
|
||||
uint8_t blink ;
|
||||
|
||||
if (SLAVE_MODE) { // i am the slave
|
||||
lcd_puts_P(7*FW, 3*FH, PSTR("Slave"));
|
||||
return;
|
||||
}
|
||||
|
||||
lcd_puts_P(3*FW, 1*FH, PSTR("mode % src"));
|
||||
|
||||
sub--;
|
||||
y = 2*FH;
|
||||
blink = s_editMode ? BLINK : INVERS ;
|
||||
|
||||
for (uint8_t i=0; i<4; i++) {
|
||||
uint8_t chan = chout_ar[g_eeGeneral.templateSetup][i]; // G: Issue 30.
|
||||
|
||||
volatile TrainerMix *td = &g_eeGeneral.trainer.mix[chan-1];
|
||||
|
||||
putsChnRaw(0, y, chan, 0);
|
||||
|
||||
edit = (sub==i && subSub==0);
|
||||
lcd_putsnAtt(4*FW, y, PSTR("off += :=")+3*td->mode, 3, edit ? blink : 0);
|
||||
if (edit && s_editMode)
|
||||
CHECK_INCDEC_GENVAR(event, td->mode, 0, 2);
|
||||
|
||||
edit = (sub==i && subSub==1);
|
||||
lcd_outdezAtt(11*FW, y, td->studWeight, edit ? blink : 0);
|
||||
if (edit && s_editMode)
|
||||
CHECK_INCDEC_GENVAR(event, td->studWeight, -100, 100);
|
||||
|
||||
edit = (sub==i && subSub==2);
|
||||
lcd_putsnAtt(12*FW, y, PSTR("ch1ch2ch3ch4")+3*td->srcChn, 3, edit ? blink : 0);
|
||||
if (edit && s_editMode)
|
||||
CHECK_INCDEC_GENVAR(event, td->srcChn, 0, 3);
|
||||
|
||||
edit = (sub==i && subSub==3);
|
||||
|
||||
y += FH;
|
||||
}
|
||||
|
||||
lcd_puts_P(0*FW, y, PSTR("Multiplier"));
|
||||
lcd_outdezAtt(13*FW, y, g_eeGeneral.PPM_Multiplier+10, (sub==4 ? INVERS : 0)|PREC1);
|
||||
if(sub==4) CHECK_INCDEC_GENVAR(event, g_eeGeneral.PPM_Multiplier, -10, 40);
|
||||
y += FH;
|
||||
|
||||
edit = (sub==5);
|
||||
lcd_putsAtt(0*FW, y, PSTR("Cal"), edit ? INVERS : 0);
|
||||
for (uint8_t i=0; i<4; i++) {
|
||||
uint8_t x = (i*8+16)*FW/2;
|
||||
#if defined (DECIMALS_DISPLAYED)
|
||||
lcd_outdezAtt(x , y, (g_ppmIns[i]-g_eeGeneral.trainer.calib[i])*2, PREC1);
|
||||
#else
|
||||
lcd_outdezAtt(x , y, (g_ppmIns[i]-g_eeGeneral.trainer.calib[i])/5, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (edit) {
|
||||
if (event==EVT_KEY_FIRST(KEY_MENU)){
|
||||
memcpy(g_eeGeneral.trainer.calib, g_ppmIns, sizeof(g_eeGeneral.trainer.calib));
|
||||
eeDirty(EE_GENERAL);
|
||||
beepKey();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void menuProcDiagVers(uint8_t event)
|
||||
{
|
||||
SIMPLE_MENU("VERSION", menuTabDiag, e_Vers, 1);
|
||||
|
||||
lcd_puts_P(0, 2*FH,stamp4 );
|
||||
lcd_puts_P(0, 3*FH,stamp1 );
|
||||
lcd_puts_P(0, 4*FH,stamp5 );
|
||||
lcd_puts_P(0, 5*FH,stamp2 );
|
||||
lcd_puts_P(0, 6*FH,stamp3 );
|
||||
lcd_puts_P(0, 7*FH,PSTR("EEPROM v"));
|
||||
lcd_outdezAtt(8*FW, 7*FH, g_eeGeneral.myVers, LEFT);
|
||||
}
|
||||
|
||||
void menuProcDiagKeys(uint8_t event)
|
||||
{
|
||||
SIMPLE_MENU("DIAG", menuTabDiag, e_Keys, 1);
|
||||
|
||||
for(uint8_t i=0; i<9; i++)
|
||||
{
|
||||
uint8_t y=i*FH; //+FH;
|
||||
if(i>(SW_ID0-SW_BASE_DIAG)) y-=FH; //overwrite ID0
|
||||
bool t=keyState((EnumKeys)(SW_BASE_DIAG+i));
|
||||
putsSwitches(8*FW, y, i+1, 0); //ohne off,on
|
||||
lcd_putcAtt(11*FW+2, y, t+'0', t ? INVERS : 0);
|
||||
}
|
||||
|
||||
for(uint8_t i=0; i<6; i++)
|
||||
{
|
||||
uint8_t y=(5-i)*FH+2*FH;
|
||||
bool t=keyState((EnumKeys)(KEY_MENU+i));
|
||||
lcd_putsn_P(0, y, PSTR(" Menu Exit Down UpRight Left")+5*i, 5);
|
||||
lcd_putcAtt(5*FW+2, y, t+'0', t);
|
||||
}
|
||||
|
||||
lcd_putsn_P(14*FW, 3*FH, PSTR("Trim- +"), 7);
|
||||
for(uint8_t i=0; i<4; i++)
|
||||
{
|
||||
uint8_t y=i*FH+FH*4;
|
||||
lcd_img(14*FW, y, sticks,i,0);
|
||||
bool tm=keyState((EnumKeys)(TRM_BASE+2*i));
|
||||
bool tp=keyState((EnumKeys)(TRM_BASE+2*i+1));
|
||||
lcd_putcAtt(18*FW, y, tm+'0',tm ? INVERS : 0);
|
||||
lcd_putcAtt(20*FW, y, tp+'0',tp ? INVERS : 0);
|
||||
}
|
||||
}
|
||||
|
||||
void menuProcDiagAna(uint8_t event)
|
||||
{
|
||||
SIMPLE_MENU("ANA", menuTabDiag, e_Ana, 2);
|
||||
|
||||
int8_t sub = m_posVert ;
|
||||
|
||||
for(uint8_t i=0; i<8; i++)
|
||||
{
|
||||
uint8_t y=i*FH;
|
||||
lcd_putsn_P( 4*FW, y,PSTR("A1A2A3A4A5A6A7A8")+2*i,2);
|
||||
lcd_outhex4( 8*FW, y,anaIn(i));
|
||||
if(i<7) lcd_outdez8(17*FW, y, (int32_t)calibratedStick[i]*100/1024);
|
||||
if(i==7) putsVolts(17*FW, y, g_vbat100mV, (sub==1 ? INVERS : 0));
|
||||
}
|
||||
// lcd_outdezAtt( 21*FW, 3*FH, g_eeGeneral.vBatCalib, 0) ;
|
||||
// lcd_outdezAtt( 21*FW, 4*FH, abRunningAvg, 0) ;
|
||||
// Display raw BandGap result (debug)
|
||||
lcd_putsn_P( 19*FW, 5*FH,PSTR("BG"),2) ;
|
||||
lcd_outdezAtt(21*FW, 6*FH, BandGap, 0);
|
||||
lcd_outdezAtt(21*FW, 7*FH, anaIn(7)*35/512, PREC1);
|
||||
|
||||
if(sub==1) CHECK_INCDEC_GENVAR(event, g_eeGeneral.vBatCalib, -127, 127);
|
||||
|
||||
}
|
||||
|
||||
void menuProcDiagCalib(uint8_t event)
|
||||
{
|
||||
SIMPLE_MENU("CALIBRATION", menuTabDiag, e_Calib, 4);
|
||||
|
||||
int8_t sub = m_posVert ;
|
||||
static int16_t midVals[7];
|
||||
static int16_t loVals[7];
|
||||
static int16_t hiVals[7];
|
||||
|
||||
for(uint8_t i=0; i<7; i++) { //get low and high vals for sticks and trims
|
||||
int16_t vt = anaIn(i);
|
||||
loVals[i] = min(vt,loVals[i]);
|
||||
hiVals[i] = max(vt,hiVals[i]);
|
||||
//if(i>=4) midVals[i] = (loVals[i] + hiVals[i])/2;
|
||||
}
|
||||
|
||||
switch(event)
|
||||
{
|
||||
case EVT_ENTRY:
|
||||
for(uint8_t i=0; i<7; i++) loVals[i] = 15000;
|
||||
break;
|
||||
case EVT_KEY_BREAK(KEY_DOWN): // !! achtung sub schon umgesetzt
|
||||
switch(sub)
|
||||
{
|
||||
case 2: //get mid
|
||||
for(uint8_t i=0; i<7; i++)midVals[i] = anaIn(i);
|
||||
beepKey();
|
||||
break;
|
||||
case 3:
|
||||
for(uint8_t i=0; i<7; i++)
|
||||
if(abs(loVals[i]-hiVals[i])>50) {
|
||||
g_eeGeneral.calibMid[i] = midVals[i];
|
||||
int16_t v = midVals[i] - loVals[i];
|
||||
g_eeGeneral.calibSpanNeg[i] = v - v/64;
|
||||
v = hiVals[i] - midVals[i];
|
||||
g_eeGeneral.calibSpanPos[i] = v - v/64;
|
||||
}
|
||||
int16_t sum=0;
|
||||
for(uint8_t i=0; i<12;i++) sum+=g_eeGeneral.calibMid[i];
|
||||
g_eeGeneral.chkSum = sum;
|
||||
eeDirty(EE_GENERAL); //eeWriteGeneral();
|
||||
beepKey();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
for(uint8_t i=1; i<4; i++)
|
||||
{
|
||||
uint8_t y=i*FH+FH;
|
||||
lcd_putsnAtt( 0, y,PSTR("SetMid SetSpanDone ")+7*(i-1),7,
|
||||
sub==i ? INVERS : 0);
|
||||
}
|
||||
for(uint8_t i=0; i<7; i++)
|
||||
{
|
||||
uint8_t y=i*FH;
|
||||
lcd_puts_P( 11*FW, y+1*FH, PSTR("< >"));
|
||||
lcd_outhex4( 8*FW-3, y+1*FH, sub==2 ? loVals[i] : g_eeGeneral.calibSpanNeg[i]);
|
||||
lcd_outhex4(12*FW, y+1*FH, sub==1 ? anaIn(i) : (sub==2 ? midVals[i] : g_eeGeneral.calibMid[i]));
|
||||
lcd_outhex4(17*FW, y+1*FH, sub==2 ? hiVals[i] : g_eeGeneral.calibSpanPos[i]);
|
||||
}
|
||||
|
||||
}
|
2243
src/gruvin9x.cpp
Normal file
2243
src/gruvin9x.cpp
Normal file
File diff suppressed because it is too large
Load diff
678
src/gruvin9x.h
Normal file
678
src/gruvin9x.h
Normal file
|
@ -0,0 +1,678 @@
|
|||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
*
|
||||
* gruvin9x is based on code named er9x by
|
||||
* Author - Erez Raviv <erezraviv@gmail.com>, which is in turn
|
||||
* was based on 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 gruvin9x_h
|
||||
#define gruvin9x_h
|
||||
|
||||
#define VERS 1
|
||||
#define SUB_VERS 2
|
||||
|
||||
// #define ASYNC_WRITE
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(PCBV3)
|
||||
#include "time.h"
|
||||
#endif
|
||||
|
||||
#ifdef SIMU
|
||||
#include "simpgmspace.h"
|
||||
#define APM
|
||||
#include "stdio.h"
|
||||
#else
|
||||
///opt/cross/avr/include/avr/pgmspace.h
|
||||
#include <stddef.h>
|
||||
#include <avr/io.h>
|
||||
#define assert(x)
|
||||
//disable whole pgmspace functionality for all avr-gcc because
|
||||
//avr-gcc > 4.2.1 does not work anyway
|
||||
//http://www.mail-archive.com/gcc-bugs@gcc.gnu.org/msg239240.html
|
||||
//http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34734
|
||||
//
|
||||
//Workarounds:
|
||||
//
|
||||
//PSTR is fixed below
|
||||
//all prog_xx definitions must use APM explicitely
|
||||
|
||||
//#define __ATTR_PROGMEM__
|
||||
#include <avr/pgmspace.h>
|
||||
#ifdef __cplusplus
|
||||
#define APM __attribute__(( section(".progmem.data") ))
|
||||
#undef PSTR
|
||||
#define PSTR(s) (__extension__({static prog_char APM __c[] = (s);&__c[0];}))
|
||||
#endif
|
||||
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/sleep.h>
|
||||
#include <avr/interrupt.h>
|
||||
#define F_CPU 16000000UL // 16 MHz
|
||||
#include <util/delay.h>
|
||||
#define pgm_read_adr(address_short) pgm_read_word(address_short)
|
||||
#include <avr/wdt.h>
|
||||
#endif
|
||||
|
||||
#include "file.h"
|
||||
|
||||
extern RlcFile theFile; //used for any file operation
|
||||
|
||||
//
|
||||
// elev thr
|
||||
// LV RV
|
||||
// 2 ^ 4 ^
|
||||
// 1 2
|
||||
// | rudd | aile
|
||||
// <----X--3-> LH <----X--0-> RH
|
||||
// 6 | 7 1 | 0
|
||||
// | |
|
||||
// 3 v 5 v
|
||||
//
|
||||
|
||||
|
||||
//PORTA 7 6 5 4 3 2 1 0
|
||||
// O O O O O O O O
|
||||
// ------------------------ LCD_DAT -----------------------
|
||||
//
|
||||
//PORTB 7 6 5 4 3 2 1 0
|
||||
// O i i i i i i O
|
||||
// light KEY_LFT KEY_RGT KEY_UP KEY_DWN KEY_EXT KEY_MEN PPM
|
||||
//
|
||||
//PORTC 7 6 5 4 3 2 1 0
|
||||
// - - O O O O O -
|
||||
// NC NC LCD_E LCD_RNW LCD_A0 LCD_RES LCD_CS1 NC
|
||||
//
|
||||
//PORTD 7 6 5 4 3 2 1 0
|
||||
// i i i i i i i i
|
||||
// TRM_D_DWN _UP TRM_C_DWN _UP TRM_B_DWN _UP TRM_A_DWN _UP
|
||||
//
|
||||
//PORTE 7 6 5 4 3 2 1 0
|
||||
// i i i i O i i i
|
||||
// PPM_IN ID2 Trainer Gear Buzzer ElevDR AileDR THRCT
|
||||
//
|
||||
//PORTF 7 6 5 4 3 2 1 0
|
||||
// ai ai ai ai ai ai ai ai
|
||||
// ANA_ BAT PITT_TRM HOV_THR HOV_PIT STCK_LH STCK_RV STCK_LV STCK_RH
|
||||
// rud thro elev aile
|
||||
//PORTG 7 6 5 4 3 2 1 0
|
||||
// - - - O i i i
|
||||
// SIM_CTL ID1 NC RF_POW RuddDR
|
||||
|
||||
#define PORTA_LCD_DAT PORTA
|
||||
|
||||
#if defined (PCBV3)
|
||||
#define OUT_C_LIGHT 0
|
||||
#else
|
||||
#define OUT_B_LIGHT 7
|
||||
#endif
|
||||
|
||||
#define INP_B_KEY_LFT 6
|
||||
#define INP_B_KEY_RGT 5
|
||||
#define INP_B_KEY_UP 4
|
||||
#define INP_B_KEY_DWN 3
|
||||
#define INP_B_KEY_EXT 2
|
||||
#define INP_B_KEY_MEN 1
|
||||
#define OUT_B_PPM 0
|
||||
#define PORTC_LCD_CTRL PORTC
|
||||
#define OUT_C_LCD_E 5
|
||||
#define OUT_C_LCD_RnW 4
|
||||
#define OUT_C_LCD_A0 3
|
||||
#define OUT_C_LCD_RES 2
|
||||
#define OUT_C_LCD_CS1 1
|
||||
|
||||
#define INP_D_TRM_LH_UP 7
|
||||
#define INP_D_TRM_LH_DWN 6
|
||||
#define INP_D_TRM_RV_DWN 5
|
||||
#define INP_D_TRM_RV_UP 4
|
||||
#define INP_D_TRM_LV_DWN 3
|
||||
#define INP_D_TRM_LV_UP 2
|
||||
#define INP_D_TRM_RH_DWN 1
|
||||
#define INP_D_TRM_RH_UP 0
|
||||
|
||||
// Legacy support for USART1 hardware mod [DEPRECATED]
|
||||
#if defined(USART1FREED)
|
||||
// do not undef the original INP_D_TRM_LV_DWN/UP as we need them later
|
||||
#define INP_C_TRM_LV_UP 0
|
||||
#define INP_G_TRM_LV_DWN 2
|
||||
#endif
|
||||
|
||||
#define INP_E_PPM_IN 7
|
||||
#define INP_E_ID2 6
|
||||
#define INP_E_Trainer 5
|
||||
#define INP_E_Gear 4
|
||||
#define OUT_E_BUZZER 3
|
||||
#define INP_E_ElevDR 2
|
||||
|
||||
|
||||
#define INP_E_AileDR 1
|
||||
#define INP_E_ThrCt 0
|
||||
|
||||
#if defined(JETI) || defined(FRSKY)
|
||||
#undef INP_E_ThrCt
|
||||
#undef INP_E_AileDR
|
||||
#define INP_C_ThrCt 6
|
||||
#define INP_C_AileDR 7
|
||||
#endif
|
||||
|
||||
#if defined (BEEPSPKR)
|
||||
#define BEEP_KEY_TIME 5
|
||||
#define BEEP_DEFAULT_FREQ 50
|
||||
#define BEEP_KEY_UP_FREQ 55
|
||||
#define BEEP_KEY_DOWN_FREQ 45
|
||||
#endif
|
||||
|
||||
#define OUT_G_SIM_CTL 4 //1 : phone-jack=ppm_in
|
||||
#define INP_G_ID1 3
|
||||
#define INP_G_RF_POW 1
|
||||
#define INP_G_RuddDR 0
|
||||
|
||||
#define SLAVE_MODE (PING & (1<<INP_G_RF_POW))
|
||||
|
||||
const uint8_t modn12x3[4][4]= {
|
||||
{1, 2, 3, 4},
|
||||
{1, 3, 2, 4},
|
||||
{4, 2, 3, 1},
|
||||
{4, 3, 2, 1} };
|
||||
|
||||
//R=1
|
||||
//E=2
|
||||
//T=3
|
||||
//A=4
|
||||
|
||||
const uint8_t chout_ar[24][4] = { //First number is 0..23 -> template setup, Second is relevant channel out
|
||||
{1,2,3,4},{1,2,4,3},{1,3,2,4},{1,3,4,2},{1,4,2,3},{1,4,3,2},
|
||||
{2,1,3,4},{2,1,4,3},{2,3,1,4},{2,3,4,1},{2,4,1,3},{2,4,3,1},
|
||||
{3,1,2,4},{3,1,4,2},{3,2,1,4},{3,2,4,1},{3,4,1,2},{3,4,2,1},
|
||||
{4,1,2,3},{4,1,3,2},{4,2,1,3},{4,2,3,1},{4,3,1,2},{4,3,2,1} };
|
||||
|
||||
//convert from mode 1 to mode g_eeGeneral.stickMode
|
||||
//NOTICE! => 1..4 -> 1..4
|
||||
#define CONVERT_MODE(x) (((x)<=4) ? modn12x3[g_eeGeneral.stickMode][((x)-1)] : (x))
|
||||
#define CHANNEL_ORDER(x) (chout_ar[g_eeGeneral.templateSetup][(x)-1])
|
||||
#define THR_STICK (2-(g_eeGeneral.stickMode&1))
|
||||
#define ELE_STICK (1+(g_eeGeneral.stickMode&1))
|
||||
#define AIL_STICK ((g_eeGeneral.stickMode&2) ? 0 : 3)
|
||||
#define RUD_STICK ((g_eeGeneral.stickMode&2) ? 3 : 0)
|
||||
|
||||
enum EnumKeys {
|
||||
KEY_MENU ,
|
||||
KEY_EXIT ,
|
||||
KEY_DOWN ,
|
||||
KEY_UP ,
|
||||
KEY_RIGHT ,
|
||||
KEY_LEFT ,
|
||||
TRM_LH_DWN ,
|
||||
TRM_LH_UP ,
|
||||
TRM_LV_DWN ,
|
||||
TRM_LV_UP ,
|
||||
TRM_RV_DWN ,
|
||||
TRM_RV_UP ,
|
||||
TRM_RH_DWN ,
|
||||
TRM_RH_UP ,
|
||||
//SW_NC ,
|
||||
//SW_ON ,
|
||||
SW_ThrCt ,
|
||||
SW_RuddDR ,
|
||||
SW_ElevDR ,
|
||||
SW_ID0 ,
|
||||
SW_ID1 ,
|
||||
SW_ID2 ,
|
||||
SW_AileDR ,
|
||||
SW_Gear ,
|
||||
SW_Trainer
|
||||
};
|
||||
|
||||
#define SWITCHES_STR "THR""RUD""ELE""ID0""ID1""ID2""AIL""GEA""TRN""SW1""SW2""SW3""SW4""SW5""SW6""SW7""SW8""SW9""SWA""SWB""SWC"
|
||||
|
||||
#define CURV_STR "---x>0x<0|x|f>0f<0|f|c1 c2 c3 c4 c5 c6 c7 c8 c9 c10c11c12c13c14c15c16"
|
||||
#define CURVE_BASE 7
|
||||
|
||||
#define CSWITCH_STR "---- v>ofs v<ofs |v|>ofs|v|<ofsAND OR XOR ""v1==v2 ""v1!=v2 ""v1>v2 ""v1<v2 ""v1>=v2 ""v1<=v2 "
|
||||
#define CSW_LEN_FUNC 7
|
||||
|
||||
#define FSWITCH_STR "---- ""Trainer ""Instant Trim ""Trims2Offsets ""Telemetry View"
|
||||
#define FSW_LEN_FUNC 14
|
||||
|
||||
#define SWASH_TYPE_STR "--- ""120 ""120X ""140 ""90 "
|
||||
|
||||
#define SWASH_TYPE_120 1
|
||||
#define SWASH_TYPE_120X 2
|
||||
#define SWASH_TYPE_140 3
|
||||
#define SWASH_TYPE_90 4
|
||||
#define SWASH_TYPE_NUM 4
|
||||
|
||||
#define CS_OFF 0
|
||||
#define CS_VPOS 1 //v>offset
|
||||
#define CS_VNEG 2 //v<offset
|
||||
#define CS_APOS 3 //|v|>offset
|
||||
#define CS_ANEG 4 //|v|<offset
|
||||
#define CS_AND 5
|
||||
#define CS_OR 6
|
||||
#define CS_XOR 7
|
||||
#define CS_EQUAL 8
|
||||
#define CS_NEQUAL 9
|
||||
#define CS_GREATER 10
|
||||
#define CS_LESS 11
|
||||
#define CS_EGREATER 12
|
||||
#define CS_ELESS 13
|
||||
#define CS_MAXF 13 //max function
|
||||
|
||||
#define CS_VOFS 0
|
||||
#define CS_VBOOL 1
|
||||
#define CS_VCOMP 2
|
||||
#define CS_STATE(x) ((x)<CS_AND ? CS_VOFS : ((x)<CS_EQUAL ? CS_VBOOL : CS_VCOMP))
|
||||
|
||||
//#define SW_BASE SW_NC
|
||||
#define SW_BASE SW_ThrCt
|
||||
#define SW_BASE_DIAG SW_ThrCt
|
||||
//#define SWITCHES_STR " NC ON THR RUD ELE ID0 ID1 ID2 AILGEARTRNR"
|
||||
#define MAX_PSWITCH (SW_Trainer-SW_ThrCt+1) // 9 physical switches
|
||||
#define MAX_SWITCH (1+MAX_PSWITCH+NUM_CSW) // 22(1+9+12) !switches + 0 + 22 switches: 6 bits needed
|
||||
#define MAX_DRSWITCH (MAX_PSWITCH+NUM_CSW/2) // 15(9+6) !switches + 0 + 15 switches: 5 bits needed
|
||||
|
||||
#define NUM_STICKS 4
|
||||
#define NUM_POTS 3
|
||||
#define PPM_BASE (MIX_FULL+3/*CYC1-CYC3*/) // because srcRaw is shifted +1!
|
||||
#define NUM_CAL_PPM 4
|
||||
#define NUM_PPM 8
|
||||
#define CHOUT_BASE (PPM_BASE+NUM_PPM)
|
||||
|
||||
#ifdef FRSKY
|
||||
#define NUM_TELEMETRY 2
|
||||
#define TELEMETRY_CHANNELS "AD1 AD2 "
|
||||
#else
|
||||
#define NUM_TELEMETRY 0
|
||||
#define TELEMETRY_CHANNELS ""
|
||||
#endif
|
||||
|
||||
#define DSW_THR 1
|
||||
#define DSW_RUD 2
|
||||
#define DSW_ELE 3
|
||||
#define DSW_ID0 4
|
||||
#define DSW_ID1 5
|
||||
#define DSW_ID2 6
|
||||
#define DSW_AIL 7
|
||||
#define DSW_GEA 8
|
||||
#define DSW_TRN 9
|
||||
#define DSW_SW1 10
|
||||
#define DSW_SW2 11
|
||||
#define DSW_SW3 12
|
||||
#define DSW_SW4 13
|
||||
#define DSW_SW5 14
|
||||
#define DSW_SW6 15
|
||||
|
||||
#define THRCHK_DEADBAND 16
|
||||
#define SPLASH_TIMEOUT (4*100) //400 msec - 4 seconds
|
||||
|
||||
#define NUM_KEYS TRM_RH_UP+1
|
||||
#define TRM_BASE TRM_LH_DWN
|
||||
|
||||
//#define _MSK_KEY_FIRST (_MSK_KEY_REPT|0x20)
|
||||
//#define EVT_KEY_GEN_BREAK(key) ((key)|0x20)
|
||||
#define _MSK_KEY_REPT 0x40
|
||||
#define _MSK_KEY_DBL 0x10
|
||||
#define IS_KEY_BREAK(key) (((key)&0xf0) == 0x20)
|
||||
#define EVT_KEY_BREAK(key) ((key)| 0x20)
|
||||
#define EVT_KEY_FIRST(key) ((key)| _MSK_KEY_REPT|0x20)
|
||||
#define EVT_KEY_REPT(key) ((key)| _MSK_KEY_REPT )
|
||||
#define EVT_KEY_LONG(key) ((key)|0x80)
|
||||
#define EVT_KEY_DBL(key) ((key)|_MSK_KEY_DBL)
|
||||
//#define EVT_KEY_DBL(key) ((key)|0x10)
|
||||
#define EVT_ENTRY (0xff - _MSK_KEY_REPT)
|
||||
#define EVT_ENTRY_UP (0xfe - _MSK_KEY_REPT)
|
||||
#define EVT_KEY_MASK 0x0f
|
||||
|
||||
|
||||
#define TMRMODE_NONE 0
|
||||
#define TMRMODE_ABS 1
|
||||
#define TMRMODE_THR 2
|
||||
#define TMRMODE_THR_REL 3
|
||||
#define MAX_ALERT_TIME 60
|
||||
|
||||
#define PROTO_PPM 0
|
||||
#define PROTO_SILV_A 1
|
||||
#define PROTO_SILV_B 2
|
||||
#define PROTO_SILV_C 3
|
||||
#define PROTO_TRACER_CTP1009 4
|
||||
#define PROT_MAX 4
|
||||
#define PROT_STR "PPM SILV_ASILV_BSILV_CTRAC09"
|
||||
#define PROT_STR_LEN 6
|
||||
|
||||
typedef void (*getADCp)();
|
||||
|
||||
#define ZCHAR_MAX 40
|
||||
|
||||
#ifdef TRANSLATIONS
|
||||
extern int8_t char2idx(char c);
|
||||
#endif
|
||||
extern char idx2char(int8_t idx);
|
||||
|
||||
/// stoppt alle events von dieser taste bis eine kurze Zeit abgelaufen ist
|
||||
void pauseEvents(uint8_t enuk);
|
||||
/// liefert die Zahl der schnellen Wiederholungen dieser Taste
|
||||
uint8_t getEventDbl(uint8_t event);
|
||||
/// stoppt alle events von dieser taste bis diese wieder losgelassen wird
|
||||
void killEvents(uint8_t enuk);
|
||||
/// liefert den Wert einer beliebigen Taste KEY_MENU..SW_Trainer
|
||||
bool keyState(EnumKeys enuk);
|
||||
/// Liefert das naechste Tasten-Event, auch trim-Tasten.
|
||||
/// Das Ergebnis hat die Form:
|
||||
/// EVT_KEY_BREAK(key), EVT_KEY_FIRST(key), EVT_KEY_REPT(key) oder EVT_KEY_LONG(key)
|
||||
uint8_t getEvent();
|
||||
void putEvent(uint8_t evt);
|
||||
#if defined (PCBV3)
|
||||
extern uint8_t keyDown();
|
||||
#endif
|
||||
|
||||
/// Gibt Alarm Maske auf lcd aus.
|
||||
/// Die Maske wird so lange angezeigt bis eine beliebige Taste gedrueckt wird.
|
||||
void alert(const prog_char * s, bool defaults=false);
|
||||
void message(const prog_char * s);
|
||||
/// periodisches Hauptprogramm
|
||||
void perMain();
|
||||
/// Bearbeitet alle zeitkritischen Jobs.
|
||||
/// wie z.B. einlesen aller Eingaenge, Entprellung, Key-Repeat..
|
||||
void per10ms();
|
||||
/// Erzeugt periodisch alle Outputs ausser Bildschirmausgaben.
|
||||
void zeroVariables();
|
||||
|
||||
#define NO_TRAINER 0x01
|
||||
#define NO_INPUT 0x02
|
||||
extern void perOut(int16_t *chanOut, uint8_t att);
|
||||
|
||||
/// Liefert den Zustand des Switches 'swtch'. Die Numerierung erfolgt ab 1
|
||||
/// (1=SW_ON, 2=SW_ThrCt, 10=SW_Trainer). 0 Bedeutet not conected.
|
||||
/// Negative Werte erzeugen invertierte Ergebnisse.
|
||||
/// Die Funktion putsSwitches(..) erzeugt den passenden Ausdruck.
|
||||
///
|
||||
/// \param swtch
|
||||
/// 0 : not connected. Liefert den Wert 'nc'
|
||||
/// 1.. MAX_SWITCH : SW_ON .. SW_Trainer
|
||||
/// -1..-MAX_SWITCH : negierte Werte
|
||||
/// \param nc Wert, der bei swtch==0 geliefert wird.
|
||||
bool getSwitch(int8_t swtch, bool nc, uint8_t level=0);
|
||||
/// Zeigt den Namen des Switches 'swtch' im display an
|
||||
/// \param x x-koordinate 0..127
|
||||
/// \param y y-koordinate 0..63 (nur durch 8 teilbar)
|
||||
/// \param swtch -MAX_SWITCH .. MAX_SWITCH
|
||||
/// \param att NO_INV,INVERS,BLINK
|
||||
///
|
||||
|
||||
uint8_t getFlightPhase();
|
||||
uint8_t getTrimFlightPhase(uint8_t idx, int8_t phase=-1);
|
||||
|
||||
extern uint16_t s_timeCumTot;
|
||||
extern uint16_t s_timeCumAbs; //laufzeit in 1/16 sec
|
||||
extern uint16_t s_timeCumSw; //laufzeit in 1/16 sec
|
||||
extern uint16_t s_timeCumThr; //gewichtete laufzeit in 1/16 sec
|
||||
extern uint16_t s_timeCum16ThrP; //gewichtete laufzeit in 1/16 sec
|
||||
extern uint8_t s_timerState;
|
||||
extern int16_t s_timerVal[2];
|
||||
|
||||
extern uint8_t trimsCheckTimer;
|
||||
|
||||
#define TMR_OFF 0
|
||||
#define TMR_RUNNING 1
|
||||
#define TMR_BEEPING 2
|
||||
#define TMR_STOPPED 3
|
||||
void resetTimer1();
|
||||
|
||||
extern uint8_t Timer2_running ;
|
||||
extern uint16_t timer2 ;
|
||||
void resetTimer2() ;
|
||||
|
||||
extern uint16_t g_tmr1Latency_max;
|
||||
extern uint16_t g_tmr1Latency_min;
|
||||
extern uint16_t g_timeMain;
|
||||
extern uint16_t g_time_per10;
|
||||
|
||||
#define MAXTRACE 120
|
||||
extern uint8_t s_traceBuf[MAXTRACE];
|
||||
extern uint16_t s_traceWr;
|
||||
extern uint16_t s_traceCnt;
|
||||
|
||||
const prog_char *get_switches_string() ;
|
||||
|
||||
uint16_t getTmr16KHz();
|
||||
unsigned int stack_free();
|
||||
|
||||
void checkMem();
|
||||
void checkTHR();
|
||||
void checkSwitches();
|
||||
|
||||
#define GETADC_SING = 0
|
||||
#define GETADC_OSMP = 1
|
||||
#define GETADC_FILT = 2
|
||||
|
||||
void getADC_single();
|
||||
void getADC_osmp();
|
||||
void getADC_filt();
|
||||
|
||||
// checkIncDec flags
|
||||
#define EE_GENERAL 0x01
|
||||
#define EE_MODEL 0x02
|
||||
|
||||
extern bool warble;
|
||||
|
||||
extern uint8_t s_eeDirtyMsk;
|
||||
|
||||
#define STORE_MODELVARS eeDirty(EE_MODEL)
|
||||
#define STORE_GENERALVARS eeDirty(EE_GENERAL)
|
||||
|
||||
#if defined (PCBV3)
|
||||
#define BACKLIGHT_ON PORTC |= (1<<OUT_C_LIGHT)
|
||||
#define BACKLIGHT_OFF PORTC &= ~(1<<OUT_C_LIGHT)
|
||||
#else
|
||||
#define BACKLIGHT_ON PORTB |= (1<<OUT_B_LIGHT)
|
||||
#define BACKLIGHT_OFF PORTB &= ~(1<<OUT_B_LIGHT)
|
||||
#endif
|
||||
|
||||
#define BITMASK(bit) (1<<(bit))
|
||||
|
||||
/// liefert Dimension eines Arrays
|
||||
#define DIM(arr) (sizeof((arr))/sizeof((arr)[0]))
|
||||
|
||||
/// liefert Betrag des Arguments
|
||||
template<class t> inline t abs(t a){ return a>0?a:-a; }
|
||||
/// liefert das Minimum der Argumente
|
||||
template<class t> inline t min(t a, t b){ return a<b?a:b; }
|
||||
/// liefert das Maximum der Argumente
|
||||
template<class t> inline t max(t a, t b){ return a>b?a:b; }
|
||||
template<class t> inline int8_t sgn(t a){ return a>0 ? 1 : (a < 0 ? -1 : 0); }
|
||||
|
||||
/// Markiert einen EEPROM-Bereich als dirty. der Bereich wird dann in
|
||||
/// eeCheck ins EEPROM zurueckgeschrieben.
|
||||
void eeWriteBlockCmp(const void *i_pointer_ram, void *i_pointer_eeprom, size_t size);
|
||||
void eeDirty(uint8_t msk);
|
||||
void eeCheck(bool immediately=false);
|
||||
//void eeWriteGeneral();
|
||||
void eeReadAll();
|
||||
bool eeModelExists(uint8_t id);
|
||||
uint16_t eeLoadModelName(uint8_t id, char *name);
|
||||
void eeLoadModel(uint8_t id);
|
||||
//void eeSaveModel(uint8_t id);
|
||||
bool eeDuplicateModel(uint8_t id);
|
||||
|
||||
///number of real input channels (1-9) plus virtual input channels X1-X4
|
||||
#define NUM_XCHNRAW (NUM_STICKS+NUM_POTS+2/*MAX/FULL*/+3/*CYC1-CYC3*/+NUM_PPM+NUM_CHNOUT+NUM_TELEMETRY)
|
||||
///number of real output channels (CH1-CH8) plus virtual output channels X1-X4
|
||||
#define NUM_XCHNOUT (NUM_CHNOUT) //(NUM_CHNOUT)//+NUM_VIRT)
|
||||
|
||||
extern inline int16_t calc100toRESX(int8_t x)
|
||||
{
|
||||
// return (int16_t)x*10 + x/4 - x/64;
|
||||
return ((x*41)>>2) - x/64;
|
||||
}
|
||||
|
||||
extern inline int16_t calc1000toRESX(int16_t x)
|
||||
{
|
||||
// return x + x/32 - x/128 + x/512;
|
||||
int16_t y = x>>5;
|
||||
x+=y;
|
||||
y=y>>2;
|
||||
x-=y;
|
||||
return x+(y>>2);
|
||||
}
|
||||
|
||||
extern volatile uint16_t g_tmr10ms;
|
||||
|
||||
extern inline uint16_t get_tmr10ms()
|
||||
{
|
||||
uint16_t time ;
|
||||
cli();
|
||||
time = g_tmr10ms ;
|
||||
sei();
|
||||
return time ;
|
||||
}
|
||||
|
||||
#define TMR_VAROFS 16
|
||||
|
||||
#define SUB_MODE_V 1
|
||||
#define SUB_MODE_H 2
|
||||
#define SUB_MODE_H_DBL 3
|
||||
|
||||
void setupPulses();
|
||||
void setupPulsesPPM();
|
||||
void setupPulsesSilver();
|
||||
void setupPulsesTracerCtp1009();
|
||||
|
||||
void initTemplates();
|
||||
|
||||
#include "lcd.h"
|
||||
extern const char stamp1[];
|
||||
extern const char stamp2[];
|
||||
extern const char stamp3[];
|
||||
extern const char stamp4[];
|
||||
extern const char stamp5[];
|
||||
#include "myeeprom.h"
|
||||
|
||||
#ifdef JETI
|
||||
// Jeti-DUPLEX Telemetry
|
||||
extern uint16_t jeti_keys;
|
||||
#include "jeti.h"
|
||||
#endif
|
||||
|
||||
#if defined (FRSKY)
|
||||
// FrSky Telemetry
|
||||
#include "frsky.h"
|
||||
#endif
|
||||
|
||||
#ifndef BATT_UNSTABLE_BANDGAP
|
||||
extern uint16_t abRunningAvg;
|
||||
extern uint8_t g_vbat100mV;
|
||||
#else
|
||||
extern uint16_t g_vbat100mV;
|
||||
#endif
|
||||
extern volatile uint16_t g_tmr10ms;
|
||||
extern volatile uint8_t g_blinkTmr10ms;
|
||||
extern uint8_t g_beepCnt;
|
||||
extern uint8_t g_beepVal[5];
|
||||
extern const PROGMEM char modi12x3[];
|
||||
extern uint16_t pulses2MHz[120];
|
||||
extern int16_t g_ppmIns[8];
|
||||
extern int16_t g_chans512[NUM_CHNOUT];
|
||||
extern volatile uint8_t tick10ms;
|
||||
extern uint16_t BandGap;
|
||||
|
||||
extern uint16_t expou(uint16_t x, uint16_t k);
|
||||
extern int16_t expo(int16_t x, int16_t k);
|
||||
extern int16_t intpol(int16_t, uint8_t);
|
||||
extern int16_t applyCurve(int16_t, uint8_t, uint8_t srcRaw);
|
||||
extern void applyExpos(int16_t *anas);
|
||||
|
||||
extern uint16_t anaIn(uint8_t chan);
|
||||
extern int16_t calibratedStick[7];
|
||||
extern int16_t ex_chans[NUM_CHNOUT];
|
||||
|
||||
#define FLASH_DURATION 50
|
||||
|
||||
extern uint8_t beepAgain;
|
||||
extern uint16_t g_LightOffCounter;
|
||||
extern uint8_t mixWarning;
|
||||
|
||||
/// Erzeugt einen beep der laenge b
|
||||
inline void _beep(uint8_t b) {
|
||||
g_beepCnt=b;
|
||||
}
|
||||
|
||||
extern uint8_t toneFreq;
|
||||
#if defined (PCBV3)
|
||||
inline void _beepSpkr(uint8_t d, uint8_t f)
|
||||
{
|
||||
g_beepCnt=d;
|
||||
OCR0A = (5000 / f); // sticking with old values approx 20(abs. min) to 90, 60 being the default tone(?).
|
||||
}
|
||||
#elif defined (BEEPSPKR)
|
||||
inline void _beepSpkr(uint8_t d, uint8_t f)
|
||||
{
|
||||
g_beepCnt=d;
|
||||
toneFreq=f;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (BEEPSPKR)
|
||||
|
||||
#define beepKeySpkr(freq) _beepSpkr(g_beepVal[0],freq)
|
||||
#define beepTrimSpkr(freq) _beepSpkr(g_beepVal[0],freq)
|
||||
#define beepWarn1Spkr(freq) _beepSpkr(g_beepVal[1],freq)
|
||||
#define beepWarn2Spkr(freq) _beepSpkr(g_beepVal[2],freq)
|
||||
#define beepKey() _beepSpkr(g_beepVal[0],BEEP_DEFAULT_FREQ)
|
||||
#define beepWarn() _beepSpkr(g_beepVal[3],BEEP_DEFAULT_FREQ)
|
||||
#define beepWarn1() _beepSpkr(g_beepVal[1],BEEP_DEFAULT_FREQ)
|
||||
#define beepWarn2() _beepSpkr(g_beepVal[2],BEEP_DEFAULT_FREQ)
|
||||
#define beepErr() _beepSpkr(g_beepVal[4],BEEP_DEFAULT_FREQ)
|
||||
|
||||
#else
|
||||
|
||||
/// Erzeugt einen kurzen beep
|
||||
#define beepKey() _beep(g_beepVal[0])
|
||||
#define beepWarn() _beep(g_beepVal[3])
|
||||
#define beepWarn1() _beep(g_beepVal[1])
|
||||
#define beepWarn2() _beep(g_beepVal[2])
|
||||
#define beepErr() _beep(g_beepVal[4])
|
||||
|
||||
#endif
|
||||
|
||||
// MM/SD card Disk IO Support
|
||||
#if defined (PCBV3)
|
||||
#include "rtc.h"
|
||||
extern void disk_timerproc(void);
|
||||
extern time_t g_unixTime; // global unix timestamp -- hold current time in seconds since 1970-01-01 00:00:00
|
||||
extern uint8_t g_ms100; // defined in drivers.cpp
|
||||
#endif
|
||||
|
||||
extern PhaseData *phaseaddress(uint8_t idx);
|
||||
extern ExpoData *expoaddress(uint8_t idx);
|
||||
extern MixData *mixaddress(uint8_t idx);
|
||||
extern LimitData *limitaddress(uint8_t idx);
|
||||
|
||||
extern void incSubtrim(uint8_t idx, int16_t inc);
|
||||
extern void instantTrim();
|
||||
extern void moveTrimsToOffsets(); // move state of 3 primary trims to offsets
|
||||
|
||||
extern uint16_t active_functions;
|
||||
inline bool isFunctionActive(uint8_t func)
|
||||
{
|
||||
return active_functions & (1 << (func-1));
|
||||
}
|
||||
|
||||
|
||||
#endif // gruvin9x_h
|
||||
/*eof*/
|
218
src/gtests.cpp
Normal file
218
src/gtests.cpp
Normal file
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
*
|
||||
* gruvin9x is based on code named er9x by
|
||||
* Author - Erez Raviv <erezraviv@gmail.com>, which is in turn
|
||||
* was based on 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 <gtest/gtest.h>
|
||||
#include "gruvin9x.h"
|
||||
|
||||
uint16_t anaIn(uint8_t chan)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST(incSubtrim, test1) {
|
||||
memset(&g_model, 0, sizeof(g_model));
|
||||
incSubtrim(0, 10);
|
||||
for (int p=0; p<MAX_PHASES; p++) {
|
||||
PhaseData *phase = phaseaddress(p);
|
||||
EXPECT_EQ(phase->trim[0], -10) << "Should be equal to -10";
|
||||
}
|
||||
EXPECT_EQ(g_model.subtrim[0], 10) << "Should be equal to 10";
|
||||
}
|
||||
|
||||
TEST(incSubtrim, test2) {
|
||||
memset(&g_model, 0, sizeof(g_model));
|
||||
phaseaddress(0)->trim[0] = -120;
|
||||
phaseaddress(1)->trim[0] = +125;
|
||||
incSubtrim(0, +10); // FP1 is trimmed by +10
|
||||
EXPECT_EQ(phaseaddress(0)->trim[0], TRIM_MIN);
|
||||
EXPECT_EQ(phaseaddress(1)->trim[0], +115); // and set to 125 just after
|
||||
EXPECT_EQ(g_model.subtrim[0], 10);
|
||||
}
|
||||
|
||||
TEST(trims, greaterTrimLink)
|
||||
{
|
||||
memset(&g_model, 0, sizeof(g_model));
|
||||
phaseaddress(1)->trim[0] = -127; // link to FP3 trim
|
||||
phaseaddress(3)->trim[0] = 32;
|
||||
EXPECT_EQ(phaseaddress(getTrimFlightPhase(0, 1))->trim[0], 32);
|
||||
}
|
||||
|
||||
TEST(trims, chainedTrims)
|
||||
{
|
||||
memset(&g_model, 0, sizeof(g_model));
|
||||
phaseaddress(0)->trim[0] = 32;
|
||||
phaseaddress(1)->trim[0] = +127; // link to FP0 trim
|
||||
phaseaddress(2)->trim[0] = -128; // link to FP1 trim
|
||||
EXPECT_EQ(phaseaddress(getTrimFlightPhase(0, 2))->trim[0], 32);
|
||||
}
|
||||
|
||||
TEST(trims, infiniteChainedTrims)
|
||||
{
|
||||
memset(&g_model, 0, sizeof(g_model));
|
||||
phaseaddress(0)->trim[0] = 32;
|
||||
phaseaddress(1)->trim[0] = -127; // link to FP3 trim
|
||||
phaseaddress(2)->trim[0] = -128; // link to FP1 trim
|
||||
phaseaddress(3)->trim[0] = -127; // link to FP2 trim
|
||||
EXPECT_EQ(phaseaddress(getTrimFlightPhase(0, 2))->trim[0], 32);
|
||||
}
|
||||
|
||||
TEST(outdezNAtt, test_unsigned) {
|
||||
uint16_t altitude = 65530;
|
||||
|
||||
uint8_t refBuf[sizeof(displayBuf)];
|
||||
memset(displayBuf, 0, sizeof(displayBuf));
|
||||
lcd_putc(0*FWNUM, 0, '6');
|
||||
lcd_putc(1*FWNUM, 0, '5');
|
||||
lcd_putc(2*FWNUM, 0, '5');
|
||||
lcd_putc(3*FWNUM, 0, '3');
|
||||
lcd_putc(4*FWNUM, 0, '0');
|
||||
memcpy(refBuf, displayBuf, sizeof(displayBuf));
|
||||
|
||||
memset(displayBuf, 0, sizeof(displayBuf));
|
||||
lcd_outdezNAtt(1, 0, altitude, LEFT|UNSIGN);
|
||||
|
||||
EXPECT_EQ(memcmp(refBuf, displayBuf, sizeof(displayBuf)), 0) << "Unsigned numbers will be bad displayed";
|
||||
}
|
||||
|
||||
TEST(EEPROM, test1) {
|
||||
eepromFile = NULL; // in memory
|
||||
RlcFile f;
|
||||
uint8_t buf[1000];
|
||||
uint8_t buf2[1000];
|
||||
|
||||
EeFsFormat();
|
||||
|
||||
for(int i=0; i<10000; i++) {
|
||||
int size = rand()%800;
|
||||
for(int j=0; j<size; j++) {
|
||||
buf[j] = rand() < (RAND_MAX/10000*i) ? 0 : (j&0xff);
|
||||
}
|
||||
f.writeRlc(5, 5, buf, size, 100);
|
||||
// printf("size=%4d red=%4d\n\n\n", size, f.size());
|
||||
f.openRd(5);
|
||||
uint16_t n = f.readRlc(buf2,size+1);
|
||||
EXPECT_EQ(n, size);
|
||||
EXPECT_EQ(memcmp(buf, buf2, size), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EEPROM, test2) {
|
||||
eepromFile = NULL; // in memory
|
||||
RlcFile f;
|
||||
uint8_t buf[1000];
|
||||
|
||||
EeFsFormat();
|
||||
|
||||
for(int i=0; i<1000; i++) buf[i]='6'+i%4;
|
||||
|
||||
f.writeRlc(6, 6, buf, 300, 100);
|
||||
|
||||
f.openRd(6);
|
||||
uint16_t sz=0;
|
||||
for(int i=0; i<500; i++){
|
||||
uint8_t b;
|
||||
uint16_t n=f.readRlc(&b,1);
|
||||
if(n) EXPECT_EQ(b, ('6'+sz%4));
|
||||
sz+=n;
|
||||
}
|
||||
EXPECT_EQ(sz, 300);
|
||||
}
|
||||
|
||||
TEST(EEPROM, eeCheckImmediately) {
|
||||
eepromFile = NULL; // in memory
|
||||
// RlcFile f;
|
||||
uint8_t buf[1000];
|
||||
|
||||
EeFsFormat();
|
||||
|
||||
for(int i=0; i<1000; i++) buf[i]='6'+i%4;
|
||||
|
||||
theFile.writeRlc(6, 6, buf, 300, false);
|
||||
|
||||
eeCheck(true);
|
||||
|
||||
theFile.openRd(6);
|
||||
uint16_t sz=0;
|
||||
for(int i=0; i<500; i++){
|
||||
uint8_t b;
|
||||
uint16_t n=theFile.readRlc(&b,1);
|
||||
if(n) EXPECT_EQ(b, ('6'+sz%4));
|
||||
sz+=n;
|
||||
}
|
||||
EXPECT_EQ(sz, 300);
|
||||
}
|
||||
|
||||
TEST(EEPROM, eeDuplicateModel) {
|
||||
eepromFile = NULL; // in memory
|
||||
|
||||
uint8_t buf[1000];
|
||||
|
||||
EeFsFormat();
|
||||
|
||||
for(int i=0; i<1000; i++) buf[i]='6'+i%4;
|
||||
|
||||
theFile.writeRlc(5, 6, buf, 300, true);
|
||||
|
||||
eeDuplicateModel(4);
|
||||
|
||||
theFile.openRd(6);
|
||||
uint16_t sz=0;
|
||||
for(int i=0; i<500; i++){
|
||||
uint8_t b;
|
||||
uint16_t n=theFile.readRlc(&b,1);
|
||||
if(n) EXPECT_EQ(b, ('6'+sz%4));
|
||||
sz+=n;
|
||||
}
|
||||
EXPECT_EQ(sz, 300);
|
||||
}
|
||||
|
||||
TEST(EEPROM, rm) {
|
||||
eepromFile = NULL; // in memory
|
||||
|
||||
uint8_t buf[1000];
|
||||
|
||||
EeFsFormat();
|
||||
|
||||
for(int i=0; i<1000; i++) buf[i]='6'+i%4;
|
||||
|
||||
theFile.writeRlc(5, 6, buf, 300, true);
|
||||
|
||||
EXPECT_EQ(EFile::exists(5), true);
|
||||
|
||||
EFile::rm(5);
|
||||
|
||||
EXPECT_EQ(EFile::exists(5), false);
|
||||
|
||||
theFile.openRd(5);
|
||||
uint16_t sz=0;
|
||||
for(int i=0; i<500; i++){
|
||||
uint8_t b;
|
||||
uint16_t n=theFile.readRlc(&b,1);
|
||||
if(n) EXPECT_EQ(b, ('6'+sz%4));
|
||||
sz+=n;
|
||||
}
|
||||
EXPECT_EQ(sz, 0);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
37
src/integer.h
Normal file
37
src/integer.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*-------------------------------------------*/
|
||||
/* Integer type definitions for FatFs module */
|
||||
/*-------------------------------------------*/
|
||||
|
||||
#ifndef _INTEGER
|
||||
#define _INTEGER
|
||||
|
||||
#ifdef _WIN32 /* FatFs development platform */
|
||||
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
|
||||
#else /* Embedded platform */
|
||||
|
||||
/* These types must be 16-bit, 32-bit or larger integer */
|
||||
typedef int INT;
|
||||
typedef unsigned int UINT;
|
||||
|
||||
/* These types must be 8-bit integer */
|
||||
typedef char CHAR;
|
||||
typedef unsigned char UCHAR;
|
||||
typedef unsigned char BYTE;
|
||||
|
||||
/* These types must be 16-bit integer */
|
||||
typedef short SHORT;
|
||||
typedef unsigned short USHORT;
|
||||
typedef unsigned short WORD;
|
||||
typedef unsigned short WCHAR;
|
||||
|
||||
/* These types must be 32-bit integer */
|
||||
typedef long LONG;
|
||||
typedef unsigned long ULONG;
|
||||
typedef unsigned long DWORD;
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
200
src/jeti.cpp
Normal file
200
src/jeti.cpp
Normal file
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* gruvin9x Author Bryan J.Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
*
|
||||
* jeti.cpp original author - Karl Szmutny <shadow@privy.de>
|
||||
*
|
||||
* Based on the Code from Peter "woggle" Mack, mac@denich.net
|
||||
* -> http://svn.mikrokopter.de/filedetails.php?repname=Projects&path=/Transportables_Koptertool/trunk/jeti.c
|
||||
*
|
||||
* 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 "jeti.h"
|
||||
#include "gruvin9x.h"
|
||||
|
||||
uint16_t jeti_keys = JETI_KEY_NOCHANGE;
|
||||
uint8_t JetiBuffer[32]; // 32 characters
|
||||
uint8_t JetiBufferReady;
|
||||
|
||||
|
||||
ISR (USART0_RX_vect)
|
||||
{
|
||||
uint8_t stat;
|
||||
uint8_t rh;
|
||||
uint8_t rl;
|
||||
static uint8_t jbp;
|
||||
|
||||
stat = UCSR0A;
|
||||
rh = UCSR0B;
|
||||
rl = UDR0;
|
||||
|
||||
|
||||
if (stat & ((1 << FE0) | (1 << DOR0) | (1 << UPE0)))
|
||||
{ // discard buffer and start new on any error
|
||||
JetiBufferReady = 0;
|
||||
jbp = 0;
|
||||
}
|
||||
else if ((rh & (1 << RXB80)) == 0)
|
||||
{ // control
|
||||
if (rl == 0xfe)
|
||||
{ // start condition
|
||||
JetiBufferReady = 0;
|
||||
jbp = 0;
|
||||
}
|
||||
else if (rl == 0xff)
|
||||
{ // stop condition
|
||||
JetiBufferReady = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // data
|
||||
if (jbp < 32)
|
||||
{
|
||||
JetiBuffer[jbp++] = rl;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void JETI_Init (void)
|
||||
{
|
||||
|
||||
jeti_keys = JETI_KEY_NOCHANGE;
|
||||
|
||||
DDRE &= ~(1 << DDE0); // set RXD0 pin as input
|
||||
PORTE &= ~(1 << PORTE0); // disable pullup on RXD0 pin
|
||||
|
||||
#undef BAUD
|
||||
#define BAUD 9600
|
||||
#include <util/setbaud.h>
|
||||
UBRR0H = UBRRH_VALUE;
|
||||
UBRR0L = UBRRL_VALUE;
|
||||
|
||||
UCSR0A &= ~(1 << U2X0); // disable double speed operation
|
||||
|
||||
// set 9O1
|
||||
UCSR0C = (1 << UPM01) | (1 << UPM00) | (1 << UCSZ01) | (1 << UCSZ00);
|
||||
UCSR0B = (1 << UCSZ02);
|
||||
|
||||
// flush receive buffer
|
||||
while ( UCSR0A & (1 << RXC0) ) UDR0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void JETI_DisableTXD (void)
|
||||
{
|
||||
UCSR0B &= ~(1 << TXEN0); // disable TX
|
||||
}
|
||||
|
||||
|
||||
void JETI_EnableTXD (void)
|
||||
{
|
||||
UCSR0B |= (1 << TXEN0); // enable TX
|
||||
}
|
||||
|
||||
|
||||
void JETI_DisableRXD (void)
|
||||
{
|
||||
UCSR0B &= ~(1 << RXEN0); // disable RX
|
||||
UCSR0B &= ~(1 << RXCIE0); // disable Interrupt
|
||||
}
|
||||
|
||||
|
||||
void JETI_EnableRXD (void)
|
||||
{
|
||||
UCSR0B |= (1 << RXEN0); // enable RX
|
||||
UCSR0B |= (1 << RXCIE0); // enable Interrupt
|
||||
}
|
||||
|
||||
|
||||
void JETI_putw (uint16_t c)
|
||||
{
|
||||
loop_until_bit_is_set(UCSR0A, UDRE0);
|
||||
UCSR0B &= ~(1 << TXB80);
|
||||
if (c & 0x0100)
|
||||
{
|
||||
UCSR0B |= (1 << TXB80);
|
||||
}
|
||||
UDR0 = c;
|
||||
}
|
||||
|
||||
void JETI_putc (uint8_t c)
|
||||
{
|
||||
loop_until_bit_is_set(UCSR0A, UDRE0);
|
||||
// UCSRB &= ~(1 << TXB8);
|
||||
UCSR0B |= (1 << TXB80);
|
||||
UDR0 = c;
|
||||
}
|
||||
|
||||
void JETI_puts (char *s)
|
||||
{
|
||||
while (*s)
|
||||
{
|
||||
JETI_putc (*s);
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
void JETI_put_start (void)
|
||||
{
|
||||
loop_until_bit_is_set(UCSR0A, UDRE0);
|
||||
UCSR0B &= ~(1 << TXB80);
|
||||
UDR0 = 0xFE;
|
||||
}
|
||||
|
||||
void JETI_put_stop (void)
|
||||
{
|
||||
loop_until_bit_is_set(UCSR0A, UDRE0);
|
||||
UCSR0B &= ~(1 << TXB80);
|
||||
UDR0 = 0xFF;
|
||||
}
|
||||
|
||||
#include "menus.h"
|
||||
void menuProcJeti(uint8_t event)
|
||||
{
|
||||
TITLE("JETI");
|
||||
|
||||
switch(event)
|
||||
{
|
||||
//case EVT_KEY_FIRST(KEY_MENU):
|
||||
// break;
|
||||
case EVT_KEY_FIRST(KEY_EXIT):
|
||||
JETI_DisableRXD();
|
||||
chainMenu(menuProc0);
|
||||
break;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < 16; i++)
|
||||
{
|
||||
lcd_putcAtt((i+2)*FW, 3*FH, JetiBuffer[i], BSS);
|
||||
lcd_putcAtt((i+2)*FW, 4*FH, JetiBuffer[i+16], BSS);
|
||||
}
|
||||
|
||||
if (JetiBufferReady)
|
||||
{
|
||||
JETI_EnableTXD();
|
||||
if (keyState((EnumKeys)(KEY_UP))) jeti_keys &= JETI_KEY_UP;
|
||||
if (keyState((EnumKeys)(KEY_DOWN))) jeti_keys &= JETI_KEY_DOWN;
|
||||
if (keyState((EnumKeys)(KEY_LEFT))) jeti_keys &= JETI_KEY_LEFT;
|
||||
if (keyState((EnumKeys)(KEY_RIGHT))) jeti_keys &= JETI_KEY_RIGHT;
|
||||
|
||||
JetiBufferReady = 0; // invalidate buffer
|
||||
|
||||
JETI_putw((uint16_t) jeti_keys);
|
||||
_delay_ms (1);
|
||||
JETI_DisableTXD();
|
||||
|
||||
jeti_keys = JETI_KEY_NOCHANGE;
|
||||
}
|
||||
}
|
49
src/jeti.h
Normal file
49
src/jeti.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Author - Karl Szmutny <shadow@privy.de>
|
||||
*
|
||||
* Based on the Code from Peter "woggle" Mack, mac@denich.net
|
||||
* -> http://svn.mikrokopter.de/filedetails.php?repname=Projects&path=/Transportables_Koptertool/trunk/jeti.c
|
||||
*
|
||||
* 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 jeti_h
|
||||
#define jeti_h
|
||||
|
||||
|
||||
#include "gruvin9x.h"
|
||||
|
||||
#define JETI_KEY_LEFT 0x70
|
||||
#define JETI_KEY_RIGHT 0xe0
|
||||
#define JETI_KEY_UP 0xd0
|
||||
#define JETI_KEY_DOWN 0xb0
|
||||
#define JETI_KEY_NOCHANGE 0xf0
|
||||
|
||||
extern uint16_t jeti_keys;
|
||||
extern uint8_t JetiBuffer[32]; // 32 characters
|
||||
extern uint8_t JetiBufferReady;
|
||||
|
||||
void JETI_Init(void);
|
||||
void JETI_DisableTXD (void);
|
||||
void JETI_EnableTXD (void);
|
||||
void JETI_DisableRXD (void);
|
||||
void JETI_EnableRXD (void);
|
||||
|
||||
void JETI_putw (uint16_t c);
|
||||
void JETI_putc (uint8_t c);
|
||||
void JETI_puts (char *s);
|
||||
void JETI_put_start (void);
|
||||
void JETI_put_stop (void);
|
||||
|
||||
void menuProcJeti(uint8_t event);
|
||||
|
||||
#endif
|
||||
|
670
src/lcd.cpp
Normal file
670
src/lcd.cpp
Normal file
|
@ -0,0 +1,670 @@
|
|||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
*
|
||||
* gruvin9x is based on code named er9x by
|
||||
* Author - Erez Raviv <erezraviv@gmail.com>, which is in turn
|
||||
* was based on 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"
|
||||
|
||||
uint8_t displayBuf[DISPLAY_W*DISPLAY_H/8];
|
||||
#define DISPLAY_END (displayBuf+sizeof(displayBuf))
|
||||
#include "font.lbm"
|
||||
#define font_5x8_x20_x7f (font+3)
|
||||
|
||||
#include "font_dblsize.lbm"
|
||||
#define font_10x16_x20_x7f (font_dblsize+3)
|
||||
|
||||
void lcd_clear()
|
||||
{
|
||||
memset(displayBuf, 0, sizeof(displayBuf));
|
||||
}
|
||||
|
||||
void lcd_img(uint8_t i_x,uint8_t i_y,const prog_uchar * imgdat,uint8_t idx,uint8_t mode)
|
||||
{
|
||||
const prog_uchar *q = imgdat;
|
||||
uint8_t w = pgm_read_byte(q++);
|
||||
uint8_t hb = (pgm_read_byte(q++)+7)/8;
|
||||
uint8_t sze1 = pgm_read_byte(q++);
|
||||
q += idx*sze1;
|
||||
bool inv = (mode & INVERS) ? true : (mode & BLINK ? BLINK_ON_PHASE : false);
|
||||
for(uint8_t yb = 0; yb < hb; yb++){
|
||||
uint8_t *p = &displayBuf[ (i_y / 8 + yb) * DISPLAY_W + i_x ];
|
||||
for(uint8_t x=0; x < w; x++){
|
||||
uint8_t b = pgm_read_byte(q++);
|
||||
*p++ = inv ? ~b : b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t lcd_lastPos;
|
||||
|
||||
void lcd_putcAtt(uint8_t x, uint8_t y, const char c, uint8_t mode)
|
||||
{
|
||||
uint8_t *p = &displayBuf[ y / 8 * DISPLAY_W + x ];
|
||||
|
||||
prog_uchar *q = &font_5x8_x20_x7f[ + (c-0x20)*5];
|
||||
bool inv = (mode & INVERS) ? true : (mode & BLINK ? BLINK_ON_PHASE : false);
|
||||
if(mode & DBLSIZE)
|
||||
{
|
||||
/* each letter consists of ten top bytes followed by
|
||||
* by ten bottom bytes (20 bytes per * char) */
|
||||
q = &font_10x16_x20_x7f[(c-0x20)*10 + ((c-0x20)/16)*160];
|
||||
for(char i=5; i>=0; i--) {
|
||||
if (mode & CONDENSED && i==0) break;
|
||||
/*top byte*/
|
||||
uint8_t b1 = i>0 ? pgm_read_byte(q) : 0;
|
||||
/*bottom byte*/
|
||||
uint8_t b3 = i>0 ? pgm_read_byte(160+q) : 0;
|
||||
/*top byte*/
|
||||
uint8_t b2 = i>0 ? pgm_read_byte(++q) : 0;
|
||||
/*bottom byte*/
|
||||
uint8_t b4 = i>0 ? pgm_read_byte(160+q) : 0;
|
||||
|
||||
if(inv) {
|
||||
b1=~b1;
|
||||
b2=~b2;
|
||||
b3=~b3;
|
||||
b4=~b4;
|
||||
}
|
||||
|
||||
if(&p[DISPLAY_W+1] < DISPLAY_END){
|
||||
p[0]=b1;
|
||||
p[1]=b2;
|
||||
p[DISPLAY_W] = b3;
|
||||
p[DISPLAY_W+1] = b4;
|
||||
p+=2;
|
||||
}
|
||||
q++;
|
||||
}
|
||||
#if OUTDEZ_SPEED != 0
|
||||
lcd_lastPos = x + 2*FW;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
uint8_t condense=0;
|
||||
|
||||
if (mode & CONDENSED) {
|
||||
*p++ = inv ? ~0 : 0;
|
||||
condense=1;
|
||||
}
|
||||
|
||||
for (char i=5; i!=0; i--) {
|
||||
uint8_t b = pgm_read_byte(q++);
|
||||
if (condense && i==4) {
|
||||
/*condense the letter by skipping column 4 */
|
||||
continue;
|
||||
}
|
||||
if(p<DISPLAY_END) *p++ = inv ? ~b : b;
|
||||
}
|
||||
if(p<DISPLAY_END) *p++ = inv ? ~0 : 0;
|
||||
|
||||
#if OUTDEZ_SPEED != 0
|
||||
lcd_lastPos = x + FW;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void lcd_putc(uint8_t x,uint8_t y,const char c)
|
||||
{
|
||||
lcd_putcAtt(x,y,c,0);
|
||||
}
|
||||
|
||||
void lcd_putsnAtt(uint8_t x,uint8_t y,const prog_char * s,uint8_t len,uint8_t mode)
|
||||
{
|
||||
while(len!=0) {
|
||||
char c;
|
||||
switch (mode & (BSS+ZCHAR)) {
|
||||
case BSS:
|
||||
c = *s;
|
||||
break;
|
||||
case ZCHAR:
|
||||
c = idx2char(*s);
|
||||
break;
|
||||
default:
|
||||
c = pgm_read_byte(s);
|
||||
break;
|
||||
}
|
||||
lcd_putcAtt(x,y,c,mode);
|
||||
x+=FW;
|
||||
if (mode&DBLSIZE) x+=FW-1;
|
||||
s++;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
void lcd_putsn_P(uint8_t x,uint8_t y,const prog_char * s,uint8_t len)
|
||||
{
|
||||
lcd_putsnAtt( x,y,s,len,0);
|
||||
}
|
||||
|
||||
void lcd_putsAtt(uint8_t x,uint8_t y,const prog_char * s,uint8_t mode)
|
||||
{
|
||||
while(1) {
|
||||
char c = (mode & BSS) ? *s++ : pgm_read_byte(s++);
|
||||
if(!c) break;
|
||||
lcd_putcAtt(x,y,c,mode);
|
||||
x+=FW;
|
||||
if(mode&DBLSIZE) x+=FW;
|
||||
}
|
||||
#if OUTDEZ_SPEED == 0
|
||||
lcd_lastPos = x;
|
||||
#endif
|
||||
}
|
||||
|
||||
void lcd_puts_P(uint8_t x,uint8_t y,const prog_char * s)
|
||||
{
|
||||
lcd_putsAtt( x, y, s, 0);
|
||||
}
|
||||
|
||||
void lcd_outhex4(uint8_t x,uint8_t y,uint16_t val)
|
||||
{
|
||||
x+=FWNUM*4;
|
||||
for(int i=0; i<4; i++)
|
||||
{
|
||||
x-=FWNUM;
|
||||
char c = val & 0xf;
|
||||
c = c>9 ? c+'A'-10 : c+'0';
|
||||
lcd_putcAtt(x,y,c,c>='A'?CONDENSED:0);
|
||||
val>>=4;
|
||||
}
|
||||
}
|
||||
void lcd_outdez8(uint8_t x, uint8_t y, int8_t val)
|
||||
{
|
||||
lcd_outdezAtt(x, y, val);
|
||||
}
|
||||
|
||||
void lcd_outdezAtt(uint8_t x, uint8_t y, int16_t val, uint8_t mode)
|
||||
{
|
||||
lcd_outdezNAtt(x, y, val, mode);
|
||||
}
|
||||
|
||||
// TODO use doxygen style comments here
|
||||
|
||||
/*
|
||||
USAGE:
|
||||
lcd_outdezNAtt(x-coord, y-coord, (un)signed-value{0..65535|0..+/-32768},
|
||||
mode_flags, length)
|
||||
|
||||
Available mode_flas: PREC{1..3}, UNSIGN (for programmer selected signed numbers
|
||||
to allow for unsigned values up to the ful 65535 16-bit limt))
|
||||
|
||||
LEADING0 means pad 0 to the left of sig. digits up to 'len' total characters
|
||||
*/
|
||||
|
||||
#if OUTDEZ_SPEED != 0
|
||||
void lcd_outdezNAtt(uint8_t x, uint8_t y, int16_t val, uint8_t flags, uint8_t len)
|
||||
{
|
||||
assert(len <= 5);
|
||||
|
||||
char digits[5]; // sig. digits buffered in reverse order
|
||||
int8_t lastDigit = 4;
|
||||
int8_t mode = MODE(flags);
|
||||
|
||||
bool neg = false;
|
||||
if (flags & UNSIGN) { flags -= UNSIGN; }
|
||||
else if (val < 0) { neg=true; val=-val; }
|
||||
|
||||
bool dblsize = (flags & DBLSIZE);
|
||||
|
||||
// Buffer characters and determine the significant digit count
|
||||
for (int8_t i=4; i>=0; i--)
|
||||
{
|
||||
if (val) lastDigit = i;
|
||||
digits[i] = ((uint16_t)val % 10) + '0';
|
||||
val = (uint16_t)val / 10;
|
||||
}
|
||||
|
||||
switch(mode)
|
||||
{
|
||||
case MODE(LEADING0):
|
||||
lastDigit = 5-len;
|
||||
break;
|
||||
default:
|
||||
if (4-lastDigit < mode)
|
||||
lastDigit = 4 - mode;
|
||||
break;
|
||||
}
|
||||
|
||||
lcd_lastPos = x;
|
||||
if (~flags & LEFT) // determine correct x-coord starting point for decimal aligned
|
||||
{
|
||||
// Starting point for regular unsigned, non-decimal number
|
||||
lcd_lastPos -= (5-lastDigit) * (dblsize ? 2*FWNUM : FWNUM) + (dblsize ? 1 : 0);
|
||||
if (mode>0 && !dblsize) lcd_lastPos -= dblsize ? 3 : 2;
|
||||
if (neg) lcd_lastPos -= dblsize ? 2*FW : FW;
|
||||
}
|
||||
|
||||
if (neg) lcd_putcAtt(lcd_lastPos, y, '-', flags); // apply sign when required
|
||||
|
||||
uint8_t xn = 0;
|
||||
uint8_t ln = 2;
|
||||
|
||||
for (int8_t i=lastDigit; i<5; i++)
|
||||
{
|
||||
lcd_putcAtt(lcd_lastPos-1, y, digits[i], flags);
|
||||
|
||||
if (dblsize) {
|
||||
lcd_lastPos--;
|
||||
}
|
||||
|
||||
// Draw decimal point
|
||||
|
||||
// Use direct screen writes to save flash, function calls, stack, cpu load
|
||||
|
||||
#if OUTDEZ_SPEED == 2
|
||||
bool inv = (flags & INVERS) ? true : (flags & BLINK ? BLINK_ON_PHASE : false);
|
||||
#endif
|
||||
|
||||
if (mode>0 && 4-i==mode) // .. then draw a d'point
|
||||
{
|
||||
if (dblsize)
|
||||
{
|
||||
xn = lcd_lastPos-1;
|
||||
if (digits[i+1]=='2' || digits[i+1]=='3' || digits[i+1]=='1') ln++;
|
||||
if (digits[i]=='2' || digits[i]=='4') {
|
||||
if (digits[i+1]=='4') xn++;
|
||||
else { xn--; ln++; }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#if OUTDEZ_SPEED == 2
|
||||
displayBuf[ y * (DISPLAY_W/8) + lcd_lastPos ] = (inv ? 0x40 ^ 0xff : 0x40);
|
||||
#else
|
||||
lcd_plot(lcd_lastPos, y+6);
|
||||
if (flags & INVERS || (flags & BLINK && BLINK_ON_PHASE))
|
||||
lcd_vline(lcd_lastPos, y, 8);
|
||||
#endif
|
||||
lcd_lastPos += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (xn) {
|
||||
lcd_hline(xn, y+2*FH-3, ln);
|
||||
lcd_hline(xn, y+2*FH-2, ln);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void lcd_outdezNAtt(uint8_t x, uint8_t y, int16_t val, uint8_t flags, uint8_t len)
|
||||
{
|
||||
uint8_t fw = FWNUM;
|
||||
int8_t mode = MODE(flags);
|
||||
|
||||
bool neg = false;
|
||||
if (flags & UNSIGN) { flags -= UNSIGN; }
|
||||
else if (val < 0) { neg=true; val=-val; }
|
||||
|
||||
uint8_t xn = 0;
|
||||
uint8_t ln = 2;
|
||||
char c;
|
||||
|
||||
if (mode != MODE(LEADING0)) {
|
||||
len = 1;
|
||||
uint16_t tmp = ((uint16_t)val) / 10;
|
||||
while (tmp) {
|
||||
len++;
|
||||
tmp /= 10;
|
||||
}
|
||||
if (len <= mode)
|
||||
len = mode + 1;
|
||||
}
|
||||
|
||||
if (flags & DBLSIZE) {
|
||||
fw += FWNUM;
|
||||
}
|
||||
else {
|
||||
if (flags & LEFT) {
|
||||
if (mode > 0)
|
||||
x += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & LEFT) {
|
||||
x += len * fw;
|
||||
if (neg)
|
||||
x += FWNUM;
|
||||
}
|
||||
|
||||
lcd_lastPos = x;
|
||||
x -= fw + 1;
|
||||
|
||||
for (uint8_t i=1; i<=len; i++) {
|
||||
c = ((uint16_t)val % 10) + '0';
|
||||
if (c=='1' && flags&DBLSIZE && i==len) { x+=2; flags|=CONDENSED; }
|
||||
lcd_putcAtt(x, y, c, flags);
|
||||
if (mode==i) {
|
||||
flags &= ~PREC2; // TODO not needed but removes 64bytes, could be improved for sure, check asm
|
||||
if (flags & DBLSIZE) {
|
||||
xn = x;
|
||||
if(c=='2' || c=='3' || c=='1') ln++;
|
||||
uint8_t tn = ((uint16_t)val/10) % 10;
|
||||
if (tn==2 || tn==4) {
|
||||
if (c=='4') { xn++; }
|
||||
else { xn--; ln++; }
|
||||
}
|
||||
}
|
||||
else {
|
||||
x -= 2;
|
||||
lcd_plot(x+1, y+6);
|
||||
if (flags & INVERS || (flags & BLINK && BLINK_ON_PHASE))
|
||||
lcd_vline(x+1, y, 8);
|
||||
}
|
||||
}
|
||||
val = ((uint16_t)val) / 10;
|
||||
x-=fw;
|
||||
}
|
||||
if (xn) {
|
||||
lcd_hline(xn, y+2*FH-3, ln);
|
||||
lcd_hline(xn, y+2*FH-2, ln);
|
||||
}
|
||||
|
||||
// TODO we could change the '-' to have one pixel removed at its left
|
||||
if (neg) { lcd_putcAtt(x, y, '-', flags); lcd_plot(x, y+3); }
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void lcd_mask(uint8_t *p, uint8_t mask, uint8_t att)
|
||||
{
|
||||
assert(p < DISPLAY_END);
|
||||
|
||||
if (att & BLACK)
|
||||
*p |= mask;
|
||||
else if (att & WHITE)
|
||||
*p &= ~mask;
|
||||
else
|
||||
*p ^= mask;
|
||||
}
|
||||
|
||||
void lcd_plot(uint8_t x,uint8_t y, uint8_t att)
|
||||
{
|
||||
uint8_t *p = &displayBuf[ y / 8 * DISPLAY_W + x ];
|
||||
if (p<DISPLAY_END)
|
||||
lcd_mask(p, BITMASK(y%8), att);
|
||||
}
|
||||
|
||||
void lcd_hlineStip(int8_t x, uint8_t y, uint8_t w, uint8_t pat, uint8_t att)
|
||||
{
|
||||
if (y >= DISPLAY_H) return;
|
||||
if (x<0) { w+=x; x=0; }
|
||||
if (x+w > DISPLAY_W) { w = DISPLAY_W - x; }
|
||||
|
||||
uint8_t *p = &displayBuf[ y / 8 * DISPLAY_W + x ];
|
||||
uint8_t msk = BITMASK(y%8);
|
||||
while(w) {
|
||||
if(pat&1) {
|
||||
lcd_mask(p, msk, att);
|
||||
pat = (pat >> 1) | 0x80;
|
||||
}
|
||||
else {
|
||||
pat = pat >> 1;
|
||||
}
|
||||
w--;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
void lcd_hline(uint8_t x,uint8_t y, uint8_t w, uint8_t att)
|
||||
{
|
||||
lcd_hlineStip(x, y, w, 0xff, att);
|
||||
}
|
||||
|
||||
void lcd_vlineStip(uint8_t x, int8_t y, int8_t h, uint8_t pat)
|
||||
{
|
||||
if (y<0) { h+=y; y=0; }
|
||||
if (y+h > DISPLAY_H) { h = DISPLAY_H - y; }
|
||||
|
||||
uint8_t *p = &displayBuf[ y / 8 * DISPLAY_W + x ];
|
||||
y = y % 8;
|
||||
if (y) {
|
||||
assert(p < DISPLAY_END);
|
||||
*p ^= ~(BITMASK(y)-1) & pat;
|
||||
p += DISPLAY_W;
|
||||
h -= 8-y;
|
||||
}
|
||||
while (h>0) {
|
||||
assert(p < DISPLAY_END);
|
||||
*p ^= pat;
|
||||
p += DISPLAY_W;
|
||||
h -= 8;
|
||||
}
|
||||
h = (h+8) % 8;
|
||||
if (h) {
|
||||
p -= DISPLAY_W;
|
||||
assert(p < DISPLAY_END);
|
||||
*p ^= ~(BITMASK(h)-1) & pat;
|
||||
}
|
||||
}
|
||||
|
||||
void lcd_vline(uint8_t x, int8_t y, int8_t h)
|
||||
{
|
||||
lcd_vlineStip(x, y, h, 0xff);
|
||||
}
|
||||
|
||||
void lcd_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t pat, uint8_t att)
|
||||
{
|
||||
if (!((att & BLINK) && BLINK_ON_PHASE)) {
|
||||
lcd_vlineStip(x, y, h, pat);
|
||||
lcd_hlineStip(x, y+h-1, w, pat);
|
||||
lcd_vlineStip(x+w-1, y, h, pat);
|
||||
lcd_hlineStip(x, y, w, pat);
|
||||
}
|
||||
}
|
||||
|
||||
void lcd_filled_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t att)
|
||||
{
|
||||
for (uint8_t i=y; i<y+h; i++)
|
||||
lcd_hline(x, i, w, att);
|
||||
}
|
||||
|
||||
void putsTime(uint8_t x,uint8_t y,int16_t tme,uint8_t att,uint8_t att2)
|
||||
{
|
||||
if (tme<0) {
|
||||
lcd_putcAtt(x - ((att & DBLSIZE) ? FW+1 : FWNUM), y, '-', att);
|
||||
tme = -tme;
|
||||
}
|
||||
|
||||
lcd_outdezNAtt(x, y, tme/60, att|LEADING0|LEFT, 2);
|
||||
lcd_putcAtt(lcd_lastPos-((att & DBLSIZE) ? 1 : 0), y, ':', att&att2);
|
||||
#if OUTDEZ_SPEED != 0
|
||||
lcd_outdezNAtt(lcd_lastPos-((att & DBLSIZE) ? 5 : 0), y, tme%60, att2|LEADING0|LEFT, 2);
|
||||
#else
|
||||
lcd_outdezNAtt(lcd_lastPos+FW, y, tme%60, att2|LEADING0|LEFT, 2);
|
||||
#endif
|
||||
}
|
||||
|
||||
void putsVolts(uint8_t x, uint8_t y, uint16_t volts, uint8_t att)
|
||||
{
|
||||
// 215.94us vs 257.31us
|
||||
lcd_outdezAtt(x, y, (int16_t)volts, att|PREC1|UNSIGN);
|
||||
if (~att & NO_UNIT) lcd_putcAtt(lcd_lastPos, y, 'v', att);
|
||||
}
|
||||
|
||||
void putsVBat(uint8_t x, uint8_t y, uint8_t att)
|
||||
{
|
||||
putsVolts(x, y, g_vbat100mV, att);
|
||||
}
|
||||
|
||||
void putsChnRaw(uint8_t x, uint8_t y, uint8_t idx, uint8_t att)
|
||||
{
|
||||
if (idx==0)
|
||||
lcd_putsnAtt(x,y,PSTR("----"),4,att);
|
||||
else if(idx<=4)
|
||||
lcd_putsnAtt(x,y,modi12x3+g_eeGeneral.stickMode*16+4*(idx-1),4,att);
|
||||
else if(idx<=NUM_XCHNRAW)
|
||||
lcd_putsnAtt(x,y,PSTR("P1 P2 P3 MAX FULLCYC1CYC2CYC3PPM1PPM2PPM3PPM4PPM5PPM6PPM7PPM8CH1 CH2 CH3 CH4 CH5 CH6 CH7 CH8 CH9 CH10CH11CH12CH13CH14CH15CH16"TELEMETRY_CHANNELS)+4*(idx-5),4,att);
|
||||
}
|
||||
|
||||
void putsChn(uint8_t x, uint8_t y, uint8_t idx, uint8_t att)
|
||||
{
|
||||
if (idx > 0 && idx <= NUM_CHNOUT)
|
||||
putsChnRaw(x, y, idx+20, att);
|
||||
}
|
||||
|
||||
void putsChnLetter(uint8_t x, uint8_t y, uint8_t idx, uint8_t attr)
|
||||
{
|
||||
lcd_putsnAtt(x, y, PSTR("RETA")+CHANNEL_ORDER(idx)-1, 1, attr);
|
||||
}
|
||||
|
||||
void putsModelName(uint8_t x, uint8_t y, char *name, uint8_t id, uint8_t att)
|
||||
{
|
||||
uint8_t len = sizeof(g_model.name);
|
||||
while (len>0 && !name[len-1]) --len;
|
||||
if (len==0) {
|
||||
lcd_putsAtt(x, y, PSTR("MODEL"/*MODEL*/), att);
|
||||
lcd_outdezNAtt(lcd_lastPos, y, id+1, att|LEADING0|LEFT, 2);
|
||||
}
|
||||
else {
|
||||
lcd_putsnAtt(x, y, name, sizeof(g_model.name), ZCHAR|att);
|
||||
}
|
||||
}
|
||||
|
||||
void putsSwitches(uint8_t x,uint8_t y,int8_t idx,uint8_t att)
|
||||
{
|
||||
switch(idx){
|
||||
case 0: lcd_putsAtt(x,y,PSTR("---"),att);return;
|
||||
case MAX_SWITCH: lcd_putsAtt(x,y,PSTR("ON "),att);return;
|
||||
case -MAX_SWITCH: lcd_putsAtt(x,y,PSTR("OFF"),att);return;
|
||||
}
|
||||
if (idx<0) lcd_putcAtt(x-FW, y, '!', att);
|
||||
lcd_putsnAtt(x,y,get_switches_string()+3*(abs(idx)-1),3,att);
|
||||
}
|
||||
|
||||
void putsFlightPhase(uint8_t x, uint8_t y, int8_t idx, uint8_t att)
|
||||
{
|
||||
if (idx==0) { lcd_putsAtt(x,y,PSTR("---"),att); return; }
|
||||
if (idx < 0) { lcd_putcAtt(x-FW, y, '!', att); idx = -idx; }
|
||||
lcd_putsAtt(x, y, PSTR("FP"), att);
|
||||
lcd_putcAtt(x+2*FW, y, '0'+idx-1, att);
|
||||
}
|
||||
|
||||
void putsTmrMode(uint8_t x, uint8_t y, int8_t mode, uint8_t att)
|
||||
{
|
||||
if (mode < 0) {
|
||||
mode = -mode;
|
||||
lcd_putcAtt(x-1*FW, y, '!', att);
|
||||
}
|
||||
|
||||
if (mode < TMR_VAROFS) {
|
||||
lcd_putsnAtt(x, y, PSTR("OFFABSRUsRU%ELsEL%THsTH%ALsAL%P1 P1%P2 P2%P3 P3%")+3*mode, 3, att);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode < TMR_VAROFS+MAX_SWITCH-1) { // normal on-off
|
||||
putsSwitches(x, y, mode-(TMR_VAROFS-1), att);
|
||||
return;
|
||||
}
|
||||
|
||||
putsSwitches(x, y, mode-(TMR_VAROFS+MAX_SWITCH-1-1), att); // momentary on-off
|
||||
if (~att & SHRT_TM_MODE) lcd_putcAtt(x+3*FW, y, 'm', att);
|
||||
}
|
||||
|
||||
#ifdef FRSKY
|
||||
// TODO move this into frsky.cpp
|
||||
void putsTelemetry(uint8_t x, uint8_t y, uint8_t val, uint8_t unit, uint8_t att)
|
||||
{
|
||||
if (unit == 0/*v*/) {
|
||||
putsVolts(x, y, val, att);
|
||||
}
|
||||
else /* raw or reserved unit */ {
|
||||
lcd_outdezAtt(x, y, val, att);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void lcdSendCtl(uint8_t val)
|
||||
{
|
||||
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1);
|
||||
#ifdef LCD_MULTIPLEX
|
||||
DDRA = 0xFF; // set LCD_DAT pins to output
|
||||
#endif
|
||||
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_A0);
|
||||
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW);
|
||||
PORTA_LCD_DAT = val;
|
||||
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
|
||||
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
|
||||
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
|
||||
#ifdef LCD_MULTIPLEX
|
||||
DDRA = 0x00; // set LCD_DAT pins to input
|
||||
#endif
|
||||
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1);
|
||||
}
|
||||
|
||||
|
||||
#define delay_1us() _delay_us(1)
|
||||
void delay_1_5us(int ms)
|
||||
{
|
||||
for(int i=0; i<ms; i++) delay_1us();
|
||||
}
|
||||
|
||||
|
||||
void lcd_init()
|
||||
{
|
||||
// /home/thus/txt/datasheets/lcd/KS0713.pdf
|
||||
// ~/txt/flieger/ST7565RV17.pdf from http://www.glyn.de/content.asp?wdid=132&sid=
|
||||
|
||||
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RES); //LCD_RES
|
||||
delay_1us();
|
||||
delay_1us();// f520 call 0xf4ce delay_1us() ; 0x0xf4ce
|
||||
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_RES); // f524 sbi 0x15, 2 IOADR-PORTC_LCD_CTRL; 21 1
|
||||
delay_1_5us(1500);
|
||||
lcdSendCtl(0xe2); //Initialize the internal functions
|
||||
lcdSendCtl(0xae); //DON = 0: display OFF
|
||||
lcdSendCtl(0xa1); //ADC = 1: reverse direction(SEG132->SEG1)
|
||||
lcdSendCtl(0xA6); //REV = 0: non-reverse display
|
||||
lcdSendCtl(0xA4); //EON = 0: normal display. non-entire
|
||||
lcdSendCtl(0xA2); // Select LCD bias=0
|
||||
lcdSendCtl(0xC0); //SHL = 0: normal direction (COM1->COM64)
|
||||
lcdSendCtl(0x2F); //Control power circuit operation VC=VR=VF=1
|
||||
lcdSendCtl(0x25); //Select int resistance ratio R2 R1 R0 =5
|
||||
lcdSendCtl(0x81); //Set reference voltage Mode
|
||||
lcdSendCtl(0x22); // 24 SV5 SV4 SV3 SV2 SV1 SV0 = 0x18
|
||||
lcdSendCtl(0xAF); //DON = 1: display ON
|
||||
g_eeGeneral.contrast = 0x22;
|
||||
}
|
||||
|
||||
void lcdSetRefVolt(uint8_t val)
|
||||
{
|
||||
lcdSendCtl(0x81);
|
||||
lcdSendCtl(val);
|
||||
}
|
||||
|
||||
void refreshDiplay()
|
||||
{
|
||||
uint8_t *p=displayBuf;
|
||||
for(uint8_t y=0; y < 8; y++) {
|
||||
lcdSendCtl(0x04);
|
||||
lcdSendCtl(0x10); //column addr 0
|
||||
lcdSendCtl( y | 0xB0); //page addr y
|
||||
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1);
|
||||
#ifdef LCD_MULTIPLEX
|
||||
DDRA = 0xFF; // set LCD_DAT pins to output
|
||||
#endif
|
||||
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
|
||||
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW);
|
||||
for(uint8_t x=128; x>0; --x) {
|
||||
PORTA_LCD_DAT = *p++;
|
||||
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
|
||||
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
|
||||
}
|
||||
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
|
||||
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1);
|
||||
}
|
||||
}
|
139
src/lcd.h
Normal file
139
src/lcd.h
Normal file
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
*
|
||||
* gruvin9x is based on code named er9x by
|
||||
* Author - Erez Raviv <erezraviv@gmail.com>, which is in turn
|
||||
* was based on 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
|
||||
|
||||
#include "gruvin9x.h"
|
||||
|
||||
#define DISPLAY_W 128
|
||||
#define DISPLAY_H 64
|
||||
#define FW 6
|
||||
#define FWNUM 5
|
||||
#define FH 8
|
||||
|
||||
#define OUTDEZ_SPEED 0
|
||||
|
||||
/* lcd common flags */
|
||||
#define BLINK 0x01
|
||||
|
||||
/* lcd text flags */
|
||||
#define INVERS 0x02
|
||||
#define DBLSIZE 0x04
|
||||
|
||||
/* lcd putc flags */
|
||||
#define CONDENSED 0x08
|
||||
|
||||
/* lcd puts flags */
|
||||
#define BSS 0x10
|
||||
#define ZCHAR 0x20
|
||||
|
||||
/* lcd outdez flags */
|
||||
#define UNSIGN 0x08
|
||||
#define LEADING0 0x10
|
||||
#define SPARE1 0x20
|
||||
#define SPARE2 0x30
|
||||
#define SPARE3 0x40
|
||||
#define PREC1 0x50
|
||||
#define PREC2 0x60
|
||||
#define PREC3 0x70
|
||||
#define MODE(flags) (-4 + ((int8_t)(flags & 0x70) >> 4))
|
||||
#define LEFT 0x80 /* align left */
|
||||
|
||||
/* line, rect, square flags */
|
||||
#define BLACK 0x02
|
||||
#define WHITE 0x04
|
||||
|
||||
/* other flags */
|
||||
#define NO_UNIT UNSIGN
|
||||
#define SHRT_TM_MODE 0x10
|
||||
|
||||
|
||||
extern uint8_t displayBuf[DISPLAY_W*DISPLAY_H/8];
|
||||
extern uint8_t lcd_lastPos;
|
||||
|
||||
extern void lcd_putc(unsigned char x,unsigned char y,const char c);
|
||||
extern void lcd_putcAtt(unsigned char x,unsigned char y,const char c,uint8_t mode);
|
||||
|
||||
extern void lcd_putsAtt(unsigned char x,unsigned char y,const prog_char * s,uint8_t mode);
|
||||
extern void lcd_putsnAtt(unsigned char x,unsigned char y,const prog_char * s,unsigned char len,uint8_t mode);
|
||||
extern void lcd_puts_P(unsigned char x,unsigned char y,const prog_char * s);
|
||||
extern void lcd_putsn_P(unsigned char x,unsigned char y,const prog_char * s,unsigned char len);
|
||||
|
||||
extern void lcd_outhex4(unsigned char x,unsigned char y,uint16_t val);
|
||||
|
||||
extern void lcd_outdezAtt(uint8_t x, uint8_t y, int16_t val, uint8_t mode=0);
|
||||
extern void lcd_outdezNAtt(uint8_t x, uint8_t y, int16_t val, uint8_t mode=0, uint8_t len=0);
|
||||
extern void lcd_outdez8(uint8_t x, uint8_t y, int8_t val);
|
||||
|
||||
extern void putsModelName(uint8_t x, uint8_t y, char *name, uint8_t id, uint8_t att);
|
||||
extern void putsSwitches(uint8_t x, uint8_t y, int8_t swtch, uint8_t att);
|
||||
extern void putsFlightPhase(uint8_t x, uint8_t y, int8_t idx, uint8_t att);
|
||||
extern void putsTmrMode(uint8_t x, uint8_t y, int8_t mode, uint8_t att);
|
||||
|
||||
extern void putsChnRaw(uint8_t x,uint8_t y,uint8_t idx1,uint8_t att);
|
||||
extern void putsChn(uint8_t x,uint8_t y,uint8_t idx1,uint8_t att);
|
||||
extern void putsChnLetter(uint8_t x, uint8_t y, uint8_t idx, uint8_t attr);
|
||||
|
||||
extern void putsVolts(uint8_t x, uint8_t y, uint16_t volts, uint8_t att);
|
||||
extern void putsVBat(uint8_t x, uint8_t y, uint8_t att);
|
||||
extern void putsTime(uint8_t x,uint8_t y, int16_t tme, uint8_t att, uint8_t att2);
|
||||
|
||||
#ifdef FRSKY
|
||||
// TODO move this into frsky.h
|
||||
extern void putsTelemetry(uint8_t x, uint8_t y, uint8_t val, uint8_t unit, uint8_t att);
|
||||
#endif
|
||||
|
||||
extern void lcd_plot(unsigned char x, unsigned char y, uint8_t att=0);
|
||||
extern void lcd_hline(unsigned char x,unsigned char y, uint8_t w, uint8_t att=0);
|
||||
extern void lcd_hlineStip(int8_t x, uint8_t y, uint8_t w, uint8_t pat, uint8_t att=0);
|
||||
extern void lcd_vline(uint8_t x, int8_t y, int8_t h);
|
||||
extern void lcd_vlineStip(uint8_t x, int8_t y, int8_t h, uint8_t pat);
|
||||
|
||||
extern void lcd_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t pat=0xff, uint8_t att=0);
|
||||
extern void lcd_filled_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t att=0);
|
||||
inline void lcd_square(uint8_t x, uint8_t y, uint8_t w, uint8_t att=0) { lcd_rect(x, y, w, w, 0xff, att); }
|
||||
|
||||
#define DO_CROSS(xx,yy,ww) \
|
||||
lcd_vline(xx,yy-ww/2,ww); \
|
||||
lcd_hline(xx-ww/2,yy,ww);
|
||||
|
||||
#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);
|
||||
|
||||
extern void lcd_img_f(unsigned char x,unsigned char y);
|
||||
extern void lcd_img(uint8_t i_x,uint8_t i_y,const prog_uchar * imgdat,uint8_t idx,uint8_t mode);
|
||||
|
||||
extern void lcdSetRefVolt(unsigned char val);
|
||||
|
||||
extern void lcd_init();
|
||||
extern void lcd_clear();
|
||||
|
||||
extern void refreshDiplay();
|
||||
|
||||
#define BLINK_ON_PHASE (g_blinkTmr10ms & (1<<6))
|
||||
#define BLINK_SYNC g_blinkTmr10ms = (3<<5)
|
||||
|
||||
|
||||
#endif
|
||||
/*eof*/
|
416
src/main_views.cpp
Normal file
416
src/main_views.cpp
Normal file
|
@ -0,0 +1,416 @@
|
|||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
*
|
||||
* gruvin9x is based on code named er9x by
|
||||
* Author - Erez Raviv <erezraviv@gmail.com>, which is in turn
|
||||
* was based on 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 "menus.h"
|
||||
|
||||
#define ALTERNATE 0x10
|
||||
|
||||
enum MainViews {
|
||||
e_outputValues,
|
||||
e_outputBars,
|
||||
e_inputs,
|
||||
e_timer2,
|
||||
#ifdef FRSKY
|
||||
e_telemetry,
|
||||
#endif
|
||||
MAX_VIEWS
|
||||
};
|
||||
|
||||
uint8_t tabViews[] = {
|
||||
1, /*e_outputValues*/
|
||||
1, /*e_outputBars*/
|
||||
3, /*e_inputs*/
|
||||
1, /*e_timer2*/
|
||||
#ifdef FRSKY
|
||||
2, /*e_telemetry*/
|
||||
#endif
|
||||
};
|
||||
|
||||
void menuMainView(uint8_t event)
|
||||
{
|
||||
static uint8_t switchView = 255;
|
||||
static bool instantTrimSwLock;
|
||||
static bool trim2OfsSwLock;
|
||||
|
||||
uint8_t view = (switchView == 255 ? g_eeGeneral.view : switchView);
|
||||
|
||||
bool telemViewSw = isFunctionActive(FUNC_VIEW_TELEMETRY);
|
||||
if (switchView == 255 && telemViewSw) { view = switchView = e_telemetry + ALTERNATE; }
|
||||
if (switchView != 255 && !telemViewSw) { view = g_eeGeneral.view; switchView = 255; }
|
||||
|
||||
uint8_t view_base = view & 0x0f;
|
||||
|
||||
switch(event)
|
||||
{
|
||||
case EVT_KEY_BREAK(KEY_MENU):
|
||||
if (view_base == e_timer2) {
|
||||
Timer2_running = !Timer2_running;
|
||||
beepKey();
|
||||
}
|
||||
break;
|
||||
case EVT_KEY_LONG(KEY_MENU):// go to last menu
|
||||
pushMenu(lastPopMenu());
|
||||
killEvents(event);
|
||||
break;
|
||||
case EVT_KEY_BREAK(KEY_RIGHT):
|
||||
case EVT_KEY_BREAK(KEY_LEFT):
|
||||
if (switchView != 255) break;
|
||||
g_eeGeneral.view = (view + (event == EVT_KEY_BREAK(KEY_RIGHT) ? ALTERNATE : tabViews[view_base]*ALTERNATE-ALTERNATE)) % (tabViews[view_base]*ALTERNATE);
|
||||
eeDirty(EE_GENERAL);
|
||||
beepKey();
|
||||
break;
|
||||
case EVT_KEY_LONG(KEY_RIGHT):
|
||||
pushMenu(menuProcModelSelect);
|
||||
killEvents(event);
|
||||
break;
|
||||
case EVT_KEY_LONG(KEY_LEFT):
|
||||
pushMenu(menuProcSetup);
|
||||
killEvents(event);
|
||||
break;
|
||||
case EVT_KEY_BREAK(KEY_UP):
|
||||
if (switchView != 255) break;
|
||||
g_eeGeneral.view = view+1;
|
||||
if(g_eeGeneral.view>=MAX_VIEWS) g_eeGeneral.view=0;
|
||||
eeDirty(EE_GENERAL);
|
||||
beepKey();
|
||||
break;
|
||||
case EVT_KEY_BREAK(KEY_DOWN):
|
||||
if (switchView != 255) break;
|
||||
if(view>0)
|
||||
g_eeGeneral.view = view - 1;
|
||||
else
|
||||
g_eeGeneral.view = MAX_VIEWS-1;
|
||||
eeDirty(EE_GENERAL);
|
||||
beepKey();
|
||||
break;
|
||||
case EVT_KEY_LONG(KEY_UP):
|
||||
chainMenu(menuProcStatistic);
|
||||
killEvents(event);
|
||||
break;
|
||||
case EVT_KEY_LONG(KEY_DOWN):
|
||||
#if defined(JETI)
|
||||
JETI_EnableRXD(); // enable JETI-Telemetry reception
|
||||
chainMenu(menuProcJeti);
|
||||
#else
|
||||
chainMenu(menuProcStatistic2);
|
||||
#endif
|
||||
killEvents(event);
|
||||
break;
|
||||
case EVT_KEY_FIRST(KEY_EXIT):
|
||||
if(s_timerState==TMR_BEEPING) {
|
||||
s_timerState = TMR_STOPPED;
|
||||
beepKey();
|
||||
}
|
||||
else if (view == e_timer2) {
|
||||
resetTimer2();
|
||||
beepKey();
|
||||
}
|
||||
#ifdef FRSKY
|
||||
else if (view == e_telemetry) {
|
||||
resetTelemetry();
|
||||
beepKey();
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
resetTimer1();
|
||||
}
|
||||
break;
|
||||
case EVT_KEY_LONG(KEY_EXIT):
|
||||
resetTimer1();
|
||||
resetTimer2();
|
||||
#ifdef FRSKY
|
||||
resetTelemetry();
|
||||
#endif
|
||||
beepKey();
|
||||
break;
|
||||
case EVT_ENTRY:
|
||||
killEvents(KEY_EXIT);
|
||||
killEvents(KEY_UP);
|
||||
killEvents(KEY_DOWN);
|
||||
instantTrimSwLock = true;
|
||||
trim2OfsSwLock = true;
|
||||
break;
|
||||
}
|
||||
|
||||
bool trimSw = isFunctionActive(FUNC_INSTANT_TRIM);
|
||||
if (!instantTrimSwLock && trimSw) instantTrim();
|
||||
instantTrimSwLock = trimSw;
|
||||
|
||||
trimSw = isFunctionActive(FUNC_TRIMS_2_OFS);
|
||||
if (!trim2OfsSwLock && trimSw) moveTrimsToOffsets();
|
||||
trim2OfsSwLock = trimSw;
|
||||
|
||||
if (view == e_telemetry+ALTERNATE) {
|
||||
putsModelName(0, 0, g_model.name, g_eeGeneral.currModel, 0);
|
||||
uint8_t att = (g_vbat100mV < g_eeGeneral.vBatWarn ? BLINK : 0);
|
||||
putsVBat(14*FW,0,att);
|
||||
if(s_timerState != TMR_OFF){
|
||||
att = (s_timerState==TMR_BEEPING ? BLINK : 0);
|
||||
putsTime(17*FW, 0, s_timerVal[0], att, att);
|
||||
}
|
||||
lcd_filled_rect(0, 0, DISPLAY_W, 8);
|
||||
}
|
||||
else {
|
||||
uint8_t phase = getFlightPhase();
|
||||
lcd_putsnAtt(6*FW+2, 2*FH, g_model.phaseData[phase].name, sizeof(g_model.phaseData[phase].name), ZCHAR);
|
||||
|
||||
uint8_t att = (g_vbat100mV < g_eeGeneral.vBatWarn ? BLINK : 0) | DBLSIZE;
|
||||
putsModelName(2*FW-2, 0*FH, g_model.name, g_eeGeneral.currModel, DBLSIZE);
|
||||
putsVBat(6*FW+1, 2*FH, att|NO_UNIT);
|
||||
lcd_putc(6*FW+2, 3*FH, 'V');
|
||||
|
||||
if (s_timerState != TMR_OFF) {
|
||||
uint8_t att = DBLSIZE | (s_timerState==TMR_BEEPING ? BLINK : 0);
|
||||
putsTime(12*FW+3, FH*2, s_timerVal[0], att,att);
|
||||
putsTmrMode(s_timerVal[0] >= 0 ? 9*FW-FW/2+5 : 9*FW-FW/2-2, FH*3, g_model.timer1.mode, SHRT_TM_MODE);
|
||||
}
|
||||
|
||||
// trim sliders
|
||||
for(uint8_t i=0; i<4; i++)
|
||||
{
|
||||
#define TL 27
|
||||
// LH LV RV RH
|
||||
static uint8_t x[4] = {128*1/4+2, 4, 128-4, 128*3/4-2};
|
||||
static uint8_t vert[4] = {0,1,1,0};
|
||||
uint8_t xm, ym;
|
||||
xm = x[i];
|
||||
|
||||
uint8_t att = 0;
|
||||
int16_t val = g_model.subtrim[i] + phaseaddress(getTrimFlightPhase(i, phase))->trim[i];
|
||||
|
||||
if (val < -125 || val > 125)
|
||||
att = BLINK;
|
||||
|
||||
if (val < -(TL+1)*4)
|
||||
val = -(TL+1);
|
||||
else if (val > (TL+1)*4)
|
||||
val = TL+1;
|
||||
else
|
||||
val /= 4;
|
||||
|
||||
if (vert[i]) {
|
||||
ym = 31;
|
||||
lcd_vline(xm, ym-TL, TL*2);
|
||||
if(((g_eeGeneral.stickMode&1) != (i&1)) || !(g_model.thrTrim)){
|
||||
lcd_vline(xm-1, ym-1, 3);
|
||||
lcd_vline(xm+1, ym-1, 3);
|
||||
}
|
||||
ym -= val;
|
||||
}
|
||||
else {
|
||||
ym = 60;
|
||||
lcd_hline(xm-TL, ym, TL*2);
|
||||
lcd_hline(xm-1, ym-1, 3);
|
||||
lcd_hline(xm-1, ym+1, 3);
|
||||
xm += val;
|
||||
}
|
||||
lcd_square(xm-3, ym-3, 7, att);
|
||||
}
|
||||
}
|
||||
|
||||
if(view_base<e_inputs) {
|
||||
for(uint8_t i=0; i<8; i++)
|
||||
{
|
||||
uint8_t x0,y0;
|
||||
int16_t val = g_chans512[i];
|
||||
//val += g_model.limitData[i].revert ? g_model.limitData[i].offset : -g_model.limitData[i].offset;
|
||||
switch(view_base)
|
||||
{
|
||||
case e_outputValues:
|
||||
x0 = (i%4*9+3)*FW/2;
|
||||
y0 = i/4*FH+40;
|
||||
// *1000/1024 = x - x/32 + x/128
|
||||
#define GPERC(x) (x - x/32 + x/128)
|
||||
#if defined (DECIMALS_DISPLAYED)
|
||||
lcd_outdezAtt( x0+4*FW , y0, GPERC(val), PREC1);
|
||||
#else
|
||||
lcd_outdezAtt( x0+4*FW , y0, GPERC(val)/10, 0); // G: Don't like the decimal part*
|
||||
#endif
|
||||
break;
|
||||
case e_outputBars:
|
||||
#define WBAR2 (50/2)
|
||||
x0 = i<4 ? 128/4+2 : 128*3/4-2;
|
||||
y0 = 38+(i%4)*5;
|
||||
int8_t l = (abs(val) * WBAR2 + 512) / 1024;
|
||||
if(l>WBAR2) l = WBAR2; // prevent bars from going over the end - comment for debugging
|
||||
|
||||
lcd_hlineStip(x0-WBAR2,y0,WBAR2*2+1,0x55);
|
||||
lcd_vline(x0,y0-2,5);
|
||||
if(val>0){
|
||||
x0+=1;
|
||||
}else{
|
||||
x0-=l;
|
||||
}
|
||||
lcd_hline(x0,y0+1,l);
|
||||
lcd_hline(x0,y0-1,l);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef FRSKY
|
||||
else if(view_base == e_telemetry) {
|
||||
static uint8_t displayCount = 0;
|
||||
static uint8_t staticTelemetry[2];
|
||||
static uint8_t staticRSSI[2];
|
||||
static bool alarmRaised[2];
|
||||
|
||||
if (frskyStreaming) {
|
||||
uint8_t y0, x0, val, blink;
|
||||
if (!displayCount) {
|
||||
for (int i=0; i<2; i++) {
|
||||
staticTelemetry[i] = frskyTelemetry[i].value;
|
||||
staticRSSI[i] = frskyRSSI[i].value;
|
||||
alarmRaised[i] = FRSKY_alarmRaised(i);
|
||||
}
|
||||
}
|
||||
displayCount = (displayCount+1) % 50;
|
||||
if (view & ALTERNATE) {
|
||||
if (g_model.frsky.channels[0].ratio || g_model.frsky.channels[1].ratio) {
|
||||
x0 = 0;
|
||||
for (int i=0; i<2; i++) {
|
||||
if (g_model.frsky.channels[i].ratio) {
|
||||
blink = (alarmRaised[i] ? INVERS : 0);
|
||||
lcd_puts_P(x0, 3*FH, PSTR("A ="));
|
||||
lcd_putc(x0+FW, 3*FH, '1'+i);
|
||||
x0 += 3*FW;
|
||||
val = ((uint16_t)staticTelemetry[i]+g_model.frsky.channels[i].offset)*g_model.frsky.channels[i].ratio / 255;
|
||||
putsTelemetry(x0, 2*FH, val, g_model.frsky.channels[i].type, blink|DBLSIZE|LEFT);
|
||||
val = ((int16_t)frskyTelemetry[i].min+g_model.frsky.channels[i].offset)*g_model.frsky.channels[i].ratio / 255;
|
||||
putsTelemetry(x0+FW, 4*FH, val, g_model.frsky.channels[i].type, 0);
|
||||
val = ((int16_t)frskyTelemetry[i].max+g_model.frsky.channels[i].offset)*g_model.frsky.channels[i].ratio / 255;
|
||||
putsTelemetry(x0+3*FW, 4*FH, val, g_model.frsky.channels[i].type, LEFT);
|
||||
x0 = 11*FW-2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Display RX Batt Volts only if a valid channel (A1/A2) has been selected
|
||||
if (g_eeFrsky.rxVoltsChannel >0)
|
||||
{
|
||||
y+=FH; lcd_puts_P(2*FW, y, PSTR("Rx Batt:"));
|
||||
// Rx batt voltage bar frame
|
||||
|
||||
// Minimum voltage
|
||||
lcd_vline(3, 58, 6); // marker
|
||||
|
||||
y = 6*FH;
|
||||
putsVolts(1, y, g_eeFrsky.rxVoltsBarMin, LEFT);
|
||||
uint8_t middleVolts = g_eeFrsky.rxVoltsBarMin+(g_eeFrsky.rxVoltsBarMax - g_eeFrsky.rxVoltsBarMin)/2;
|
||||
putsVolts(64-FW, y, middleVolts, LEFT);
|
||||
lcd_vline(64, 58, 6); // marker
|
||||
putsVolts(128-FW, y, g_eeFrsky.rxVoltsBarMax, 0);
|
||||
lcd_vline(125, 58, 6); // marker
|
||||
|
||||
// Rx Batt: volts (255 == g_eefrsky.rxVoltsMax)
|
||||
uint16_t centaVolts = (voltsVal > 0) ? (10 * (uint16_t)g_eeFrsky.rxVoltsMax * (uint32_t)(voltsVal) / 255) + g_eeFrsky.rxVoltsOfs : 0;
|
||||
lcd_outdezAtt(13*FW, 4*FH, centaVolts, 0|PREC2);
|
||||
lcd_putc(13*FW, 4*FH, 'v');
|
||||
|
||||
// draw the actual voltage bar
|
||||
uint16_t centaVoltsMin = 10 * g_eeFrsky.rxVoltsBarMin;
|
||||
if (centaVolts >= centaVoltsMin)
|
||||
{
|
||||
uint8_t vbarLen = (centaVolts - (10 * (uint16_t)g_eeFrsky.rxVoltsBarMin)) * 12
|
||||
/ (g_eeFrsky.rxVoltsBarMax - g_eeFrsky.rxVoltsBarMin);
|
||||
for (uint8_t i = 59; i < 63; i++) // Bar 4 pixels thick (high)
|
||||
lcd_hline(4, i, (vbarLen > 120) ? 120 : vbarLen);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
lcd_puts_P(0, 6*FH, PSTR("Rx="));
|
||||
lcd_outdezAtt(3 * FW, 5*FH+2, staticRSSI[0], DBLSIZE|LEFT);
|
||||
lcd_outdezAtt(4 * FW, 7*FH, frskyRSSI[0].min, 0);
|
||||
lcd_outdezAtt(6 * FW, 7*FH, frskyRSSI[0].max, LEFT);
|
||||
lcd_puts_P(11 * FW - 2, 6*FH, PSTR("Tx="));
|
||||
lcd_outdezAtt(14 * FW - 2, 5*FH+2, staticRSSI[1], DBLSIZE|LEFT);
|
||||
lcd_outdezAtt(15 * FW - 2, 7*FH, frskyRSSI[1].min, 0);
|
||||
lcd_outdezAtt(17 * FW - 2, 7*FH, frskyRSSI[1].max, LEFT);
|
||||
}
|
||||
else {
|
||||
y0 = 5*FH;
|
||||
//lcd_puts_P(2*FW-3, y0, PSTR("Tele:"));
|
||||
x0 = 4*FW-3;
|
||||
for (int i=0; i<2; i++) {
|
||||
if (g_model.frsky.channels[i].ratio) {
|
||||
blink = (alarmRaised[i] ? INVERS+BLINK : 0)|LEFT;
|
||||
lcd_puts_P(x0, y0, PSTR("A ="));
|
||||
lcd_putc(x0+FW, y0, '1'+i);
|
||||
val = ((int16_t)staticTelemetry[i]+g_model.frsky.channels[i].offset)*g_model.frsky.channels[i].ratio / 255;
|
||||
putsTelemetry(x0+3*FW, y0, val, g_model.frsky.channels[i].type, blink);
|
||||
x0 = 13*FW-3;
|
||||
}
|
||||
}
|
||||
y0+=FH;
|
||||
//lcd_puts_P(2*FW-3, y0, PSTR("RSSI:"));
|
||||
lcd_puts_P(4*FW-3, y0, PSTR("Rx="));
|
||||
lcd_outdezAtt(7*FW-3, y0, staticRSSI[0], LEFT);
|
||||
lcd_puts_P(13*FW-3, y0, PSTR("Tx="));
|
||||
lcd_outdezAtt(16*FW-3, y0, staticRSSI[1], LEFT);
|
||||
}
|
||||
}
|
||||
else {
|
||||
lcd_putsAtt(22, 40, PSTR("NO DATA"), DBLSIZE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if (view_base<e_timer2) {
|
||||
#define BOX_WIDTH 23
|
||||
#define BAR_HEIGHT (BOX_WIDTH-1l)
|
||||
#define MARKER_WIDTH 5
|
||||
#define SCREEN_WIDTH 128
|
||||
#define SCREEN_HEIGHT 64
|
||||
#define BOX_LIMIT (BOX_WIDTH-MARKER_WIDTH)
|
||||
#define LBOX_CENTERX ( SCREEN_WIDTH/4 + 10)
|
||||
#define LBOX_CENTERY (SCREEN_HEIGHT-9-BOX_WIDTH/2)
|
||||
#define RBOX_CENTERX (3*SCREEN_WIDTH/4 - 10)
|
||||
#define RBOX_CENTERY (SCREEN_HEIGHT-9-BOX_WIDTH/2)
|
||||
|
||||
lcd_square(LBOX_CENTERX-BOX_WIDTH/2, LBOX_CENTERY-BOX_WIDTH/2, BOX_WIDTH);
|
||||
lcd_square(RBOX_CENTERX-BOX_WIDTH/2, RBOX_CENTERY-BOX_WIDTH/2, BOX_WIDTH);
|
||||
|
||||
DO_CROSS(LBOX_CENTERX,LBOX_CENTERY,3)
|
||||
DO_CROSS(RBOX_CENTERX,RBOX_CENTERY,3)
|
||||
|
||||
lcd_square(LBOX_CENTERX+(calibratedStick[0]*BOX_LIMIT/(2*RESX))-MARKER_WIDTH/2, LBOX_CENTERY-(calibratedStick[1]*BOX_LIMIT/(2*RESX))-MARKER_WIDTH/2, MARKER_WIDTH);
|
||||
lcd_square(RBOX_CENTERX+(calibratedStick[3]*BOX_LIMIT/(2*RESX))-MARKER_WIDTH/2, RBOX_CENTERY-(calibratedStick[2]*BOX_LIMIT/(2*RESX))-MARKER_WIDTH/2, MARKER_WIDTH);
|
||||
|
||||
// Optimization by Mike Blandford
|
||||
{
|
||||
uint8_t x, y, len ; // declare temporary variables
|
||||
for( x = -5, y = 4 ; y < 7 ; x += 5, y += 1 )
|
||||
{
|
||||
len = ((calibratedStick[y]+RESX)*BAR_HEIGHT/(RESX*2))+1l ; // calculate once per loop
|
||||
V_BAR(SCREEN_WIDTH/2+x,SCREEN_HEIGHT-10, len )
|
||||
}
|
||||
}
|
||||
|
||||
int8_t a = (view == e_inputs) ? 0 : 3+(view/ALTERNATE)*6;
|
||||
int8_t b = (view == e_inputs) ? 6 : 6+(view/ALTERNATE)*6;
|
||||
for(int8_t i=a; i<(a+3); i++) lcd_putsnAtt(2*FW-2 ,(i-a)*FH+4*FH,get_switches_string()+3*i,3,getSwitch(i+1, 0) ? INVERS : 0);
|
||||
for(int8_t i=b; i<(b+3); i++) lcd_putsnAtt(17*FW-1,(i-b)*FH+4*FH,get_switches_string()+3*i,3,getSwitch(i+1, 0) ? INVERS : 0);
|
||||
}
|
||||
else // timer2
|
||||
{
|
||||
putsTime(33+FW+2, FH*5, timer2, DBLSIZE, DBLSIZE);
|
||||
}
|
||||
}
|
514
src/menus.cpp
Normal file
514
src/menus.cpp
Normal file
|
@ -0,0 +1,514 @@
|
|||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
*
|
||||
* gruvin9x is based on code named er9x by
|
||||
* Author - Erez Raviv <erezraviv@gmail.com>, which is in turn
|
||||
* was based on 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 "gruvin9x.h"
|
||||
#include "templates.h"
|
||||
#include "menus.h"
|
||||
|
||||
int16_t calibratedStick[NUM_STICKS+NUM_POTS];
|
||||
int16_t ex_chans[NUM_CHNOUT]; // Outputs + intermidiates
|
||||
uint8_t s_pgOfs;
|
||||
uint8_t s_editMode;
|
||||
uint8_t s_noHi;
|
||||
|
||||
int16_t g_chans512[NUM_CHNOUT];
|
||||
|
||||
void menu_lcd_onoff( uint8_t x,uint8_t y, uint8_t value, uint8_t mode )
|
||||
{
|
||||
lcd_putsnAtt( x, y, PSTR("OFFON ")+3*value,3,mode ? INVERS:0) ;
|
||||
}
|
||||
|
||||
void menu_lcd_HYPHINV( uint8_t x,uint8_t y, uint8_t value, uint8_t mode )
|
||||
{
|
||||
lcd_putsnAtt( x, y, PSTR("---INV")+3*value,3,mode ? INVERS:0) ;
|
||||
}
|
||||
|
||||
void DisplayScreenIndex(uint8_t index, uint8_t count, uint8_t attr)
|
||||
{
|
||||
lcd_outdezAtt(128,0,count,attr);
|
||||
lcd_putcAtt(1+128-FW*(count>9 ? 3 : 2),0,'/',attr);
|
||||
lcd_outdezAtt(1+128-FW*(count>9 ? 3 : 2),0,index+1,attr);
|
||||
}
|
||||
|
||||
int16_t p1valdiff;
|
||||
int8_t checkIncDec_Ret;
|
||||
int16_t checkIncDec(uint8_t event, int16_t val, int16_t i_min, int16_t i_max, uint8_t i_flags)
|
||||
{
|
||||
int16_t newval = val;
|
||||
uint8_t kpl=KEY_RIGHT, kmi=KEY_LEFT, kother = -1;
|
||||
|
||||
if(event & _MSK_KEY_DBL){
|
||||
uint8_t hlp=kpl;
|
||||
kpl=kmi;
|
||||
kmi=hlp;
|
||||
event=EVT_KEY_FIRST(EVT_KEY_MASK & event);
|
||||
}
|
||||
if(event==EVT_KEY_FIRST(kpl) || event== EVT_KEY_REPT(kpl) || (s_editMode && (event==EVT_KEY_FIRST(KEY_UP) || event== EVT_KEY_REPT(KEY_UP))) ) {
|
||||
newval++;
|
||||
#if defined (BEEPSPKR)
|
||||
beepKeySpkr(BEEP_KEY_UP_FREQ);
|
||||
#else
|
||||
beepKey();
|
||||
#endif
|
||||
kother=kmi;
|
||||
}else if(event==EVT_KEY_FIRST(kmi) || event== EVT_KEY_REPT(kmi) || (s_editMode && (event==EVT_KEY_FIRST(KEY_DOWN) || event== EVT_KEY_REPT(KEY_DOWN))) ) {
|
||||
newval--;
|
||||
#if defined (BEEPSPKR)
|
||||
beepKeySpkr(BEEP_KEY_DOWN_FREQ);
|
||||
#else
|
||||
beepKey();
|
||||
#endif
|
||||
kother=kpl;
|
||||
}
|
||||
if((kother != (uint8_t)-1) && keyState((EnumKeys)kother)){
|
||||
newval=-val;
|
||||
killEvents(kmi);
|
||||
killEvents(kpl);
|
||||
}
|
||||
if(i_min==0 && i_max==1 && event==EVT_KEY_FIRST(KEY_MENU)) {
|
||||
s_editMode = false;
|
||||
newval=!val;
|
||||
killEvents(event);
|
||||
}
|
||||
|
||||
//change values based on P1
|
||||
newval -= p1valdiff;
|
||||
|
||||
if(newval > i_max)
|
||||
{
|
||||
newval = i_max;
|
||||
killEvents(event);
|
||||
#if defined (BEEPSPKR)
|
||||
beepWarn2Spkr(BEEP_KEY_UP_FREQ);
|
||||
#else
|
||||
beepWarn2();
|
||||
#endif
|
||||
}
|
||||
if(newval < i_min)
|
||||
{
|
||||
newval = i_min;
|
||||
killEvents(event);
|
||||
#if defined (BEEPSPKR)
|
||||
beepWarn2Spkr(BEEP_KEY_DOWN_FREQ);
|
||||
#else
|
||||
beepWarn2();
|
||||
#endif
|
||||
}
|
||||
if(newval != val){
|
||||
if(newval==0) {
|
||||
pauseEvents(event); // delay before auto-repeat continues
|
||||
#if defined (BEEPSPKR)
|
||||
if (newval>val)
|
||||
beepWarn2Spkr(BEEP_KEY_UP_FREQ);
|
||||
else
|
||||
beepWarn2Spkr(BEEP_KEY_DOWN_FREQ);
|
||||
#else
|
||||
beepKey();
|
||||
#endif
|
||||
}
|
||||
eeDirty(i_flags & (EE_GENERAL|EE_MODEL));
|
||||
checkIncDec_Ret = (newval > val ? 1 : -1);
|
||||
}
|
||||
else {
|
||||
checkIncDec_Ret = 0;
|
||||
}
|
||||
return newval;
|
||||
}
|
||||
|
||||
int8_t checkIncDecModel(uint8_t event, int8_t i_val, int8_t i_min, int8_t i_max)
|
||||
{
|
||||
return checkIncDec(event,i_val,i_min,i_max,EE_MODEL);
|
||||
}
|
||||
|
||||
int8_t checkIncDecGen(uint8_t event, int8_t i_val, int8_t i_min, int8_t i_max)
|
||||
{
|
||||
return checkIncDec(event,i_val,i_min,i_max,EE_GENERAL);
|
||||
}
|
||||
|
||||
bool check_simple(uint8_t event, uint8_t curr, MenuFuncP *menuTab, uint8_t menuTabSize, uint8_t maxrow)
|
||||
{
|
||||
return check(event, curr, menuTab, menuTabSize, 0, 0, maxrow);
|
||||
}
|
||||
|
||||
bool check_submenu_simple(uint8_t event, uint8_t maxrow)
|
||||
{
|
||||
return check_simple(event, 0, 0, 0, maxrow);
|
||||
}
|
||||
|
||||
#define MAXCOL(row) (horTab ? pgm_read_byte(horTab+min(row, horTabMax)) : (const uint8_t)0)
|
||||
#define INC(val,max) if(val<max) {val++;} else {val=0;}
|
||||
#define DEC(val,max) if(val>0 ) {val--;} else {val=max;}
|
||||
bool check(uint8_t event, uint8_t curr, MenuFuncP *menuTab, uint8_t menuTabSize, prog_uint8_t *horTab, uint8_t horTabMax, uint8_t maxrow)
|
||||
{
|
||||
if (menuTab) {
|
||||
uint8_t attr = m_posVert==0 ? INVERS : 0;
|
||||
|
||||
if (m_posVert==0) {
|
||||
switch(event)
|
||||
{
|
||||
case EVT_KEY_FIRST(KEY_LEFT):
|
||||
if(curr>0)
|
||||
chainMenu((MenuFuncP)pgm_read_adr(&menuTab[curr-1]));
|
||||
else
|
||||
chainMenu((MenuFuncP)pgm_read_adr(&menuTab[menuTabSize-1]));
|
||||
return false;
|
||||
case EVT_KEY_FIRST(KEY_RIGHT):
|
||||
if(curr < (menuTabSize-1))
|
||||
chainMenu((MenuFuncP)pgm_read_adr(&menuTab[curr+1]));
|
||||
else
|
||||
chainMenu((MenuFuncP)pgm_read_adr(&menuTab[0]));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
DisplayScreenIndex(curr, menuTabSize, attr);
|
||||
}
|
||||
|
||||
uint8_t maxcol = MAXCOL(m_posVert);
|
||||
switch(event)
|
||||
{
|
||||
case EVT_ENTRY:
|
||||
minit();
|
||||
s_editMode = false;
|
||||
break;
|
||||
case EVT_KEY_FIRST(KEY_MENU):
|
||||
if (maxcol > 0)
|
||||
s_editMode = !s_editMode;
|
||||
break;
|
||||
case EVT_KEY_LONG(KEY_EXIT):
|
||||
s_editMode = false;
|
||||
popMenu(false);
|
||||
break;
|
||||
case EVT_KEY_BREAK(KEY_EXIT):
|
||||
if(s_editMode) {
|
||||
s_editMode = false;
|
||||
break;
|
||||
}
|
||||
if(m_posVert==0 || !menuTab) {
|
||||
popMenu(); //beeps itself
|
||||
}
|
||||
else {
|
||||
beepKey();
|
||||
minit();BLINK_SYNC;
|
||||
}
|
||||
break;
|
||||
|
||||
case EVT_KEY_REPT(KEY_RIGHT): //inc
|
||||
if(m_posHorz==maxcol) break;
|
||||
case EVT_KEY_FIRST(KEY_RIGHT)://inc
|
||||
if(!horTab || s_editMode)break;
|
||||
INC(m_posHorz,maxcol);
|
||||
BLINK_SYNC;
|
||||
break;
|
||||
|
||||
case EVT_KEY_REPT(KEY_LEFT): //dec
|
||||
if(m_posHorz==0) break;
|
||||
case EVT_KEY_FIRST(KEY_LEFT)://dec
|
||||
if(!horTab || s_editMode)break;
|
||||
DEC(m_posHorz,maxcol);
|
||||
BLINK_SYNC;
|
||||
break;
|
||||
|
||||
case EVT_KEY_REPT(KEY_DOWN): //inc
|
||||
if(m_posVert==maxrow) break;
|
||||
case EVT_KEY_FIRST(KEY_DOWN): //inc
|
||||
if(s_editMode)break;
|
||||
do {
|
||||
INC(m_posVert,maxrow);
|
||||
} while(MAXCOL(m_posVert) == (uint8_t)-1);
|
||||
m_posHorz = min(m_posHorz, MAXCOL(m_posVert));
|
||||
BLINK_SYNC;
|
||||
break;
|
||||
|
||||
case EVT_KEY_REPT(KEY_UP): //dec
|
||||
if(m_posVert==0) break;
|
||||
case EVT_KEY_FIRST(KEY_UP): //dec
|
||||
if(s_editMode)break;
|
||||
do {
|
||||
DEC(m_posVert,maxrow);
|
||||
} while(MAXCOL(m_posVert) == (uint8_t)-1);
|
||||
m_posHorz = min(m_posHorz, MAXCOL(m_posVert));
|
||||
BLINK_SYNC;
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t max = menuTab ? 7 : 6;
|
||||
if(m_posVert<1) s_pgOfs=0;
|
||||
else if(m_posVert-s_pgOfs>max) s_pgOfs = m_posVert-max;
|
||||
else if(m_posVert-s_pgOfs<1) s_pgOfs = m_posVert-1;
|
||||
return true;
|
||||
}
|
||||
|
||||
MenuFuncP g_menuStack[5];
|
||||
uint8_t g_menuPos[4];
|
||||
uint8_t g_menuStackPtr = 0;
|
||||
|
||||
uint8_t m_posVert;
|
||||
uint8_t m_posHorz;
|
||||
|
||||
void popMenu(bool uppermost)
|
||||
{
|
||||
if (g_menuStackPtr>0) {
|
||||
g_menuStackPtr = uppermost ? 0 : g_menuStackPtr-1;
|
||||
beepKey();
|
||||
m_posHorz = g_menuPos[g_menuStackPtr] & 0x0F;
|
||||
m_posVert = g_menuPos[g_menuStackPtr] >> 4;
|
||||
(*g_menuStack[g_menuStackPtr])(EVT_ENTRY_UP);
|
||||
}
|
||||
else {
|
||||
alert(PSTR("menuStack underflow"));
|
||||
}
|
||||
}
|
||||
|
||||
void chainMenu(MenuFuncP newMenu)
|
||||
{
|
||||
g_menuStack[g_menuStackPtr] = newMenu;
|
||||
(*newMenu)(EVT_ENTRY);
|
||||
beepKey();
|
||||
}
|
||||
|
||||
void pushMenu(MenuFuncP newMenu)
|
||||
{
|
||||
g_menuPos[g_menuStackPtr] = (m_posVert << 4) + m_posHorz;
|
||||
|
||||
g_menuStackPtr++;
|
||||
if(g_menuStackPtr >= DIM(g_menuStack))
|
||||
{
|
||||
g_menuStackPtr--;
|
||||
alert(PSTR("menuStack overflow"));
|
||||
return;
|
||||
}
|
||||
beepKey();
|
||||
g_menuStack[g_menuStackPtr] = newMenu;
|
||||
(*newMenu)(EVT_ENTRY);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
the functions below are from int-level
|
||||
the functions below are from int-level
|
||||
the functions below are from int-level
|
||||
******************************************************************************/
|
||||
|
||||
void setupPulses()
|
||||
{
|
||||
switch(g_model.protocol)
|
||||
{
|
||||
case PROTO_PPM:
|
||||
setupPulsesPPM();
|
||||
break;
|
||||
case PROTO_SILV_A:
|
||||
case PROTO_SILV_B:
|
||||
case PROTO_SILV_C:
|
||||
setupPulsesSilver();
|
||||
break;
|
||||
case PROTO_TRACER_CTP1009:
|
||||
setupPulsesTracerCtp1009();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//inline int16_t reduceRange(int16_t x) // for in case we want to have room for subtrims
|
||||
//{
|
||||
// return x-(x/4); //512+128 =? 640, 640 - 640/4 == 640 * 3/4 => 480 (just below 500msec - it can still reach 500 with offset)
|
||||
//}
|
||||
|
||||
void setupPulsesPPM() // changed 10/05/2010 by dino Issue 128
|
||||
{
|
||||
#define PPM_CENTER 1200*2
|
||||
int16_t PPM_range = g_model.extendedLimits ? 640*2 : 512*2; //range of 0.7..1.7msec
|
||||
|
||||
//Total frame length = 22.5msec
|
||||
//each pulse is 0.7..1.7ms long with a 0.3ms stop tail
|
||||
//The pulse ISR is 2mhz so everything is multiplied by 2
|
||||
|
||||
// G: Found the following reference at th9x. The below code does not seem
|
||||
// to produce quite exactly this, to my eye. *shrug*
|
||||
// http://www.aerodesign.de/peter/2000/PCM/frame_ppm.gif
|
||||
|
||||
uint8_t j=0;
|
||||
uint8_t p=8+g_model.ppmNCH*2; //Channels *2
|
||||
uint16_t q=(g_model.ppmDelay*50+300)*2; //Stoplen *2
|
||||
uint16_t rest=22500u*2-q; //Minimum Framelen=22.5 ms
|
||||
if(p>9) rest=p*(1720u*2 + q) + 4000u*2; //for more than 9 channels, frame must be longer
|
||||
for(uint8_t i=0;i<p;i++){ //NUM_CHNOUT
|
||||
int16_t v = max(min(g_chans512[i],(int16_t)PPM_range),(int16_t)-PPM_range) + (int16_t)PPM_CENTER;
|
||||
rest-=(v+q);
|
||||
pulses2MHz[j++] = q;
|
||||
pulses2MHz[j++] = v - q + 600; /* as Pat MacKenzie suggests */
|
||||
}
|
||||
pulses2MHz[j++]=q;
|
||||
pulses2MHz[j++]=rest;
|
||||
pulses2MHz[j++]=0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
uint16_t *pulses2MHzPtr;
|
||||
#define BITLEN (600u*2)
|
||||
void _send_hilo(uint16_t hi,uint16_t lo)
|
||||
{
|
||||
*pulses2MHzPtr++=hi; *pulses2MHzPtr++=lo;
|
||||
}
|
||||
#define send_hilo_silv( hi, lo) _send_hilo( (hi)*BITLEN,(lo)*BITLEN )
|
||||
|
||||
void sendBitSilv(uint8_t val)
|
||||
{
|
||||
send_hilo_silv((val)?2:1,(val)?2:1);
|
||||
}
|
||||
void send2BitsSilv(uint8_t val)
|
||||
{
|
||||
sendBitSilv(val&2);sendBitSilv(val&1);
|
||||
}
|
||||
// _ oder - je 0.6ms (gemessen 0.7ms)
|
||||
//
|
||||
//____-----_-_-_--_--_ -_--__ -_-_-_-_ -_-_-_-_ --__--__-_______
|
||||
// trailer chan m1 m2
|
||||
//
|
||||
//see /home/thus/txt/silverlit/thus.txt
|
||||
//m1, m2 most significant bit first |m1-m2| <= 9
|
||||
//chan: 01=C 10=B
|
||||
//chk = 0 - chan -m1>>2 -m1 -m2>>2 -m2
|
||||
//<= 500us Probleme
|
||||
//>= 650us Probleme
|
||||
//periode orig: 450ms
|
||||
void setupPulsesSilver()
|
||||
{
|
||||
int8_t chan=1; //chan 1=C 2=B 0=A?
|
||||
|
||||
switch(g_model.protocol)
|
||||
{
|
||||
case PROTO_SILV_A: chan=0; break;
|
||||
case PROTO_SILV_B: chan=2; break;
|
||||
case PROTO_SILV_C: chan=1; break;
|
||||
}
|
||||
|
||||
int8_t m1 = (uint16_t)(g_chans512[0]+1024)*2 / 256;
|
||||
int8_t m2 = (uint16_t)(g_chans512[1]+1024)*2 / 256;
|
||||
if (m1 < 0) m1=0;
|
||||
if (m2 < 0) m2=0;
|
||||
if (m1 > 15) m1=15;
|
||||
if (m2 > 15) m2=15;
|
||||
if (m2 > m1+9) m1=m2-9;
|
||||
if (m1 > m2+9) m2=m1-9;
|
||||
//uint8_t i=0;
|
||||
pulses2MHzPtr=pulses2MHz;
|
||||
send_hilo_silv(5,1); //idx 0 erzeugt pegel=0 am Ausgang, wird als high gesendet
|
||||
send2BitsSilv(0);
|
||||
send_hilo_silv(2,1);
|
||||
send_hilo_silv(2,1);
|
||||
|
||||
send2BitsSilv(chan); //chan 1=C 2=B 0=A?
|
||||
uint8_t sum = 0 - chan;
|
||||
|
||||
send2BitsSilv(m1>>2); //m1
|
||||
sum-=m1>>2;
|
||||
send2BitsSilv(m1);
|
||||
sum-=m1;
|
||||
|
||||
send2BitsSilv(m2>>2); //m2
|
||||
sum-=m2>>2;
|
||||
send2BitsSilv(m2);
|
||||
sum-=m2;
|
||||
|
||||
send2BitsSilv(sum); //chk
|
||||
|
||||
sendBitSilv(0);
|
||||
pulses2MHzPtr--;
|
||||
send_hilo_silv(50,0); //low-impuls (pegel=1) ueberschreiben
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
TRACE CTP-1009
|
||||
- = send 45MHz
|
||||
_ = send nix
|
||||
start1 0 1 start2
|
||||
-------__ --_ -__ -----__
|
||||
7ms 2 .8 .4 .4 .8 5 2
|
||||
|
||||
frame:
|
||||
start1 24Bits_1 start2 24_Bits2
|
||||
|
||||
24Bits_1:
|
||||
7 x Bits Throttle lsb first
|
||||
1 x 0
|
||||
|
||||
6 x Bits rotate lsb first
|
||||
1 x Bit 1=rechts
|
||||
1 x 0
|
||||
|
||||
4 x Bits chk5 = nib2 ^ nib4
|
||||
4 x Bits chk6 = nib1 ^ nib3
|
||||
|
||||
24Bits_2:
|
||||
7 x Bits Vorwaets lsb first 0x3f = mid
|
||||
1 x 1
|
||||
|
||||
7 x Bits 0x0e lsb first
|
||||
1 x 1
|
||||
|
||||
4 x Bits chk5 = nib2 ^ nib4
|
||||
4 x Bits chk6 = nib1 ^ nib3
|
||||
|
||||
*/
|
||||
|
||||
#define BIT_TRA (400u*2)
|
||||
void sendBitTra(uint8_t val)
|
||||
{
|
||||
if(val) _send_hilo( BIT_TRA*1 , BIT_TRA*2 );
|
||||
else _send_hilo( BIT_TRA*2 , BIT_TRA*1 );
|
||||
}
|
||||
void sendByteTra(uint8_t val)
|
||||
{
|
||||
for(uint8_t i=0; i<8; i++, val>>=1) sendBitTra(val&1);
|
||||
}
|
||||
void setupPulsesTracerCtp1009()
|
||||
{
|
||||
pulses2MHzPtr=pulses2MHz;
|
||||
static bool phase;
|
||||
if( (phase=!phase) ){
|
||||
uint8_t thr = min(127u,(uint16_t)(g_chans512[0]+1024+8) / 16u);
|
||||
uint8_t rot;
|
||||
if (g_chans512[1] >= 0)
|
||||
{
|
||||
rot = min(63u,(uint16_t)( g_chans512[1]+16) / 32u) | 0x40;
|
||||
}else{
|
||||
rot = min(63u,(uint16_t)(-g_chans512[1]+16) / 32u);
|
||||
}
|
||||
sendByteTra(thr);
|
||||
sendByteTra(rot);
|
||||
uint8_t chk=thr^rot;
|
||||
sendByteTra( (chk>>4) | (chk<<4) );
|
||||
_send_hilo( 5000*2, 2000*2 );
|
||||
}else{
|
||||
uint8_t fwd = min(127u,(uint16_t)(g_chans512[2]+1024) / 16u) | 0x80;
|
||||
sendByteTra(fwd);
|
||||
sendByteTra(0x8e);
|
||||
uint8_t chk=fwd^0x8e;
|
||||
sendByteTra( (chk>>4) | (chk<<4) );
|
||||
_send_hilo( 7000*2, 2000*2 );
|
||||
}
|
||||
*pulses2MHzPtr++=0;
|
||||
if((pulses2MHzPtr-pulses2MHz) >= (signed)DIM(pulses2MHz)) alert(PSTR("pulse tab overflow"));
|
||||
}
|
129
src/menus.h
Normal file
129
src/menus.h
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
*
|
||||
* gruvin9x is based on code named er9x by
|
||||
* Author - Erez Raviv <erezraviv@gmail.com>, which is in turn
|
||||
* was based on 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
Insert obligatories here
|
||||
|
||||
*/
|
||||
|
||||
#ifndef menus_h
|
||||
#define menus_h
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "gruvin9x.h"
|
||||
|
||||
#define IS_THROTTLE(x) (((2-(g_eeGeneral.stickMode&1)) == x) && (x<4))
|
||||
|
||||
#define NO_HI_LEN 25
|
||||
|
||||
#define RESX 1024
|
||||
#define RESXu 1024u
|
||||
#define RESXul 1024ul
|
||||
#define RESXl 1024l
|
||||
#define RESKul 100ul
|
||||
#define RESX_PLUS_TRIM (RESX+128)
|
||||
|
||||
typedef void (*MenuFuncP)(uint8_t event);
|
||||
|
||||
void DisplayScreenIndex(uint8_t index, uint8_t count, uint8_t attr);
|
||||
|
||||
extern uint8_t s_pgOfs;
|
||||
extern uint8_t s_noHi;
|
||||
|
||||
// extern int16_t expo(int16_t x, int16_t k);
|
||||
|
||||
void menu_lcd_onoff(uint8_t x, uint8_t y, uint8_t value, uint8_t mode);
|
||||
void menu_lcd_HYPHINV(uint8_t x, uint8_t y, uint8_t value, uint8_t mode);
|
||||
|
||||
extern MenuFuncP g_menuStack[5];
|
||||
extern uint8_t g_menuStackPtr;
|
||||
|
||||
/// 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);
|
||||
///deliver address of last menu which was popped from
|
||||
inline MenuFuncP lastPopMenu()
|
||||
{
|
||||
return g_menuStack[g_menuStackPtr+1];
|
||||
}
|
||||
/// return to last menu in menustack
|
||||
/// if uppermost is set true, thenmenu return to uppermost menu in menustack
|
||||
void popMenu(bool uppermost=false);
|
||||
|
||||
void menuMainView(uint8_t event);
|
||||
void menuProcSetup(uint8_t event);
|
||||
void menuProcModelSelect(uint8_t event);
|
||||
void menuProcStatistic(uint8_t event);
|
||||
void menuProcStatistic2(uint8_t event);
|
||||
|
||||
extern int16_t p1valdiff;
|
||||
extern int8_t checkIncDec_Ret; // global helper vars
|
||||
extern uint8_t s_editMode; // global editmode
|
||||
|
||||
int16_t checkIncDec(uint8_t event, int16_t i_pval, int16_t i_min, int16_t i_max, uint8_t i_flags);
|
||||
int8_t checkIncDecModel(uint8_t event, int8_t i_val, int8_t i_min, int8_t i_max);
|
||||
int8_t checkIncDecGen(uint8_t event, int8_t i_val, int8_t i_min, int8_t i_max);
|
||||
|
||||
#define CHECK_INCDEC_MODELVAR( event, var, min, max) \
|
||||
var = checkIncDecModel(event,var,min,max)
|
||||
|
||||
#define CHECK_INCDEC_GENVAR( event, var, min, max) \
|
||||
var = checkIncDecGen(event,var,min,max)
|
||||
|
||||
// Menus related stuff ...
|
||||
extern uint8_t m_posVert;
|
||||
extern uint8_t m_posHorz;
|
||||
inline void minit(){m_posVert=m_posHorz=0;}
|
||||
bool check(uint8_t event, uint8_t curr, MenuFuncP *menuTab, uint8_t menuTabSize, prog_uint8_t *subTab, uint8_t subTabMax, uint8_t maxrow);
|
||||
bool check_simple(uint8_t event, uint8_t curr, MenuFuncP *menuTab, uint8_t menuTabSize, uint8_t maxrow);
|
||||
bool check_submenu_simple(uint8_t event, uint8_t maxrow);
|
||||
|
||||
typedef PROGMEM void (*MenuFuncP_PROGMEM)(uint8_t event);
|
||||
|
||||
#define TITLEP(pstr) lcd_putsAtt(0,0,pstr,INVERS)
|
||||
#define TITLE(str) TITLEP(PSTR(str))
|
||||
|
||||
#define MENU(title, tab, menu, lines_count, lines...) \
|
||||
TITLE(title); \
|
||||
static prog_uint8_t APM mstate_tab[] = lines; \
|
||||
if (!check(event,menu,tab,DIM(tab),mstate_tab,DIM(mstate_tab)-1,lines_count-1)) return;
|
||||
|
||||
#define SIMPLE_MENU_NOTITLE(tab, menu, lines_count) \
|
||||
if (!check_simple(event,menu,tab,DIM(tab),lines_count-1)) return;
|
||||
|
||||
#define SIMPLE_MENU(title, tab, menu, lines_count) \
|
||||
TITLE(title); \
|
||||
SIMPLE_MENU_NOTITLE(tab, menu, lines_count)
|
||||
|
||||
#define SUBMENU(title, lines_count, lines...) \
|
||||
TITLE(title); \
|
||||
static prog_uint8_t APM mstate_tab[] = lines; \
|
||||
if (!check(event,0,NULL,0,mstate_tab,DIM(mstate_tab)-1,lines_count-1)) return;
|
||||
|
||||
#define SIMPLE_SUBMENU_NOTITLE(lines_count) \
|
||||
if (!check_submenu_simple(event,lines_count-1)) return;
|
||||
|
||||
#define SIMPLE_SUBMENU(title, lines_count) \
|
||||
TITLE(title); \
|
||||
SIMPLE_SUBMENU_NOTITLE(lines_count)
|
||||
|
||||
#endif
|
1773
src/model_menus.cpp
Normal file
1773
src/model_menus.cpp
Normal file
File diff suppressed because it is too large
Load diff
256
src/myeeprom.h
Normal file
256
src/myeeprom.h
Normal file
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* Author - Erez Raviv <erezraviv@gmail.com>
|
||||
*
|
||||
* Based on 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 eeprom_h
|
||||
#define eeprom_h
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#define WARN_THR_BIT 0x01
|
||||
#define WARN_BEP_BIT 0x80
|
||||
#define WARN_SW_BIT 0x02
|
||||
#define WARN_MEM_BIT 0x04
|
||||
#define WARN_BVAL_BIT 0x38
|
||||
|
||||
#define WARN_THR (!(g_eeGeneral.warnOpts & WARN_THR_BIT))
|
||||
#define WARN_BEP (!(g_eeGeneral.warnOpts & WARN_BEP_BIT))
|
||||
#define WARN_SW (!(g_eeGeneral.warnOpts & WARN_SW_BIT))
|
||||
#define WARN_MEM (!(g_eeGeneral.warnOpts & WARN_MEM_BIT))
|
||||
#define BEEP_VAL ( (g_eeGeneral.warnOpts & WARN_BVAL_BIT) >>3 )
|
||||
|
||||
#define EEPROM_ER9X_VER 4
|
||||
#define EEPROM_ER9X_r751 9
|
||||
|
||||
#define EEPROM_VER_r584 3
|
||||
#define EEPROM_VER_r751 5
|
||||
#define EEPROM_VER 105
|
||||
|
||||
typedef struct t_TrainerMix {
|
||||
uint8_t srcChn:6; // 0-7 = ch1-8
|
||||
uint8_t mode:2; // off,add-mode,subst-mode
|
||||
int8_t studWeight;
|
||||
} __attribute__((packed)) TrainerMix; //
|
||||
|
||||
typedef struct t_TrainerData {
|
||||
int16_t calib[4];
|
||||
TrainerMix mix[4];
|
||||
} __attribute__((packed)) TrainerData;
|
||||
|
||||
typedef struct t_FrSkyRSSIAlarm {
|
||||
uint8_t level:2;
|
||||
int8_t value:6;
|
||||
} __attribute__((packed)) FrSkyRSSIAlarm;
|
||||
|
||||
typedef struct t_EEGeneral {
|
||||
uint8_t myVers;
|
||||
int16_t calibMid[7];
|
||||
int16_t calibSpanNeg[7];
|
||||
int16_t calibSpanPos[7];
|
||||
uint16_t chkSum;
|
||||
uint8_t currModel; //0..15
|
||||
uint8_t contrast;
|
||||
uint8_t vBatWarn;
|
||||
int8_t vBatCalib;
|
||||
int8_t lightSw;
|
||||
TrainerData trainer;
|
||||
uint8_t view; //index of subview in main scrren
|
||||
uint8_t disableThrottleWarning:1;
|
||||
int8_t switchWarning:2; // -1=down, 0=off, 1=up
|
||||
uint8_t beeperVal:3;
|
||||
uint8_t disableMemoryWarning:1;
|
||||
uint8_t disableAlarmWarning:1;
|
||||
uint8_t stickMode;
|
||||
uint8_t inactivityTimer;
|
||||
uint8_t throttleReversed:1;
|
||||
uint8_t minuteBeep:1;
|
||||
uint8_t preBeep:1;
|
||||
uint8_t flashBeep:1;
|
||||
uint8_t disableSplashScreen:1;
|
||||
uint8_t enableTelemetryAlarm:1; // 0=no, 1=yes (Sound alarm when there's no telem. data coming in)
|
||||
uint8_t spare:2;
|
||||
uint8_t filterInput;
|
||||
uint8_t lightAutoOff;
|
||||
uint8_t templateSetup; //RETA order according to chout_ar array
|
||||
int8_t PPM_Multiplier;
|
||||
FrSkyRSSIAlarm frskyRssiAlarms[2];
|
||||
} __attribute__((packed)) EEGeneral;
|
||||
|
||||
// eeprom modelspec
|
||||
|
||||
typedef struct t_ExpoData {
|
||||
uint8_t mode:2; // 0=end, 1=pos, 2=neg, 3=both
|
||||
uint8_t chn:2;
|
||||
uint8_t curve:4; // 0=no curve, 1-6=std curves, 7-10=CV1-CV4, 11-15=CV9-CV13
|
||||
int8_t swtch:5;
|
||||
uint8_t phase:3; // if negPhase is 0: 0=normal, 5=FP4 if negPhase is 1: 5=!FP4
|
||||
uint8_t negPhase:1;
|
||||
uint8_t weight:7;
|
||||
int8_t expo;
|
||||
} __attribute__((packed)) ExpoData;
|
||||
|
||||
typedef struct t_LimitData {
|
||||
int8_t min;
|
||||
int8_t max;
|
||||
bool revert;
|
||||
int16_t offset;
|
||||
} __attribute__((packed)) LimitData;
|
||||
|
||||
typedef struct t_MixData {
|
||||
uint8_t destCh:5; // 0, 1..NUM_CHNOUT
|
||||
uint8_t mixWarn:3; // mixer warning
|
||||
#define MIX_P1 5
|
||||
#define MIX_P2 6
|
||||
#define MIX_P3 7
|
||||
#define MIX_MAX 8
|
||||
#define MIX_FULL 9
|
||||
#define MIX_CYC1 10
|
||||
#define MIX_CYC2 11
|
||||
#define MIX_CYC3 12
|
||||
uint8_t srcRaw; //
|
||||
int8_t weight;
|
||||
int8_t swtch;
|
||||
uint8_t curve; // 0=symmetrisch, 1=no neg, 2=no pos
|
||||
uint8_t delayUp:4;
|
||||
uint8_t delayDown:4;
|
||||
uint8_t speedUp:4; // Servogeschwindigkeit aus Tabelle (10ms Cycle)
|
||||
uint8_t speedDown:4; // 0 nichts
|
||||
uint8_t carryTrim:1;
|
||||
#define MLTPX_ADD 0
|
||||
#define MLTPX_MUL 1
|
||||
#define MLTPX_REP 2
|
||||
uint8_t mltpx:3; // multiplex method 0=+ 1=* 2=replace
|
||||
int8_t phase:4; // -5=!FP4, 0=normal, 5=FP4
|
||||
int8_t sOffset;
|
||||
} __attribute__((packed)) MixData;
|
||||
|
||||
typedef struct t_CustomSwData { // Custom Switches data
|
||||
int8_t v1; //input
|
||||
int8_t v2; //offset
|
||||
uint8_t func;
|
||||
} __attribute__((packed)) CustomSwData;
|
||||
|
||||
typedef struct t_SafetySwData { // Safety Switches data
|
||||
int8_t swtch;
|
||||
int8_t val;
|
||||
} __attribute__((packed)) SafetySwData;
|
||||
|
||||
#define FUNC_TRAINER 1
|
||||
#define FUNC_INSTANT_TRIM 2
|
||||
#define FUNC_TRIMS_2_OFS 3
|
||||
#define FUNC_VIEW_TELEMETRY 4
|
||||
#define FUNC_LAST 4
|
||||
|
||||
typedef struct t_FuncSwData { // Function Switches data
|
||||
int8_t swtch; //input
|
||||
uint8_t func;
|
||||
} __attribute__((packed)) FuncSwData;
|
||||
|
||||
typedef struct t_FrSkyChannelData {
|
||||
uint8_t ratio; // 0.0 means not used, 0.1V steps EG. 6.6 Volts = 66. 25.1V = 251, etc.
|
||||
uint8_t type:4; // channel unit (0=volts, ...)
|
||||
int8_t offset:4; // calibration offset. Signed 0.1V steps. EG. -4 to substract 0.4V
|
||||
uint8_t alarms_value[2]; // 0.1V steps EG. 6.6 Volts = 66. 25.1V = 251, etc.
|
||||
uint8_t alarms_level:4;
|
||||
uint8_t alarms_greater:2; // 0=LT(<), 1=GT(>)
|
||||
uint8_t spare:2;
|
||||
int8_t barMin; // minimum for bar display
|
||||
uint8_t barMax; // ditto for max display (would usually = ratio)
|
||||
} __attribute__((packed)) FrSkyChannelData;
|
||||
|
||||
typedef struct t_FrSkyData {
|
||||
FrSkyChannelData channels[2];
|
||||
} __attribute__((packed)) FrSkyData;
|
||||
|
||||
typedef struct t_SwashRingData { // Swash Ring data
|
||||
uint8_t invertELE:1;
|
||||
uint8_t invertAIL:1;
|
||||
uint8_t invertCOL:1;
|
||||
uint8_t type:5;
|
||||
uint8_t collectiveSource;
|
||||
uint8_t value;
|
||||
|
||||
/* TODO BSS everything is in comments in menus.cpp, how should it be used?
|
||||
uint8_t lim; // 0 mean off 100 full deflection
|
||||
uint8_t chX; // 2 channels to limit
|
||||
uint8_t chY; // 2 channels to limit */
|
||||
} __attribute__((packed)) SwashRingData;
|
||||
|
||||
typedef struct t_PhaseData {
|
||||
#define TRIM_MAX 125
|
||||
#define TRIM_MIN (-TRIM_MAX)
|
||||
int8_t trim[4]; // -125..125 => trim value, 127 => use trim of phase 0, -128, -127, -126 => use trim of phases 1|2|3|4 instead
|
||||
int8_t swtch; // swtch of phase[0] is not used
|
||||
char name[6];
|
||||
uint8_t fadeIn:4;
|
||||
uint8_t fadeOut:4;
|
||||
} __attribute__((packed)) PhaseData;
|
||||
|
||||
#define MAX_MODELS 16
|
||||
#define MAX_PHASES 5
|
||||
#define MAX_MIXERS 32
|
||||
#define MAX_EXPOS 14
|
||||
#define MAX_CURVE5 8
|
||||
#define MAX_CURVE9 8
|
||||
|
||||
#define NUM_CHNOUT 16 // number of real output channels CH1-CH16
|
||||
#define NUM_CSW 12 // number of custom switches
|
||||
#define NUM_FSW 12 // number of functions assigned to switches
|
||||
|
||||
typedef struct t_TimerData {
|
||||
int8_t mode; // timer trigger source -> off, abs, stk, stk%, sw/!sw, !m_sw/!m_sw
|
||||
uint16_t val:14;
|
||||
uint8_t persistent:1;
|
||||
uint8_t dir:1; // 0=>Count Down, 1=>Count Up
|
||||
} __attribute__((packed)) TimerData;
|
||||
|
||||
typedef struct t_ModelData {
|
||||
char name[10]; // 10 must be first for eeLoadModelName
|
||||
TimerData timer1; // TODO timers array
|
||||
uint8_t protocol:3;
|
||||
int8_t ppmNCH:3;
|
||||
uint8_t thrTrim:1; // Enable Throttle Trim
|
||||
uint8_t thrExpo:1; // Enable Throttle Expo
|
||||
uint8_t trimInc:3; // Trim Increments
|
||||
uint8_t spare1:1;
|
||||
uint8_t pulsePol:1;
|
||||
uint8_t extendedLimits:1;
|
||||
uint8_t extendedTrims:1;
|
||||
uint8_t spare2:1;
|
||||
int8_t ppmDelay;
|
||||
uint8_t beepANACenter; // 1<<0->A1.. 1<<6->A7
|
||||
TimerData timer2;
|
||||
MixData mixData[MAX_MIXERS];
|
||||
LimitData limitData[NUM_CHNOUT];
|
||||
ExpoData expoData[MAX_EXPOS];
|
||||
int8_t curves5[MAX_CURVE5][5];
|
||||
int8_t curves9[MAX_CURVE9][9];
|
||||
CustomSwData customSw[NUM_CSW];
|
||||
SafetySwData safetySw[NUM_CHNOUT];
|
||||
FuncSwData funcSw[NUM_FSW];
|
||||
SwashRingData swashR;
|
||||
PhaseData phaseData[MAX_PHASES];
|
||||
#define SUBTRIM_MAX (1024-TRIM_MAX)
|
||||
#define SUBTRIM_MIN (-SUBTRIM_MAX)
|
||||
int16_t subtrim[NUM_STICKS];
|
||||
FrSkyData frsky;
|
||||
} __attribute__((packed)) ModelData;
|
||||
|
||||
extern EEGeneral g_eeGeneral;
|
||||
extern ModelData g_model;
|
||||
|
||||
#define TOTAL_EEPROM_USAGE (sizeof(ModelData)*MAX_MODELS + sizeof(EEGeneral))
|
||||
|
||||
#endif
|
||||
/*eof*/
|
411
src/pers.cpp
Normal file
411
src/pers.cpp
Normal file
|
@ -0,0 +1,411 @@
|
|||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
*
|
||||
* gruvin9x is based on code named er9x by
|
||||
* Author - Erez Raviv <erezraviv@gmail.com>, which is in turn
|
||||
* was based on 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef TRANSLATIONS
|
||||
#include "eeprom_v4.h"
|
||||
#include "eeprom_v3.h"
|
||||
#endif
|
||||
|
||||
#include "gruvin9x.h"
|
||||
#include "templates.h"
|
||||
|
||||
RlcFile theFile; //used for any file operation
|
||||
|
||||
#define FILE_TYP_GENERAL 1
|
||||
#define FILE_TYP_MODEL 2
|
||||
|
||||
void generalDefault()
|
||||
{
|
||||
memset(&g_eeGeneral,0,sizeof(g_eeGeneral));
|
||||
g_eeGeneral.myVers = EEPROM_VER;
|
||||
g_eeGeneral.currModel= 0;
|
||||
g_eeGeneral.contrast = 25;
|
||||
g_eeGeneral.vBatWarn = 90;
|
||||
#ifdef DEFAULTMODE1
|
||||
g_eeGeneral.stickMode= 0; // default to mode 1
|
||||
#else
|
||||
g_eeGeneral.stickMode= 2; // default to mode 2
|
||||
#endif
|
||||
for (int i = 0; i < 7; ++i) {
|
||||
g_eeGeneral.calibMid[i] = 0x200;
|
||||
g_eeGeneral.calibSpanNeg[i] = 0x180;
|
||||
g_eeGeneral.calibSpanPos[i] = 0x180;
|
||||
}
|
||||
int16_t sum=0;
|
||||
for(int i=0; i<12;i++) sum+=g_eeGeneral.calibMid[i];
|
||||
g_eeGeneral.chkSum = sum;
|
||||
}
|
||||
|
||||
#ifdef TRANSLATIONS
|
||||
uint8_t Translate()
|
||||
{
|
||||
if (g_eeGeneral.myVers == EEPROM_VER_r584 || g_eeGeneral.myVers == EEPROM_ER9X_VER) {
|
||||
alert(g_eeGeneral.myVers == EEPROM_VER_r584 ? PSTR("EEprom Data v3") : PSTR("EEprom Data Er9x v4"), true);
|
||||
message(PSTR("EEPROM Converting"));
|
||||
theFile.readRlc1((uint8_t*)&g_eeGeneral, sizeof(g_eeGeneral));
|
||||
memset(&g_eeGeneral.frskyRssiAlarms, 0 , sizeof(g_eeGeneral.frskyRssiAlarms));
|
||||
if (g_eeGeneral.myVers == EEPROM_VER_r584) {
|
||||
// previous version had only 6 custom switches, OFF and ON values have to be shifted 6
|
||||
if (g_eeGeneral.lightSw == MAX_SWITCH-6)
|
||||
g_eeGeneral.lightSw += 6;
|
||||
if (g_eeGeneral.lightSw == -MAX_SWITCH+6)
|
||||
g_eeGeneral.lightSw -= 6;
|
||||
}
|
||||
g_eeGeneral.view = 0; // will not translate the view index
|
||||
EEPROM_V3::EEGeneral *old = (EEPROM_V3::EEGeneral *)&g_eeGeneral;
|
||||
g_eeGeneral.disableMemoryWarning = old->disableMemoryWarning;
|
||||
g_eeGeneral.switchWarning = old->disableSwitchWarning ? 0 : -1;
|
||||
for (uint8_t i=0; i<4; i++) {
|
||||
g_eeGeneral.trainer.mix[i].srcChn = old->trainer.mix[i].srcChn;
|
||||
g_eeGeneral.trainer.mix[i].mode = old->trainer.mix[i].mode;
|
||||
g_eeGeneral.trainer.mix[i].studWeight = old->trainer.mix[i].studWeight * 13 / 4;
|
||||
}
|
||||
for (uint8_t id=0; id<MAX_MODELS; id++) {
|
||||
theFile.openRlc(FILE_MODEL(id));
|
||||
uint16_t sz = theFile.readRlc1((uint8_t*)&g_model, sizeof(EEPROM_V4::ModelData));
|
||||
if(sz > 0) {
|
||||
EEPROM_V4::ModelData *v4 = (EEPROM_V4::ModelData *)&g_model;
|
||||
EEPROM_V3::ModelData *v3 = (EEPROM_V3::ModelData *)&g_model;
|
||||
SwashRingData swashR;
|
||||
swashR.invertELE = v4->swashInvertELE;
|
||||
swashR.invertAIL = v4->swashInvertAIL;
|
||||
swashR.invertCOL = v4->swashInvertCOL;
|
||||
swashR.type = v4->swashType;
|
||||
swashR.collectiveSource = v4->swashCollectiveSource;
|
||||
swashR.value = v4->swashRingValue;
|
||||
int8_t trims[4];
|
||||
memcpy(&trims[0], &v3->trim[0], 4);
|
||||
int8_t trimSw = v3->trimSw;
|
||||
for (uint8_t i=0; i<10; i++)
|
||||
g_model.name[i] = char2idx(g_model.name[i]);
|
||||
g_model.timer1.mode = v3->tmrMode;
|
||||
g_model.timer1.val = v3->tmrVal;
|
||||
g_model.timer1.persistent = 0;
|
||||
g_model.timer1.dir = v3->tmrDir;
|
||||
g_model.protocol = v3->protocol;
|
||||
g_model.ppmNCH = v3->ppmNCH;
|
||||
g_model.thrTrim = v3->thrTrim;
|
||||
g_model.thrExpo = v3->thrExpo;
|
||||
g_model.trimInc = v3->trimInc;
|
||||
g_model.spare1 = 0;
|
||||
g_model.pulsePol = v3->pulsePol;
|
||||
if (g_eeGeneral.myVers == EEPROM_ER9X_VER) {
|
||||
g_model.extendedLimits = v4->extendedLimits;
|
||||
}
|
||||
else {
|
||||
g_model.extendedLimits = 0;
|
||||
}
|
||||
g_model.extendedTrims = 0;
|
||||
g_model.spare2 = 0;
|
||||
g_model.ppmDelay = v3->ppmDelay;
|
||||
g_model.beepANACenter = v3->beepANACenter;
|
||||
g_model.timer2.mode = 0;
|
||||
g_model.timer2.val = 0;
|
||||
g_model.timer2.persistent = 0;
|
||||
g_model.timer2.dir = 0;
|
||||
for (uint8_t i=0; i<MAX_MIXERS; i++) {
|
||||
memmove(&g_model.mixData[i], &v3->mixData[i], sizeof(MixData)); // MixData size changed!
|
||||
g_model.mixData[i].mixWarn = g_model.mixData[i].phase;
|
||||
g_model.mixData[i].phase = 0;
|
||||
}
|
||||
assert((char *)&g_model.limitData[0] < (char *)&v3->limitData[0]);
|
||||
memmove(&g_model.limitData[0], &v3->limitData[0], sizeof(LimitData)*NUM_CHNOUT);
|
||||
assert((char *)&g_model.expoData[0] < (char *)v3->expoData);
|
||||
EEPROM_V4::ExpoData expo4[4];
|
||||
memcpy(&expo4[0], &v4->expoData[0], sizeof(expo4));
|
||||
memset(&g_model.expoData[0], 0, sizeof(expo4));
|
||||
uint8_t e = 0;
|
||||
for (uint8_t ch=0; ch<4 && e<MAX_EXPOS; ch++) {
|
||||
for (int8_t dr=2; dr>=0 && e<MAX_EXPOS; dr--) {
|
||||
if ((dr==2 && !expo4[ch].drSw1) ||
|
||||
(dr==1 && !expo4[ch].drSw2) ||
|
||||
(dr==0 && !expo4[ch].expo[0][0][0] && !expo4[ch].expo[0][0][1] && !expo4[ch].expo[0][1][0] && !expo4[ch].expo[2][1][1])) continue;
|
||||
g_model.expoData[e].swtch = (dr == 0 ? expo4[ch].drSw1 : (dr == 1 ? expo4[ch].drSw2 : 0));
|
||||
g_model.expoData[e].chn = ch;
|
||||
g_model.expoData[e].expo = expo4[ch].expo[dr][0][0];
|
||||
g_model.expoData[e].weight = 100 + expo4[ch].expo[dr][1][0];
|
||||
if (expo4[ch].expo[dr][0][0] == expo4[ch].expo[dr][0][1] && expo4[ch].expo[dr][1][0] == expo4[ch].expo[dr][1][1]) {
|
||||
g_model.expoData[e++].mode = 3;
|
||||
}
|
||||
else {
|
||||
g_model.expoData[e].mode = 1;
|
||||
if (e < MAX_EXPOS-1) {
|
||||
g_model.expoData[e+1].swtch = g_model.expoData[e].swtch;
|
||||
g_model.expoData[++e].chn = ch;
|
||||
g_model.expoData[e].mode = 2;
|
||||
g_model.expoData[e].expo = expo4[ch].expo[dr][0][1];
|
||||
g_model.expoData[e++].weight = 100 + expo4[ch].expo[dr][1][1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
assert((char *)&g_model.curves5[0][0] < (char *)&v3->curves5[0][0]);
|
||||
memmove(&g_model.curves5[0][0], &v3->curves5[0][0], 5*MAX_CURVE5);
|
||||
assert((char *)&g_model.curves9[0][0] < (char *)&v3->curves9[0][0]);
|
||||
memmove(&g_model.curves9[0][0], &v3->curves9[0][0], 9*MAX_CURVE9);
|
||||
if (g_eeGeneral.myVers == EEPROM_VER_r584) {
|
||||
memmove(&g_model.customSw[0], &v3->customSw[0], sizeof(CustomSwData)*6);
|
||||
memset(&g_model.customSw[6], 0, sizeof(CustomSwData)*6);
|
||||
memset(&g_model.safetySw[0], 0, sizeof(SafetySwData)*NUM_CHNOUT + sizeof(SwashRingData) + sizeof(FrSkyData));
|
||||
}
|
||||
else {
|
||||
assert((char *)&g_model.customSw[0] < (char *)&v4->customSw[0]);
|
||||
memmove(&g_model.customSw[0], &v4->customSw[0], sizeof(CustomSwData)*12);
|
||||
assert((char *)&g_model.safetySw[0] < (char *)&v4->safetySw[0]);
|
||||
memmove(&g_model.safetySw[0], &v4->safetySw[0], sizeof(SafetySwData)*NUM_CHNOUT);
|
||||
memcpy(&g_model.swashR, &swashR, sizeof(SwashRingData));
|
||||
for (uint8_t i=0; i<2; i++) {
|
||||
// TODO this conversion is bad
|
||||
// assert(&g_model.frsky.channels[i].ratio < &v4->frsky.channels[i].ratio);
|
||||
g_model.frsky.channels[i].ratio = v4->frsky.channels[i].ratio;
|
||||
g_model.frsky.channels[i].type = v4->frsky.channels[i].type;
|
||||
g_model.frsky.channels[i].offset = 0;
|
||||
g_model.frsky.channels[i].alarms_value[0] = v4->frsky.channels[i].alarms_value[0];
|
||||
g_model.frsky.channels[i].alarms_value[1] = v4->frsky.channels[i].alarms_value[1];
|
||||
g_model.frsky.channels[i].alarms_level = v4->frsky.channels[i].alarms_level;
|
||||
g_model.frsky.channels[i].alarms_greater = v4->frsky.channels[i].alarms_greater;
|
||||
g_model.frsky.channels[i].barMin = 0;
|
||||
g_model.frsky.channels[i].barMax = 0;
|
||||
}
|
||||
}
|
||||
memset(&g_model.phaseData[0], 0, sizeof(g_model.phaseData) + sizeof(g_model.subtrim));
|
||||
memset(&g_model.funcSw[0], 0, sizeof(g_model.funcSw));
|
||||
if (trimSw) {
|
||||
g_model.funcSw[0].swtch = trimSw;
|
||||
g_model.funcSw[0].func = FUNC_INSTANT_TRIM;
|
||||
g_model.funcSw[1].swtch = trimSw;
|
||||
g_model.funcSw[1].func = FUNC_TRIMS_2_OFS;
|
||||
}
|
||||
memcpy(&g_model.phaseData[0].trim[0], &trims[0], 4);
|
||||
theFile.writeRlc(FILE_MODEL(id), FILE_TYP_MODEL, (uint8_t*)&g_model, sizeof(g_model), true);
|
||||
}
|
||||
}
|
||||
g_eeGeneral.myVers = EEPROM_VER;
|
||||
theFile.writeRlc(FILE_GENERAL, FILE_TYP_GENERAL, (uint8_t*)&g_eeGeneral, sizeof(EEGeneral), true);
|
||||
return sizeof(EEGeneral);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool eeLoadGeneral()
|
||||
{
|
||||
theFile.openRlc(FILE_GENERAL);
|
||||
uint8_t sz = 0;
|
||||
|
||||
if (theFile.readRlc((uint8_t*)&g_eeGeneral, 1) == 1) {
|
||||
theFile.openRlc(FILE_GENERAL);
|
||||
if (g_eeGeneral.myVers == EEPROM_VER) {
|
||||
sz = theFile.readRlc((uint8_t*)&g_eeGeneral, sizeof(g_eeGeneral));
|
||||
}
|
||||
#ifdef TRANSLATIONS
|
||||
else {
|
||||
sz = Translate();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (sz == sizeof(EEGeneral)) {
|
||||
uint16_t sum=0;
|
||||
for(int i=0; i<12;i++) sum+=g_eeGeneral.calibMid[i];
|
||||
return g_eeGeneral.chkSum == sum;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void modelDefault(uint8_t id)
|
||||
{
|
||||
memset(&g_model, 0, sizeof(g_model));
|
||||
applyTemplate(0); //default 4 channel template
|
||||
}
|
||||
|
||||
uint16_t eeLoadModelName(uint8_t id, char *name)
|
||||
{
|
||||
memset(name, 0, sizeof(g_model.name));
|
||||
if (id<MAX_MODELS) {
|
||||
theFile.openRlc(FILE_MODEL(id));
|
||||
if (theFile.readRlc((uint8_t*)name, sizeof(g_model.name)) == sizeof(g_model.name)) {
|
||||
return theFile.size();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool eeModelExists(uint8_t id)
|
||||
{
|
||||
return EFile::exists(FILE_MODEL(id));
|
||||
}
|
||||
|
||||
void eeLoadModel(uint8_t id)
|
||||
{
|
||||
if(id<MAX_MODELS)
|
||||
{
|
||||
theFile.openRlc(FILE_MODEL(id));
|
||||
uint16_t sz = theFile.readRlc((uint8_t*)&g_model, sizeof(g_model));
|
||||
|
||||
if (sz != sizeof(ModelData)) {
|
||||
// alert("Error Loading Model");
|
||||
modelDefault(id);
|
||||
}
|
||||
|
||||
resetTimer1();
|
||||
resetTimer2();
|
||||
#ifdef FRSKY
|
||||
resetTelemetry();
|
||||
FRSKY_setModelAlarms();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool eeDuplicateModel(uint8_t id)
|
||||
{
|
||||
uint8_t i;
|
||||
for( i=id+1; i<MAX_MODELS; i++)
|
||||
{
|
||||
if(! EFile::exists(FILE_MODEL(i))) break;
|
||||
}
|
||||
if(i==MAX_MODELS) return false; // no free space in directory left
|
||||
|
||||
EFile theFile2;
|
||||
theFile2.openRd(FILE_MODEL(id));
|
||||
|
||||
#ifdef ASYNC_WRITE
|
||||
theFile.create(FILE_MODEL(i), FILE_TYP_MODEL, true);
|
||||
#else
|
||||
theFile.create(FILE_MODEL(i), FILE_TYP_MODEL, 600);
|
||||
#endif
|
||||
uint8_t buf[15];
|
||||
uint8_t len;
|
||||
while((len=theFile2.read(buf, 15)))
|
||||
{
|
||||
theFile.write(buf, len);
|
||||
wdt_reset(); // TODO I don't know what it is
|
||||
if (errno() != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
theFile.close();
|
||||
return true;
|
||||
}
|
||||
void eeReadAll()
|
||||
{
|
||||
if(!EeFsOpen() ||
|
||||
EeFsck() < 0 ||
|
||||
!eeLoadGeneral()
|
||||
)
|
||||
{
|
||||
alert(PSTR("Bad EEprom Data"), true);
|
||||
message(PSTR("EEPROM Formatting"));
|
||||
EeFsFormat();
|
||||
//alert(PSTR("format ok"));
|
||||
generalDefault();
|
||||
//alert(PSTR("default ok"));
|
||||
|
||||
#ifdef ASYNC_WRITE
|
||||
theFile.writeRlc(FILE_GENERAL, FILE_TYP_GENERAL,(uint8_t*)&g_eeGeneral,sizeof(EEGeneral), true);
|
||||
#else
|
||||
uint16_t sz = theFile.writeRlc(FILE_GENERAL,FILE_TYP_GENERAL,(uint8_t*)&g_eeGeneral,sizeof(EEGeneral), 200);
|
||||
if(sz!=sizeof(EEGeneral)) alert(PSTR("genwrite error"));
|
||||
#endif
|
||||
|
||||
modelDefault(0);
|
||||
//alert(PSTR("modef ok"));
|
||||
#ifdef ASYNC_WRITE
|
||||
theFile.writeRlc(FILE_MODEL(0), FILE_TYP_MODEL, (uint8_t*)&g_model, sizeof(g_model), true);
|
||||
#else
|
||||
theFile.writeRlc(FILE_MODEL(0), FILE_TYP_MODEL, (uint8_t*)&g_model, sizeof(g_model),200);
|
||||
#endif
|
||||
//alert(PSTR("modwrite ok"));
|
||||
}
|
||||
|
||||
eeLoadModel(g_eeGeneral.currModel);
|
||||
}
|
||||
|
||||
|
||||
uint8_t s_eeDirtyMsk;
|
||||
#ifndef ASYNC_WRITE
|
||||
static uint16_t s_eeDirtyTime10ms;
|
||||
#define WRITE_DELAY_10MS 100
|
||||
#endif
|
||||
void eeDirty(uint8_t msk)
|
||||
{
|
||||
s_eeDirtyMsk |= msk;
|
||||
#ifndef ASYNC_WRITE
|
||||
if (msk)
|
||||
s_eeDirtyTime10ms = get_tmr10ms();
|
||||
#endif
|
||||
}
|
||||
|
||||
void eeCheck(bool immediately)
|
||||
{
|
||||
#ifdef ASYNC_WRITE
|
||||
if (immediately) {
|
||||
theFile.flush();
|
||||
}
|
||||
if (s_eeDirtyMsk & EE_GENERAL) {
|
||||
s_eeDirtyMsk -= EE_GENERAL;
|
||||
theFile.writeRlc(FILE_GENERAL, FILE_TYP_GENERAL, (uint8_t*)&g_eeGeneral, sizeof(EEGeneral), immediately);
|
||||
if (!immediately) return;
|
||||
}
|
||||
if (s_eeDirtyMsk & EE_MODEL) {
|
||||
s_eeDirtyMsk = 0;
|
||||
theFile.writeRlc(FILE_MODEL(g_eeGeneral.currModel), FILE_TYP_MODEL, (uint8_t*)&g_model, sizeof(g_model), immediately);
|
||||
}
|
||||
#else
|
||||
uint8_t msk = s_eeDirtyMsk;
|
||||
if (!msk) return;
|
||||
if( !immediately && ((get_tmr10ms() - s_eeDirtyTime10ms) < WRITE_DELAY_10MS)) return;
|
||||
s_eeDirtyMsk = 0;
|
||||
|
||||
if(msk & EE_GENERAL){
|
||||
if(theFile.writeRlc(FILE_TMP, FILE_TYP_GENERAL, (uint8_t*)&g_eeGeneral,
|
||||
sizeof(EEGeneral),20) == sizeof(EEGeneral))
|
||||
{
|
||||
EFile::swap(FILE_GENERAL,FILE_TMP);
|
||||
}else{
|
||||
if(errno()==ERR_TMO){
|
||||
s_eeDirtyMsk |= EE_GENERAL; //try again
|
||||
s_eeDirtyTime10ms = get_tmr10ms() - WRITE_DELAY_10MS;
|
||||
}else{
|
||||
alert(PSTR("EEPROM overflow"));
|
||||
}
|
||||
}
|
||||
//first finish GENERAL, then MODEL !!avoid Toggle effect
|
||||
}
|
||||
if(msk & EE_MODEL){
|
||||
if(theFile.writeRlc(FILE_TMP, FILE_TYP_MODEL, (uint8_t*)&g_model,
|
||||
sizeof(g_model),20) == sizeof(g_model))
|
||||
{
|
||||
EFile::swap(FILE_MODEL(g_eeGeneral.currModel),FILE_TMP);
|
||||
}else{
|
||||
if(errno()==ERR_TMO){
|
||||
s_eeDirtyMsk |= EE_MODEL; //try again
|
||||
s_eeDirtyTime10ms = get_tmr10ms() - WRITE_DELAY_10MS;
|
||||
}else{
|
||||
alert(PSTR("EEPROM overflow"));
|
||||
}
|
||||
}
|
||||
}
|
||||
//beepWarn1();
|
||||
#endif
|
||||
}
|
259
src/rtc.cpp
Normal file
259
src/rtc.cpp
Normal file
|
@ -0,0 +1,259 @@
|
|||
/*--------------------------------------------------------------------------*/
|
||||
/* RTC controls */
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <string.h>
|
||||
#include "rtc.h"
|
||||
|
||||
|
||||
|
||||
#define SCL_LOW() DDRB |= 0x20 /* SCL = LOW */
|
||||
#define SCL_HIGH() DDRB &= ~0x20 /* SCL = High-Z */
|
||||
#define SCL_VAL ((PINB & 0x20) ? 1 : 0) /* SCL input level */
|
||||
#define SDA_LOW() DDRB |= 0x40 /* SDA = LOW */
|
||||
#define SDA_HIGH() DDRB &= ~0x40 /* SDA = High-Z */
|
||||
#define SDA_VAL ((PINB & 0x40) ? 1 : 0) /* SDA input level */
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------*/
|
||||
/* I2C bus protocol */
|
||||
|
||||
|
||||
static
|
||||
void iic_delay (void)
|
||||
{
|
||||
int n;
|
||||
|
||||
for (n = 4; n; n--) PINB;
|
||||
}
|
||||
|
||||
|
||||
/* Generate start condition on the IIC bus */
|
||||
static
|
||||
void iic_start (void)
|
||||
{
|
||||
SDA_HIGH();
|
||||
iic_delay();
|
||||
SCL_HIGH();
|
||||
iic_delay();
|
||||
SDA_LOW();
|
||||
iic_delay();
|
||||
SCL_LOW();
|
||||
iic_delay();
|
||||
}
|
||||
|
||||
|
||||
/* Generate stop condition on the IIC bus */
|
||||
static
|
||||
void iic_stop (void)
|
||||
{
|
||||
SDA_LOW();
|
||||
iic_delay();
|
||||
SCL_HIGH();
|
||||
iic_delay();
|
||||
SDA_HIGH();
|
||||
iic_delay();
|
||||
}
|
||||
|
||||
|
||||
/* Send a byte to the IIC bus */
|
||||
static
|
||||
int iic_send (BYTE dat)
|
||||
{
|
||||
BYTE b = 0x80;
|
||||
int ack;
|
||||
|
||||
|
||||
do {
|
||||
if (dat & b) { /* SDA = Z/L */
|
||||
SDA_HIGH();
|
||||
} else {
|
||||
SDA_LOW();
|
||||
}
|
||||
iic_delay();
|
||||
SCL_HIGH();
|
||||
iic_delay();
|
||||
SCL_LOW();
|
||||
iic_delay();
|
||||
} while (b >>= 1);
|
||||
SDA_HIGH();
|
||||
iic_delay();
|
||||
SCL_HIGH();
|
||||
ack = SDA_VAL ? 0 : 1; /* Sample ACK */
|
||||
iic_delay();
|
||||
SCL_LOW();
|
||||
iic_delay();
|
||||
return ack;
|
||||
}
|
||||
|
||||
|
||||
/* Receive a byte from the IIC bus */
|
||||
static
|
||||
BYTE iic_rcvr (int ack)
|
||||
{
|
||||
UINT d = 1;
|
||||
|
||||
|
||||
do {
|
||||
d <<= 1;
|
||||
SCL_HIGH();
|
||||
if (SDA_VAL) d++;
|
||||
iic_delay();
|
||||
SCL_LOW();
|
||||
iic_delay();
|
||||
} while (d < 0x100);
|
||||
if (ack) { /* SDA = ACK */
|
||||
SDA_LOW();
|
||||
} else {
|
||||
SDA_HIGH();
|
||||
}
|
||||
iic_delay();
|
||||
SCL_HIGH();
|
||||
iic_delay();
|
||||
SCL_LOW();
|
||||
SDA_HIGH();
|
||||
iic_delay();
|
||||
|
||||
return (BYTE)d;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------*/
|
||||
/* I2C block read/write controls */
|
||||
|
||||
|
||||
int iic_read (
|
||||
BYTE dev, /* Device address */
|
||||
UINT adr, /* Read start address */
|
||||
UINT cnt, /* Read byte count */
|
||||
BYTE *buff /* Read data buffer */
|
||||
)
|
||||
{
|
||||
BYTE *rbuff = buff;
|
||||
int n;
|
||||
|
||||
|
||||
if (!cnt) return 0;
|
||||
|
||||
n = 10;
|
||||
do { /* Select device */
|
||||
iic_start();
|
||||
} while (!iic_send(dev) && --n);
|
||||
if (n) {
|
||||
if (iic_send((BYTE)adr)) { /* Set start address */
|
||||
iic_start(); /* Reselect device in read mode */
|
||||
if (iic_send(dev | 1)) {
|
||||
do { /* Receive data */
|
||||
cnt--;
|
||||
*rbuff++ = iic_rcvr(cnt ? 1 : 0);
|
||||
} while (cnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iic_stop(); /* Deselect device */
|
||||
|
||||
return cnt ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int iic_write (
|
||||
BYTE dev, /* Device address */
|
||||
UINT adr, /* Write start address */
|
||||
UINT cnt, /* Write byte count */
|
||||
const BYTE *buff /* Data to be written */
|
||||
)
|
||||
{
|
||||
const BYTE *wbuff = buff;
|
||||
int n;
|
||||
|
||||
|
||||
if (!cnt) return 0;
|
||||
|
||||
n = 10;
|
||||
do { /* Select device */
|
||||
iic_start();
|
||||
} while (!iic_send(dev) && --n);
|
||||
if (n) {
|
||||
if (iic_send((BYTE)adr)) { /* Set start address */
|
||||
do { /* Send data */
|
||||
if (!iic_send(*wbuff++)) break;
|
||||
} while (--cnt);
|
||||
}
|
||||
}
|
||||
|
||||
iic_stop(); /* Deselect device */
|
||||
|
||||
return cnt ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------*/
|
||||
/* RTC functions */
|
||||
|
||||
|
||||
int rtc_gettime (RTC *rtc)
|
||||
{
|
||||
BYTE buf[8];
|
||||
|
||||
|
||||
if (!iic_read(0xD0, 0, 7, buf)) return 0;
|
||||
|
||||
rtc->sec = (buf[0] & 0x0F) + ((buf[0] >> 4) & 7) * 10;
|
||||
rtc->min = (buf[1] & 0x0F) + (buf[1] >> 4) * 10;
|
||||
rtc->hour = (buf[2] & 0x0F) + ((buf[2] >> 4) & 3) * 10;
|
||||
rtc->wday = (buf[2] & 0x07);
|
||||
rtc->mday = (buf[4] & 0x0F) + ((buf[4] >> 4) & 3) * 10;
|
||||
rtc->month = (buf[5] & 0x0F) + ((buf[5] >> 4) & 1) * 10;
|
||||
rtc->year = 2000 + (buf[6] & 0x0F) + (buf[6] >> 4) * 10;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int rtc_settime (const RTC *rtc)
|
||||
{
|
||||
|
||||
BYTE buf[8];
|
||||
|
||||
|
||||
buf[0] = rtc->sec / 10 * 16 + rtc->sec % 10;
|
||||
buf[1] = rtc->min / 10 * 16 + rtc->min % 10;
|
||||
buf[2] = rtc->hour / 10 * 16 + rtc->hour % 10;
|
||||
buf[3] = rtc->wday & 7;
|
||||
buf[4] = rtc->mday / 10 * 16 + rtc->mday % 10;
|
||||
buf[5] = rtc->month / 10 * 16 + rtc->month % 10;
|
||||
buf[6] = (rtc->year - 2000) / 10 * 16 + (rtc->year - 2000) % 10;
|
||||
return iic_write(0xD0, 0, 7, buf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int rtc_init (void)
|
||||
{
|
||||
BYTE buf[8]; /* RTC R/W buffer */
|
||||
UINT adr;
|
||||
|
||||
|
||||
/* Read RTC registers */
|
||||
if (!iic_read(0xD0, 0, 8, buf)) return 0; /* IIC error */
|
||||
|
||||
if (buf[7] & 0x20) { /* When data has been volatiled, set default time */
|
||||
/* Clear nv-ram. Reg[8..63] */
|
||||
memset(buf, 0, 8);
|
||||
for (adr = 8; adr < 64; adr += 8)
|
||||
iic_write(0x0D, adr, 8, buf);
|
||||
/* Reset time to Jan 1, '08. Reg[0..7] */
|
||||
buf[4] = 1; buf[5] = 1; buf[6] = 8;
|
||||
iic_write(0x0D, 0, 8, buf);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
23
src/rtc.h
Normal file
23
src/rtc.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#ifndef RTC_H
|
||||
#define RTC_H
|
||||
|
||||
#include "integer.h"
|
||||
|
||||
typedef struct {
|
||||
WORD year; /* 2000..2099 */
|
||||
BYTE month; /* 1..12 */
|
||||
BYTE mday; /* 1.. 31 */
|
||||
BYTE wday; /* 1..7 */
|
||||
BYTE hour; /* 0..23 */
|
||||
BYTE min; /* 0..59 */
|
||||
BYTE sec; /* 0..59 */
|
||||
} RTC;
|
||||
|
||||
int iic_write (BYTE, UINT, UINT, const void*); /* Write to IIC device */
|
||||
int iic_read (BYTE, UINT, UINT, void*); /* Read from IIC device */
|
||||
|
||||
int rtc_init (void); /* Initialize RTC */
|
||||
int rtc_gettime (RTC*); /* Get time */
|
||||
int rtc_settime (const RTC*); /* Set time */
|
||||
|
||||
#endif
|
11
src/s9xsplash.lbm
Normal file
11
src/s9xsplash.lbm
Normal file
|
@ -0,0 +1,11 @@
|
|||
prog_uchar APM s9xsplash[] = {
|
||||
128,64,1024,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x08,0x04,0x04,0x84,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0xc4,0x04,0x04,0x88,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xbf,0x80,0x80,0x80,0xbf,0x80,0x80,0x80,0x80,0x00,0x00,0x30,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x88,0x09,0x09,0x08,0xf0,0x00,0x00,0x00,0x01,0x01,0x01,0x7f,0x01,0x01,0x01,0x01,0x00,0x00,0x7f,0x49,0x49,0x49,0x49,0x41,0x41,0x40,0x00,0x7f,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x7f,0x49,0x49,0x49,0x49,0x41,0x41,0x40,0x00,0x7f,0x01,0x06,0x0c,0x10,0x10,0x0c,0x06,0x01,0x7f,0x00,0x00,0x7f,0x49,0x49,0x49,0x49,0x41,0x41,0x40,0x01,0x01,0x01,0x7f,0x01,0x01,0x01,0x01,0x00,0x00,0x7f,0x09,0x09,0x09,0x09,0x19,0x29,0x4e,0x00,0x01,0x03,0x06,0x0c,0x78,0x0c,0x06,0x03,0x01,0x00,0x00,
|
||||
0x00,0x00,0xf8,0xfe,0xff,0xff,0xff,0x0f,0x07,0x07,0x07,0x07,0x07,0x07,0x37,0x47,0x87,0x87,0x87,0x97,0x97,0x07,0x5f,0xdf,0xdf,0xdf,0xde,0xd8,0x80,0x10,0x10,0x10,0x10,0x10,0x0f,0x00,0x80,0x40,0x3f,0x80,0xc0,0xe0,0xe0,0xe0,0x60,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0xd0,0x90,0x90,0x90,0x90,0x90,0x00,0x00,0x00,0xf0,0x90,0x90,0x90,0x90,0x10,0x10,0x00,0x00,0xf0,0x90,0x90,0x90,0x90,0x90,0x90,0xe0,0x00,0x00,0xf0,0x00,0x00,0x00,0xf0,0x90,0x90,0x90,0x90,0x10,0x10,0x00,0x60,0xd0,0x90,0x90,0x90,0x90,0x90,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x01,0x07,0x07,0x0f,0x0f,0x0f,0x0e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x0e,0x0e,0x0e,0x0e,0x0e,0x8e,0xce,0xee,0xfc,0xf9,0x73,0x27,0x0f,0x1f,0x3f,0x7e,0xfc,0xf9,0xf1,0xf1,0xf9,0xfc,0x3e,0x1f,0x0f,0x07,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x06,0x04,0x04,0x04,0x04,0x04,0x03,0x00,0x00,0x07,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,0x07,0x00,0x00,0x00,0x00,0x01,0x02,0x04,0x00,0x00,0x07,0x00,0x00,0x00,0x07,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x02,0x06,0x04,0x04,0x04,0x04,0x04,0x03,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1e,0x1e,0x1e,0x0e,0x0e,0x0f,0x07,0x07,0x03,0x03,0x01,0x80,0xc0,0xe0,0xf0,0xf8,0x7c,0x3e,0x1f,0x0f,0x07,0x07,0x0f,0x1f,0x3f,0x7e,0xfc,0xf8,0xf0,0xe0,0xc0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7e,0x4a,0x4a,0x4a,0x4a,0x4a,0x7c,0x00,0x02,0x06,0x0c,0x70,0x08,0x04,0x02,0x02,0x00,0x00,0x00,0x00,0x1c,0x22,0x41,0x41,0x49,0x49,0x49,0x3a,0x18,0x00,0x00,0x7e,0x12,0x12,0x12,0x12,0x32,0x4c,0x00,0x00,0x3e,0x40,0x40,0x40,0x40,0x40,0x3e,0x00,0x02,0x0c,0x18,0x60,0x60,0x30,0x0c,0x02,0x00,0x7e,0x00,0x00,0x7e,0x02,0x0c,0x18,0x30,0x40,0x7e,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0xe0,0x10,0x10,0x10,0xe0,0x00,0x00,0xc0,0x80,0x40,0x80,0x00,0x00,0x80,0x40,0x40,0x80,0x00,0x00,0xcc,0x8e,0x4f,0x8f,0x0f,0x07,0x03,0x01,0x00,0x00,0x00,0x60,0x90,0x90,0x10,0x00,0x00,0x00,0x80,0x41,0x43,0x87,0x0f,0x0f,0xcf,0x0e,0x0c,0xc0,0x00,0x00,0xc0,0x80,0x40,0xc0,0x00,0x00,0x80,0x40,0x40,0x40,0x00,0x00,0x80,0x40,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x07,0x08,0x08,0x08,0x07,0x00,0x00,0x3f,0x04,0x08,0x07,0x00,0x00,0x07,0x09,0xc9,0x49,0x40,0x40,0x8f,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x09,0x06,0x00,0x00,0x07,0x08,0x08,0x07,0x00,0x00,0x07,0x08,0x04,0x0f,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x40,0x07,0x08,0x08,0x08,0x00,0x00,0x07,0x09,0x09,0x09,0x00,0x00,0x00,0xc8,0x00,0x00,0x08,0xc0,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x20,0x00,0x00,0x20,0x00,0x00,0x00,0x3f,0x04,0x04,0x04,0x03,0x00,0x00,0x1e,0x21,0x21,0x1e,0x00,0x07,0x38,0x0e,0x0e,0x38,0x07,0x00,0x1e,0x25,0x25,0x26,0x00,0x00,0x3f,0x02,0x01,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x3f,0x00,0x00,0x3f,0x02,0x01,0x3e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x3c,0x03,0x00,0x00,0x00,0x1e,0x21,0x21,0x1e,0x00,0x00,0x1f,0x20,0x10,0x3f,0x00,0x3f,0x02,0x01,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x02,0x02,0x02,0x3f,0x00,0x00,0x19,0x25,0x15,0x1e,0x20,0x00,0x3f,0x02,0x01,0x3e,0x00,0x1e,0x21,0x12,0x3f,0x00,0x00,0x22,0x25,0x29,0x11,0x00
|
||||
};
|
89
src/s9xsplash.xbm
Normal file
89
src/s9xsplash.xbm
Normal file
|
@ -0,0 +1,89 @@
|
|||
#define s9xsplash_width 128
|
||||
#define s9xsplash_height 64
|
||||
static unsigned char s9xsplash_bits[] = {
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,
|
||||
0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x80,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,
|
||||
0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x40,0xf8,0xff,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x40,0x04,0x00,0x24,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x04,0x00,
|
||||
0x18,0xfc,0xf3,0x27,0xe0,0xcf,0xc0,0xfc,0xfd,0xf3,0x67,0x30,
|
||||
0x00,0x40,0x04,0x00,0x00,0x20,0x10,0x20,0x20,0x40,0xa1,0x04,
|
||||
0x20,0x10,0xc8,0x18,0x00,0x40,0x04,0x00,0x00,0x20,0x10,0x20,
|
||||
0x20,0x40,0xb3,0x04,0x20,0x10,0x88,0x0d,0x00,0x40,0x04,0xfc,
|
||||
0x3f,0x20,0xf0,0x21,0xe0,0x43,0x92,0x7c,0x20,0xf0,0x0f,0x07,
|
||||
0x00,0x40,0x04,0x02,0x40,0x20,0x10,0x20,0x20,0x40,0x8c,0x04,
|
||||
0x20,0x10,0x02,0x02,0x00,0x40,0x04,0x02,0x40,0x20,0x10,0x20,
|
||||
0x20,0x40,0x80,0x04,0x20,0x10,0x04,0x02,0x00,0x00,0x00,0xfc,
|
||||
0x43,0x20,0xf0,0xef,0xef,0x5f,0x80,0xfc,0x23,0x10,0x08,0x02,
|
||||
0x80,0xff,0x7f,0x00,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0xf0,0xff,0xff,0x03,0x44,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0x07,
|
||||
0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0xf8,0xff,0xff,0x07,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0xfc,0x00,0xc0,0x0f,0x44,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0x40,0xd8,0xef,
|
||||
0x43,0x00,0x00,0x00,0x00,0xe0,0xc7,0x9f,0x3f,0xe2,0xcf,0x0f,
|
||||
0x7c,0x40,0x00,0x00,0x40,0x3e,0x00,0x00,0x00,0x10,0x40,0x80,
|
||||
0x40,0x22,0x20,0x00,0x7c,0x80,0xc0,0x0f,0x20,0x1f,0x00,0x00,
|
||||
0x00,0x30,0x40,0x80,0x40,0x22,0x60,0x00,0x7c,0x00,0x9f,0x1f,
|
||||
0x90,0x0f,0x00,0x00,0x00,0xe0,0xc7,0x87,0x7f,0xe2,0xc3,0x0f,
|
||||
0xfc,0x00,0x00,0x3f,0xcf,0x07,0x00,0x00,0x00,0x00,0x48,0x80,
|
||||
0x10,0x22,0x00,0x10,0xf8,0xff,0x7f,0x7e,0xe0,0x03,0x00,0x00,
|
||||
0x00,0x30,0x48,0x80,0x20,0x22,0x60,0x10,0xf8,0xff,0xff,0xfc,
|
||||
0xf0,0x01,0x00,0x00,0x00,0xe0,0xc7,0xbf,0x40,0xe2,0xdf,0x0f,
|
||||
0xe0,0xff,0xff,0xf9,0xf9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x7e,0x80,0xf3,0x7f,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xe7,
|
||||
0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0xe0,0xc3,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x81,0x1f,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x80,
|
||||
0x3f,0x00,0x00,0x00,0x00,0x80,0x0f,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0xe0,0x7f,0xc0,0x7f,0x00,0x00,0x7e,0x86,0x41,0x10,0x3f,
|
||||
0x82,0x02,0x65,0x08,0xc0,0xff,0x1f,0xe0,0xff,0x00,0x00,0x82,
|
||||
0x4c,0x20,0x00,0x41,0x82,0x84,0xa4,0x08,0x80,0xff,0x07,0xf0,
|
||||
0xf9,0x01,0x00,0xfe,0x28,0x20,0x3e,0x41,0x82,0x8c,0xa4,0x09,
|
||||
0x00,0xff,0x00,0xf8,0xf0,0x03,0x00,0x82,0x10,0x20,0x30,0x3f,
|
||||
0x82,0x48,0x24,0x0b,0x00,0x00,0x00,0x7c,0xe0,0x07,0x00,0x82,
|
||||
0x10,0x40,0x10,0x21,0x82,0x70,0x24,0x0a,0x00,0x00,0x00,0x3e,
|
||||
0xc0,0x0f,0x00,0xfe,0x10,0x80,0x0f,0x41,0x7c,0x30,0x24,0x0c,
|
||||
0x00,0x00,0x00,0x1f,0x80,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x1f,0x00,0x3f,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x0f,
|
||||
0x00,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0xe0,0x07,0x00,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x03,0x00,0xf8,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x00,
|
||||
0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x44,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x44,0x0a,0xa3,0x00,0x01,0x23,0x69,0x1c,
|
||||
0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x96,0x64,0x01,
|
||||
0x86,0x24,0x59,0x82,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x44,0x92,0x27,0x01,0x88,0x24,0x09,0x82,0x07,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x44,0x92,0x20,0x01,0x90,0x24,0x09,0x82,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x96,0x20,0x01,
|
||||
0x90,0xa4,0x09,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x38,0x0a,0x27,0x01,0x0f,0x43,0x09,0x1c,0x47,0x12,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x1e,0x00,0x00,0x00,0x00,0x01,0x40,0x04,0x00,0x00,
|
||||
0x88,0x00,0x00,0x01,0x00,0x00,0x22,0x00,0x00,0x00,0x00,0x00,
|
||||
0x40,0x04,0x00,0x00,0x88,0x00,0x00,0x01,0x00,0x00,0x22,0x26,
|
||||
0x64,0x34,0xc0,0x29,0x80,0xc2,0x48,0x0d,0x88,0x1c,0x45,0x71,
|
||||
0x00,0x00,0x22,0xa9,0x95,0x2c,0x00,0x59,0x80,0x22,0x49,0x0b,
|
||||
0xf8,0x20,0xab,0x09,0x00,0x00,0x1e,0xa9,0xf5,0x04,0x00,0x49,
|
||||
0x00,0x21,0x49,0x01,0x88,0x38,0x29,0x11,0x00,0x00,0x02,0xc9,
|
||||
0x13,0x04,0x00,0x49,0x00,0x21,0x49,0x01,0x88,0x24,0x29,0x21,
|
||||
0x00,0x00,0x02,0x49,0x12,0x04,0x00,0x49,0x00,0x21,0x69,0x01,
|
||||
0x88,0x34,0xa9,0x41,0x80,0x24,0x02,0x46,0xe2,0x04,0x00,0x49,
|
||||
0x00,0xc1,0x50,0x01,0x88,0x48,0x49,0x39,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00};
|
BIN
src/s9xsplash.xcf
Normal file
BIN
src/s9xsplash.xcf
Normal file
Binary file not shown.
104
src/simpgmspace.cpp
Normal file
104
src/simpgmspace.cpp
Normal file
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
*
|
||||
* gruvin9x is based on code named er9x by
|
||||
* Author - Erez Raviv <erezraviv@gmail.com>, which is in turn
|
||||
* was based on 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 <unistd.h>
|
||||
#include <time.h>
|
||||
#include <ctype.h>
|
||||
#include "simpgmspace.h"
|
||||
#include "lcd.h"
|
||||
#include "gruvin9x.h"
|
||||
#include "menus.h"
|
||||
|
||||
volatile unsigned char pinb=0, pinc=0xff, pind, pine=0xff, ping=0xff;
|
||||
unsigned char portb, dummyport;
|
||||
const char *eepromFile = "eeprom.bin";
|
||||
volatile size_t eeprom_buffer_size = 0;
|
||||
|
||||
uint8_t eeprom[EESIZE];
|
||||
|
||||
void eeWriteBlockCmp(const void *i_pointer_ram, void *pointer_eeprom, size_t size)
|
||||
{
|
||||
#if 0
|
||||
printf(" eeWriteBlockCmp(%d %d)", size, (int)pointer_eeprom);
|
||||
for(uint8_t i=0; i<size; i++)
|
||||
printf(" %02X", ((const char*)i_pointer_ram)[i]);
|
||||
printf("\n");fflush(stdout);
|
||||
#endif
|
||||
|
||||
if (eepromFile) {
|
||||
FILE *fp = fopen(eepromFile, "r+");
|
||||
long ofs = (long) pointer_eeprom;
|
||||
const char* pointer_ram= (const char*)i_pointer_ram;
|
||||
//printf("eeWr p=%10p blk%3d ofs=%2d l=%d",pointer_ram,
|
||||
// (int)pointer_eeprom/16,
|
||||
// (int)pointer_eeprom%16,
|
||||
// (int)size);
|
||||
while(size) {
|
||||
if(fseek(fp, ofs , SEEK_SET)==-1) perror("error in seek");
|
||||
char buf[1];
|
||||
if (fread(buf, 1, 1, fp) != 1) perror("error in read");
|
||||
|
||||
if (buf[0] != pointer_ram[0]){
|
||||
//printf("X");
|
||||
g_tmr10ms++;
|
||||
if(fseek(fp, ofs , SEEK_SET)==-1) perror("error in seek");
|
||||
fwrite(pointer_ram, 1, 1,fp);
|
||||
}
|
||||
else{
|
||||
//printf(".");
|
||||
}
|
||||
|
||||
size--;
|
||||
ofs++;
|
||||
(const char*)pointer_ram++;
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
else {
|
||||
memcpy(&eeprom[(int64_t)pointer_eeprom], i_pointer_ram, size);
|
||||
}
|
||||
}
|
||||
|
||||
void eeprom_read_block (void *pointer_ram,
|
||||
const void *pointer_eeprom,
|
||||
size_t size)
|
||||
{
|
||||
if (eepromFile) {
|
||||
FILE *fp=fopen(eepromFile, "r");
|
||||
if(fseek(fp, (long) pointer_eeprom, SEEK_SET)==-1) perror("error in seek");
|
||||
if (fread(pointer_ram, size, 1, fp) <= 0) perror("error in read");
|
||||
fclose(fp);
|
||||
}
|
||||
else {
|
||||
memcpy(pointer_ram, &eeprom[(int)pointer_eeprom], size);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void EeFsDump(){
|
||||
for(int i=0; i<EESIZE; i++)
|
||||
{
|
||||
printf("%02x ",eeprom[i]);
|
||||
if(i%16 == 15) puts("");
|
||||
}
|
||||
puts("");
|
||||
}
|
||||
#endif
|
85
src/simpgmspace.h
Normal file
85
src/simpgmspace.h
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
*
|
||||
* gruvin9x is based on code named er9x by
|
||||
* Author - Erez Raviv <erezraviv@gmail.com>, which is in turn
|
||||
* was based on 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 <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef unsigned char prog_uchar;
|
||||
typedef const char prog_char;
|
||||
typedef const uint16_t prog_uint16_t;
|
||||
typedef const uint8_t prog_uint8_t;
|
||||
typedef const int16_t prog_int16_t;
|
||||
typedef const int8_t prog_int8_t;
|
||||
|
||||
|
||||
|
||||
#define PROGMEM
|
||||
#define pgm_read_byte(address_short) (*(uint8_t*)(address_short))
|
||||
#define pgm_read_word(address_short) (*(uint16_t*)(address_short))
|
||||
#define pgm_read_adr(address_short) *address_short
|
||||
#define pgm_read_stringP(adr) ((adr))
|
||||
#define PSTR(adr) adr
|
||||
#define _delay_us(a)
|
||||
#define cli()
|
||||
#define sei()
|
||||
#define strcpy_P strcpy
|
||||
#define memcpy_P memcpy
|
||||
|
||||
#define PORTA dummyport
|
||||
#define PORTB portb
|
||||
#define PORTC dummyport
|
||||
#define PORTD dummyport
|
||||
#define PORTE dummyport
|
||||
#define PORTF dummyport
|
||||
#define PORTG dummyport
|
||||
#define DDRA dummyport
|
||||
#define DDRB dummyport
|
||||
#define DDRC dummyport
|
||||
#define DDRD dummyport
|
||||
#define DDRE dummyport
|
||||
#define DDRF dummyport
|
||||
#define DDRG dummyport
|
||||
#define PINB ~pinb
|
||||
#define PINC ~pinc
|
||||
#define PIND ~pind
|
||||
#define PINE ~pine
|
||||
#define PING ~ping
|
||||
#define EEMEM
|
||||
|
||||
#define UCSR0B dummyport
|
||||
#define UDRIE0 dummyport
|
||||
#define TXEN0 dummyport
|
||||
#define RXEN0 dummyport
|
||||
#define DDE0 dummyport
|
||||
#define PORTE0 dummyport
|
||||
#define RXCIE0 dummyport
|
||||
|
||||
extern volatile unsigned char pinb,pinc,pind,pine,ping;
|
||||
extern unsigned char portb,dummyport;
|
||||
|
||||
extern const char *eepromFile;
|
||||
void eeprom_read_block (void *pointer_ram,
|
||||
const void *pointer_eeprom,
|
||||
size_t size);
|
||||
|
||||
#define offsetof(st, m) ((size_t) ( (char *)&((st *)(0))->m - (char *)0 ))
|
||||
#define wdt_reset()
|
442
src/simu.cpp
Normal file
442
src/simu.cpp
Normal file
|
@ -0,0 +1,442 @@
|
|||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
*
|
||||
* gruvin9x is based on code named er9x by
|
||||
* Author - Erez Raviv <erezraviv@gmail.com>, which is in turn
|
||||
* was based on 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 "fx.h"
|
||||
#include "FXExpression.h"
|
||||
#include "FXPNGImage.h"
|
||||
#include <unistd.h>
|
||||
#include "simpgmspace.h"
|
||||
#include "lcd.h"
|
||||
#include "fxkeys.h"
|
||||
#include "gruvin9x.h"
|
||||
#include "menus.h"
|
||||
#include <time.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define W DISPLAY_W
|
||||
#define H DISPLAY_H
|
||||
#define W2 W*2
|
||||
#define H2 H*2
|
||||
|
||||
int g_snapshot_idx = 0;
|
||||
|
||||
class Gruvin9xSim: public FXMainWindow
|
||||
{
|
||||
FXDECLARE(Gruvin9xSim)
|
||||
public:
|
||||
Gruvin9xSim(){};
|
||||
Gruvin9xSim(FXApp* a);
|
||||
long onKeypress(FXObject*,FXSelector,void*);
|
||||
long onArrowPress(FXObject*,FXSelector,void*);
|
||||
long onChore(FXObject*,FXSelector,void*);
|
||||
long onTimeout(FXObject*,FXSelector,void*);
|
||||
void makeSnapshot(const FXDrawable* drawable);
|
||||
void doEvents();
|
||||
void refreshDiplay();
|
||||
private:
|
||||
|
||||
|
||||
FX::FXuchar buf2[W2*H2/8];
|
||||
FXBitmap *bmp;
|
||||
FXBitmapFrame *bmf;
|
||||
bool firstTime;
|
||||
|
||||
public:
|
||||
FXSlider *sliders[8];
|
||||
FXKnob *knobs[8];
|
||||
FXKnob *knobsppm[8];
|
||||
FXArrowButton *arrow[3];
|
||||
FXArrowButton *arrow2[3];
|
||||
FXToggleButton *togButPpm;
|
||||
};
|
||||
// Message Map
|
||||
FXDEFMAP(Gruvin9xSim) Gruvin9xSimMap[]={
|
||||
|
||||
//________Message_Type_________ID_____________________Message_Handler_______
|
||||
FXMAPFUNC(SEL_CHORE, 1, Gruvin9xSim::onChore),
|
||||
FXMAPFUNC(SEL_TIMEOUT, 2, Gruvin9xSim::onTimeout),
|
||||
FXMAPFUNC(SEL_COMMAND, 1000, Gruvin9xSim::onArrowPress),
|
||||
FXMAPFUNC(SEL_KEYPRESS, 0, Gruvin9xSim::onKeypress),
|
||||
};
|
||||
|
||||
FXIMPLEMENT(Gruvin9xSim,FXMainWindow,Gruvin9xSimMap,ARRAYNUMBER(Gruvin9xSimMap))
|
||||
|
||||
|
||||
Gruvin9xSim::Gruvin9xSim(FXApp* a)
|
||||
:FXMainWindow(a,"Gruvin9xSim",NULL,NULL,DECOR_ALL,20,90,0,0)
|
||||
{
|
||||
|
||||
firstTime=true;
|
||||
for(int i=0; i<(W*H/8); i++) displayBuf[i]=0;//rand();
|
||||
for(int i=0; i<(W2*H2/8); i++) buf2[i]=0;//rand();
|
||||
bmp = new FXBitmap(a,&buf2,BITMAP_KEEP,W2,H2);
|
||||
|
||||
FXHorizontalFrame *hf00=new FXHorizontalFrame(this,LAYOUT_CENTER_X);
|
||||
FXHorizontalFrame *hf01=new FXHorizontalFrame(this,LAYOUT_CENTER_X);
|
||||
FXHorizontalFrame *hf02=new FXHorizontalFrame(this,LAYOUT_CENTER_X);
|
||||
//FXHorizontalFrame *hf2=new FXHorizontalFrame(this,LAYOUT_FILL_X);
|
||||
FXHorizontalFrame *hf10=new FXHorizontalFrame(this,LAYOUT_CENTER_X);
|
||||
FXHorizontalFrame *hf11=new FXHorizontalFrame(this,LAYOUT_CENTER_X);
|
||||
FXHorizontalFrame *hf1=new FXHorizontalFrame(this,LAYOUT_FILL_X);
|
||||
|
||||
//rh lv rv lh
|
||||
for(int i=0; i<4; i++){
|
||||
switch(i)
|
||||
{
|
||||
#define L LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT|LAYOUT_FIX_X|LAYOUT_FIX_Y
|
||||
#undef X0
|
||||
#define X0 10
|
||||
#define Y0 20
|
||||
case 0:
|
||||
sliders[i]=new FXSlider(hf1,NULL,0,L|SLIDER_HORIZONTAL,X0+0,Y0+120,100,20);
|
||||
break;
|
||||
case 1:
|
||||
sliders[i]=new FXSlider(hf1,NULL,0,L|SLIDER_VERTICAL,X0+100,Y0+20,20,100);
|
||||
break;
|
||||
case 2:
|
||||
sliders[i]=new FXSlider(hf1,NULL,0,L|SLIDER_VERTICAL,X0+120,Y0+20,20,100);
|
||||
break;
|
||||
case 3:
|
||||
sliders[i]=new FXSlider(hf1,NULL,0,L|SLIDER_HORIZONTAL,X0+140,Y0+120,100,20);
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
sliders[i]->setRange(0+i*50,1023);
|
||||
sliders[i]->setTickDelta(7);
|
||||
sliders[i]->setValue(i==1 ? 200 : 512+i*25);
|
||||
}
|
||||
arrow[0]= new FXArrowButton(hf10,this,1000,ARROW_LEFT);
|
||||
arrow[1]= new FXArrowButton(hf10,this,1000,ARROW_UP);
|
||||
arrow[2]= new FXArrowButton(hf10,this,1000,ARROW_RIGHT);
|
||||
for(int i=4; i<8; i++){
|
||||
knobs[i]= new FXKnob(hf11,NULL,0,KNOB_TICKS|LAYOUT_LEFT);
|
||||
knobs[i]->setRange(0,1023);
|
||||
knobs[i]->setValue(512);
|
||||
}
|
||||
|
||||
arrow2[0]= new FXArrowButton(hf00,this,1000,ARROW_LEFT);
|
||||
arrow2[1]= new FXArrowButton(hf00,this,1000,ARROW_UP);
|
||||
arrow2[2]= new FXArrowButton(hf00,this,1000,ARROW_RIGHT);
|
||||
togButPpm = new FXToggleButton(hf00,"on", "off", NULL, NULL, NULL, 0, TOGGLEBUTTON_NORMAL);
|
||||
for(int i=0; i<8; i++){
|
||||
knobsppm[i]= new FXKnob(i<4?hf01:hf02,NULL,0,KNOB_TICKS|LAYOUT_LEFT);
|
||||
knobsppm[i]->setRange(1000,2000);
|
||||
knobsppm[i]->setValue(1500+i*20);
|
||||
}
|
||||
|
||||
|
||||
bmf = new FXBitmapFrame(this,bmp,0,0,0,0,0,0,0,0,0);
|
||||
bmf->setOnColor(FXRGB(0,0,0));
|
||||
|
||||
//getApp()->addChore(this,1);
|
||||
getApp()->addTimeout(this,2,100);
|
||||
}
|
||||
|
||||
void Gruvin9xSim::makeSnapshot(const FXDrawable* drawable)
|
||||
{
|
||||
// Construct and create an FXImage object
|
||||
FXPNGImage snapshot(getApp(), NULL, 0, drawable->getWidth(), drawable->getHeight());
|
||||
snapshot.create();
|
||||
|
||||
// Create a window device context and lock it onto the image
|
||||
FXDCWindow dc(&snapshot);
|
||||
|
||||
// Draw from the widget to this
|
||||
dc.drawArea(drawable, 0, 0, drawable->getWidth(), drawable->getHeight(), 0, 0);
|
||||
|
||||
// Release lock
|
||||
dc.end();
|
||||
|
||||
// Grab pixels from server side back to client side
|
||||
snapshot.restore();
|
||||
|
||||
// Save recovered pixels to a file
|
||||
FXFileStream stream;
|
||||
char buf[100];
|
||||
sprintf(buf,"snapshot-%02d.png", ++g_snapshot_idx);
|
||||
for(unsigned i=4; i<strlen(buf); i++)
|
||||
{
|
||||
if(!isalnum(buf[i]) && buf[i]!='.' ) buf[i]='_';
|
||||
}
|
||||
|
||||
if (stream.open(buf, FXStreamSave))
|
||||
//if (stream.open("snapshot.png", FXStreamSave))
|
||||
{
|
||||
snapshot.savePixels(stream);
|
||||
stream.close();
|
||||
printf("Snapshot written: %s\n",buf);
|
||||
}
|
||||
else {
|
||||
printf("Cannot create snapshot %s\n", buf);
|
||||
}
|
||||
}
|
||||
void Gruvin9xSim::doEvents()
|
||||
{
|
||||
//getApp()->addChore(this,1);
|
||||
getApp()->runOneEvent(false);
|
||||
}
|
||||
|
||||
long Gruvin9xSim::onArrowPress(FXObject*sender,FXSelector sel,void*v)
|
||||
{
|
||||
int which,val;
|
||||
if(sender==arrow[0]) { which=1; val=0;}
|
||||
if(sender==arrow[1]) { which=1; val=512;}
|
||||
if(sender==arrow[2]) { which=1; val=1023;}
|
||||
if(sender==arrow2[0]){ which=2; val=1000;}
|
||||
if(sender==arrow2[1]){ which=2; val=1500;}
|
||||
if(sender==arrow2[2]){ which=2; val=2000;}
|
||||
if(which == 1){
|
||||
for(int i=0; i<4; i++) sliders[i]->setValue(val);
|
||||
for(int i=4; i<7; i++) knobs[i]->setValue(val);
|
||||
}
|
||||
if(which == 2){
|
||||
for(int i=0; i<8; i++) knobsppm[i]->setValue(val);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
long Gruvin9xSim::onKeypress(FXObject*,FXSelector,void*v)
|
||||
{
|
||||
FXEvent *evt=(FXEvent*)v;
|
||||
// printf("keypress %x\n", evt->code);
|
||||
if (evt->code=='s'){
|
||||
makeSnapshot(bmf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern uint16_t s_trainerLast10ms;
|
||||
long Gruvin9xSim::onTimeout(FXObject*,FXSelector,void*)
|
||||
{
|
||||
if(togButPpm->getState()){
|
||||
for(int i=0; i<8; i++){
|
||||
g_ppmIns[i]=knobsppm[i]->getValue()-1500;
|
||||
if(g_ppmIns[i]<-400){
|
||||
// TODO BSS g_trainerSlaveActiveChns = i;
|
||||
// TODO BSS s_trainerLast10ms = g_tmr10ms;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
per10ms();
|
||||
getApp()->addChore(this,1);
|
||||
getApp()->addTimeout(this,2,10);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Gruvin9xSim::refreshDiplay()
|
||||
{
|
||||
if(portb & 1<<OUT_B_LIGHT) bmf->setOffColor(FXRGB(150,200,152));
|
||||
else bmf->setOffColor(FXRGB(200,200,200));
|
||||
|
||||
for(int x=0;x<W;x++){
|
||||
for(int y=0;y<H;y++)
|
||||
{
|
||||
int o2 = x/4 + y*W*2*2/8;
|
||||
if( displayBuf[x+(y/8)*W] & (1<<(y%8))) {
|
||||
buf2[o2] |= 3<<(x%4*2);
|
||||
buf2[o2+W2/8] |= 3<<(x%4*2);
|
||||
}
|
||||
else {
|
||||
buf2[o2] &= ~(3<<(x%4*2));
|
||||
buf2[o2+W2/8] &= ~(3<<(x%4*2));
|
||||
//buf2[x2/8+y2*W2/8] &= ~(3<<(x%8));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bmp->setData (buf2,0);
|
||||
bmp->render();
|
||||
bmf->setBitmap( bmp );
|
||||
|
||||
if(hasFocus()) {
|
||||
static FXuint keys1[]={
|
||||
KEY_Return, INP_B_KEY_MEN,
|
||||
KEY_Page_Up, INP_B_KEY_MEN,
|
||||
KEY_KP_1, INP_B_KEY_MEN,
|
||||
KEY_Page_Down, INP_B_KEY_EXT,
|
||||
KEY_BackSpace, INP_B_KEY_EXT,
|
||||
KEY_KP_0, INP_B_KEY_EXT,
|
||||
KEY_Down, INP_B_KEY_DWN,
|
||||
KEY_Up, INP_B_KEY_UP,
|
||||
KEY_Right, INP_B_KEY_RGT,
|
||||
KEY_Left, INP_B_KEY_LFT
|
||||
};
|
||||
|
||||
pinb &= ~ 0x7e;
|
||||
for(unsigned i=0; i<DIM(keys1);i+=2){
|
||||
if(getApp()->getKeyState(keys1[i])) pinb |= (1<<keys1[i+1]);
|
||||
}
|
||||
|
||||
#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 keys2[]={KEY_Y, KEY_T, KEY_W, KEY_Q, KEY_I, KEY_U, KEY_E, KEY_R };
|
||||
#else
|
||||
static FXuint keys2[]={KEY_F8, KEY_F7, KEY_F4, KEY_F3, KEY_F6, KEY_F5, KEY_F1, KEY_F2 };
|
||||
#endif
|
||||
pind = 0;
|
||||
for(unsigned i=0; i<DIM(keys2);i++){
|
||||
if(getApp()->getKeyState(keys2[i])) pind |= (1<<i);
|
||||
}
|
||||
|
||||
struct SwitchKey {
|
||||
FXuint key;
|
||||
volatile unsigned char& pin;
|
||||
unsigned char shift;
|
||||
unsigned char value;
|
||||
};
|
||||
|
||||
static SwitchKey keys3[] = {
|
||||
#if defined(JETI) || defined(FRSKY)
|
||||
{ KEY_1, pinc, INP_C_ThrCt, 0 },
|
||||
{ KEY_6, pinc, INP_C_AileDR, 0 },
|
||||
#else
|
||||
{ KEY_1, pine, INP_E_ThrCt, 0 },
|
||||
{ KEY_6, pine, INP_E_AileDR, 0 },
|
||||
#endif
|
||||
{ KEY_2, ping, INP_G_RuddDR, 0 },
|
||||
{ KEY_3, pine, INP_E_ElevDR, 0 },
|
||||
//KEY_4, ping, INP_G_ID1, 0,
|
||||
//KEY_5, pine, INP_E_ID2, 0,
|
||||
{ KEY_7, pine, INP_E_Gear, 0 },
|
||||
{ KEY_8, pine, INP_E_Trainer, 0 } };
|
||||
|
||||
for(unsigned i=0; i<DIM(keys3); i++){
|
||||
bool ks = getApp()->getKeyState(keys3[i].key);
|
||||
if (ks != keys3[i].value) {
|
||||
if (ks) keys3[i].pin ^= (1<<keys3[i].shift);
|
||||
keys3[i].value = ks;
|
||||
}
|
||||
}
|
||||
// INP_G_ID1 INP_E_ID2
|
||||
// id0 0 1
|
||||
// id1 1 1
|
||||
// id2 1 0
|
||||
static FXuint id=0,k4st=0,k5st=0;
|
||||
bool ks=getApp()->getKeyState(KEY_4);
|
||||
if(ks != k4st){
|
||||
if(ks && id>0) id--;
|
||||
k4st = ks;
|
||||
}
|
||||
ks=getApp()->getKeyState(KEY_5);
|
||||
if(ks != k5st){
|
||||
if(ks && id<2) id++;
|
||||
k5st = ks;
|
||||
}
|
||||
switch(id){
|
||||
case 0: ping |= (1<<INP_G_ID1); pine &= ~(1<<INP_E_ID2); break;
|
||||
case 1: ping &= ~(1<<INP_G_ID1); pine &= ~(1<<INP_E_ID2); break;
|
||||
case 2: ping &= ~(1<<INP_G_ID1); pine |= (1<<INP_E_ID2); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int state = 0;
|
||||
void *init_function(void *) {
|
||||
g_menuStack[0] = menuMainView;
|
||||
g_menuStack[1] = menuProcModelSelect;
|
||||
eeReadAll(); //load general setup and selected model
|
||||
checkMem(); //enough eeprom free?
|
||||
checkTHR();
|
||||
checkSwitches(); //must be last
|
||||
state = 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <pthread.h>
|
||||
long Gruvin9xSim::onChore(FXObject*,FXSelector,void*)
|
||||
{
|
||||
pthread_t pid;
|
||||
|
||||
refreshDiplay();
|
||||
|
||||
switch (state) {
|
||||
case 0:
|
||||
state = 1;
|
||||
pthread_create(&pid, NULL, &init_function, NULL);
|
||||
break;
|
||||
case 2:
|
||||
perMain();
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Gruvin9xSim *th9xSim;
|
||||
void doFxEvents()
|
||||
{
|
||||
//puts("doFxEvents");
|
||||
th9xSim->getApp()->runOneEvent(false);
|
||||
th9xSim->refreshDiplay();
|
||||
}
|
||||
|
||||
int main(int argc,char **argv)
|
||||
{
|
||||
if(argc>=2){
|
||||
eepromFile = argv[1];
|
||||
}
|
||||
printf("eeprom = %s\n",eepromFile);
|
||||
|
||||
// Each FOX GUI program needs one, and only one, application object.
|
||||
// The application objects coordinates some common stuff shared between
|
||||
// all the widgets; for example, it dispatches events, keeps track of
|
||||
// all the windows, and so on.
|
||||
// We pass the "name" of the application, and its "vendor", the name
|
||||
// and vendor are used to search the registry database (which stores
|
||||
// persistent information e.g. fonts and colors).
|
||||
FXApp application("Gruvin9xSim", "thus");
|
||||
|
||||
// Here we initialize the application. We pass the command line arguments
|
||||
// because FOX may sometimes need to filter out some of the arguments.
|
||||
// This opens up the display as well, and reads the registry database
|
||||
// so that persistent settings are now available.
|
||||
application.init(argc,argv);
|
||||
|
||||
// This creates the main window. We pass in the title to be displayed
|
||||
// above the window, and possibly some icons for when its iconified.
|
||||
// The decorations determine stuff like the borders, close buttons,
|
||||
// drag handles, and so on the Window Manager is supposed to give this
|
||||
// window.
|
||||
//FXMainWindow *main=new FXMainWindow(&application,"Hello",NULL,NULL,DECOR_ALL);
|
||||
th9xSim = new Gruvin9xSim(&application);
|
||||
application.create();
|
||||
|
||||
// Pretty self-explanatory:- this shows the window, and places it in the
|
||||
// middle of the screen.
|
||||
#ifndef __APPLE__
|
||||
th9xSim->show(PLACEMENT_SCREEN);
|
||||
#else
|
||||
th9xSim->show(); // Otherwise the main window gets centred across my two monitors, split down the middle.
|
||||
#endif
|
||||
|
||||
return application.run();
|
||||
}
|
||||
|
||||
uint16_t anaIn(uint8_t chan)
|
||||
{
|
||||
if(chan<4) return th9xSim->sliders[chan]->getValue();
|
||||
return th9xSim->knobs[chan]->getValue();
|
||||
//return 512 - 512*10*chan/100;
|
||||
//return (rand() & 0x1f) + 0x2f8;
|
||||
}
|
6
src/stamp-gruvin9x.h
Normal file
6
src/stamp-gruvin9x.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
//Automatically generated file (Makefile) - do not edit
|
||||
#define DATE_STR "2011-09-13"
|
||||
#define TIME_STR "19:07:15"
|
||||
#define TAG_VERS 2-bsongis
|
||||
#define SVN_VERS "gruvin9x-dev-r819"
|
||||
#define BUILD_NUM 827
|
13
src/stamp.cpp
Normal file
13
src/stamp.cpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
#include "gruvin9x.h"
|
||||
#include "stamp-gruvin9x.h"
|
||||
|
||||
#define STR2(s) #s
|
||||
#define DEFNUMSTR(s) STR2(s)
|
||||
|
||||
const char APM stamp1[] = "VERS: V" DEFNUMSTR(VERS) "." DEFNUMSTR(TAG_VERS);
|
||||
const char APM stamp2[] = "DATE: " DATE_STR;
|
||||
const char APM stamp3[] = "TIME: " TIME_STR;
|
||||
const char APM stamp4[] = " SVN: " SVN_VERS;
|
||||
const char APM stamp5[] = " BLD: " DEFNUMSTR(BUILD_NUM);
|
||||
|
||||
|
105
src/statistics_views.cpp
Normal file
105
src/statistics_views.cpp
Normal file
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Authors (alphabetical order)
|
||||
* - Bertrand Songis <bsongis@gmail.com>
|
||||
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
*
|
||||
* gruvin9x is based on code named er9x by
|
||||
* Author - Erez Raviv <erezraviv@gmail.com>, which is in turn
|
||||
* was based on 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 "menus.h"
|
||||
|
||||
void menuProcStatistic(uint8_t event)
|
||||
{
|
||||
TITLE("STAT");
|
||||
switch(event)
|
||||
{
|
||||
case EVT_KEY_FIRST(KEY_UP):
|
||||
chainMenu(menuProcStatistic2);
|
||||
break;
|
||||
case EVT_KEY_FIRST(KEY_DOWN):
|
||||
case EVT_KEY_FIRST(KEY_EXIT):
|
||||
chainMenu(menuMainView);
|
||||
break;
|
||||
}
|
||||
|
||||
lcd_puts_P( 1*FW, FH*1, PSTR("TME"));
|
||||
putsTime( 5*FW, FH*1, s_timeCumAbs, 0, 0);
|
||||
lcd_puts_P( 17*FW, FH*1, PSTR("TSW"));
|
||||
putsTime( 11*FW, FH*1, s_timeCumSw, 0, 0);
|
||||
|
||||
lcd_puts_P( 1*FW, FH*2, PSTR("STK"));
|
||||
putsTime( 5*FW, FH*2, s_timeCumThr, 0, 0);
|
||||
lcd_puts_P( 17*FW, FH*2, PSTR("ST%"));
|
||||
putsTime( 11*FW, FH*2, s_timeCum16ThrP/16, 0, 0);
|
||||
|
||||
lcd_puts_P( 17*FW, FH*0, PSTR("TOT"));
|
||||
putsTime( 11*FW, FH*0, s_timeCumTot, 0, 0);
|
||||
|
||||
uint16_t traceRd = s_traceCnt>MAXTRACE ? s_traceWr : 0;
|
||||
uint8_t x=5;
|
||||
uint8_t y=60;
|
||||
lcd_hline(x-3,y,120+3+3);
|
||||
lcd_vline(x,y-32,32+3);
|
||||
|
||||
for(uint8_t i=0; i<120; i+=6)
|
||||
{
|
||||
lcd_vline(x+i+6,y-1,3);
|
||||
}
|
||||
for(uint8_t i=1; i<=120; i++)
|
||||
{
|
||||
lcd_vline(x+i,y-s_traceBuf[traceRd],s_traceBuf[traceRd]);
|
||||
traceRd++;
|
||||
if(traceRd>=MAXTRACE) traceRd=0;
|
||||
if(traceRd==s_traceWr) break;
|
||||
}
|
||||
}
|
||||
|
||||
void menuProcStatistic2(uint8_t event)
|
||||
{
|
||||
TITLE("STAT2");
|
||||
switch(event)
|
||||
{
|
||||
case EVT_KEY_FIRST(KEY_MENU):
|
||||
g_tmr1Latency_min = 0x7ff;
|
||||
g_tmr1Latency_max = 0;
|
||||
g_timeMain = 0;
|
||||
// g_time_per10 = 0;
|
||||
beepKey();
|
||||
break;
|
||||
case EVT_KEY_FIRST(KEY_DOWN):
|
||||
chainMenu(menuProcStatistic);
|
||||
break;
|
||||
case EVT_KEY_FIRST(KEY_UP):
|
||||
case EVT_KEY_FIRST(KEY_EXIT):
|
||||
chainMenu(menuMainView);
|
||||
break;
|
||||
}
|
||||
lcd_puts_P( 0*FW, 1*FH, PSTR("tmr1Lat max us"));
|
||||
lcd_outdez8(15*FW , 1*FH, g_tmr1Latency_max/2 );
|
||||
lcd_puts_P( 0*FW, 2*FH, PSTR("tmr1Lat min us"));
|
||||
lcd_outdez8(15*FW , 2*FH, g_tmr1Latency_min/2 );
|
||||
lcd_puts_P( 0*FW, 3*FH, PSTR("tmr1 Jitter us"));
|
||||
lcd_outdez8(15*FW , 3*FH, (g_tmr1Latency_max - g_tmr1Latency_min) /2 );
|
||||
lcd_puts_P( 0*FW, 4*FH, PSTR("tmain max ms"));
|
||||
lcd_outdezAtt(15*FW, 4*FH, (g_timeMain*100)/16, PREC2);
|
||||
lcd_puts_P( 0*FW, 5*FH, PSTR("t10ms us"));
|
||||
lcd_outdez8(15*FW , 5*FH, g_time_per10/2 );
|
||||
#ifndef SIMU
|
||||
lcd_puts_P( 0*FW, 6*FH, PSTR("Free Stack min b"));
|
||||
lcd_outdezAtt(18*FW-1, 6*FH, stack_free() ) ;
|
||||
#endif
|
||||
lcd_puts_P( 3*FW, 7*FH, PSTR("[MENU] to reset"));
|
||||
}
|
7
src/sticks.lbm
Normal file
7
src/sticks.lbm
Normal file
|
@ -0,0 +1,7 @@
|
|||
prog_uchar APM sticks[] = {
|
||||
18,8,18,
|
||||
0x00,0x08,0x1c,0x08,0x08,0x08,0x1c,0x08,0x00,0x00,0x08,0x22,0x00,0x49,0x00,0x22,0x08,0x00,
|
||||
0x00,0x00,0x00,0x00,0x22,0x7f,0x22,0x00,0x00,0x00,0x08,0x22,0x00,0x49,0x00,0x22,0x08,0x00,
|
||||
0x00,0x08,0x22,0x00,0x49,0x00,0x22,0x08,0x00,0x00,0x00,0x22,0x7f,0x22,0x00,0x00,0x00,0x00,
|
||||
0x00,0x08,0x22,0x00,0x49,0x00,0x22,0x08,0x00,0x00,0x08,0x1c,0x08,0x08,0x08,0x1c,0x08,0x00,
|
||||
};
|
11
src/sticks_4x1.xbm
Normal file
11
src/sticks_4x1.xbm
Normal file
|
@ -0,0 +1,11 @@
|
|||
#define sticks_width 18
|
||||
#define sticks_height 32
|
||||
static unsigned char sticks_bits[] = {
|
||||
0x00, 0x20, 0x00, 0x00, 0x88, 0x00, 0x44, 0x00, 0x00, 0xfe, 0x24, 0x01,
|
||||
0x44, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
|
||||
0x20, 0x20, 0x00, 0x70, 0x88, 0x00, 0x20, 0x00, 0x00, 0x20, 0x24, 0x01,
|
||||
0x20, 0x00, 0x00, 0x70, 0x88, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00,
|
||||
0x10, 0x10, 0x00, 0x44, 0x38, 0x00, 0x00, 0x10, 0x00, 0x92, 0x10, 0x00,
|
||||
0x00, 0x10, 0x00, 0x44, 0x38, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
|
||||
0x10, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x88, 0x00, 0x92, 0xfc, 0x01,
|
||||
0x00, 0x88, 0x00, 0x44, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
207
src/templates.cpp
Normal file
207
src/templates.cpp
Normal file
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* gruvin9x Author Bryan J.Rentoul (Gruvin) <gruvin@gmail.com>
|
||||
*
|
||||
* templates.cpp original author - Erez Raviv <erezraviv@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* ============================================================
|
||||
* Templates file
|
||||
*
|
||||
* eccpm
|
||||
* crow
|
||||
* throttle cut
|
||||
* flaperon
|
||||
* elevon
|
||||
* v-tail
|
||||
* throttle hold
|
||||
* Aileron Differential
|
||||
* Spoilers
|
||||
* Snap Roll
|
||||
* ELE->Flap
|
||||
* Flap->ELE
|
||||
*
|
||||
*
|
||||
*
|
||||
* =============================================================
|
||||
* Assumptions:
|
||||
* All primary channels are per modi12x3
|
||||
* Each template added to the end of each channel
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gruvin9x.h"
|
||||
#include "templates.h"
|
||||
|
||||
MixData* setDest(uint8_t dch)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
while ((g_model.mixData[i].destCh<=dch) && (g_model.mixData[i].destCh) && (i<MAX_MIXERS)) i++;
|
||||
if(i==MAX_MIXERS) return &g_model.mixData[0];
|
||||
|
||||
memmove(&g_model.mixData[i+1],&g_model.mixData[i],
|
||||
(MAX_MIXERS-(i+1))*sizeof(MixData) );
|
||||
memset(&g_model.mixData[i],0,sizeof(MixData));
|
||||
g_model.mixData[i].destCh = dch;
|
||||
return &g_model.mixData[i];
|
||||
}
|
||||
|
||||
void clearMixes()
|
||||
{
|
||||
memset(g_model.mixData,0,sizeof(g_model.mixData)); //clear all mixes
|
||||
}
|
||||
|
||||
void clearCurves()
|
||||
{
|
||||
memset(g_model.curves5,0,sizeof(g_model.curves5)); //clear all curves
|
||||
memset(g_model.curves9,0,sizeof(g_model.curves9)); //clear all curves
|
||||
}
|
||||
|
||||
void setCurve(uint8_t c, int8_t ar[])
|
||||
{
|
||||
if(c<MAX_CURVE5) //5 pt curve
|
||||
for(uint8_t i=0; i<5; i++) g_model.curves5[c][i] = ar[i];
|
||||
else //9 pt curve
|
||||
for(uint8_t i=0; i<9; i++) g_model.curves9[c-MAX_CURVE5][i] = ar[i];
|
||||
}
|
||||
|
||||
void setSwitch(uint8_t idx, uint8_t func, int8_t v1, int8_t v2)
|
||||
{
|
||||
g_model.customSw[idx-1].func = func;
|
||||
g_model.customSw[idx-1].v1 = v1;
|
||||
g_model.customSw[idx-1].v2 = v2;
|
||||
}
|
||||
|
||||
void applyTemplate(uint8_t idx)
|
||||
{
|
||||
int8_t heli_ar1[] = {-100, 20, 50, 70, 90};
|
||||
int8_t heli_ar2[] = {90, 70, 50, 70, 90};
|
||||
int8_t heli_ar3[] = {-20, -20, 0, 60, 100};
|
||||
int8_t heli_ar4[] = {-100, -60, 0, 60, 100};
|
||||
int8_t heli_ar5[] = {-100, 0, 0, 0, 100};
|
||||
|
||||
|
||||
MixData *md = &g_model.mixData[0];
|
||||
|
||||
//CC(STK) -> vSTK
|
||||
//ICC(vSTK) -> STK
|
||||
#define ICC(x) icc[(x)-1]
|
||||
uint8_t icc[4] = {0};
|
||||
for(uint8_t i=1; i<=4; i++) //generate inverse array
|
||||
for(uint8_t j=1; j<=4; j++) if(CC(i)==j) icc[j-1]=i;
|
||||
|
||||
|
||||
switch (idx){
|
||||
//Simple 4-Ch
|
||||
case (0):
|
||||
md=setDest(ICC(STK_RUD)); md->srcRaw=CM(STK_RUD); md->weight=100;
|
||||
md=setDest(ICC(STK_ELE)); md->srcRaw=CM(STK_ELE); md->weight=100;
|
||||
md=setDest(ICC(STK_THR)); md->srcRaw=CM(STK_THR); md->weight=100;
|
||||
md=setDest(ICC(STK_AIL)); md->srcRaw=CM(STK_AIL); md->weight=100;
|
||||
break;
|
||||
|
||||
//T-Cut
|
||||
case (1):
|
||||
md=setDest(ICC(STK_THR)); md->srcRaw=MIX_MAX; md->weight=-100; md->swtch=DSW_THR; md->mltpx=MLTPX_REP;
|
||||
break;
|
||||
|
||||
//V-Tail
|
||||
case (2):
|
||||
md=setDest(ICC(STK_RUD)); md->srcRaw=CM(STK_RUD); md->weight= 100;
|
||||
md=setDest(ICC(STK_RUD)); md->srcRaw=CM(STK_ELE); md->weight=-100;
|
||||
md=setDest(ICC(STK_ELE)); md->srcRaw=CM(STK_RUD); md->weight= 100;
|
||||
md=setDest(ICC(STK_ELE)); md->srcRaw=CM(STK_ELE); md->weight= 100;
|
||||
break;
|
||||
|
||||
//Elevon\\Delta
|
||||
case (3):
|
||||
md=setDest(ICC(STK_ELE)); md->srcRaw=CM(STK_ELE); md->weight= 100;
|
||||
md=setDest(ICC(STK_ELE)); md->srcRaw=CM(STK_AIL); md->weight= 100;
|
||||
md=setDest(ICC(STK_AIL)); md->srcRaw=CM(STK_ELE); md->weight= 100;
|
||||
md=setDest(ICC(STK_AIL)); md->srcRaw=CM(STK_AIL); md->weight=-100;
|
||||
break;
|
||||
|
||||
//eCCPM
|
||||
case (4):
|
||||
md=setDest(ICC(STK_ELE)); md->srcRaw=CM(STK_ELE); md->weight= 72;
|
||||
md=setDest(ICC(STK_ELE)); md->srcRaw=CM(STK_THR); md->weight= 55;
|
||||
md=setDest(ICC(STK_AIL)); md->srcRaw=CM(STK_ELE); md->weight=-36;
|
||||
md=setDest(ICC(STK_AIL)); md->srcRaw=CM(STK_AIL); md->weight= 62;
|
||||
md=setDest(ICC(STK_AIL)); md->srcRaw=CM(STK_THR); md->weight= 55;
|
||||
md=setDest(6); md->srcRaw=CM(STK_ELE); md->weight=-36;
|
||||
md=setDest(6); md->srcRaw=CM(STK_AIL); md->weight=-62;
|
||||
md=setDest(6); md->srcRaw=CM(STK_THR); md->weight= 55;
|
||||
break;
|
||||
|
||||
//Heli Setup
|
||||
case (5):
|
||||
clearMixes(); //This time we want a clean slate
|
||||
clearCurves();
|
||||
|
||||
//Set up Mixes
|
||||
md=setDest(ICC(STK_AIL)); md->srcRaw=CH(9); md->weight= 50;
|
||||
md=setDest(ICC(STK_AIL)); md->srcRaw=CH(10); md->weight=-100;
|
||||
md=setDest(ICC(STK_AIL)); md->srcRaw=CH(11); md->weight= 100; md->carryTrim=TRIM_OFF;
|
||||
|
||||
md=setDest(ICC(STK_ELE)); md->srcRaw=CH(9); md->weight=-100;
|
||||
md=setDest(ICC(STK_ELE)); md->srcRaw=CH(11); md->weight= 100; md->carryTrim=TRIM_OFF;
|
||||
|
||||
md=setDest(ICC(STK_THR)); md->srcRaw=CM(STK_THR); md->weight= 100; md->swtch=DSW_ID0; md->curve=CV(1); md->carryTrim=TRIM_OFF;
|
||||
md=setDest(ICC(STK_THR)); md->srcRaw=CM(STK_THR); md->weight= 100; md->swtch=DSW_ID1; md->curve=CV(2); md->carryTrim=TRIM_OFF;
|
||||
md=setDest(ICC(STK_THR)); md->srcRaw=CM(STK_THR); md->weight= 110; md->swtch=DSW_ID2; md->curve=CV(2); md->carryTrim=TRIM_OFF;
|
||||
md=setDest(ICC(STK_THR)); md->srcRaw=MIX_MAX; md->weight=-125; md->swtch=DSW_THR; md->mltpx=MLTPX_REP; md->carryTrim=TRIM_OFF;
|
||||
|
||||
md=setDest(ICC(STK_RUD)); md->srcRaw=CM(STK_RUD); md->weight=100;
|
||||
|
||||
md=setDest(5); md->srcRaw=MIX_MAX; md->weight= 50; md->swtch=-DSW_GEA; md->carryTrim=TRIM_OFF;
|
||||
md=setDest(5); md->srcRaw=MIX_MAX; md->weight=-50; md->swtch= DSW_GEA; md->carryTrim=TRIM_OFF;
|
||||
md=setDest(5); md->srcRaw=STK_P3; md->weight= 40; md->carryTrim=TRIM_OFF;
|
||||
|
||||
md=setDest(6); md->srcRaw=CH(9); md->weight= -50;
|
||||
md=setDest(6); md->srcRaw=CH(10); md->weight=-100;
|
||||
md=setDest(6); md->srcRaw=CH(11); md->weight=-100; md->carryTrim=TRIM_OFF;
|
||||
|
||||
md=setDest(9); md->srcRaw=CM(STK_ELE); md->weight= 60;
|
||||
md=setDest(10); md->srcRaw=CM(STK_AIL); md->weight=-52;
|
||||
md=setDest(11); md->srcRaw=CM(STK_THR); md->weight= 70; md->swtch=DSW_ID0; md->curve=CV(3); md->carryTrim=TRIM_OFF;
|
||||
md=setDest(11); md->srcRaw=CM(STK_THR); md->weight= 70; md->swtch=DSW_ID1; md->curve=CV(4); md->carryTrim=TRIM_OFF;
|
||||
md=setDest(11); md->srcRaw=CM(STK_THR); md->weight= 70; md->swtch=DSW_ID2; md->curve=CV(4); md->carryTrim=TRIM_OFF;
|
||||
md=setDest(11); md->srcRaw=CM(STK_THR); md->weight=100; md->swtch=DSW_THR; md->curve=CV(5); md->carryTrim=TRIM_OFF; md->mltpx=MLTPX_REP;
|
||||
|
||||
//Set up Curves
|
||||
setCurve(CURVE5(1),heli_ar1);
|
||||
setCurve(CURVE5(2),heli_ar2);
|
||||
setCurve(CURVE5(3),heli_ar3);
|
||||
setCurve(CURVE5(4),heli_ar4);
|
||||
setCurve(CURVE5(5),heli_ar5);
|
||||
break;
|
||||
|
||||
//Servo Test
|
||||
case (6):
|
||||
md=setDest(15); md->srcRaw=CH(16); md->weight= 100; md->speedUp = 8; md->speedDown = 8;
|
||||
md=setDest(16); md->srcRaw=MIX_FULL; md->weight= 110; md->swtch=DSW_SW1;
|
||||
md=setDest(16); md->srcRaw=MIX_MAX; md->weight=-110; md->swtch=DSW_SW2; md->mltpx=MLTPX_REP;
|
||||
md=setDest(16); md->srcRaw=MIX_MAX; md->weight= 110; md->swtch=DSW_SW3; md->mltpx=MLTPX_REP;
|
||||
|
||||
setSwitch(1,CS_LESS,CH(15),CH(16));
|
||||
setSwitch(2,CS_VPOS,CH(15), 105);
|
||||
setSwitch(3,CS_VNEG,CH(15), -105);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
STORE_MODELVARS;
|
||||
|
||||
}
|
88
src/templates.h
Normal file
88
src/templates.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Author - Erez Raviv <erezraviv@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* ============================================================
|
||||
* Templates file
|
||||
*
|
||||
* eccpm
|
||||
* crow
|
||||
* throttle cut
|
||||
* flaperon
|
||||
* elevon
|
||||
* v-tail
|
||||
* throttle hold
|
||||
* Aileron Differential
|
||||
* Spoilers
|
||||
* Snap Roll
|
||||
* ELE->Flap
|
||||
* Flap->ELE
|
||||
*
|
||||
*
|
||||
*
|
||||
* =============================================================
|
||||
* Assumptions:
|
||||
* All primary channels are per modi12x3
|
||||
* Each template added to the end of each channel
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TEMPLATES_H
|
||||
#define TEMPLATES_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
|
||||
#define STK_RUD 1
|
||||
#define STK_ELE 2
|
||||
#define STK_THR 3
|
||||
#define STK_AIL 4
|
||||
#define STK_P1 5
|
||||
#define STK_P2 6
|
||||
#define STK_P3 7
|
||||
#define NUM_TEMPLATES DIM(n_Templates)
|
||||
#define NUM_TEMPLATE_MIX 8
|
||||
#define TEMPLATE_NLEN 15
|
||||
|
||||
#define TRIM_ON 0
|
||||
#define TRIM_OFF 1
|
||||
|
||||
#define CM(x) (CONVERT_MODE(x)) //good for SRC
|
||||
#define CH(x) (CHOUT_BASE+(x))
|
||||
#define CV(x) (CURVE_BASE+(x)-1)
|
||||
#define CC(x) (CHANNEL_ORDER(x)) //need to invert this to work with dest
|
||||
|
||||
#define CURVE5(x) ((x)-1)
|
||||
#define CURVE9(x) (MAX_CURVE5+(x)-1)
|
||||
|
||||
const char n_Templates[][TEMPLATE_NLEN] = {
|
||||
"Simple 4-CH",
|
||||
"T-Cut",
|
||||
"V-Tail",
|
||||
"Elevon\\Delta",
|
||||
"eCCPM",
|
||||
"Heli Setup",
|
||||
"Servo Test"
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
void clearMixes();
|
||||
void clearCurves();
|
||||
void applyTemplate(uint8_t idx);
|
||||
|
||||
|
||||
#endif //TEMPLATES_H
|
||||
|
||||
|
463
src/time.cpp
Normal file
463
src/time.cpp
Normal file
|
@ -0,0 +1,463 @@
|
|||
#include "time.h"
|
||||
|
||||
#define LEAP_SECONDS_POSSIBLE 0
|
||||
|
||||
/* Shift A right by B bits portably, by dividing A by 2**B and
|
||||
truncating towards minus infinity. A and B should be free of side
|
||||
effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
|
||||
INT_BITS is the number of useful bits in an int. GNU code can
|
||||
assume that INT_BITS is at least 32.
|
||||
|
||||
ISO C99 says that A >> B is implementation-defined if A < 0. Some
|
||||
implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
|
||||
right in the usual way when A < 0, so SHR falls back on division if
|
||||
ordinary A >> B doesn't seem to be the usual signed shift. */
|
||||
#define SHR(a, b) \
|
||||
(-1 >> 1 == -1 \
|
||||
? (a) >> (b) \
|
||||
: (a) / (1 << (b)) - ((a) % (1 << (b)) < 0))
|
||||
|
||||
/* The extra casts in the following macros work around compiler bugs,
|
||||
e.g., in Cray C 5.0.3.0. */
|
||||
|
||||
/* True if the arithmetic type T is an integer type. bool counts as
|
||||
an integer. */
|
||||
#define TYPE_IS_INTEGER(t) ((t) 1.5 == 1)
|
||||
|
||||
/* True if negative values of the signed integer type T use two's
|
||||
complement, ones' complement, or signed magnitude representation,
|
||||
respectively. Much GNU code assumes two's complement, but some
|
||||
people like to be portable to all possible C hosts. */
|
||||
#define TYPE_TWOS_COMPLEMENT(t) ((t) ~ (t) 0 == (t) -1)
|
||||
#define TYPE_ONES_COMPLEMENT(t) ((t) ~ (t) 0 == 0)
|
||||
#define TYPE_SIGNED_MAGNITUDE(t) ((t) ~ (t) 0 < (t) -1)
|
||||
|
||||
/* True if the arithmetic type T is signed. */
|
||||
#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
|
||||
|
||||
/* The maximum and minimum values for the integer type T. These
|
||||
macros have undefined behavior if T is signed and has padding bits.
|
||||
If this is a problem for you, please let us know how to fix it for
|
||||
your host. */
|
||||
#define TYPE_MINIMUM(t) \
|
||||
((t) (! TYPE_SIGNED (t) \
|
||||
? (t) 0 \
|
||||
: TYPE_SIGNED_MAGNITUDE (t) \
|
||||
? ~ (t) 0 \
|
||||
: ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1)))
|
||||
#define TYPE_MAXIMUM(t) \
|
||||
((t) (! TYPE_SIGNED (t) \
|
||||
? (t) -1 \
|
||||
: ~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1))))
|
||||
|
||||
#ifndef TIME_T_MIN
|
||||
# define TIME_T_MIN TYPE_MINIMUM (time_t)
|
||||
#endif
|
||||
#ifndef TIME_T_MAX
|
||||
# define TIME_T_MAX TYPE_MAXIMUM (time_t)
|
||||
#endif
|
||||
#define TIME_T_MIDPOINT (SHR (TIME_T_MIN + TIME_T_MAX, 1) + 1)
|
||||
|
||||
/* Verify a requirement at compile-time (unlike assert, which is runtime). */
|
||||
#define verify(name, assertion) struct name { char a[(assertion) ? 1 : -1]; }
|
||||
|
||||
verify (time_t_is_integer, TYPE_IS_INTEGER (time_t));
|
||||
verify (twos_complement_arithmetic, TYPE_TWOS_COMPLEMENT (int));
|
||||
/* The code also assumes that signed integer overflow silently wraps
|
||||
around, but this assumption can't be stated without causing a
|
||||
diagnostic on some hosts. */
|
||||
|
||||
#define EPOCH_YEAR 1970
|
||||
#define TM_YEAR_BASE 1900
|
||||
verify (base_year_is_a_multiple_of_100, TM_YEAR_BASE % 100 == 0);
|
||||
|
||||
#define SECS_PER_HOUR 3600ul
|
||||
#define SECS_PER_DAY 86400ul
|
||||
#define EOVERFLOW 0
|
||||
|
||||
/* Return 1 if YEAR + TM_YEAR_BASE is a leap year. */
|
||||
static inline int
|
||||
leapyear (long int year)
|
||||
{
|
||||
/* Don't add YEAR to TM_YEAR_BASE, as that might overflow.
|
||||
Also, work even if YEAR is negative. */
|
||||
return
|
||||
((year & 3) == 0
|
||||
&& (year % 100 != 0
|
||||
|| ((year / 100) & 3) == (- (TM_YEAR_BASE / 100) & 3)));
|
||||
}
|
||||
|
||||
const unsigned short int __mon_yday[2][13] =
|
||||
{
|
||||
/* Normal years. */
|
||||
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
|
||||
/* Leap years. */
|
||||
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
|
||||
};
|
||||
|
||||
/* Compute the `struct tm' representation of *T,
|
||||
offset OFFSET seconds east of UTC,
|
||||
and store year, yday, mon, mday, wday, hour, min, sec into *TP.
|
||||
Return nonzero if successful. */
|
||||
int
|
||||
__offtime (
|
||||
time_t *t,
|
||||
long int offset,
|
||||
struct tm *tp)
|
||||
{
|
||||
long int days, rem, y;
|
||||
const unsigned short int *ip;
|
||||
|
||||
days = *t / SECS_PER_DAY;
|
||||
rem = *t % SECS_PER_DAY;
|
||||
rem += offset;
|
||||
while (rem < 0)
|
||||
{
|
||||
rem += SECS_PER_DAY;
|
||||
--days;
|
||||
}
|
||||
while (rem >= SECS_PER_DAY)
|
||||
{
|
||||
rem -= SECS_PER_DAY;
|
||||
++days;
|
||||
}
|
||||
tp->tm_hour = rem / SECS_PER_HOUR;
|
||||
rem %= SECS_PER_HOUR;
|
||||
tp->tm_min = rem / 60;
|
||||
tp->tm_sec = rem % 60;
|
||||
/* January 1, 1970 was a Thursday. */
|
||||
tp->tm_wday = (4 + days) % 7;
|
||||
if (tp->tm_wday < 0)
|
||||
tp->tm_wday += 7;
|
||||
y = 1970;
|
||||
|
||||
#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
|
||||
#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
|
||||
|
||||
while (days < 0 || days >= (leapyear (y) ? 366 : 365))
|
||||
{
|
||||
/* Guess a corrected year, assuming 365 days per year. */
|
||||
long int yg = y + days / 365 - (days % 365 < 0);
|
||||
|
||||
/* Adjust DAYS and Y to match the guessed year. */
|
||||
days -= ((yg - y) * 365
|
||||
+ LEAPS_THRU_END_OF (yg - 1)
|
||||
- LEAPS_THRU_END_OF (y - 1));
|
||||
y = yg;
|
||||
}
|
||||
tp->tm_year = y - 1900;
|
||||
if (tp->tm_year != y - 1900)
|
||||
{
|
||||
/* The year cannot be represented due to overflow. */
|
||||
// __set_errno (EOVERFLOW);
|
||||
return 0;
|
||||
}
|
||||
tp->tm_yday = days;
|
||||
ip = __mon_yday[leapyear(y)];
|
||||
for (y = 11; days < (long int) ip[y]; --y)
|
||||
continue;
|
||||
days -= ip[y];
|
||||
tp->tm_mon = y;
|
||||
tp->tm_mday = days + 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* time_r function implementations */
|
||||
// G: No time zones in our implementation so just do the converion from time_t to struct tm
|
||||
struct tm *
|
||||
__localtime_r (time_t * t, struct tm * tp)
|
||||
{
|
||||
__offtime(t, 0, tp);
|
||||
return tp;
|
||||
}
|
||||
|
||||
|
||||
/* Return an integer value measuring (YEAR1-YDAY1 HOUR1:MIN1:SEC1) -
|
||||
(YEAR0-YDAY0 HOUR0:MIN0:SEC0) in seconds, assuming that the clocks
|
||||
were not adjusted between the time stamps.
|
||||
|
||||
The YEAR values uses the same numbering as TP->tm_year. Values
|
||||
need not be in the usual range. However, YEAR1 must not be less
|
||||
than 2 * INT_MIN or greater than 2 * INT_MAX.
|
||||
|
||||
The result may overflow. It is the caller's responsibility to
|
||||
detect overflow. */
|
||||
|
||||
static inline time_t
|
||||
ydhms_diff (long int year1, long int yday1, int hour1, int min1, int sec1,
|
||||
int year0, int yday0, int hour0, int min0, int sec0)
|
||||
{
|
||||
verify (C99_integer_division, -1 / 2 == 0);
|
||||
verify (long_int_year_and_yday_are_wide_enough,
|
||||
INT_MAX <= LONG_MAX / 2 || TIME_T_MAX <= UINT_MAX);
|
||||
|
||||
/* Compute intervening leap days correctly even if year is negative.
|
||||
Take care to avoid integer overflow here. */
|
||||
int a4 = SHR (year1, 2) + SHR (TM_YEAR_BASE, 2) - ! (year1 & 3);
|
||||
int b4 = SHR (year0, 2) + SHR (TM_YEAR_BASE, 2) - ! (year0 & 3);
|
||||
int a100 = a4 / 25 - (a4 % 25 < 0);
|
||||
int b100 = b4 / 25 - (b4 % 25 < 0);
|
||||
int a400 = SHR (a100, 2);
|
||||
int b400 = SHR (b100, 2);
|
||||
int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
|
||||
|
||||
/* Compute the desired time in time_t precision. Overflow might
|
||||
occur here. */
|
||||
time_t tyear1 = year1;
|
||||
time_t years = tyear1 - year0;
|
||||
time_t days = 365 * years + yday1 - yday0 + intervening_leap_days;
|
||||
time_t hours = 24 * days + hour1 - hour0;
|
||||
time_t minutes = 60 * hours + min1 - min0;
|
||||
time_t seconds = 60 * minutes + sec1 - sec0;
|
||||
return seconds;
|
||||
}
|
||||
|
||||
/* Return a time_t value corresponding to (YEAR-YDAY HOUR:MIN:SEC),
|
||||
assuming that *T corresponds to *TP and that no clock adjustments
|
||||
occurred between *TP and the desired time.
|
||||
If TP is null, return a value not equal to *T; this avoids false matches.
|
||||
If overflow occurs, yield the minimal or maximal value, except do not
|
||||
yield a value equal to *T. */
|
||||
static time_t
|
||||
guess_time_tm (long int year, long int yday, int hour, int min, int sec,
|
||||
time_t *t, struct tm *tp)
|
||||
{
|
||||
if (tp)
|
||||
{
|
||||
time_t d = ydhms_diff (year, yday, hour, min, sec,
|
||||
tp->tm_year, tp->tm_yday,
|
||||
tp->tm_hour, tp->tm_min, tp->tm_sec);
|
||||
time_t t1 = *t + d;
|
||||
if ((t1 < *t) == (TYPE_SIGNED (time_t) ? d < 0 : TIME_T_MAX / 2 < d))
|
||||
return t1;
|
||||
}
|
||||
|
||||
/* Overflow occurred one way or another. Return the nearest result
|
||||
that is actually in range, except don't report a zero difference
|
||||
if the actual difference is nonzero, as that would cause a false
|
||||
match; and don't oscillate between two values, as that would
|
||||
confuse the spring-forward gap detector. */
|
||||
return (*t < TIME_T_MIDPOINT
|
||||
? (*t <= TIME_T_MIN + 1 ? *t + 1 : TIME_T_MIN)
|
||||
: (TIME_T_MAX - 1 <= *t ? *t - 1 : TIME_T_MAX));
|
||||
}
|
||||
|
||||
/* Use CONVERT to convert *T to a broken down time in *TP.
|
||||
If *T is out of range for conversion, adjust it so that
|
||||
it is the nearest in-range value and then convert that. */
|
||||
static struct tm *
|
||||
ranged_convert (struct tm *(*convert) (time_t *, struct tm *),
|
||||
time_t *t, struct tm *tp)
|
||||
{
|
||||
struct tm *r = convert (t, tp);
|
||||
|
||||
if (!r && *t)
|
||||
{
|
||||
time_t bad = *t;
|
||||
time_t ok = 0;
|
||||
|
||||
/* BAD is a known unconvertible time_t, and OK is a known good one.
|
||||
Use binary search to narrow the range between BAD and OK until
|
||||
they differ by 1. */
|
||||
while (bad != ok + (bad < 0 ? -1 : 1))
|
||||
{
|
||||
time_t mid = *t = (bad < 0
|
||||
? bad + ((ok - bad) >> 1)
|
||||
: ok + ((bad - ok) >> 1));
|
||||
r = convert (t, tp);
|
||||
if (r)
|
||||
ok = mid;
|
||||
else
|
||||
bad = mid;
|
||||
}
|
||||
|
||||
if (!r && ok)
|
||||
{
|
||||
/* The last conversion attempt failed;
|
||||
revert to the most recent successful attempt. */
|
||||
*t = ok;
|
||||
r = convert (t, tp);
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Convert *TP to a time_t value, inverting
|
||||
the monotonic and mostly-unit-linear conversion function CONVERT.
|
||||
Use *OFFSET to keep track of a guess at the offset of the result,
|
||||
compared to what the result would be for UTC without leap seconds.
|
||||
If *OFFSET's guess is correct, only one CONVERT call is needed.
|
||||
This function is external because it is used also by timegm.c. */
|
||||
time_t
|
||||
__mktime_internal (struct tm *tp,
|
||||
struct tm *(*convert) (time_t *, struct tm *),
|
||||
time_t *offset)
|
||||
{
|
||||
time_t t, gt, t0, t1, t2;
|
||||
struct tm tm;
|
||||
|
||||
/* The maximum number of probes (calls to CONVERT) should be enough
|
||||
to handle any combinations of time zone rule changes, solar time,
|
||||
leap seconds, and oscillations around a spring-forward gap.
|
||||
POSIX.1 prohibits leap seconds, but some hosts have them anyway. */
|
||||
int remaining_probes = 6;
|
||||
|
||||
/* Time requested. Copy it in case CONVERT modifies *TP; this can
|
||||
occur if TP is localtime's returned value and CONVERT is localtime. */
|
||||
int sec = tp->tm_sec;
|
||||
int min = tp->tm_min;
|
||||
int hour = tp->tm_hour;
|
||||
int mday = tp->tm_mday;
|
||||
int mon = tp->tm_mon;
|
||||
int year_requested = tp->tm_year;
|
||||
|
||||
/* Ensure that mon is in range, and set year accordingly. */
|
||||
int mon_remainder = mon % 12;
|
||||
int negative_mon_remainder = mon_remainder < 0;
|
||||
int mon_years = mon / 12 - negative_mon_remainder;
|
||||
long int lyear_requested = year_requested;
|
||||
long int year = lyear_requested + mon_years;
|
||||
|
||||
/* The other values need not be in range:
|
||||
the remaining code handles minor overflows correctly,
|
||||
assuming int and time_t arithmetic wraps around.
|
||||
Major overflows are caught at the end. */
|
||||
|
||||
/* Calculate day of year from year, month, and day of month.
|
||||
The result need not be in range. */
|
||||
int mon_yday = ((__mon_yday[leapyear (year)]
|
||||
[mon_remainder + 12 * negative_mon_remainder])
|
||||
- 1);
|
||||
long int lmday = mday;
|
||||
long int yday = mon_yday + lmday;
|
||||
|
||||
time_t guessed_offset = *offset;
|
||||
|
||||
int sec_requested = sec;
|
||||
|
||||
/*
|
||||
if (LEAP_SECONDS_POSSIBLE)
|
||||
{
|
||||
// Handle out-of-range seconds specially,
|
||||
// since ydhms_tm_diff assumes every minute has 60 seconds.
|
||||
if (sec < 0)
|
||||
sec = 0;
|
||||
if (59 < sec)
|
||||
sec = 59;
|
||||
}
|
||||
*/
|
||||
|
||||
/* Invert CONVERT by probing. First assume the same offset as last
|
||||
time. */
|
||||
|
||||
t0 = ydhms_diff (year, yday, hour, min, sec,
|
||||
EPOCH_YEAR - TM_YEAR_BASE, 0, 0, 0, - guessed_offset);
|
||||
|
||||
if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
|
||||
{
|
||||
/* time_t isn't large enough to rule out overflows, so check
|
||||
for major overflows. A gross check suffices, since if t0
|
||||
has overflowed, it is off by a multiple of TIME_T_MAX -
|
||||
TIME_T_MIN + 1. So ignore any component of the difference
|
||||
that is bounded by a small value. */
|
||||
|
||||
/* Approximate log base 2 of the number of time units per
|
||||
biennium. A biennium is 2 years; use this unit instead of
|
||||
years to avoid integer overflow. For example, 2 average
|
||||
Gregorian years are 2 * 365.2425 * 24 * 60 * 60 seconds,
|
||||
which is 63113904 seconds, and rint (log2 (63113904)) is
|
||||
26. */
|
||||
int ALOG2_SECONDS_PER_BIENNIUM = 26;
|
||||
int ALOG2_MINUTES_PER_BIENNIUM = 20;
|
||||
int ALOG2_HOURS_PER_BIENNIUM = 14;
|
||||
int ALOG2_DAYS_PER_BIENNIUM = 10;
|
||||
int LOG2_YEARS_PER_BIENNIUM = 1;
|
||||
|
||||
int approx_requested_biennia =
|
||||
(SHR (year_requested, LOG2_YEARS_PER_BIENNIUM)
|
||||
- SHR (EPOCH_YEAR - TM_YEAR_BASE, LOG2_YEARS_PER_BIENNIUM)
|
||||
+ SHR (mday, ALOG2_DAYS_PER_BIENNIUM)
|
||||
+ SHR (hour, ALOG2_HOURS_PER_BIENNIUM)
|
||||
+ SHR (min, ALOG2_MINUTES_PER_BIENNIUM)
|
||||
+ (LEAP_SECONDS_POSSIBLE
|
||||
? 0
|
||||
: SHR (sec, ALOG2_SECONDS_PER_BIENNIUM)));
|
||||
|
||||
int approx_biennia = SHR (t0, ALOG2_SECONDS_PER_BIENNIUM);
|
||||
int diff = approx_biennia - approx_requested_biennia;
|
||||
int abs_diff = diff < 0 ? - diff : diff;
|
||||
|
||||
/* IRIX 4.0.5 cc miscalculates TIME_T_MIN / 3: it erroneously
|
||||
gives a positive value of 715827882. Setting a variable
|
||||
first then doing math on it seems to work.
|
||||
(ghazi@caip.rutgers.edu) */
|
||||
time_t time_t_max = TIME_T_MAX;
|
||||
time_t time_t_min = TIME_T_MIN;
|
||||
time_t overflow_threshold =
|
||||
(time_t_max / 3 - time_t_min / 3) >> ALOG2_SECONDS_PER_BIENNIUM;
|
||||
|
||||
if (overflow_threshold < abs_diff)
|
||||
{
|
||||
/* Overflow occurred. Try repairing it; this might work if
|
||||
the time zone offset is enough to undo the overflow. */
|
||||
time_t repaired_t0 = -1 - t0;
|
||||
approx_biennia = SHR (repaired_t0, ALOG2_SECONDS_PER_BIENNIUM);
|
||||
diff = approx_biennia - approx_requested_biennia;
|
||||
abs_diff = diff < 0 ? - diff : diff;
|
||||
if (overflow_threshold < abs_diff)
|
||||
return -1;
|
||||
guessed_offset += repaired_t0 - t0;
|
||||
t0 = repaired_t0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Repeatedly use the error to improve the guess. */
|
||||
|
||||
for (t = t1 = t2 = t0;
|
||||
(gt = guess_time_tm (year, yday, hour, min, sec, &t,
|
||||
ranged_convert (convert, &t, &tm)),
|
||||
t != gt);
|
||||
t1 = t2, t2 = t, t = gt)
|
||||
if (t == t1 && t != t2)
|
||||
goto offset_found;
|
||||
else if (--remaining_probes == 0)
|
||||
return -1;
|
||||
|
||||
offset_found:
|
||||
*offset = guessed_offset + t - t0;
|
||||
|
||||
if (LEAP_SECONDS_POSSIBLE && sec_requested != tm.tm_sec)
|
||||
{
|
||||
/* Adjust time to reflect the tm_sec requested, not the normalized value.
|
||||
Also, repair any damage from a false match due to a leap second. */
|
||||
int sec_adjustment = (sec == 0 && tm.tm_sec == 60) - sec;
|
||||
t1 = t + sec_requested;
|
||||
t2 = t1 + sec_adjustment;
|
||||
if (((t1 < t) != (sec_requested < 0))
|
||||
| ((t2 < t1) != (sec_adjustment < 0))
|
||||
| ! convert (&t2, &tm))
|
||||
return -1;
|
||||
t = t2;
|
||||
}
|
||||
|
||||
*tp = tm;
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Convert *TP to a time_t value. */
|
||||
time_t
|
||||
mktime (struct tm *tp)
|
||||
{
|
||||
// no time zone stuff. Just do the math ;)
|
||||
static time_t localtime_offset;
|
||||
return __mktime_internal (tp, __localtime_r, &localtime_offset);
|
||||
}
|
||||
|
||||
/* Fill a (struct tm) TP* from a given time_t time stamp */
|
||||
time_t
|
||||
filltm(time_t *t, struct tm *tp)
|
||||
{
|
||||
return __offtime(t, 0, tp);
|
||||
}
|
||||
|
34
src/time.h
Normal file
34
src/time.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#ifndef g9x_time_h
|
||||
#define g9x_time_h
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#define CHAR_BIT 8
|
||||
#define INT_MAX 32767
|
||||
#define INT_MIN -32767
|
||||
#define LONG_MAX 0x7FFFFFFFL
|
||||
#define LONG_MIN ((long) 0x80000000L)
|
||||
#define UINT_MAX 0xFFFFU/0xFFFFFFFFUL
|
||||
#define ULONG_MAX 0xFFFFFFFFUL
|
||||
|
||||
typedef long int time_t;
|
||||
|
||||
struct tm
|
||||
{
|
||||
int8_t tm_sec; /* Seconds. [0-60] (1 leap second) */
|
||||
int8_t tm_min; /* Minutes. [0-59] */
|
||||
int8_t tm_hour; /* Hours. [0-23] */
|
||||
int8_t tm_mday; /* Day. [1-31] */
|
||||
int8_t tm_mon; /* Month. [0-11] */
|
||||
int8_t tm_year; /* Year - 1900. Limited to the year 2115. Oh no! :P */
|
||||
int8_t tm_wday; /* Day of week. [0-6] */
|
||||
int16_t tm_yday; /* Day of year. [0-365] Needed internally for calculations */
|
||||
};
|
||||
|
||||
extern const unsigned short int __mon_yday[2][13];
|
||||
|
||||
extern time_t mktime(struct tm *tp);
|
||||
extern time_t filltm(time_t *t, struct tm *tp);
|
||||
|
||||
#endif
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue