#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 = UINT8_MAX - TCNT0_MAX,
TIMER0_PRESCALER = 8u,
TIMER0_CLOCKS_PER_MS = F_CPU / TIMER0_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 >= TIMER0_CLOCKS_PER_MS * ms) {
advance_states();
advance_times();
run_states();
}
TCNT0 = TCNT0_START;
}
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+CiNpbmNsdWRlIDxzdGRpbnQuaD4KCiNkZWZpbmUgQVJSQVlfU0laRShhKSAoc2l6ZW9mIChhKSAvIHNpemVvZiAqKGEpKQoKc3RhdGljIGNvbnN0IHN0cnVjdCB0cmFmZmljX2xpZ2h0IHsKICBzdHJ1Y3QgdHJhZmZpY19saWdodF9sZWQgewogICAgdm9sYXRpbGUgdWludDhfdCAqcG9ydDsKICAgIHVpbnQ4X3QgcGluOwogIH0gcmVkLCBhbWJlciwgZ3JlZW47Cn0gdHJhZmZpY19saWdodHNbXSA9IHsKICAvKiBOb3J0aCB0cmFmZmljIGxpZ2h0cyAqLwogIHsKICAgIHsmUE9SVEEsIF9CVihQQTApfSwKICAgIHsmUE9SVEEsIF9CVihQQTEpfSwKICAgIHsmUE9SVEEsIF9CVihQQTIpfQogIH0sCiAgLyogU291dGggdHJhZmZpYyBsaWdodHMgKi8KICB7CiAgICB7JlBPUlRBLCBfQlYoUEEzKX0sCiAgICB7JlBPUlRBLCBfQlYoUEE0KX0sCiAgICB7JlBPUlRBLCBfQlYoUEE1KX0KICB9LAogIC8qIEVhc3QgdHJhZmZpYyBsaWdodHMgKi8KICB7CiAgICB7JlBPUlRBLCBfQlYoUEE2KX0sCiAgICB7JlBPUlRBLCBfQlYoUEE3KX0sCiAgICB7JlBPUlRCLCBfQlYoUEIwKX0KICB9LAogIC8qIFdlc3QgdHJhZmZpYyBsaWdodHMgKi8KICB7CiAgICB7JlBPUlRCLCBfQlYoUEIxKX0sCiAgICB7JlBPUlRCLCBfQlYoUEIyKX0sCiAgICB7JlBPUlRCLCBfQlYoUEIzKX0KICB9LAp9OwoKc3RhdGljIHZvaWQgc2V0X3RyYWZmaWNfbGlnaHRfbGVkKGNvbnN0IHN0cnVjdCB0cmFmZmljX2xpZ2h0X2xlZCAqbGVkKSB7CiAgKihsZWQtPnBvcnQpIHw9IGxlZC0+cGluOwp9CgpzdGF0aWMgdm9pZCByZXNldF90cmFmZmljX2xpZ2h0X2xlZChjb25zdCBzdHJ1Y3QgdHJhZmZpY19saWdodF9sZWQgKmxlZCkgewogICoobGVkLT5wb3J0KSAmPSB+KGxlZC0+cGluKTsKfQoKc3RhdGljIHZvaWQgc2V0X3RyYWZmaWNfbGlnaHRfZ3JlZW4oY29uc3Qgc3RydWN0IHRyYWZmaWNfbGlnaHQgKmxpZ2h0KSB7CiAgc2V0X3RyYWZmaWNfbGlnaHRfbGVkKCZsaWdodC0+Z3JlZW4pOwogIHJlc2V0X3RyYWZmaWNfbGlnaHRfbGVkKCZsaWdodC0+YW1iZXIpOwogIHJlc2V0X3RyYWZmaWNfbGlnaHRfbGVkKCZsaWdodC0+cmVkKTsKfQoKc3RhdGljIHZvaWQgc2V0X3RyYWZmaWNfbGlnaHRfYW1iZXIoY29uc3Qgc3RydWN0IHRyYWZmaWNfbGlnaHQgKmxpZ2h0KSB7CiAgcmVzZXRfdHJhZmZpY19saWdodF9sZWQoJmxpZ2h0LT5ncmVlbik7CiAgc2V0X3RyYWZmaWNfbGlnaHRfbGVkKCZsaWdodC0+YW1iZXIpOwogIHJlc2V0X3RyYWZmaWNfbGlnaHRfbGVkKCZsaWdodC0+cmVkKTsKfQoKc3RhdGljIHZvaWQgc2V0X3RyYWZmaWNfbGlnaHRfcmVkKGNvbnN0IHN0cnVjdCB0cmFmZmljX2xpZ2h0ICpsaWdodCkgewogIHJlc2V0X3RyYWZmaWNfbGlnaHRfbGVkKCZsaWdodC0+Z3JlZW4pOwogIHJlc2V0X3RyYWZmaWNfbGlnaHRfbGVkKCZsaWdodC0+YW1iZXIpOwogIHNldF90cmFmZmljX2xpZ2h0X2xlZCgmbGlnaHQtPnJlZCk7Cn0KCnN0YXRpYyB2b2lkIHJlc2V0X3RyYWZmaWNfbGlnaHQoY29uc3Qgc3RydWN0IHRyYWZmaWNfbGlnaHQgKmxpZ2h0KSB7CiAgcmVzZXRfdHJhZmZpY19saWdodF9sZWQoJmxpZ2h0LT5ncmVlbik7CiAgcmVzZXRfdHJhZmZpY19saWdodF9sZWQoJmxpZ2h0LT5hbWJlcik7CiAgcmVzZXRfdHJhZmZpY19saWdodF9sZWQoJmxpZ2h0LT5yZWQpOwp9Cgp0eXBlZGVmIHZvaWQgKG91dHB1dF9zdGF0ZSkoY29uc3Qgc3RydWN0IHRyYWZmaWNfbGlnaHQgKik7CgojZGVmaW5lIHNfb2ZmICAgJnJlc2V0X3RyYWZmaWNfbGlnaHQKI2RlZmluZSBzX2dyZWVuICZzZXRfdHJhZmZpY19saWdodF9ncmVlbgojZGVmaW5lIHNfYW1iZXIgJnNldF90cmFmZmljX2xpZ2h0X2FtYmVyCiNkZWZpbmUgc19yZWQgICAmc2V0X3RyYWZmaWNfbGlnaHRfcmVkCgpzdGF0aWMgb3V0cHV0X3N0YXRlICogY29uc3Qgb3V0cHV0X3N0YXRlc1tdID0gewogIHNfZ3JlZW4sIHNfb2ZmLCBzX2dyZWVuLCBzX29mZiwgc19ncmVlbiwgc19vZmYsIHNfZ3JlZW4sIHNfb2ZmLCBzX2FtYmVyLAogIHNfcmVkLCAgIHNfcmVkLCBzX3JlZCwgICBzX3JlZCwgc19yZWQsICAgc19yZWQsIHNfcmVkLCAgIHNfcmVkLCBzX3JlZCwKICBzX3JlZCwgICBzX3JlZCwgc19yZWQsICAgc19yZWQsIHNfcmVkLCAgIHNfcmVkLCBzX3JlZCwgICBzX3JlZCwgc19yZWQsCiAgc19yZWQsICAgc19yZWQsIHNfcmVkLCAgIHNfcmVkLCBzX3JlZCwgICBzX3JlZCwgc19yZWQsICAgc19yZWQsIHNfcmVkCn07CgplbnVtIHsKICBUQ05UMF9NQVggPSAyNTB1LAogIFRDTlQwX1NUQVJUID0gVUlOVDhfTUFYIC0gVENOVDBfTUFYLAogIFRJTUVSMF9QUkVTQ0FMRVIgPSA4dSwKICBUSU1FUjBfQ0xPQ0tTX1BFUl9NUyA9IEZfQ1BVIC8gVElNRVIwX1BSRVNDQUxFUiAvIFRDTlQwX01BWCAvIDEwMDB1Cn07CgpzdGF0aWMgdm9sYXRpbGUgc2l6ZV90IG92ZiA9IDA7CgovKiBTdGF0ZSB0cmFuc2l0aW9uIHRpbWVzIGluIG1pbGxpc2Vjb25kcyAqLwplbnVtIHsKICBHUkVFTl9NUyA9IDEwMDAwdSwKICBCTElOS19NUyA9IDUwMHUsCiAgQU1CRVJfTVMgPSAzMDAwdQp9OwogIApzdGF0aWMgY29uc3Qgc2l6ZV90IHRpbWVzW10gPSB7CiAgR1JFRU5fTVMsIEJMSU5LX01TLCBCTElOS19NUywKICBCTElOS19NUywgQkxJTktfTVMsIEJMSU5LX01TLAogIEJMSU5LX01TLCBCTElOS19NUywgQU1CRVJfTVMKfTsKCnN0YXRpYyB2b2xhdGlsZSBzaXplX3QgdGltZXNfaW5kZXggPSAwdTsKc3RhdGljIHZvbGF0aWxlIHNpemVfdCBtcyA9IDUwMDB1OwoKc3RhdGljIHZvaWQgc2V0X3RpbWVycyh2b2lkKSB7CiAgbXMgPSB0aW1lc1t0aW1lc19pbmRleF07CiAgVENDUjAgfD0gX0JWKENTMDEpOwogIFRDTlQwID0gVENOVDBfU1RBUlQ7CiAgb3ZmID0gMHU7Cn0KCi8qIEluZGljZXMgaW4gdGhlIHN0YXRlcyB2ZWN0b3IgKi8Kc3RhdGljIHZvbGF0aWxlIHNpemVfdCBjdXJyZW50X3N0YXRlc1tdID0gewogIDB1LCAgLyogTm9ydGggVHJhZmZpYyBMaWdodCBTdGFydCBTdGF0ZSAqLwogIDI3dSwgLyogU291dGggVHJhZmZpYyBMaWdodCBTdGFydCBTdGF0ZSAqLwogIDE4dSwgLyogRWFzdCBUcmFmZmljIExpZ2h0IFN0YXJ0IFN0YXRlICovCiAgOXUgICAvKiBOb3J0aCBUcmFmZmljIExpZ2h0IFN0YXJ0IFN0YXRlICovCn07CgpzdGF0aWMgdm9pZCBydW5fc3RhdGVzKHZvaWQpIHsKICBmb3IgKHNpemVfdCBpID0gMHU7IGkgPCBBUlJBWV9TSVpFKGN1cnJlbnRfc3RhdGVzKTsgKytpKSB7CiAgICBvdXRwdXRfc3RhdGVzW2N1cnJlbnRfc3RhdGVzW2ldXSh0cmFmZmljX2xpZ2h0cyArIGkpOwogIH0KfQoKc3RhdGljIHZvaWQgYWR2YW5jZSh2b2xhdGlsZSBzaXplX3QgKmluZGV4LCBzaXplX3Qgc2l6ZSkgewogICsrKmluZGV4OwogICppbmRleCAlPSBzaXplOwp9CgpzdGF0aWMgdm9pZCBhZHZhbmNlX3N0YXRlcyh2b2lkKSB7CiAgZm9yIChzaXplX3QgaSA9IDB1OyBpIDwgQVJSQVlfU0laRShjdXJyZW50X3N0YXRlcyk7ICsraSkgewogICAgYWR2YW5jZShjdXJyZW50X3N0YXRlcyArIGksIEFSUkFZX1NJWkUob3V0cHV0X3N0YXRlcykpOwogIH0KfQoKc3RhdGljIHZvaWQgYWR2YW5jZV90aW1lcyh2b2lkKSB7CiAgYWR2YW5jZSgmdGltZXNfaW5kZXgsIEFSUkFZX1NJWkUodGltZXMpKTsKICBzZXRfdGltZXJzKCk7Cn0KCklTUihUSU1FUjBfT1ZGX3ZlY3QpIHsKICBpZiAoKytvdmYgPj0gVElNRVIwX0NMT0NLU19QRVJfTVMgKiBtcykgewogICAgYWR2YW5jZV9zdGF0ZXMoKTsKICAgIGFkdmFuY2VfdGltZXMoKTsKICAgIHJ1bl9zdGF0ZXMoKTsKICB9CiAgVENOVDAgPSBUQ05UMF9TVEFSVDsKfQoKc3RhdGljIHZvaWQgc2V0X2lvX3JlZ2lzdGVycyh2b2lkKSB7CiAgRERSQSA9IDB4ZmZ1OwogIEREUkIgfD0gMHgwZnU7Cn0KCnN0YXRpYyB2b2lkIHNldF9pbnRlcnJ1cHRfcmVnaXN0ZXJzKHZvaWQpIHsKICBUSU1TSyB8PSBfQlYoVE9JRTApOwogIHNlaSgpOwp9CgpzdGF0aWMgdm9pZCBzZXRfc3RhcnRfc3RhdGUodm9pZCkgewogIHJ1bl9zdGF0ZXMoKTsKfQoKaW50IG1haW4odm9pZCkgewogIHNldF9pb19yZWdpc3RlcnMoKTsKICBzZXRfaW50ZXJydXB0X3JlZ2lzdGVycygpOwogIHNldF9zdGFydF9zdGF0ZSgpOwogIHNldF90aW1lcnMoKTsKICBzZXRfc2xlZXBfbW9kZShTTEVFUF9NT0RFX0lETEUpOwogIGZvciAoOzspIHsKICAgIHNsZWVwX21vZGUoKTsKICB9CiAgcmV0dXJuIDA7Cn0K