vail-adapter

Firmware for USB morse code key adapter
git clone https://git.woozle.org/neale/vail-adapter.git

commit
7dda0a9
parent
9cd61a5
author
WrathPak
date
2025-08-18 15:44:56 -0600 MDT
Update adapter.cpp, revert for radio mode issue
1 files changed,  +85, -82
M adapter.cpp
+85, -82
  1@@ -1,4 +1,3 @@
  2-// adapter.cpp - FINAL VERSION
  3 #include <Arduino.h>
  4 #include <Keyboard.h>
  5 #include <MIDIUSB.h>
  6@@ -7,7 +6,9 @@
  7 #include "adapter.h"
  8 #include "polybuzzer.h"
  9 
 10+// For SAMD21 software reset if needed by other parts of code
 11 #if defined(ARDUINO_ARCH_SAMD)
 12+// NVIC_SystemReset() is typically available through Arduino.h / CMSIS includes
 13 #endif
 14 
 15 extern void saveSettingsToEEPROM(uint8_t keyerType, uint16_t ditDuration, uint8_t txNote);
 16@@ -24,7 +25,6 @@ this->lastCapDahTime = 0;
 17 this->capDahPressCount = 0;
 18 this->radioDitState = false;
 19 this->radioDahState = false;
 20-this->activePaddle = 0;
 21 this->keyboardMode = true;
 22 this->keyer = NULL;
 23 this->txNote = DEFAULT_TONE_NOTE;
 24@@ -63,20 +63,22 @@ void VailAdapter::ResetDahCounter() {
 25 this->capDahPressCount = 0;
 26 }
 27 
 28+// Corrected MIDI key event function
 29 void VailAdapter::midiKey(uint8_t key, bool down) {
 30 uint8_t header;
 31 uint8_t status_byte;
 32 uint8_t velocity;
 33 
 34-if (down) {
 35-    header = 0x09;
 36-    status_byte = 0x90;
 37-    velocity = 0x7F;
 38-} else {
 39-    header = 0x08;
 40-    status_byte = 0x80;
 41-    velocity = 0x00;
 42+if (down) { // Note On
 43+    header = 0x09;      // CIN = 9 (Note On) for USB MIDI event packet
 44+    status_byte = 0x90; // MIDI Status = 0x90 (Note On, Channel 1)
 45+    velocity = 0x7F;    // Standard velocity for Note On
 46+} else { // Note Off
 47+    header = 0x08;      // CIN = 8 (Note Off) for USB MIDI event packet
 48+    status_byte = 0x80; // MIDI Status = 0x80 (Note Off, Channel 1)
 49+    velocity = 0x00;    // Velocity for Note Off (0x00 is common)
 50 }
 51+// Construct the MIDI event packet for MIDIUSB library
 52 midiEventPacket_t event = {header, status_byte, key, velocity};
 53 MidiUSB.sendMIDI(event);
 54 MidiUSB.flush();
 55@@ -105,58 +107,44 @@ void VailAdapter::setRadioDah(bool active) {(void)active;}
 56 
 57 void VailAdapter::BeginTx() {
 58 if (!keyIsPressed) {
 59-    keyIsPressed = true;
 60-    if (!this->radioModeActive) {
 61-        if (this->keyPressStartTime == 0) {
 62-            this->keyPressStartTime = millis();
 63-        }
 64-    }
 65+keyIsPressed = true;
 66+if (!this->radioModeActive) {
 67+if (this->keyPressStartTime == 0) {
 68+this->keyPressStartTime = millis();
 69+}
 70+}
 71 }
 72 
 73-if (this->buzzerEnabled && !this->radioModeActive) {
 74+if (this->buzzerEnabled && !this->radioModeActive) { 
 75     this->buzzer->Note(0, this->txNote);
 76 }
 77 
 78-if (!this->radioModeActive) {
 79+if (!this->radioModeActive) { 
 80     if (this->keyboardMode) {
 81-        if (this->activePaddle == 2) { // DAH
 82-            this->keyboardKey(KEY_RIGHT_CTRL, true);
 83-            this->keyboardKey(']', true);
 84-        } else { // DIT, STRAIGHT, or IAMBIC default
 85-            this->keyboardKey(KEY_LEFT_CTRL, true);
 86-            this->keyboardKey('[', true);
 87-        }
 88+        this->keyboardKey(KEY_LEFT_CTRL, true);
 89     } else {
 90-        this->midiKey(0, true);
 91+        this->midiKey(0, true); 
 92     }
 93 }
 94 }
 95 
 96 void VailAdapter::EndTx() {
 97 if (keyIsPressed) {
 98-    keyIsPressed = false;
 99-    if (!this->radioModeActive) {
100-        this->keyPressStartTime = 0;
101-    }
102+keyIsPressed = false;
103+if (!this->radioModeActive) {
104+this->keyPressStartTime = 0;
105+}
106 }
107 
108-this->buzzer->NoTone(0);
109+this->buzzer->NoTone(0); 
110 
111-if (!this->radioModeActive) {
112+if (!this->radioModeActive) { 
113     if (this->keyboardMode) {
114-        if (this->activePaddle == 2) { // DAH
115-            this->keyboardKey(KEY_RIGHT_CTRL, false);
116-            this->keyboardKey(']', false);
117-        } else { // DIT, STRAIGHT, or IAMBIC default
118-            this->keyboardKey(KEY_LEFT_CTRL, false);
119-            this->keyboardKey('[', false);
120-        }
121+        this->keyboardKey(KEY_LEFT_CTRL, false);
122     } else {
123         this->midiKey(0, false);
124     }
125 }
126-// Reset state AFTER using it, so iambic keyer can read the last state
127-// this->activePaddle = 0; // We will now set this on the next paddle press instead.
128 }
129 
130 void VailAdapter::DisableBuzzer() {
131@@ -173,18 +161,18 @@ void VailAdapter::ToggleRadioMode() {
132 #ifdef HAS_RADIO_OUTPUT
133 this->radioModeActive = !this->radioModeActive;
134 
135-if (keyer) keyer->Release();
136-if (keyIsPressed) EndTx();
137+if (keyer) keyer->Release(); 
138+if (keyIsPressed) EndTx(); 
139 
140-setRadioDit(false);
141+setRadioDit(false); 
142 setRadioDah(false);
143 radioDitState = false;
144 radioDahState = false;
145-keyIsPressed = false;
146+keyIsPressed = false; 
147 
148 if (this->radioModeActive) {
149     Serial.println("Radio Mode Activated (Sidetone Disabled)");
150-    this->buzzer->NoTone(0);
151+    this->buzzer->NoTone(0); 
152     this->buzzer->Note(1, 60); delay(100);
153     this->buzzer->Note(1, 65); delay(100);
154     this->buzzer->Note(1, 70); delay(100);
155@@ -195,9 +183,9 @@ if (this->radioModeActive) {
156     this->buzzer->Note(1, 65); delay(100);
157     this->buzzer->Note(1, 60); delay(100);
158     this->buzzer->NoTone(1);
159-    delay(100);
160-
161-    NVIC_SystemReset();
162+    delay(100); 
163+    
164+    NVIC_SystemReset(); 
165 }
166 #else
167 Serial.println("Radio output not configured. Radio mode unavailable.");
168@@ -213,7 +201,7 @@ if (paddle == PADDLE_DIT && pressed && this->buzzerEnabled) {
169         this->ditPressCount++;
170         if (this->ditPressCount >= DIT_SPAM_COUNT_BUZZER_DISABLE) {
171             this->DisableBuzzer();
172-            this->ditPressCount = 0;
173+            this->ditPressCount = 0; 
174         }
175     } else {
176         this->ditPressCount = 1;
177@@ -241,41 +229,54 @@ this->capDahPressCount = 0;
178 
179 if (this->radioModeActive) {
180 #ifdef HAS_RADIO_OUTPUT
181-    // ... Radio logic unchanged ...
182-#endif
183-} else { // Computer mode
184-    if (paddle == PADDLE_STRAIGHT) {
185-        this->activePaddle = 0;
186-        if (pressed) BeginTx(); else EndTx();
187-    } else { // Paddle mode
188-        if (this->keyer) {
189-            this->keyer->Key(paddle, pressed);
190-        } else { // Passthrough paddle mode
191-            bool currentPaddleActivity = false;
192-            if (paddle == PADDLE_DIT) {
193-                this->activePaddle = 1;
194-                if (this->keyboardMode) this->keyboardKey(DIT_KEYBOARD_KEY, pressed);
195-                else this->midiKey(1, pressed);
196-                if (pressed) currentPaddleActivity = true;
197-            } else if (paddle == PADDLE_DAH) {
198-                this->activePaddle = 2;
199-                if (this->keyboardMode) this->keyboardKey(DAH_KEYBOARD_KEY, pressed);
200-                else this->midiKey(2, pressed);
201-                if (pressed) currentPaddleActivity = true;
202-            }
203+bool radioKeyIsActiveBefore = radioDitState || radioDahState;
204+
205+    if (paddle == PADDLE_DIT) {
206+        radioDitState = pressed;
207+        setRadioDit(radioDitState);
208+    } else if (paddle == PADDLE_DAH) {
209+        radioDahState = pressed;
210+        setRadioDah(radioDahState);
211+    } else if (paddle == PADDLE_STRAIGHT) { 
212+        radioDitState = pressed; 
213+        setRadioDit(pressed);
214+    }
215 
216-            if (currentPaddleActivity) {
217-                if (!keyIsPressed) BeginTx();
218-            } else {
219-                if (keyIsPressed) EndTx();
220+    keyIsPressed = radioDitState || radioDahState; 
221+
222+    if (!keyIsPressed && radioKeyIsActiveBefore) { 
223+         this->buzzer->NoTone(0);
224+    }
225+#endif
226+} else {
227+if (paddle == PADDLE_STRAIGHT) {
228+if (pressed) BeginTx(); else EndTx();
229+} else {
230+if (this->keyer) {
231+this->keyer->Key(paddle, pressed);
232+} else {
233+bool currentPaddleActivity = false;
234+if (paddle == PADDLE_DIT) {
235+if (this->keyboardMode) this->keyboardKey(DIT_KEYBOARD_KEY, pressed);
236+else this->midiKey(1, pressed);
237+if (pressed) currentPaddleActivity = true;
238+} else if (paddle == PADDLE_DAH) {
239+if (this->keyboardMode) this->keyboardKey(DAH_KEYBOARD_KEY, pressed);
240+else this->midiKey(2, pressed);
241+if (pressed) currentPaddleActivity = true;
242+}
243+
244+            if (currentPaddleActivity) { 
245+                if(!keyIsPressed) BeginTx(); 
246+            } else { 
247+                if(keyIsPressed) EndTx();
248             }
249         }
250     }
251-}
252+  }
253 }
254 
255 void VailAdapter::HandleMIDI(midiEventPacket_t event) {
256-// ... This function is unchanged ...
257 uint16_t msg = (event.byte1 << 8) | (event.byte2 << 0);
258 switch (event.byte1) {
259 case 0xB0:
260@@ -296,6 +297,7 @@ break;
261 case 2:
262 this->txNote = event.byte3;
263 Serial.print("TX Note set to: "); Serial.println(this->txNote);
264+
265 saveSettingsToEEPROM(getCurrentKeyerType(), this->ditDuration, this->txNote);
266 break;
267 }
268@@ -325,12 +327,13 @@ break;
269 
270 void VailAdapter::Tick(unsigned int currentMillis) {
271 if (!radioModeActive && keyIsPressed && this->buzzerEnabled && this->keyPressStartTime > 0) {
272-    if (currentMillis - this->keyPressStartTime >= KEY_HOLD_DISABLE_THRESHOLD) {
273-        this->DisableBuzzer();
274-    }
275+if (currentMillis - this->keyPressStartTime >= KEY_HOLD_DISABLE_THRESHOLD) {
276+this->DisableBuzzer();
277+}
278 }
279 
280-if (this->keyer && !this->radioModeActive) {
281+if (this->keyer && !this->radioModeActive) { 
282     this->keyer->Tick(currentMillis);
283 }
284 }
285+