00001
00086 #include <avr/io.h>
00087 #include <avr/interrupt.h>
00088 #include <avr/wdt.h>
00089 #include <avr/fuse.h>
00090 #include <string.h>
00091
00092
00093
00094
00095
00096 #define STATIC_ASSERT(expr) extern char static_assert[ (!!(expr))*2 - 1]
00097 #define elements_of(array) (sizeof(array) / sizeof(array[0]))
00098
00099
00100 FUSES =
00101 {
00102 .low = LFUSE_DEFAULT,
00103 .high = (FUSE_EESAVE & FUSE_SPIEN),
00104 };
00105
00106
00107
00108
00109
00110
00111 static volatile uint8_t red_led = 0;
00112 static volatile uint8_t green_led = 0;
00113 static volatile uint8_t red_led_1 = 0;
00114 static volatile uint8_t green_led_1 = 0;
00115 static volatile uint16_t volume_activated_timer = 0;
00116 static volatile uint8_t timer1ovfl = 0;
00117
00118
00120 enum EGO_X012 {
00121 EGO_X012_INACTIVE = 1 * _BV(PA6) | 1 * _BV(PA5) | 1 * _BV(PA4),
00122 EGO_X012_PLAY_UNHOOK = 0 * _BV(PA6) | 0 * _BV(PA5) | 0 * _BV(PA4),
00123 EGO_X012_STOP_ONHOOK = 1 * _BV(PA6) | 0 * _BV(PA5) | 0 * _BV(PA4),
00124 EGO_X012_VOL_UP = 0 * _BV(PA6) | 0 * _BV(PA5) | 1 * _BV(PA4),
00125 EGO_X012_VOL_DOWN = 1 * _BV(PA6) | 0 * _BV(PA5) | 1 * _BV(PA4),
00126 EGO_X012_NEXT = 0 * _BV(PA6) | 1 * _BV(PA5) | 0 * _BV(PA4),
00127 EGO_X012_PREV = 1 * _BV(PA6) | 1 * _BV(PA5) | 0 * _BV(PA4),
00128 };
00129
00130 #define EGO_RED_LED_IS_ON() (!(PINB & _BV(PB5)))
00131 #define EGO_GREEN_LED_IS_ON() (!(PINA & _BV(PA7)))
00132 #define EGO_MUTE_ON() (!(PINB & _BV(PB3)))
00133 #define EGO_X012(x) PORTA = (PORTA & ~EGO_X012_INACTIVE) | ((x) & EGO_X012_INACTIVE)
00134 #define EGO_INIT() DDRA &= ~(_BV(PA7));DDRA |= EGO_X012_INACTIVE; PORTA |= _BV(PA7); DDRB &= ~(_BV(PB5) | _BV(PB3)); PORTB |= _BV(PB5);
00135
00136
00137
00138
00139 #define BTN1_LED_GREEN_ON() PORTA |= _BV(PA2)
00140 #define BTN1_LED_GREEN_OFF() PORTA &= ~_BV(PA2)
00141 #define BTN1_LED_GREEN_INIT() DDRA |= _BV(PA2);BTN1_LED_GREEN_OFF()
00142
00143 #define BTN2_LED_RED_ON() PORTA |= _BV(PA0)
00144 #define BTN2_LED_RED_OFF() PORTA &= ~_BV(PA0)
00145 #define BTN2_LED_RED_INIT() DDRA |= _BV(PA0);BTN2_LED_RED_OFF()
00146
00147 #define BTN_GREEN_PRESSED() (!(PINA & _BV(PA3)))
00148 #define BTN_RED_PRESSED() (!(PINA & _BV(PA1)))
00149 #define BTN_INIT() DDRA &= ~(_BV(PA3) | _BV(PA1));PORTA |= (_BV(PA3) | _BV(PA1))
00150
00151
00152
00154 enum {
00155 STRW_UP_INPUT = 7,
00156 STRW_DOWN_INPUT = 9
00157 };
00158
00160 #define VOLTAGE_TO_ADC_VALUE(v) (uint16_t)(v * ((1UL<<16)-1) / (2.56 * 2))
00161
00163 #if 0
00164 enum {
00165 VOLTAGE1 = VOLTAGE_TO_ADC_VALUE(5.0 * 1/6),
00166 VOLTAGE2 = VOLTAGE_TO_ADC_VALUE(5.0 * 3/6),
00167 VOLTAGE3 = VOLTAGE_TO_ADC_VALUE(5.0 * 5/6)
00168 };
00169 #endif
00170 enum {
00171 VOLTAGE1 = VOLTAGE_TO_ADC_VALUE(0.5),
00172 VOLTAGE2 = VOLTAGE_TO_ADC_VALUE(1.5),
00173 VOLTAGE3 = VOLTAGE_TO_ADC_VALUE(3.0),
00174 MUTE_ON_THRES = VOLTAGE_TO_ADC_VALUE(0.6)
00175 };
00176
00177 volatile uint16_t voltages[] = {VOLTAGE1,VOLTAGE2,VOLTAGE3};
00178
00180 typedef enum {
00181 STRW_INACTIVE = 0,
00182 STRW_HIGH = 1,
00183 STRW_LOW = 2,
00184 STRW_GND = 3
00185 } btn_t;
00186
00188 typedef enum {
00189 STRW_NONE = (STRW_INACTIVE << 2) + STRW_INACTIVE,
00190 STRW_UP = (STRW_LOW << 2) + STRW_INACTIVE,
00191 STRW_DOWN = (STRW_INACTIVE << 2) + STRW_LOW,
00192 STRW_VOL_UP = (STRW_HIGH << 2) + STRW_INACTIVE,
00193 STRW_VOL_DOWN = (STRW_INACTIVE << 2) + STRW_HIGH,
00194 STRW_MODE = (STRW_GND << 2) + STRW_INACTIVE,
00195 STRW_PWR = (STRW_INACTIVE << 2) + STRW_GND,
00196 STRW_DOWN_MODE = (STRW_GND << 2) + STRW_LOW,
00197 } wheel_control_t;
00198
00199
00201 static void adc_init(void)
00202 {
00203 ADMUX = _BV(REFS2) * 1 | _BV(REFS1) * 1 | _BV(REFS0) * 0 | _BV(ADLAR);
00204 ADCSRA = _BV(ADEN) | _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0);
00205 ADCSRB = _BV(REFS2) * 1;
00206 }
00207
00209 static uint16_t measure_adc(uint8_t ch) {
00210 ADMUX = (ADMUX & ~0x1F) | (ch & 0xF);
00211 ADCSRA |= _BV(ADEN);
00212 ADCSRA |= _BV(ADSC);
00213 while (bit_is_set(ADCSRA, ADSC))
00214 ;
00215 uint16_t value = ADC;
00216 return value;
00217 }
00218
00220 static btn_t convert_from_voltage(uint16_t measurement) {
00221 if (measurement < VOLTAGE1) {
00222 return STRW_GND;
00223 }
00224 else if (measurement < VOLTAGE2) {
00225 return STRW_LOW;
00226 }
00227 else if (measurement < VOLTAGE3) {
00228 return STRW_HIGH;
00229 }
00230 else {
00231 return STRW_INACTIVE;
00232 }
00233 }
00234
00235 #define debug_voltage(v) \
00236 { \
00237 red_led = v & 0x1;\
00238 green_led = v & 0x2;\
00239 }
00240
00242 static wheel_control_t get_wheel_control(void)
00243 {
00244 btn_t b1 = convert_from_voltage(measure_adc(STRW_UP_INPUT));
00245 btn_t b2 = convert_from_voltage(measure_adc(STRW_DOWN_INPUT));
00246
00247 return (b1 << 2 | b2);
00248 }
00249
00250
00251
00252
00253
00254
00255
00256 STATIC_ASSERT(F_CPU > 0);
00257
00258 #define T1_OVERFLOW_TIME_MS ((4UL*256UL*1000UL) / F_CPU)
00259 #define MS_TO_TICKS(t) (t/T1_OVERFLOW_TIME_MS)
00260 #define VOLUME_ACTIVATE_TIMEOUT MS_TO_TICKS(300)
00261
00262 STATIC_ASSERT(VOLUME_ACTIVATE_TIMEOUT > 1);
00263
00264
00265
00266
00267
00268
00270 static void default_strwh_inactive(void)
00271 {
00272 if (BTN_RED_PRESSED()) {
00273 EGO_X012(EGO_X012_STOP_ONHOOK);
00274 }
00275 else if (BTN_GREEN_PRESSED()) {
00276 EGO_X012(EGO_X012_PLAY_UNHOOK);
00277 }
00278 else {
00279 EGO_X012(EGO_X012_INACTIVE);
00280 }
00281 }
00282
00283
00284
00285 ISR(SIG_OVERFLOW1)
00286 {
00287 if (!green_led_1) BTN1_LED_GREEN_ON(); else BTN1_LED_GREEN_OFF();
00288 if (!red_led_1) BTN2_LED_RED_ON(); else BTN2_LED_RED_OFF();
00289 if (volume_activated_timer > 0) volume_activated_timer--;
00290 timer1ovfl++;
00291 }
00292
00293 ISR(SIG_OUTPUT_COMPARE1A)
00294 {
00295 if (!green_led) {
00296 BTN1_LED_GREEN_OFF();
00297 }
00298 }
00299
00300
00301 ISR(SIG_OUTPUT_COMPARE1B)
00302 {
00303 if (!red_led) {
00304 BTN2_LED_RED_OFF();
00305 }
00306 }
00307
00309 int main(void)
00310 {
00311 wheel_control_t prev = STRW_NONE;
00312 uint8_t volume_activated = 0;
00313
00314
00315 adc_init();
00316 BTN2_LED_RED_INIT();
00317 BTN1_LED_GREEN_INIT();
00318 BTN_INIT();
00319 EGO_INIT();
00320 EGO_X012(EGO_X012_INACTIVE);
00321
00322
00323 PLLCSR = 0;
00324 TCCR1A = 0;
00325 TCCR1B = 3;
00326 TCCR1D = 0;
00327 TCCR1E = 0;
00328 TIMSK |= _BV(TOIE1) | _BV(OCIE1A) | _BV(OCIE1B);
00329 OCR1A = 2 * 256/100;
00330 OCR1B = 3 * 256/100;
00331
00332 sei();
00333
00334
00335 for (;;)
00336 {
00337
00338 wdt_reset();
00339 if (timer1ovfl > 20)
00340 {
00341 wheel_control_t ctrl = 0;
00342 timer1ovfl = 0;
00343 ctrl = get_wheel_control();
00344
00345
00346 red_led = EGO_RED_LED_IS_ON();
00347 green_led = EGO_GREEN_LED_IS_ON();
00348
00349 if (volume_activated_timer == 0) {
00350 prev = STRW_NONE;
00351 }
00352 if (BTN_RED_PRESSED()) red_led_1 = 1; else red_led_1 = 0;
00353 if (BTN_GREEN_PRESSED()) green_led_1 = 1; else green_led_1 = 0;
00354
00355 if (0) {
00356 default_strwh_inactive();
00357 }
00358 else {
00359 if (EGO_MUTE_ON() && EGO_RED_LED_IS_ON()) {
00360 switch (ctrl){
00361 default:
00362 case STRW_NONE: default_strwh_inactive();break;
00363 case STRW_VOL_UP: EGO_X012(EGO_X012_VOL_UP);break;
00364 case STRW_VOL_DOWN: EGO_X012(EGO_X012_VOL_DOWN);break;
00365 case STRW_UP: EGO_X012(EGO_X012_PLAY_UNHOOK);break;
00366 case STRW_DOWN: EGO_X012(EGO_X012_STOP_ONHOOK);break;
00367 case STRW_DOWN_MODE: EGO_X012(EGO_X012_STOP_ONHOOK); break;
00368 }
00369 }
00370 else {
00371 if (EGO_GREEN_LED_IS_ON() && !EGO_RED_LED_IS_ON()) {
00372
00373 switch (ctrl){
00374 default:
00375 case STRW_NONE:
00376 default_strwh_inactive();
00377 break;
00378 case STRW_VOL_UP:
00379 {
00380 volume_activated_timer = VOLUME_ACTIVATE_TIMEOUT;
00381 if (prev == STRW_VOL_DOWN) {
00382 volume_activated = 1;
00383 }
00384 if (volume_activated) {
00385 EGO_X012(EGO_X012_VOL_UP);
00386 }
00387 }
00388 break;
00389 case STRW_VOL_DOWN:
00390 {
00391 volume_activated_timer = VOLUME_ACTIVATE_TIMEOUT;
00392 if (prev == STRW_VOL_UP) {
00393 volume_activated = 1;
00394 }
00395 if (volume_activated) {
00396 EGO_X012(EGO_X012_VOL_DOWN);
00397 }
00398 }
00399 break;
00400
00401 case STRW_UP:
00402 EGO_X012(EGO_X012_NEXT);
00403 break;
00404 case STRW_DOWN:
00405 EGO_X012(EGO_X012_PREV);
00406 break;
00407 case STRW_DOWN_MODE:
00408 EGO_X012(EGO_X012_STOP_ONHOOK);
00409 break;
00410 }
00411 }
00412 else {
00413 switch (ctrl){
00414 default:
00415 case STRW_NONE:
00416 default_strwh_inactive();
00417 break;
00418 case STRW_DOWN_MODE: EGO_X012(EGO_X012_STOP_ONHOOK);
00419 break;
00420 }
00421 }
00422 }
00423 }
00424
00425 if (ctrl != STRW_NONE) {
00426 prev = ctrl;
00427 }
00428
00429 if (ctrl != STRW_VOL_DOWN || ctrl != STRW_VOL_UP) {
00430 volume_activated = 0;
00431 }
00432 }
00433 }
00434 return 0;
00435 }
00436
00437