state machines for PEV and EVSE completed until precharge.

This commit is contained in:
uhi22 2022-11-08 22:53:18 +01:00
parent 40dcb1681c
commit 13cd9378ce
3 changed files with 246 additions and 71 deletions

View file

@ -66,6 +66,21 @@ exiHexDemoSupportedApplicationProtocolRequest2="8000ebab9371d34b9b79d189a98989c1
# Command line:
# ./OpenV2G.exe DH80400040
# (4) SessionSetupRequest DIN
# 809a0011d00000
# Command line:
# ./OpenV2G.exe DD809a0011d00000
# (5) SessionSetupResponse DIN
# 809a02004080c1014181c211e0000080
# ./OpenV2G.exe DD809a02004080c1014181c211e0000080
# (6) CableCheckReq
# "result": "809a001010400000"
# (7) PreChargeReq
# "result": "809a001150400000c80006400000"
# Configuration of the exi converter tool
pathToOpenV2GExe = "..\\OpenV2Gx\\Release\\OpenV2G.exe";
@ -140,7 +155,7 @@ def exiDecode(exiHex, prefix="DH"):
exiHex = exiByteArrayToHex(exiHex)
#print("type is " + str(type(exiHex)))
param1 = prefix + exiHex # DH for decode handshake
print("exiDecode: trying to decode " + exiHex + " with schema " + prefix)
#print("exiDecode: trying to decode " + exiHex + " with schema " + prefix)
result = subprocess.run(
[pathToOpenV2GExe, param1], capture_output=True, text=True)
#print("stdout:", result.stdout)
@ -159,7 +174,7 @@ def exiEncode(strMessageName, params=""):
strConverterResult = "exiEncode ERROR. stderr:" + result.stderr
print(strConverterResult)
else:
print("exiEncode stdout:", result.stdout)
#print("exiEncode stdout:", result.stdout)
# Now we have an encoder result in json form, something like:
# {
# "info": "",
@ -169,7 +184,7 @@ def exiEncode(strMessageName, params=""):
try:
y = json.loads(result.stdout)
strConverterResult = y["result"]
print("strConverterResult is " + str(strConverterResult))
#print("strConverterResult is " + str(strConverterResult))
except:
strConverterResult = "exiEncode failed to convert json to dict."
print(strConverterResult)
@ -186,27 +201,53 @@ def testByteArrayConversion(s):
print("with V2GTP header=" + exiWithHeaderString)
def testDecoder(strHex, pre="DH", comment=""):
global nFail
print("Decoder test for " + comment + " with data " + strHex)
decoded=exiDecode(strHex, pre)
print(decoded)
strExpected = comment
if (decoded.find(strExpected)>0):
print("---pass---")
else:
print("---***!!!FAIL!!!***---")
nFail+=1
if __name__ == "__main__":
nFail=0
print("Testing exiConnector...")
testByteArrayConversion("123456")
testByteArrayConversion("1234567")
testByteArrayConversion("ABCDEF")
testByteArrayConversion("00112233445566778899AABBCCDDEEFF")
testByteArrayConversion("TRASH!")
#testByteArrayConversion("123456")
#testByteArrayConversion("1234567")
#testByteArrayConversion("ABCDEF")
#testByteArrayConversion("00112233445566778899AABBCCDDEEFF")
#testByteArrayConversion("TRASH!")
print("Testing exiDecode with exiHexDemoSupportedApplicationProtocolRequestIoniq")
print(exiDecode(exiHexDemoSupportedApplicationProtocolRequestIoniq))
print("Testing exiDecode with exiHexDemoSupportedApplicationProtocolRequest2")
strConverterResult = exiDecode(exiHexDemoSupportedApplicationProtocolRequest2)
print(strConverterResult)
testDecoder("8000ebab9371d34b9b79d189a98989c1d191d191818981d26b9b3a232b30010000040001b75726e3a64696e3a37303132313a323031323a4d73674465660020000100880", pre="DH", comment="supportedAppProtocolReq")
testDecoder("80400040", pre="DH", comment="supportedAppProtocolRes")
strConverterResult = exiDecode(exiHexToByteArray(exiHexDemoSupportedApplicationProtocolRequest2))
print(strConverterResult)
testDecoder("809a0011d00000", pre="DD", comment="SessionSetupReq")
testDecoder("809a02004080c1014181c211e0000080", pre="DD", comment="SessionSetupRes")
testDecoder("809a001198", pre="DD", comment="ServiceDiscoveryReq")
testDecoder("809a0011a0012002412104", pre="DD", comment="ServiceDiscoveryRes")
testDecoder("809a0011b2001280", pre="DD", comment="ServicePaymentSelectionReq")
testDecoder("809a0011c000", pre="DD", comment="ServicePaymentSelectionRes")
testDecoder("809a00107211400dc0c8c82324701900", pre="DD", comment="ChargeParameterDiscoveryReq")
testDecoder("809a001080004820400000c99002062050193080c0c802064c8010190140c80a20", pre="DD", comment="ChargeParameterDiscoveryRes")
testDecoder("809a001010400000", pre="DD", comment="CableCheckReq")
testDecoder("809a0010200200000000", pre="DD", comment="CableCheckRes")
testDecoder("809a001150400000c80006400000", pre="DD", comment="PreChargeReq")
testDecoder("809a00116002000000320000", pre="DD", comment="PreChargeRes")
print("Number of fails: " + str(nFail))
if (strConverterResult.find("ProtocolNamespace=urn:din")>0):
print("Detected DIN")
param1 = "ED1" # ED for encode DIN, session setup response
result = subprocess.run([pathToOpenV2GExe, param1], capture_output=True, text=True)
print("stdout:", result.stdout)
print("stderr:", result.stderr)
#print("Testing exiDecode with exiHexDemoSupportedApplicationProtocolRequestIoniq")
#print(exiDecode(exiHexDemoSupportedApplicationProtocolRequestIoniq))
#print("Testing exiDecode with exiHexDemoSupportedApplicationProtocolRequest2")
#strConverterResult = exiDecode(exiHexDemoSupportedApplicationProtocolRequest2)
#print(strConverterResult)
#strConverterResult = exiDecode(exiHexToByteArray(exiHexDemoSupportedApplicationProtocolRequest2))
#print(strConverterResult)

