~gabe/flashlight-firmware/anduril2

« back to all changes in this revision

Viewing changes to ToyKeeper/spaghetti-monster/anduril/anduril.c

merged recent fsm branch updates

Show diffs side-by-side

added added

removed removed

Lines of Context:
32
32
//#define FSM_FF_ROT66_DRIVER
33
33
//#define FSM_FF_ROT66_219_DRIVER
34
34
//#define FSM_FW3A_DRIVER
 
35
//#define FSM_SOFIRN_SP36_DRIVER
35
36
 
36
37
#define USE_LVP  // FIXME: won't build when this option is turned off
37
38
 
114
115
#elif defined(FSM_FW3A_DRIVER)
115
116
#include "cfg-fw3a.h"
116
117
 
 
118
#elif defined(FSM_SOFIRN_SP36_DRIVER)
 
119
#include "cfg-sofirn-sp36.h"
 
120
 
117
121
#endif
118
122
 
119
123
 
136
140
/********* Configure SpaghettiMonster *********/
137
141
#define USE_DELAY_ZERO
138
142
#define USE_RAMPING
 
143
#ifndef RAMP_LENGTH
139
144
#define RAMP_LENGTH 150  // default, if not overridden in a driver cfg file
 
145
#endif
140
146
#define MAX_BIKING_LEVEL 120  // should be 127 or less
141
147
#define USE_BATTCHECK
142
 
#ifdef USE_MUGGLE_MODE
143
 
#define MAX_CLICKS 6
 
148
 
 
149
#if defined(USE_MUGGLE_MODE)
 
150
#ifndef MUGGLE_FLOOR
144
151
#define MUGGLE_FLOOR 22
 
152
#endif
 
153
#ifndef MUGGLE_CEILING
145
154
#define MUGGLE_CEILING (MAX_1x7135+20)
146
 
#else
147
 
#define MAX_CLICKS 5
 
155
#endif
148
156
#endif
149
157
#define USE_IDLE_MODE  // reduce power use while awake and no tasks are pending
150
158
#define USE_DYNAMIC_UNDERCLOCKING  // cut clock speed at very low modes for better efficiency
209
217
 
210
218
 
211
219
// FSM states
212
 
uint8_t off_state(EventPtr event, uint16_t arg);
 
220
uint8_t off_state(Event event, uint16_t arg);
213
221
// simple numeric entry config menu
214
 
