diff --git a/src/Makefile b/src/Makefile index d40bbfc7b..79fbec1e5 100644 --- a/src/Makefile +++ b/src/Makefile @@ -230,10 +230,6 @@ ifeq ($(FLIGHT_PHASES), YES) CPPDEFS += -DFLIGHT_PHASES endif -ifeq ($(HAPTIC), YES) - CPPDEFS += -DHAPTIC -endif - # If ARDUPILOT-Support is enabled ifeq ($(EXT), ARDUPILOT) CPPDEFS += -DARDUPILOT @@ -292,7 +288,7 @@ ifeq ($(PCB), ARM) # ersky9x/ff.c ersky9x/diskio_sam3s.c ersky9x/Media.c ersky9x/ccsbcs.c ersky9x/sdcard.c ersky9x/MEDSdcard.c EEPROMSRC = eeprom_arm.cpp PULSESSRC = pulses_arm.cpp - CPPSRC += audio.cpp + CPPSRC += audio.cpp haptic.cpp CPPSRC += ersky9x/sound.cpp endif @@ -304,7 +300,7 @@ ifeq ($(PCB), V4) BOARDSRC += board_gruvin9x.cpp EEPROMSRC = eeprom_avr.cpp PULSESSRC = pulses_avr.cpp - CPPSRC += audio.cpp + CPPSRC += audio.cpp haptic.cpp CPPSRC += gruvin9x/gtime.cpp CPPSRC += gruvin9x/rtc.cpp CPPSRC += gruvin9x/ff.cpp @@ -346,6 +342,12 @@ ifeq ($(PCB), STD) else CPPSRC += beeper.cpp endif + + ifeq ($(HAPTIC), YES) + CPPDEFS += -DHAPTIC + CPPSRC += haptic.cpp + endif + endif ### Global Build-Option Directives ### diff --git a/src/audio.cpp b/src/audio.cpp index 8bbb27a5a..5dd7dc49a 100644 --- a/src/audio.cpp +++ b/src/audio.cpp @@ -40,20 +40,8 @@ audioQueue::audioQueue() t_queueRidx = 0; t_queueWidx = 0; - -#ifdef HAPTIC - hapticTick = 0; - hapticSpinUpTime = 0; -#endif } -#if 0 -bool audioQueue::freeslots(uint8_t slots) -{ - return AUDIO_QUEUE_LENGTH - ((t_queueWidx + AUDIO_QUEUE_LENGTH - t_queueRidx) % AUDIO_QUEUE_LENGTH) >= slots; -} -#endif - // heartbeat is responsibile for issueing the audio tones and general square waves // it is essentially the life of the class. // it is called every 10ms @@ -70,27 +58,8 @@ void audioQueue::heartbeat() toneFreqIncr * 61 / 2)) { toneTimeLeft = 0; //time gets counted down } - - -#if defined(HAPTIC) - - if (toneHaptic) { - hapticOn((g_eeGeneral.hapticStrength * 2) * 10); - hapticSpinUpTime = HAPTIC_SPINUP; //min time haptic runs for. Might be worth a config option in system prefs to allow user to set to suit motor? - } - -#endif } else { - -#if defined(HAPTIC) - if(hapticSpinUpTime > 0){ - hapticSpinUpTime--; - } else { - hapticOff(); - } -#endif - if (tonePause) { if (queueTone(0, tonePause * 10, 0)) { tonePause = 0; //time gets counted down @@ -102,8 +71,6 @@ void audioQueue::heartbeat() toneTimeLeft = queueToneLength[t_queueRidx]; toneFreqIncr = queueToneFreqIncr[t_queueRidx]; tonePause = queueTonePause[t_queueRidx]; - toneHaptic = queueToneHaptic[t_queueRidx]; - hapticTick = 0; if (!queueToneRepeat[t_queueRidx]--) { t_queueRidx = (t_queueRidx + 1) % AUDIO_QUEUE_LENGTH; } @@ -120,23 +87,10 @@ void audioQueue::heartbeat() #endif toneTimeLeft--; //time gets counted down toneFreq += toneFreqIncr; - -#if defined(HAPTIC) - if (toneHaptic){ - if (hapticTick-- > 0) { - HAPTIC_ON; // haptic output 'high' - } - else { - HAPTIC_OFF; // haptic output 'low' - hapticTick = g_eeGeneral.hapticStrength; - } - } -#endif } else { SPEAKER_OFF; - HAPTIC_OFF; - + if (tonePause > 0) { tonePause--; } @@ -145,9 +99,7 @@ void audioQueue::heartbeat() toneTimeLeft = queueToneLength[t_queueRidx]; toneFreqIncr = queueToneFreqIncr[t_queueRidx]; tonePause = queueTonePause[t_queueRidx]; -#if defined(HAPTIC) - toneHaptic = queueToneHaptic[t_queueRidx]; -#endif + if (!queueToneRepeat[t_queueRidx]--) { t_queueRidx = (t_queueRidx + 1) % AUDIO_QUEUE_LENGTH; } @@ -169,38 +121,30 @@ inline uint8_t audioQueue::getToneLength(uint8_t tLen) } bool s_beeper; -#if defined(HAPTIC) -bool s_haptic; -#endif + void audioQueue::playNow(uint8_t tFreq, uint8_t tLen, uint8_t tPause, - uint8_t tRepeat, uint8_t tHaptic, int8_t tFreqIncr) + uint8_t tRepeat, int8_t tFreqIncr) { toneFreq = ((s_beeper && tFreq) ? tFreq + g_eeGeneral.speakerPitch + BEEP_OFFSET : 0); // add pitch compensator toneTimeLeft = getToneLength(tLen); tonePause = tPause; -#if defined(HAPTIC) - toneHaptic = s_haptic ? tHaptic : 0; -#endif toneFreqIncr = tFreqIncr; t_queueWidx = t_queueRidx; if (tRepeat) { - playASAP(tFreq, tLen, tPause, tRepeat-1, tHaptic, tFreqIncr); + playASAP(tFreq, tLen, tPause, tRepeat-1, tFreqIncr); } } void audioQueue::playASAP(uint8_t tFreq, uint8_t tLen, uint8_t tPause, - uint8_t tRepeat, uint8_t tHaptic, int8_t tFreqIncr) + uint8_t tRepeat, int8_t tFreqIncr) { uint8_t next_queueWidx = (t_queueWidx + 1) % AUDIO_QUEUE_LENGTH; if (next_queueWidx != t_queueRidx) { queueToneFreq[t_queueWidx] = ((s_beeper && tFreq) ? tFreq + g_eeGeneral.speakerPitch + BEEP_OFFSET : 0); // add pitch compensator queueToneLength[t_queueWidx] = getToneLength(tLen); queueTonePause[t_queueWidx] = tPause; -#if defined(HAPTIC) - queueToneHaptic[t_queueWidx] = s_haptic ? tHaptic : 0; -#endif queueToneRepeat[t_queueWidx] = tRepeat; queueToneFreqIncr[t_queueWidx] = tFreqIncr; t_queueWidx = next_queueWidx; @@ -210,9 +154,6 @@ void audioQueue::playASAP(uint8_t tFreq, uint8_t tLen, uint8_t tPause, void audioQueue::event(uint8_t e, uint8_t f) { s_beeper = (g_eeGeneral.beeperMode>0 || (g_eeGeneral.beeperMode==0 && e>=AU_WARNING1) || (g_eeGeneral.beeperMode>=-1 && e<=AU_ERROR)); -#if defined(HAPTIC) - s_haptic = (g_eeGeneral.hapticMode>0 || (g_eeGeneral.hapticMode==0 && e>=AU_WARNING1) || (g_eeGeneral.hapticMode>=-1 && e<=AU_ERROR)); -#endif if (g_eeGeneral.flashBeep && (e <= AU_ERROR || e >= AU_WARNING1)) g_LightOffCounter = FLASH_DURATION; // we got an event do we need to flash the display ? if (e < AU_FRSKY_FIRST || empty()) { switch (e) { @@ -223,25 +164,25 @@ void audioQueue::event(uint8_t e, uint8_t f) // low battery in tx case AU_TX_BATTERY_LOW: if (empty()) { - playASAP(60, 20, 3, 2, 0, 1); - playASAP(80, 20, 3, 2, 1, -1); + playASAP(60, 20, 3, 2, 1); + playASAP(80, 20, 3, 2, -1); } break; // error case AU_ERROR: - playNow(BEEP_DEFAULT_FREQ, 40, 1, 0, 1); + playNow(BEEP_DEFAULT_FREQ, 40, 1, 0); break; // keypad up (seems to be used when going left/right through system menu options. 0-100 scales etc) case AU_KEYPAD_UP: - playNow(BEEP_KEY_UP_FREQ, 10, 1, 0, 1); + playNow(BEEP_KEY_UP_FREQ, 10, 1, 0); break; // keypad down (seems to be used when going left/right through system menu options. 0-100 scales etc) case AU_KEYPAD_DOWN: - playNow(BEEP_KEY_DOWN_FREQ, 10, 1, 0, 1); + playNow(BEEP_KEY_DOWN_FREQ, 10, 1, 0); break; // menu display (also used by a few generic beeps) case AU_MENUS: - playNow(BEEP_DEFAULT_FREQ, 10, 2, 0, 1); + playNow(BEEP_DEFAULT_FREQ, 10, 2, 0); break; // trim move case AU_TRIM_MOVE: @@ -249,19 +190,19 @@ void audioQueue::event(uint8_t e, uint8_t f) break; // trim center case AU_TRIM_MIDDLE: - playNow(BEEP_DEFAULT_FREQ, 10, 2, 0, 1); + playNow(BEEP_DEFAULT_FREQ, 10, 2, 0); break; // warning one case AU_WARNING1: - playNow(BEEP_DEFAULT_FREQ, 10, 1, 0, 1); + playNow(BEEP_DEFAULT_FREQ, 10, 1, 0); break; // warning two case AU_WARNING2: - playNow(BEEP_DEFAULT_FREQ, 20, 1, 0, 1); + playNow(BEEP_DEFAULT_FREQ, 20, 1, 0); break; // warning three case AU_WARNING3: - playNow(BEEP_DEFAULT_FREQ, 30, 1, 0, 1); + playNow(BEEP_DEFAULT_FREQ, 30, 1, 0); break; // startup tune case AU_TADA: @@ -271,63 +212,63 @@ void audioQueue::event(uint8_t e, uint8_t f) break; // pot/stick center case AU_POT_STICK_MIDDLE: - playNow(BEEP_DEFAULT_FREQ + 50, 10, 1, 0, 0); + playNow(BEEP_DEFAULT_FREQ + 50, 10, 1, 0); break; // mix warning 1 case AU_MIX_WARNING_1: - playNow(BEEP_DEFAULT_FREQ + 50, 6, 0, 0, 1); + playNow(BEEP_DEFAULT_FREQ + 50, 6, 0, 0); break; // mix warning 2 case AU_MIX_WARNING_2: - playNow(BEEP_DEFAULT_FREQ + 52, 6, 0, 0, 1); + playNow(BEEP_DEFAULT_FREQ + 52, 6, 0, 0); break; // mix warning 3 case AU_MIX_WARNING_3: - playNow(BEEP_DEFAULT_FREQ + 54, 6, 0, 0, 1); + playNow(BEEP_DEFAULT_FREQ + 54, 6, 0, 0); break; // time 30 seconds left case AU_TIMER_30: - playNow(BEEP_DEFAULT_FREQ + 50, 15, 3, 3, 1); + playNow(BEEP_DEFAULT_FREQ + 50, 15, 3, 3); break; // time 20 seconds left case AU_TIMER_20: - playNow(BEEP_DEFAULT_FREQ + 50, 15, 3, 2, 1); + playNow(BEEP_DEFAULT_FREQ + 50, 15, 3, 2); break; // time 10 seconds left case AU_TIMER_10: - playNow(BEEP_DEFAULT_FREQ + 50, 15, 3, 1, 1); + playNow(BEEP_DEFAULT_FREQ + 50, 15, 3, 1); break; // time <3 seconds left case AU_TIMER_LT3: - playNow(BEEP_DEFAULT_FREQ, 20, 25, 1, 1); + playNow(BEEP_DEFAULT_FREQ, 20, 25, 1); break; case AU_FRSKY_WARN1: - playASAP(BEEP_DEFAULT_FREQ+20,15,5,2,1); + playASAP(BEEP_DEFAULT_FREQ+20,15,5,2); break; case AU_FRSKY_WARN2: - playASAP(BEEP_DEFAULT_FREQ+30,15,5,2,1); + playASAP(BEEP_DEFAULT_FREQ+30,15,5,2); break; case AU_FRSKY_CHEEP: - playASAP(BEEP_DEFAULT_FREQ+30,10,2,2,1,2); + playASAP(BEEP_DEFAULT_FREQ+30,10,2,2,2); break; case AU_FRSKY_RING: - playASAP(BEEP_DEFAULT_FREQ+25,5,2,10,1); - playASAP(BEEP_DEFAULT_FREQ+25,5,10,1,1); - playASAP(BEEP_DEFAULT_FREQ+25,5,2,10,1); + playASAP(BEEP_DEFAULT_FREQ+25,5,2,10); + playASAP(BEEP_DEFAULT_FREQ+25,5,10,1); + playASAP(BEEP_DEFAULT_FREQ+25,5,2,10); break; case AU_FRSKY_SCIFI: - playASAP(80,10,3,2,0,-1); - playASAP(60,10,3,2,0,1); - playASAP(70,10,1,0,2); + playASAP(80,10,3,2,-1); + playASAP(60,10,3,2,1); + playASAP(70,10,1,0); break; case AU_FRSKY_ROBOT: - playASAP(70,5,1,1,1); - playASAP(50,15,2,1,1); - playASAP(80,15,2,1,1); + playASAP(70,5,1,1); + playASAP(50,15,2,1); + playASAP(80,15,2,1); break; case AU_FRSKY_CHIRP: - playASAP(BEEP_DEFAULT_FREQ+40,5,1,2,1); - playASAP(BEEP_DEFAULT_FREQ+54,5,1,3,1); + playASAP(BEEP_DEFAULT_FREQ+40,5,1,2); + playASAP(BEEP_DEFAULT_FREQ+54,5,1,3); break; case AU_FRSKY_TADA: playASAP(50,5,5); @@ -335,40 +276,25 @@ void audioQueue::event(uint8_t e, uint8_t f) playASAP(110,3,4,2); break; case AU_FRSKY_CRICKET: - playASAP(80,5,10,3,1); - playASAP(80,5,20,1,1); - playASAP(80,5,10,3,1); + playASAP(80,5,10,3); + playASAP(80,5,20,1); + playASAP(80,5,10,3); break; case AU_FRSKY_SIREN: - playASAP(10,20,5,2,1,1); + playASAP(10,20,5,2,1); break; case AU_FRSKY_ALARMC: - playASAP(50,4,10,2,1); - playASAP(70,8,20,1,1); - playASAP(50,8,10,2,1); - playASAP(70,4,20,1,1); + playASAP(50,4,10,2); + playASAP(70,8,20,1); + playASAP(50,8,10,2); + playASAP(70,4,20,1); break; case AU_FRSKY_RATATA: - playASAP(BEEP_DEFAULT_FREQ+50,5,10,10,1); + playASAP(BEEP_DEFAULT_FREQ+50,5,10,10); break; case AU_FRSKY_TICK: - playASAP(BEEP_DEFAULT_FREQ+50,5,50,2,1); + playASAP(BEEP_DEFAULT_FREQ+50,5,50,2); break; -#ifdef HAPTIC - case AU_FRSKY_HAPTIC1: - playASAP(0,30,10,0,1); - playASAP(0,10,50,0,1); - break; - case AU_FRSKY_HAPTIC2: - playASAP(0,30,10,0,1); - playASAP(0,10,10,0,1); - playASAP(0,10,30,0,1); - break; - case AU_FRSKY_HAPTIC3: - playASAP(0,30,10,0,1); - playASAP(0,10,10,2,1); - break; -#endif default: break; } @@ -378,4 +304,7 @@ void audioQueue::event(uint8_t e, uint8_t f) void audioDefevent(uint8_t e) { audio.event(e, BEEP_DEFAULT_FREQ); +#ifdef HAPTIC + hapticAudioEvent(e); +#endif } diff --git a/src/audio.h b/src/audio.h index 1647274e7..8ba66e320 100644 --- a/src/audio.h +++ b/src/audio.h @@ -34,13 +34,6 @@ #ifndef audio_h #define audio_h -//#define ISER9X //enable this define for er9x. comment out for open9x - -#if defined(ISER9X) -#define HAPTIC -#define PCBSTD -#endif - #if defined(PCBARM) #include "ersky9x/sound.h" #endif @@ -66,10 +59,10 @@ enum AUDIO_SOUNDS { AU_KEYPAD_DOWN, AU_MENUS, AU_TRIM_MOVE, - AU_TRIM_MIDDLE, AU_WARNING1, AU_WARNING2, AU_WARNING3, + AU_TRIM_MIDDLE, AU_TADA, AU_POT_STICK_MIDDLE, AU_MIX_WARNING_1, @@ -93,11 +86,6 @@ enum AUDIO_SOUNDS { AU_FRSKY_ALARMC, AU_FRSKY_RATATA, AU_FRSKY_TICK, -#ifdef HAPTIC - AU_FRSKY_HAPTIC1, - AU_FRSKY_HAPTIC2, - AU_FRSKY_HAPTIC3, -#endif AU_FRSKY_LAST, }; @@ -109,9 +97,9 @@ class audioQueue // only difference between these two functions is that one does the // interupt queue (Now) and the other queues for playing ASAP. - void playNow(uint8_t tFreq, uint8_t tLen, uint8_t tPause, uint8_t tRepeat=0, uint8_t tHaptic=0, int8_t tFreqIncr=0); + void playNow(uint8_t tFreq, uint8_t tLen, uint8_t tPause, uint8_t tRepeat=0, int8_t tFreqIncr=0); - void playASAP(uint8_t tFreq, uint8_t tLen, uint8_t tPause, uint8_t tRepeat=0, uint8_t tHaptic=0, int8_t tFreqIncr=0); + void playASAP(uint8_t tFreq, uint8_t tLen, uint8_t tPause, uint8_t tRepeat=0, int8_t tFreqIncr=0); inline bool busy() { return (toneTimeLeft > 0); } @@ -184,13 +172,6 @@ class audioQueue uint8_t queueTonePause[AUDIO_QUEUE_LENGTH]; uint8_t queueToneRepeat[AUDIO_QUEUE_LENGTH]; -#ifdef HAPTIC - uint8_t toneHaptic; - uint8_t hapticTick; - uint8_t queueToneHaptic[AUDIO_QUEUE_LENGTH]; - uint8_t hapticSpinUpTime; -#endif - #if defined(PCBSTD) uint8_t toneCounter; #endif @@ -201,8 +182,6 @@ extern audioQueue audio; void audioDefevent(uint8_t e); -#define HAPTIC_SPINUP (10); - #define AUDIO_KEYPAD_UP() audioDefevent(AU_KEYPAD_UP) #define AUDIO_KEYPAD_DOWN() audioDefevent(AU_KEYPAD_DOWN) #define AUDIO_MENUS() audioDefevent(AU_MENUS) @@ -225,6 +204,7 @@ void audioDefevent(uint8_t e); #define AUDIO_POT_STICK_MIDDLE() audioDefevent(AU_POT_STICK_MIDDLE) #define AUDIO_VARIO_UP() audioDefevent(AU_KEYPAD_UP) #define AUDIO_VARIO_DOWN() audioDefevent(AU_KEYPAD_DOWN) +#define AUDIO_TRIM_MIDDLE() audioDefevent(AU_TRIM_MIDDLE) #if defined(PCBSTD) #define AUDIO_DRIVER() audio.driver() diff --git a/src/beeper.cpp b/src/beeper.cpp index a817de706..6c995c224 100644 --- a/src/beeper.cpp +++ b/src/beeper.cpp @@ -39,9 +39,6 @@ uint8_t beepAgainOrig = 0; uint8_t beepOn = false; bool warble = false; bool warbleC; -#if defined(HAPTIC) -uint8_t hapticTick = 0; -#endif // The various "beep" tone lengths static const pm_uint8_t beepTab[] PROGMEM = { @@ -60,4 +57,7 @@ void beep(uint8_t val) if (g_eeGeneral.beeperMode>0 || (g_eeGeneral.beeperMode==0 && val!=0) || (g_eeGeneral.beeperMode==-1 && val>=3)) { _beep(pgm_read_byte(beepTab+5*(2+g_eeGeneral.beeperLength)+val)); } +#ifdef HAPTIC + hapticBeepEvent(val); +#endif } diff --git a/src/beeper.h b/src/beeper.h index 2f4a54716..bc059da62 100644 --- a/src/beeper.h +++ b/src/beeper.h @@ -40,9 +40,6 @@ extern uint8_t beepAgainOrig; extern uint8_t beepOn; extern bool warble; extern bool warbleC; -#if defined(HAPTIC) -extern uint8_t hapticTick; -#endif #if defined(PCBARM) #include "ersky9x/sound.h" @@ -76,6 +73,7 @@ extern void beep(uint8_t val); #define AUDIO_POT_STICK_MIDDLE() beep(2) #define AUDIO_VARIO_UP() _beep(1) #define AUDIO_VARIO_DOWN() _beep(1) +#define AUDIO_TRIM_MIDDLE() beep(2) #define IS_AUDIO_BUSY() (g_beepCnt || beepAgain || beepOn) @@ -109,19 +107,9 @@ FORCEINLINE void AUDIO_HEARTBEAT() BUZZER_OFF; else BUZZER_ON; -#if defined(HAPTIC) - if (hapticTick-- > 0) { - HAPTIC_ON; // haptic output 'high' - } - else { - HAPTIC_OFF; // haptic output 'low' - hapticTick = g_eeGeneral.hapticStrength; - } -#endif } else { BUZZER_OFF; - HAPTIC_OFF; } } #endif diff --git a/src/eeprom_arm.cpp b/src/eeprom_arm.cpp index e526d3134..89ca64bdb 100644 --- a/src/eeprom_arm.cpp +++ b/src/eeprom_arm.cpp @@ -495,7 +495,7 @@ void eeLoadModel(uint8_t id) resetProto(); resetAll(); -#ifdef LOGS +#ifdef SDCARD initLogs(); #endif } diff --git a/src/eeprom_avr.cpp b/src/eeprom_avr.cpp index e2ee151eb..5dbbe1787 100644 --- a/src/eeprom_avr.cpp +++ b/src/eeprom_avr.cpp @@ -526,6 +526,34 @@ bool RlcFile::copy(uint8_t i_fileDst, uint8_t i_fileSrc) return true; } +#ifdef SDCARD +const pm_char * eeArchiveModel(uint8_t i_fileSrc) +{ + char buf[15]; + FIL archiveFile; + + eeLoadModelName(i_fileSrc, buf); + + FRESULT result = f_open(&archiveFile, buf, FA_OPEN_ALWAYS | FA_WRITE); + if (result != FR_OK) { + return SDCARD_ERROR(result); + } + + EFile theFile2; + theFile2.openRd(i_fileSrc); + + uint8_t len; + while ((len=theFile2.read((uint8_t *)buf, 15))) + { + for (uint8_t i=0; i7*FH) return; }subN++; @@ -170,7 +177,7 @@ void menuProcSetup(uint8_t event) #ifdef AUDIO if(s_pgOfs7*FH) return; }subN++; if(s_pgOfs7*FH) return; }subN++; + + if(s_pgOfs7*FH) return; + }subN++; + #endif -// TODO port onoffMenuItem here to save flash #if defined(PCBARM) if(s_pgOfs7*FH) return; }subN++; if(s_pgOfs7*FH) return; }subN++; if(s_pgOfs7*FH) return; @@ -246,42 +258,34 @@ void menuProcSetup(uint8_t event) if(s_pgOfs7*FH) return; }subN++; if(s_pgOfs7*FH) return; }subN++; if(s_pgOfs7*FH) return; }subN++; if(s_pgOfs7*FH) return; }subN++; if(s_pgOfs7*FH) return; + g_eeGeneral.flashBeep = onoffMenuItem( g_eeGeneral.flashBeep, y, STR_FLASHONBEEP, sub==subN, event ) ; + if((y+=FH)>7*FH) return; }subN++; if(s_pgOfs7*FH) return; }subN++; @@ -289,11 +293,11 @@ void menuProcSetup(uint8_t event) if(s_pgOfs7*FH) return; @@ -301,77 +305,47 @@ void menuProcSetup(uint8_t event) #ifdef SPLASH if(s_pgOfs7*FH) return; + uint8_t b = 1-g_eeGeneral.disableSplashScreen; + g_eeGeneral.disableSplashScreen = 1 - onoffMenuItem( b, y, STR_SPLASHSCREEN, sub==subN, event ) ; + if((y+=FH)>7*FH) return; }subN++; #endif if(s_pgOfs7*FH) return; + uint8_t b = 1-g_eeGeneral.disableThrottleWarning; + g_eeGeneral.disableThrottleWarning = 1-onoffMenuItem( b, y, STR_THROTTLEWARNING, sub==subN, event ) ; + if((y+=FH)>7*FH) return; }subN++; if(s_pgOfs7*FH) return; }subN++; if(s_pgOfs7*FH) return; + uint8_t b = 1-g_eeGeneral.disableMemoryWarning; + g_eeGeneral.disableMemoryWarning = 1 - onoffMenuItem( b, y, STR_MEMORYWARNING, sub==subN, event ) ; + if((y+=FH)>7*FH) return; }subN++; if(s_pgOfs7*FH) return; + uint8_t b = 1-g_eeGeneral.disableAlarmWarning; + g_eeGeneral.disableAlarmWarning = 1 - onoffMenuItem( b, y, STR_ALARMWARNING, sub==subN, event ) ; + if((y+=FH)>7*FH) return; }subN++; #ifdef FRSKY if(s_pgOfs7*FH) return; + uint8_t b = g_eeGeneral.enableTelemetryAlarm; + g_eeGeneral.disableAlarmWarning = onoffMenuItem( b, y, STR_NODATAALARM, sub==subN, event ) ; + if((y+=FH)>7*FH) return; }subN++; if(s_pgOfs7*FH) return; @@ -379,7 +353,7 @@ void menuProcSetup(uint8_t event) if(s_pgOfs7*FH) return; }subN++; diff --git a/src/gruvin9x/logs.cpp b/src/gruvin9x/logs.cpp index 91ef9170f..0ec1960c9 100644 --- a/src/gruvin9x/logs.cpp +++ b/src/gruvin9x/logs.cpp @@ -107,10 +107,7 @@ void initLogs() else { g_logState = -result; - if (result == FR_NOT_READY) - g_logError = PSTR("NO SDCARD"); - else - g_logError = PSTR("SDCARD ERROR"); + g_logError = SDCARD_ERROR(result); return; } } @@ -118,6 +115,14 @@ void initLogs() // g_logFilename should now be set appropriately. } +const pm_char *SDCARD_ERROR(FRESULT result) +{ + if (result == FR_NOT_READY) + return STR_NO_SDCARD; + else + return STR_SDCARD_ERROR; +} + void writeLogs() { FRESULT result; diff --git a/src/gruvin9x/logs.h b/src/gruvin9x/logs.h index 185f8e79c..578ef9e2f 100644 --- a/src/gruvin9x/logs.h +++ b/src/gruvin9x/logs.h @@ -44,5 +44,7 @@ extern FIL g_oLogFile; extern void initLogs(); extern void writeLogs(); +const pm_char *SDCARD_ERROR(FRESULT result); + #endif diff --git a/src/haptic.cpp b/src/haptic.cpp new file mode 100644 index 000000000..229de62c8 --- /dev/null +++ b/src/haptic.cpp @@ -0,0 +1,150 @@ +/* + * Authors (alphabetical order) + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - Thomas Husterer + * + * open9x is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "open9x.h" + +hapticQueue::hapticQueue() +{ + buzzTimeLeft = 0; + buzzPause = 0; + + t_queueRidx = 0; + t_queueWidx = 0; + + hapticTick = 0; +} + +void hapticQueue::heartbeat() +{ +#if defined(SIMU) + return; +#endif + +#if defined(PCBARM) + if (buzzTimeLeft > 0) { + buzzTimeLeft--; //time gets counted down + hapticOn((g_eeGeneral.hapticStrength * 2) * 10); + } + else { + hapticOff(); + + if (buzzPause > 0) { + buzzPause--; + } + else if (t_queueRidx != t_queueWidx) { + buzzTimeLeft = queueHapticLength[t_queueRidx]; + buzzPause = queueHapticPause[t_queueRidx]; + if (!queueHapticRepeat[t_queueRidx]--) { + t_queueRidx = (t_queueRidx + 1) % HAPTIC_QUEUE_LENGTH; + } + } + } +#else + if (buzzTimeLeft > 0) { + buzzTimeLeft--; // time gets counted down + + if (hapticTick-- > 0) { + HAPTIC_ON; // haptic output 'high' + } + else { + HAPTIC_OFF; // haptic output 'high' + hapticTick = g_eeGeneral.hapticStrength; + } + } + else { + HAPTIC_OFF; // haptic output 'high' + if (buzzPause > 0) { + buzzPause--; + } + else if (t_queueRidx != t_queueWidx) { + buzzTimeLeft = queueHapticLength[t_queueRidx]; + buzzPause = queueHapticPause[t_queueRidx]; + if (!queueHapticRepeat[t_queueRidx]--) { + t_queueRidx = (t_queueRidx + 1) % HAPTIC_QUEUE_LENGTH; + } + } + } +#endif +} + +inline uint8_t hapticQueue::getHapticLength(uint8_t tLen) +{ + return ((g_eeGeneral.hapticLength * 2) + tLen) * 2; +} + +void hapticQueue::playNow(uint8_t tLen, uint8_t tPause, uint8_t tRepeat) +{ + buzzTimeLeft = getHapticLength(tLen); + buzzPause = tPause; + t_queueWidx = t_queueRidx; + + if (tRepeat) { + playASAP(tLen, tPause, tRepeat-1); + } +} + +void hapticQueue::playASAP(uint8_t tLen, uint8_t tPause, uint8_t tRepeat) +{ + uint8_t next_queueWidx = (t_queueWidx + 1) % HAPTIC_QUEUE_LENGTH; + if (next_queueWidx != t_queueRidx) { + queueHapticLength[t_queueWidx] = getHapticLength(tLen); + queueHapticPause[t_queueWidx] = tPause; + queueHapticRepeat[t_queueWidx] = tRepeat-1; + t_queueWidx = next_queueWidx; + } +} + +void hapticQueue::event(uint8_t e) +{ + switch (e) { + case 0: // very little buzz for keys / trims + playNow(5, 0, 0); + break; + case 1: // one buzz + playASAP(10,2,1); + break; + case 2: // two buzz + playASAP(10,2,2); + break; + case 3: // three buzz + playASAP(10,2,3); + break; + default: + break; + } +} + +void hapticDefevent(uint8_t e) +{ + haptic.event(e); +} diff --git a/src/haptic.h b/src/haptic.h new file mode 100644 index 000000000..6be7fed3a --- /dev/null +++ b/src/haptic.h @@ -0,0 +1,114 @@ +/* + * Authors (alphabetical order) + * - Bertrand Songis + * - Bryan J. Rentoul (Gruvin) + * - Cameron Weeks + * - Erez Raviv + * - Jean-Pierre Parisy + * - Karl Szmutny + * - Michael Blandford + * - Michal Hlavinka + * - Pat Mackenzie + * - Philip Moss + * - Rob Thomson + * - Romolo Manfredini + * - Thomas Husterer + * + * open9x is based on code named + * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, + * er9x by Erez Raviv: http://code.google.com/p/er9x/, + * and the original (and ongoing) project by + * Thomas Husterer, th9x: http://code.google.com/p/th9x/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef haptic_h +#define haptic_h + +#define HAPTIC_QUEUE_LENGTH 3 + +class hapticQueue +{ + public: + + hapticQueue(); + + // only difference between these two functions is that one does the + // interupt queue (Now) and the other queues for playing ASAP. + void playNow(uint8_t tLen, uint8_t tPause, uint8_t tRepeat=0); + + void playASAP(uint8_t tLen, uint8_t tPause, uint8_t tRepeat=0); + + inline bool busy() { return (buzzTimeLeft > 0); } + + void event(uint8_t e); + + // heartbeat is responsibile for issueing the haptic buzzs and general square waves + // it is essentially the life of the class. + void heartbeat(); + + // bool freeslots(uint8_t slots); + + inline bool empty() { + return (t_queueRidx == t_queueWidx); + } + + protected: + inline uint8_t getHapticLength(uint8_t tLen); + + private: + uint8_t t_queueRidx; + uint8_t t_queueWidx; + + uint8_t buzzTimeLeft; + uint8_t buzzPause; + + uint8_t hapticTick; + + // queue arrays + uint8_t queueHapticLength[HAPTIC_QUEUE_LENGTH]; + uint8_t queueHapticPause[HAPTIC_QUEUE_LENGTH]; + uint8_t queueHapticRepeat[HAPTIC_QUEUE_LENGTH]; +}; + +//wrapper function - dirty but results in a space saving!!! +extern hapticQueue haptic; + +void hapticDefevent(uint8_t e); + +#define IS_HAPTIC_BUSY() haptic.busy() + +#define HAPTIC_HEARTBEAT() haptic.heartbeat() + +#ifdef AUDIO +inline void hapticAudioEvent(uint8_t e) +{ + if (g_eeGeneral.hapticMode>=-1 && e<=AU_ERROR) + hapticDefevent(1); + else if (g_eeGeneral.hapticMode==0 && e>=AU_WARNING1) + hapticDefevent(1); + else if (g_eeGeneral.hapticMode>0) + hapticDefevent(0); +} +#else +inline void hapticBeepEvent(uint8_t e) +{ + if (g_eeGeneral.hapticMode>=-1 && e>=3) + hapticDefevent(1); + else if (g_eeGeneral.hapticMode==0 && e>0) + hapticDefevent(1); + else if (g_eeGeneral.hapticMode>0) + hapticDefevent(0); +} +#endif + +#endif // haptic_h diff --git a/src/model_menus.cpp b/src/model_menus.cpp index dda3df658..44070b68d 100644 --- a/src/model_menus.cpp +++ b/src/model_menus.cpp @@ -122,6 +122,11 @@ inline int8_t eeFindEmptyModel(uint8_t id, bool down) return i; } +#ifdef SDCARD +// TODO to be elsewhere if common to many menus +const pm_char * s_sdcard_error = NULL; +#endif + void menuProcModelSelect(uint8_t event) { TITLE(STR_MENUMODELSEL); @@ -138,7 +143,7 @@ void menuProcModelSelect(uint8_t event) } #if defined(SDCARD) - uint8_t _event = (s_warning || s_menu_count) ? 0 : event; + uint8_t _event = (s_warning || s_sdcard_error || s_menu_count) ? 0 : event; #else uint8_t _event = s_warning ? 0 : event; #endif @@ -356,6 +361,12 @@ void menuProcModelSelect(uint8_t event) } #if defined(SDCARD) + if (s_sdcard_error) { + s_warning = s_sdcard_error; + displayWarning(event); + s_warning = NULL; + } + if (s_menu_count) { const pm_char * result = displayMenu(event); if (result) { @@ -369,7 +380,7 @@ void menuProcModelSelect(uint8_t event) } } else if (result == STR_ARCHIVE_MODEL) { - // TODO + s_sdcard_error = eeArchiveModel(sub); } else if (result == STR_RESTORE_MODEL) { // TODO @@ -1651,14 +1662,22 @@ void menuProcMixAll(uint8_t event) void menuProcLimits(uint8_t event) { - MENU(STR_MENULIMITS, menuTabModel, e_Limits, 1+NUM_CHNOUT+1, {0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0}); +#ifdef LIMITS_US +#define LIMITS_ITEMS_COUNT 4 +#else +#define LIMITS_ITEMS_COUNT 3 +#endif + + MENU(STR_MENULIMITS, menuTabModel, e_Limits, 1+NUM_CHNOUT+1, {0, LIMITS_ITEMS_COUNT, LIMITS_ITEMS_COUNT, LIMITS_ITEMS_COUNT, LIMITS_ITEMS_COUNT, LIMITS_ITEMS_COUNT, LIMITS_ITEMS_COUNT, LIMITS_ITEMS_COUNT, LIMITS_ITEMS_COUNT, LIMITS_ITEMS_COUNT, LIMITS_ITEMS_COUNT, LIMITS_ITEMS_COUNT, LIMITS_ITEMS_COUNT, LIMITS_ITEMS_COUNT, LIMITS_ITEMS_COUNT, LIMITS_ITEMS_COUNT, LIMITS_ITEMS_COUNT, 0}); int8_t sub = m_posVert - 1; +#ifdef LIMITS_US if (sub >= 0) { lcd_outdezAtt(12*FW, 0, PPM_CENTER+g_model.servoCenter[sub]+g_chans512[sub]/2, 0); lcd_puts(12*FW, 0, STR_US); } +#endif for (uint8_t i=0; i<7; i++) { uint8_t y = (i+1)*FH; @@ -1677,21 +1696,32 @@ void menuProcLimits(uint8_t event) } LimitData *ld = limitaddress(k) ; + +#ifndef LIMITS_US + int16_t v = (ld->revert) ? -ld->offset : ld->offset; + + char swVal = '-'; // '-', '<', '>' + if((g_chans512[k] - v) > 50) swVal = (ld->revert ? 127 : 126); // Switch to raw inputs? - remove trim! + if((g_chans512[k] - v) < -50) swVal = (ld->revert ? 126 : 127); + putsChn(0, y, k+1, 0); + lcd_putcAtt(12*FW+5, y, swVal, 0); +#endif + int8_t limit = (g_model.extendedLimits ? 125 : 100); putsChn(0, y, k+1, 0); - for (uint8_t j=0; j<5; j++) { + for (uint8_t j=0; j<=LIMITS_ITEMS_COUNT; j++) { uint8_t attr = ((sub==k && m_posHorz==j) ? ((s_editMode>0) ? BLINK|INVERS : INVERS) : 0); uint8_t active = (attr && (s_editMode>0 || p1valdiff)) ; switch(j) { - case 0: + case 0: #ifdef LIMITS_US lcd_outdezAtt( 8*FW, y, ((ld->offset)*128) / 25, attr|PREC1); #else - lcd_outdezAtt( 8*FW, y, ld->offset, attr|PREC1); -#endif + lcd_outdezAtt( 8*FW, y, ld->offset, attr|PREC1); +#endif if (active) { ld->offset = checkIncDec(event, ld->offset, -1000, 1000, EE_MODEL|NO_INCDEC_MARKS); } @@ -1706,7 +1736,7 @@ void menuProcLimits(uint8_t event) #ifdef LIMITS_US lcd_outdezAtt(12*FW+1, y, (((int16_t)ld->min-100)*128) / 25, attr | INFLIGHT(ld->min)); #else - lcd_outdezAtt(12*FW+1, y, (int8_t)(ld->min-100), attr | INFLIGHT(ld->min)); + lcd_outdezAtt(12*FW, y, (int8_t)(ld->min-100), attr | INFLIGHT(ld->min)); #endif if (active) { CHECK_INFLIGHT_INCDEC_MODELVAR(event, ld->min, -limit, 25, +100, STR_MINLIMIT); @@ -1716,24 +1746,30 @@ void menuProcLimits(uint8_t event) #ifdef LIMITS_US lcd_outdezAtt(16*FW, y, (((int16_t)ld->max+100)*128) / 25, attr | INFLIGHT(ld->max)); #else - lcd_outdezAtt(16*FW, y, (int8_t)(ld->max+100), attr | INFLIGHT(ld->max)); + lcd_outdezAtt(17*FW, y, (int8_t)(ld->max+100), attr | INFLIGHT(ld->max)); #endif if (active) { CHECK_INFLIGHT_INCDEC_MODELVAR(event, ld->max, -25, limit, -100, STR_MAXLIMIT); } break; case 3: +#ifdef LIMITS_US lcd_putcAtt(17*FW-2, y, ld->revert ? 127 : 126, attr); +#else + lcd_putsiAtt(18*FW, y, STR_MMMINV, ld->revert, attr); +#endif if (active) { CHECK_INCDEC_MODELVAR(event, ld->revert, 0, 1); } break; +#ifdef LIMITS_US case 4: lcd_outdezAtt(21*FW+2, y, PPM_CENTER+g_model.servoCenter[k], attr); if (active) { CHECK_INCDEC_MODELVAR(event, g_model.servoCenter[k], -125, +125); } break; +#endif } } } @@ -1923,6 +1959,12 @@ void menuProcFunctionSwitches(uint8_t event) break; #endif } +#if defined(HAPTIC) + else if (sd->func == FUNC_HAPTIC) { + val_max = 3; + lcd_outdezAtt(21*FW, y, val_displayed, attr); + } +#endif #if defined(SOMO) else if (sd->func == FUNC_PLAY_SOMO) { lcd_outdezAtt(21*FW, y, val_displayed, attr); diff --git a/src/myeeprom.h b/src/myeeprom.h index ac0e59f4c..1e9090f93 100644 --- a/src/myeeprom.h +++ b/src/myeeprom.h @@ -251,15 +251,18 @@ enum Functions { FUNC_TRAINER_THR, FUNC_TRAINER_AIL, FUNC_INSTANT_TRIM, + FUNC_RESET, FUNC_PLAY_SOUND, +#ifdef HAPTIC + FUNC_HAPTIC, +#endif #ifdef SOMO FUNC_PLAY_SOMO, #endif - FUNC_RESET, #if defined(FRSKY_HUB) || defined(WS_HOW_HIGH) FUNC_VARIO, #endif -#ifdef LOGS +#ifdef SDCARD FUNC_LOGS, #endif #ifdef DEBUG diff --git a/src/o9xstrings.cpp b/src/o9xstrings.cpp index 9d5104d6d..2827c22f0 100644 --- a/src/o9xstrings.cpp +++ b/src/o9xstrings.cpp @@ -305,6 +305,8 @@ const pm_char STR_LOAD_MODEL[] PROGMEM = TR_LOAD_MODEL; const pm_char STR_ARCHIVE_MODEL[] PROGMEM = TR_ARCHIVE_MODEL; const pm_char STR_DELETE_MODEL[] PROGMEM = TR_DELETE_MODEL; const pm_char STR_RESTORE_MODEL[] PROGMEM = TR_RESTORE_MODEL; +const pm_char STR_SDCARD_ERROR[] PROGMEM = TR_SDCARD_ERROR; +const pm_char STR_NO_SDCARD[] PROGMEM = TR_NO_SDCARD; #endif const pm_uchar font[] PROGMEM = { diff --git a/src/o9xstrings.h b/src/o9xstrings.h index 4ad9a340a..6f12da71c 100644 --- a/src/o9xstrings.h +++ b/src/o9xstrings.h @@ -366,6 +366,8 @@ extern const pm_char STR_LOAD_MODEL[]; extern const pm_char STR_ARCHIVE_MODEL[]; extern const pm_char STR_DELETE_MODEL[]; extern const pm_char STR_RESTORE_MODEL[]; +extern const pm_char STR_SDCARD_ERROR[]; +extern const pm_char STR_NO_SDCARD[]; #endif extern const pm_uchar font[]; diff --git a/src/open9x.cpp b/src/open9x.cpp index 39956bd24..757e28aea 100644 --- a/src/open9x.cpp +++ b/src/open9x.cpp @@ -60,10 +60,13 @@ uint16_t g_time_per10; #endif #ifdef AUDIO -//new audio object audioQueue audio; #endif +#ifdef HAPTIC +hapticQueue haptic; +#endif + uint8_t heartbeat; uint8_t stickMode; @@ -905,7 +908,7 @@ uint8_t checkTrim(uint8_t event) if (beepTrim) { killEvents(event); - AUDIO_WARNING2(); + AUDIO_TRIM_MIDDLE(); } else { #if defined (AUDIO) @@ -1382,6 +1385,13 @@ void evalFunctions() beep(3); #endif } + +#if defined(HAPTIC) + if (sd->func == FUNC_HAPTIC) { + hapticDefevent(sd->param); + } +#endif + active_functions |= mask; } else { @@ -1937,7 +1947,7 @@ void perMain() if((inacCounter&0x3F)==10) AUDIO_INACTIVITY(); } -#if defined (LOGS) +#if defined(SDCARD) writeLogs(); #endif @@ -2039,6 +2049,7 @@ void perMain() #if defined(PCBARM) AUDIO_HEARTBEAT(); // the queue processing + HAPTIC_HEARTBEAT(); #endif } @@ -2109,6 +2120,10 @@ ISR(TIMER0_COMP_vect, ISR_NOBLOCK) //10ms timer AUDIO_HEARTBEAT(); +#ifdef HAPTIC + HAPTIC_HEARTBEAT(); +#endif + #ifdef DEBUG // Record start time from TCNT1 to record excution time cli(); diff --git a/src/open9x.h b/src/open9x.h index ee1a09d87..c0318fa05 100644 --- a/src/open9x.h +++ b/src/open9x.h @@ -818,7 +818,11 @@ extern uint16_t jeti_keys; #include "beeper.h" #endif -#ifdef LOGS +#if defined(HAPTIC) +#include "haptic.h" +#endif + +#if defined(SDCARD) #include "logs.h" #endif diff --git a/src/pulses_arm.cpp b/src/pulses_arm.cpp index 6141471bd..be109bfa4 100644 --- a/src/pulses_arm.cpp +++ b/src/pulses_arm.cpp @@ -140,7 +140,7 @@ void setupPulsesPPM() // Don't enable interrupts through here pwmptr = PWM; // Now set up pulses -#define PPM_CENTER 1500*2 + int16_t PPM_range = g_model.extendedLimits ? 640 * 2 : 512 * 2; //range of 0.7..1.7msec //Total frame length = 22.5msec @@ -155,7 +155,7 @@ void setupPulsesPPM() // Don't enable interrupts through here uint16_t rest = 22500u * 2; //Minimum Framelen=22.5 ms rest += (int16_t(g_model.ppmFrameLength)) * 1000; for (uint32_t i = 0; i < p; i++) { //NUM_CHNOUT - int16_t v = limit((int16_t)-PPM_range, g_chans512[i], (int16_t)PPM_range) + PPM_CENTER; + int16_t v = limit((int16_t)-PPM_range, g_chans512[i], (int16_t)PPM_range) + 2*PPM_CENTER; rest -= (v); *ptr++ = v; /* as Pat MacKenzie suggests */ } diff --git a/src/pulses_avr.cpp b/src/pulses_avr.cpp index 3737b0afa..44a0047b0 100644 --- a/src/pulses_avr.cpp +++ b/src/pulses_avr.cpp @@ -210,7 +210,11 @@ FORCEINLINE void setupPulsesPPM() uint16_t rest = 22500u*2-q; //Minimum Framelen=22.5 ms rest += (int16_t(g_model.ppmFrameLength))*1000; for (uint8_t i=0; i