Have fun!
using System; using System.Threading; using System.Collections; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using SecretLabs.NETMF.Hardware; using SecretLabs.NETMF.Hardware.Netduino; namespace iambic_keyer { public class Program { static OutputPort pin_led = new OutputPort(Pins.ONBOARD_LED, false); static PWM pin_buzzer = new PWM(Pins.GPIO_PIN_D10); static InputPort pin_left = new InputPort(Pins.GPIO_PIN_D11, false, Port.ResistorMode.PullUp); static InputPort pin_right = new InputPort(Pins.GPIO_PIN_D12, false, Port.ResistorMode.PullUp); static AnalogInput pin_speed = new AnalogInput(Pins.GPIO_PIN_A0); static bool both_paddles_old; static bool both_paddles_released; enum TIMER_STATE { IDLE1, IDLE2, IDLE3, ON1, ON2, OFF }; static TIMER_STATE timer_state; static long dit_time; static long duration; enum KEYER_MODE { IAMBIC_A, IAMBIC_B }; static KEYER_MODE keyer_mode; static long element_stop_time; static long char_stop_time; static long word_stop_time; static uint buzzer_period; static int mchar; static int mchar_elements; static Hashtable mcode_tab = new Hashtable(); public static void Main() { setup(); while (true) { loop(); } } static void setup() { mcode_tab[0x0201] = "A"; // 01 mcode_tab[0x0408] = "B"; // 1000 mcode_tab[0x040A] = "C"; // 1010 mcode_tab[0x0304] = "D"; // 100 mcode_tab[0x0100] = "E"; // 0 mcode_tab[0x0402] = "F"; // 0010 mcode_tab[0x0306] = "G"; // 110 mcode_tab[0x0400] = "H"; // 0000 mcode_tab[0x0200] = "I"; // 00 mcode_tab[0x0407] = "J"; // 0111 mcode_tab[0x0305] = "K"; // 101 mcode_tab[0x0404] = "L"; // 0100 mcode_tab[0x0203] = "M"; // 11 mcode_tab[0x0202] = "N"; // 10 mcode_tab[0x0307] = "O"; // 111 mcode_tab[0x0406] = "P"; // 0110 mcode_tab[0x040D] = "Q"; // 1101 mcode_tab[0x0302] = "R"; // 010 mcode_tab[0x0300] = "S"; // 000 mcode_tab[0x0101] = "T"; // 1 mcode_tab[0x0301] = "U"; // 001 mcode_tab[0x0401] = "V"; // 0001 mcode_tab[0x0303] = "W"; // 011 mcode_tab[0x0409] = "X"; // 1001 mcode_tab[0x040B] = "Y"; // 1011 mcode_tab[0x040C] = "Z"; // 1100 mcode_tab[0x050F] = "1"; // 01111 mcode_tab[0x0507] = "2"; // 00111 mcode_tab[0x0503] = "3"; // 00011 mcode_tab[0x0501] = "4"; // 00001 mcode_tab[0x0500] = "5"; // 00000 mcode_tab[0x0510] = "6"; // 10000 mcode_tab[0x0518] = "7"; // 11000 mcode_tab[0x051C] = "8"; // 11100 mcode_tab[0x051E] = "9"; // 11110 mcode_tab[0x051F] = "0"; // 11111 mcode_tab[0x0511] = "="; // 10001 mcode_tab[0x0615] = "."; // 010101 mcode_tab[0x0605] = "SK"; // 000101 mcode_tab[0x0516] = "KN"; // 10110 mcode_tab[0x0512] = "/"; // 10010 mcode_tab[0x060C] = "?"; // 001100 both_paddles_old = false; both_paddles_released = false; timer_state = TIMER_STATE.IDLE3; duration = 1; // 1 = dit, 3 = dah mchar = 0; mchar_elements = 0; pin_speed.SetRange(5, 50); // wpm: 5 .. 50 buzzer_period = 1000000 / 800; // buzzer frequency: 800 Hz // keyer_mode = KEYER_MODE.IAMBIC_A; keyer_mode = KEYER_MODE.IAMBIC_B; } static void loop() { int wpm = pin_speed.Read(); bool right_paddle = !pin_right.Read(); bool left_paddle = !pin_left.Read(); long milliseconds = Utility.GetMachineTime().Ticks / System.TimeSpan.TicksPerMillisecond; dit_time = 1022 / wpm; // dit duration in milliseconds bool both_paddles = left_paddle && right_paddle; both_paddles_released = both_paddles_released || (both_paddles_old && !both_paddles); both_paddles_old = both_paddles; switch (timer_state) { case TIMER_STATE.IDLE1: if (milliseconds >= char_stop_time) { int mcode; mcode = mchar_elements << 8 | mchar; object x = mcode_tab[mcode]; if (x != null) { Debug.Print(x.ToString()); } mchar_elements = 0; mchar = 0; timer_state = TIMER_STATE.IDLE2; } goto ts_idle3; case TIMER_STATE.IDLE2: if (milliseconds >= word_stop_time) { Debug.Print(" "); timer_state = TIMER_STATE.IDLE3; } goto ts_idle3; case TIMER_STATE.IDLE3: ts_idle3: if (keyer_mode == KEYER_MODE.IAMBIC_B && both_paddles_released) { both_paddles_released = false; duration = duration == 1 ? 3 : 1; timer_state = TIMER_STATE.ON1; } else if (left_paddle && !right_paddle) { duration = 1; // dit timer_state = TIMER_STATE.ON1; } else if (!left_paddle && right_paddle) { duration = 3; // dah timer_state = TIMER_STATE.ON1; } else if (left_paddle && right_paddle) { duration = duration == 1 ? 3 : 1; timer_state = TIMER_STATE.ON1; } break; case TIMER_STATE.ON1: element_stop_time = milliseconds + dit_time * duration; // dit or dah pin_buzzer.SetPulse(buzzer_period, buzzer_period / 2); // Buzzer on pin_led.Write(true); // LED on timer_state = TIMER_STATE.ON2; break; case TIMER_STATE.ON2: if (milliseconds >= element_stop_time) { element_stop_time = milliseconds + dit_time; // space after dit or dah pin_buzzer.SetPulse(0, 0); // Buzzer off pin_led.Write(false); // LED off timer_state = TIMER_STATE.OFF; } break; case TIMER_STATE.OFF: if (milliseconds >= element_stop_time) { if (mchar_elements < 8) { switch (duration) { case 1: mchar = mchar << 1; // dit = 0 mchar_elements++; break; case 3: mchar = (mchar << 1) + 1; // dah = 1 mchar_elements++; break; } } char_stop_time = milliseconds + dit_time * 3; // gap between letters word_stop_time = milliseconds + dit_time * 7; // gap between words timer_state = TIMER_STATE.IDLE1; } break; } } } }