uint8_t config_state_base(EventPtr event, uint16_t arg,
 
222
uint8_t config_state_base(Event event, uint16_t arg,
215
223
                          uint8_t num_config_steps,
216
224
                          void (*savefunc)());
217
225
#define MAX_CONFIG_VALUES 3
218
226
uint8_t config_state_values[MAX_CONFIG_VALUES];
219
227
// ramping mode and its related config mode
220
 
uint8_t steady_state(EventPtr event, uint16_t arg);
221
 
uint8_t ramp_config_state(EventPtr event, uint16_t arg);
 
228
uint8_t steady_state(Event event, uint16_t arg);
 
229
uint8_t ramp_config_state(Event event, uint16_t arg);
222
230
// party and tactical strobes
223
231
#ifdef USE_STROBE_STATE
224
 
uint8_t strobe_state(EventPtr event, uint16_t arg);
 
232
uint8_t strobe_state(Event event, uint16_t arg);
225
233
#endif
226
234
#ifdef USE_BATTCHECK
227
 
uint8_t battcheck_state(EventPtr event, uint16_t arg);
 
235
uint8_t battcheck_state(Event event, uint16_t arg);
228
236
#endif
229
237
#ifdef USE_THERMAL_REGULATION
230
 
uint8_t tempcheck_state(EventPtr event, uint16_t arg);
231
 
uint8_t thermal_config_state(EventPtr event, uint16_t arg);
 
238
uint8_t tempcheck_state(Event event, uint16_t arg);
 
239
uint8_t thermal_config_state(Event event, uint16_t arg);
232
240
#endif
233
241
// 1-hour ramp down from low, then automatic off
234
 
uint8_t goodnight_state(EventPtr event, uint16_t arg);
 
242
uint8_t goodnight_state(Event event, uint16_t arg);
235
243
// beacon mode and its related config mode
236
 
uint8_t beacon_state(EventPtr event, uint16_t arg);
237
 
uint8_t beacon_config_state(EventPtr event, uint16_t arg);
 
244
uint8_t beacon_state(Event event, uint16_t arg);
 
245
uint8_t beacon_config_state(Event event, uint16_t arg);
238
246
// soft lockout
239
247
#define MOON_DURING_LOCKOUT_MODE
240
 
uint8_t lockout_state(EventPtr event, uint16_t arg);
 
248
uint8_t lockout_state(Event event, uint16_t arg);
241
249
// momentary / signalling mode
242
 
uint8_t momentary_state(EventPtr event, uint16_t arg);
 
250
uint8_t momentary_state(Event event, uint16_t arg);
243
251
#ifdef USE_MUGGLE_MODE
244
252
// muggle mode, super-simple, hard to exit
245
 
uint8_t muggle_state(EventPtr event, uint16_t arg);
 
253
uint8_t muggle_state(Event event, uint16_t arg);
246
254
uint8_t muggle_mode_active = 0;
247
255
#endif
248
256
 
249
257
// general helper function for config modes
250
 
uint8_t number_entry_state(EventPtr event, uint16_t arg);
 
258
uint8_t number_entry_state(Event event, uint16_t arg);
251
259
// return value from number_entry_state()
252
260
volatile uint8_t number_entry_value;
253
261
 
370
378
volatile uint8_t beacon_seconds = 2;
371
379
 
372
380
 
373
 
uint8_t off_state(EventPtr event, uint16_t arg) {
 
381
uint8_t off_state(Event event, uint16_t arg) {
374
382
    // turn emitter off when entering state
375
383
    if (event == EV_enter_state) {
376
384
        set_level(0);
488
496
        return MISCHIEF_MANAGED;
489
497
    }
490
498
    #endif
 
499
    #ifdef USE_INDICATOR_LED
 
500
    // 7 clicks: change indicator LED mode
 
501
    else if (event == EV_7clicks) {
 
502
        uint8_t mode = (indicator_led_mode & 3) + 1;
 
503
        #ifdef TICK_DURING_STANDBY
 
504
        mode = mode & 3;
 
505
        #else
 
506
        mode = mode % 3;
 
507
        #endif
 
508
        #ifdef INDICATOR_LED_SKIP_LOW
 
509
        if (mode == 1) { mode ++; }
 
510
        #endif
 
511
        indicator_led_mode = (indicator_led_mode & 0b11111100) | mode;
 
512
        indicator_led(mode);
 
513
        save_config();
 
514
        return MISCHIEF_MANAGED;
 
515
    }
 
516
    #endif
491
517
    return EVENT_NOT_HANDLED;
492
518
}
493
519
 
494
520
 
495
 
uint8_t steady_state(EventPtr event, uint16_t arg) {
 
521
uint8_t steady_state(Event event, uint16_t arg) {
496
522
    uint8_t mode_min = ramp_smooth_floor;
497
523
    uint8_t mode_max = ramp_smooth_ceil;
498
524
    uint8_t ramp_step_size = 1;
811
837
 
812
838
 
813
839
#ifdef USE_STROBE_STATE
814
 
uint8_t strobe_state(EventPtr event, uint16_t arg) {
 
840
uint8_t strobe_state(Event event, uint16_t arg) {
815
841
    // 'st' reduces ROM size by avoiding access to a volatile var
816
842
    // (maybe I should just make it nonvolatile?)
817
843
    strobe_mode_te st = strobe_type;
1024
1050
 
1025
1051
 
1026
1052
#ifdef USE_BATTCHECK
1027
 
uint8_t battcheck_state(EventPtr event, uint16_t arg) {
 
1053
uint8_t battcheck_state(Event event, uint16_t arg) {
1028
1054
    // 1 click: off
1029
1055
    if (event == EV_1click) {
1030
1056
        set_state(off_state, 0);
1041
1067
 
1042
1068
 
1043
1069
#ifdef USE_THERMAL_REGULATION
1044
 
uint8_t tempcheck_state(EventPtr event, uint16_t arg) {
 
1070
uint8_t tempcheck_state(Event event, uint16_t arg) {
1045
1071
    // 1 click: off
1046
1072
    if (event == EV_1click) {
1047
1073
        set_state(off_state, 0);
1062
1088
#endif
1063
1089
 
1064
1090
 
1065
 
uint8_t beacon_state(EventPtr event, uint16_t arg) {
 
1091
uint8_t beacon_state(Event event, uint16_t arg) {
1066
1092
    // 1 click: off
1067
1093
    if (event == EV_1click) {
1068
1094
        set_state(off_state, 0);
1089
1115
 
1090
1116
 
1091
1117
#define GOODNIGHT_TICKS_PER_STEPDOWN (GOODNIGHT_TIME*TICKS_PER_SECOND*60L/GOODNIGHT_LEVEL)
1092
 
uint8_t goodnight_state(EventPtr event, uint16_t arg) {
 
1118
uint8_t goodnight_state(Event event, uint16_t arg) {
1093
1119
    static uint16_t ticks_since_stepdown = 0;
1094
1120
    // blink on start
1095
1121
    if (event == EV_enter_state) {
1128
1154
}
1129
1155
 
1130
1156
 
1131
 
uint8_t lockout_state(EventPtr event, uint16_t arg) {
 
1157
uint8_t lockout_state(Event event, uint16_t arg) {
1132
1158
    #ifdef MOON_DURING_LOCKOUT_MODE
1133
1159
    // momentary(ish) moon mode during lockout
1134
 
    // not all presses will be counted;
1135
 
    // it depends on what is in the master event_sequences table
1136
 
    uint8_t last = 0;
1137
 
    for(uint8_t i=0; pgm_read_byte(event + i) && (i<EV_MAX_LEN); i++)
1138
 
        last = pgm_read_byte(event + i);
1139
 
    if (arg == 0) {  // Only turn on/off when button state changes
1140
 
        if ((last == A_PRESS) || (last == A_HOLD)) {
1141
 
            #ifdef LOCKOUT_MOON_LOWEST
1142
 
            // Use lowest moon configured
1143
 
            uint8_t lvl = ramp_smooth_floor;
1144
 
            if (ramp_discrete_floor < lvl) lvl = ramp_discrete_floor;
1145
 
            set_level(lvl);
1146
 
            #else
1147
 
            // Use moon from current ramp
1148
 
            set_level(nearest_level(1));
1149
 
            #endif
1150
 
        }
1151
 
        else if ((last == A_RELEASE) || (last == A_RELEASE_TIMEOUT)) {
1152
 
            set_level(0);
1153
 
        }
 
1160
    // button is being held
 
1161
    if ((event & (B_CLICK | B_PRESS)) == (B_CLICK | B_PRESS)) {
 
1162
        #ifdef LOCKOUT_MOON_LOWEST
 
1163
        // Use lowest moon configured
 
1164
        uint8_t lvl = ramp_smooth_floor;
 
1165
        if (ramp_discrete_floor < lvl) lvl = ramp_discrete_floor;
 
1166
        set_level(lvl);
 
1167
        #else
 
1168
        // Use moon from current ramp
 
1169
        set_level(nearest_level(1));
 
1170
        #endif
 
1171
    }
 
1172
    // button was released
 
1173
    else if ((event & (B_CLICK | B_PRESS)) == (B_CLICK)) {
 
1174
        set_level(0);
1154
1175
    }
1155
1176
    #endif
1156
1177
 
1198
1219
        save_config();
1199
1220
        return MISCHIEF_MANAGED;
1200
1221
    }
 
1222
    #if 0  // old method, deprecated in favor of "7 clicks from off"
1201
1223
    // click, click, hold: rotate through indicator LED modes (off mode)
1202
1224
    else if (event == EV_click3_hold) {
1203
1225
        #ifndef USE_INDICATOR_LED_WHILE_RAMPING
1230
1252
        return MISCHIEF_MANAGED;
1231
1253
    }
1232
1254
    #endif
 
1255
    #endif
1233
1256
    // 4 clicks: exit
1234
1257
    else if (event == EV_4clicks) {
1235
1258
        blink_confirm(1);
1241
1264
}
1242
1265
 
1243
1266
 
1244
 
uint8_t momentary_state(EventPtr event, uint16_t arg) {
 
1267
uint8_t momentary_state(Event event, uint16_t arg) {
1245
1268
    // TODO: momentary strobe here?  (for light painting)
1246
 
    if (event == EV_click1_press) {
 
1269
 
 
1270
    // light up when the button is pressed; go dark otherwise
 
1271
    // button is being held
 
1272
    if ((event & (B_CLICK | B_PRESS)) == (B_CLICK | B_PRESS)) {
1247
1273
        set_level(memorized_level);
1248
 
        empty_event_sequence();  // don't attempt to parse multiple clicks
1249
1274
        return MISCHIEF_MANAGED;
1250
1275
    }
1251
 
 
1252
 
    else if (event == EV_release) {
 
1276
    // button was released
 
1277
    else if ((event & (B_CLICK | B_PRESS)) == (B_CLICK)) {
1253
1278
        set_level(0);
1254
 
        empty_event_sequence();  // don't attempt to parse multiple clicks
1255
1279
        //go_to_standby = 1;  // sleep while light is off
1256
 
        // TODO: lighted button should use lockout config?
1257
1280
        return MISCHIEF_MANAGED;
1258
1281
    }
1259
1282
 
1265
1288
    else if ((event == EV_tick)  &&  (actual_level == 0)) {
1266
1289
        if (arg > TICKS_PER_SECOND*15) {  // sleep after 15 seconds
1267
1290
            go_to_standby = 1;  // sleep while light is off
 
1291
            // TODO: lighted button should use lockout config?
1268
1292
        }
1269
1293
        return MISCHIEF_MANAGED;
1270
1294
    }
1274
1298
 
1275
1299
 
1276
1300
#ifdef USE_MUGGLE_MODE
1277
 
uint8_t muggle_state(EventPtr event, uint16_t arg) {
 
1301
uint8_t muggle_state(Event event, uint16_t arg) {
1278
1302
    static int8_t ramp_direction;
1279
1303
    static int8_t muggle_off_mode;
1280
1304
 
1424
1448
 
1425
1449
 
1426
1450
// ask the user for a sequence of numbers, then save them and return to caller
1427
 
uint8_t config_state_base(EventPtr event, uint16_t arg,
 
1451
uint8_t config_state_base(Event event, uint16_t arg,
1428
1452
                          uint8_t num_config_steps,
1429
1453
                          void (*savefunc)()) {
1430
1454
    static uint8_t config_step;
1483
1507
    }
1484
1508
}
1485
1509
 
1486
 
uint8_t ramp_config_state(EventPtr event, uint16_t arg) {
 
1510
uint8_t ramp_config_state(Event event, uint16_t arg) {
1487
1511
    uint8_t num_config_steps;
1488
1512
    num_config_steps = 2 + ramp_style;
1489
1513
    return config_state_base(event, arg,
1511
1535
    if (therm_ceil > MAX_THERM_CEIL) therm_ceil = MAX_THERM_CEIL;
1512
1536
}
1513
1537
 
1514
 
uint8_t thermal_config_state(EventPtr event, uint16_t arg) {
 
1538
uint8_t thermal_config_state(Event event, uint16_t arg) {
1515
1539
    return config_state_base(event, arg,
1516
1540
                             2, thermal_config_save);
1517
1541
}
1526
1550
    }
1527
1551
}
1528
1552
 
1529
 
uint8_t beacon_config_state(EventPtr event, uint16_t arg) {
 
1553
uint8_t beacon_config_state(Event event, uint16_t arg) {
1530
1554
    return config_state_base(event, arg,
1531
1555
                             1, beacon_config_save);
1532
1556
}
1533
1557
 
1534
1558
 
1535
 
uint8_t number_entry_state(EventPtr event, uint16_t arg) {
 
1559
uint8_t number_entry_state(Event event, uint16_t arg) {
1536
1560
    static uint8_t value;
1537
1561
    static uint8_t blinks_left;
1538
1562
    static uint8_t entry_step;