main.ino 6.47 KB
Newer Older
Michael Nelson's avatar
Michael Nelson committed
1 2 3
#include <avr/power.h>

#define MODE_OFF 0
Michael Nelson's avatar
Michael Nelson committed
4
#define DEBUG_WITH_BUILTIN_LED false
Michael Nelson's avatar
Michael Nelson committed
5 6 7 8 9 10 11 12 13 14 15

// Foreground Modes
#define FG_MODE_BLINK_L 1
#define FG_MODE_BLINK_R 2

// Background modes
#define BG_MODE_HAZARDS 1
#define BG_MODE_RUNNING_LIGHTS 2
#define BG_MODE_RUNNING_W_BLINK 3
#define BG_MODE_AUXILARY_LIGHTS 4

16
// Pins 2-6 are for itmes on the handlebars.
Michael Nelson's avatar
Michael Nelson committed
17 18 19 20 21 22 23 24 25
// Ethernet coloring plan:
// Brown          - Ground
// Brown striped  - Speaker
// Green          - Left button
// Green striped  - Right button
// Orange         - Left button LED
// Orange striped - Right button LED
// Blue           - Available
// Blue striped   - Available
26

Michael Nelson's avatar
Michael Nelson committed
27 28 29 30 31
// Inputs
#define PIN_IN_LEFT_BUTTON 4
#define PIN_IN_RIGHT_BUTTON 5

// Outputs
Michael Nelson's avatar
Michael Nelson committed
32 33
#define PIN_OUT_LEFT_BUTTON_LED 2
#define PIN_OUT_RIGHT_BUTTON_LED 3
34

Michael Nelson's avatar
Michael Nelson committed
35 36 37 38 39 40
#define PIN_OUT_SPEAKER 6
#define PIN_OUT_BLINKER_L 7
#define PIN_OUT_BLINKER_R 8
#define PIN_OUT_WHITES 9

// Config
41
#define BLINK_RATE 250
42
#define RUNNING_LIGHT_BLINK_RATE 920
Michael Nelson's avatar
Michael Nelson committed
43 44 45 46 47 48
#define HOLD_DOWN_TIME 350

// State
int fg_mode = MODE_OFF;
int bg_mode = MODE_OFF;
int blinker_light_state;
Michael Nelson's avatar
Michael Nelson committed
49
int last_fg_mode = MODE_OFF;
50
bool hold_waiting = false;
Michael Nelson's avatar
Michael Nelson committed
51 52

// Just-released variables
53 54
bool input_single_left_hit = false;
bool input_single_right_hit = false;
55
bool input_single_both_hit = false;
56 57 58

bool input_hold_left_hit = false;
bool input_hold_right_hit = false;
59
bool input_hold_both_hit = false;
Michael Nelson's avatar
Michael Nelson committed
60 61 62 63 64 65 66 67 68 69

// Time accumulator variables
int cycle_time = 0;
int left_hold_time = 0;
int right_hold_time = 0;
int both_hold_time = 0;

void setup()
{
  // Initialize a serial connection for reporting values to the host
70
  Serial.begin(9600);
Michael Nelson's avatar
Michael Nelson committed
71 72 73 74 75 76 77

  pinMode(PIN_IN_LEFT_BUTTON, INPUT_PULLUP);
  pinMode(PIN_IN_RIGHT_BUTTON, INPUT_PULLUP);

  pinMode(PIN_OUT_SPEAKER, OUTPUT);
  pinMode(PIN_OUT_BLINKER_L, OUTPUT);
  pinMode(PIN_OUT_BLINKER_R, OUTPUT);
78 79
  pinMode(PIN_OUT_LEFT_BUTTON_LED, OUTPUT);
  pinMode(PIN_OUT_RIGHT_BUTTON_LED, OUTPUT);
Michael Nelson's avatar
Michael Nelson committed
80 81 82

  /* clock_prescale_set(clock_div_2); */

Michael Nelson's avatar
Michael Nelson committed
83
  /* Serial.println("Started."); */
Michael Nelson's avatar
Michael Nelson committed
84 85
}