View file

@ -12,9 +12,9 @@ from exiConnector import * # for EXI data handling/converting
stateWaitForSupportedApplicationProtocolRequest = 0
stateWaitForSessionSetupRequest = 1
stateWaitForServiceDiscoveryRequest = 2
stateWaitForPaymentServiceSelectionRequest = 3
stateWaitForServicePaymentSelectionRequest = 3
stateWaitForAuthorizationRequest = 4
stateWaitForChargeParameterRequest = 5
stateWaitForChargeParameterDiscoveryRequest = 5
stateWaitForCableCheckRequest = 6
stateWaitForPreChargeRequest = 7
stateWaitForPowerDeliveryRequest = 8
@ -34,7 +34,6 @@ class fsmEvse():
if (len(self.rxData)>0):
print("In state WaitForSupportedApplicationProtocolRequest, received " + prettyHexMessage(self.rxData))
exidata = removeV2GTPHeader(self.rxData)
print("received exi" + prettyHexMessage(exidata))
self.rxData = []
strConverterResult = exiDecode(exidata, "DH") # Decode Handshake-request
print(strConverterResult)
@ -45,69 +44,115 @@ class fsmEvse():
msg = addV2GTPHeader(exiEncode("Eh"))
print("responding " + prettyHexMessage(msg))
self.Tcp.transmit(msg)
self.enterState(1)
self.enterState(stateWaitForSessionSetupRequest)
def stateFunctionWaitForSessionSetupRequest(self):
if (len(self.rxData)>0):
print("In state stateFunctionWaitForSessionSetupRequest, received " + prettyHexMessage(self.rxData))
exidata = removeV2GTPHeader(self.rxData)
print("received exi" + prettyHexMessage(exidata))
self.rxData = []
strConverterResult = exiDecode(exidata)
strConverterResult = exiDecode(exidata, "DD")
print(strConverterResult)
if (True):
if (strConverterResult.find("SessionSetupReq")>0):
# todo: check the request content, and fill response parameters
msg = addV2GTPHeader(exiEncode("EDa")) # EDa for Encode, Din, SessionSetupResponse
print("responding " + prettyHexMessage(msg))
self.Tcp.transmit(msg)
self.enterState(2)
self.enterState(stateWaitForServiceDiscoveryRequest)
if (self.isTooLong()):
self.enterState(0)
def stateFunctionWaitForServiceDiscoveryRequest(self):
if (len(self.rxData)>0):
print("In state WaitForServiceDiscoveryRequest, received " + prettyHexMessage(self.rxData))
exidata = removeV2GTPHeader(self.rxData)
self.rxData = []
self.enterState(3)
strConverterResult = exiDecode(exidata, "DD")
print(strConverterResult)
if (strConverterResult.find("ServiceDiscoveryReq")>0):
# todo: check the request content, and fill response parameters
msg = addV2GTPHeader(exiEncode("EDb")) # EDb for Encode, Din, ServiceDiscoveryResponse
print("responding " + prettyHexMessage(msg))
self.Tcp.transmit(msg)
self.enterState(stateWaitForServicePaymentSelectionRequest)
if (self.isTooLong()):
self.enterState(0)
def stateFunctionWaitForPaymentServiceSelectionRequest(self):
def stateFunctionWaitForServicePaymentSelectionRequest(self):
if (len(self.rxData)>0):
print("In state WaitForServicePaymentSelectionRequest, received " + prettyHexMessage(self.rxData))
exidata = removeV2GTPHeader(self.rxData)
self.rxData = []
self.enterState(4)
strConverterResult = exiDecode(exidata, "DD")
print(strConverterResult)
if (strConverterResult.find("ServicePaymentSelectionReq")>0):
# todo: check the request content, and fill response parameters
msg = addV2GTPHeader(exiEncode("EDc")) # EDc for Encode, Din, ServicePaymentSelectionResponse
print("responding " + prettyHexMessage(msg))
self.Tcp.transmit(msg)
self.enterState(stateWaitForChargeParameterDiscoveryRequest)
if (self.isTooLong()):
self.enterState(0)
def stateFunctionWaitForAuthorizationRequest(self):
def stateFunctionWaitForAuthorizationRequest(self): # not specified in the DIN
if (len(self.rxData)>0):
self.rxData = []
self.enterState(5)
if (self.isTooLong()):
self.enterState(0)
def stateFunctionWaitForChargeParameterRequest(self):
def stateFunctionWaitForChargeParameterDiscoveryRequest(self):
if (len(self.rxData)>0):
print("In state WaitForChargeParameterDiscoveryRequest, received " + prettyHexMessage(self.rxData))
exidata = removeV2GTPHeader(self.rxData)
self.rxData = []
self.enterState(6)
strConverterResult = exiDecode(exidata, "DD")
print(strConverterResult)
if (strConverterResult.find("ChargeParameterDiscoveryReq")>0):
# todo: check the request content, and fill response parameters
msg = addV2GTPHeader(exiEncode("EDe")) # EDe for Encode, Din, ChargeParameterDiscoveryResponse
print("responding " + prettyHexMessage(msg))
self.Tcp.transmit(msg)
self.enterState(stateWaitForCableCheckRequest)
if (self.isTooLong()):
self.enterState(0)
def stateFunctionWaitForCableCheckRequest(self):
if (len(self.rxData)>0):
print("In state WaitForCableCheckRequest, received " + prettyHexMessage(self.rxData))
exidata = removeV2GTPHeader(self.rxData)
self.rxData = []
self.enterState(7)
strConverterResult = exiDecode(exidata, "DD")
print(strConverterResult)
if (strConverterResult.find("CableCheckReq")>0):
# todo: check the request content, and fill response parameters
msg = addV2GTPHeader(exiEncode("EDf")) # EDf for Encode, Din, CableCheckResponse
print("responding " + prettyHexMessage(msg))
self.Tcp.transmit(msg)
self.enterState(stateWaitForPreChargeRequest)
if (self.isTooLong()):
self.enterState(0)
def stateFunctionWaitForPreChargeRequest(self):
if (len(self.rxData)>0):
print("In state WaitForPreChargeRequest, received " + prettyHexMessage(self.rxData))
exidata = removeV2GTPHeader(self.rxData)
self.rxData = []
self.enterState(8)
strConverterResult = exiDecode(exidata, "DD")
print(strConverterResult)
if (strConverterResult.find("PreChargeReq")>0):
# todo: check the request content, and fill response parameters
msg = addV2GTPHeader(exiEncode("EDg")) # EDf for Encode, Din, PreChargeResponse
print("responding " + prettyHexMessage(msg))
self.Tcp.transmit(msg)
self.enterState(stateWaitForPowerDeliveryRequest)
if (self.isTooLong()):
self.enterState(0)
def stateFunctionWaitForPowerDeliveryRequest(self):
if (len(self.rxData)>0):
print("In state WaitForPowerDeliveryRequest, received " + prettyHexMessage(self.rxData))
print("Todo: Reaction in state WaitForPowerDeliveryRequest is not implemented yet.")
self.rxData = []
self.enterState(0)
if (self.isTooLong()):
@ -118,9 +163,9 @@ class fsmEvse():
stateWaitForSupportedApplicationProtocolRequest: stateFunctionWaitForSupportedApplicationProtocolRequest,
stateWaitForSessionSetupRequest: stateFunctionWaitForSessionSetupRequest,
stateWaitForServiceDiscoveryRequest: stateFunctionWaitForServiceDiscoveryRequest,
stateWaitForPaymentServiceSelectionRequest: stateFunctionWaitForPaymentServiceSelectionRequest,
stateWaitForAuthorizationRequest: stateFunctionWaitForAuthorizationRequest,
stateWaitForChargeParameterRequest: stateFunctionWaitForChargeParameterRequest,
stateWaitForServicePaymentSelectionRequest: stateFunctionWaitForServicePaymentSelectionRequest,
# stateWaitForAuthorizationRequest: stateFunctionWaitForAuthorizationRequest, not in DIN
stateWaitForChargeParameterDiscoveryRequest: stateFunctionWaitForChargeParameterDiscoveryRequest,
stateWaitForCableCheckRequest: stateFunctionWaitForCableCheckRequest,
stateWaitForPreChargeRequest: stateFunctionWaitForPreChargeRequest,
stateWaitForPowerDeliveryRequest: stateFunctionWaitForPowerDeliveryRequest,
@ -144,9 +189,6 @@ class fsmEvse():
if (self.Tcp.isRxDataAvailable()):
self.rxData = self.Tcp.getRxData()
#print("received " + str(self.rxData))
#msg = "ok, you sent " + str(self.rxData)
#print("responding " + msg)
#self.Tcp.transmit(bytes(msg, "utf-8"))
# run the state machine:
self.cyclesInState += 1 # for timeout handling, count how long we are in a state
self.stateFunctions[self.state](self)

