@@ -8,45 +8,24 @@ import (
88
99 "github.com/evcc-io/evcc/util"
1010 ocpp16 "github.com/lorenzodonini/ocpp-go/ocpp1.6"
11+ "github.com/lorenzodonini/ocpp-go/ocpp1.6/core"
1112)
1213
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+
1321type CS struct {
14- mu sync.Mutex
15- log * util.Logger
1622 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
1926 txnId atomic.Int64
2027}
2128
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-
5029// errorHandler logs error channel
5130func (cs * CS ) errorHandler (errC <- chan error ) {
5231 for err := range errC {
@@ -58,38 +37,67 @@ func (cs *CS) ChargepointByID(id string) (*CP, error) {
5837 cs .mu .Lock ()
5938 defer cs .mu .Unlock ()
6039
61- cp , ok := cs .cps [id ]
40+ reg , ok := cs .regs [id ]
6241 if ! ok {
6342 return nil , fmt .Errorf ("unknown charge point: %s" , id )
6443 }
65- if cp == nil {
44+ if reg . cp == nil {
6645 return nil , fmt .Errorf ("charge point not configured: %s" , id )
6746 }
68- return cp , nil
47+ return reg . cp , nil
6948}
7049
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
7164func (cs * CS ) RegisterChargepoint (id string , newfun func () * CP , init func (* CP ) error ) (* CP , error ) {
7265 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
7772 }
78- cs .mu .Unlock ()
7973
8074 // 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+ }
8388
84- // already registered?
85- if cp , err := cs .ChargepointByID (id ); err == nil {
8689 return cp , nil
8790 }
8891
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 )
93101 }
94102
95103 return cp , init (cp )
@@ -101,28 +109,29 @@ func (cs *CS) NewChargePoint(chargePoint ocpp16.ChargePointConnection) {
101109 defer cs .mu .Unlock ()
102110
103111 // check for configured charge point
104- cp , ok := cs .cps [chargePoint .ID ()]
112+ reg , ok := cs .regs [chargePoint .ID ()]
105113 if ok {
106114 cs .log .DEBUG .Printf ("charge point connected: %s" , chargePoint .ID ())
107115
108116 // trigger initial connection if charge point is already setup
109- if cp != nil {
117+ if cp := reg . cp ; cp != nil {
110118 cp .connect (true )
111119 }
112120
113121 return
114122 }
115123
116124 // 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
119128 cs .log .INFO .Printf ("charge point connected, registering: %s" , chargePoint .ID ())
120129
121130 // update id
122131 cp .RegisterID (chargePoint .ID ())
123132
124- cs .cps [chargePoint .ID ()] = cp
125- delete (cs .cps , "" )
133+ cs .regs [chargePoint .ID ()]. cp = cp
134+ delete (cs .regs , "" )
126135
127136 cp .connect (true )
128137
@@ -133,7 +142,7 @@ func (cs *CS) NewChargePoint(chargePoint ocpp16.ChargePointConnection) {
133142
134143 // register unknown charge point
135144 // 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 )
137146}
138147
139148// ChargePointDisconnected implements ocpp16.ChargePointConnectionHandler
0 commit comments