86
void blink_frame(bool left, bool right, int tone_divisor = 2)
Michael Nelson's avatar
Michael Nelson committed
87 88 89 90 91 92 93
{
  if (cycle_time > BLINK_RATE)
  {
    cycle_time = 0;
    blinker_light_state = !blinker_light_state;
  }

94 95
  if (cycle_time == 1 && !blinker_light_state)
    blink_speaker_frame(tone_divisor);
Michael Nelson's avatar
Michael Nelson committed
96

Michael Nelson's avatar
Michael Nelson committed
97
  // Actual light
98 99 100 101 102
  if (left)
  {
    digitalWrite(PIN_OUT_BLINKER_L,       blinker_light_state ? LOW : HIGH);
    digitalWrite(PIN_OUT_LEFT_BUTTON_LED, blinker_light_state ? LOW : HIGH);
  }
Michael Nelson's avatar
Michael Nelson committed
103

104 105 106 107 108
  if (right)
  {
    digitalWrite(PIN_OUT_BLINKER_R,        blinker_light_state ? LOW : HIGH);
    digitalWrite(PIN_OUT_RIGHT_BUTTON_LED, blinker_light_state ? LOW : HIGH);
  }
Michael Nelson's avatar
Michael Nelson committed
109 110 111 112 113 114 115 116

  #if DEBUG_WITH_BUILTIN_LED
  digitalWrite(LED_BUILTIN, blinker_light_state ? LOW : HIGH);
  #endif

  cycle_time++;
}

117 118 119 120 121
void running_light_frame(bool with_blink = false)
{
  if (cycle_time > RUNNING_LIGHT_BLINK_RATE)
    cycle_time = 0;

122 123
  digitalWrite(PIN_OUT_BLINKER_L,       !(cycle_time % 9) || (with_blink && cycle_time < 70) ? HIGH : LOW);
  digitalWrite(PIN_OUT_BLINKER_R,       !(cycle_time % 9) || (with_blink && cycle_time < 70) ? HIGH : LOW);
124

125
  digitalWrite(PIN_OUT_LEFT_BUTTON_LED, !(cycle_time % 9) || (with_blink && cycle_time < 70) ? HIGH : LOW);
126 127 128 129

  cycle_time++;
}

130
void blink_speaker_frame(int divisor)
Michael Nelson's avatar
Michael Nelson committed
131
{
132 133 134 135
  /* if (!blinker_light_state && cycle_time < 40) { */
  /*   digitalWrite(PIN_OUT_SPEAKER, !(cycle_time % divisor) ? HIGH : LOW); */
  /* } */
  tone(PIN_OUT_SPEAKER, 2000, 20);
Michael Nelson's avatar
Michael Nelson committed
136 137
}

138
// Each frame, this increments L/R/B hold time variables while the user is holding a button (or both) down.
139 140
// It also checks for the release. In that case it flips on either input_single_* or input_hold_* variables
// to be consumed later in the frame.
Michael Nelson's avatar
Michael Nelson committed
141 142
void read_dual_buttons()
{
143 144
  input_single_left_hit = false;
  input_single_right_hit = false;
145 146 147 148 149
  input_single_both_hit = false;

  input_hold_left_hit = false;
  input_hold_right_hit = false;
  input_hold_both_hit = false;
Michael Nelson's avatar
Michael Nelson committed
150 151 152 153 154 155 156 157 158

  if (digitalRead(PIN_IN_LEFT_BUTTON) == LOW && digitalRead(PIN_IN_RIGHT_BUTTON) == LOW)
    both_hold_time++;
  else if (digitalRead(PIN_IN_LEFT_BUTTON) == LOW)
    left_hold_time++;
  else if (digitalRead(PIN_IN_RIGHT_BUTTON) == LOW)
    right_hold_time++;
  else
  {
159
    if (left_hold_time && !hold_waiting)
160 161
      input_single_left_hit = true;

162
    if (right_hold_time && !hold_waiting)
163 164
      input_single_right_hit = true;

165 166
    if (both_hold_time && !hold_waiting)
      input_single_both_hit = true;
Michael Nelson's avatar
Michael Nelson committed
167 168 169 170

    both_hold_time = 0;
    left_hold_time = 0;
    right_hold_time = 0;
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
    hold_waiting = false;
  }

  if (left_hold_time == HOLD_DOWN_TIME)
  {
    input_hold_left_hit = true;
    hold_waiting = true;
  }

  else if (right_hold_time == HOLD_DOWN_TIME)
  {
    input_hold_right_hit = true;
    hold_waiting = true;
  }

  else if (both_hold_time == HOLD_DOWN_TIME)
  {
    input_hold_both_hit = true;
    hold_waiting = true;
Michael Nelson's avatar
Michael Nelson committed
190 191 192 193 194 195 196
  }
}