120
fsmPev.py
View file

@ -13,9 +13,9 @@ stateInitialized = 0
stateWaitForSupportedApplicationProtocolResponse = 1
stateWaitForSessionSetupResponse = 2
stateWaitForServiceDiscoveryResponse = 3
stateWaitForPaymentServiceSelectionResponse = 4
stateWaitForServicePaymentSelectionResponse = 4
stateWaitForAuthorizationResponse = 5
stateWaitForChargeParameterResponse = 6
stateWaitForChargeParameterDiscoveryResponse = 6
stateWaitForCableCheckResponse = 7
stateWaitForPreChargeResponse = 8
stateWaitForPowerDeliveryResponse = 9
@ -32,34 +32,129 @@ class fsmPev():
def stateFunctionInitialized(self):
if (self.Tcp.isConnected):
# we just use the initial request message from the Ioniq. It contains one entry: DIN.
self.Tcp.transmit(addV2GTPHeader(exiHexToByteArray(exiHexDemoSupportedApplicationProtocolRequestIoniq)))
self.enterState(stateWaitForSupportedApplicationProtocolResponse)
def stateFunctionWaitForSupportedApplicationProtocolResponse(self):
if (len(self.rxData)>0):
print("In state stateFunctionWaitForSupportedApplicationProtocolResponse, received " + prettyHexMessage(self.rxData))
print("In state WaitForSupportedApplicationProtocolResponse, received " + prettyHexMessage(self.rxData))
exidata = removeV2GTPHeader(self.rxData)
print("received exi" + prettyHexMessage(exidata))
self.rxData = []
strConverterResult = exiDecode(exidata, "Dh") # Decode Handshake-response
print(strConverterResult)
# todo: evaluate the message
# EDA for encode DIN, SessionSetupRequest
msg = addV2GTPHeader(exiEncode("EDA"))
print("sending SessionSetupRequest" + prettyHexMessage(msg))
if (strConverterResult.find("supportedAppProtocolRes")>0):
# todo: check the request content, and fill response parameters
msg = addV2GTPHeader(exiEncode("EDA")) # EDA for Encode, Din, SessionSetupReq
print("responding " + prettyHexMessage(msg))
self.Tcp.transmit(msg)
self.enterState(stateWaitForSessionSetupResponse)
if (self.isTooLong()):
self.enterState(0)
def stateFunctionWaitForSessionSetupResponse(self):
if (len(self.rxData)>0):
#self.enterState(stateWaitForServiceDiscoveryResponse)
pass
print("In state WaitForSessionSetupResponse, received " + prettyHexMessage(self.rxData))
exidata = removeV2GTPHeader(self.rxData)
self.rxData = []
strConverterResult = exiDecode(exidata, "DD") # Decode DIN
print(strConverterResult)
if (strConverterResult.find("SessionSetupRes")>0):
# todo: check the request content, and fill response parameters
msg = addV2GTPHeader(exiEncode("EDB")) # EDB for Encode, Din, ServiceDiscoveryRequest
print("responding " + prettyHexMessage(msg))
self.Tcp.transmit(msg)
self.enterState(stateWaitForServiceDiscoveryResponse)
if (self.isTooLong()):
self.enterState(0)
def stateFunctionWaitForServiceDiscoveryResponse(self):
if (len(self.rxData)>0):
print("In state WaitForServiceDiscoveryResponse, received " + prettyHexMessage(self.rxData))
exidata = removeV2GTPHeader(self.rxData)
self.rxData = []
strConverterResult = exiDecode(exidata, "DD") # Decode DIN
print(strConverterResult)
if (strConverterResult.find("ServiceDiscoveryRes")>0):
# todo: check the request content, and fill response parameters
msg = addV2GTPHeader(exiEncode("EDC")) # EDC for Encode, Din, ServicePaymentSelection
print("responding " + prettyHexMessage(msg))
self.Tcp.transmit(msg)
self.enterState(stateWaitForServicePaymentSelectionResponse)
if (self.isTooLong()):
self.enterState(0)
def stateFunctionWaitForServicePaymentSelectionResponse(self):
if (len(self.rxData)>0):
print("In state WaitForServicePaymentSelectionResponse, received " + prettyHexMessage(self.rxData))
exidata = removeV2GTPHeader(self.rxData)
self.rxData = []
strConverterResult = exiDecode(exidata, "DD") # Decode DIN
print(strConverterResult)
if (strConverterResult.find("ServicePaymentSelectionRes")>0):
# todo: check the request content, and fill response parameters
msg = addV2GTPHeader(exiEncode("EDE")) # EDE for Encode, Din, ChargeParameterDiscovery. We ignore Authorization, not specified in DIN.
print("responding " + prettyHexMessage(msg))
self.Tcp.transmit(msg)
self.enterState(stateWaitForChargeParameterDiscoveryResponse)
if (self.isTooLong()):
self.enterState(0)
def stateFunctionWaitForChargeParameterDiscoveryResponse(self):
if (len(self.rxData)>0):
print("In state WaitForChargeParameterDiscoveryResponse, received " + prettyHexMessage(self.rxData))
exidata = removeV2GTPHeader(self.rxData)
self.rxData = []
strConverterResult = exiDecode(exidata, "DD") # Decode DIN
print(strConverterResult)
if (strConverterResult.find("ChargeParameterDiscoveryRes")>0):
# todo: check the request content, and fill response parameters
msg = addV2GTPHeader(exiEncode("EDF")) # EDF for Encode, Din, CableCheck
print("responding " + prettyHexMessage(msg))
self.Tcp.transmit(msg)
self.enterState(stateWaitForCableCheckResponse)
if (self.isTooLong()):
self.enterState(0)
def stateFunctionWaitForCableCheckResponse(self):
if (len(self.rxData)>0):
print("In state WaitForCableCheckResponse, received " + prettyHexMessage(self.rxData))
exidata = removeV2GTPHeader(self.rxData)
self.rxData = []
strConverterResult = exiDecode(exidata, "DD") # Decode DIN
print(strConverterResult)
if (strConverterResult.find("CableCheckRes")>0):
# todo: check the request content, and fill response parameters
msg = addV2GTPHeader(exiEncode("EDG")) # EDG for Encode, Din, PreCharge
print("responding " + prettyHexMessage(msg))
self.Tcp.transmit(msg)
self.enterState(stateWaitForPreChargeResponse)
if (self.isTooLong()):
self.enterState(0)
def stateFunctionWaitForPreChargeResponse(self):
if (len(self.rxData)>0):
print("In state WaitForPreChargeResponse, received " + prettyHexMessage(self.rxData))
exidata = removeV2GTPHeader(self.rxData)
self.rxData = []
strConverterResult = exiDecode(exidata, "DD") # Decode DIN
print(strConverterResult)
if (strConverterResult.find("PreChargeRes")>0):
# todo: check the request content, and fill response parameters
print("PreCharge aknowledge received.")
print("As Demo, we stay in PreCharge until the timeout elapses.")
if (self.isTooLong()):
self.enterState(0)
stateFunctions = {
stateInitialized: stateFunctionInitialized,
stateWaitForSupportedApplicationProtocolResponse: stateFunctionWaitForSupportedApplicationProtocolResponse,
stateWaitForSessionSetupResponse: stateFunctionWaitForSessionSetupResponse,
stateWaitForServiceDiscoveryResponse: stateFunctionWaitForServiceDiscoveryResponse,
stateWaitForServicePaymentSelectionResponse: stateFunctionWaitForServicePaymentSelectionResponse,
stateWaitForChargeParameterDiscoveryResponse: stateFunctionWaitForChargeParameterDiscoveryResponse,
stateWaitForCableCheckResponse: stateFunctionWaitForCableCheckResponse,
stateWaitForPreChargeResponse: stateFunctionWaitForPreChargeResponse,
}
def reInit(self):
@ -83,10 +178,7 @@ class fsmPev():
#self.Tcp.mainfunction() # call the lower-level worker
if (self.Tcp.isRxDataAvailable()):
self.rxData = self.Tcp.getRxData()
print("received " + prettyHexMessage(self.rxData))
#msg = "ok, you sent " + str(self.rxData)
#print("responding " + msg)
#self.Tcp.transmit(bytes(msg, "utf-8"))
#print("received " + prettyHexMessage(self.rxData))
# run the state machine:
self.cyclesInState += 1 # for timeout handling, count how long we are in a state
self.stateFunctions[self.state](self)