You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

306 lines
8.5KB

  1. // Copyright 2012 Olivier Gillet.
  2. //
  3. // Author: Olivier Gillet (ol.gillet@gmail.com)
  4. //
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. #include <avr/eeprom.h>
  16. #include <avr/pgmspace.h>
  17. #include "avrlib/adc.h"
  18. #include "avrlib/boot.h"
  19. #include "avrlib/gpio.h"
  20. #include "avrlib/watchdog_timer.h"
  21. using namespace avrlib;
  22. enum LedState {
  23. LED_STATE_OFF,
  24. LED_STATE_RED,
  25. LED_STATE_GREEN
  26. };
  27. Gpio<PortD, 4> in_1;
  28. Gpio<PortD, 3> out_1_a;
  29. Gpio<PortD, 0> out_1_b;
  30. Gpio<PortD, 1> led_1_a;
  31. Gpio<PortD, 2> led_1_k;
  32. Gpio<PortD, 7> in_2;
  33. Gpio<PortD, 6> out_2_a;
  34. Gpio<PortD, 5> out_2_b;
  35. Gpio<PortB, 1> led_2_a;
  36. Gpio<PortB, 0> led_2_k;
  37. Gpio<PortC, 2> switch_2;
  38. Gpio<PortC, 3> switch_1;
  39. Adc adc;
  40. const uint16_t kLongPressTime = 6250; // 800 * 8000 / 1024
  41. const uint16_t kLedGateDelay = 0x1ff;
  42. static uint8_t adc_channel;
  43. static uint16_t p[2];
  44. bool toggle_mode[2];
  45. bool latch_mode[2];
  46. bool input_state[2];
  47. bool previous_state[2];
  48. bool switch_state[2];
  49. bool inhibit_switch[2];
  50. uint16_t press_time[2];
  51. uint8_t led_state[2];
  52. uint16_t led_gate_delay[2];
  53. uint32_t rng_state;
  54. const prog_uint16_t linear_table[] PROGMEM = {
  55. 0, 0, 259, 518, 777, 1036, 1295, 1554,
  56. 1813, 2072, 2331, 2590, 2849, 3108, 3367, 3626,
  57. 3885, 4145, 4404, 4663, 4922, 5181, 5440, 5699,
  58. 5958, 6217, 6476, 6735, 6994, 7253, 7512, 7771,
  59. 8030, 8289, 8548, 8807, 9066, 9325, 9584, 9843,
  60. 10102, 10361, 10620, 10879, 11138, 11397, 11656, 11915,
  61. 12174, 12434, 12693, 12952, 13211, 13470, 13729, 13988,
  62. 14247, 14506, 14765, 15024, 15283, 15542, 15801, 16060,
  63. 16319, 16578, 16837, 17096, 17355, 17614, 17873, 18132,
  64. 18391, 18650, 18909, 19168, 19427, 19686, 19945, 20204,
  65. 20463, 20723, 20982, 21241, 21500, 21759, 22018, 22277,
  66. 22536, 22795, 23054, 23313, 23572, 23831, 24090, 24349,
  67. 24608, 24867, 25126, 25385, 25644, 25903, 26162, 26421,
  68. 26680, 26939, 27198, 27457, 27716, 27975, 28234, 28493,
  69. 28753, 29012, 29271, 29530, 29789, 30048, 30307, 30566,
  70. 30825, 31084, 31343, 31602, 31861, 32120, 32379, 32638,
  71. 32897, 33156, 33415, 33674, 33933, 34192, 34451, 34710,
  72. 34969, 35228, 35487, 35746, 36005, 36264, 36523, 36782,
  73. 37042, 37301, 37560, 37819, 38078, 38337, 38596, 38855,
  74. 39114, 39373, 39632, 39891, 40150, 40409, 40668, 40927,
  75. 41186, 41445, 41704, 41963, 42222, 42481, 42740, 42999,
  76. 43258, 43517, 43776, 44035, 44294, 44553, 44812, 45072,
  77. 45331, 45590, 45849, 46108, 46367, 46626, 46885, 47144,
  78. 47403, 47662, 47921, 48180, 48439, 48698, 48957, 49216,
  79. 49475, 49734, 49993, 50252, 50511, 50770, 51029, 51288,
  80. 51547, 51806, 52065, 52324, 52583, 52842, 53101, 53361,
  81. 53620, 53879, 54138, 54397, 54656, 54915, 55174, 55433,
  82. 55692, 55951, 56210, 56469, 56728, 56987, 57246, 57505,
  83. 57764, 58023, 58282, 58541, 58800, 59059, 59318, 59577,
  84. 59836, 60095, 60354, 60613, 60872, 61131, 61390, 61650,
  85. 61909, 62168, 62427, 62686, 62945, 63204, 63463, 63722,
  86. 63981, 64240, 64499, 64758, 65017, 65276, 65535, 65535,
  87. };
  88. void Init() {
  89. Gpio<PortB, 4>::set_mode(DIGITAL_OUTPUT);
  90. Gpio<PortB, 4>::Low();
  91. in_1.set_mode(DIGITAL_INPUT);
  92. in_2.set_mode(DIGITAL_INPUT);
  93. in_1.High();
  94. in_2.High();
  95. switch_1.set_mode(DIGITAL_INPUT);
  96. switch_2.set_mode(DIGITAL_INPUT);
  97. switch_1.High();
  98. switch_2.High();
  99. out_1_a.set_mode(DIGITAL_OUTPUT);
  100. out_1_b.set_mode(DIGITAL_OUTPUT);
  101. led_1_a.set_mode(DIGITAL_OUTPUT);
  102. led_1_k.set_mode(DIGITAL_OUTPUT);
  103. out_2_a.set_mode(DIGITAL_OUTPUT);
  104. out_2_b.set_mode(DIGITAL_OUTPUT);
  105. led_2_a.set_mode(DIGITAL_OUTPUT);
  106. led_2_k.set_mode(DIGITAL_OUTPUT);
  107. led_1_a.Low();
  108. led_2_a.Low();
  109. led_1_k.Low();
  110. led_2_k.Low();
  111. adc.Init();
  112. adc.set_reference(ADC_DEFAULT);
  113. adc.set_alignment(ADC_LEFT_ALIGNED);
  114. adc.StartConversion(0);
  115. uint8_t configuration_byte = ~eeprom_read_byte((uint8_t*) 0);
  116. toggle_mode[0] = configuration_byte & 1;
  117. latch_mode[0] = configuration_byte & 2;
  118. toggle_mode[1] = configuration_byte & 4;
  119. latch_mode[1] = configuration_byte & 8;
  120. led_state[0] = led_state[1] = 0;
  121. switch_state[0] = switch_state[1] = false;
  122. TCCR1A = 0;
  123. TCCR1B = 5;
  124. }
  125. bool Read(uint8_t channel) {
  126. return channel == 0 ? !in_1.value() : !in_2.value();
  127. }
  128. bool ReadSwitch(uint8_t channel) {
  129. return channel == 0 ? !switch_1.value() : !switch_2.value();
  130. }
  131. void GateOn(uint8_t channel, bool outcome) {
  132. if (channel == 0) {
  133. if (outcome) {
  134. out_1_a.Low();
  135. out_1_b.High();
  136. } else {
  137. out_1_a.High();
  138. out_1_b.Low();
  139. }
  140. } else {
  141. if (outcome) {
  142. out_2_a.Low();
  143. out_2_b.High();
  144. } else {
  145. out_2_a.High();
  146. out_2_b.Low();
  147. }
  148. }
  149. }
  150. void GateOff(uint8_t channel) {
  151. if (channel == 0) {
  152. out_1_a.Low();
  153. out_1_b.Low();
  154. } else {
  155. out_2_a.Low();
  156. out_2_b.Low();
  157. }
  158. }
  159. void LedOff(uint8_t channel) {
  160. if (channel == 0) {
  161. led_1_a.Low();
  162. led_1_k.Low();
  163. } else {
  164. led_2_a.Low();
  165. led_2_k.Low();
  166. }
  167. }
  168. void DisplayConfigurationAndSave(uint8_t channel) {
  169. uint8_t configuration_byte = 0;
  170. if (toggle_mode[0]) configuration_byte |= 1;
  171. if (latch_mode[0]) configuration_byte |= 2;
  172. if (toggle_mode[1]) configuration_byte |= 4;
  173. if (latch_mode[1]) configuration_byte |= 8;
  174. eeprom_write_byte((uint8_t*) 0, ~configuration_byte);
  175. }
  176. int main(void) {
  177. ResetWatchdog();
  178. Init();
  179. input_state[0] = input_state[1] = false;
  180. rng_state = 1;
  181. while (1) {
  182. // Whenever an ADC cycle is finished, update the probability variables.
  183. if (adc.ready()) {
  184. uint8_t channel_index = 1 - adc_channel; // ADC pins are swapped!
  185. p[channel_index] = pgm_read_word(linear_table + adc.ReadOut8());
  186. adc_channel = (adc_channel + 1) & 1;
  187. adc.StartConversion(adc_channel);
  188. }
  189. // Scan switches
  190. for (uint8_t i = 0; i < 2; ++i) {
  191. bool new_input_state = ReadSwitch(i);
  192. if (!switch_state[i] && new_input_state) {
  193. press_time[i] = TCNT1;
  194. inhibit_switch[i] = false;
  195. }
  196. if (switch_state[i] && !inhibit_switch[i]) {
  197. uint16_t this_press_time = TCNT1 - press_time[i];
  198. if (this_press_time >= kLongPressTime) {
  199. inhibit_switch[i] = true;
  200. latch_mode[i] = !latch_mode[i];
  201. DisplayConfigurationAndSave(i);
  202. } else if (this_press_time >= 64 && !new_input_state) {
  203. toggle_mode[i] = !toggle_mode[i];
  204. DisplayConfigurationAndSave(i);
  205. }
  206. }
  207. switch_state[i] = new_input_state;
  208. }
  209. // Scan inputs
  210. uint32_t random_words = rng_state;
  211. for (uint8_t i = 0; i < 2; ++i) {
  212. bool new_input_state = Read(i);
  213. if (new_input_state || latch_mode[i]) {
  214. // Hold the LED while the trigger is high or when in latch mode
  215. led_gate_delay[i] = kLedGateDelay;
  216. }
  217. if (new_input_state && !input_state[i] /* Rising edge */) {
  218. uint16_t random = random_words & 0xffff;
  219. uint16_t threshold = p[i];
  220. bool outcome = random >= threshold && threshold != 65535;
  221. if (toggle_mode[i]) {
  222. outcome = outcome ^ previous_state[i];
  223. }
  224. previous_state[i] = outcome;
  225. GateOn(i, outcome);
  226. led_state[i] = outcome ? 1 : 2;
  227. } else if (!new_input_state && input_state[i] && !latch_mode[i]) {
  228. GateOff(i);
  229. }
  230. input_state[i] = new_input_state;
  231. random_words >>= 16;
  232. if (led_gate_delay[i]) {
  233. --led_gate_delay[i];
  234. if (!led_gate_delay[i]) {
  235. led_state[i] = 0;
  236. }
  237. }
  238. }
  239. // Refresh LEDs
  240. if (led_state[0] == 0) {
  241. led_1_a.Low();
  242. led_1_k.Low();
  243. } else if (led_state[0] == 1) {
  244. led_1_a.Low();
  245. led_1_k.High();
  246. } else {
  247. led_1_a.High();
  248. led_1_k.Low();
  249. }
  250. if (led_state[1] == 0) {
  251. led_2_a.Low();
  252. led_2_k.Low();
  253. } else if (led_state[1] == 1) {
  254. led_2_a.Low();
  255. led_2_k.High();
  256. } else {
  257. led_2_a.High();
  258. led_2_k.Low();
  259. }
  260. // rng_state = rng_state * 1664525 + 1013904223;
  261. rng_state = (rng_state >> 1) ^ (-(rng_state & 1u) & 0xD0000001u);
  262. }
  263. }