diff --git a/App/apps/app_api.h b/App/apps/app_api.h index a1384ae0..7ed8b148 100644 --- a/App/apps/app_api.h +++ b/App/apps/app_api.h @@ -107,6 +107,8 @@ enum { APP_TRIVFO_TX = 1u << 3, APP_TRIVFO_USER_POWER = 1u << 4, APP_TRIVFO_AUDIO_BAR = 1u << 5, + APP_TRIVFO_GUI_CLASSIC = 1u << 6, + APP_TRIVFO_PTT_ONEPUSH = 1u << 7, }; enum { @@ -218,7 +220,7 @@ typedef struct app_api { void (*trivfo_select)(uint8_t vfo); uint16_t (*trivfo_step)(uint8_t vfo, int8_t direction); uint8_t (*trivfo_tick)(void); - uint8_t (*trivfo_ptt)(bool pressed); /* 0 OK; non-zero TX denial/timeout */ + uint8_t (*trivfo_ptt)(bool pressed); /* physical PTT edge; resident applies SetPTT */ } app_api_t; /* BK4819 AF modes for set_af (mirror driver/bk4819.h values). */ diff --git a/App/apps/app_overlay.c b/App/apps/app_overlay.c index 4fc849f0..fad7ba2c 100644 --- a/App/apps/app_overlay.c +++ b/App/apps/app_overlay.c @@ -101,8 +101,11 @@ static bool app_trivfo_ctcss_ok; static bool app_trivfo_cdcss_ok; static bool app_trivfo_ab_dirty; static bool app_trivfo_restore_selection; +static bool app_trivfo_onepush_stop_armed; static uint8_t app_trivfo_freq_dirty; +static void app_trivfo_end_tx(void); + static VFO_Info_t *app_trivfo_vfo(uint8_t vfo) { return vfo < 2u ? &gEeprom.VfoInfo[vfo] : &app_trivfo_c; @@ -228,6 +231,7 @@ static uint16_t app_trivfo_enter(uint16_t c_channel) app_trivfo_hold = 0; app_trivfo_running = true; app_trivfo_transmitting = false; + app_trivfo_onepush_stop_armed = false; app_trivfo_ab_dirty = false; app_trivfo_freq_dirty = 0; app_trivfo_tune(0); @@ -238,10 +242,8 @@ static void app_trivfo_leave(void) { if (!app_trivfo_running) return; - if (app_trivfo_transmitting) { - BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_PA_ENABLE, false); - BK4819_ToggleGpioOut(BK4819_GPIO5_PIN1_RED, false); - } + if (app_trivfo_transmitting) + app_trivfo_end_tx(); AUDIO_AudioPathOff(); gEnableSpeaker = false; app_trivfo_running = false; @@ -289,6 +291,8 @@ static void app_trivfo_get(uint8_t index, app_trivfo_info_t *info) #ifdef ENABLE_AUDIO_BAR if (gSetting_mic_bar) info->flags |= APP_TRIVFO_AUDIO_BAR; #endif + if (gSetting_set_gui) info->flags |= APP_TRIVFO_GUI_CLASSIC; + if (gSetting_set_ptt_session) info->flags |= APP_TRIVFO_PTT_ONEPUSH; if (IS_MR_CHANNEL(vfo->CHANNEL_SAVE)) memcpy(info->name, vfo->Name, sizeof(info->name) - 1u); } @@ -340,7 +344,17 @@ static uint16_t app_trivfo_step(uint8_t index, int8_t direction) return channel; } -static uint8_t app_trivfo_ptt(bool pressed); +static void app_trivfo_end_tx(void) +{ + if (!app_trivfo_transmitting) + return; + RADIO_SendEndOfTransmission(); + app_trivfo_transmitting = false; + app_trivfo_onepush_stop_armed = false; + BK4819_ToggleGpioOut(BK4819_GPIO5_PIN1_RED, false); + app_trivfo_hold = APP_TRIVFO_TX_HOLD_TICKS; + app_trivfo_tune(app_trivfo_selected); +} static uint8_t app_trivfo_tick(void) { @@ -349,7 +363,7 @@ static uint8_t app_trivfo_tick(void) if (app_trivfo_transmitting) { const uint32_t timeout = ((uint32_t)gEeprom.TX_TIMEOUT_TIMER + 1u) * 250u; if (++app_trivfo_tx_ticks >= timeout) { - app_trivfo_ptt(false); + app_trivfo_end_tx(); return APP_TRIVFO_HOLD; } return APP_TRIVFO_TX_STATE; @@ -420,15 +434,18 @@ static uint8_t app_trivfo_ptt(bool pressed) if (!pressed) { if (!app_trivfo_transmitting) return 0; - RADIO_SendEndOfTransmission(); - app_trivfo_transmitting = false; - BK4819_ToggleGpioOut(BK4819_GPIO5_PIN1_RED, false); - app_trivfo_hold = APP_TRIVFO_TX_HOLD_TICKS; - app_trivfo_tune(app_trivfo_selected); + /* ONEPUSH mirrors the resident PTT sequence: the first release keeps + * TX keyed; the release following the second press ends TX. */ + if (gSetting_set_ptt_session && !app_trivfo_onepush_stop_armed) + return 0; + app_trivfo_end_tx(); return 0; } - if (app_trivfo_transmitting) + if (app_trivfo_transmitting) { + if (gSetting_set_ptt_session) + app_trivfo_onepush_stop_armed = true; return 0; + } VFO_Info_t *vfo = app_trivfo_vfo(app_trivfo_selected); if ((TX_freq_check(vfo->pTX->Frequency) != 0 && vfo->TX_LOCK) || @@ -447,6 +464,7 @@ static uint8_t app_trivfo_ptt(bool pressed) app_trivfo_current = app_trivfo_selected; app_trivfo_receiving = false; app_trivfo_transmitting = true; + app_trivfo_onepush_stop_armed = false; app_trivfo_tx_ticks = 0; return 0; } diff --git a/App/apps/trivfo/trivfo_app.c b/App/apps/trivfo/trivfo_app.c index 72a09347..c5c36142 100644 --- a/App/apps/trivfo/trivfo_app.c +++ b/App/apps/trivfo/trivfo_app.c @@ -14,6 +14,7 @@ #define CFG_MAGIC 0xC3u #define VFO_COUNT 3u #define MR_MAX 1024u +#define STATUS_PTT_X 54u static const app_api_t *A; static app_trivfo_info_t vi[VFO_COUNT]; @@ -30,6 +31,16 @@ static const uint8_t fontF[8] = { 0x7f, 0x00, 0x76, 0x76, 0x76, 0x76, 0x7e, 0x7f }; +/* Same two 2x6 glyphs and same x=54 slot as UI_DisplayStatus(). */ +static const uint8_t fontPttOnePush[12] = { + 0x00, 0x3e, 0x41, 0x41, 0x41, 0x3e, + 0x00, 0x7f, 0x09, 0x09, 0x09, 0x06 +}; +static const uint8_t fontPttClassic[12] = { + 0x00, 0x3e, 0x41, 0x41, 0x41, 0x22, + 0x00, 0x7f, 0x40, 0x40, 0x40, 0x40 +}; + static uint8_t slen(const char *s){ uint8_t n=0; while(s[n])n++; return n; } static bool copyName(char *d,const char *s){ uint8_t n=0; @@ -93,6 +104,11 @@ static void drawMeter(const app_trivfo_info_t *v){ } } +static void drawPttStatus(void){ + const uint8_t *glyph=(vi[0].flags&APP_TRIVFO_PTT_ONEPUSH)?fontPttOnePush:fontPttClassic; + for(uint8_t i=0;i<12u;i++) A->status_line[STATUS_PTT_X+i]=glyph[i]; +} + static void drawVfo(uint8_t n){ const app_trivfo_info_t *v=&vi[n]; uint8_t mainLine=(uint8_t)(n*2u+1u), techLine=(uint8_t)(mainLine+1u); @@ -114,22 +130,39 @@ static void drawVfo(uint8_t n){ } const char *mod=v->modulation==0u?"FM":v->modulation==1u?"AM":v->modulation==2u?"USB":v->modulation==3u?"BYP":v->modulation==4u?"RAW":"?"; - A->print_tiny(mod,3,techY,false,true); static const char *const power[7]={"LOW1","LOW2","LOW3","LOW4","LOW5","MID","HIGH"}; uint8_t p=(v->power>=1u&&v->power<=7u)?(uint8_t)(v->power-1u):0u; - A->print_tiny(power[p],24,techY,false,true); - if(v->flags&APP_TRIVFO_USER_POWER){ - A->fb[techLine][19]=0x3e; A->fb[techLine][20]=0x1c; A->fb[techLine][21]=0x08; + if(v->flags&APP_TRIVFO_GUI_CLASSIC){ + A->print_normal(mod,2,0,techLine); + if(v->modulation==0u&&v->code_type==1u) A->print_normal("CT",22,0,techLine); + else if(v->modulation==0u&&(v->code_type==2u||v->code_type==3u)) A->print_normal("DC",22,0,techLine); + static const char *const powerShort[7]={"L1","L2","L3","L4","L5","M","H"}; + A->print_normal(powerShort[p],42,0,techLine); + if(v->flags&APP_TRIVFO_USER_POWER){ + A->fb[techLine][38]=0x3e; A->fb[techLine][39]=0x1c; A->fb[techLine][40]=0x08; + } + if(v->offset_direction==1u) A->print_normal("+",60,0,techLine); + else if(v->offset_direction==2u) A->print_normal("-",60,0,techLine); + if(v->reverse) A->print_normal("R",68,0,techLine); + A->print_normal(v->bandwidth==0u?"W":v->bandwidth==1u?"N":"N+",80,0,techLine); + text[0]='S'; text[1]='Q'; text[2]='L'; text[3]=(char)('0'+(v->squelch%10u)); text[4]='\0'; + A->print_normal(text,98,0,techLine); + } else { + A->print_tiny(mod,3,techY,false,true); + A->print_tiny(power[p],24,techY,false,true); + if(v->flags&APP_TRIVFO_USER_POWER){ + A->fb[techLine][19]=0x3e; A->fb[techLine][20]=0x1c; A->fb[techLine][21]=0x08; + } + if(v->offset_direction==1u) A->print_normal("+",41,0,techLine); + else if(v->offset_direction==2u) A->print_normal("-",41,0,techLine); + if(v->reverse) A->print_tiny("R",51,techY,false,true); + if(v->code_type==1u){ A->print_tiny("CT",58,techY,false,true); formatCode(text,v); A->print_tiny(text,68,techY,false,true); } + else if(v->code_type==2u||v->code_type==3u){ A->print_tiny("DC",58,techY,false,true); formatCode(text,v); A->print_tiny(text,68,techY,false,true); } + else { formatStep(text,v->step); A->print_tiny(text,58,techY,false,true); } + A->print_tiny(v->bandwidth==0u?"WIDE":v->bandwidth==1u?"NAR":"NAR+",91,techY,false,true); + text[0]='S'; text[1]='Q'; text[2]='L'; text[3]=(char)('0'+(v->squelch%10u)); text[4]='\0'; + A->print_tiny(text,110,techY,false,true); } - if(v->offset_direction==1u) A->print_normal("+",41,0,techLine); - else if(v->offset_direction==2u) A->print_normal("-",41,0,techLine); - if(v->reverse) A->print_tiny("R",51,techY,false,true); - if(v->code_type==1u){ A->print_tiny("CT",58,techY,false,true); formatCode(text,v); A->print_tiny(text,68,techY,false,true); } - else if(v->code_type==2u||v->code_type==3u){ A->print_tiny("DC",58,techY,false,true); formatCode(text,v); A->print_tiny(text,68,techY,false,true); } - else { formatStep(text,v->step); A->print_tiny(text,58,techY,false,true); } - A->print_tiny(v->bandwidth==0u?"WIDE":v->bandwidth==1u?"NAR":"NAR+",91,techY,false,true); - text[0]='S'; text[1]='Q'; text[2]='L'; text[3]=(char)('0'+(v->squelch%10u)); text[4]='\0'; - A->print_tiny(text,110,techY,false,true); } static void draw(void){ @@ -144,6 +177,7 @@ static void draw(void){ /* Keep the application title in the resident upper-left position. */ A->draw_battery(); A->print_inverse("TRIPLE VFO",2,0,true,true,42); + drawPttStatus(); if(fArm){ for(uint8_t i=0;i<8u;i++) A->status_line[69u+i]=fontF[i]; } for(uint8_t i=0;i