forked from lincomatic/open_evse
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathopen_evse.pde
3734 lines (3365 loc) · 94.5 KB
/
open_evse.pde
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
// -*- C++ -*-
/*
* Open EVSE Firmware
*
* Copyright (c) 2011-2013 Sam C. Lin <[email protected]>
* Copyright (c) 2011-2013 Chris Howell <[email protected]>
* timer code Copyright (c) 2013 Kevin L <[email protected]>
* Maintainers: SCL/CH
Revised Ver By Reason
6/21/13 20b3 Scott Rubin fixed LCD display bugs with RTC enabled
6/25/13 20b4 Scott Rubin fixed LCD display bugs, CLI fixes, when RTC disabled
6/30/13 20b5 Scott Rubin added LcdDetected() function, prevents hang if LCD not installed
7/06/13 20b5 Scott Rubin rewrote power detection in POST function for 1 or 2 relays
7/11/13 20b5 Scott Rubin skips POST if EV is connected, won't charge if open ground or stuck relay
8/12/13 20b5b Scott Rubin fix GFI error - changed gfi.Reset() to check for constant GFI signal
8/26/13 20b6 Scott Rubin add Stuck Relay State delay, fix Stuck Relay state exit (for Active E)
9/20/13 20b7 Chris Howell updated/tweaked/shortened CLI messages
* This file is part of Open EVSE.
* Open EVSE 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, or (at your option)
* any later version.
* Open EVSE 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 Open EVSE; see the file COPYING. If not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <EEPROM.h>
#include <avr/wdt.h>
#include <avr/pgmspace.h>
#include <pins_arduino.h>
#include <Wire.h>
#include <RTClib.h>
#include <FlexiTimer2.h> // Required for RTC and Delay Timer
#include <Time.h>
#if defined(ARDUINO) && (ARDUINO >= 100)
#include "Arduino.h"
#else
#include "WProgram.h" // shouldn't need this but arduino sometimes messes up and puts inside an #ifdef
#endif // ARDUINO
prog_char VERSTR[] PROGMEM = "2.0.0";
//-- begin features
// enable watchdog timer
//#define WATCHDOG
// GFI support
#define GFI
// serial port command line
// For the RTC version, only CLI or LCD can be defined at one time.
// There is a directive to take care of that if you forget.
#define SERIALCLI
//Adafruit RGBLCD
#define RGBLCD
// Adafruit LCD backpack in I2C mode
//#define I2CLCD
// White LCD - define all colors as white
//#define WHITELCD
// Advanced Powersupply... Ground check, stuck relay, L1/L2 detection.
#define ADVPWR
// single button menus (needs LCD enabled)
// connect an SPST button between BTN_PIN and GND or enable ADAFRUIT_BTN to use the
// select button of the Adafruit RGB LCD
// How to use 1-button menu
// Long press activates menu
// When within menus, short press cycles menu items, long press selects and exits current submenu
#define BTN_MENU
// When not in menus, short press instantly stops the EVSE - another short press resumes. Long press activates menus
// also allows menus to be manipulated even when in State B/C
#define BTN_ENABLE_TOGGLE
#ifdef BTN_MENU
// use Adafruit RGB LCD select button
#ifdef RGBLCD
#define ADAFRUIT_BTN
#endif // RGBLCD
#endif // BTN_MENU
// Option for RTC and DelayTime
//#define RTC // enable RTC & timer functions
#ifdef RTC
// Option for Delay Timer - GoldServe
#define DELAYTIMER
// Option for AutoStart Enable/Disable - GoldServe
#define MANUALSTART
// Option for AutoStart Menu. If defined, ManualStart feature is also defined by default - GoldServe
//#define AUTOSTART_MENU
// AutoStart feature must be defined if Delay Timers are used - GoldServe
#if defined(DELAYTIMER)||defined(AUTOSTART_MENU)
#define MANUALSTART
#endif
#endif // RTC
// for stability testing - shorter timeout/higher retry count
//#define GFI_TESTING
// phase and frequency correct PWM 1/8000 resolution
// when not defined, use fast PWM -> 1/250 resolution
#define PAFC_PWM
//-- end features
#if defined(RGBLCD) || defined(I2CLCD)
#define LCD16X2
//If LCD is not defined, undef BTN_MENU - requires LCD
#else
#undef BTN_MENU
#endif // RGBLCD || I2CLCD
//If LCD and RTC is defined, un-define CLI so we can save ram space.
#if defined(RTC) && defined(LCD16X2)
#undef SERIALCLI
#endif
//-- begin configuration
#define LCD_MAX_CHARS_PER_LINE 16
// n.b. DEFAULT_SERVICE_LEVEL is ignored if ADVPWR defined, since it's autodetected
#define DEFAULT_SERVICE_LEVEL 2 // 1=L1, 2=L2
// current capacity in amps
#define DEFAULT_CURRENT_CAPACITY_L1 12
#define DEFAULT_CURRENT_CAPACITY_L2 16
// minimum allowable current in amps
#define MIN_CURRENT_CAPACITY 6
// maximum allowable current in amps
#define MAX_CURRENT_CAPACITY_L1 16 // J1772 Max for L1 on a 20A circuit
#define MAX_CURRENT_CAPACITY_L2 80 // J1772 Max for L2
//J1772EVSEController
//#define CURRENT_PIN 0 // analog current reading pin A0
#define VOLT_PIN 1 // analog voltage reading pin A1
#define ACLINE1_PIN 3 // TEST PIN 1 for L1/L2, ground and stuck relay
#define ACLINE2_PIN 4 // TEST PIN 2 for L1/L2, ground and stuck relay
#define RED_LED_PIN 5 // Digital pin
#define CHARGING_PIN2 7 // digital Relay trigger pin for second relay
#define CHARGING_PIN 8 // digital Charging LED and Relay Trigger pin
// N.B. if PAFC_PWM is enabled, then PILOT_PIN can be either 9 or 10
// (i.e PORTB pins 1 & 2)
// if using fast PWM (PAFC_PWM disabled) PILOT_PIN *MUST* be digital 10
// and digital 9 may NOT be used for other purposes
#define PILOT_PIN 10
#define GREEN_LED_PIN 13 // Digital pin
#define SERIAL_BAUD 38400
// EEPROM offsets for settings
#define EOFS_CURRENT_CAPACITY_L1 0 // 1 byte
#define EOFS_CURRENT_CAPACITY_L2 1 // 1 byte
#define EOFS_FLAGS 2 // 1 byte
// EEPROM offsets for Delay Timer function - GoldServe
#define EOFS_TIMER_FLAGS 3 // 1 byte
#define EOFS_TIMER_START_HOUR 4 // 1 byte
#define EOFS_TIMER_START_MIN 5 // 1 byte
#define EOFS_TIMER_STOP_HOUR 6 // 1 byte
#define EOFS_TIMER_STOP_MIN 7 // 1 byte
// must stay within thresh for this time in ms before switching states
#define DELAY_STATE_TRANSITION 250
// must transition to state A from contacts closed in < 100ms according to spec
// but Leaf sometimes bounces from 3->1 so we will debounce it a little anyway
#define DELAY_STATE_TRANSITION_A 25
// for ADVPWR
#define GROUND_CHK_DELAY 1000 // delay after charging started to test, ms
#define STUCK_RELAY_DELAY 1000 // delay after charging opened to test, ms
#define RelaySettlingTime 250 // time for relay to settle in post, ms
#ifdef GFI
#define GFI_INTERRUPT 0 // interrupt number 0 = D2, 1 = D3
#define GFI_PIN 2 // interrupt number 0 = D2, 1 = D3
#ifdef GFI_TESTING
#define GFI_TIMEOUT ((unsigned long)(15*1000))
#define GFI_RETRY_COUNT 255
#else // !GFI_TESTING
#define GFI_TIMEOUT ((unsigned long)(15*60000)) // 15*60*1000 doesn't work. go figure
#define GFI_RETRY_COUNT 3
#endif // GFI_TESTING
#endif // GFI
// for RGBLCD
#define RED 0x1
#define YELLOW 0x3
#define GREEN 0x2
#define BLUE 0x4
#define TEAL 0x6
#define VIOLET 0x5
#define WHITE 0x7
#if defined(RGBLCD) || defined(I2CLCD)
// Using LiquidTWI2 for both types of I2C LCD's
// see http://blog.lincomatic.com/?p=956 for installation instructions
#include <Wire.h>
#include <LiquidTWI2.h>
#define LCD_I2C_ADDR 0x20 // for adafruit shield or backpack
#endif // RGBLCD || I2CLCD
#define BTN_PIN A3 // button sensing pin
#define BTN_PRESS_SHORT 100 // ms
#define BTN_PRESS_LONG 500 // ms
#ifdef RTC
// Default start/stop timers for un-initialized EEPROMs.
// Makes it easy to compile in default time without need to set it up the first time.
#define DEFAULT_START_HOUR 0x00 //Start time: 00:05
#define DEFAULT_START_MIN 0x05
#define DEFAULT_STOP_HOUR 0x06 //End time: 6:55
#define DEFAULT_STOP_MIN 0x37
#endif // RTC
//-- end configuration
//-- begin class definitions
#ifdef SERIALCLI
#define CLI_BUFLEN 20
class CLI {
char m_CLIinstr[CLI_BUFLEN]; // CLI byte being read in
int m_CLIstrCount; //CLI string counter
char *m_strBuf;
int m_strBufLen;
void info();
public:
CLI();
void Init();
void println(char *s) {
Serial.println(s);
}
void println_P(prog_char *s);
void print(char *s) {
Serial.print(s);
}
void print_P(prog_char *s);
void printlnn();
void flush() {
Serial.flush();
}
void getInput();
uint8_t getInt();
};
#endif // SERIALCLI
#ifdef LCD16X2
char *g_BlankLine = " ";
#endif // LCD16X2
class OnboardDisplay
{
#if defined(RGBLCD) || defined(I2CLCD)
LiquidTWI2 m_Lcd;
#endif
char m_strBuf[LCD_MAX_CHARS_PER_LINE+1];
public:
OnboardDisplay();
void Init();
void SetGreenLed(uint8_t state);
void SetRedLed(uint8_t state);
#ifdef LCD16X2
void LcdBegin(int x,int y) {
#ifdef I2CLCD
m_Lcd.setMCPType(LTI_TYPE_MCP23008);
m_Lcd.begin(x,y);
m_Lcd.setBacklight(HIGH);
#elif defined(RGBLCD)
m_Lcd.setMCPType(LTI_TYPE_MCP23017);
m_Lcd.begin(x,y,2);
m_Lcd.setBacklight(WHITE);
#endif
}
void LcdPrint(const char *s) {
if (m_Lcd.LcdDetected()) m_Lcd.print(s);
}
void LcdPrint_P(const prog_char *s);
void LcdPrint(int y,const char *s);
void LcdPrint_P(int y,const prog_char *s);
void LcdPrint(int x,int y,const char *s) {
m_Lcd.setCursor(x,y);
if (m_Lcd.LcdDetected()) m_Lcd.print(s);
}
void LcdPrint_P(int x,int y,const prog_char *s);
void LcdPrint(int i) {
if (m_Lcd.LcdDetected()) m_Lcd.print(i);
}
void LcdSetCursor(int x,int y) {
m_Lcd.setCursor(x,y);
}
void LcdClearLine(int y) {
m_Lcd.setCursor(0,y);
if (m_Lcd.LcdDetected()) m_Lcd.print(g_BlankLine);
}
void LcdClear() {
m_Lcd.clear();
}
void LcdWrite(uint8_t data) {
m_Lcd.write(data);
}
void LcdMsg(const char *l1,const char *l2);
void LcdMsg_P(const prog_char *l1,const prog_char *l2);
void LcdSetBacklightColor(uint8_t c) {
#ifdef RGBLCD
m_Lcd.setBacklight(c);
#endif // RGBLCD
}
#ifdef RGBLCD
uint8_t readButtons() { return m_Lcd.readButtons(); }
#endif // RGBLCD
#endif // LCD16X2
void Update();
};
#ifdef GFI
class Gfi {
uint8_t m_GfiFault;
public:
Gfi() {}
void Init();
void Reset();
void SetFault() { m_GfiFault = 1; }
uint8_t Fault() { return m_GfiFault; }
};
#endif // GFI
typedef enum {
PILOT_STATE_P12,PILOT_STATE_PWM,PILOT_STATE_N12}
PILOT_STATE;
class J1772Pilot {
#ifndef PAFC_PWM
uint8_t m_bit;
uint8_t m_port;
#endif // PAFC_PWM
PILOT_STATE m_State;
public:
J1772Pilot() {
}
void Init();
void SetState(PILOT_STATE pstate); // P12/N12
PILOT_STATE GetState() {
return m_State;
}
int SetPWM(int amps); // 12V 1KHz PWM
};
// EVSE states for m_EvseState
#define EVSE_STATE_UNKNOWN 0x00
#define EVSE_STATE_A 0x01 // vehicle state A 12V - not connected
#define EVSE_STATE_B 0x02 // vehicle state B 9V - connected, ready
#define EVSE_STATE_C 0x03 // vehicle state C 6V - charging
#define EVSE_STATE_D 0x04 // vehicle state D 3V - vent required
#define EVSE_STATE_DIODE_CHK_FAILED 0x05 // diode check failed
#define EVSE_STATE_GFCI_FAULT 0x06 // GFCI fault
#define EVSE_STATE_NO_GROUND 0x07 //bad ground
#define EVSE_STATE_STUCK_RELAY 0x08 //stuck relay
#define EVSE_STATE_DISABLED 0xff // disabled
typedef struct threshdata {
uint16_t m_ThreshAB; // state A -> B
uint16_t m_ThreshBC; // state B -> C
uint16_t m_ThreshCD; // state C -> D
uint16_t m_ThreshD; // state D
uint16_t m_ThreshDS; // diode short
} THRESH_DATA,*PTHRESH_DATA;
typedef struct calibdata {
uint16_t m_pMax;
uint16_t m_pAvg;
uint16_t m_pMin;
uint16_t m_nMax;
uint16_t m_nAvg;
uint16_t m_nMin;
} CALIB_DATA,*PCALIB_DATA;
// J1772EVSEController m_bFlags bits - saved to EEPROM
#define ECF_L2 0x01 // service level 2
#define ECF_DIODE_CHK_DISABLED 0x02 // no diode check
#define ECF_VENT_REQ_DISABLED 0x04 // no vent required state
#define ECF_GND_CHK_DISABLED 0x08 // no chk for ground fault
#define ECF_STUCK_RELAY_CHK_DISABLED 0x10 // no chk for stuck relay
#define ECF_AUTO_SVC_LEVEL_DISABLED 0x20 // auto detect svc level - requires ADVPWR
// Ability set the EVSE for manual button press to start charging - GoldServe
#define ECF_AUTO_START_DISABLED 0x40 // no auto start charging
#define ECF_SERIAL_DBG 0x80 // enable debugging messages via serial
#define ECF_DEFAULT 0x00
// J1772EVSEController volatile m_bVFlags bits - not saved to EEPROM
#define ECVF_NOGND_TRIPPED 0x20 // no ground has tripped at least once
#define ECVF_CHARGING_ON 0x40 // charging relay is closed
#define ECVF_GFI_TRIPPED 0x80 // gfi has tripped at least once
#define ECVF_DEFAULT 0x00
class J1772EVSEController {
J1772Pilot m_Pilot;
#ifdef GFI
Gfi m_Gfi;
unsigned long m_GfiTimeout;
unsigned long m_GfiRetryCnt;
uint8_t m_GfiTripCnt;
#endif // GFI
#ifdef ADVPWR
unsigned long m_NoGndTimeout;
unsigned long m_NoGndRetryCnt;
uint8_t m_NoGndTripCnt;
unsigned long m_StuckRelayStartTimeMS;
uint8_t StuckRelayTripCnt;
#endif // ADVPWR
uint8_t m_bFlags; // ECF_xxx
uint8_t m_bVFlags; // ECVF_xxx
THRESH_DATA m_ThreshData;
uint8_t m_EvseState;
uint8_t m_PrevEvseState;
uint8_t m_TmpEvseState;
unsigned long m_TmpEvseStateStart;
uint8_t m_CurrentCapacity; // max amps we can output
unsigned long m_ChargeStartTimeMS;
unsigned long m_ChargeOffTimeMS;
time_t m_ChargeStartTime;
time_t m_ChargeOffTime;
time_t m_ElapsedChargeTime;
time_t m_ElapsedChargeTimePrev;
#ifdef ADVPWR
// Define the Power states read from the L1 and L2 test lines
// 00 = both, 01 = L1on, 10 = L2on, 11 = none ( active low )
enum {both, L1on, L2on, none}
PowerSTATE;
// Define Service States UD = undefined state, L1 = level 1, L2 = level 2, OG = open ground, SR = stuck Relay
enum { UD, L1, L2, OG, SR}
SVCSTATE;
uint8_t doPost();
#endif // ADVPWR
void chargingOn();
void chargingOff();
uint8_t chargingIsOn() { return m_bVFlags & ECVF_CHARGING_ON; }
void setFlags(uint8_t flags) {
m_bFlags |= flags;
}
void clrFlags(uint8_t flags) {
m_bFlags &= ~flags;
}
public:
J1772EVSEController();
void Init();
void Update(); // read sensors
void Enable();
void Disable();
void LoadThresholds();
uint8_t GetFlags() { return m_bFlags; }
uint8_t GetState() {
return m_EvseState;
}
uint8_t GetPrevState() {
return m_PrevEvseState;
}
int StateTransition() {
return (m_EvseState != m_PrevEvseState) ? 1 : 0;
}
uint8_t GetCurrentCapacity() {
return m_CurrentCapacity;
}
int SetCurrentCapacity(uint8_t amps,uint8_t updatepwm=0);
//int GetCurrentReading() { return m_CurrentReading; }
//float GetCurrentAmps();
time_t GetElapsedChargeTime() {
return m_ElapsedChargeTime;
}
time_t GetElapsedChargeTimePrev() {
return m_ElapsedChargeTimePrev;
}
time_t GetChargeOffTime() {
return m_ChargeOffTime;
}
void Calibrate(PCALIB_DATA pcd);
uint8_t GetCurSvcLevel() {
return (m_bFlags & ECF_L2) ? 2 : 1;
}
void SetSvcLevel(uint8_t svclvl);
PTHRESH_DATA GetThreshData() {
return &m_ThreshData;
}
uint8_t DiodeCheckEnabled() {
return (m_bFlags & ECF_DIODE_CHK_DISABLED) ? 0 : 1;
}
void EnableDiodeCheck(uint8_t tf);
uint8_t VentReqEnabled() {
return (m_bFlags & ECF_VENT_REQ_DISABLED) ? 0 : 1;
}
void EnableVentReq(uint8_t tf);
#ifdef ADVPWR
uint8_t GndChkEnabled() {
return (m_bFlags & ECF_GND_CHK_DISABLED) ? 0 : 1;
}
void EnableGndChk(uint8_t tf);
void EnableStuckRelayChk(uint8_t tf);
uint8_t StuckRelayChkEnabled() {
return (m_bFlags & ECF_STUCK_RELAY_CHK_DISABLED) ? 0 : 1;
}
uint8_t AutoSvcLevelEnabled() { return (m_bFlags & ECF_AUTO_SVC_LEVEL_DISABLED) ? 0 : 1; }
void EnableAutoSvcLevel(uint8_t tf);
void SetNoGndTripped();
uint8_t NoGndTripped() { return m_bVFlags & ECVF_NOGND_TRIPPED; }
#endif // ADVPWR
#ifdef GFI
void SetGfiTripped();
uint8_t GfiTripped() { return m_bVFlags & ECVF_GFI_TRIPPED; }
#endif // GFI
uint8_t SerDbgEnabled() {
return (m_bFlags & ECF_SERIAL_DBG) ? 1 : 0;
}
// Function to suppport Auto Start feature - GoldServe
#ifdef MANUALSTART
void EnableAutoStart(uint8_t tf);
uint8_t AutoStartEnabled() {
return (m_bFlags & ECF_AUTO_START_DISABLED) ? 0 : 1;
}
#endif //ifdef MANUALSTART
void EnableSerDbg(uint8_t tf);
};
#ifdef BTN_MENU
#define BTN_STATE_OFF 0
#define BTN_STATE_SHORT 1 // short press
#define BTN_STATE_LONG 2 // long press
class Btn {
uint8_t buttonState;
long lastDebounceTime; // the last time the output pin was toggled
public:
Btn();
void init();
void read();
uint8_t shortPress();
uint8_t longPress();
};
class Menu {
public:
prog_char *m_Title;
uint8_t m_CurIdx;
void init(const char *firstitem);
Menu();
virtual void Init() = 0;
virtual void Next() = 0;
virtual Menu *Select() = 0;
};
class SetupMenu : public Menu {
public:
SetupMenu();
void Init();
void Next();
Menu *Select();
};
class SvcLevelMenu : public Menu {
public:
SvcLevelMenu();
void Init();
void Next();
Menu *Select();
};
class MaxCurrentMenu : public Menu {
uint8_t m_MaxCurrent;
uint8_t m_MaxIdx;
uint8_t *m_MaxAmpsList;
public:
MaxCurrentMenu();
void Init();
void Next();
Menu *Select();
};
class DiodeChkMenu : public Menu {
public:
DiodeChkMenu();
void Init();
void Next();
Menu *Select();
};
class VentReqMenu : public Menu {
public:
VentReqMenu();
void Init();
void Next();
Menu *Select();
};
#ifdef ADVPWR
class GndChkMenu : public Menu {
public:
GndChkMenu();
void Init();
void Next();
Menu *Select();
};
#endif // ADVPWR
class ResetMenu : public Menu {
public:
ResetMenu();
void Init();
void Next();
Menu *Select();
};
#ifdef AUTOSTART_MENU
class AutoStartMenu : public Menu {
public:
AutoStartMenu();
void Init();
void Next();
Menu *Select();
};
#endif //#ifdef AUTOSTART_MENU
#ifdef DELAYTIMER
class RTCMenu : public Menu {
public:
RTCMenu();
void Init();
void Next();
Menu *Select();
};
class RTCMenuMonth : public Menu {
public:
RTCMenuMonth();
void Init();
void Next();
Menu *Select();
};
class RTCMenuDay : public Menu {
public:
RTCMenuDay();
void Init();
void Next();
Menu *Select();
};
class RTCMenuYear : public Menu {
public:
RTCMenuYear();
void Init();
void Next();
Menu *Select();
};
class RTCMenuHour : public Menu {
public:
RTCMenuHour();
void Init();
void Next();
Menu *Select();
};
class RTCMenuMinute : public Menu {
public:
RTCMenuMinute();
void Init();
void Next();
Menu *Select();
};
class DelayMenu : public Menu {
public:
DelayMenu();
void Init();
void Next();
Menu *Select();
};
class DelayMenuEnableDisable : public Menu {
public:
DelayMenuEnableDisable();
void Init();
void Next();
Menu *Select();
};
class DelayMenuStartHour : public Menu {
public:
DelayMenuStartHour();
void Init();
void Next();
Menu *Select();
};
class DelayMenuStartMin : public Menu {
public:
DelayMenuStartMin();
void Init();
void Next();
Menu *Select();
};
class DelayMenuStopHour : public Menu {
public:
DelayMenuStopHour();
void Init();
void Next();
Menu *Select();
};
class DelayMenuStopMin : public Menu {
public:
DelayMenuStopMin();
void Init();
void Next();
Menu *Select();
};
#endif //ifdef DELAYTIMER
class BtnHandler {
Btn m_Btn;
Menu *m_CurMenu;
public:
BtnHandler();
void init() { m_Btn.init(); }
void ChkBtn();
uint8_t InMenu() { return (m_CurMenu == NULL) ? 0 : 1; }
};
prog_char g_psSetup[] PROGMEM = "Setup";
prog_char g_psSvcLevel[] PROGMEM = "Service Level";
prog_char g_psMaxCurrent[] PROGMEM = "Max Current";
prog_char g_psDiodeCheck[] PROGMEM = "Diode Check";
prog_char g_psVentReqChk[] PROGMEM = "Vent Req'd Check";
#ifdef ADVPWR
prog_char g_psGndChk[] PROGMEM = "Ground Check";
#endif // ADVPWR
prog_char g_psReset[] PROGMEM = "Reset";
prog_char g_psExit[] PROGMEM = "Exit";
// Add additional strings - GoldServe
#ifdef AUTOSTART_MENU
prog_char g_psAutoStart[] PROGMEM = "Auto Start";
#endif //#ifdef AUTOSTART_MENU
#ifdef DELAYTIMER
prog_char g_psRTC[] PROGMEM = "Date/Time";
prog_char g_psRTC_Month[] PROGMEM = "Set Month";
prog_char g_psRTC_Day[] PROGMEM = "Set Day";
prog_char g_psRTC_Year[] PROGMEM = "Set Year";
prog_char g_psRTC_Hour[] PROGMEM = "Set Hour";
prog_char g_psRTC_Minute[] PROGMEM = "Set Minute";
prog_char g_psDelayTimer[] PROGMEM = "Delay Timer";
//prog_char g_psDelayTimerEnableDisable[] PROGMEM = "Enable/Disable Timer?";
prog_char g_psDelayTimerStartHour[] PROGMEM = "Set Start Hour";
prog_char g_psDelayTimerStartMin[] PROGMEM = "Set Start Min";
prog_char g_psDelayTimerStopHour[] PROGMEM = "Set Stop Hour";
prog_char g_psDelayTimerStopMin[] PROGMEM = "Set Stop Min";
char *g_sHHMMfmt = "%02d:%02d";
#endif
SetupMenu g_SetupMenu;
SvcLevelMenu g_SvcLevelMenu;
MaxCurrentMenu g_MaxCurrentMenu;
DiodeChkMenu g_DiodeChkMenu;
VentReqMenu g_VentReqMenu;
#ifdef ADVPWR
GndChkMenu g_GndChkMenu;
#endif // ADVPWR
ResetMenu g_ResetMenu;
// Instantiate additional Menus - GoldServe
#ifdef AUTOSTART_MENU
AutoStartMenu g_AutoStartMenu;
#endif //#ifdef AUTOSTART_MENU
#ifdef DELAYTIMER
RTCMenu g_RTCMenu;
RTCMenuMonth g_RTCMenuMonth;
RTCMenuDay g_RTCMenuDay;
RTCMenuYear g_RTCMenuYear;
RTCMenuHour g_RTCMenuHour;
RTCMenuMinute g_RTCMenuMinute;
DelayMenu g_DelayMenu;
DelayMenuEnableDisable g_DelayMenuEnableDisable;
DelayMenuStartHour g_DelayMenuStartHour;
DelayMenuStopHour g_DelayMenuStopHour;
DelayMenuStartMin g_DelayMenuStartMin;
DelayMenuStopMin g_DelayMenuStopMin;
#endif
BtnHandler g_BtnHandler;
#endif // BTN_MENU
// Start Delay Timer class definition - GoldServe
#ifdef DELAYTIMER
class DelayTimer {
uint8_t m_DelayTimerEnabled;
uint8_t m_StartTimerHour;
uint8_t m_StartTimerMin;
uint8_t m_StopTimerHour;
uint8_t m_StopTimerMin;
uint8_t m_CurrHour;
uint8_t m_CurrMin;
uint8_t m_CheckNow;
public:
DelayTimer(){
m_CheckNow = 1; //Check as soon as the EVSE initializes
};
void Init();
void CheckTime();
void CheckNow(){
m_CheckNow = 1;
};
void Enable();
void Disable();
uint8_t IsTimerEnabled(){
return m_DelayTimerEnabled;
};
uint8_t GetStartTimerHour(){
return m_StartTimerHour;
};
uint8_t GetStartTimerMin(){
return m_StartTimerMin;
};
uint8_t GetStopTimerHour(){
return m_StopTimerHour;
};
uint8_t GetStopTimerMin(){
return m_StopTimerMin;
};
void SetStartTimer(uint8_t hour, uint8_t min){
m_StartTimerHour = hour;
m_StartTimerMin = min;
EEPROM.write(EOFS_TIMER_START_HOUR, m_StartTimerHour);
EEPROM.write(EOFS_TIMER_START_MIN, m_StartTimerMin);
SaveSettings();
};
void SetStopTimer(uint8_t hour, uint8_t min){
m_StopTimerHour = hour;
m_StopTimerMin = min;
EEPROM.write(EOFS_TIMER_STOP_HOUR, m_StopTimerHour);
EEPROM.write(EOFS_TIMER_STOP_MIN, m_StopTimerMin);
SaveSettings();
};
uint8_t IsTimerValid(){
if (m_StartTimerHour || m_StartTimerMin || m_StopTimerHour || m_StopTimerMin){ // Check not all equal 0
if ((m_StartTimerHour == m_StopTimerHour) && (m_StartTimerMin == m_StopTimerMin)){ // Check start time not equal to stop time
return 0;
} else {
return 1;
}
} else {
return 0;
}
};
void PrintTimerIcon();
};
#endif
// -- end class definitions
//-- begin global variables
char g_sTmp[64];
THRESH_DATA g_DefaultThreshData = {875,780,690,0,260};
J1772EVSEController g_EvseController;
OnboardDisplay g_OBD;
// Instantiate RTC and Delay Timer - GoldServe
#ifdef DELAYTIMER
RTC_DS1307 g_RTC;
DelayTimer g_DelayTimer;
// Start variables to support RTC and Delay Timer - GoldServe
uint16_t g_year;
uint8_t g_month;
uint8_t g_day;
uint8_t g_hour;
uint8_t g_min;
uint8_t sec = 0;
DateTime g_CurrTime;
#endif
#ifdef SERIALCLI
CLI g_CLI;
prog_char g_psEnabled[] PROGMEM = "enabled";
prog_char g_psDisabled[] PROGMEM = "disabled";
#endif // SERIALCLI
#ifdef LCD16X2
#ifdef ADVPWR
prog_char g_psPwrOn[] PROGMEM = "Power On";
prog_char g_psSelfTest[] PROGMEM = "Self Test";
prog_char g_psAutoDetect[] PROGMEM = "Auto Detect";
prog_char g_psLevel1[] PROGMEM = "Svc Level: L1";
prog_char g_psLevel2[] PROGMEM = "Svc Level: L2";
prog_char g_psStuckRelay[] PROGMEM = "--Stuck Relay--";
prog_char g_psEarthGround[] PROGMEM = "--Earth Ground--";
//prog_char g_psTestPassed[] PROGMEM = "Test Passed";
prog_char g_psTestFailed[] PROGMEM = "TEST FAILED";
#endif // ADVPWR
prog_char g_psEvseError[] PROGMEM = "EVSE ERROR";
prog_char g_psVentReq[] PROGMEM = "VENT REQUIRED";
prog_char g_psDiodeChkFailed[] PROGMEM = "DIODE CHK FAILED";
prog_char g_psGfciFault[] PROGMEM = "GFCI FAULT";
prog_char g_psNoGround[] PROGMEM = "NO GROUND";
prog_char g_psEStuckRelay[] PROGMEM = "STUCK RELAY";
prog_char g_psStopped[] PROGMEM = "Stopped";
prog_char g_psEvConnected[] PROGMEM = "EV Connected";
prog_char g_psEvNotConnected[] PROGMEM = "EV Not Connected";
#endif // LCD16X2
//-- end global variables
void EvseReset();
void SaveSettings()
{
// n.b. should we add dirty bits so we only write the changed values? or should we just write them on the fly when necessary?
EEPROM.write((g_EvseController.GetCurSvcLevel() == 1) ? EOFS_CURRENT_CAPACITY_L1 : EOFS_CURRENT_CAPACITY_L2,(byte)g_EvseController.GetCurrentCapacity());
EEPROM.write(EOFS_FLAGS,g_EvseController.GetFlags());
}
#ifdef SERIALCLI
CLI::CLI()
{
m_CLIstrCount = 0;
m_strBuf = g_sTmp;
m_strBufLen = sizeof(g_sTmp);
}
void CLI::info()
{
println_P(PSTR("OpenEVSE")); // CLI print prompt when serial is ready
print_P(PSTR("Software - Open EVSE V")); //CLI info
println_P(VERSTR);
printlnn();
}
void CLI::Init()
{
info();
println_P(PSTR("type help for command list"));
print_P(PSTR("OpenEVSE> ")); // CLI Prompt
flush();
}
uint8_t CLI::getInt()
{
uint8_t c;
uint8_t num = 0;
do {
c = Serial.read(); // read the byte
if ((c >= '0') && (c <= '9')) {
num = (num * 10) + c - '0';
}
} while (c != 13);
return num;
}
void CLI::printlnn()
{
println("");
}
prog_char g_pson[] PROGMEM = "on";