mirror of
https://github.com/opentx/opentx.git
synced 2025-07-22 07:45:14 +03:00
Last changes to gruvin9x
This commit is contained in:
parent
3772179692
commit
2b4823ab84
12 changed files with 927 additions and 563 deletions
53
src/Makefile
53
src/Makefile
|
@ -72,6 +72,22 @@ DECIMALS = NO
|
||||||
# Values = YES, NO
|
# Values = YES, NO
|
||||||
TRANSLATIONS = YES
|
TRANSLATIONS = YES
|
||||||
|
|
||||||
|
# DISPLAY_USER_DATA to display on screen data from FrSky module (testing/demo purpose)
|
||||||
|
# Values = YES, NO
|
||||||
|
DISPLAY_USER_DATA = NO
|
||||||
|
|
||||||
|
# PXX (FrSky PCM) protocol
|
||||||
|
PXX = NO
|
||||||
|
|
||||||
|
# DSM2 (Spektrum) protocol
|
||||||
|
DSM2 = YES
|
||||||
|
|
||||||
|
# Silver protocol
|
||||||
|
SILVER = NO
|
||||||
|
|
||||||
|
# CTP-1009 protocol
|
||||||
|
CTP1009 = NO
|
||||||
|
|
||||||
#------- END BUILD OPTIONS ---------------------------
|
#------- END BUILD OPTIONS ---------------------------
|
||||||
|
|
||||||
# MCU name
|
# MCU name
|
||||||
|
@ -98,16 +114,12 @@ TARGET = gruvin9x
|
||||||
OBJDIR = obj
|
OBJDIR = obj
|
||||||
|
|
||||||
# List C++ source files here. (C dependencies are automatically generated.)
|
# 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
|
CPPSRC = gruvin9x.cpp pulses.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
|
||||||
|
|
||||||
ifeq ($(EXT), JETI)
|
ifeq ($(EXT), JETI)
|
||||||
CPPSRC += jeti.cpp
|
CPPSRC += jeti.cpp
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(EXT), FRSKY)
|
|
||||||
CPPSRC += frsky.cpp
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Disk IO support (PCB V2+ only)
|
# Disk IO support (PCB V2+ only)
|
||||||
ifneq ($(PCB), STD)
|
ifneq ($(PCB), STD)
|
||||||
CPPSRC += time.cpp
|
CPPSRC += time.cpp
|
||||||
|
@ -166,10 +178,13 @@ CPPDEFS = -DF_CPU=$(F_CPU)UL
|
||||||
# NOTE: PCB version now overrides all the earlier individual settings
|
# NOTE: PCB version now overrides all the earlier individual settings
|
||||||
# These individual settings work only for PCB=STD
|
# These individual settings work only for PCB=STD
|
||||||
|
|
||||||
|
CPPDEFS += -DEEPROM_ASYNC_WRITE
|
||||||
|
|
||||||
ifeq ($(PCB), STD)
|
ifeq ($(PCB), STD)
|
||||||
# STD PCB, so ...
|
# STD PCB, so ...
|
||||||
|
|
||||||
CPPDEFS += -DPCBSTD -DEEPROM_ASYNC_WRITE
|
CPPDEFS += -DPCBSTD
|
||||||
|
|
||||||
# If Hardware PPM mode ( PB0<->BP7) switch the Backlight output with the original PPM to use hardware facility to generate precise PPM (hardware mods)
|
# If Hardware PPM mode ( PB0<->BP7) switch the Backlight output with the original PPM to use hardware facility to generate precise PPM (hardware mods)
|
||||||
# G: TODO This prevents HARDPPM being used with FRSKY. HARDPPM needs its own option XXX
|
# G: TODO This prevents HARDPPM being used with FRSKY. HARDPPM needs its own option XXX
|
||||||
ifeq ($(EXT), HARDPPM)
|
ifeq ($(EXT), HARDPPM)
|
||||||
|
@ -184,11 +199,13 @@ ifeq ($(PCB), STD)
|
||||||
# If FRSKY-Support is enabled
|
# If FRSKY-Support is enabled
|
||||||
ifeq ($(EXT), FRSKY)
|
ifeq ($(EXT), FRSKY)
|
||||||
CPPDEFS += -DFRSKY -DFRSKY_HUB
|
CPPDEFS += -DFRSKY -DFRSKY_HUB
|
||||||
|
CPPSRC += frsky.cpp
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# If FRSKY-Support is enabled
|
# If FRSKY-Support is enabled
|
||||||
ifeq ($(EXT), FRSKY_NOHUB)
|
ifeq ($(EXT), FRSKY_NOHUB)
|
||||||
CPPDEFS += -DFRSKY
|
CPPDEFS += -DFRSKY
|
||||||
|
CPPSRC += frsky.cpp
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# gruvin: If buzzer speaker replacment supported
|
# gruvin: If buzzer speaker replacment supported
|
||||||
|
@ -254,6 +271,25 @@ ifeq ($(TEMPLATES), YES)
|
||||||
CPPSRC += templates.cpp
|
CPPSRC += templates.cpp
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(DISPLAY_USER_DATA), YES)
|
||||||
|
CPPDEFS += -DDISPLAY_USER_DATA
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(PXX), YES)
|
||||||
|
CPPDEFS += -DPXX
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(DSM2), YES)
|
||||||
|
CPPDEFS += -DDSM2
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(SILVER), YES)
|
||||||
|
CPPDEFS += -DSILVER
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CTP1009), YES)
|
||||||
|
CPPDEFS += -DCTP1009
|
||||||
|
endif
|
||||||
|
|
||||||
#---------------- Compiler Options C ----------------
|
#---------------- Compiler Options C ----------------
|
||||||
# -g*: generate debugging information
|
# -g*: generate debugging information
|
||||||
|
@ -661,7 +697,10 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
simu: $(CPPSRC) Makefile simu.cpp $(CPPSRC) simpgmspace.cpp *.h *.lbm eeprom.bin
|
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
|
g++ simu.cpp $(CPPFLAGS) $(CPPSRC) simpgmspace.cpp $(ARCH) -MD -DSIMU -o simu $(FOXINC) $(FOXLIB)
|
||||||
|
|
||||||
|
gruvin9x.so: $(CPPSRC) Makefile export.cpp $(CPPSRC) simpgmspace.cpp *.h *.lbm
|
||||||
|
g++ export.cpp $(CPPFLAGS) $(CPPSRC) simpgmspace.cpp $(ARCH) -g -MD -DSIMU -shared -fPIC -Wl,-soname,$@ -o $@
|
||||||
|
|
||||||
eeprom.bin:
|
eeprom.bin:
|
||||||
dd if=/dev/zero of=$@ bs=1 count=2048
|
dd if=/dev/zero of=$@ bs=1 count=2048
|
||||||
|
|
61
src/export.cpp
Normal file
61
src/export.cpp
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Authors (alphabetical 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 "simpgmspace.h"
|
||||||
|
#include "lcd.h"
|
||||||
|
#include "gruvin9x.h"
|
||||||
|
#include "menus.h"
|
||||||
|
|
||||||
|
int16_t g_anas[NUM_STICKS+NUM_POTS];
|
||||||
|
uint8_t *g_switches[MAX_PSWITCH];
|
||||||
|
extern uint8_t eeprom[EESIZE];
|
||||||
|
|
||||||
|
extern "C" void initGruvin9x(uint8_t *_eeprom)
|
||||||
|
{
|
||||||
|
eepromFile = NULL; // in memory
|
||||||
|
memcpy(eeprom, _eeprom, sizeof(eeprom));
|
||||||
|
|
||||||
|
g_menuStack[0] = menuMainView;
|
||||||
|
g_menuStack[1] = menuProcModelSelect;
|
||||||
|
eeReadAll(); //load general setup and selected model
|
||||||
|
// TODO
|
||||||
|
//checkLowEEPROM(); //enough eeprom free?
|
||||||
|
//checkTHR();
|
||||||
|
//checkSwitches(); //must be last
|
||||||
|
//state = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void runGruvin9x(int16_t *anas, uint8_t *switches, int16_t *chans, uint8_t *display)
|
||||||
|
{
|
||||||
|
memcpy(g_anas, anas, sizeof(uint16_t) * NUM_STICKS+NUM_POTS);
|
||||||
|
memcpy(g_switches, switches, sizeof(uint8_t) * MAX_PSWITCH);
|
||||||
|
|
||||||
|
g_tmr10ms++;
|
||||||
|
perMain();
|
||||||
|
|
||||||
|
memcpy(chans, g_chans512, sizeof(g_chans512));
|
||||||
|
memcpy(display, displayBuf, sizeof(displayBuf));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t anaIn(uint8_t chan)
|
||||||
|
{
|
||||||
|
// printf("anaIn(%d) => %d\n", chan, g_anas[chan]); fflush(stdout);
|
||||||
|
return g_anas[chan];
|
||||||
|
}
|
399
src/gruvin9x.cpp
399
src/gruvin9x.cpp
|
@ -55,6 +55,8 @@ uint8_t toneOn = false;
|
||||||
|
|
||||||
bool warble = false;
|
bool warble = false;
|
||||||
|
|
||||||
|
uint8_t heartbeat;
|
||||||
|
|
||||||
const prog_char APM modi12x3[]=
|
const prog_char APM modi12x3[]=
|
||||||
"RUD ELE THR AIL "
|
"RUD ELE THR AIL "
|
||||||
"RUD THR ELE AIL "
|
"RUD THR ELE AIL "
|
||||||
|
@ -295,8 +297,8 @@ void applyExpos(int16_t *anas)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool s_noStickInputs = false;
|
bool s_noStickInputs = false;
|
||||||
inline int16_t getValue(uint8_t i)
|
inline int16_t __attribute__ ((always_inline)) getValue(uint8_t i)
|
||||||
{
|
{
|
||||||
if(i<NUM_STICKS+NUM_POTS) return (s_noStickInputs ? 0 : calibratedStick[i]);
|
if(i<NUM_STICKS+NUM_POTS) return (s_noStickInputs ? 0 : calibratedStick[i]);
|
||||||
else if(i<MIX_FULL/*srcRaw is shifted +1!*/) return 1024; //FULL/MAX
|
else if(i<MIX_FULL/*srcRaw is shifted +1!*/) return 1024; //FULL/MAX
|
||||||
|
@ -309,6 +311,118 @@ inline int16_t getValue(uint8_t i)
|
||||||
else return 0;
|
else return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
volatile uint16_t s_last_switch_used;
|
||||||
|
volatile uint16_t s_last_switch_value;
|
||||||
|
bool __getSwitch(int8_t swtch)
|
||||||
|
{
|
||||||
|
bool result;
|
||||||
|
|
||||||
|
if (swtch == 0)
|
||||||
|
return s_last_switch_used & (1<<15);
|
||||||
|
|
||||||
|
uint8_t cs_idx = abs(swtch);
|
||||||
|
|
||||||
|
if (cs_idx == MAX_SWITCH) {
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
else if (cs_idx < MAX_SWITCH-NUM_CSW) {
|
||||||
|
result = keyState((EnumKeys)(SW_BASE+cs_idx-1));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cs_idx -= MAX_SWITCH-NUM_CSW;
|
||||||
|
volatile CustomSwData &cs = g_model.customSw[cs_idx];
|
||||||
|
if (cs.func == CS_OFF) return false;
|
||||||
|
|
||||||
|
uint8_t s = CS_STATE(cs.func);
|
||||||
|
if (s == CS_VBOOL) {
|
||||||
|
uint16_t mask = (1 << cs_idx);
|
||||||
|
if (s_last_switch_used & mask) {
|
||||||
|
result = (s_last_switch_value & mask);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s_last_switch_used |= mask;
|
||||||
|
bool res1 = __getSwitch(cs.v1);
|
||||||
|
bool res2 = __getSwitch(cs.v2);
|
||||||
|
switch (cs.func) {
|
||||||
|
case CS_AND:
|
||||||
|
result = (res1 && res2);
|
||||||
|
break;
|
||||||
|
case CS_OR:
|
||||||
|
result = (res1 || res2);
|
||||||
|
break;
|
||||||
|
// case CS_XOR:
|
||||||
|
default:
|
||||||
|
result = (res1 ^ res2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result)
|
||||||
|
s_last_switch_value |= (1<<cs_idx);
|
||||||
|
else
|
||||||
|
s_last_switch_value &= ~(1<<cs_idx);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int16_t x = getValue(cs.v1-1);
|
||||||
|
int16_t y;
|
||||||
|
if (s == CS_VOFS) {
|
||||||
|
#ifdef FRSKY
|
||||||
|
if (cs.v1 > CHOUT_BASE+NUM_CHNOUT)
|
||||||
|
y = 125+cs.v2;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
y = calc100toRESX(cs.v2);
|
||||||
|
|
||||||
|
switch (cs.func) {
|
||||||
|
case CS_VPOS:
|
||||||
|
result = (x>y);
|
||||||
|
break;
|
||||||
|
case CS_VNEG:
|
||||||
|
result = (x<y);
|
||||||
|
break;
|
||||||
|
case CS_APOS:
|
||||||
|
result = (abs(x)>y);
|
||||||
|
break;
|
||||||
|
// case CS_ANEG:
|
||||||
|
default:
|
||||||
|
result = (abs(x)<y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
y = getValue(cs.v2-1);
|
||||||
|
|
||||||
|
switch (cs.func) {
|
||||||
|
case CS_EQUAL:
|
||||||
|
result = (x==y);
|
||||||
|
break;
|
||||||
|
case CS_NEQUAL:
|
||||||
|
result = (x!=y);
|
||||||
|
break;
|
||||||
|
case CS_GREATER:
|
||||||
|
result = (x>y);
|
||||||
|
break;
|
||||||
|
case CS_LESS:
|
||||||
|
result = (x<y);
|
||||||
|
break;
|
||||||
|
case CS_EGREATER:
|
||||||
|
result = (x>=y);
|
||||||
|
break;
|
||||||
|
// case CS_ELESS:
|
||||||
|
default:
|
||||||
|
result = (x<=y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return swtch > 0 ? result : !result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getSwitch(int8_t swtch, bool nc)
|
||||||
|
{
|
||||||
|
s_last_switch_used = (nc<<15);
|
||||||
|
return __getSwitch(swtch);
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t getFlightPhase()
|
uint8_t getFlightPhase()
|
||||||
{
|
{
|
||||||
for (uint8_t i=1; i<MAX_PHASES; i++) {
|
for (uint8_t i=1; i<MAX_PHASES; i++) {
|
||||||
|
@ -349,119 +463,6 @@ uint8_t getTrimFlightPhase(uint8_t idx, int8_t phase) // TODO uint8_t phase?
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getSwitch(int8_t swtch, bool nc, uint8_t level)
|
|
||||||
{
|
|
||||||
if(level>5) return false; //prevent recursive loop going too deep
|
|
||||||
|
|
||||||
switch(swtch){
|
|
||||||
case 0: return nc;
|
|
||||||
case MAX_SWITCH: return true;
|
|
||||||
case -MAX_SWITCH: return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t dir = swtch>0;
|
|
||||||
if(abs(swtch)<(MAX_SWITCH-NUM_CSW)) {
|
|
||||||
if(!dir) return ! keyState((EnumKeys)(SW_BASE-swtch-1));
|
|
||||||
return keyState((EnumKeys)(SW_BASE+swtch-1));
|
|
||||||
}
|
|
||||||
|
|
||||||
//custom switch, Issue 78
|
|
||||||
//use putsChnRaw
|
|
||||||
//input -> 1..4 -> sticks, 5..8 pots
|
|
||||||
//MAX,FULL - disregard
|
|
||||||
//ppm
|
|
||||||
CustomSwData &cs = g_model.customSw[abs(swtch)-(MAX_SWITCH-NUM_CSW)];
|
|
||||||
if(!cs.func) return false;
|
|
||||||
|
|
||||||
|
|
||||||
int8_t a = cs.v1;
|
|
||||||
int8_t b = cs.v2;
|
|
||||||
int16_t x = 0;
|
|
||||||
int16_t y = 0;
|
|
||||||
|
|
||||||
// init values only if needed
|
|
||||||
uint8_t s = CS_STATE(cs.func);
|
|
||||||
if(s == CS_VOFS)
|
|
||||||
{
|
|
||||||
x = getValue(cs.v1-1);
|
|
||||||
#ifdef FRSKY
|
|
||||||
if (cs.v1 > CHOUT_BASE+NUM_CHNOUT)
|
|
||||||
y = 125+cs.v2;
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
y = calc100toRESX(cs.v2);
|
|
||||||
}
|
|
||||||
else if(s == CS_VCOMP)
|
|
||||||
{
|
|
||||||
x = getValue(cs.v1-1);
|
|
||||||
y = getValue(cs.v2-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (cs.func) {
|
|
||||||
case (CS_VPOS):
|
|
||||||
return swtch>0 ? (x>y) : !(x>y);
|
|
||||||
break;
|
|
||||||
case (CS_VNEG):
|
|
||||||
return swtch>0 ? (x<y) : !(x<y);
|
|
||||||
break;
|
|
||||||
case (CS_APOS):
|
|
||||||
{
|
|
||||||
bool res = (abs(x)>y) ;
|
|
||||||
return swtch>0 ? res : !res ;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case (CS_ANEG):
|
|
||||||
{
|
|
||||||
bool res = (abs(x)<y) ;
|
|
||||||
return swtch>0 ? res : !res ;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case (CS_AND):
|
|
||||||
case (CS_OR):
|
|
||||||
case (CS_XOR):
|
|
||||||
{
|
|
||||||
bool res1 = getSwitch(a,0,level+1) ;
|
|
||||||
bool res2 = getSwitch(b,0,level+1) ;
|
|
||||||
if ( cs.func == CS_AND )
|
|
||||||
{
|
|
||||||
return res1 && res2 ;
|
|
||||||
}
|
|
||||||
else if ( cs.func == CS_OR )
|
|
||||||
{
|
|
||||||
return res1 || res2 ;
|
|
||||||
}
|
|
||||||
else // CS_XOR
|
|
||||||
{
|
|
||||||
return res1 ^ res2 ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case (CS_EQUAL):
|
|
||||||
return (x==y);
|
|
||||||
case (CS_NEQUAL):
|
|
||||||
return (x!=y);
|
|
||||||
case (CS_GREATER):
|
|
||||||
return (x>y);
|
|
||||||
case (CS_LESS):
|
|
||||||
return (x<y);
|
|
||||||
case (CS_EGREATER):
|
|
||||||
return (x>=y);
|
|
||||||
case (CS_ELESS):
|
|
||||||
return (x<=y);
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//#define CS_EQUAL 8
|
|
||||||
//#define CS_NEQUAL 9
|
|
||||||
//#define CS_GREATER 10
|
|
||||||
//#define CS_LESS 11
|
|
||||||
//#define CS_EGREATER 12
|
|
||||||
//#define CS_ELESS 13
|
|
||||||
|
|
||||||
#if defined (PCBV3) && !defined (PCBV4)
|
#if defined (PCBV3) && !defined (PCBV4)
|
||||||
// The ugly scanned keys thing should be gone for PCBV4+. In the meantime ...
|
// The ugly scanned keys thing should be gone for PCBV4+. In the meantime ...
|
||||||
uint8_t keyDown()
|
uint8_t keyDown()
|
||||||
|
@ -1084,7 +1085,6 @@ uint16_t isqrt32(uint32_t n)
|
||||||
|
|
||||||
// static variables used in perOut - moved here so they don't interfere with the stack
|
// static variables used in perOut - moved here so they don't interfere with the stack
|
||||||
// It's also easier to initialize them here.
|
// It's also easier to initialize them here.
|
||||||
uint16_t pulses2MHz[120] = {0};
|
|
||||||
int16_t anas [NUM_XCHNRAW] = {0};
|
int16_t anas [NUM_XCHNRAW] = {0};
|
||||||
int16_t trims[NUM_STICKS] = {0};
|
int16_t trims[NUM_STICKS] = {0};
|
||||||
int32_t chans[NUM_CHNOUT] = {0};
|
int32_t chans[NUM_CHNOUT] = {0};
|
||||||
|
@ -1654,70 +1654,6 @@ uint8_t ppmInState = 0; //0=unsync 1..8= wait for value i-1
|
||||||
|
|
||||||
#ifndef SIMU
|
#ifndef SIMU
|
||||||
|
|
||||||
#define HEART_TIMER2Mhz 1;
|
|
||||||
#define HEART_TIMER10ms 2;
|
|
||||||
|
|
||||||
uint8_t heartbeat;
|
|
||||||
|
|
||||||
|
|
||||||
ISR(TIMER1_COMPA_vect) //2MHz pulse generation
|
|
||||||
{
|
|
||||||
static uint8_t pulsePol;
|
|
||||||
static uint16_t *pulsePtr = pulses2MHz;
|
|
||||||
|
|
||||||
// TODO understand what Bryan did here
|
|
||||||
uint8_t i = 0;
|
|
||||||
while((TCNT1L < 10) && (++i < 50)) // Timer does not read too fast, so i
|
|
||||||
;
|
|
||||||
uint16_t dt=TCNT1;//-OCR1A;
|
|
||||||
|
|
||||||
//vinceofdrink@gmail harwared ppm
|
|
||||||
//Orginal bitbang for PPM
|
|
||||||
#ifndef DPPMPB7_HARDWARE
|
|
||||||
if(pulsePol)
|
|
||||||
{
|
|
||||||
PORTB |= (1<<OUT_B_PPM); // GCC optimisation should result in a single SBI instruction
|
|
||||||
pulsePol = 0;
|
|
||||||
}else{
|
|
||||||
PORTB &= ~(1<<OUT_B_PPM); // GCC optimisation should result in a single CBI instruction
|
|
||||||
pulsePol = 1;
|
|
||||||
}
|
|
||||||
g_tmr1Latency_max = max(dt,g_tmr1Latency_max); // max has leap, therefore vary in length
|
|
||||||
g_tmr1Latency_min = min(dt,g_tmr1Latency_min); // min has leap, therefore vary in length
|
|
||||||
#endif
|
|
||||||
OCR1A = *pulsePtr++;
|
|
||||||
|
|
||||||
//vinceofdrink@gmail harwared ppm
|
|
||||||
#if defined (DPPMPB7_HARDWARE)
|
|
||||||
OCR1C=OCR1A; //just copy the value of the OCR1A to OCR1C to test PPM out without to much change in the code not optimum but will not alter ppm precision
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( *pulsePtr == 0) {
|
|
||||||
//currpulse=0;
|
|
||||||
pulsePtr = pulses2MHz;
|
|
||||||
pulsePol = g_model.pulsePol;//0;
|
|
||||||
|
|
||||||
cli();
|
|
||||||
#if defined (PCBV3)
|
|
||||||
TIMSK1 &= ~(1<<OCIE1A); //stop reentrance
|
|
||||||
#else
|
|
||||||
TIMSK &= ~(1<<OCIE1A); //stop reentrance
|
|
||||||
#endif
|
|
||||||
sei();
|
|
||||||
|
|
||||||
setupPulses();
|
|
||||||
|
|
||||||
cli();
|
|
||||||
#if defined (PCBV3)
|
|
||||||
TIMSK1 |= (1<<OCIE1A);
|
|
||||||
#else
|
|
||||||
TIMSK |= (1<<OCIE1A);
|
|
||||||
#endif
|
|
||||||
sei();
|
|
||||||
}
|
|
||||||
heartbeat |= HEART_TIMER2Mhz;
|
|
||||||
}
|
|
||||||
|
|
||||||
volatile uint8_t g_tmr16KHz; //continuous timer 16ms (16MHz/1024/256) -- 8-bit counter overflow
|
volatile uint8_t g_tmr16KHz; //continuous timer 16ms (16MHz/1024/256) -- 8-bit counter overflow
|
||||||
#if defined (PCBV3)
|
#if defined (PCBV3)
|
||||||
ISR(TIMER2_OVF_vect)
|
ISR(TIMER2_OVF_vect)
|
||||||
|
@ -1753,9 +1689,9 @@ ISR(TIMER0_COMP_vect, ISR_NOBLOCK) //10ms timer
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
cli();
|
cli();
|
||||||
|
#if defined (PCBV3)
|
||||||
static uint8_t accuracyWarble = 4; // becasue 16M / 1024 / 100 = 156.25. So bump every 4.
|
static uint8_t accuracyWarble = 4; // becasue 16M / 1024 / 100 = 156.25. So bump every 4.
|
||||||
uint8_t bump = (!(accuracyWarble++ & 0x03)) ? 157 : 156;
|
uint8_t bump = (!(accuracyWarble++ & 0x03)) ? 157 : 156;
|
||||||
#if defined (PCBV3)
|
|
||||||
TIMSK2 &= ~(1<<OCIE2A); //stop reentrance
|
TIMSK2 &= ~(1<<OCIE2A); //stop reentrance
|
||||||
OCR2A += bump;
|
OCR2A += bump;
|
||||||
#else
|
#else
|
||||||
|
@ -1763,6 +1699,8 @@ ISR(TIMER0_COMP_vect, ISR_NOBLOCK) //10ms timer
|
||||||
#if defined (BEEPSPKR)
|
#if defined (BEEPSPKR)
|
||||||
OCR0 += 2; // run much faster, to generate speaker tones
|
OCR0 += 2; // run much faster, to generate speaker tones
|
||||||
#else
|
#else
|
||||||
|
static uint8_t accuracyWarble = 4; // becasue 16M / 1024 / 100 = 156.25. So bump every 4.
|
||||||
|
uint8_t bump = (!(accuracyWarble++ & 0x03)) ? 157 : 156;
|
||||||
OCR0 += bump;
|
OCR0 += bump;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
@ -2055,6 +1993,32 @@ void moveTrimsToOffsets() // copy state of 3 primary to subtrim
|
||||||
beepWarn1();
|
beepWarn1();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined (PCBV4)
|
||||||
|
// Rotary encoder interrupts
|
||||||
|
uint8_t volatile g_rotenc1, g_rotenc2 = 0;
|
||||||
|
ISR(INT2_vect)
|
||||||
|
{
|
||||||
|
uint8_t input = PIND & 0b00001100;
|
||||||
|
if (input == 0 || input == 0b00001100) g_rotenc1--;
|
||||||
|
}
|
||||||
|
ISR(INT3_vect)
|
||||||
|
{
|
||||||
|
uint8_t input = PIND & 0b00001100;
|
||||||
|
if (input == 0 || input == 0b00001100) g_rotenc1++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ISR(INT5_vect)
|
||||||
|
{
|
||||||
|
uint8_t input = PINE & 0b01100000;
|
||||||
|
if (input == 0 || input == 0b01100000) g_rotenc2++;
|
||||||
|
}
|
||||||
|
ISR(INT6_vect)
|
||||||
|
{
|
||||||
|
uint8_t input = PINE & 0b01100000;
|
||||||
|
if (input == 0 || input == 0b01100000) g_rotenc2--;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef SIMU
|
#ifndef SIMU
|
||||||
|
|
||||||
extern unsigned char __bss_end ;
|
extern unsigned char __bss_end ;
|
||||||
|
@ -2077,13 +2041,13 @@ int main(void)
|
||||||
DDRA = 0xff; PORTA = 0x00; // LCD data
|
DDRA = 0xff; PORTA = 0x00; // LCD data
|
||||||
|
|
||||||
#if defined (PCBV4)
|
#if defined (PCBV4)
|
||||||
DDRB = 0b11000111; PORTB = 0b00111001; // 7:SPKR, 6:PPM_OUT, 5:TrainSW, 4:IDL2_SW, SDCARD[3:MISO 2:MOSI 1:SCK 0:CS]
|
DDRB = 0b11000111; PORTB = 0b00111111; // 7:SPKR, 6:PPM_OUT, 5:TrainSW, 4:IDL2_SW, SDCARD[3:MISO 2:MOSI 1:SCK 0:CS]
|
||||||
DDRC = 0x3f; PORTC = 0xc0; // 7:AilDR, 6:EleDR, LCD[5,4,3,2,1[, 0:BackLight
|
DDRC = 0x3f; PORTC = 0xc0; // 7:AilDR, 6:EleDR, LCD[5,4,3,2,1], 0:BackLight
|
||||||
DDRD = 0x00; PORTD = 0xfc; // 7/6:Spare3/4, 5:RENC2_PUSH, 4:RENC1_PUSH, 3:RENC2_B, 2:RENC2_A, 1:I2C_SDA, 0:I2C_SCL
|
DDRD = 0x00; PORTD = 0b11111100; // 7/6:Spare3/4, 5:RENC2_PUSH, 4:RENC1_PUSH, 3:RENC2_B, 2:RENC2_A, 1:I2C_SDA, 0:I2C_SCL
|
||||||
DDRE = 0b00001010; PORTE = 0b11110101; // 7:PPM_IN, 6: RENC1_B, 5:RENC1_A, 4:USB_DNEG, 3:BUZZER, 2:USB_DPOS, 1:TELEM_TX, 0:TELEM_RX
|
DDRE = 0b00001010; PORTE = 0b11110101; // 7:PPM_IN, 6: RENC1_B, 5:RENC1_A, 4:USB_DNEG, 3:BUZZER, 2:USB_DPOS, 1:TELEM_TX, 0:TELEM_RX
|
||||||
DDRF = 0x00; PORTF = 0x00; // 7-4:JTAG, 3:ADC_REF_1.2V input, 2-0:ADC_SPARE_2-0
|
DDRF = 0x00; PORTF = 0x00; // 7-4:JTAG, 3:ADC_REF_1.2V input, 2-0:ADC_SPARE_2-0
|
||||||
DDRG = 0b00010000; PORTG = 0xff; // 7-6:N/A, 5:GearSW, 4: Sim_Ctrl[out], 3:IDL1_Sw, 2:TCut_Sw, 1:RF_Power[in], 0: RudDr_Sw
|
DDRG = 0b00010000; PORTG = 0xff; // 7-6:N/A, 5:GearSW, 4: Sim_Ctrl[out], 3:IDL1_Sw, 2:TCut_Sw, 1:RF_Power[in], 0: RudDr_Sw
|
||||||
DDRH = 0x00; PORTH = 0xff; // 7:0 Spare port -- all inputer for now [Bit 2:VIB_OPTION -- setting to input for now]
|
DDRH = 0x00; PORTH = 0xff; // 7:0 Spare port -- all inputs for now [Bit 2:VIB_OPTION -- setting to input for now]
|
||||||
DDRJ = 0x00; PORTJ = 0xff; // 7-0:Trim switch inputs
|
DDRJ = 0x00; PORTJ = 0xff; // 7-0:Trim switch inputs
|
||||||
DDRK = 0x00; PORTK = 0x00; // anain. No pull-ups!
|
DDRK = 0x00; PORTK = 0x00; // anain. No pull-ups!
|
||||||
DDRL = 0x00; PORTL = 0xff; // 7-6:Spare6/5 (inputs), 5-0: User Button inputs
|
DDRL = 0x00; PORTL = 0xff; // 7-6:Spare6/5 (inputs), 5-0: User Button inputs
|
||||||
|
@ -2218,15 +2182,6 @@ int main(void)
|
||||||
|
|
||||||
clearKeyEvents(); //make sure no keys are down before proceeding
|
clearKeyEvents(); //make sure no keys are down before proceeding
|
||||||
|
|
||||||
//addon Vinceofdrink@gmail (hardware ppm)
|
|
||||||
#if defined (DPPMPB7_HARDWARE)
|
|
||||||
TCCR1A |=(1<<COM1C0); // (COM1C1=0 and COM1C0=1 in TCCR1A) toogle the state of PB7 on each TCNT1=OCR1C
|
|
||||||
#endif
|
|
||||||
|
|
||||||
setupPulses();
|
|
||||||
|
|
||||||
wdt_enable(WDTO_500MS);
|
|
||||||
|
|
||||||
perOut(g_chans512);
|
perOut(g_chans512);
|
||||||
|
|
||||||
lcdSetRefVolt(g_eeGeneral.contrast);
|
lcdSetRefVolt(g_eeGeneral.contrast);
|
||||||
|
@ -2234,14 +2189,6 @@ int main(void)
|
||||||
|
|
||||||
if(cModel!=g_eeGeneral.currModel) eeDirty(EE_GENERAL); // if model was quick-selected, make sure it sticks
|
if(cModel!=g_eeGeneral.currModel) eeDirty(EE_GENERAL); // if model was quick-selected, make sure it sticks
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if defined (PCBV3)
|
|
||||||
TIMSK1 |= (1<<OCIE1A); // Pulse generator enable immediately before mainloop
|
|
||||||
#else
|
|
||||||
TIMSK |= (1<<OCIE1A); // Pulse generator enable immediately before mainloop
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined (PCBV3)
|
#if defined (PCBV3)
|
||||||
// Initialise global unix timestamp with current time from RTC chip on SD card interface
|
// Initialise global unix timestamp with current time from RTC chip on SD card interface
|
||||||
RTC rtc;
|
RTC rtc;
|
||||||
|
@ -2257,6 +2204,54 @@ int main(void)
|
||||||
g_unixTime = mktime(&utm);
|
g_unixTime = mktime(&utm);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined (PCBV4)
|
||||||
|
/***************************************************/
|
||||||
|
/* Rotary encoder interrupt set-up (V4 board only) */
|
||||||
|
|
||||||
|
// All external interrupts initialise to disabled. But maybe not after
|
||||||
|
// a WDT or BOD event? So to be safe ...
|
||||||
|
EIMSK = 0; // disable ALL external interrupts.
|
||||||
|
|
||||||
|
// encoder 1
|
||||||
|
EICRB = (1<<ISC60) | (1<<ISC50); // 01 = interrupt on any edge
|
||||||
|
EIFR = (3<<INTF5); // clear the int. flag in case it got set when changing modes
|
||||||
|
|
||||||
|
// encoder 2
|
||||||
|
EICRA = (1<<ISC30) | (1<<ISC20); // do the same for encoder 1
|
||||||
|
EIFR = (3<<INTF2);
|
||||||
|
|
||||||
|
EIMSK = (3<<INT5) | (3<<INT2); // enable the two rot. enc. ext. int. pairs.
|
||||||
|
/***************************************************/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/***********************************************************/
|
||||||
|
/*** Keep this code block directly before the main loop ****/
|
||||||
|
|
||||||
|
setupPulses();
|
||||||
|
|
||||||
|
#if defined (PCBV4)
|
||||||
|
OCR1B = 0xffff; /* Prevent any PPM_PUT pin toggle before the TCNT1 interrupt
|
||||||
|
fires for the first time and sets up the pulse period. */
|
||||||
|
// TCCR1A |= (1<<COM1B0); // (COM1B1=0 and COM1B0=1 in TCCR1A) toogle the state of PB6(OC1B) on each TCNT1==OCR1B
|
||||||
|
TCCR1A = (3<<COM1B0); // Connect OC1B to PPM_OUT pin (SET the state of PB6(OC1B) on next TCNT1==OCR1B)
|
||||||
|
#else
|
||||||
|
//addon Vinceofdrink@gmail (hardware ppm)
|
||||||
|
# if defined (DPPMPB7_HARDWARE)
|
||||||
|
OCR1C = 0xffff; // See comment for PCBV4, above
|
||||||
|
TCCR1A |= (1<<COM1C0); // (COM1C1=0 and COM1C0=1 in TCCR1A) toogle the state of PB7(OC1C) on each TCNT1==OCR1C
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined (PCBV3)
|
||||||
|
TIMSK1 |= (1<<OCIE1A); // Pulse generator enable immediately before mainloop
|
||||||
|
#else
|
||||||
|
TIMSK |= (1<<OCIE1A); // Pulse generator enable immediately before mainloop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
wdt_enable(WDTO_500MS);
|
||||||
|
/*** Keep this code block directly before the main loop ****/
|
||||||
|
/***********************************************************/
|
||||||
|
|
||||||
while(1){
|
while(1){
|
||||||
uint16_t t0 = getTmr16KHz();
|
uint16_t t0 = getTmr16KHz();
|
||||||
getADC[g_eeGeneral.filterInput]();
|
getADC[g_eeGeneral.filterInput]();
|
||||||
|
|
|
@ -393,6 +393,8 @@ enum EnumKeys {
|
||||||
#define EVT_ENTRY_UP (0xfe - _MSK_KEY_REPT)
|
#define EVT_ENTRY_UP (0xfe - _MSK_KEY_REPT)
|
||||||
#define EVT_KEY_MASK 0x0f
|
#define EVT_KEY_MASK 0x0f
|
||||||
|
|
||||||
|
#define HEART_TIMER2Mhz 1
|
||||||
|
#define HEART_TIMER10ms 2
|
||||||
|
|
||||||
#define TMRMODE_NONE 0
|
#define TMRMODE_NONE 0
|
||||||
#define TMRMODE_ABS 1
|
#define TMRMODE_ABS 1
|
||||||
|
@ -401,14 +403,18 @@ enum EnumKeys {
|
||||||
#define MAX_ALERT_TIME 60
|
#define MAX_ALERT_TIME 60
|
||||||
|
|
||||||
#define PROTO_PPM 0
|
#define PROTO_PPM 0
|
||||||
#define PROTO_SILV_A 1
|
#define PROTO_PXX 1
|
||||||
#define PROTO_SILV_B 2
|
#define PROTO_DSM2 2
|
||||||
#define PROTO_SILV_C 3
|
#define PROTO_SILV_A 3
|
||||||
#define PROTO_TRACER_CTP1009 4
|
#define PROTO_SILV_B 4
|
||||||
#define PROT_MAX 4
|
#define PROTO_SILV_C 5
|
||||||
#define PROT_STR "PPM SILV_ASILV_BSILV_CTRAC09"
|
#define PROTO_CTP1009 6
|
||||||
|
#define PROT_MAX 6
|
||||||
|
#define PROT_STR "PPM PXX DSM2 SILV_ASILV_BSILV_CTRAC09"
|
||||||
#define PROT_STR_LEN 6
|
#define PROT_STR_LEN 6
|
||||||
|
|
||||||
|
extern uint8_t heartbeat;
|
||||||
|
|
||||||
typedef void (*getADCp)();
|
typedef void (*getADCp)();
|
||||||
|
|
||||||
#define ZCHAR_MAX 40
|
#define ZCHAR_MAX 40
|
||||||
|
@ -459,7 +465,7 @@ extern void perOut(int16_t *chanOut, uint8_t att);
|
||||||
/// 1.. MAX_SWITCH : SW_ON .. SW_Trainer
|
/// 1.. MAX_SWITCH : SW_ON .. SW_Trainer
|
||||||
/// -1..-MAX_SWITCH : negierte Werte
|
/// -1..-MAX_SWITCH : negierte Werte
|
||||||
/// \param nc Wert, der bei swtch==0 geliefert wird.
|
/// \param nc Wert, der bei swtch==0 geliefert wird.
|
||||||
bool getSwitch(int8_t swtch, bool nc, uint8_t level=0);
|
bool getSwitch(int8_t swtch, bool nc);
|
||||||
/// Zeigt den Namen des Switches 'swtch' im display an
|
/// Zeigt den Namen des Switches 'swtch' im display an
|
||||||
/// \param x x-koordinate 0..127
|
/// \param x x-koordinate 0..127
|
||||||
/// \param y y-koordinate 0..63 (nur durch 8 teilbar)
|
/// \param y y-koordinate 0..63 (nur durch 8 teilbar)
|
||||||
|
@ -542,12 +548,13 @@ extern uint8_t s_eeDirtyMsk;
|
||||||
#define DIM(arr) (sizeof((arr))/sizeof((arr)[0]))
|
#define DIM(arr) (sizeof((arr))/sizeof((arr)[0]))
|
||||||
|
|
||||||
/// liefert Betrag des Arguments
|
/// liefert Betrag des Arguments
|
||||||
template<class t> inline t abs(t a){ return a>0?a:-a; }
|
template<class t> inline t __attribute__ ((always_inline)) abs(t a){ return a>0?a:-a; }
|
||||||
/// liefert das Minimum der Argumente
|
/// liefert das Minimum der Argumente
|
||||||
template<class t> inline t min(t a, t b){ return a<b?a:b; }
|
template<class t> inline t min(t a, t b){ return a<b?a:b; }
|
||||||
/// liefert das Maximum der Argumente
|
/// liefert das Maximum der Argumente
|
||||||
template<class t> inline t max(t a, t b){ return a>b?a:b; }
|
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); }
|
template<class t> inline int8_t sgn(t a){ return a>0 ? 1 : (a < 0 ? -1 : 0); }
|
||||||
|
template<class t> inline t limit(t mi, t x, t ma){ return min(max(mi,x),ma); }
|
||||||
|
|
||||||
/// Markiert einen EEPROM-Bereich als dirty. der Bereich wird dann in
|
/// Markiert einen EEPROM-Bereich als dirty. der Bereich wird dann in
|
||||||
/// eeCheck ins EEPROM zurueckgeschrieben.
|
/// eeCheck ins EEPROM zurueckgeschrieben.
|
||||||
|
@ -602,9 +609,6 @@ extern inline uint16_t get_tmr10ms()
|
||||||
#define SUB_MODE_H_DBL 3
|
#define SUB_MODE_H_DBL 3
|
||||||
|
|
||||||
void setupPulses();
|
void setupPulses();
|
||||||
void setupPulsesPPM();
|
|
||||||
void setupPulsesSilver();
|
|
||||||
void setupPulsesTracerCtp1009();
|
|
||||||
|
|
||||||
void initTemplates();
|
void initTemplates();
|
||||||
|
|
||||||
|
@ -638,7 +642,6 @@ extern volatile uint8_t g_blinkTmr10ms;
|
||||||
extern uint8_t g_beepCnt;
|
extern uint8_t g_beepCnt;
|
||||||
extern uint8_t g_beepVal[5];
|
extern uint8_t g_beepVal[5];
|
||||||
extern const PROGMEM char modi12x3[];
|
extern const PROGMEM char modi12x3[];
|
||||||
extern uint16_t pulses2MHz[120];
|
|
||||||
extern int16_t g_ppmIns[8];
|
extern int16_t g_ppmIns[8];
|
||||||
extern int16_t g_chans512[NUM_CHNOUT];
|
extern int16_t g_chans512[NUM_CHNOUT];
|
||||||
extern volatile uint8_t tick10ms;
|
extern volatile uint8_t tick10ms;
|
||||||
|
|
|
@ -234,6 +234,22 @@ TEST(FrSky, dateNtime) {
|
||||||
EXPECT_EQ(frskyHubData.sec, 50);
|
EXPECT_EQ(frskyHubData.sec, 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(getSwitch, undefCSW) {
|
||||||
|
memset(&g_model, 0, sizeof(g_model));
|
||||||
|
EXPECT_EQ(getSwitch(MAX_SWITCH-NUM_CSW, 0), false);
|
||||||
|
EXPECT_EQ(getSwitch(-(MAX_SWITCH-NUM_CSW), 0), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(getSwitch, circularCSW) {
|
||||||
|
memset(&g_model, 0, sizeof(g_model));
|
||||||
|
g_model.customSw[0] = { MAX_SWITCH-NUM_CSW, MAX_SWITCH-NUM_CSW, CS_OR };
|
||||||
|
g_model.customSw[1] = { MAX_SWITCH-NUM_CSW, MAX_SWITCH-NUM_CSW, CS_AND };
|
||||||
|
EXPECT_EQ(getSwitch(MAX_SWITCH-NUM_CSW, 0), false);
|
||||||
|
EXPECT_EQ(getSwitch(-(MAX_SWITCH-NUM_CSW), 0), true);
|
||||||
|
EXPECT_EQ(getSwitch(1+MAX_SWITCH-NUM_CSW, 0), false);
|
||||||
|
EXPECT_EQ(getSwitch(-(1+MAX_SWITCH-NUM_CSW), 0), true);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
::testing::InitGoogleTest(&argc, argv);
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
return RUN_ALL_TESTS();
|
return RUN_ALL_TESTS();
|
||||||
|
|
15
src/lcd.cpp
15
src/lcd.cpp
|
@ -275,7 +275,7 @@ void lcd_outdezNAtt(uint8_t x, uint8_t y, int16_t val, uint8_t flags, uint8_t le
|
||||||
|
|
||||||
void lcd_mask(uint8_t *p, uint8_t mask, uint8_t att)
|
void lcd_mask(uint8_t *p, uint8_t mask, uint8_t att)
|
||||||
{
|
{
|
||||||
assert(p < DISPLAY_END);
|
assert(p >= displayBuf && p < DISPLAY_END);
|
||||||
|
|
||||||
if (att & BLACK)
|
if (att & BLACK)
|
||||||
*p |= mask;
|
*p |= mask;
|
||||||
|
@ -326,13 +326,13 @@ void lcd_vlineStip(uint8_t x, int8_t y, int8_t h, uint8_t pat)
|
||||||
uint8_t *p = &displayBuf[ y / 8 * DISPLAY_W + x ];
|
uint8_t *p = &displayBuf[ y / 8 * DISPLAY_W + x ];
|
||||||
y = y % 8;
|
y = y % 8;
|
||||||
if (y) {
|
if (y) {
|
||||||
assert(p < DISPLAY_END);
|
assert(p >= displayBuf && p < DISPLAY_END);
|
||||||
*p ^= ~(BITMASK(y)-1) & pat;
|
*p ^= ~(BITMASK(y)-1) & pat;
|
||||||
p += DISPLAY_W;
|
p += DISPLAY_W;
|
||||||
h -= 8-y;
|
h -= 8-y;
|
||||||
}
|
}
|
||||||
while (h>0) {
|
while (h>0) {
|
||||||
assert(p < DISPLAY_END);
|
assert(p >= displayBuf && p < DISPLAY_END);
|
||||||
*p ^= pat;
|
*p ^= pat;
|
||||||
p += DISPLAY_W;
|
p += DISPLAY_W;
|
||||||
h -= 8;
|
h -= 8;
|
||||||
|
@ -340,7 +340,7 @@ void lcd_vlineStip(uint8_t x, int8_t y, int8_t h, uint8_t pat)
|
||||||
h = (h+8) % 8;
|
h = (h+8) % 8;
|
||||||
if (h) {
|
if (h) {
|
||||||
p -= DISPLAY_W;
|
p -= DISPLAY_W;
|
||||||
assert(p < DISPLAY_END);
|
assert(p >= displayBuf && p < DISPLAY_END);
|
||||||
*p ^= ~(BITMASK(h)-1) & pat;
|
*p ^= ~(BITMASK(h)-1) & pat;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,10 +360,11 @@ void lcd_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t pat, uint8_t a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void lcd_filled_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t att)
|
void lcd_filled_rect(uint8_t x, int8_t y, uint8_t w, uint8_t h, uint8_t att)
|
||||||
{
|
{
|
||||||
for (uint8_t i=y; i<y+h; i++)
|
for (int8_t i=y; i<y+h; i++) {
|
||||||
lcd_hline(x, i, w, att);
|
if (i>=0 && i<64) lcd_hline(x, i, w, att);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void putsTime(uint8_t x,uint8_t y,int16_t tme,uint8_t att,uint8_t att2)
|
void putsTime(uint8_t x,uint8_t y,int16_t tme,uint8_t att,uint8_t att2)
|
||||||
|
|
|
@ -81,6 +81,8 @@ 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_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 lcd_outdez8(uint8_t x, uint8_t y, int8_t val);
|
||||||
|
|
||||||
|
extern void putsStrIdx(uint8_t x, uint8_t y, const prog_char *str, uint8_t idx, uint8_t att=0);
|
||||||
|
|
||||||
extern void putsModelName(uint8_t x, uint8_t y, char *name, uint8_t id, uint8_t att);
|
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=0);
|
extern void putsSwitches(uint8_t x, uint8_t y, int8_t swtch, uint8_t att=0);
|
||||||
extern void putsFlightPhase(uint8_t x, uint8_t y, int8_t idx, uint8_t att=0);
|
extern void putsFlightPhase(uint8_t x, uint8_t y, int8_t idx, uint8_t att=0);
|
||||||
|
@ -107,7 +109,7 @@ 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_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_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);
|
extern void lcd_filled_rect(uint8_t x, int8_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); }
|
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) \
|
#define DO_CROSS(xx,yy,ww) \
|
||||||
|
|
212
src/menus.cpp
212
src/menus.cpp
|
@ -303,215 +303,3 @@ void pushMenu(MenuFuncP newMenu)
|
||||||
g_menuStack[g_menuStackPtr] = newMenu;
|
g_menuStack[g_menuStackPtr] = newMenu;
|
||||||
(*newMenu)(EVT_ENTRY);
|
(*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"));
|
|
||||||
}
|
|
||||||
|
|
|
@ -67,6 +67,7 @@ void menuProcTelemetry(uint8_t event);
|
||||||
#ifdef TEMPLATES
|
#ifdef TEMPLATES
|
||||||
void menuProcTemplates(uint8_t event);
|
void menuProcTemplates(uint8_t event);
|
||||||
#endif
|
#endif
|
||||||
|
void menuProcExpoOne(uint8_t event);
|
||||||
|
|
||||||
MenuFuncP_PROGMEM APM menuTabModel[] = {
|
MenuFuncP_PROGMEM APM menuTabModel[] = {
|
||||||
menuProcModelSelect,
|
menuProcModelSelect,
|
||||||
|
@ -678,99 +679,137 @@ void menuProcHeli(uint8_t event)
|
||||||
|
|
||||||
static uint8_t s_curveChan;
|
static uint8_t s_curveChan;
|
||||||
|
|
||||||
|
typedef int16_t (*FnFuncP) (int16_t x);
|
||||||
|
|
||||||
|
int16_t expoFn(int16_t x)
|
||||||
|
{
|
||||||
|
ExpoData *ed = expoaddress(s_currIdx);
|
||||||
|
int16_t anas[NUM_STICKS] = {0};
|
||||||
|
anas[ed->chn] = x;
|
||||||
|
applyExpos(anas);
|
||||||
|
return anas[ed->chn];
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t curveFn(int16_t x)
|
||||||
|
{
|
||||||
|
return intpol(x, s_curveChan);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawCurve(FnFuncP fn)
|
||||||
|
{
|
||||||
|
lcd_vlineStip(X0, 0, DISPLAY_H, 0xee);
|
||||||
|
lcd_hlineStip(X0-WCHART, Y0, WCHART*2, 0xee);
|
||||||
|
|
||||||
|
for (int8_t xv=-WCHART+1; xv<WCHART; xv++) {
|
||||||
|
uint16_t yv = (RESX + fn(xv * (RESX/WCHART))) / 2;
|
||||||
|
yv = (DISPLAY_H-1) - yv * (DISPLAY_H-1) / RESX;
|
||||||
|
lcd_plot(X0+xv, yv, BLACK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void menuProcCurveOne(uint8_t event)
|
void menuProcCurveOne(uint8_t event)
|
||||||
{
|
{
|
||||||
#define XD X0-2
|
uint8_t points;
|
||||||
bool cv9 = s_curveChan >= MAX_CURVE5;
|
int8_t *crv;
|
||||||
|
static int8_t dfltCrv;
|
||||||
|
static uint8_t autoThrStep;
|
||||||
|
|
||||||
SUBMENU("CURVE", 2+(cv9 ? 9 : 5), { 9, 0/*repeated...*/});
|
TITLE("CURVE");
|
||||||
lcd_outdezAtt(6*FW, 0, s_curveChan+1, INVERS);
|
lcd_outdezAtt(5*FW+1, 0, s_curveChan+1, INVERS|LEFT);
|
||||||
|
|
||||||
int8_t *crv = cv9 ? g_model.curves9[s_curveChan-MAX_CURVE5] : g_model.curves5[s_curveChan];
|
if (s_curveChan >= MAX_CURVE5) {
|
||||||
|
points = 9;
|
||||||
|
crv = g_model.curves9[s_curveChan-MAX_CURVE5];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
points = 5;
|
||||||
|
crv = g_model.curves5[s_curveChan];
|
||||||
|
}
|
||||||
|
|
||||||
int8_t sub = m_posVert-1;
|
switch(event) {
|
||||||
int8_t subSub = m_posHorz;
|
case EVT_ENTRY:
|
||||||
|
dfltCrv = 0;
|
||||||
switch(event){
|
autoThrStep = 0;
|
||||||
|
break;
|
||||||
|
case EVT_KEY_FIRST(KEY_MENU):
|
||||||
|
if (!s_editMode) {
|
||||||
|
switch (m_posHorz) {
|
||||||
|
case 0:
|
||||||
|
s_editMode = true;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (++dfltCrv > 4)
|
||||||
|
dfltCrv = -4;
|
||||||
|
for (uint8_t i=0; i<points; i++)
|
||||||
|
crv[i] = (i-(points/2)) * dfltCrv * 50 / (points-1);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
crv[0] = -100; crv[points-1] = 100;
|
||||||
|
autoThrStep = 1; // the lowest point first
|
||||||
|
// s_autoThrValue =
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
case EVT_KEY_FIRST(KEY_EXIT):
|
case EVT_KEY_FIRST(KEY_EXIT):
|
||||||
if(subSub!=0) {
|
killEvents(event);
|
||||||
subSub = m_posHorz = 0;
|
if (autoThrStep) {
|
||||||
killEvents(event);
|
autoThrStep = 0;
|
||||||
|
}
|
||||||
|
else if (s_editMode) {
|
||||||
|
m_posHorz = 0;
|
||||||
|
s_editMode = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
popMenu();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EVT_KEY_REPT(KEY_LEFT):
|
case EVT_KEY_REPT(KEY_LEFT):
|
||||||
case EVT_KEY_FIRST(KEY_LEFT):
|
case EVT_KEY_FIRST(KEY_LEFT):
|
||||||
if (s_editMode && subSub>0) m_posHorz--;
|
if (!autoThrStep && m_posHorz>0) m_posHorz--;
|
||||||
break;
|
break;
|
||||||
case EVT_KEY_REPT(KEY_RIGHT):
|
case EVT_KEY_REPT(KEY_RIGHT):
|
||||||
case EVT_KEY_FIRST(KEY_RIGHT):
|
case EVT_KEY_FIRST(KEY_RIGHT):
|
||||||
if(s_editMode && subSub<(cv9 ? 9 : 5)) m_posHorz++;
|
if (!autoThrStep && m_posHorz<(s_editMode ? points-1 : ((g_menuStack[g_menuStackPtr-1] == menuProcExpoOne && IS_THROTTLE(expoaddress(s_currIdx)->chn)) ? 2 : 1))) m_posHorz++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
s_editMode = m_posHorz;
|
for (uint8_t i = 0; i < points; i++) {
|
||||||
|
uint8_t x, y;
|
||||||
for (uint8_t i = 0; i < 5; i++) {
|
if (i>4) {
|
||||||
uint8_t y = i * FH + 16;
|
x = 8*FW; y = (i-4) * FH;
|
||||||
uint8_t attr = sub == i ? INVERS : 0;
|
|
||||||
lcd_outdezAtt(4 * FW, y, crv[i], attr);
|
|
||||||
}
|
|
||||||
if(cv9)
|
|
||||||
for (uint8_t i = 0; i < 4; i++) {
|
|
||||||
uint8_t y = i * FH + 16;
|
|
||||||
uint8_t attr = sub == i + 5 ? INVERS : 0;
|
|
||||||
lcd_outdezAtt(8 * FW, y, crv[i + 5], attr);
|
|
||||||
}
|
}
|
||||||
lcd_putsAtt( 2*FW, 1*FH,PSTR("EDIT->"),((sub == -1) && (subSub == 0)) ? INVERS : 0);
|
else {
|
||||||
lcd_putsAtt( 2*FW, 7*FH,PSTR("PRESET"),sub == (cv9 ? 9 : 5) ? INVERS : 0);
|
x = 4*FW; y = (i+1) * FH;
|
||||||
|
|
||||||
static int8_t dfltCrv;
|
|
||||||
if((sub<(cv9 ? 9 : 5)) && (sub>-1)) CHECK_INCDEC_MODELVAR( event, crv[sub], -100,100);
|
|
||||||
else if(sub>0){ //make sure we're not on "EDIT"
|
|
||||||
dfltCrv = checkIncDec(event, dfltCrv, -4, 4, EE_MODEL);
|
|
||||||
if (checkIncDec_Ret) {
|
|
||||||
if(cv9) for (uint8_t i = 0; i < 9; i++) crv[i] = (i-4)*dfltCrv* 100 / 16;
|
|
||||||
else for (uint8_t i = 0; i < 5; i++) crv[i] = (i-2)*dfltCrv* 100 / 8;
|
|
||||||
}
|
}
|
||||||
|
uint8_t attr = (s_editMode && m_posHorz == i) ? INVERS : 0;
|
||||||
|
lcd_outdezAtt(x, y, crv[i], attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(s_editMode)
|
lcd_puts_P(0*FW, 7*FH, PSTR("MODE"));
|
||||||
{
|
lcd_putsnAtt(5*FW-2, 7*FH, PSTR("EDIT ""PRSET""A.THR")+5*(!s_editMode)*m_posHorz, 5, s_editMode || autoThrStep ? 0 : INVERS);
|
||||||
for(uint8_t i=0; i<(cv9 ? 9 : 5); i++)
|
|
||||||
{
|
|
||||||
uint8_t xx = XD-1-WCHART+i*WCHART/(cv9 ? 4 : 2);
|
|
||||||
uint8_t yy = Y0-crv[i]*WCHART/100;
|
|
||||||
|
|
||||||
|
if (s_editMode || autoThrStep) {
|
||||||
|
for (uint8_t i=0; i<points; i++) {
|
||||||
|
uint8_t xx = X0-1-WCHART+i*WCHART/(points/2);
|
||||||
|
uint8_t yy = (DISPLAY_H-1) - (100 + crv[i]) * (DISPLAY_H-1) / 200;
|
||||||
|
|
||||||
if(subSub==(i+1))
|
if (autoThrStep) {
|
||||||
{
|
if (autoThrStep==i+1)
|
||||||
if((yy-2)<WCHART*2) lcd_hline( xx-1, yy-2, 5); //do selection square
|
lcd_filled_rect(xx-1, yy-2, 5, 5); // do selection square
|
||||||
if((yy-1)<WCHART*2) lcd_hline( xx-1, yy-1, 5);
|
|
||||||
if(yy<WCHART*2) lcd_hline( xx-1, yy , 5);
|
|
||||||
if((yy+1)<WCHART*2) lcd_hline( xx-1, yy+1, 5);
|
|
||||||
if((yy+2)<WCHART*2) lcd_hline( xx-1, yy+2, 5);
|
|
||||||
|
|
||||||
if(p1valdiff || event==EVT_KEY_FIRST(KEY_DOWN) || event==EVT_KEY_FIRST(KEY_UP) || event==EVT_KEY_REPT(KEY_DOWN) || event==EVT_KEY_REPT(KEY_UP))
|
|
||||||
CHECK_INCDEC_MODELVAR( event, crv[i], -100,100); // edit on up/down
|
|
||||||
}
|
}
|
||||||
else
|
else if (m_posHorz==i) {
|
||||||
{
|
lcd_filled_rect(xx-1, yy-2, 5, 5); // do selection square
|
||||||
if((yy-1)<WCHART*2) lcd_hline( xx, yy-1, 3); // do markup square
|
if (p1valdiff || event==EVT_KEY_FIRST(KEY_DOWN) || event==EVT_KEY_FIRST(KEY_UP) || event==EVT_KEY_REPT(KEY_DOWN) || event==EVT_KEY_REPT(KEY_UP))
|
||||||
if(yy<WCHART*2) lcd_hline( xx, yy , 3);
|
CHECK_INCDEC_MODELVAR( event, crv[i], -100,100); // edit on up/down
|
||||||
if((yy+1)<WCHART*2) lcd_hline( xx, yy+1, 3);
|
}
|
||||||
|
else {
|
||||||
|
lcd_filled_rect(xx, yy-1, 3, 3); // do markup square
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint8_t xv = 0; xv < WCHART * 2; xv++) {
|
DrawCurve(curveFn);
|
||||||
uint16_t yv = intpol(xv * (RESXu / WCHART) - RESXu, s_curveChan) / (RESXu
|
|
||||||
/ WCHART);
|
|
||||||
lcd_plot(XD + xv - WCHART, Y0 - yv);
|
|
||||||
if ((xv & 3) == 0) {
|
|
||||||
lcd_plot(XD + xv - WCHART, Y0 + 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lcd_vline(XD, Y0 - WCHART, WCHART * 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t getExpoMixCount(uint8_t expo)
|
uint8_t getExpoMixCount(uint8_t expo)
|
||||||
|
@ -1001,19 +1040,10 @@ void menuProcExpoOne(uint8_t event)
|
||||||
y+=FH;
|
y+=FH;
|
||||||
}
|
}
|
||||||
|
|
||||||
lcd_vlineStip(X0, 0, DISPLAY_H, 0xee);
|
DrawCurve(expoFn);
|
||||||
lcd_hlineStip(X0-WCHART, Y0, WCHART*2, 0xee);
|
|
||||||
|
|
||||||
int16_t anas[NUM_STICKS] = {0};
|
|
||||||
for(int8_t xv=-WCHART; xv<WCHART; xv++) {
|
|
||||||
anas[ed->chn] = xv*(RESX/WCHART);
|
|
||||||
applyExpos(anas);
|
|
||||||
uint16_t yv = (RESX + anas[ed->chn]) / 2;
|
|
||||||
yv = (DISPLAY_H-1) - yv * (DISPLAY_H-1) / RESX;
|
|
||||||
lcd_plot(X0+xv, yv, BLACK);
|
|
||||||
}
|
|
||||||
|
|
||||||
int16_t x512 = calibratedStick[ed->chn];
|
int16_t x512 = calibratedStick[ed->chn];
|
||||||
|
int16_t anas[NUM_STICKS] = {0};
|
||||||
anas[ed->chn] = x512;
|
anas[ed->chn] = x512;
|
||||||
applyExpos(anas);
|
applyExpos(anas);
|
||||||
int16_t y512 = anas[ed->chn];
|
int16_t y512 = anas[ed->chn];
|
||||||
|
@ -1123,7 +1153,6 @@ static uint8_t s_maxLines = 8;
|
||||||
static uint8_t s_copySrcIdx;
|
static uint8_t s_copySrcIdx;
|
||||||
static uint8_t s_copySrcCh;
|
static uint8_t s_copySrcCh;
|
||||||
|
|
||||||
#define FIRST 0x10
|
|
||||||
inline void displayMixerLine(uint8_t row, uint8_t mix, uint8_t ch, uint8_t idx, uint8_t cur, uint8_t event)
|
inline void displayMixerLine(uint8_t row, uint8_t mix, uint8_t ch, uint8_t idx, uint8_t cur, uint8_t event)
|
||||||
{
|
{
|
||||||
uint8_t y = (row-s_pgOfs)*FH;
|
uint8_t y = (row-s_pgOfs)*FH;
|
||||||
|
@ -1173,7 +1202,7 @@ inline void displayExpoLine(uint8_t row, uint8_t expo, uint8_t ch, uint8_t idx,
|
||||||
lcd_outdezAtt(9*FW+1, y, ed->expo, 0);
|
lcd_outdezAtt(9*FW+1, y, ed->expo, 0);
|
||||||
putsFlightPhase(10*FW, y, ed->negPhase ? -ed->phase : +ed->phase);
|
putsFlightPhase(10*FW, y, ed->negPhase ? -ed->phase : +ed->phase);
|
||||||
putsSwitches(13*FW+4, y, ed->swtch, 0); // normal switches
|
putsSwitches(13*FW+4, y, ed->swtch, 0); // normal switches
|
||||||
if (ed->mode!=3) lcd_putc(17*FW, y, ed->mode == 2 ? 127 : 126);//'|' : (stkVal[i] ? '<' : '>'),0);*/
|
if (ed->mode!=3) lcd_putc(17*FW, y, ed->mode == 2 ? 126 : 127);//'|' : (stkVal[i] ? '<' : '>'),0);*/
|
||||||
if (ed->curve) putsCurve(18*FW+2, y, ed->curve+(ed->curve >= CURVE_BASE+4 ? 4 : 0));
|
if (ed->curve) putsCurve(18*FW+2, y, ed->curve+(ed->curve >= CURVE_BASE+4 ? 4 : 0));
|
||||||
|
|
||||||
if (s_copyMode) {
|
if (s_copyMode) {
|
||||||
|
@ -1394,31 +1423,25 @@ void menuProcLimits(uint8_t event)
|
||||||
|
|
||||||
static bool swVal[NUM_CHNOUT];
|
static bool swVal[NUM_CHNOUT];
|
||||||
|
|
||||||
uint8_t y = 0;
|
int8_t sub = m_posVert - 1;
|
||||||
uint8_t k = 0;
|
|
||||||
int8_t sub = m_posVert - 1;
|
|
||||||
|
|
||||||
switch(event)
|
for (uint8_t i=0; i<7; i++) {
|
||||||
{
|
uint8_t y = (i+1)*FH;
|
||||||
case EVT_KEY_LONG(KEY_MENU):
|
uint8_t k = i+s_pgOfs;
|
||||||
if(sub>=0 && sub<NUM_CHNOUT) {
|
|
||||||
int16_t v = g_chans512[sub - s_pgOfs];
|
if (k==NUM_CHNOUT) {
|
||||||
LimitData *ld = limitaddress(sub);
|
//last line available - add the "copy trim menu" line
|
||||||
switch (m_posHorz) {
|
uint8_t attr = (sub==NUM_CHNOUT) ? INVERS : 0;
|
||||||
case 0:
|
lcd_putsAtt(3*FW, y, PSTR("COPY TRIM [MENU]"), s_noHi ? 0 : attr);
|
||||||
ld->offset = (ld->revert) ? -v : v;
|
if (attr && event==EVT_KEY_LONG(KEY_MENU)) {
|
||||||
STORE_MODELVARS;
|
s_noHi = NO_HI_LEN;
|
||||||
break;
|
killEvents(event);
|
||||||
}
|
moveTrimsToOffsets(); // if highlighted and menu pressed - copy trims
|
||||||
}
|
}
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(uint8_t i=0; i<7; i++){
|
LimitData *ld = limitaddress(k) ;
|
||||||
y=(i+1)*FH;
|
|
||||||
k=i+s_pgOfs;
|
|
||||||
if(k==NUM_CHNOUT) break;
|
|
||||||
LimitData *ld = limitaddress( k ) ;
|
|
||||||
int16_t v = (ld->revert) ? -ld->offset : ld->offset;
|
int16_t v = (ld->revert) ? -ld->offset : ld->offset;
|
||||||
if((g_chans512[k] - v) > 50) swVal[k] = (true==ld->revert);// Switch to raw inputs? - remove trim!
|
if((g_chans512[k] - v) > 50) swVal[k] = (true==ld->revert);// Switch to raw inputs? - remove trim!
|
||||||
if((g_chans512[k] - v) < -50) swVal[k] = (false==ld->revert);
|
if((g_chans512[k] - v) < -50) swVal[k] = (false==ld->revert);
|
||||||
|
@ -1434,6 +1457,12 @@ void menuProcLimits(uint8_t event)
|
||||||
if (active) {
|
if (active) {
|
||||||
ld->offset = checkIncDec(event, ld->offset, -1000, 1000, EE_MODEL);
|
ld->offset = checkIncDec(event, ld->offset, -1000, 1000, EE_MODEL);
|
||||||
}
|
}
|
||||||
|
else if (attr && event==EVT_KEY_LONG(KEY_MENU)) {
|
||||||
|
int16_t zero = g_chans512[k];
|
||||||
|
ld->offset = (ld->revert) ? -zero : zero;
|
||||||
|
s_editMode = false;
|
||||||
|
STORE_MODELVARS;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
lcd_outdezAtt( 12*FW, y, (int8_t)(ld->min-100), attr);
|
lcd_outdezAtt( 12*FW, y, (int8_t)(ld->min-100), attr);
|
||||||
|
@ -1466,16 +1495,6 @@ void menuProcLimits(uint8_t event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(k==NUM_CHNOUT){
|
|
||||||
//last line available - add the "copy trim menu" line
|
|
||||||
uint8_t attr = (sub==NUM_CHNOUT) ? INVERS : 0;
|
|
||||||
lcd_putsAtt(3*FW,y,PSTR("COPY TRIM [MENU]"),s_noHi ? 0 : attr);
|
|
||||||
if(attr && event==EVT_KEY_LONG(KEY_MENU)) {
|
|
||||||
s_noHi = NO_HI_LEN;
|
|
||||||
killEvents(event);
|
|
||||||
moveTrimsToOffsets(); // if highlighted and menu pressed - copy trims
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void menuProcCurvesAll(uint8_t event)
|
void menuProcCurvesAll(uint8_t event)
|
||||||
|
@ -1505,17 +1524,15 @@ void menuProcCurvesAll(uint8_t event)
|
||||||
if(cv9 && (yd>6)) break;
|
if(cv9 && (yd>6)) break;
|
||||||
if(yd>7) break;
|
if(yd>7) break;
|
||||||
if(!m) m = attr;
|
if(!m) m = attr;
|
||||||
lcd_putsAtt( FW*0, y,PSTR("CV"),attr);
|
putsStrIdx(0, y, PSTR("CV"), k+1, attr);
|
||||||
lcd_outdezAtt( (k<9) ? FW*3 : FW*4-1, y,k+1 ,attr);
|
|
||||||
|
|
||||||
int8_t *crv = cv9 ? g_model.curves9[k-MAX_CURVE5] : g_model.curves5[k];
|
int8_t *crv = cv9 ? g_model.curves9[k-MAX_CURVE5] : g_model.curves5[k];
|
||||||
for (uint8_t j = 0; j < (5); j++) {
|
for (uint8_t j = 0; j < (5); j++) {
|
||||||
lcd_outdezAtt( j*(3*FW+3) + 7*FW, y, crv[j], 0);
|
lcd_outdezAtt( j*(3*FW+3) + 7*FW + 2, y, crv[j], 0);
|
||||||
}
|
}
|
||||||
y += FH;yd++;
|
y += FH;yd++;
|
||||||
if(cv9){
|
if(cv9){
|
||||||
for (uint8_t j = 0; j < 4; j++) {
|
for (uint8_t j = 0; j < 4; j++) {
|
||||||
lcd_outdezAtt( j*(3*FW+3) + 7*FW, y, crv[j+5], 0);
|
lcd_outdezAtt( j*(3*FW+3) + 7*FW + 2, y, crv[j+5], 0);
|
||||||
}
|
}
|
||||||
y += FH;yd++;
|
y += FH;yd++;
|
||||||
}
|
}
|
||||||
|
@ -1541,8 +1558,8 @@ void menuProcCustomSwitches(uint8_t event)
|
||||||
|
|
||||||
//write SW names here
|
//write SW names here
|
||||||
lcd_putsnAtt( 0*FW , y, PSTR("SW"),2,0);
|
lcd_putsnAtt( 0*FW , y, PSTR("SW"),2,0);
|
||||||
lcd_putc( 2*FW , y, k + (k>8 ? 'A'-9: '1'));
|
lcd_putc( 2*FW, y, k + (k>8 ? 'A'-9: '1'));
|
||||||
lcd_putsnAtt( 4*FW , y, PSTR(CSWITCH_STR)+CSW_LEN_FUNC*cs.func,CSW_LEN_FUNC,m_posHorz==0 ? attr : 0);
|
lcd_putsnAtt( 4*FW - 1, y, PSTR(CSWITCH_STR)+CSW_LEN_FUNC*cs.func,CSW_LEN_FUNC,m_posHorz==0 ? attr : 0);
|
||||||
|
|
||||||
uint8_t cstate = CS_STATE(cs.func);
|
uint8_t cstate = CS_STATE(cs.func);
|
||||||
|
|
||||||
|
|
|
@ -232,11 +232,10 @@ typedef struct t_ModelData {
|
||||||
char name[10]; // 10 must be first for eeLoadModelName
|
char name[10]; // 10 must be first for eeLoadModelName
|
||||||
TimerData timer1; // TODO timers array
|
TimerData timer1; // TODO timers array
|
||||||
uint8_t protocol:3;
|
uint8_t protocol:3;
|
||||||
int8_t ppmNCH:3;
|
|
||||||
uint8_t thrTrim:1; // Enable Throttle Trim
|
uint8_t thrTrim:1; // Enable Throttle Trim
|
||||||
uint8_t thrExpo:1; // Enable Throttle Expo
|
int8_t ppmNCH:4;
|
||||||
uint8_t trimInc:3; // Trim Increments
|
uint8_t trimInc:3; // Trim Increments
|
||||||
uint8_t spare1:1;
|
uint8_t thrExpo:1; // Enable Throttle Expo
|
||||||
uint8_t pulsePol:1;
|
uint8_t pulsePol:1;
|
||||||
uint8_t extendedLimits:1;
|
uint8_t extendedLimits:1;
|
||||||
uint8_t extendedTrims:1;
|
uint8_t extendedTrims:1;
|
||||||
|
|
|
@ -114,7 +114,6 @@ uint8_t Translate()
|
||||||
g_model.thrTrim = v3->thrTrim;
|
g_model.thrTrim = v3->thrTrim;
|
||||||
g_model.thrExpo = v3->thrExpo;
|
g_model.thrExpo = v3->thrExpo;
|
||||||
g_model.trimInc = v3->trimInc;
|
g_model.trimInc = v3->trimInc;
|
||||||
g_model.spare1 = 0;
|
|
||||||
g_model.pulsePol = v3->pulsePol;
|
g_model.pulsePol = v3->pulsePol;
|
||||||
if (g_eeGeneral.myVers == EEPROM_VER_r584)
|
if (g_eeGeneral.myVers == EEPROM_VER_r584)
|
||||||
g_model.extendedLimits = 0;
|
g_model.extendedLimits = 0;
|
||||||
|
|
444
src/pulses.cpp
Normal file
444
src/pulses.cpp
Normal file
|
@ -0,0 +1,444 @@
|
||||||
|
/*
|
||||||
|
* 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 CTP1009
|
||||||
|
uint16_t pulses2MHz[50] = {0};
|
||||||
|
#else
|
||||||
|
uint16_t pulses2MHz[40] = {0};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint16_t *pulses2MHzRPtr = pulses2MHz;
|
||||||
|
uint16_t *pulses2MHzWPtr = pulses2MHz;
|
||||||
|
|
||||||
|
#define CTRL_END 0
|
||||||
|
#define CTRL_CNT 1
|
||||||
|
#define CTRL_REP_1CMD -3
|
||||||
|
#define CTRL_REP_2CMD -6
|
||||||
|
|
||||||
|
ISR(TIMER1_COMPA_vect) //2MHz pulse generation
|
||||||
|
{
|
||||||
|
static uint8_t pulsePol; // TODO strange, it's always 0 at first, shouldn't it be initialized properly in setupPulses?
|
||||||
|
|
||||||
|
// Latency -- how far further on from interrupt trigger has the timer counted?
|
||||||
|
// (or -- how long did it take to get to this function)
|
||||||
|
uint8_t dt = TCNT1L;
|
||||||
|
if (dt > g_tmr1Latency_max) g_tmr1Latency_max = dt;
|
||||||
|
if (dt < g_tmr1Latency_min) g_tmr1Latency_min = dt;
|
||||||
|
|
||||||
|
// vinceofdrink@gmail harwared ppm
|
||||||
|
// Orginal bitbang for PPM
|
||||||
|
#if !defined (DPPMPB7_HARDWARE) && !defined (PCBV4)
|
||||||
|
if (pulsePol) {
|
||||||
|
PORTB |= (1<<OUT_B_PPM); // GCC optimisation should result in a single SBI instruction
|
||||||
|
pulsePol = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PORTB &= ~(1<<OUT_B_PPM);
|
||||||
|
pulsePol = 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
OCR1A = *pulses2MHzRPtr; // Schedule next interrupt vector (to this handler)
|
||||||
|
|
||||||
|
#if defined (PCBV4)
|
||||||
|
OCR1B = *pulses2MHzRPtr; /* G: Using timer in CTC mode, restricted to using OCR1A for interrupt triggering.
|
||||||
|
So we actually have to handle the OCR1B register separately in this way. */
|
||||||
|
|
||||||
|
// We cannot read the status of the PPM_OUT pin when OC1B is connected to it on the ATmega2560.
|
||||||
|
// So the only way to set polarity is to manually control set/reset mode in COM1B0/1
|
||||||
|
if (pulsePol) {
|
||||||
|
TCCR1A = (3<<COM1B0); // SET the state of PB6(OC1B) on next TCNT1==OCR1B
|
||||||
|
pulsePol = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
TCCR1A = (2<<COM1B0); // CLEAR the state of PB6(OC1B) on next TCNT1==OCR1B
|
||||||
|
pulsePol = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//vinceofdrink@gmail harwared ppm
|
||||||
|
#elif defined (DPPMPB7_HARDWARE)
|
||||||
|
OCR1C = *pulses2MHzRPtr; // just copy the value of the OCR1A to OCR1C to test PPM out without too
|
||||||
|
// much change in the code not optimum but will not alter ppm precision
|
||||||
|
#endif
|
||||||
|
|
||||||
|
++pulses2MHzRPtr;
|
||||||
|
|
||||||
|
if (pulses2MHzRPtr == pulses2MHzWPtr) {
|
||||||
|
//currpulse=0;
|
||||||
|
pulsePol = g_model.pulsePol;//0;
|
||||||
|
// channel = 0 ;
|
||||||
|
// PulseTotal = 0 ;
|
||||||
|
|
||||||
|
// cli(); // TODO I remove this cli, we are in a blocking interrupt
|
||||||
|
#if defined (PCBV3)
|
||||||
|
TIMSK1 &= ~(1<<OCIE1A); //stop reentrance
|
||||||
|
#else
|
||||||
|
TIMSK &= ~(1<<OCIE1A); //stop reentrance
|
||||||
|
#endif
|
||||||
|
sei();
|
||||||
|
setupPulses();
|
||||||
|
|
||||||
|
#if !defined (PCBV3) && defined (DPPMPB7_HARDWARE)
|
||||||
|
// G: NOTE: This strategy does not work on the '2560 becasue you can't
|
||||||
|
// read the PPM out pin when connected to OC1B. Vincent says
|
||||||
|
// it works on the '64A. I haven't personally tested it.
|
||||||
|
if (PINB & (1<<OUT_B_PPM) && g_model.pulsePol)
|
||||||
|
TCCR1C=(1<<FOC1C);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
cli();
|
||||||
|
#if defined (PCBV3)
|
||||||
|
TIMSK1 |= (1<<OCIE1A);
|
||||||
|
#else
|
||||||
|
TIMSK |= (1<<OCIE1A);
|
||||||
|
#endif
|
||||||
|
// sei(); TODO I remove this sei
|
||||||
|
}
|
||||||
|
heartbeat |= HEART_TIMER2Mhz;
|
||||||
|
}
|
||||||
|
|
||||||
|
//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)
|
||||||
|
//}
|
||||||
|
//int16_t PPM_range = 512*2; //range of 0.7..1.7msec
|
||||||
|
//uint16_t PPM_gap = 300 * 2; //Stoplen *2
|
||||||
|
//uint16_t PPM_frame ;
|
||||||
|
|
||||||
|
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 that's why 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
|
||||||
|
uint16_t *ptr = pulses2MHz ; // TODO check this saves flash
|
||||||
|
uint8_t p = 8+(g_model.ppmNCH*2); // channels count
|
||||||
|
uint16_t q = (g_model.ppmDelay*50+300)*2; //Stoplen *2
|
||||||
|
uint16_t rest = 22500u*2-q; //Minimum Framelen=22.5 ms
|
||||||
|
// TODO in er9x this line replaces the next one: rest += (int16_t(g_model.ppmFrameLength))*1000;
|
||||||
|
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++) {
|
||||||
|
int16_t v = max(min(g_chans512[i], PPM_range), -PPM_range) + PPM_CENTER;
|
||||||
|
rest -= (v+q);
|
||||||
|
*ptr++ = q;
|
||||||
|
*ptr++ = v - q + 600; /* as Pat MacKenzie suggests */
|
||||||
|
}
|
||||||
|
*ptr = q;
|
||||||
|
*(ptr+1) = rest;
|
||||||
|
pulses2MHzWPtr = ptr+2;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PXX
|
||||||
|
|
||||||
|
void setupPulsesPXX()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DSM2
|
||||||
|
|
||||||
|
// DSM2 protocol pulled from th9x - Thanks thus!!!
|
||||||
|
|
||||||
|
//http://www.rclineforum.de/forum/board49-zubeh-r-elektronik-usw/fernsteuerungen-sender-und-emp/neuer-9-kanal-sender-f-r-70-au/Beitrag_3897736#post3897736
|
||||||
|
//(dsm2( LP4DSM aus den RTF ( Ready To Fly ) Sendern von Spektrum.
|
||||||
|
//http://www.rcgroups.com/forums/showpost.php?p=18554028&postcount=237
|
||||||
|
// /home/thus/txt/flieger/PPMtoDSM.c
|
||||||
|
/*
|
||||||
|
125000 Baud 8n1 _ xxxx xxxx - ---
|
||||||
|
#define DSM2_CHANNELS 6 // Max number of DSM2 Channels transmitted
|
||||||
|
#define DSM2_BIT (8*2)
|
||||||
|
bind:
|
||||||
|
DSM2_Header = 0x80,0
|
||||||
|
static byte DSM2_Channel[DSM2_CHANNELS*2] = {
|
||||||
|
ch
|
||||||
|
0x00,0xAA, 0 0aa
|
||||||
|
0x05,0xFF, 1 1ff
|
||||||
|
0x09,0xFF, 2 1ff
|
||||||
|
0x0D,0xFF, 3 1ff
|
||||||
|
0x13,0x54, 4 354
|
||||||
|
0x14,0xAA 5 0aa
|
||||||
|
};
|
||||||
|
|
||||||
|
normal:
|
||||||
|
DSM2_Header = 0,0;
|
||||||
|
DSM2_Channel[i*2] = (byte)(i<<2) | highByte(pulse);
|
||||||
|
DSM2_Channel[i*2+1] = lowByte(pulse);
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
inline void _send_1(uint16_t v)
|
||||||
|
{
|
||||||
|
*pulses2MHzWPtr++ = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BITLEN_DSM2 (8*2) //125000 Baud
|
||||||
|
void sendByteDsm2(uint8_t b) //max 10changes 0 10 10 10 10 1
|
||||||
|
{
|
||||||
|
bool lev = 0;
|
||||||
|
uint8_t len = BITLEN_DSM2; //max val: 9*16 < 256
|
||||||
|
for( uint8_t i=0; i<=8; i++){ //8Bits + Stop=1
|
||||||
|
bool nlev = b & 1; //lsb first
|
||||||
|
if(lev == nlev){
|
||||||
|
len += BITLEN_DSM2;
|
||||||
|
}else{
|
||||||
|
_send_1(len-1);
|
||||||
|
len = BITLEN_DSM2;
|
||||||
|
lev = nlev;
|
||||||
|
}
|
||||||
|
b = (b>>1) | 0x80; //shift in stop bit
|
||||||
|
}
|
||||||
|
_send_1(len + 10*BITLEN_DSM2 -1); //some more space-time for security
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void setupPulsesDsm2(uint8_t chns)
|
||||||
|
{
|
||||||
|
static uint8_t dsmDat[2+6*2]={0x80,0, 0x00,0xAA, 0x05,0xFF, 0x09,0xFF, 0x0D,0xFF, 0x13,0x54, 0x14,0xAA};
|
||||||
|
|
||||||
|
static uint8_t state = 0;
|
||||||
|
|
||||||
|
if(state==0){
|
||||||
|
|
||||||
|
if((dsmDat[0] == 0) || ! keyState(SW_Trainer) ){ //init - bind!
|
||||||
|
dsmDat[0]=0; dsmDat[1]=0; //DSM2_Header = 0,0;
|
||||||
|
for(uint8_t i=0; i<chns; i++){
|
||||||
|
uint16_t pulse = limit(0, g_chans512[i]+512,1023);
|
||||||
|
dsmDat[2+2*i] = (i<<2) | ((pulse>>8)&0x03);
|
||||||
|
dsmDat[3+2*i] = pulse & 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sendByteDsm2(dsmDat[state++]);
|
||||||
|
sendByteDsm2(dsmDat[state++]);
|
||||||
|
if(state >= 2+chns*2){
|
||||||
|
pulses2MHzWPtr--; //remove last stopbits and
|
||||||
|
_send_1(20000u*2 -1); //prolong them
|
||||||
|
state=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(SILVER) || defined(CTP1009)
|
||||||
|
void _send_hilo(uint16_t hi,uint16_t lo)
|
||||||
|
{
|
||||||
|
*pulses2MHzWPtr++=hi;
|
||||||
|
*pulses2MHzWPtr++=lo;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SILVER
|
||||||
|
|
||||||
|
#define BITLEN (600u*2)
|
||||||
|
#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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
pulses2MHzWPtr--;
|
||||||
|
send_hilo_silv(50,0); //low-impuls (pegel=1) ueberschreiben
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CTP1009
|
||||||
|
|
||||||
|
/*
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
if((pulses2MHzWPtr-pulses2MHz) >= (signed)DIM(pulses2MHz)) alert(PSTR("pulse tab overflow"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void setupPulses()
|
||||||
|
{
|
||||||
|
pulses2MHzWPtr = pulses2MHz;
|
||||||
|
pulses2MHzRPtr = pulses2MHz;
|
||||||
|
|
||||||
|
switch(g_model.protocol) {
|
||||||
|
case PROTO_PPM:
|
||||||
|
setupPulsesPPM();
|
||||||
|
break;
|
||||||
|
#ifdef SILVER
|
||||||
|
case PROTO_SILV_A:
|
||||||
|
case PROTO_SILV_B:
|
||||||
|
case PROTO_SILV_C:
|
||||||
|
setupPulsesSilver();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef CTP1009
|
||||||
|
case PROTO_CTP1009:
|
||||||
|
setupPulsesTracerCtp1009();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef PXX
|
||||||
|
case PROTO_PXX:
|
||||||
|
setupPulsesPXX();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef DSM2
|
||||||
|
case PROTO_DSM2:
|
||||||
|
setupPulsesDsm2(6);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue