main.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. /*
  2. * Morse code beeper
  3. *
  4. * Copyright (C) 2010 Michael Buesch <m@bues.ch>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program; if not, write to the Free Software Foundation, Inc.,
  18. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. */
  20. #include "util.h"
  21. #include <util/delay.h>
  22. #include <avr/sleep.h>
  23. #include <avr/interrupt.h>
  24. #include <avr/eeprom.h>
  25. #include "../encoder/morse_encoder.h"
  26. /* Beeper connection */
  27. #define MORSE_BEEPER_PORT PORTB
  28. #define MORSE_BEEPER_DDR DDRB
  29. #define MORSE_BEEPER_BIT 0
  30. /* The morse symbols, in EEPROM. */
  31. static const morse_sym_t EEMEM morse_symbols[32];
  32. /* Beeper context */
  33. enum {
  34. BEEPER_STOPPED,
  35. BEEPER_NEXTSYM,
  36. BEEPER_INSYM,
  37. };
  38. static uint8_t beeper_state;
  39. static uint16_t timer;
  40. static uint16_t counter;
  41. static uint8_t morse_sym_ptr; /* Symbol pointer */
  42. static uint8_t morse_sym_size; /* Size of the current symbol */
  43. static uint16_t morse_sym_marks; /* The marks of the current symbol */
  44. #define TIMER_INBEEP 1
  45. #define TIMER_DIT (TIMER_INBEEP * 240)
  46. #define TIMER_DAH (TIMER_DIT * 3)
  47. #define TIMER_INTERMARK (TIMER_DIT * 1)
  48. #define TIMER_INTERCHAR (TIMER_DIT * 3)
  49. #define TIMER_INTERWORD (TIMER_DIT * 7)
  50. /* 2 kHz trigger frequency */
  51. ISR(TIM0_COMPA_vect)
  52. {
  53. if (timer)
  54. timer--;
  55. }
  56. static inline void timer_set(uint16_t value)
  57. {
  58. timer = value;
  59. }
  60. static inline uint8_t timer_running(void)
  61. {
  62. return (timer != 0);
  63. }
  64. static void timer_init(void)
  65. {
  66. TCCR0B = 0; /* Disable */
  67. TIFR0 |= (1 << OCF0A);
  68. TIMSK0 |= (1 << OCIE0A); /* Enable compA IRQ */
  69. TCNT0 = 0;
  70. OCR0A = 38;
  71. TCCR0A = (1 << WGM01); /* CTC */
  72. TCCR0B = (0 << CS02) | (1 << CS01) | (1 << CS00); /* prescaler 64 */
  73. }
  74. static void beeper_startup(void)
  75. {
  76. beeper_state = BEEPER_NEXTSYM;
  77. morse_sym_ptr = 0;
  78. }
  79. static void beeper_stop(void)
  80. {
  81. beeper_state = BEEPER_STOPPED;
  82. MORSE_BEEPER_PORT &= ~(1 << MORSE_BEEPER_BIT);
  83. }
  84. static inline uint8_t int0_triggered(void)
  85. {
  86. return !(PINB & (1 << 1));
  87. }
  88. ISR(INT0_vect)
  89. {
  90. if (beeper_state == BEEPER_STOPPED)
  91. beeper_startup();
  92. else
  93. beeper_stop();
  94. while (1) {
  95. while (int0_triggered())
  96. ; /* Wait for release */
  97. _delay_ms(50);
  98. if (!int0_triggered())
  99. break;
  100. }
  101. }
  102. /* Runs with IRQs disabled. */
  103. static void run_beeper(void)
  104. {
  105. morse_sym_t sym;
  106. if (timer_running())
  107. return; /* delay */
  108. switch (beeper_state) {
  109. case BEEPER_NEXTSYM:
  110. if (morse_sym_ptr >= ARRAY_SIZE(morse_symbols)) {
  111. beeper_stop();
  112. return;
  113. }
  114. sym = eeprom_read_word(&morse_symbols[morse_sym_ptr]);
  115. if (sym == 0xFFFF) {
  116. beeper_stop();
  117. return;
  118. }
  119. morse_sym_ptr++;
  120. if (MORSE_SYM_IS_SPACE(sym)) {
  121. timer_set(TIMER_INTERWORD);
  122. return;
  123. }
  124. morse_sym_marks = MORSE_SYM_MARKS(sym);
  125. morse_sym_size = MORSE_SYM_SIZE(sym);
  126. beeper_state = BEEPER_INSYM;
  127. timer_set(TIMER_INBEEP);
  128. counter = 0;
  129. /* fallthrough */
  130. case BEEPER_INSYM:
  131. if (counter == 0) {
  132. if (!morse_sym_size) {
  133. beeper_state = BEEPER_NEXTSYM;
  134. timer_set(TIMER_INTERCHAR);
  135. return;
  136. }
  137. if ((morse_sym_marks & 1) == MORSE_DIT)
  138. counter = TIMER_DIT;
  139. else /* dah */
  140. counter = TIMER_DAH;
  141. morse_sym_size--;
  142. morse_sym_marks >>= 1;
  143. } else {
  144. counter--;
  145. if (counter == 0) {
  146. timer_set(TIMER_INTERMARK);
  147. MORSE_BEEPER_PORT &= ~(1 << MORSE_BEEPER_BIT);
  148. return;
  149. }
  150. }
  151. MORSE_BEEPER_PORT ^= (1 << MORSE_BEEPER_BIT);
  152. timer_set(TIMER_INBEEP);
  153. break;
  154. }
  155. }
  156. int main(void)
  157. {
  158. irq_disable();
  159. PORTB = 0xFF;
  160. DDRB = 0x00;
  161. MORSE_BEEPER_DDR |= (1 << MORSE_BEEPER_BIT);
  162. MORSE_BEEPER_PORT &= ~(1 << MORSE_BEEPER_BIT);
  163. /* Set up INT0 */
  164. MCUCR |= (0 << ISC01) | (0 << ISC00); /* low level triggered */
  165. PORTB |= (1 << 1); /* enable pullup */
  166. DDRB &= ~(1 << 1);
  167. GIMSK |= (1 << INT0);
  168. timer_init();
  169. set_sleep_mode(SLEEP_MODE_IDLE);
  170. sleep_enable();
  171. while (1) {
  172. mb();
  173. if (beeper_state == BEEPER_STOPPED)
  174. set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  175. else
  176. set_sleep_mode(SLEEP_MODE_IDLE);
  177. irq_enable();
  178. sleep_cpu();
  179. irq_disable();
  180. if (beeper_state != BEEPER_STOPPED)
  181. run_beeper();
  182. }
  183. }