-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwinda.ino
2315 lines (2107 loc) · 74.9 KB
/
winda.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/** winda.ino ***********************************************************
Fake elevator - a resurrection of an old elevator button board.
Copyright (C) 2019 Piotr Karpiewski
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 <https://www.gnu.org/licenses/>.
Contact author at [email protected]
This revision:
- vastly advanced story logic
- changed comment numbering
- most comments get true durations
- introduce mystery floor 11
- bug fixes, code cleanup
*************************************************************************/
#include "FastLED.h"
#include <Wtv020sd16p.h>
// wtv020 pin
#define WTV_RESET_PIN 9
#define WTV_CLOCK_PIN 5
#define WTV_DATA_PIN 6
#define WTV_BUSY_PIN 19 // not used if async play only
// init wtv management object
Wtv020sd16p wtv020sd16p(WTV_RESET_PIN, WTV_CLOCK_PIN, WTV_DATA_PIN, WTV_BUSY_PIN);
// How many leds in your strip?
#define NUM_LEDS 13
#define NUM_PHYS_KEYS 13
#define NUM_KEYS 23 // 10 virtual keys (with shift)
#define NUM_FLOORS 13 // 0 ground (P), 1..10 floors, 11 hidden floor, 12 lift cabin
// virtual keys
#define KEY_P 0
#define KEY_DIGIT_MIN 1
#define KEY_DIGIT_MAX 20
#define KEY_STOP 21
#define KEY_BELL 22
#define LED_P 0
#define LED_STOP 11
#define LED_BELL 12
// Serial to parallel shift register 74hc595
#define SHIFT_CLOCK_PIN A4 // rising edge active
#define SHIFT_LATCH_PIN A6 // L - block, H - show
#define SHIFT_DATA_PIN 10
// relays polarity
#define POLARITY_ON_PIN 11 // L - active
#define POLARITY_OFF_PIN 13 // L - active
#define ENERGIZE_DURATION 35 // 30 - 72ms, 35 - 84ms -> 5 - 12ms
#define NO_MATTER 0 // value that does not matter, zero is fine too
// For led chips like Neopixels, which have a data line, ground, and power, you just
// need to define DATA_PIN. For led chipsets that are SPI based (four wires - data, clock,
// ground, and power), like the LPD8806 define both DATA_PIN and CLOCK_PIN
#define DATA_PIN 3
#define CLOCK_PIN 13
// Define the array of leds
CRGB leds[NUM_LEDS];
// LED related declarations
#define BLINK_TIME 500
char blink_state = 0;
int blink_countdown = 0;
// KEYPAD related declarations
// keyboard matrix definition
// ROWS act as outputs
#define ROW_1 2
#define ROW_2 4
#define ROW_3 7
#define ROW_4 8
#define COL_1 12
#define COL_2 A0
#define COL_3 A1
#define COL_4 A2
#define NUM_MODESETS 5 // 0 - lift, 1,2,3 - switches, 4 - lift stop
// map keypad number to number in the LED chain
char keymap[NUM_KEYS] = {7, // KEY_P
6, 8, 5, 9, 4, 10, 3, 11, 2, 12, // DIGITS
6, 8, 5, 9, 4, 10, 3, 11, 2, 12, // DIGITS
1, 0}; // KEY_STOP, KEY_BELL
char mode[NUM_MODESETS][NUM_KEYS];
char physical_key[NUM_PHYS_KEYS];
char key[NUM_KEYS]; // 0 - released, 1 - pressed
char last_key[NUM_KEYS]; // last state of key; used to detect a change
#define MAX_KEY_COUNTDOWN 3000
#define MAX_KEY_PRESS_COUNTDOWN 900
int key_countdown[NUM_KEYS]; // indicating time after key was pressed
int key_press_countdown[NUM_KEYS]; // indicating time the key stays pressed
char key_num;
char key_pressed;
#define SLEEP_TIME 5000
long sleep_countdown = 0;
// LIFT related declarations
#define RESTART_THIS_STATE 0 // set last_state to this one to pretend the state has changed even if it has not
#define LIFT_STOPPING 1
#define LIFT_STOPPED 2
#define DOOR_OPENING 3
#define DOOR_OPEN 4
#define DOOR_CLOSING 5
#define DOOR_CLOSED 6
#define LIFT_STARTING 7
#define LIFT_RUNNING_UP 8
#define LIFT_RUNNING_DOWN 9
#define PASSENGERS_MOVEMENT 10
#define LIFT_START_FALLING 11
#define LIFT_FALLING_DOWN 12
#define LIFT_CRASHING 13
char state = DOOR_OPEN;
char last_state = RESTART_THIS_STATE;
int state_countdown = 0;
// FLOOR related declarations
char curr_floor = 0;
char target_floor = 0;
int dir = 1;
char floors[NUM_FLOORS]; // !!! was [NUM_KEYS]; make sure it is not required
char ff;
char modeset_num = 0;
char last_active_modeset_num = 0;
void readKbd() {
// Rows are strobed by pinMode and not digitalWrite
// so all rows except the selected one are high impedance.
//digitalWrite(ROW_1, LOW);
pinMode(ROW_1, OUTPUT);
if(digitalRead(COL_1) == LOW)
physical_key[10] = 1;
else
physical_key[10] = 0;
if(digitalRead(COL_2) == LOW)
physical_key[8] = 1;
else
physical_key[8] = 0;
if(digitalRead(COL_3) == LOW)
physical_key[6] = 1;
else
physical_key[6] = 0;
if(digitalRead(COL_4) == LOW)
physical_key[4] = 1;
else
physical_key[4] = 0;
pinMode(ROW_1, INPUT);
//digitalWrite(ROW_1, HIGH);
//digitalWrite(ROW_2, LOW);
pinMode(ROW_2, OUTPUT);
if(digitalRead(COL_1) == LOW)
physical_key[2] = 1;
else
physical_key[2] = 0;
if(digitalRead(COL_2) == LOW)
physical_key[0] = 1;
else
physical_key[0] = 0;
if(digitalRead(COL_3) == LOW)
physical_key[1] = 1;
else
physical_key[1] = 0;
if(digitalRead(COL_4) == LOW)
physical_key[3] = 1;
else
physical_key[3] = 0;
pinMode(ROW_2, INPUT);
//digitalWrite(ROW_2, HIGH);
//digitalWrite(ROW_3, LOW);
pinMode(ROW_3, OUTPUT);
if(digitalRead(COL_1) == LOW)
physical_key[5] = 1;
else
physical_key[5] = 0;
if(digitalRead(COL_2) == LOW)
physical_key[7] = 1;
else
physical_key[7] = 0;
if(digitalRead(COL_3) == LOW)
physical_key[9] = 1;
else
physical_key[9] = 0;
/* if(digitalRead(COL_4) == LOW)
physical_key[4] = 1;
else
physical_key[4] = 0; */
pinMode(ROW_3, INPUT);
//digitalWrite(ROW_3, HIGH);
//digitalWrite(ROW_4, LOW);
pinMode(ROW_4, OUTPUT);
if(digitalRead(COL_1) == LOW)
physical_key[11] = 1;
else
physical_key[11] = 0;
if(digitalRead(COL_2) == LOW)
physical_key[12] = 1;
else
physical_key[12] = 0;
/* if(digitalRead(COL_3) == LOW)
physical_key[6] = 1;
else
physical_key[6] = 0;
if(digitalRead(COL_4) == LOW)
physical_key[4] = 1;
else
physical_key[4] = 0; */
pinMode(ROW_4, INPUT);
//digitalWrite(ROW_4, HIGH);
}
void mapPhysKeyToKey(char mode, char key_p_state) {
switch(mode) {
case 0: // lift
memcpy(&key[0], &physical_key[0], sizeof(physical_key[0]) * 11);
memcpy(&key[21], &physical_key[11], sizeof(physical_key[11]) * 2);
break;
// switches
case 1:
case 2:
case 3:
case 4: if(key_p_state == 0) { // P key is OFF
// copy keys normal way, digits to lower bank
memcpy(&key[0], &physical_key[0], sizeof(physical_key[0]) * 11);
memcpy(&key[21], &physical_key[11], sizeof(physical_key[11]) * 2);
}
else {
// P key is ON -> copy digit keys to upper bank
memcpy(&key[0], &physical_key[0], sizeof(physical_key[0]));
memcpy(&key[11], &physical_key[1], sizeof(physical_key[1]) * 10);
memcpy(&key[21], &physical_key[11], sizeof(physical_key[11]) * 2);
}
break;
}
}
// actualize each key's key_countdown
void countdownKbd(char from_key, char to_key) {
char key_num;
for(key_num=from_key; key_num<=to_key; key_num++)
if(key[key_num] != last_key[key_num]) {
key_countdown[key_num] = MAX_KEY_COUNTDOWN;
key_press_countdown[key_num] = MAX_KEY_PRESS_COUNTDOWN;
}
else {
if(key_countdown[key_num] > 0)
key_countdown[key_num]--;
if(key[key_num]) // key is pressed
if(key_press_countdown[key_num] > 0)
key_press_countdown[key_num]--;
}
}
// Has any floor been called below current one
char is_below(char curr_floor) {
for(ff=curr_floor-1; ff>=0; ff--)
if(floors[ff] > 0)
return ff;
return -1;
}
// Has any floor been called above current one
char is_above(char curr_floor) {
for(ff=curr_floor+1; ff<NUM_FLOORS; ff++)
if(floors[ff] > 0)
return ff;
return -1;
}
// manage key modes
unsigned long modeset[NUM_MODESETS][5] =
{{4, CRGB::Red, CRGB::Yellow, CRGB::Green, CRGB::Blue}, // func keys
{2, CRGB::Black, CRGB::Yellow}, // switches
{2, CRGB::Black, CRGB::Green}, // switches
{2, CRGB::Black, CRGB::Blue}, // switches
{1, CRGB::Black}}; // Floor STOP key
#define MODESET_FUNCKEYS 0
#define MODESET_SWITCHES_1 1
#define MODESET_SWITCHES_2 2
#define MODESET_SWITCHES_3 3
#define MODESET_FLOOR_STOP 4
// set key to next color in given modeset
void next_mode(char key_num, char modeset_num) {
if(mode[modeset_num][key_num] < modeset[modeset_num][0]-1)
mode[modeset_num][key_num]++;
else
mode[modeset_num][key_num] = 0;
}
void switch_mode_while_visible(char key_num, char modeset_num) { // used by bell key
// Switch mode only if pressed while lit.
if(last_key[key_num] != key[key_num] && // just pressed or released
key_press_countdown[key_num] > 0) // and no long press
if(key_countdown[key_num] > 0) { // and did not sleep at the moment
next_mode(key_num, modeset_num);
}
}
void switch_mode(char key_num, char modeset_num) { // used by all except bell key
if(last_key[key_num] != key[key_num] && // just pressed or released
key_press_countdown[key_num] > 0) { // and no long press
next_mode(key_num, modeset_num);
}
}
void handle_queue(char key_num, char modeset_num) { // used by individual digit keys
if(last_key[key_num] != key[key_num] && // just pressed or released
key_press_countdown[key_num] > 0) { // and no long press
// Update queue of shift register pins events
if(mode[modeset_num][KEY_STOP]) // key stop is active
if(key_num >= KEY_DIGIT_MIN && key_num <= KEY_DIGIT_MAX) { // number keys only
if(mode[modeset_num][key_num]) {
add_to_queue(key_num-1, ENERGIZE_DURATION, 1, 1, 1); // bit_num, duration, exclusive, polarity, energize
last_active_modeset_num = modeset_num;
}
else
add_to_queue(key_num-1, ENERGIZE_DURATION, 1, 0, 1);
}
}
}
void all_digits_off() {
for(unsigned char ff = KEY_DIGIT_MIN; ff<=KEY_DIGIT_MAX; ff++) {
if(mode[last_active_modeset_num][ff])
add_to_queue(ff-KEY_DIGIT_MIN, ENERGIZE_DURATION, 1, 0, 1);
}
mode[last_active_modeset_num][KEY_STOP] = 0; // turn off STOP key in last modeset
}
void handle_queue_bulk(char key_num, char modeset_num) { // used by stop key
if(last_key[key_num] != key[key_num] && // just pressed or released
key_press_countdown[key_num] > 0) { // and no long press
if(last_active_modeset_num != modeset_num)
all_digits_off();
// Update queue with all digits ON if key STOP is pressed
for(unsigned char ff = KEY_DIGIT_MIN; ff<=KEY_DIGIT_MAX; ff++) {
if(mode[modeset_num][ff])
add_to_queue(ff-KEY_DIGIT_MIN, ENERGIZE_DURATION, 1, mode[modeset_num][KEY_STOP], 1);
if(mode[modeset_num][KEY_STOP])
last_active_modeset_num = modeset_num;
}
}
}
void handle_long_press(char key_num, char modeset_num) { // used by stop key
if(key_press_countdown[key_num] == 0) { // long pressed
key_press_countdown[key_num] = -1; // avoid reexecution at the next tick
// Update all digits to ON or OFF if key STOP is pressed long
for(unsigned char ff = KEY_DIGIT_MIN; ff<=KEY_DIGIT_MAX; ff++) {
if(mode[modeset_num][KEY_STOP] != mode[modeset_num][ff]) {
// update to mode of the stop key
next_mode(ff, modeset_num);
add_to_queue(ff-KEY_DIGIT_MIN, ENERGIZE_DURATION, 1, mode[modeset_num][KEY_STOP], 1);
if(mode[modeset_num][KEY_STOP])
last_active_modeset_num = modeset_num;
}
}
}
}
// handle pressed keys
void manage_key_mode(char modeset_num) {
if(key[KEY_BELL])
switch_mode_while_visible(KEY_BELL, modeset_num);
if(key[KEY_P]) {
switch_mode(KEY_P, modeset_num);
}
if(key[KEY_STOP]) {
//switch_mode(KEY_STOP, modeset_num); // just pressed
//handle_queue_bulk(KEY_STOP, modeset_num); // just pressed
handle_long_press(KEY_STOP, modeset_num);
} else {
switch_mode(KEY_STOP, modeset_num); // just released
handle_queue_bulk(KEY_STOP, modeset_num); // just released
}
for(key_num=KEY_DIGIT_MIN; key_num<=KEY_DIGIT_MAX; key_num++) {
if(key[key_num]) {
switch_mode(key_num, modeset_num);
handle_queue(key_num, modeset_num);
}
}
}
void display_based_on_floor(char from_key, char to_key) {
for(key_num=from_key; key_num<=to_key; key_num++)
if(key_num == curr_floor) {
if(blink_state && sleep_countdown)
leds[keymap[key_num]] = CRGB::Red;
else
leds[keymap[key_num]] = CRGB::Black;
if(sleep_countdown)
leds[keymap[key_num]] = (((long)blink_countdown * 256) / BLINK_TIME) << 16;
}
else {
if(floors[key_num] > 0)
leds[keymap[key_num]] = CRGB::White;
else
leds[keymap[key_num]] = CRGB::Black;
}
}
void display_based_on_mode(char from_led, char to_led, char modeset_num, char key_p_state) {
// lit up the right mode if recently pressed; turn off if slept long
char led_num;
for(led_num=from_led; led_num <= to_led; led_num++) {
if(led_num == 0)
key_num = KEY_P;
else
if(led_num == 11)
key_num = KEY_STOP;
else
if(led_num == 12)
key_num = KEY_BELL;
else
// digit keys
key_num = led_num + key_p_state * 10;
if(key_num == KEY_BELL) {
if(key_countdown[key_num] > 0)
leds[keymap[key_num]] = modeset[modeset_num][mode[modeset_num][key_num]+1];
else
leds[keymap[key_num]] = CRGB::Black;
}
else
leds[keymap[key_num]] = modeset[modeset_num][mode[modeset_num][key_num]+1];
}
}
void dim_turned_off_by_group(char driver_key_mode, char from_key, char to_key) {
for(key_num=from_key; key_num <= to_key; key_num++) {
if(driver_key_mode == CRGB::Black) {
leds[keymap[key_num]] = modeset[modeset_num][mode[modeset_num][key_num]];
}
else
leds[keymap[key_num]].setRGB(((CRGB)modeset[modeset_num][mode[modeset_num][key_num]]).r / 2,
((CRGB)modeset[modeset_num][mode[modeset_num][key_num]]).g / 2,
((CRGB)modeset[modeset_num][mode[modeset_num][key_num]]).b / 2);
}
}
/* SPEAK QUEUE */
#define MAX_SPK 400 // 512
unsigned char spk_len[MAX_SPK] = {
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7,
5, // 46 wynosza
5, // 47 ma przy sobie
5, 15, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
3, // 75 i
3, // 76 oraz
5, 5, 5, 7, 7, 7, 5, 5, 5, 5, 5, 5,
21, // 89 donos do GRU - pietro zawiera
21, // 90 mdleje na widok 11 pietra
21, // 91 mowi, ze istnieje 11 pietro
19, // 92 musi poczekac
19, // 93 musza poczekac
26, // 94 smutni raportuja utrudnienia
35, // 95 dobra zmiana ignor limitow
6, // 96 niestety
6, // 97 wyprowadzaja
5, 5,
5, 5, 5, 5, // 100-103 Ania
6, 6, 5, 5, // 104-107 Gosia
4, 4, 5, 4, // 108-111 Rysiu
5, 5, 5, 5, // 112-115 Agnieszka
3, 3, 5, 3, // 116-119 Jozef
4, 4, 4, 4, // Julia
5, 5, 5, 5, // Kasia
6, 6, 7, 6, // 128-131 Krzysztof
5, 5, 5, 5, // 132-135 Lena
4, 4, 6, 5, // 136-139 Lukasz
4, 4, 5, 4, // 140-143 Marcin
5, 5, 5, 5, // 144-147 Mariola
4, 4, 5, 4, // 148-151 Michal
3, 3, 5, 3, // 152-155 Piotr
4, 4, 5, 4, // 156-159 Rafal
5, 5, 5, 5, // 160-163 Jola
5, 5, 5, 5, // 164-167 Sowa
5, 5, 5, 5, // 168-171 Wladek
5, 5, 5, 5, // 172-175 Zosia
5, 5, 5, 5, // 176-179 Nastka
5, 5, 5, 5, // 180-183 Asia
5, 5, 5, 5, // 184-187 Majka
5, 5, 5, 5, // 188-191 Ela
7, 7, 7, 7, // 192-195 Grupa smutnych panow
9, 9, 10, 10, // 196-199 Srebrny deweloper
4, 4, 4, 4, // 200-203 Anuszka
6, 6, 6, 6, // 204-207 Malgorzata
8, 8,10,10, // 208-211 Kot Behemot
6, 6, 8, 7, // 212-215 Woland
13, 13, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
35, // 228 musi wyjsc z windy
35, // 229 musza wyjsc z windy
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7, 7, 8, 8, // 300-303 Olej slonecznikowy
5, 5, 5, 5, // 304-307 Dlugopis
5, 5, 5, 5, // 308-311 Rekopis
4, 4, 4, 4, // 312-315 Frytki
4, 4, 4, 4, // 316-319 Gwozdz
4, 4, 4, 4, // 320-323 Kartka
5, 5, 5, 5, //
5, 5, 5, 5, // 328-331 Klucz
5, 5, 5, 5, // 332-335 Kwiat
3, 3, 3, 3, // 336-339 List
4, 4, 4, 4, // 340-343 Mlotek
5, 5, 5, 5, // 344-347 Nasionko
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
8, 8, 8, 8, // 360-363 przepis na piwo
5, 5, 5, 5,
5, 5, 5, 5,
6, 6, 6, 6, // Worek ziemniakow
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5
}; // 5 = 500 ms
#define MAX_SPK_QUEUE 30
int spk_que[MAX_SPK_QUEUE];
unsigned char spk_que_len = 0;
//long spk_que_pos = 0;
long spk_countdown = -1;
void add_spk(int spk_num) {
if(spk_que_len < MAX_SPK_QUEUE - 1) {
spk_que[spk_que_len] = spk_num;
spk_que_len++;
}
}
// change latest added spk, if any
void chg_spk(int spk_num) {
if(spk_que_len > 0) {
spk_que[spk_que_len-1] = spk_num;
}
}
void say_num(long num) {
char buf[15];
sprintf(buf, "%ld", num);
for(char ff=0; ff<strlen(buf); ff++) {
wtv020sd16p.asyncPlayVoice(buf[ff] - '0' + 10);
delay(1000);
}
}
void spk_que_tick() {
int spk;
if(spk_que_len > 0 && spk_countdown == -1)
spk_countdown = 0;
if(spk_countdown == 0) {
//wtv020sd16p.asyncPlayVoice(2);
if(0 < spk_que_len) {
spk = spk_que[0];
spk_countdown = spk_len[ spk ] * 100;
/*
if(spk_que[0] == 212 || spk_que[0] == 213) {
say_num(spk_len[spk]);
wtv020sd16p.asyncPlayVoice(104);
delay(100);
say_num(spk_len[213]);
wtv020sd16p.asyncPlayVoice(104);
delay(100);
say_num(spk_countdown);
}
*/
wtv020sd16p.asyncPlayVoice(spk_que[0]);
memmove(&spk_que[0], &spk_que[1], sizeof(spk_que[1])*(spk_que_len-1)); // thanks to this line spk_qie_pos is always 0
spk_que_len--;
//spk_que_pos++;
} else {
//wtv020sd16p.stopVoice();
spk_countdown = -1; // don't get in here again until spk_que_len gets > 0
}
} else {
if(spk_countdown > 0)
spk_countdown--;
}
}
char is_speaking() {
return (spk_que_len > 0 || spk_countdown > 0);
}
/* END of SPEAK QUEUE */
/* LIFT WORLD SIMULATION */
#define NUM_ITEMS 21
#define NUM_PERSONS 29
//#define NUM_FLOORS 13 // 0 ground (P), 1..10 floors, 11 mystery floor, 12 lift cabin
#define PLACE_GROUND_FLOOR 0
#define PLACE_MYSTERY_FLOOR 11
#define PLACE_CABIN 12
// item levels, lower level item can hold higher level item
#define LVL_1 0x40 // 0100 0000
#define LVL_2 0x80 // 1000 0000
#define LVL_3 0xC0 // 1100 0000
// plot specific parameters
#define PERSON_ANIA 0
#define PERSON_ANUSZKA 25
#define PERSON_GOSIA 1
#define PERSON_MALGORZATA 26
#define PERSON_RYSIU 2
#define PERSON_KOT_BEHEMOT 27
#define PERSON_WOLAND 28
#define PERSON_WLADEK 17
#define PERSON_SPY PERSON_WLADEK
#define PERSON_SMUTNI 23
#define PERSON_SREBRNY 24
#define ITEM_OLEJ_SLONECZNIKOWY 0
#define ITEM_WYROK 20 // !!! 20 to zegarek, chwilowo uzyty jako wezwanie
#define ITEM_NAKAZ 22
#define ITEM_WEZWANIE 23
char person_spy = PERSON_SPY;
#define ALT_FLOOR_ANNOUNCEMENTS 0 // anuszka starts announcements
#define ANUSZKA_BROKE_OIL 1
#define ANUSZKA_BROKE_OIL_SILENT 2
#define LIMITS_APPLY_FLAG 3 // people dont go overboard
//char alt_floor_announcements = 0;
//char anuszka_broke_oil = 0;
unsigned long plot_flags = 0;
unsigned long nuts_person_flags = 0;
unsigned long unhappy_person_flags = 0;
unsigned long rejected_person_flags = 0;
unsigned long targeted_person_flags = 0;
void set_plot_flag(unsigned long *flags, char flag_num) {
unsigned long mask = 1;
*flags |= mask << flag_num;
}
void clear_plot_flag(unsigned long *flags, char flag_num) {
unsigned long mask = 1;
*flags &= ((mask << flag_num) ^ 0xFFFF);
}
char is_plot_flag(unsigned long *flags, char flag_num) {
unsigned long mask = 1;
return ((*flags & (mask << flag_num)) > 0); // return exactly 1 or 0
}
char num_set_flags(unsigned long *flags) {
unsigned long mask = 1;
char flag_count = 0;
for(char ff = 0; ff < 32; ff++) {
if(*flags & mask) {
flag_count++;
}
mask <<= 1;
}
return flag_count;
}
// returns number of n-th flag being set (least significant bit first)
// n starting from 0
// returns 0 if first bit is set or if none is; works exactly as array
// so make sure to call only if you know any bits are set
char next_set_flag(unsigned long *flags, char n) {
unsigned long mask = 1;
char flag_count = 0;
for(char ff = 0; ff < 32; ff++) {
if(*flags & mask) {
if(flag_count == n)
return ff;
flag_count++;
}
mask <<= 1;
}
return 0;
}
// who/what is where
char lift_obj[NUM_PERSONS + NUM_ITEMS] =
{
// persons
0, // person 0 Ania is on floor 0
3, // person 1 Gosia is on floor 3
2, // person 2 Rysiu is on floor 3
9, // person 3 Agnieszka
4, // person 4 Jozef
5, // person 5 Julia
6, // person 6 Kasia
7, // person 7 Krzysztof
8, // person 8 Lena
9, // person 9 Lukasz
7, // person 10 Marcin
8, // person 11 Mariola
6, // person 12 Michał
7, // person 13 Piotr
8, // person 14 Rafal
3, // person 15 Jola
2, // person 16 Sowa
3, // person 17 Wladek
4, // person 18 Zosia
5, // person 19 Nastka
6, // person 20 Asia
10, // person 21 Majka
1, // person 22 Ela
0, // person 23 Grupa smutnych panow
10, // person 24 Srebrny deweloper
11, // person 25 Anuszka
11, // person 26 Malgorzata
11, // person 27 Kot Behemot
11, // person 28 Woland
// items
LVL_1 + 0, // item 0 olej slonecznikowy is on 0th floor
LVL_1 + NUM_FLOORS + 1, // item 1 dlugopis is on person 1 Gosia
LVL_1 + NUM_FLOORS + NUM_PERSONS + 5, // item 2 rekopis is on item 5 kartka
LVL_2 + NUM_FLOORS + NUM_PERSONS + 18, // item 3 frytki is on item 18 worek ziemniakow
LVL_1 + 0, // item 4 gwozdz is on ground floor
LVL_1 + NUM_FLOORS + 1, // item 5 kartka is on person 1 Gosia
LVL_1 + NUM_FLOORS + NUM_PERSONS + 17, // item 6 konstytucja is on item 17 szkatulka
LVL_1 + NUM_FLOORS + 5, // item 7 klucz is on 5th person Julia
LVL_1 + NUM_FLOORS + NUM_PERSONS + 11, // item 8 kwiat is in item 11 nasionko
LVL_1 + NUM_FLOORS + 2, // item 9 list is on 2nd person
LVL_1 + NUM_FLOORS + 5, // item 10 mlotek is on person 5 Julia
LVL_1 + 0, // item 11 nasionko is on ground_floor
LVL_1 + 1, // item 12 noz is on 1st floor
LVL_1 + 2, // item 13 okulary is on 2nd floor
LVL_1 + 3, // item 14 pierscionek is on 3rd floor
LVL_1 + NUM_FLOORS + 4, // item 15 przepis na piwo is on person 4 Jozef
LVL_1 + 5, // item 16 ramka is on 5th floor
LVL_1 + 6, // item 17 szkatulka is on 6th floor
LVL_1 + 0, // item 18 worek ziemniakow is on 0th floor
LVL_1 + 8, // item 19 zdjecie is on 8th floor
LVL_1 + NUM_FLOORS + PERSON_SMUTNI // item 20 zegarek is on person smutni panowie
// nakaz aresztowania
// wezwanie
//
};
char people_on_board;
char max_people_on_board;
char hospitalized_person;
char removed_person = -1;
char rozsadek_rzadu = 3; // !!! make it bigger; declines with rejections of smutni
char smutni_target = -1; // noone on target
//char exiting[NUM_PERSONS];
char ex_count;
unsigned long exiting_flags = 0;
// uses curr_floor
void exit_lift(char person) {
lift_obj[person] = curr_floor;
//exiting[ex_count] = person;
set_plot_flag(&exiting_flags, person);
ex_count++;
people_on_board--;
}
char forced_ex_count = 0;
unsigned long forced_exiting_flags = 0;
void force_exit_lift(char person) {
lift_obj[person] = curr_floor;
//exiting[ex_count] = person;
set_plot_flag(&forced_exiting_flags, person);
forced_ex_count++;
people_on_board--;
}
void move_person_by_stairs(char person, char to_floor) {
// ignore if person is not on real floor (dont move her from cabin)
if(lift_obj[person] >= PLACE_CABIN)
return;
lift_obj[person] = to_floor;
}
void move_item_floor_to_floor(char item, char to_floor) {
// ignore if item is in cabin or on person
if((lift_obj[NUM_PERSONS + item] & 0x3F) >= PLACE_CABIN)
return;
lift_obj[NUM_PERSONS + item] =
(lift_obj[NUM_PERSONS + item] & 0xC0) + to_floor;
}
// uses curr_floor
void hospitalize(char person) {
lift_obj[person] = -1;
hospitalized_person = person;
people_on_board--;
}
char is_guilty(char person) {
if(is_item_on_person(NUM_PERSONS + ITEM_WYROK) == person+1)
return ITEM_WYROK;
if(is_item_on_person(NUM_PERSONS + ITEM_NAKAZ) == person+1)
return ITEM_NAKAZ;
if(is_item_on_person(NUM_PERSONS + ITEM_WEZWANIE) == person+1)
return ITEM_WEZWANIE;
return 0;
}
void remove_person(char person) {
lift_obj[person] = -2;
removed_person = person;
people_on_board--;
smutni_target = -1;
drop_items(person);
}
// sentence modifiers
#define MIANOWNIK_UP 0
#define MIANOWNIK_DOWN 1
#define CELOWNIK_PERSONS 2
#define BIERNIK_PERSONS 3
#define BIERNIK_UP_ITEMS 2
#define BIERNIK_DOWN_ITEMS 3
#define MSG_OFFS_PLACES 50
#define MSG_OFFS_PERSONS 100 // 0 M/, 1 M\, 2 C
#define MSG_OFFS_ITEMS 300
#define MSG_ALT_FLOOR_ANUSZKA 12 // alternative floor announcements
// general sentences
#define MSG_I 75
#define MSG_ORAZ 76
#define MSG_LIFT_FALLING_SCREAM_3 77 // there are three consecutive, replaceable msgs
#define MSG_DOOR_OPEN_2 80 // there are two consecutive msgs
#define MSG_DOOR_CLOSE 82
#define MSG_LIFT_RUNNING 83
#define MSG_LIFT_RUNNING_OVERWEIGHT 84
#define MSG_LIFT_DECELERATING 85
#define MSG_LIFT_DECELERATING_OVERWEIGHT 86
#define MSG_CRASH_2 87
// specific sentences
#define MSG_WSIADA 42
#define MSG_WSIADAJA 43
#define MSG_Z_WINDY_WYSIADA 44
#define MSG_Z_WINDY_WYSIADAJA 45
#define MSG_WYNOSZA 46
#define MSG_OWNS 47
#define MSG_JESTES_U_CELU 48
#define MSG_ANUSZKA_ROZLALA_OLEJ 49
#define MSG_FLOOR_CONTAINS 89
#define MSG_SHOCKED_DICOVERY_MYSTERY_FLOOR 90 // !!! dodac "mdleje na widok nieznanego piętra"
#define MSG_SAYS_MYSTERY_FLOOR_EXISTS 91 // !!! dodac "mówi, ze istnieje tajemne pietro"
#define MSG_NIE_WPUSZCZONY 92
#define MSG_NIE_WPUSZCZENI 93
#define MSG_SMUTNI_RAPORTUJA_UTRUDNIENIA 94
#define MSG_DOBRA_ZMIANA_IGNOR_LIMITOW 95
#define MSG_NIESTETY 96
#define MSG_WYPROWADZAJA 97
#define MSG_HANDING 98
#define MSG_SMUTNI_CHCA_ZNALEZC 99
#define MSG_MUSI_WYJSC 228
#define MSG_MUSZA_WYJSC 229
void communicate_exits() {
char ff;
if(hospitalized_person > -1) {
add_spk(MSG_WYNOSZA);
add_spk(MSG_OFFS_PERSONS + hospitalized_person * 4 + BIERNIK_PERSONS);
}
if(removed_person > -1) {
add_spk(MSG_WYPROWADZAJA);
add_spk(MSG_OFFS_PERSONS + removed_person * 4 + BIERNIK_PERSONS);
}
if(ex_count == 0)
return;
if(ex_count == 1) {
add_spk(MSG_Z_WINDY_WYSIADA);
//add_spk(MSG_OFFS_PERSONS + exiting[0] * 4 + MIANOWNIK_DOWN);
add_spk(MSG_OFFS_PERSONS + next_set_flag(&exiting_flags, 0) * 4 + MIANOWNIK_DOWN);
}
else {
add_spk(MSG_Z_WINDY_WYSIADAJA);
for(ff=0; ff<ex_count-1; ff++) {
//add_spk(MSG_OFFS_PERSONS + exiting[ff] * 4 + MIANOWNIK_UP);
add_spk(MSG_OFFS_PERSONS + next_set_flag(&exiting_flags, ff) * 4 + MIANOWNIK_UP);
}
add_spk(MSG_I + random(2));
//add_spk(MSG_OFFS_PERSONS + exiting[ff] * 4 + MIANOWNIK_DOWN);
add_spk(MSG_OFFS_PERSONS + next_set_flag(&exiting_flags, ff) * 4 + MIANOWNIK_DOWN);
}
}
//char entering[NUM_PERSONS];
char ent_count;
unsigned long entering_flags = 0;
void enter_lift(char person) {
lift_obj[person] = PLACE_CABIN;
// register action for further communication
//entering[ent_count] = person;
set_plot_flag(&entering_flags, person);
ent_count++;
people_on_board++;
}
void communicate_entries() {
char ff;
if(ent_count == 0)
return;
if(ent_count == 1) {
add_spk(MSG_WSIADA);
//add_spk(MSG_OFFS_PERSONS + entering[0] * 4 + MIANOWNIK_DOWN);
add_spk(MSG_OFFS_PERSONS + next_set_flag(&entering_flags, 0) * 4 + MIANOWNIK_DOWN);
}
else {
add_spk(MSG_WSIADAJA);
for(ff=0; ff<ent_count-1; ff++) {
//add_spk(MSG_OFFS_PERSONS + entering[ff] * 4 + MIANOWNIK_UP);
add_spk(MSG_OFFS_PERSONS + next_set_flag(&entering_flags, ff) * 4 + MIANOWNIK_UP);
}
add_spk(MSG_I + random(2));
//add_spk(MSG_OFFS_PERSONS + entering[ff] * 4 + MIANOWNIK_DOWN);
add_spk(MSG_OFFS_PERSONS + next_set_flag(&entering_flags, ff) * 4 + MIANOWNIK_DOWN);
}
}
char picking[NUM_ITEMS];
char picked[NUM_ITEMS];
char pick_count;
// have person take item from place where she stands
void pick_item(char person, char item_idx) {
char item_desc = (lift_obj[item_idx] & 0xC0);
lift_obj[item_idx] = NUM_FLOORS + item_desc + person; // move the item to person (person 0 idx in lift_obj[] == NUM_FLOORS)
// register action for further communication
picking[pick_count] = person;
picked[pick_count] = item_idx;
pick_count++;
}
char dropping[NUM_ITEMS];
char dropped[NUM_ITEMS];
char drop_count;
// have person drop item to the place the person is in and register the action
void drop_item(char item_idx) {
// assume it's never called if item is not on person
char person_holding_item = (lift_obj[item_idx] & 0x3F) - NUM_FLOORS;
char person_location = (lift_obj[ person_holding_item ] & 0x3F);
char item_desc = (lift_obj[item_idx] & 0xC0);
lift_obj[item_idx] = item_desc + person_location; // move the item to floor idx
// register action for further communication
dropping[drop_count] = person_holding_item;
dropped[drop_count] = item_idx;
drop_count++;
}
void drop_items(char person) {
for(char ff = NUM_PERSONS; ff < NUM_PERSONS + NUM_ITEMS; ff++) {
if(is_item_on_person(ff) == person+1)
drop_item(ff);
}
}
char handing[NUM_ITEMS]; // osoba która daje
char handed[NUM_ITEMS]; // dawany przedmiot
char receiver[NUM_ITEMS]; // osoba która dostaje
char hand_count;
char hand_item_to_other_person(char item_idx, char other_person) {
// assume it's never called if item is not on person
char person_holding_item = (lift_obj[item_idx] & 0x3F) - NUM_FLOORS;
char item_desc = (lift_obj[ item_idx ] & 0xC0);
lift_obj[item_idx] = NUM_FLOORS + item_desc + other_person; // move the item to person
// register action for further communication
handing[hand_count] = person_holding_item;
handed[hand_count] = item_idx - NUM_PERSONS;
receiver[hand_count] = other_person;