@@ -8,45 +8,24 @@ import (
8
8
9
9
"github.com/evcc-io/evcc/util"
10
10
ocpp16 "github.com/lorenzodonini/ocpp-go/ocpp1.6"
11
+ "github.com/lorenzodonini/ocpp-go/ocpp1.6/core"
11
12
)
12
13
14
+ type registration struct {
15
+ mu sync.RWMutex
16
+ setup sync.RWMutex // serialises chargepoint setup
17
+ cp * CP // guarded by setup and CS mutexes
18
+ status * core.StatusNotificationRequest // guarded by mu mutex
19
+ }
20
+
13
21
type CS struct {
14
- mu sync.Mutex
15
- log * util.Logger
16
22
ocpp16.CentralSystem
17
- cps map [string ]* CP
18
- init map [string ]* sync.Mutex
23
+ mu sync.Mutex
24
+ log * util.Logger
25
+ regs map [string ]* registration // guarded by mu mutex
19
26
txnId atomic.Int64
20
27
}
21
28
22
- // Register registers a charge point with the central system.
23
- // The charge point identified by id may already be connected in which case initial connection is triggered.
24
- func (cs * CS ) register (id string , new * CP ) error {
25
- cs .mu .Lock ()
26
- defer cs .mu .Unlock ()
27
-
28
- cp , ok := cs .cps [id ]
29
-
30
- // case 1: charge point neither registered nor physically connected
31
- if ! ok {
32
- cs .cps [id ] = new
33
- return nil
34
- }
35
-
36
- // case 2: duplicate registration of id empty
37
- if id == "" {
38
- return errors .New ("cannot have >1 charge point with empty station id" )
39
- }
40
-
41
- // case 3: charge point not registered but physically already connected
42
- if cp == nil {
43
- cs .cps [id ] = new
44
- new .connect (true )
45
- }
46
-
47
- return nil
48
- }
49
-
50
29
// errorHandler logs error channel
51
30
func (cs * CS ) errorHandler (errC <- chan error ) {
52
31
for err := range errC {
@@ -58,38 +37,67 @@ func (cs *CS) ChargepointByID(id string) (*CP, error) {
58
37
cs .mu .Lock ()
59
38
defer cs .mu .Unlock ()
60
39
61
- cp , ok := cs .cps [id ]
40
+ reg , ok := cs .regs [id ]
62
41
if ! ok {
63
42
return nil , fmt .Errorf ("unknown charge point: %s" , id )
64
43
}
65
- if cp == nil {
44
+ if reg . cp == nil {
66
45
return nil , fmt .Errorf ("charge point not configured: %s" , id )
67
46
}
68
- return cp , nil
47
+ return reg . cp , nil
69
48
}
70
49
50
+ func (cs * CS ) WithChargepointStatusByID (id string , fun func (status * core.StatusNotificationRequest )) {
51
+ cs .mu .Lock ()
52
+ defer cs .mu .Unlock ()
53
+
54
+ if reg , ok := cs .regs [id ]; ok {
55
+ reg .mu .RLock ()
56
+ if reg .status != nil {
57
+ fun (reg .status )
58
+ }
59
+ reg .mu .RUnlock ()
60
+ }
61
+ }
62
+
63
+ // RegisterChargepoint registers a charge point with the central system of returns an already registered charge point
71
64
func (cs * CS ) RegisterChargepoint (id string , newfun func () * CP , init func (* CP ) error ) (* CP , error ) {
72
65
cs .mu .Lock ()
73
- cpmu , ok := cs .init [id ]
74
- if ! ok {
75
- cpmu = new (sync.Mutex )
76
- cs .init [id ] = cpmu
66
+
67
+ // prepare shadow state
68
+ reg , registered := cs .regs [id ]
69
+ if ! registered {
70
+ reg = new (registration )
71
+ cs .regs [id ] = reg
77
72
}
78
- cs .mu .Unlock ()
79
73
80
74
// serialise on chargepoint id
81
- cpmu .Lock ()
82
- defer cpmu .Unlock ()
75
+ reg .setup .Lock ()
76
+ defer reg .setup .Unlock ()
77
+
78
+ cp := reg .cp
79
+
80
+ cs .mu .Unlock ()
81
+
82
+ // setup already completed?
83
+ if cp != nil {
84
+ // duplicate registration of id empty
85
+ if id == "" {
86
+ return nil , errors .New ("cannot have >1 charge point with empty station id" )
87
+ }
83
88
84
- // already registered?
85
- if cp , err := cs .ChargepointByID (id ); err == nil {
86
89
return cp , nil
87
90
}
88
91
89
- // first time- registration should not error
90
- cp := newfun ()
91
- if err := cs .register (id , cp ); err != nil {
92
- return nil , err
92
+ // first time- create the charge point
93
+ cp = newfun ()
94
+
95
+ cs .mu .Lock ()
96
+ reg .cp = cp
97
+ cs .mu .Unlock ()
98
+
99
+ if registered {
100
+ cp .connect (true )
93
101
}
94
102
95
103
return cp , init (cp )
@@ -101,28 +109,29 @@ func (cs *CS) NewChargePoint(chargePoint ocpp16.ChargePointConnection) {
101
109
defer cs .mu .Unlock ()
102
110
103
111
// check for configured charge point
104
- cp , ok := cs .cps [chargePoint .ID ()]
112
+ reg , ok := cs .regs [chargePoint .ID ()]
105
113
if ok {
106
114
cs .log .DEBUG .Printf ("charge point connected: %s" , chargePoint .ID ())
107
115
108
116
// trigger initial connection if charge point is already setup
109
- if cp != nil {
117
+ if cp := reg . cp ; cp != nil {
110
118
cp .connect (true )
111
119
}
112
120
113
121
return
114
122
}
115
123
116
124
// check for configured anonymous charge point
117
- cp , ok = cs .cps ["" ]
118
- if ok && cp != nil {
125
+ reg , ok = cs .regs ["" ]
126
+ if ok && reg .cp != nil {
127
+ cp := reg .cp
119
128
cs .log .INFO .Printf ("charge point connected, registering: %s" , chargePoint .ID ())
120
129
121
130
// update id
122
131
cp .RegisterID (chargePoint .ID ())
123
132
124
- cs .cps [chargePoint .ID ()] = cp
125
- delete (cs .cps , "" )
133
+ cs .regs [chargePoint .ID ()]. cp = cp
134
+ delete (cs .regs , "" )
126
135
127
136
cp .connect (true )
128
137
@@ -133,7 +142,7 @@ func (cs *CS) NewChargePoint(chargePoint ocpp16.ChargePointConnection) {
133
142
134
143
// register unknown charge point
135
144
// when charge point setup is complete, it will eventually be associated with the connected id
136
- cs .cps [chargePoint .ID ()] = nil
145
+ cs .regs [chargePoint .ID ()] = new ( registration )
137
146
}
138
147
139
148
// ChargePointDisconnected implements ocpp16.ChargePointConnectionHandler
0 commit comments