#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/sleep.h>
#include <stddef.h>
#include <stdint.h>
#define ARRAY_SIZE(a) (sizeof (a) / sizeof (*a))
static const struct traffic_light {
struct traffic_light_led {
volatile uint8_t *port;
uint8_t pin;
} red, amber, green;
} traffic_lights[] = {
/* North traffic lights */
{
{&PORTA, _BV(PA0)},
{&PORTA, _BV(PA1)},
{&PORTA, _BV(PA2)}
},
/* South traffic lights */
{
{&PORTA, _BV(PA3)},
{&PORTA, _BV(PA4)},
{&PORTA, _BV(PA5)}
},
/* East traffic lights */
{
{&PORTA, _BV(PA6)},
{&PORTA, _BV(PA7)},
{&PORTB, _BV(PB0)}
},
/* West traffic lights */
{
{&PORTB, _BV(PB1)},
{&PORTB, _BV(PB2)},
{&PORTB, _BV(PB3)}
},
};
static void set_traffic_light_led(const struct traffic_light_led *led) {
*(led->port) |= led->pin;
}
static void reset_traffic_light_led(const struct traffic_light_led *led) {
*(led->port) &= ~(led->pin);
}
static void set_traffic_light_green(const struct traffic_light *light) {
set_traffic_light_led(&light->green);
reset_traffic_light_led(&light->amber);
reset_traffic_light_led(&light->red);
}
static void set_traffic_light_amber(const struct traffic_light *light) {
reset_traffic_light_led(&light->green);
set_traffic_light_led(&light->amber);
reset_traffic_light_led(&light->red);
}
static void set_traffic_light_red(const struct traffic_light *light) {
reset_traffic_light_led(&light->green);
reset_traffic_light_led(&light->amber);
set_traffic_light_led(&light->red);
}
static void reset_traffic_light(const struct traffic_light *light) {
reset_traffic_light_led(&light->green);
reset_traffic_light_led(&light->amber);
reset_traffic_light_led(&light->red);
}
typedef void (output_state)(const struct traffic_light *);
#define s_off &reset_traffic_light
#define s_green &set_traffic_light_green
#define s_amber &set_traffic_light_amber
#define s_red &set_traffic_light_red
static output_state * const output_states[] = {
s_green, s_off, s_green, s_off, s_green, s_off, s_green, s_off, s_amber,
s_red, s_red, s_red, s_red, s_red, s_red, s_red, s_red, s_red,
s_red, s_red, s_red, s_red, s_red, s_red, s_red, s_red, s_red,
s_red, s_red, s_red, s_red, s_red, s_red, s_red, s_red, s_red
};
enum {
TCNT0_MAX = 250u,
TCNT0_START = 256u - TCNT0_MAX,
PRESCALER = 8u,
CLOCKS_PER_MS = F_CPU / PRESCALER / TCNT0_MAX / 1000u
};
static volatile size_t ovf = 0;
/* State transition times in milliseconds */
enum {
GREEN_MS = 10000u,
BLINK_MS = 500u,
AMBER_MS = 3000u
};
static const size_t times[] = {
GREEN_MS, BLINK_MS, BLINK_MS,
BLINK_MS, BLINK_MS, BLINK_MS,
BLINK_MS, BLINK_MS, AMBER_MS
};
static volatile size_t times_index = 0u;
static volatile size_t ms = 5000u;
static void set_timers(void) {
ms = times[times_index];
TCCR0 |= _BV(CS01);
TCNT0 = TCNT0_START;
ovf = 0u;
}
/* Indices in the states vector */
static volatile size_t current_states[] = {
0u, /* North Traffic Light Start State */
27u, /* South Traffic Light Start State */
18u, /* East Traffic Light Start State */
9u /* North Traffic Light Start State */
};
static void run_states(void) {
for (size_t i = 0u; i < ARRAY_SIZE(current_states); ++i) {
output_states[current_states[i]](traffic_lights + i);
}
}
static void advance(volatile size_t *index, size_t size) {
++*index;
*index %= size;
}
static void advance_states(void) {
for (size_t i = 0u; i < ARRAY_SIZE(current_states); ++i) {
advance(current_states + i, ARRAY_SIZE(output_states));
}
}
static void advance_times(void) {
advance(×_index, ARRAY_SIZE(times));
set_timers();
}
ISR(TIMER0_OVF_vect) {
if (++ovf >= CLOCKS_PER_MS * ms) {
advance_states();
advance_times();
run_states();
}
}
static void set_io_registers(void) {
DDRA = 0xffu;
DDRB |= 0x0fu;
}
static void set_interrupt_registers(void) {
TIMSK |= _BV(TOIE0);
sei();
}
static void set_start_state(void) {
run_states();
}
int main(void) {
set_io_registers();
set_interrupt_registers();
set_start_state();
set_timers();
set_sleep_mode(SLEEP_MODE_IDLE);
for (;;) {
sleep_mode();
}
return 0;
}
I2luY2x1ZGUgPGF2ci9pbnRlcnJ1cHQuaD4KI2luY2x1ZGUgPGF2ci9pby5oPgojaW5jbHVkZSA8YXZyL3NsZWVwLmg+CgojaW5jbHVkZSA8c3RkZGVmLmg+CiNpbmNsdWRlIDxzdGRpbnQuaD4KCiNkZWZpbmUgQVJSQVlfU0laRShhKSAoc2l6ZW9mIChhKSAvIHNpemVvZiAoKmEpKQoKc3RhdGljIGNvbnN0IHN0cnVjdCB0cmFmZmljX2xpZ2h0IHsKICBzdHJ1Y3QgdHJhZmZpY19saWdodF9sZWQgewogICAgdm9sYXRpbGUgdWludDhfdCAqcG9ydDsKICAgIHVpbnQ4X3QgcGluOwogIH0gcmVkLCBhbWJlciwgZ3JlZW47Cn0gdHJhZmZpY19saWdodHNbXSA9IHsKICAvKiBOb3J0aCB0cmFmZmljIGxpZ2h0cyAqLwogIHsKICAgIHsmUE9SVEEsIF9CVihQQTApfSwKICAgIHsmUE9SVEEsIF9CVihQQTEpfSwKICAgIHsmUE9SVEEsIF9CVihQQTIpfQogIH0sCiAgLyogU291dGggdHJhZmZpYyBsaWdodHMgKi8KICB7CiAgICB7JlBPUlRBLCBfQlYoUEEzKX0sCiAgICB7JlBPUlRBLCBfQlYoUEE0KX0sCiAgICB7JlBPUlRBLCBfQlYoUEE1KX0KICB9LAogIC8qIEVhc3QgdHJhZmZpYyBsaWdodHMgKi8KICB7CiAgICB7JlBPUlRBLCBfQlYoUEE2KX0sCiAgICB7JlBPUlRBLCBfQlYoUEE3KX0sCiAgICB7JlBPUlRCLCBfQlYoUEIwKX0KICB9LAogIC8qIFdlc3QgdHJhZmZpYyBsaWdodHMgKi8KICB7CiAgICB7JlBPUlRCLCBfQlYoUEIxKX0sCiAgICB7JlBPUlRCLCBfQlYoUEIyKX0sCiAgICB7JlBPUlRCLCBfQlYoUEIzKX0KICB9LAp9OwoKc3RhdGljIHZvaWQgc2V0X3RyYWZmaWNfbGlnaHRfbGVkKGNvbnN0IHN0cnVjdCB0cmFmZmljX2xpZ2h0X2xlZCAqbGVkKSB7CiAgKihsZWQtPnBvcnQpIHw9IGxlZC0+cGluOwp9CgpzdGF0aWMgdm9pZCByZXNldF90cmFmZmljX2xpZ2h0X2xlZChjb25zdCBzdHJ1Y3QgdHJhZmZpY19saWdodF9sZWQgKmxlZCkgewogICoobGVkLT5wb3J0KSAmPSB+KGxlZC0+cGluKTsKfQoKc3RhdGljIHZvaWQgc2V0X3RyYWZmaWNfbGlnaHRfZ3JlZW4oY29uc3Qgc3RydWN0IHRyYWZmaWNfbGlnaHQgKmxpZ2h0KSB7CiAgc2V0X3RyYWZmaWNfbGlnaHRfbGVkKCZsaWdodC0+Z3JlZW4pOwogIHJlc2V0X3RyYWZmaWNfbGlnaHRfbGVkKCZsaWdodC0+YW1iZXIpOwogIHJlc2V0X3RyYWZmaWNfbGlnaHRfbGVkKCZsaWdodC0+cmVkKTsKfQoKc3RhdGljIHZvaWQgc2V0X3RyYWZmaWNfbGlnaHRfYW1iZXIoY29uc3Qgc3RydWN0IHRyYWZmaWNfbGlnaHQgKmxpZ2h0KSB7CiAgcmVzZXRfdHJhZmZpY19saWdodF9sZWQoJmxpZ2h0LT5ncmVlbik7CiAgc2V0X3RyYWZmaWNfbGlnaHRfbGVkKCZsaWdodC0+YW1iZXIpOwogIHJlc2V0X3RyYWZmaWNfbGlnaHRfbGVkKCZsaWdodC0+cmVkKTsKfQoKc3RhdGljIHZvaWQgc2V0X3RyYWZmaWNfbGlnaHRfcmVkKGNvbnN0IHN0cnVjdCB0cmFmZmljX2xpZ2h0ICpsaWdodCkgewogIHJlc2V0X3RyYWZmaWNfbGlnaHRfbGVkKCZsaWdodC0+Z3JlZW4pOwogIHJlc2V0X3RyYWZmaWNfbGlnaHRfbGVkKCZsaWdodC0+YW1iZXIpOwogIHNldF90cmFmZmljX2xpZ2h0X2xlZCgmbGlnaHQtPnJlZCk7Cn0KCnN0YXRpYyB2b2lkIHJlc2V0X3RyYWZmaWNfbGlnaHQoY29uc3Qgc3RydWN0IHRyYWZmaWNfbGlnaHQgKmxpZ2h0KSB7CiAgcmVzZXRfdHJhZmZpY19saWdodF9sZWQoJmxpZ2h0LT5ncmVlbik7CiAgcmVzZXRfdHJhZmZpY19saWdodF9sZWQoJmxpZ2h0LT5hbWJlcik7CiAgcmVzZXRfdHJhZmZpY19saWdodF9sZWQoJmxpZ2h0LT5yZWQpOwp9Cgp0eXBlZGVmIHZvaWQgKG91dHB1dF9zdGF0ZSkoY29uc3Qgc3RydWN0IHRyYWZmaWNfbGlnaHQgKik7CgojZGVmaW5lIHNfb2ZmICAgJnJlc2V0X3RyYWZmaWNfbGlnaHQKI2RlZmluZSBzX2dyZWVuICZzZXRfdHJhZmZpY19saWdodF9ncmVlbgojZGVmaW5lIHNfYW1iZXIgJnNldF90cmFmZmljX2xpZ2h0X2FtYmVyCiNkZWZpbmUgc19yZWQgICAmc2V0X3RyYWZmaWNfbGlnaHRfcmVkCgpzdGF0aWMgb3V0cHV0X3N0YXRlICogY29uc3Qgb3V0cHV0X3N0YXRlc1tdID0gewogIHNfZ3JlZW4sIHNfb2ZmLCBzX2dyZWVuLCBzX29mZiwgc19ncmVlbiwgc19vZmYsIHNfZ3JlZW4sIHNfb2ZmLCBzX2FtYmVyLAogIHNfcmVkLCAgIHNfcmVkLCBzX3JlZCwgICBzX3JlZCwgc19yZWQsICAgc19yZWQsIHNfcmVkLCAgIHNfcmVkLCBzX3JlZCwKICBzX3JlZCwgICBzX3JlZCwgc19yZWQsICAgc19yZWQsIHNfcmVkLCAgIHNfcmVkLCBzX3JlZCwgICBzX3JlZCwgc19yZWQsCiAgc19yZWQsICAgc19yZWQsIHNfcmVkLCAgIHNfcmVkLCBzX3JlZCwgICBzX3JlZCwgc19yZWQsICAgc19yZWQsIHNfcmVkCn07CgplbnVtIHsKICBUQ05UMF9NQVggICAgID0gMjUwdSwKICBUQ05UMF9TVEFSVCAgID0gMjU2dSAtIFRDTlQwX01BWCwKICBQUkVTQ0FMRVIgICAgID0gOHUsCiAgQ0xPQ0tTX1BFUl9NUyA9IEZfQ1BVIC8gUFJFU0NBTEVSIC8gVENOVDBfTUFYIC8gMTAwMHUKfTsKCnN0YXRpYyB2b2xhdGlsZSBzaXplX3Qgb3ZmID0gMDsKCi8qIFN0YXRlIHRyYW5zaXRpb24gdGltZXMgaW4gbWlsbGlzZWNvbmRzICovCmVudW0gewogIEdSRUVOX01TID0gMTAwMDB1LAogIEJMSU5LX01TID0gNTAwdSwKICBBTUJFUl9NUyA9IDMwMDB1Cn07CiAgCnN0YXRpYyBjb25zdCBzaXplX3QgdGltZXNbXSA9IHsKICBHUkVFTl9NUywgQkxJTktfTVMsIEJMSU5LX01TLAogIEJMSU5LX01TLCBCTElOS19NUywgQkxJTktfTVMsCiAgQkxJTktfTVMsIEJMSU5LX01TLCBBTUJFUl9NUwp9OwoKc3RhdGljIHZvbGF0aWxlIHNpemVfdCB0aW1lc19pbmRleCA9IDB1OwpzdGF0aWMgdm9sYXRpbGUgc2l6ZV90IG1zID0gNTAwMHU7CgpzdGF0aWMgdm9pZCBzZXRfdGltZXJzKHZvaWQpIHsKICBtcyA9IHRpbWVzW3RpbWVzX2luZGV4XTsKICBUQ0NSMCB8PSBfQlYoQ1MwMSk7CiAgVENOVDAgPSBUQ05UMF9TVEFSVDsKICBvdmYgPSAwdTsKfQoKLyogSW5kaWNlcyBpbiB0aGUgc3RhdGVzIHZlY3RvciAqLwpzdGF0aWMgdm9sYXRpbGUgc2l6ZV90IGN1cnJlbnRfc3RhdGVzW10gPSB7CiAgMHUsICAvKiBOb3J0aCBUcmFmZmljIExpZ2h0IFN0YXJ0IFN0YXRlICovCiAgMjd1LCAvKiBTb3V0aCBUcmFmZmljIExpZ2h0IFN0YXJ0IFN0YXRlICovCiAgMTh1LCAvKiBFYXN0IFRyYWZmaWMgTGlnaHQgU3RhcnQgU3RhdGUgKi8KICA5dSAgIC8qIE5vcnRoIFRyYWZmaWMgTGlnaHQgU3RhcnQgU3RhdGUgKi8KfTsKCnN0YXRpYyB2b2lkIHJ1bl9zdGF0ZXModm9pZCkgewogIGZvciAoc2l6ZV90IGkgPSAwdTsgaSA8IEFSUkFZX1NJWkUoY3VycmVudF9zdGF0ZXMpOyArK2kpIHsKICAgIG91dHB1dF9zdGF0ZXNbY3VycmVudF9zdGF0ZXNbaV1dKHRyYWZmaWNfbGlnaHRzICsgaSk7CiAgfQp9CgpzdGF0aWMgdm9pZCBhZHZhbmNlKHZvbGF0aWxlIHNpemVfdCAqaW5kZXgsIHNpemVfdCBzaXplKSB7CiAgKysqaW5kZXg7CiAgKmluZGV4ICU9IHNpemU7Cn0KCnN0YXRpYyB2b2lkIGFkdmFuY2Vfc3RhdGVzKHZvaWQpIHsKICBmb3IgKHNpemVfdCBpID0gMHU7IGkgPCBBUlJBWV9TSVpFKGN1cnJlbnRfc3RhdGVzKTsgKytpKSB7CiAgICBhZHZhbmNlKGN1cnJlbnRfc3RhdGVzICsgaSwgQVJSQVlfU0laRShvdXRwdXRfc3RhdGVzKSk7CiAgfQp9CgpzdGF0aWMgdm9pZCBhZHZhbmNlX3RpbWVzKHZvaWQpIHsKICBhZHZhbmNlKCZ0aW1lc19pbmRleCwgQVJSQVlfU0laRSh0aW1lcykpOwogIHNldF90aW1lcnMoKTsKfQoKSVNSKFRJTUVSMF9PVkZfdmVjdCkgewogIGlmICgrK292ZiA+PSBDTE9DS1NfUEVSX01TICogbXMpIHsKICAgIGFkdmFuY2Vfc3RhdGVzKCk7CiAgICBhZHZhbmNlX3RpbWVzKCk7CiAgICBydW5fc3RhdGVzKCk7CiAgfQp9CgpzdGF0aWMgdm9pZCBzZXRfaW9fcmVnaXN0ZXJzKHZvaWQpIHsKICBERFJBID0gMHhmZnU7CiAgRERSQiB8PSAweDBmdTsKfQoKc3RhdGljIHZvaWQgc2V0X2ludGVycnVwdF9yZWdpc3RlcnModm9pZCkgewogIFRJTVNLIHw9IF9CVihUT0lFMCk7CiAgc2VpKCk7Cn0KCnN0YXRpYyB2b2lkIHNldF9zdGFydF9zdGF0ZSh2b2lkKSB7CiAgcnVuX3N0YXRlcygpOwp9CgppbnQgbWFpbih2b2lkKSB7CiAgc2V0X2lvX3JlZ2lzdGVycygpOwogIHNldF9pbnRlcnJ1cHRfcmVnaXN0ZXJzKCk7CiAgc2V0X3N0YXJ0X3N0YXRlKCk7CiAgc2V0X3RpbWVycygpOwogIHNldF9zbGVlcF9tb2RlKFNMRUVQX01PREVfSURMRSk7CiAgZm9yICg7OykgewogICAgc2xlZXBfbW9kZSgpOwogIH0KICByZXR1cm4gMDsKfQo=