void set_up_mode()
{
  read_dual_buttons();

197
  if (input_hold_both_hit)
Michael Nelson's avatar
Michael Nelson committed
198
  {
199
    bg_mode = bg_mode == BG_MODE_HAZARDS ? MODE_OFF : BG_MODE_HAZARDS;
Michael Nelson's avatar
Michael Nelson committed
200 201
    fg_mode = MODE_OFF;
  }
202
  else if (input_single_both_hit)
Michael Nelson's avatar
Michael Nelson committed
203 204 205 206 207
  {
    bg_mode = MODE_OFF;
    fg_mode = MODE_OFF;
  }
  // Cycle between running lights
208
  else if (input_hold_left_hit)
Michael Nelson's avatar
Michael Nelson committed
209
  {
210
    if (!bg_mode)
Michael Nelson's avatar
Michael Nelson committed
211
      bg_mode = BG_MODE_RUNNING_LIGHTS;
212 213 214 215
    else if (bg_mode >= BG_MODE_RUNNING_W_BLINK)
      bg_mode = MODE_OFF;
    else
      bg_mode++;
Michael Nelson's avatar
Michael Nelson committed
216 217 218

    fg_mode = MODE_OFF;
  }
219
  else if (input_single_left_hit)
220
  {
Michael Nelson's avatar
Michael Nelson committed
221
    fg_mode = fg_mode == FG_MODE_BLINK_L ? MODE_OFF : FG_MODE_BLINK_L;
222
  }
223
  else if (input_hold_right_hit)
Michael Nelson's avatar
Michael Nelson committed
224 225 226 227
  {
    bg_mode = BG_MODE_AUXILARY_LIGHTS;
    fg_mode = MODE_OFF;
  }
228
  else if (input_single_right_hit)
229
  {
Michael Nelson's avatar
Michael Nelson committed
230
    fg_mode = fg_mode == FG_MODE_BLINK_R ? MODE_OFF : FG_MODE_BLINK_R;
231
  }
Michael Nelson's avatar
Michael Nelson committed
232 233
}

Michael Nelson's avatar
Michael Nelson committed
234 235 236
void reset_all()
{
  cycle_time = 0;
237
  blinker_light_state = 0;
Michael Nelson's avatar
Michael Nelson committed
238 239 240 241 242 243 244 245 246 247 248 249

  #if DEBUG_WITH_BUILTIN_LED
  digitalWrite(LED_BUILTIN, LOW);
  #endif

  digitalWrite(PIN_OUT_BLINKER_L, LOW);
  digitalWrite(PIN_OUT_BLINKER_R, LOW);
  digitalWrite(PIN_OUT_LEFT_BUTTON_LED, LOW);
  digitalWrite(PIN_OUT_RIGHT_BUTTON_LED, LOW);
  digitalWrite(PIN_OUT_WHITES, LOW);
}

Michael Nelson's avatar
Michael Nelson committed
250 251
void loop()
{
252
  delay(1);
Michael Nelson's avatar
Michael Nelson committed
253
  set_up_mode();
Michael Nelson's avatar
Michael Nelson committed
254

255
  // Reset all lights going directly from one direction to the next.
Michael Nelson's avatar
Michael Nelson committed
256 257 258
  if (fg_mode != last_fg_mode && fg_mode != MODE_OFF)
    reset_all();

259 260 261 262 263 264
  if (fg_mode == FG_MODE_BLINK_L)
    blink_frame(true, false);
  else if (fg_mode == FG_MODE_BLINK_R)
    blink_frame(false, true);
  else if (bg_mode == BG_MODE_HAZARDS)
    blink_frame(true, true, 3);
265 266 267 268
  else if (bg_mode == BG_MODE_RUNNING_LIGHTS)
    running_light_frame();
  else if (bg_mode == BG_MODE_RUNNING_W_BLINK)
    running_light_frame(true);
Michael Nelson's avatar
Michael Nelson committed
269
  else
Michael Nelson's avatar
Michael Nelson committed
270
    reset_all();
Michael Nelson's avatar
Michael Nelson committed
271

Michael Nelson's avatar
Michael Nelson committed
272
  last_fg_mode = fg_mode;
Michael Nelson's avatar
Michael Nelson committed
273
}