|
- // Copyright 2012 Olivier Gillet.
- //
- // Author: Olivier Gillet (ol.gillet@gmail.com)
- //
- // This program is free software: you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- // You should have received a copy of the GNU General Public License
- // along with this program. If not, see <http://www.gnu.org/licenses/>.
-
- #include <avr/eeprom.h>
- #include <avr/pgmspace.h>
-
- #include "avrlib/adc.h"
- #include "avrlib/boot.h"
- #include "avrlib/gpio.h"
- #include "avrlib/watchdog_timer.h"
-
- using namespace avrlib;
-
- enum LedState {
- LED_STATE_OFF,
- LED_STATE_RED,
- LED_STATE_GREEN
- };
-
- Gpio<PortD, 4> in_1;
- Gpio<PortD, 3> out_1_a;
- Gpio<PortD, 0> out_1_b;
- Gpio<PortD, 1> led_1_a;
- Gpio<PortD, 2> led_1_k;
-
- Gpio<PortD, 7> in_2;
- Gpio<PortD, 6> out_2_a;
- Gpio<PortD, 5> out_2_b;
- Gpio<PortB, 1> led_2_a;
- Gpio<PortB, 0> led_2_k;
-
- Gpio<PortC, 2> switch_2;
- Gpio<PortC, 3> switch_1;
-
- Adc adc;
-
- const uint16_t kLongPressTime = 6250; // 800 * 8000 / 1024
- const uint16_t kLedGateDelay = 0x1ff;
-
- static uint8_t adc_channel;
- static uint16_t p[2];
-
- bool toggle_mode[2];
- bool latch_mode[2];
-
- bool input_state[2];
- bool previous_state[2];
-
- bool switch_state[2];
- bool inhibit_switch[2];
- uint16_t press_time[2];
-
- uint8_t led_state[2];
- uint16_t led_gate_delay[2];
-
- uint32_t rng_state;
-
- const prog_uint16_t linear_table[] PROGMEM = {
- 0, 0, 259, 518, 777, 1036, 1295, 1554,
- 1813, 2072, 2331, 2590, 2849, 3108, 3367, 3626,
- 3885, 4145, 4404, 4663, 4922, 5181, 5440, 5699,
- 5958, 6217, 6476, 6735, 6994, 7253, 7512, 7771,
- 8030, 8289, 8548, 8807, 9066, 9325, 9584, 9843,
- 10102, 10361, 10620, 10879, 11138, 11397, 11656, 11915,
- 12174, 12434, 12693, 12952, 13211, 13470, 13729, 13988,
- 14247, 14506, 14765, 15024, 15283, 15542, 15801, 16060,
- 16319, 16578, 16837, 17096, 17355, 17614, 17873, 18132,
- 18391, 18650, 18909, 19168, 19427, 19686, 19945, 20204,
- 20463, 20723, 20982, 21241, 21500, 21759, 22018, 22277,
- 22536, 22795, 23054, 23313, 23572, 23831, 24090, 24349,
- 24608, 24867, 25126, 25385, 25644, 25903, 26162, 26421,
- 26680, 26939, 27198, 27457, 27716, 27975, 28234, 28493,
- 28753, 29012, 29271, 29530, 29789, 30048, 30307, 30566,
- 30825, 31084, 31343, 31602, 31861, 32120, 32379, 32638,
- 32897, 33156, 33415, 33674, 33933, 34192, 34451, 34710,
- 34969, 35228, 35487, 35746, 36005, 36264, 36523, 36782,
- 37042, 37301, 37560, 37819, 38078, 38337, 38596, 38855,
- 39114, 39373, 39632, 39891, 40150, 40409, 40668, 40927,
- 41186, 41445, 41704, 41963, 42222, 42481, 42740, 42999,
- 43258, 43517, 43776, 44035, 44294, 44553, 44812, 45072,
- 45331, 45590, 45849, 46108, 46367, 46626, 46885, 47144,
- 47403, 47662, 47921, 48180, 48439, 48698, 48957, 49216,
- 49475, 49734, 49993, 50252, 50511, 50770, 51029, 51288,
- 51547, 51806, 52065, 52324, 52583, 52842, 53101, 53361,
- 53620, 53879, 54138, 54397, 54656, 54915, 55174, 55433,
- 55692, 55951, 56210, 56469, 56728, 56987, 57246, 57505,
- 57764, 58023, 58282, 58541, 58800, 59059, 59318, 59577,
- 59836, 60095, 60354, 60613, 60872, 61131, 61390, 61650,
- 61909, 62168, 62427, 62686, 62945, 63204, 63463, 63722,
- 63981, 64240, 64499, 64758, 65017, 65276, 65535, 65535,
- };
-
- void Init() {
- Gpio<PortB, 4>::set_mode(DIGITAL_OUTPUT);
- Gpio<PortB, 4>::Low();
-
- in_1.set_mode(DIGITAL_INPUT);
- in_2.set_mode(DIGITAL_INPUT);
- in_1.High();
- in_2.High();
-
- switch_1.set_mode(DIGITAL_INPUT);
- switch_2.set_mode(DIGITAL_INPUT);
- switch_1.High();
- switch_2.High();
-
- out_1_a.set_mode(DIGITAL_OUTPUT);
- out_1_b.set_mode(DIGITAL_OUTPUT);
- led_1_a.set_mode(DIGITAL_OUTPUT);
- led_1_k.set_mode(DIGITAL_OUTPUT);
-
- out_2_a.set_mode(DIGITAL_OUTPUT);
- out_2_b.set_mode(DIGITAL_OUTPUT);
- led_2_a.set_mode(DIGITAL_OUTPUT);
- led_2_k.set_mode(DIGITAL_OUTPUT);
-
- led_1_a.Low();
- led_2_a.Low();
- led_1_k.Low();
- led_2_k.Low();
-
- adc.Init();
- adc.set_reference(ADC_DEFAULT);
- adc.set_alignment(ADC_LEFT_ALIGNED);
- adc.StartConversion(0);
-
- uint8_t configuration_byte = ~eeprom_read_byte((uint8_t*) 0);
- toggle_mode[0] = configuration_byte & 1;
- latch_mode[0] = configuration_byte & 2;
- toggle_mode[1] = configuration_byte & 4;
- latch_mode[1] = configuration_byte & 8;
-
- led_state[0] = led_state[1] = 0;
- switch_state[0] = switch_state[1] = false;
-
- TCCR1A = 0;
- TCCR1B = 5;
- }
-
- bool Read(uint8_t channel) {
- return channel == 0 ? !in_1.value() : !in_2.value();
- }
-
- bool ReadSwitch(uint8_t channel) {
- return channel == 0 ? !switch_1.value() : !switch_2.value();
- }
-
- void GateOn(uint8_t channel, bool outcome) {
- if (channel == 0) {
- if (outcome) {
- out_1_a.Low();
- out_1_b.High();
- } else {
- out_1_a.High();
- out_1_b.Low();
- }
- } else {
- if (outcome) {
- out_2_a.Low();
- out_2_b.High();
- } else {
- out_2_a.High();
- out_2_b.Low();
- }
- }
- }
-
- void GateOff(uint8_t channel) {
- if (channel == 0) {
- out_1_a.Low();
- out_1_b.Low();
- } else {
- out_2_a.Low();
- out_2_b.Low();
- }
- }
-
- void LedOff(uint8_t channel) {
- if (channel == 0) {
- led_1_a.Low();
- led_1_k.Low();
- } else {
- led_2_a.Low();
- led_2_k.Low();
- }
- }
-
- void DisplayConfigurationAndSave(uint8_t channel) {
- uint8_t configuration_byte = 0;
- if (toggle_mode[0]) configuration_byte |= 1;
- if (latch_mode[0]) configuration_byte |= 2;
- if (toggle_mode[1]) configuration_byte |= 4;
- if (latch_mode[1]) configuration_byte |= 8;
- eeprom_write_byte((uint8_t*) 0, ~configuration_byte);
- }
-
- int main(void) {
- ResetWatchdog();
- Init();
-
- input_state[0] = input_state[1] = false;
- rng_state = 1;
- while (1) {
- // Whenever an ADC cycle is finished, update the probability variables.
- if (adc.ready()) {
- uint8_t channel_index = 1 - adc_channel; // ADC pins are swapped!
- p[channel_index] = pgm_read_word(linear_table + adc.ReadOut8());
- adc_channel = (adc_channel + 1) & 1;
- adc.StartConversion(adc_channel);
- }
-
- // Scan switches
- for (uint8_t i = 0; i < 2; ++i) {
- bool new_input_state = ReadSwitch(i);
- if (!switch_state[i] && new_input_state) {
- press_time[i] = TCNT1;
- inhibit_switch[i] = false;
- }
- if (switch_state[i] && !inhibit_switch[i]) {
- uint16_t this_press_time = TCNT1 - press_time[i];
- if (this_press_time >= kLongPressTime) {
- inhibit_switch[i] = true;
- latch_mode[i] = !latch_mode[i];
- DisplayConfigurationAndSave(i);
- } else if (this_press_time >= 64 && !new_input_state) {
- toggle_mode[i] = !toggle_mode[i];
- DisplayConfigurationAndSave(i);
- }
- }
- switch_state[i] = new_input_state;
- }
-
- // Scan inputs
- uint32_t random_words = rng_state;
- for (uint8_t i = 0; i < 2; ++i) {
- bool new_input_state = Read(i);
-
- if (new_input_state || latch_mode[i]) {
- // Hold the LED while the trigger is high or when in latch mode
- led_gate_delay[i] = kLedGateDelay;
- }
-
- if (new_input_state && !input_state[i] /* Rising edge */) {
- uint16_t random = random_words & 0xffff;
- uint16_t threshold = p[i];
- bool outcome = random >= threshold && threshold != 65535;
- if (toggle_mode[i]) {
- outcome = outcome ^ previous_state[i];
- }
- previous_state[i] = outcome;
- GateOn(i, outcome);
- led_state[i] = outcome ? 1 : 2;
- } else if (!new_input_state && input_state[i] && !latch_mode[i]) {
- GateOff(i);
- }
- input_state[i] = new_input_state;
- random_words >>= 16;
-
- if (led_gate_delay[i]) {
- --led_gate_delay[i];
- if (!led_gate_delay[i]) {
- led_state[i] = 0;
- }
- }
- }
-
- // Refresh LEDs
- if (led_state[0] == 0) {
- led_1_a.Low();
- led_1_k.Low();
- } else if (led_state[0] == 1) {
- led_1_a.Low();
- led_1_k.High();
- } else {
- led_1_a.High();
- led_1_k.Low();
- }
-
- if (led_state[1] == 0) {
- led_2_a.Low();
- led_2_k.Low();
- } else if (led_state[1] == 1) {
- led_2_a.Low();
- led_2_k.High();
- } else {
- led_2_a.High();
- led_2_k.Low();
- }
-
- // rng_state = rng_state * 1664525 + 1013904223;
- rng_state = (rng_state >> 1) ^ (-(rng_state & 1u) & 0xD0000001u);
- }
- }
|