/* * Authors (alphabetical order) * - Bertrand Songis * - Bryan J. Rentoul (Gruvin) * * gruvin9x is based on code named er9x by * Author - Erez Raviv , 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; uint8_t s_noScroll; 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(val0 ) {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 = 0; if (m_posVert==0 && !s_noScroll) { attr = INVERS; 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; } } s_noScroll = 0; 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(); 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() { if (g_menuStackPtr>0) { g_menuStackPtr = g_menuStackPtr-1; beepKey(); m_posHorz = 0; m_posVert = g_menuPos[g_menuStackPtr]; (*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; 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>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")); }