#include <avr/interrupt.h>
#include <avr/io.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
};
static const size_t ticks_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 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_states(void) {
for (size_t i = 0u; i < ARRAY_SIZE(current_states); ++i) {
if (current_states[i] != ARRAY_SIZE(current_states) - 1u) {
++current_states[i];
} else {
current_states[i] = 0u;
}
}
}
static void advance_times(void) {
if (times_index != ARRAY_SIZE(times) - 1) {
++times_index;
} else {
times_index = 0u;
}
ms = times[times_index];
TCNT0 = TCNT0_START;
ovf = 0u;
}
ISR(TIMER0_OVF_vect) {
if (++ovf >= ticks_per_ms * ms) {
advance_states();
advance_times();
run_states();
}
}
static void initialize_io_registers(void) {
DDRA = 0xffu;
DDRB |= _BV(PB0) | _BV(PB1) | _BV(PB2) | _BV(PB3);
}
static void initialize_interrupt_registers(void) {
TIMSK |= (_BV(TOIE0));
sei();
}
static void initialize_start_state(void) {
run_states();
ms = times[times_index];
TCCR0 |= (_BV(CS01));
TCNT0 = TCNT0_START;
}
int main(void) {
initialize_io_registers();
initialize_interrupt_registers();
initialize_start_state();
for (;;);
return 0;
}
I2luY2x1ZGUgPGF2ci9pbnRlcnJ1cHQuaD4KI2luY2x1ZGUgPGF2ci9pby5oPgoKI2luY2x1ZGUgPHN0ZGRlZi5oPgojaW5jbHVkZSA8c3RkaW50Lmg+CgojZGVmaW5lIEFSUkFZX1NJWkUoYSkgKHNpemVvZiAoYSkgLyBzaXplb2YgKCphKSkKCnN0YXRpYyBjb25zdCBzdHJ1Y3QgdHJhZmZpY19saWdodCB7CiAgc3RydWN0IHRyYWZmaWNfbGlnaHRfbGVkIHsKICAgIHZvbGF0aWxlIHVpbnQ4X3QgKnBvcnQ7CiAgICB1aW50OF90IHBpbjsKICB9IHJlZCwgYW1iZXIsIGdyZWVuOwp9IHRyYWZmaWNfbGlnaHRzW10gPSB7CiAgLyogTm9ydGggdHJhZmZpYyBsaWdodHMgKi8KICB7CiAgICB7JlBPUlRBLCBQQTB9LAogICAgeyZQT1JUQSwgUEExfSwKICAgIHsmUE9SVEEsIFBBMn0KICB9LAogIC8qIFNvdXRoIHRyYWZmaWMgbGlnaHRzICovCiAgewogICAgeyZQT1JUQSwgUEEzfSwKICAgIHsmUE9SVEEsIFBBNH0sCiAgICB7JlBPUlRBLCBQQTV9CiAgfSwKICAvKiBFYXN0IHRyYWZmaWMgbGlnaHRzICovCiAgewogICAgeyZQT1JUQSwgUEE2fSwKICAgIHsmUE9SVEEsIFBBN30sCiAgICB7JlBPUlRCLCBQQjB9CiAgfSwKICAvKiBXZXN0IHRyYWZmaWMgbGlnaHRzICovCiAgewogICAgeyZQT1JUQiwgUEIxfSwKICAgIHsmUE9SVEIsIFBCMn0sCiAgICB7JlBPUlRCLCBQQjN9CiAgfSwKfTsKCnN0YXRpYyB2b2lkIHNldF90cmFmZmljX2xpZ2h0X2xlZChjb25zdCBzdHJ1Y3QgdHJhZmZpY19saWdodF9sZWQgKmxlZCkgewogICoobGVkLT5wb3J0KSB8PSBfQlYobGVkLT5waW4pOwp9CgpzdGF0aWMgdm9pZCByZXNldF90cmFmZmljX2xpZ2h0X2xlZChjb25zdCBzdHJ1Y3QgdHJhZmZpY19saWdodF9sZWQgKmxlZCkgewogICoobGVkLT5wb3J0KSAmPSB+KF9CVihsZWQtPnBpbikpOwp9CgpzdGF0aWMgdm9pZCBzZXRfdHJhZmZpY19saWdodF9ncmVlbihjb25zdCBzdHJ1Y3QgdHJhZmZpY19saWdodCAqbGlnaHQpIHsKICBzZXRfdHJhZmZpY19saWdodF9sZWQoJmxpZ2h0LT5ncmVlbik7CiAgcmVzZXRfdHJhZmZpY19saWdodF9sZWQoJmxpZ2h0LT5hbWJlcik7CiAgcmVzZXRfdHJhZmZpY19saWdodF9sZWQoJmxpZ2h0LT5yZWQpOwp9CgpzdGF0aWMgdm9pZCBzZXRfdHJhZmZpY19saWdodF9hbWJlcihjb25zdCBzdHJ1Y3QgdHJhZmZpY19saWdodCAqbGlnaHQpIHsKICByZXNldF90cmFmZmljX2xpZ2h0X2xlZCgmbGlnaHQtPmdyZWVuKTsKICBzZXRfdHJhZmZpY19saWdodF9sZWQoJmxpZ2h0LT5hbWJlcik7CiAgcmVzZXRfdHJhZmZpY19saWdodF9sZWQoJmxpZ2h0LT5yZWQpOwp9CgpzdGF0aWMgdm9pZCBzZXRfdHJhZmZpY19saWdodF9yZWQoY29uc3Qgc3RydWN0IHRyYWZmaWNfbGlnaHQgKmxpZ2h0KSB7CiAgcmVzZXRfdHJhZmZpY19saWdodF9sZWQoJmxpZ2h0LT5ncmVlbik7CiAgcmVzZXRfdHJhZmZpY19saWdodF9sZWQoJmxpZ2h0LT5hbWJlcik7CiAgc2V0X3RyYWZmaWNfbGlnaHRfbGVkKCZsaWdodC0+cmVkKTsKfQoKc3RhdGljIHZvaWQgcmVzZXRfdHJhZmZpY19saWdodChjb25zdCBzdHJ1Y3QgdHJhZmZpY19saWdodCAqbGlnaHQpIHsKICByZXNldF90cmFmZmljX2xpZ2h0X2xlZCgmbGlnaHQtPmdyZWVuKTsKICByZXNldF90cmFmZmljX2xpZ2h0X2xlZCgmbGlnaHQtPmFtYmVyKTsKICByZXNldF90cmFmZmljX2xpZ2h0X2xlZCgmbGlnaHQtPnJlZCk7Cn0KCnR5cGVkZWYgdm9pZCAob3V0cHV0X3N0YXRlKShjb25zdCBzdHJ1Y3QgdHJhZmZpY19saWdodCAqKTsKCiNkZWZpbmUgc19vZmYgICAgJnJlc2V0X3RyYWZmaWNfbGlnaHQKI2RlZmluZSBzX2dyZWVuICAmc2V0X3RyYWZmaWNfbGlnaHRfZ3JlZW4KI2RlZmluZSBzX2FtYmVyICAmc2V0X3RyYWZmaWNfbGlnaHRfYW1iZXIKI2RlZmluZSBzX3JlZCAgICAmc2V0X3RyYWZmaWNfbGlnaHRfcmVkCgpzdGF0aWMgb3V0cHV0X3N0YXRlICogY29uc3Qgb3V0cHV0X3N0YXRlc1tdID0gewogIHNfZ3JlZW4sIHNfb2ZmLCBzX2dyZWVuLCBzX29mZiwgc19ncmVlbiwgc19vZmYsIHNfZ3JlZW4sIHNfb2ZmLCBzX2FtYmVyLAogIHNfcmVkLCAgIHNfcmVkLCBzX3JlZCwgICBzX3JlZCwgc19yZWQsICAgc19yZWQsIHNfcmVkLCAgIHNfcmVkLCBzX3JlZCwKICBzX3JlZCwgICBzX3JlZCwgc19yZWQsICAgc19yZWQsIHNfcmVkLCAgIHNfcmVkLCBzX3JlZCwgICBzX3JlZCwgc19yZWQsCiAgc19yZWQsICAgc19yZWQsIHNfcmVkLCAgIHNfcmVkLCBzX3JlZCwgICBzX3JlZCwgc19yZWQsICAgc19yZWQsIHNfcmVkCn07CgplbnVtIHsKICBUQ05UMF9NQVggPSAyNTB1LAogIFRDTlQwX1NUQVJUID0gMjU2dSAtIFRDTlQwX01BWCwKICBQUkVTQ0FMRVIgPSA4dQp9OwoKc3RhdGljIGNvbnN0IHNpemVfdCB0aWNrc19wZXJfbXMgPSBGX0NQVSAvIFBSRVNDQUxFUiAvIFRDTlQwX01BWCAvIDEwMDB1OwpzdGF0aWMgdm9sYXRpbGUgc2l6ZV90IG92ZiA9IDA7CgovKiBTdGF0ZSB0cmFuc2l0aW9uIHRpbWVzIGluIG1pbGxpc2Vjb25kcyAqLwplbnVtIHsKICBHUkVFTl9NUyA9IDEwMDAwdSwKICBCTElOS19NUyA9IDUwMHUsCiAgQU1CRVJfTVMgPSAzMDAwdQp9OwoKLyogSW5kaWNlcyBpbiB0aGUgc3RhdGVzIHZlY3RvciAqLwplbnVtIHsKICBOT1JUSF9UUkFGRklDX0xJR0hUU19TVEFSVF9TVEFURSA9IDB1LAogIFNPVVRIX1RSQUZGSUNfTElHSFRTX1NUQVJUX1NUQVRFID0gMjd1LAogIEVBU1RfVFJBRkZJQ19MSUdIVFNfU1RBUlRfU1RBVEUgID0gMTh1LAogIFdFU1RfVFJBRkZJQ19MSUdIVFNfU1RBUlRfU1RBVEUgID0gOXUsCn07CgpzdGF0aWMgY29uc3Qgc2l6ZV90IHRpbWVzW10gPSB7CiAgR1JFRU5fTVMsIEJMSU5LX01TLCBCTElOS19NUywKICBCTElOS19NUywgQkxJTktfTVMsIEJMSU5LX01TLAogIEJMSU5LX01TLCBCTElOS19NUywgQU1CRVJfTVMKfTsKCnN0YXRpYyB2b2xhdGlsZSBzaXplX3QgdGltZXNfaW5kZXggPSAwdTsKc3RhdGljIHZvbGF0aWxlIHNpemVfdCBtcyA9IDUwMDB1OwoKc3RhdGljIHZvbGF0aWxlIHNpemVfdCBjdXJyZW50X3N0YXRlc1tdID0gewogIE5PUlRIX1RSQUZGSUNfTElHSFRTX1NUQVJUX1NUQVRFLAogIFNPVVRIX1RSQUZGSUNfTElHSFRTX1NUQVJUX1NUQVRFLAogIEVBU1RfVFJBRkZJQ19MSUdIVFNfU1RBUlRfU1RBVEUsCiAgV0VTVF9UUkFGRklDX0xJR0hUU19TVEFSVF9TVEFURQp9OwoKc3RhdGljIHZvaWQgcnVuX3N0YXRlcyh2b2lkKSB7CiAgZm9yIChzaXplX3QgaSA9IDB1OyBpIDwgQVJSQVlfU0laRShjdXJyZW50X3N0YXRlcyk7ICsraSkgewogICAgb3V0cHV0X3N0YXRlc1tjdXJyZW50X3N0YXRlc1tpXV0oJnRyYWZmaWNfbGlnaHRzW2ldKTsKICB9Cn0KCnN0YXRpYyB2b2lkIGFkdmFuY2Vfc3RhdGVzKHZvaWQpIHsKICBmb3IgKHNpemVfdCBpID0gMHU7IGkgPCBBUlJBWV9TSVpFKGN1cnJlbnRfc3RhdGVzKTsgKytpKSB7CiAgICBpZiAoY3VycmVudF9zdGF0ZXNbaV0gIT0gQVJSQVlfU0laRShjdXJyZW50X3N0YXRlcykgLSAxdSkgewogICAgICArK2N1cnJlbnRfc3RhdGVzW2ldOwogICAgfSBlbHNlIHsKICAgICAgY3VycmVudF9zdGF0ZXNbaV0gPSAwdTsKICAgIH0KICB9Cn0KCnN0YXRpYyB2b2lkIGFkdmFuY2VfdGltZXModm9pZCkgewogIGlmICh0aW1lc19pbmRleCAhPSBBUlJBWV9TSVpFKHRpbWVzKSAtIDEpIHsKICAgICsrdGltZXNfaW5kZXg7CiAgfSBlbHNlIHsKICAgIHRpbWVzX2luZGV4ID0gMHU7CiAgfQogIG1zID0gdGltZXNbdGltZXNfaW5kZXhdOwogIFRDTlQwID0gVENOVDBfU1RBUlQ7CiAgb3ZmID0gMHU7Cn0KCklTUihUSU1FUjBfT1ZGX3ZlY3QpIHsKICBpZiAoKytvdmYgPj0gdGlja3NfcGVyX21zICogbXMpIHsKICAgIGFkdmFuY2Vfc3RhdGVzKCk7CiAgICBhZHZhbmNlX3RpbWVzKCk7CiAgICBydW5fc3RhdGVzKCk7CiAgfQp9CgpzdGF0aWMgdm9pZCBpbml0aWFsaXplX2lvX3JlZ2lzdGVycyh2b2lkKSB7CiAgRERSQSA9IDB4ZmZ1OwogIEREUkIgfD0gX0JWKFBCMCkgfCBfQlYoUEIxKSB8IF9CVihQQjIpIHwgX0JWKFBCMyk7Cn0KCnN0YXRpYyB2b2lkIGluaXRpYWxpemVfaW50ZXJydXB0X3JlZ2lzdGVycyh2b2lkKSB7CiAgVElNU0sgfD0gKF9CVihUT0lFMCkpOwogIHNlaSgpOwp9CgpzdGF0aWMgdm9pZCBpbml0aWFsaXplX3N0YXJ0X3N0YXRlKHZvaWQpIHsKICBydW5fc3RhdGVzKCk7CiAgbXMgPSB0aW1lc1t0aW1lc19pbmRleF07CiAgVENDUjAgfD0gKF9CVihDUzAxKSk7CiAgVENOVDAgPSBUQ05UMF9TVEFSVDsKfQoKaW50IG1haW4odm9pZCkgewogIGluaXRpYWxpemVfaW9fcmVnaXN0ZXJzKCk7CiAgaW5pdGlhbGl6ZV9pbnRlcnJ1cHRfcmVnaXN0ZXJzKCk7CiAgaW5pdGlhbGl6ZV9zdGFydF9zdGF0ZSgpOwogIGZvciAoOzspOwogIHJldHVybiAwOwp9Cg==