void main(void) { uint16_t i; char usb_char, err; const char init_msg[] = {'I', 'N', 'I', 'T'}; //extern FILE *stdout = _H_USER; // redirect stdout to USB init(); storage_init(); display_cnt = 0; volume_tick = 0; chan_tick = 0; usb_tick = 0; ir_tick = 0; ir_speedup = 20; dac_lock_tick = 0; display_set_alt(0x00, 0x00, 0x00); display_set(0x00, 0x00, 1); ir_receiver_init(); err = relay_boards_init(); // as side-effect: determine board Type and Id amp_state_init(); set_relays(0x00, 0x00, 0x00, 0x00); display_oled_init(); if (has_oled_display) { display_oled_chars( 0, 0, 5, "hello"); display_set_alt(DIGIT_D, 0x00, 3); } else if (err) display_set_alt(DIGIT_E, 0x01, 3); // Globally enable interrupts #ifdef UseIPEN INTCONbits.GIEH = 1; INTCONbits.GIEL = 1; #else INTCONbits.PEIE = 1; INTCONbits.GIE = 1; #endif // (re-)launch USB activity prev_usb_bus_sense = 0; usb_write(init_msg, (uint8_t) 4); // The above 'set_relays' enabled the power relay for the analog supply. #ifdef __DEBUG power_tick = 0; #else power_tick = 120; #endif // Set a timer to later undo the mute and activate last volume setting. // wait some time for stabilization before enabling all other interrupts while (power_tick > 0) ; // gets decreased on timer interrupts, 183Hz // power==0 now, from amp_state_init(). // incr power now quickly to 1, and later to 2. power_incr = 1; INTCON3bits.INT1IF = 0; INTCON3bits.INT1IE = 1; INTCON3bits.INT2IF = 0; INTCON3bits.INT2IE = 1; INTCON3bits.INT3IF = 0; INTCON3bits.INT3IE = 1; // Check if a DAC is present in this Relaixed, if so initialize. // This check was delayed to allow DAC power-up, otherwise its i2c interface stays in reset dac_init(); while (1) { if (volume_incr) volume_update(); if (balance_incr > 1 || balance_incr < -1) // suppress a single tick, might have been by accident balance_update(); if (channel_incr) channel_update(); if (power_incr) { if (flash_tick != 0 && power_incr < 0) { // quickly save recent volume/balance update flash_tick = 0; flash_volume_channel(); } else if (power_incr > 0 && power_state() == 0) { // if we move power_state from 0 to 1, we surely want to go later to 2 // For RelaixedPassive: wait somewhat longer for its soft-switch main power power_tick = (isRelaixedXLR) ? 500 : 700; } if (power_incr > 0) dac_init(); // check (again) for presence of DAC: it needs time to get out of reset power_update(); } if (ir_received_ok) { ir_received_ok = 0; ir_handle_code(); if (volume_incr) { vol_usb_msg[0] = 'V'; // when 'volume' keeps pressed, the volume-tick-speed goes up if (ir_speedup <= 49) ir_speedup += 4; } else { vol_usb_msg[0] = 'v'; ir_speedup = 20; } byte2hex(vol_usb_msg + 1, ir_tick); byte2hex(vol_usb_msg + 3, ir_speedup); if (power_incr) ir_tick = 100; // increase the default 20 to 100 on power on/off else flash_tick = 400; usb_write(vol_usb_msg, 5); } if (flash_tick == 1) { flash_tick = 0; flash_volume_channel(); } if (dac_status() >= DAC_NOLOCK && dac_lock_tick == 0) { dac_check_lock(); dac_lock_tick = 45; // check lock 4x per secnd } /* some I/O to check repeatedly, for absence of interrupt-on-change */ check_usb_power(err); } }
void interrupt high_priority app_isr_high(void) { // Timer4 wrap-around timer event, issued at 183Hz rate // Used for display multiplexing, but also for various local time counters if (PIE3bits.TMR4IE && PIR3bits.TMR4IF) { display_isr(); if (volume_tick) volume_tick--; if (ir_tick) ir_tick--; if (chan_tick) { chan_tick--; if (chan_tick == 0 && INTCON2bits.INTEDG3 && power_state() == 2) // waited long for rising edge: do power-down power_incr = -1; } if (power_tick) { power_tick--; if (power_tick == 0) { power_incr = 1; // INTCON3bits.INT3IE set only after reaching here?? } } if (flash_tick > 1) flash_tick--; if (dac_lock_tick) dac_lock_tick--; PIR3bits.TMR4IF = 0; } if (INTCON3bits.INT1IE && INTCON3bits.INT1IF) { // edge on IR-receiver input // ir_tick, set high, needs to count down to ir_speedup, to accept a next volume command // From ir_speedup to 0 it counts down further, allowing as 'continuation' an increase in 'ir_speedup'. // The baseline value of '20' for ir-speedup covers the interval of about 100msec pause // between successive ir_commands in RC5 when the button maintains pressed if (((char) ir_tick) - ir_speedup <= 0) { // the tick counter is to prevent a too high rate of processing volume/channel updates ir_receiver_isr(); } INTCON3bits.INT1IF = 0; INTCON2bits.INTEDG1 = !IRserial; } if (INTCONbits.TMR0IE && INTCONbits.TMR0IF) { // IR receiver timer expires: about 5 ms after end of IR pulse-train // Might also be a an unexpected termination on a bad signal reception ir_received_ok = ir_tmr_isr(); if (ir_tick == 0) ir_speedup = 20; // reset accelleration if (ir_received_ok) ir_tick = 65; // wait-time to process a next IR signal train; avoid unwanted/fast command repeats INTCONbits.TMR0IE = 0; // do this interrupt only once after IR pulse train. INTCON2bits.INTEDG1 = 0; // a new pulse-train should start with a neg-edge. } if (INTCON3bits.INT2IE && INTCON3bits.INT2IF) { // edge on VolA input: check edge-direction of VolA against VolB value: if (volume_tick == 0) { if (INTCON2bits.INTEDG3 == 1) //channel-button is pressed { if (INTCON2bits.INTEDG2 == VolB) balance_incr -= 1; else balance_incr += 1; if (balance_incr > 1 || balance_incr < -1) chan_tick = 0; // Suppress channel or power action on button release } else { if (INTCON2bits.INTEDG2 == VolB) volume_incr -= 1; else volume_incr += 1; } volume_tick = 2; // create delay flash_tick = 400; } INTCON2bits.INTEDG2 = !VolA; INTCON3bits.INT2IF = 0; } if (INTCON3bits.INT3IE && INTCON3bits.INT3IF) { // activity on channel-select push-button if (INTCON2bits.INTEDG3 && chan_tick < 252) { // rising edge on channel input (release of SelectB) if (chan_tick == 0) { // did already do power-down a while ago // or knob-turning created this into just balance adjust } else { // quick release: do next channel if (power_state() == 2) { channel_incr = 1; flash_tick = 300; } } chan_tick = 3; INTCON2bits.INTEDG3 = 0; // look for falling edge } else if (!INTCON2bits.INTEDG3 && chan_tick == 0) { // falling edge on channel input (SelectB) if (power_state() == 0) { // launch power-up sequence power_incr = 1; chan_tick = 3; } else chan_tick = 255; // Count duration of push button INTCON2bits.INTEDG3 = 1; // look for rising edge } INTCON3bits.INT3IF = 0; } // Power-supply drop on digital power: quickly mute audio if (PIE2bits.LVDIE && PIR2bits.LVDIF) { if (power_state() == 2) { power_incr = -1; PIE2bits.LVDIE = 0; // we go power-down, prevent interrupt to repeat } PIR2bits.LVDIF = 0; } #ifdef UseIPEN }
void app_isr_high(void) { // Timer4 wrap-around timer event, issued at 183Hz rate // Used for display multiplexing, but also for various local time counters if (PIE3bits.TMR4IE && PIR3bits.TMR4IF) { display_isr(); if (volume_tick) volume_tick--; if (ir_tick) ir_tick--; if (chan_tick) { chan_tick--; if (chan_tick == 0 && INTCON2bits.INTEDG3 && power_state() == 2) // waited long for rising edge: do power-down power_incr = -1; } if (power_tick) { power_tick--; if (power_tick == 0) { power_incr = 1; // INTCON3bits.INT3IE set only after reaching here?? } } if (flash_tick > 1) flash_tick--; PIR3bits.TMR4IF = 0; } if (INTCON3bits.INT1IE && INTCON3bits.INT1IF) { // edge on IR-receiver input if (ir_tick == 0) { // the tick counter is to prevent a too high rate of processing volume/channel updates ir_receiver_isr(); } INTCON3bits.INT1IF = 0; INTCON2bits.INTEDG1 = !IRserial; } if (INTCONbits.TMR0IE && INTCONbits.TMR0IF) { // IR receiver timer expires: end of IR pulse-train // Might also be a an unexpected termination on a bad signal reception ir_received_ok = ir_tmr_isr(); if (ir_received_ok) ir_tick = 20; INTCONbits.TMR0IE = 0; // do this interrupt only once after IR pulse train. INTCON2bits.INTEDG1 = 0; // a new pulse-train should start with a neg-edge. } if (INTCON3bits.INT2IE && INTCON3bits.INT2IF) { // edge on VolA input: check edge-direction of VolA against VolB value: if (volume_tick == 0) { if (INTCON2bits.INTEDG3 == 1) //channel-button is pressed { if (INTCON2bits.INTEDG2 == VolB) balance_incr -= 1; else balance_incr += 1; if (balance_incr > 1 || balance_incr < -1) chan_tick = 0; // Suppress channel or power action on button release } else { if (INTCON2bits.INTEDG2 == VolB) volume_incr -= 1; else volume_incr += 1; } volume_tick = 2; // create delay flash_tick = 400; } INTCON2bits.INTEDG2 = !VolA; INTCON3bits.INT2IF = 0; } if (INTCON3bits.INT3IE && INTCON3bits.INT3IF) { // activity on channel-select input if (INTCON2bits.INTEDG3 && chan_tick < 252) { // rising edge on channel input (release of SelectB) if (chan_tick == 0) { // did already do power-down a while ago // or knob-turning created this into just balance adjust } else { // quick release: do next channel if (power_state() == 2) { channel_incr = 1; flash_tick = 300; } else if (power_state() == 0) { power_incr = 1; } } chan_tick = 3; INTCON2bits.INTEDG3 = 0; // look for falling edge } else if (!INTCON2bits.INTEDG3 && chan_tick == 0) { // falling edge on channel input (SelectB) chan_tick = 255; // Count duration of push button INTCON2bits.INTEDG3 = 1; // look for rising edge } INTCON3bits.INT3IF = 0; } // Power-supply drop on digital power: quickly mute audio if (PIE2bits.LVDIE && PIR2bits.LVDIF) { if (power_state() == 2) { power_incr = -1; PIE2bits.LVDIE = 0; // we go power-down, prevent interrupt to repeat } PIR2bits.LVDIF = 0; } #ifdef UseIPEN }
static void bluetooth_parse_command(uint8_t len) { uint8_t response = RESPONSE_OK; sei(); if (len == 0) { response = RESPONSE_NO_RESPONSE; } else if (strncmp(rxbuff, BLUETOOTH_CMD_HELP, len) == 0) { uint8_t i = 0; for (i = 1; i < sizeof(commands) / sizeof(commands[0]); i ++) { uart_puts(commands[i]); if ((i % 3) == 0) { uart_puts("\r\n"); } else { uint8_t padding = 0, j = 0; padding = 26 - strlen(commands[i]); for (j = 0; j < padding; j++) { uart_putc(' '); } } } if (((i - 1) % 3) != 0) { uart_puts("\r\n"); } response = RESPONSE_NO_RESPONSE; } else if (strncmp(rxbuff, BLUETOOTH_CMD_BATTERY, len) == 0) { uint8_t capacity = 0; char resp[16]; capacity = battery_get_capacity(); itoa(capacity, resp, 10); uart_puts(BLUETOOTH_CMD_BATTERY); uart_puts(": "); uart_puts(resp); uart_puts("%\r\n"); response = RESPONSE_NO_RESPONSE; } else if (strncmp(rxbuff, BLUETOOTH_CMD_ECHO, len) == 0) { echo = TRUE; uart_puts("\r\n"); response = RESPONSE_NO_RESPONSE; } else if (strncmp(rxbuff, BLUETOOTH_CMD_EYES, strlen(BLUETOOTH_CMD_EYES)) == 0) { char *param = rxbuff + strlen(BLUETOOTH_CMD_EYES) + 1; if (len == strlen(BLUETOOTH_CMD_EYES) + strlen(BLUETOOTH_PARAM_ON) + 1) { if (strncmp(param, BLUETOOTH_PARAM_ON, strlen(BLUETOOTH_PARAM_ON)) == 0) { power_on(EYES); } else { response = RESPONSE_ERROR; } } else if (len == strlen(BLUETOOTH_CMD_EYES) + strlen(BLUETOOTH_PARAM_OFF) + 1) { if (strncmp(param, BLUETOOTH_PARAM_OFF, strlen(BLUETOOTH_PARAM_OFF)) == 0) { power_off(EYES); } else { response = RESPONSE_ERROR; } } else if (len == strlen(BLUETOOTH_CMD_EYES)) { uint8_t state = power_state(EYES); uart_puts(BLUETOOTH_CMD_EYES); uart_puts(": "); if (state == POWER_ON) { uart_puts(BLUETOOTH_PARAM_ON); } else { uart_puts(BLUETOOTH_PARAM_OFF); } uart_puts("\r\n"); response = RESPONSE_NO_RESPONSE; } else { response = RESPONSE_ERROR; } } else if (strncmp(rxbuff, BLUETOOTH_CMD_HELMET, strlen(BLUETOOTH_CMD_HELMET)) == 0) { char *param = rxbuff + strlen(BLUETOOTH_CMD_HELMET) + 1; if (len == strlen(BLUETOOTH_CMD_HELMET) + strlen(BLUETOOTH_PARAM_OPEN) + 1) { if (strncmp(param, BLUETOOTH_PARAM_OPEN, strlen(BLUETOOTH_PARAM_OPEN)) == 0) { helmet_open(); } else { response = RESPONSE_ERROR; } } else if (len == strlen(BLUETOOTH_CMD_HELMET) + strlen(BLUETOOTH_PARAM_CLOSE) + 1) { if (strncmp(param, BLUETOOTH_PARAM_CLOSE, strlen(BLUETOOTH_PARAM_CLOSE)) == 0) { helmet_close(); } else { response = RESPONSE_ERROR; } } else if (len == strlen(BLUETOOTH_CMD_HELMET)) { uint8_t state = helmet_state(); uart_puts(BLUETOOTH_CMD_HELMET); uart_puts(": "); if (state == HELMET_OPEN) { uart_puts(BLUETOOTH_PARAM_OPEN); } else { uart_puts(BLUETOOTH_PARAM_CLOSE); } uart_puts("\r\n"); response = RESPONSE_NO_RESPONSE; } else { response = RESPONSE_ERROR; } } else if (strncmp(rxbuff, BLUETOOTH_CMD_INTENSITY, strlen(BLUETOOTH_CMD_INTENSITY)) == 0) { uint8_t device = 0; char *param = rxbuff + strlen(BLUETOOTH_CMD_INTENSITY) + 1; if (strncmp(param, BLUETOOTH_CMD_EYES, strlen(BLUETOOTH_CMD_EYES)) == 0) { if (len == strlen(BLUETOOTH_CMD_INTENSITY) + strlen(BLUETOOTH_CMD_EYES) + 3) { device = EYES; } else if (len == strlen(BLUETOOTH_CMD_INTENSITY) + strlen(BLUETOOTH_CMD_EYES) + 1) { device = EYES; response = RESPONSE_NO_RESPONSE; } else { response = RESPONSE_ERROR; } } else if (strncmp(param, BLUETOOTH_CMD_REPULSORS, strlen(BLUETOOTH_CMD_REPULSORS)) == 0) { if (len == strlen(BLUETOOTH_CMD_INTENSITY) + strlen(BLUETOOTH_CMD_REPULSORS) + 3) { device = REPULSORS_POWER; } else if (len == strlen(BLUETOOTH_CMD_INTENSITY) + strlen(BLUETOOTH_CMD_REPULSORS) + 1) { device = REPULSORS_POWER; response = RESPONSE_NO_RESPONSE; } else { response = RESPONSE_ERROR; } } else if (strncmp(param, BLUETOOTH_CMD_UNIBEAM, strlen(BLUETOOTH_CMD_UNIBEAM)) == 0) { if (len == strlen(BLUETOOTH_CMD_INTENSITY) + strlen(BLUETOOTH_CMD_UNIBEAM) + 3) { device = UNIBEAM; } else if (len == strlen(BLUETOOTH_CMD_INTENSITY) + strlen(BLUETOOTH_CMD_UNIBEAM) + 1) { device = UNIBEAM; response = RESPONSE_NO_RESPONSE; } else { response = RESPONSE_ERROR; } } else { response = RESPONSE_ERROR; } if (response == RESPONSE_OK) { // convert number in ascii to integer uint8_t intensity = rxbuff[len - 1] - '0'; if ((intensity >= 0) && (intensity <= 9)) { power_set_intensity(device, intensity); } else { response = RESPONSE_ERROR; } } else if (response == RESPONSE_NO_RESPONSE) { int8_t intensity = power_get_intensity(device); uart_puts(BLUETOOTH_CMD_INTENSITY); uart_puts(": "); uart_putc('0' + intensity); uart_puts("\r\n"); } } else if (strncmp(rxbuff, BLUETOOTH_CMD_QUOTE, len) == 0) { if (voice_is_playing()) { voice_stop_playback(); } else { voice_play_quote(); } } else if (strncmp(rxbuff, BLUETOOTH_CMD_REBOOT, len) == 0) { response = RESPONSE_NO_RESPONSE; // stop reporting of battery status battery_reporting_stop(); voice_play_sound(SOUND_SLEEP_0); _delay_ms(1000); voice_play_sound(SOUND_SLEEP_2); voice_play_sound_no_wait(SOUND_POWER_DOWN); // turn off all devices power_off(ALL); // restart mcu wdt_reboot(); } else if (strncmp(rxbuff, BLUETOOTH_CMD_REPULSORS, strlen(BLUETOOTH_CMD_REPULSORS)) == 0) { char *param = rxbuff + strlen(BLUETOOTH_CMD_REPULSORS) + 1; if (len == strlen(BLUETOOTH_CMD_REPULSORS) + strlen(BLUETOOTH_PARAM_ON) + 1) { if (strncmp(param, BLUETOOTH_PARAM_ON, strlen(BLUETOOTH_PARAM_ON)) == 0) { power_on(REPULSORS_POWER); } else { response = RESPONSE_ERROR; } } else if (len == strlen(BLUETOOTH_CMD_REPULSORS) + strlen(BLUETOOTH_PARAM_OFF) + 1) { if (strncmp(param, BLUETOOTH_PARAM_OFF, strlen(BLUETOOTH_PARAM_OFF)) == 0) { power_off(REPULSORS_POWER); } else { response = RESPONSE_ERROR; } } else if (len == strlen(BLUETOOTH_CMD_REPULSORS)) { uint8_t state = power_state(REPULSORS_POWER); uart_puts(BLUETOOTH_CMD_REPULSORS); uart_puts(": "); if (state == POWER_ON) { uart_puts(BLUETOOTH_PARAM_ON); } else { uart_puts(BLUETOOTH_PARAM_OFF); } uart_puts("\r\n"); response = RESPONSE_NO_RESPONSE; } else { response = RESPONSE_ERROR; } } else if (strncmp(rxbuff, BLUETOOTH_CMD_REPULSOR, strlen(BLUETOOTH_CMD_REPULSOR)) == 0) { char *param = rxbuff + strlen(BLUETOOTH_CMD_REPULSOR) + 1; if (len == strlen(BLUETOOTH_CMD_REPULSOR) + strlen(BLUETOOTH_PARAM_LEFT) + 1) { if (strncmp(param, BLUETOOTH_PARAM_LEFT, strlen(BLUETOOTH_PARAM_LEFT)) == 0) { power_blast(REPULSOR_LEFT); } else { response = RESPONSE_ERROR; } } else if (len == strlen(BLUETOOTH_CMD_REPULSOR) + strlen(BLUETOOTH_PARAM_RIGHT) + 1) { if (strncmp(param, BLUETOOTH_PARAM_RIGHT, strlen(BLUETOOTH_PARAM_RIGHT)) == 0) { power_blast(REPULSOR_RIGHT); } else { response = RESPONSE_ERROR; } } else { response = RESPONSE_ERROR; } } else if (strncmp(rxbuff, BLUETOOTH_CMD_UNIBEAM, strlen(BLUETOOTH_CMD_UNIBEAM)) == 0) { char *param = rxbuff + strlen(BLUETOOTH_CMD_UNIBEAM) + 1; if (len == strlen(BLUETOOTH_CMD_UNIBEAM) + strlen(BLUETOOTH_PARAM_ON) + 1) { if (strncmp(param, BLUETOOTH_PARAM_ON, strlen(BLUETOOTH_PARAM_ON)) == 0) { power_on(UNIBEAM); } else { response = RESPONSE_ERROR; } } else if (len == strlen(BLUETOOTH_CMD_UNIBEAM) + strlen(BLUETOOTH_PARAM_OFF) + 1) { if (strncmp(param, BLUETOOTH_PARAM_OFF, strlen(BLUETOOTH_PARAM_OFF)) == 0) { power_off(UNIBEAM); } else { response = RESPONSE_ERROR; } } else if (len == strlen(BLUETOOTH_CMD_UNIBEAM)) { uint8_t state = power_state(UNIBEAM); uart_puts(BLUETOOTH_CMD_UNIBEAM); uart_puts(": "); if (state == POWER_ON) { uart_puts(BLUETOOTH_PARAM_ON); } else { uart_puts(BLUETOOTH_PARAM_OFF); } uart_puts("\r\n"); response = RESPONSE_NO_RESPONSE; } else { response = RESPONSE_ERROR; } } else if (strncmp(rxbuff, BLUETOOTH_CMD_VERSION, len) == 0) { uart_puts(BLUETOOTH_RESPONSE_VERSION); uart_puts("\r\n"); response = RESPONSE_NO_RESPONSE; } else if (strncmp(rxbuff, BLUETOOTH_CMD_VOLUME, strlen(BLUETOOTH_CMD_VOLUME)) == 0) { if (len == strlen(BLUETOOTH_CMD_VOLUME) + 2) { // convert number in ascii to integer uint8_t volume = rxbuff[len - 1] - '0'; if ((volume >= 0) && (volume <= 7)) { voice_set_volume(SOUND_VOLUME_0 + volume); } else { response = RESPONSE_ERROR; } } else if (len == strlen(BLUETOOTH_CMD_VOLUME)) { uint8_t volume = voice_get_volume() - SOUND_VOLUME_0; uart_puts(BLUETOOTH_CMD_VOLUME); uart_puts(": "); uart_putc('0' + volume); uart_puts("\r\n"); response = RESPONSE_NO_RESPONSE; } else { response = RESPONSE_ERROR; } } else { response = RESPONSE_ERROR; } if (response == RESPONSE_OK) { uart_puts(BLUETOOTH_RESPONSE_OK); uart_puts("\r\n"); } else if (response == RESPONSE_ERROR) { uart_puts(BLUETOOTH_RESPONSE_ERROR); uart_puts("\r\n"); } if (echo) { uart_puts(BLUETOOTH_PROMPT); } }
void main(void) { unsigned int i; char usb_char, err; const char init_msg[] = {'I', 'N', 'I', 'T'}; extern FILE *stdout = _H_USER; // redirect stdout to USB init(); display_cnt = 0; volume_tick = 0; chan_tick = 0; usb_tick = 0; ir_tick = 0; display_set( 0x00, 0x00); display_set_alt( 0x00, 0x00, 0x00); ir_receiver_init(); storage_init(); err = relay_boards_init(); set_relays(0x00, 0x00, 0x00, 0x00, 0x00); amp_state_init(); if (err) display_set_alt( DIGIT_E, 0x01, 3); // Globally enable interrupts #ifdef UseIPEN INTCONbits.GIEH = 1; INTCONbits.GIEL = 1; #else INTCONbits.PEIE = 1; INTCONbits.GIE = 1; #endif // (re-)launch USB activity prev_usb_bus_sense = 0; usb_write( init_msg, (byte)4); // The above 'set_relays' enabled the power relay for the analog supply. power_tick = 150; // Set a timer to later undo the mute and activate last volume setting. // wait some time for stabilization before enabling all other interrupts while (power_tick > 0) ; // gets decreased on timer interrupts // power==0 now, from amp_state_init(). // incr power now quickly to 1, and later to 2. power_incr = 1; INTCON3bits.INT1IF = 0; INTCON3bits.INT1IE = 1; INTCON3bits.INT2IF = 0; INTCON3bits.INT2IE = 1; INTCON3bits.INT3IF = 0; INTCON3bits.INT3IE = 1; while (1) { if (volume_incr) volume_update(); if (balance_incr > 1 || balance_incr < -1) // suppress a single tick, might have been by accident balance_update(); if (channel_incr) channel_update(); if (power_incr) { if (flash_tick && power_incr < 0) { // quickly save recent volume/balance update flash_tick = 0; flash_volume_channel(); } else if (power_incr > 0 && power_state() == 0) { // if we move power_state from 0 to 1, we surely want to go later to 2 power_tick = 500; } power_update(); } if (ir_received_ok) { ir_received_ok = 0; ir_handle_code(); if (power_incr) ir_tick = 100; else flash_tick = 400; } if (flash_tick == 1) { flash_tick = 0; flash_volume_channel(); } /* some I/O to check repeatedly, for absence of interrupt-on-change */ check_usb_power(err); } }