#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, PA0},
{&PORTA, PA1},
{&PORTA, PA2}
},
/* South traffic lights */
{
{&PORTA, PA3},
{&PORTA, PA4},
{&PORTA, PA5}
},
/* East traffic lights */
{
{&PORTA, PA6},
{&PORTA, PA7},
{&PORTB, PB0}
},
/* West traffic lights */
{
{&PORTB, PB1},
{&PORTB, PB2},
{&PORTB, PB3}
},
};
static void set_traffic_light_led(const struct traffic_light_led *led) {
*(led->port) |= _BV(led->pin);
}
static void reset_traffic_light_led(const struct traffic_light_led *led) {
*(led->port) &= ~(_BV(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
};
/* Indices in the states vector */
enum {
NORTH_TRAFFIC_LIGHTS_START_STATE = 0u,
SOUTH_TRAFFIC_LIGHTS_START_STATE = 27u,
EAST_TRAFFIC_LIGHTS_START_STATE = 18u,
WEST_TRAFFIC_LIGHTS_START_STATE = 9u,
};
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;
}
static volatile size_t current_states[] = {
NORTH_TRAFFIC_LIGHTS_START_STATE,
SOUTH_TRAFFIC_LIGHTS_START_STATE,
EAST_TRAFFIC_LIGHTS_START_STATE,
WEST_TRAFFIC_LIGHTS_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 array_size) {
if (*index != array_size) {
++*index;
} else {
*index = 0;
}
}
static void advance_states(void) {
for (size_t i = 0u; i < ARRAY_SIZE(current_states); ++i) {
advance(current_states + i, ARRAY_SIZE(current_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 |= _BV(PB0) | _BV(PB1) | _BV(PB2) | _BV(PB3);
}
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+CiNpbmNsdWRlIDxzdGRpbnQuaD4KCiNkZWZpbmUgQVJSQVlfU0laRShhKSAoc2l6ZW9mIChhKSAvIHNpemVvZiAoKmEpKQoKc3RhdGljIGNvbnN0IHN0cnVjdCB0cmFmZmljX2xpZ2h0IHsKICBzdHJ1Y3QgdHJhZmZpY19saWdodF9sZWQgewogICAgdm9sYXRpbGUgdWludDhfdCAqcG9ydDsKICAgIHVpbnQ4X3QgcGluOwogIH0gcmVkLCBhbWJlciwgZ3JlZW47Cn0gdHJhZmZpY19saWdodHNbXSA9IHsKICAvKiBOb3J0aCB0cmFmZmljIGxpZ2h0cyAqLwogIHsKICAgIHsmUE9SVEEsIFBBMH0sCiAgICB7JlBPUlRBLCBQQTF9LAogICAgeyZQT1JUQSwgUEEyfQogIH0sCiAgLyogU291dGggdHJhZmZpYyBsaWdodHMgKi8KICB7CiAgICB7JlBPUlRBLCBQQTN9LAogICAgeyZQT1JUQSwgUEE0fSwKICAgIHsmUE9SVEEsIFBBNX0KICB9LAogIC8qIEVhc3QgdHJhZmZpYyBsaWdodHMgKi8KICB7CiAgICB7JlBPUlRBLCBQQTZ9LAogICAgeyZQT1JUQSwgUEE3fSwKICAgIHsmUE9SVEIsIFBCMH0KICB9LAogIC8qIFdlc3QgdHJhZmZpYyBsaWdodHMgKi8KICB7CiAgICB7JlBPUlRCLCBQQjF9LAogICAgeyZQT1JUQiwgUEIyfSwKICAgIHsmUE9SVEIsIFBCM30KICB9LAp9OwoKc3RhdGljIHZvaWQgc2V0X3RyYWZmaWNfbGlnaHRfbGVkKGNvbnN0IHN0cnVjdCB0cmFmZmljX2xpZ2h0X2xlZCAqbGVkKSB7CiAgKihsZWQtPnBvcnQpIHw9IF9CVihsZWQtPnBpbik7Cn0KCnN0YXRpYyB2b2lkIHJlc2V0X3RyYWZmaWNfbGlnaHRfbGVkKGNvbnN0IHN0cnVjdCB0cmFmZmljX2xpZ2h0X2xlZCAqbGVkKSB7CiAgKihsZWQtPnBvcnQpICY9IH4oX0JWKGxlZC0+cGluKSk7Cn0KCnN0YXRpYyB2b2lkIHNldF90cmFmZmljX2xpZ2h0X2dyZWVuKGNvbnN0IHN0cnVjdCB0cmFmZmljX2xpZ2h0ICpsaWdodCkgewogIHNldF90cmFmZmljX2xpZ2h0X2xlZCgmbGlnaHQtPmdyZWVuKTsKICByZXNldF90cmFmZmljX2xpZ2h0X2xlZCgmbGlnaHQtPmFtYmVyKTsKICByZXNldF90cmFmZmljX2xpZ2h0X2xlZCgmbGlnaHQtPnJlZCk7Cn0KCnN0YXRpYyB2b2lkIHNldF90cmFmZmljX2xpZ2h0X2FtYmVyKGNvbnN0IHN0cnVjdCB0cmFmZmljX2xpZ2h0ICpsaWdodCkgewogIHJlc2V0X3RyYWZmaWNfbGlnaHRfbGVkKCZsaWdodC0+Z3JlZW4pOwogIHNldF90cmFmZmljX2xpZ2h0X2xlZCgmbGlnaHQtPmFtYmVyKTsKICByZXNldF90cmFmZmljX2xpZ2h0X2xlZCgmbGlnaHQtPnJlZCk7Cn0KCnN0YXRpYyB2b2lkIHNldF90cmFmZmljX2xpZ2h0X3JlZChjb25zdCBzdHJ1Y3QgdHJhZmZpY19saWdodCAqbGlnaHQpIHsKICByZXNldF90cmFmZmljX2xpZ2h0X2xlZCgmbGlnaHQtPmdyZWVuKTsKICByZXNldF90cmFmZmljX2xpZ2h0X2xlZCgmbGlnaHQtPmFtYmVyKTsKICBzZXRfdHJhZmZpY19saWdodF9sZWQoJmxpZ2h0LT5yZWQpOwp9CgpzdGF0aWMgdm9pZCByZXNldF90cmFmZmljX2xpZ2h0KGNvbnN0IHN0cnVjdCB0cmFmZmljX2xpZ2h0ICpsaWdodCkgewogIHJlc2V0X3RyYWZmaWNfbGlnaHRfbGVkKCZsaWdodC0+Z3JlZW4pOwogIHJlc2V0X3RyYWZmaWNfbGlnaHRfbGVkKCZsaWdodC0+YW1iZXIpOwogIHJlc2V0X3RyYWZmaWNfbGlnaHRfbGVkKCZsaWdodC0+cmVkKTsKfQoKdHlwZWRlZiB2b2lkIChvdXRwdXRfc3RhdGUpKGNvbnN0IHN0cnVjdCB0cmFmZmljX2xpZ2h0ICopOwoKI2RlZmluZSBzX29mZiAgICZyZXNldF90cmFmZmljX2xpZ2h0CiNkZWZpbmUgc19ncmVlbiAmc2V0X3RyYWZmaWNfbGlnaHRfZ3JlZW4KI2RlZmluZSBzX2FtYmVyICZzZXRfdHJhZmZpY19saWdodF9hbWJlcgojZGVmaW5lIHNfcmVkICAgJnNldF90cmFmZmljX2xpZ2h0X3JlZAoKc3RhdGljIG91dHB1dF9zdGF0ZSAqIGNvbnN0IG91dHB1dF9zdGF0ZXNbXSA9IHsKICBzX2dyZWVuLCBzX29mZiwgc19ncmVlbiwgc19vZmYsIHNfZ3JlZW4sIHNfb2ZmLCBzX2dyZWVuLCBzX29mZiwgc19hbWJlciwKICBzX3JlZCwgICBzX3JlZCwgc19yZWQsICAgc19yZWQsIHNfcmVkLCAgIHNfcmVkLCBzX3JlZCwgICBzX3JlZCwgc19yZWQsCiAgc19yZWQsICAgc19yZWQsIHNfcmVkLCAgIHNfcmVkLCBzX3JlZCwgICBzX3JlZCwgc19yZWQsICAgc19yZWQsIHNfcmVkLAogIHNfcmVkLCAgIHNfcmVkLCBzX3JlZCwgICBzX3JlZCwgc19yZWQsICAgc19yZWQsIHNfcmVkLCAgIHNfcmVkLCBzX3JlZAp9OwoKZW51bSB7CiAgVENOVDBfTUFYICAgICA9IDI1MHUsCiAgVENOVDBfU1RBUlQgICA9IDI1NnUgLSBUQ05UMF9NQVgsCiAgUFJFU0NBTEVSICAgICA9IDh1LAogIENMT0NLU19QRVJfTVMgPSBGX0NQVSAvIFBSRVNDQUxFUiAvIFRDTlQwX01BWCAvIDEwMDB1Cn07CgpzdGF0aWMgdm9sYXRpbGUgc2l6ZV90IG92ZiA9IDA7CgovKiBTdGF0ZSB0cmFuc2l0aW9uIHRpbWVzIGluIG1pbGxpc2Vjb25kcyAqLwplbnVtIHsKICBHUkVFTl9NUyA9IDEwMDAwdSwKICBCTElOS19NUyA9IDUwMHUsCiAgQU1CRVJfTVMgPSAzMDAwdQp9OwoKLyogSW5kaWNlcyBpbiB0aGUgc3RhdGVzIHZlY3RvciAqLwplbnVtIHsKICBOT1JUSF9UUkFGRklDX0xJR0hUU19TVEFSVF9TVEFURSA9IDB1LAogIFNPVVRIX1RSQUZGSUNfTElHSFRTX1NUQVJUX1NUQVRFID0gMjd1LAogIEVBU1RfVFJBRkZJQ19MSUdIVFNfU1RBUlRfU1RBVEUgID0gMTh1LAogIFdFU1RfVFJBRkZJQ19MSUdIVFNfU1RBUlRfU1RBVEUgID0gOXUsCn07CgpzdGF0aWMgY29uc3Qgc2l6ZV90IHRpbWVzW10gPSB7CiAgR1JFRU5fTVMsIEJMSU5LX01TLCBCTElOS19NUywKICBCTElOS19NUywgQkxJTktfTVMsIEJMSU5LX01TLAogIEJMSU5LX01TLCBCTElOS19NUywgQU1CRVJfTVMKfTsKCnN0YXRpYyB2b2xhdGlsZSBzaXplX3QgdGltZXNfaW5kZXggPSAwdTsKc3RhdGljIHZvbGF0aWxlIHNpemVfdCBtcyA9IDUwMDB1OwoKc3RhdGljIHZvaWQgc2V0X3RpbWVycyh2b2lkKSB7CiAgbXMgPSB0aW1lc1t0aW1lc19pbmRleF07CiAgVENDUjAgfD0gKF9CVihDUzAxKSk7CiAgVENOVDAgPSBUQ05UMF9TVEFSVDsKICBvdmYgPSAwdTsKfQoKc3RhdGljIHZvbGF0aWxlIHNpemVfdCBjdXJyZW50X3N0YXRlc1tdID0gewogIE5PUlRIX1RSQUZGSUNfTElHSFRTX1NUQVJUX1NUQVRFLAogIFNPVVRIX1RSQUZGSUNfTElHSFRTX1NUQVJUX1NUQVRFLAogIEVBU1RfVFJBRkZJQ19MSUdIVFNfU1RBUlRfU1RBVEUsCiAgV0VTVF9UUkFGRklDX0xJR0hUU19TVEFSVF9TVEFURQp9OwoKc3RhdGljIHZvaWQgcnVuX3N0YXRlcyh2b2lkKSB7CiAgZm9yIChzaXplX3QgaSA9IDB1OyBpIDwgQVJSQVlfU0laRShjdXJyZW50X3N0YXRlcyk7ICsraSkgewogICAgb3V0cHV0X3N0YXRlc1tjdXJyZW50X3N0YXRlc1tpXV0odHJhZmZpY19saWdodHMgKyBpKTsKICB9Cn0KCnN0YXRpYyB2b2lkIGFkdmFuY2Uodm9sYXRpbGUgc2l6ZV90ICppbmRleCwgc2l6ZV90IGFycmF5X3NpemUpIHsKICBpZiAoKmluZGV4ICE9IGFycmF5X3NpemUpIHsKICAgICsrKmluZGV4OwogIH0gZWxzZSB7CiAgICAqaW5kZXggPSAwOwogIH0KfQoKc3RhdGljIHZvaWQgYWR2YW5jZV9zdGF0ZXModm9pZCkgewogIGZvciAoc2l6ZV90IGkgPSAwdTsgaSA8IEFSUkFZX1NJWkUoY3VycmVudF9zdGF0ZXMpOyArK2kpIHsKICAgIGFkdmFuY2UoY3VycmVudF9zdGF0ZXMgKyBpLCBBUlJBWV9TSVpFKGN1cnJlbnRfc3RhdGVzKSk7CiAgfQp9CgpzdGF0aWMgdm9pZCBhZHZhbmNlX3RpbWVzKHZvaWQpIHsKICBhZHZhbmNlKCZ0aW1lc19pbmRleCwgQVJSQVlfU0laRSh0aW1lcykpOwogIHNldF90aW1lcnMoKTsKfQoKSVNSKFRJTUVSMF9PVkZfdmVjdCkgewogIGlmICgrK292ZiA+PSBDTE9DS1NfUEVSX01TICogbXMpIHsKICAgIGFkdmFuY2Vfc3RhdGVzKCk7CiAgICBhZHZhbmNlX3RpbWVzKCk7CiAgICBydW5fc3RhdGVzKCk7CiAgfQp9CgpzdGF0aWMgdm9pZCBzZXRfaW9fcmVnaXN0ZXJzKHZvaWQpIHsKICBERFJBID0gMHhmZnU7CiAgRERSQiB8PSBfQlYoUEIwKSB8IF9CVihQQjEpIHwgX0JWKFBCMikgfCBfQlYoUEIzKTsKfQoKc3RhdGljIHZvaWQgc2V0X2ludGVycnVwdF9yZWdpc3RlcnModm9pZCkgewogIFRJTVNLIHw9IChfQlYoVE9JRTApKTsKICBzZWkoKTsKfQoKc3RhdGljIHZvaWQgc2V0X3N0YXJ0X3N0YXRlKHZvaWQpIHsKICBydW5fc3RhdGVzKCk7Cn0KCmludCBtYWluKHZvaWQpIHsKICBzZXRfaW9fcmVnaXN0ZXJzKCk7CiAgc2V0X2ludGVycnVwdF9yZWdpc3RlcnMoKTsKICBzZXRfc3RhcnRfc3RhdGUoKTsKICBzZXRfdGltZXJzKCk7CiAgc2V0X3NsZWVwX21vZGUoU0xFRVBfTU9ERV9JRExFKTsKICBmb3IgKDs7KSB7CiAgICBzbGVlcF9tb2RlKCk7CiAgfQogIHJldHVybiAwOwp9Cg==