//====================================================================== // ubitx_iop.ino //====================================================================== #include #include #include "audio.h" #include "config.h" #include "ubitx_iop.h" #include "keyer.h" #include "menu.h" #include "rig.h" #include "TxSwitch.h" Keyer keyer{15, 3.0}; // NOTE: make configurable RigConfig rigConfig; RigAudio rigAudio{rigConfig.audio}; basic_rig rig{rigConfig, rigAudio}; CATSwitch catPTT; //MicSwitch micPTTHelper; GPIOSwitch micPTT(true, MIC_PTT_PIN); //LineSwitch linePTTHelper; GPIOSwitch linePTT(false, LINE_PTT_PIN); Encoder knob(ENCODER_A_PIN, ENCODER_B_PIN); long knobPos = 0; Bounce btn; elapsedMillis btnMillis; Main_menu main_menu(rig); Menu_item* menu_item = &main_menu; elapsedMillis frameMillis; unsigned frameTime; unsigned frameCounter; unsigned audioProcUsage; unsigned audioMemUsage; //====================================================================== void setup() { // put your setup code here, to run once: initCAT(38400, SERIAL_8N1); USBDEBUG("setup started"); AudioMemory(16); // NOTE: Need to fine tune this. Have had errors due to this being too low. initKeyLine(); rigAudio.init(); frameCounter = 0; frameMillis = 0; knob.write(0); btn.attach(ENCODER_SW_PIN, INPUT_PULLUP); btn.interval(25); rig.init(); USBDEBUG("setup completed"); } //====================================================================== void update_io_menu(Menu_item* item, bool is_active) { Menu_string text; if (!is_active || (is_active && item == nullptr)) { sendIOPMenuInactive(); } else { item->get_text(text); sendIOPMenuDisplay(text.data()); } } //====================================================================== void loop() { static bool menu_is_active = false; static bool menu_updated = false; static char frame_status[100]; static char old_mode_text[17] = " "; static bool paddle_loop = false; // long oldPos = knobPos; rig_mode oldRigMode; frameCounter++; if (rig.is_cw_mode()) { if (keyer.do_paddles()) { // Checking for T/R separately from the paddle loop, because it's // possible we're already transmitting (PTT/Key being held), and // we don't want to run the tx() actions if we're already in TX. if (rig.is_rx()) { USBDEBUG("entered TX via paddles"); rig.tx(); } paddle_loop = true; if (keyer.is_down()) { setKeyDown(); } else { setKeyUp(); } return; // return early for paddle responsiveness } else { if (paddle_loop) { // If we exit the paddle loop (i.e. keyer completes its keying // sequence), then we'll go back to receive, even if one of the // PTT/Key lines is still held separately. General principle is // that if "something" stops transmitting, then the rig will // stop transmitting. paddle_loop = false; rig.rx(); USBDEBUG("exited TX from paddles"); } } } rig.update(); oldRigMode = rig.get_rig_mode(); // Update the mic PTT. We need to tell it if we're in SSB mode, so that // it knows if it should switch to the mic input if pressed. We also // need to make it inactive if we're in DGT mode, since only CAT will be // used to start transmitting in that case. micPTT.setSSBMode(rig.is_ssb_mode()); micPTT.update(rig.mode(), !rig.is_digi_mode()); // Update the line PTT. We need to tell it if we're in SSB mode, so that // it knows if it should switch to the line input if pressed. We also // need to make it inactive if we're in DGT mode, since only CAT will be // used to start transmitting in that case. linePTT.setSSBMode(rig.is_ssb_mode()); linePTT.update(rig.mode(), !rig.is_digi_mode()); serviceCAT(); menu_updated = false; btn.update(); knobPos = knob.read(); if (btn.fell()) { btnMillis = 0; USBDEBUG("button pressed"); // cancel out any knob rotation that occurred during in conjunction with press/release knob.write(0); } else if (btn.rose()) { menu_updated = true; if (btnMillis > 1000) { // long press - exit menu_item = menu_item->exit(); USBDEBUG("button released - long (exit)"); } else if (btnMillis > 500) { // medium press - altSelect if (menu_is_active) { menu_item = menu_item->altSelect(); } else { menu_item = audio_config_menu; menu_is_active = true; } USBDEBUG("button released - medium (altSelect)"); } else { // short press - select if (menu_is_active) { menu_item = menu_item->select(); } else { menu_item = &main_menu; menu_is_active = true; } USBDEBUG("button released - short (select)"); } // cancel out any knob rotation that occurred during in conjunction with press/release knob.write(0); } else if (knobPos > 3 && menu_is_active) { // left menu_item = menu_item->prev(); knob.write(0); menu_updated = true; USBDEBUG("knob turned left"); } else if (knobPos < -3 && menu_is_active) { // right menu_item = menu_item->next(); knob.write(0); menu_updated = true; USBDEBUG("knob turned right"); } if (menu_item == nullptr) { menu_item = &main_menu; menu_is_active = false; menu_updated = true; USBDEBUG("null menu - reset to main menu"); } if (menu_updated) { update_io_menu(menu_item, menu_is_active); USBDEBUG("updated main menu"); } rig.update(); if (frameMillis > 5000) { #if defined(DEBUG) frameTime = frameMillis; audioProcUsage = AudioProcessorUsageMax(); audioMemUsage = AudioMemoryUsageMax(); sprintf(frame_status, "update: %u ms, %u frames, %d %% CPU max, %d %% mem max\n", frameTime, frameCounter, audioProcUsage, audioMemUsage); USBDEBUG(frame_status); #endif frameMillis = 0; frameCounter = 0; } //audioUpdate(); // was used to update the speech compressor } //====================================================================== // EOF //======================================================================