2022-11-06 21:47:32 +00:00
# EXI is specified in w3.org/TR/exi
# For decoding and encoding, different decoders are availabe:
# 1. https://github.com/FlUxIuS/V2Gdecoder
# https://github.com/FlUxIuS/V2Gdecoder/releases
# Install java from https://www.java.com/de/download/manual.jsp
#
# C:\>java -version
# java version "1.8.0_351"
# Java(TM) SE Runtime Environment (build 1.8.0_351-b10)
# Java HotSpot(TM) Client VM (build 25.351-b10, mixed mode, sharing)
# C:\>
#
# java -jar V2Gdecoder.jar -e -s 8000dbab9371d3234b71d1b981899189d191818991d26b9b3a232b30020000040040
# ERROR: 'Premature EOS found while reading data.'
# <?xml version="1.0" encoding="UTF-8"?><ns4:supportedAppProtocolReq xmlns:ns4="urn:iso:15118:2:2010:AppProtocol"
# xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns3="http://www.w3.org/2001/XMLSchema">
# <AppProtocol>
# <ProtocolNamespace>urn:din:70121:2012:MsgDef</ProtocolNamespace>
# <VersionNumberMajor>2</VersionNumberMajor>
# <VersionNumberMinor>0</VersionNumberMinor>
# <SchemaID>1</SchemaID>
# <Priority>1</Priority>
# </AppProtocol>
# </ns4:supportedAppProtocolReq>
#
# 2. OpenV2G from https://github.com/Martin-P/OpenV2G
# Pro: The schema-specific files are already included as generated C-code, this
# makes it very fast.
# Contra: Is only a demo, does not provide an interface which could be used for decoding/encoding.
# Work in progress: Fork in https://github.com/uhi22/OpenV2Gx, to add a command line interface (and maybe a socket interface).
#
#
#
#
#
#
#
from helpers import showAsHex , twoCharHex
import subprocess
import sys
import time
2022-11-08 11:01:54 +00:00
import json
2022-11-20 13:23:37 +00:00
import os
2022-11-06 21:47:32 +00:00
2022-11-07 12:38:06 +00:00
# Example data:
# (1) From the Ioniq:
# In wireshark: Copy as hex stream
# 01fe8001000000228000dbab9371d3234b71d1b981899189d191818991d26b9b3a232b30020000040040
# remove the 8 bytes V2GTP header
# 8000dbab9371d3234b71d1b981899189d191818991d26b9b3a232b30020000040040
exiHexDemoSupportedApplicationProtocolRequestIoniq = " 8000dbab9371d3234b71d1b981899189d191818991d26b9b3a232b30020000040040 "
2022-11-08 21:53:18 +00:00
# Command line:
# ./OpenV2G.exe DH8000dbab9371d3234b71d1b981899189d191818991d26b9b3a232b30020000040040
2022-11-08 12:15:36 +00:00
2022-11-07 12:38:06 +00:00
# (2) From OpenV2G main_example.appHandshake()
2022-11-08 21:53:18 +00:00
# 8000ebab9371d34b9b79d189a98989c1d191d191818981d26b9b3a232b30010000040001b75726e3a64696e3a37303132313a323031323a4d73674465660020000100880
2022-11-07 12:38:06 +00:00
exiHexDemoSupportedApplicationProtocolRequest2 = " 8000ebab9371d34b9b79d189a98989c1d191d191818981d26b9b3a232b30010000040001b75726e3a64696e3a37303132313a323031323a4d73674465660020000100880 "
2022-11-08 21:53:18 +00:00
# Command line:
# ./OpenV2G.exe DH8000ebab9371d34b9b79d189a98989c1d191d191818981d26b9b3a232b30010000040001b75726e3a64696e3a37303132313a323031323a4d73674465660020000100880
2022-11-08 12:15:36 +00:00
# (3) SupportedApplicationProtocolResponse
2022-11-08 21:53:18 +00:00
# 80400040
# 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"
2022-11-06 21:47:32 +00:00
2023-05-15 20:34:49 +00:00
# 809a0232417b661514a4cb91e0202d0691559529548c0841e0fc1af4507460c0 SessionSetupRes with NewSessionEstablished
# 809a0232417b661514a4cb91e0A02d0691559529548c0841e0fc1af4507460c0 SessionSetupRes with SequenceError
# 809a021a3b7c417774813311a00120024100c4 ServiceDiscoveryRes
# 809a021a3b7c417774813311a0A120024100c4 ServiceDiscoveryRes with SequenceError
# 809a021a3b7c417774813311c000 ServicePaymentSelectionRes
# 809a021a3b7c417774813311c0A0 ServicePaymentSelectionRes with SequenceError
# 809a021a3b7c417774813310c00200 ContractAuthenticationRes
# 809a021a3b7c417774813310c0A200 ContractAuthenticationRes with SequenceError
# 809a0125e6cecc50800001ec00200004051828758405500080000101844138101c2432c04081436c900c0c000041435ecc044606000200 ChargeParameterDiscovery
# 809a0125e6cecd50810001ec00201004051828758405500080000101844138101c2432c04081436c900c0c000041435ecc044606000200 ChargeParameterDiscovery with ServiceSelectionInvalid
# 809a0125e6cecc5020004080000400 CableCheckRes
# 809a0125e6cecc5020804080000400 CableCheckRes with "FAILED"
# 809a0125e6cecc516000408000008284de880800 PreChargeRes
# 809a0125e6cecc516080408000008284de880800 PreChargeRes with "FAILED"
# 809a0125e6cecc51400420400000 PowerDeliveryRes
# 809a0125e6cecc51408420400000 PowerDeliveryRes with "FAILED"
# 809a0125e6cecc50e0004080000082867dc8081818000000040a1b64802030882702038486580800 CurrentDemandRes
# 809a0125e6cecc50e0804080000082867dc8081818000000040a1b64802030882702038486580800 CurrentDemandRes with "FAILED"
2022-11-06 21:47:32 +00:00
2022-11-07 12:38:06 +00:00
# Configuration of the exi converter tool
2022-11-20 13:23:37 +00:00
if os . name == " nt " :
# Windows: Path to the EXI decoder/encoder
pathToOpenV2GExe = " .. \\ OpenV2Gx \\ Release \\ OpenV2G.exe "
else :
# Linux: Path to the EXI decoder/encoder
pathToOpenV2GExe = " ../OpenV2Gx/Release/OpenV2G.exe " ;
2022-11-06 21:47:32 +00:00
2022-11-07 12:38:06 +00:00
# Functions
2022-11-20 18:13:41 +00:00
def exiprint ( s ) :
# todo: print to console or log or whatever
pass
2022-11-07 12:38:06 +00:00
def exiHexToByteArray ( hexString ) :
# input: a string with the two-byte-hex representation
# output: a byte array with the same data.
# If the convertion fails, we return an empty byte array.
hexlen = len ( hexString )
if ( ( hexlen % 2 ) != 0 ) :
print ( " exiHexToByteArray: unplausible length of " + hexString )
return bytearray ( 0 )
exiframe = bytearray ( int ( hexlen / 2 ) ) # two characters in the input string are one byte in the exiframe
for i in range ( 0 , int ( hexlen / 2 ) ) :
x = hexString [ 2 * i : 2 * i + 2 ]
#print("valuestring = " + x)
try :
v = int ( x , 16 )
#print("value " + hex(v))
exiframe [ i ] = v
except :
print ( " exiHexToByteArray: unplausible data " + x )
return bytearray ( 0 )
return exiframe
2022-11-06 21:47:32 +00:00
2022-11-07 12:38:06 +00:00
def exiByteArrayToHex ( b ) :
# input: Byte array
# output: a string with the two-byte-hex representation of the byte array
2022-11-06 21:47:32 +00:00
s = " "
2022-11-07 12:38:06 +00:00
for i in range ( 0 , len ( b ) ) :
s = s + twoCharHex ( b [ i ] )
return s
def addV2GTPHeader ( exidata ) :
2022-11-08 11:01:54 +00:00
#print("type is " + str(type(exidata)))
2022-11-07 12:38:06 +00:00
if ( str ( type ( exidata ) ) == " <class ' str ' > " ) :
2022-11-08 11:01:54 +00:00
#print("changing type to bytearray")
2022-11-07 12:38:06 +00:00
exidata = exiHexToByteArray ( exidata )
2022-11-08 11:01:54 +00:00
#print("type is " + str(type(exidata)))
2022-11-07 12:38:06 +00:00
# takes the bytearray with exidata, and adds a header to it, according to the Vehicle-to-Grid-Transport-Protocol
exiLen = len ( exidata )
header = bytearray ( 8 ) # V2GTP header has 8 bytes
# 1 byte protocol version
# 1 byte protocol version inverted
# 2 bytes payload type
# 4 byte payload length
header [ 0 ] = 0x01 # version
header [ 1 ] = 0xfe # version inverted
header [ 2 ] = 0x80 # payload type. 0x8001 means "EXI data"
header [ 3 ] = 0x01 #
header [ 4 ] = ( exiLen >> 24 ) & 0xff # length 4 byte.
header [ 5 ] = ( exiLen >> 16 ) & 0xff
header [ 6 ] = ( exiLen >> 8 ) & 0xff
header [ 7 ] = exiLen & 0xff
return header + exidata
def removeV2GTPHeader ( v2gtpData ) :
#removeV2GTPHeader
return v2gtpData [ 8 : ]
def exiDecode ( exiHex , prefix = " DH " ) :
# input: exi data. Either hexstring, or bytearray or bytes
# prefix to select the schema
# if the input is a byte array, we convert it into hex string. If it is already a hex string, we take it as it is.
2022-11-08 11:01:54 +00:00
#print("type is " + str(type(exiHex)))
2022-11-07 12:38:06 +00:00
if ( str ( type ( exiHex ) ) == " <class ' bytearray ' > " ) :
2022-11-08 11:01:54 +00:00
#print("changing type to hex string")
2022-11-07 12:38:06 +00:00
exiHex = exiByteArrayToHex ( exiHex )
if ( str ( type ( exiHex ) ) == " <class ' bytes ' > " ) :
2022-11-08 11:01:54 +00:00
#print("changing type to hex string")
2022-11-07 12:38:06 +00:00
exiHex = exiByteArrayToHex ( exiHex )
2022-11-08 11:01:54 +00:00
#print("type is " + str(type(exiHex)))
2022-11-07 12:38:06 +00:00
param1 = prefix + exiHex # DH for decode handshake
2022-11-08 21:53:18 +00:00
#print("exiDecode: trying to decode " + exiHex + " with schema " + prefix)
2022-11-07 12:38:06 +00:00
result = subprocess . run (
2022-11-06 21:47:32 +00:00
[ pathToOpenV2GExe , param1 ] , capture_output = True , text = True )
2022-11-07 12:38:06 +00:00
#print("stdout:", result.stdout)
if ( len ( result . stderr ) > 0 ) :
print ( " exiDecode ERROR. stderr: " + result . stderr )
2022-11-06 21:47:32 +00:00
strConverterResult = result . stdout
2022-11-07 12:38:06 +00:00
return strConverterResult
2022-11-16 18:31:45 +00:00
def exiEncode ( strMessageName ) :
2022-11-07 12:38:06 +00:00
# todo: handle the schema, the message name and the parameters
2022-11-08 11:01:54 +00:00
# param1 = "Eh" # Eh for encode handshake, SupportedApplicationProtocolResponse
# param1 = "EDa" # EDa for Encode, Din, SessionSetupResponse
param1 = strMessageName
2022-11-20 18:13:41 +00:00
exiprint ( " [EXICONNECTOR] exiEncode " + param1 )
2022-11-07 12:38:06 +00:00
result = subprocess . run ( [ pathToOpenV2GExe , param1 ] , capture_output = True , text = True )
if ( len ( result . stderr ) > 0 ) :
2022-11-08 11:01:54 +00:00
strConverterResult = " exiEncode ERROR. stderr: " + result . stderr
print ( strConverterResult )
else :
2022-11-08 21:53:18 +00:00
#print("exiEncode stdout:", result.stdout)
2022-11-08 11:01:54 +00:00
# Now we have an encoder result in json form, something like:
# {
# "info": "",
# "error": "",
# "result": "8004440400"
# }
try :
y = json . loads ( result . stdout )
strConverterResult = y [ " result " ]
2022-11-16 18:31:45 +00:00
strConverterError = y [ " error " ]
if ( len ( strConverterError ) > 0 ) :
print ( " [EXICONNECTOR] exiEncode error " + strConverterError )
2022-11-08 21:53:18 +00:00
#print("strConverterResult is " + str(strConverterResult))
2022-11-08 11:01:54 +00:00
except :
strConverterResult = " exiEncode failed to convert json to dict. "
print ( strConverterResult )
2022-11-07 12:38:06 +00:00
return strConverterResult
def testByteArrayConversion ( s ) :
print ( " Testing conversion of " + s )
x = exiHexToByteArray ( s )
newHexString = exiByteArrayToHex ( x )
print ( " exi as hex= " + newHexString )
exiWithHeader = addV2GTPHeader ( x )
exiWithHeaderString = exiByteArrayToHex ( exiWithHeader )
print ( " with V2GTP header= " + exiWithHeaderString )
2022-11-08 21:53:18 +00:00
def testDecoder ( strHex , pre = " DH " , comment = " " ) :
global nFail
2022-11-09 20:00:50 +00:00
strHex = strHex . replace ( " " , " " ) # remove blanks
2022-11-08 21:53:18 +00:00
print ( " Decoder test for " + comment + " with data " + strHex )
decoded = exiDecode ( strHex , pre )
print ( decoded )
2022-11-09 21:05:33 +00:00
if ( len ( comment ) > 0 ) :
strExpected = comment
if ( decoded . find ( strExpected ) > 0 ) :
print ( " ---pass--- " )
else :
print ( " ---***!!!FAIL!!!***--- " )
nFail + = 1
2022-12-09 11:06:10 +00:00
def testReadExiFromSnifferFile ( ) :
2022-11-09 21:05:33 +00:00
file1 = open ( ' results \\ tmp.txt ' , ' r ' )
Lines = file1 . readlines ( )
for myLine in Lines :
if ( myLine [ 0 : 9 ] == " [SNIFFER] " ) :
posOfEqualsign = myLine . find ( " = " )
s = myLine [ posOfEqualsign + 1 : ] # The part after the "=" contains the EXI hex data.
s = s . replace ( " " , " " ) # Remove blanks
s = s . replace ( " \n " , " " ) # Remove line feeds
#print(s)
testDecoder ( s , " DD " , " " )
2022-11-20 18:13:41 +00:00
2023-06-19 05:52:08 +00:00
def testReadExiFromExiLogFile ( strLogFileName ) :
try :
file1 = open ( strLogFileName , ' r ' )
fileOut = open ( ' PevExiLog.decoded.txt ' , ' w ' )
# example: "ED 809a02004080c1014181c210b8"
# example with timestamp: "2022-12-20T08:17:15.055755=ED 809a02004080c1014181c21198"
Lines = file1 . readlines ( )
for myLine in Lines :
posOfEqual = myLine . find ( " = " )
if ( posOfEqual > 0 ) :
# we have an equal-sign. Take the string behind it.
strToDecode = myLine [ posOfEqual + 1 : ]
else :
# no equal-sign. Take the complete line.
strToDecode = myLine
if ( strToDecode [ 1 : 3 ] == " D " ) : # it is DIN
posOfSpace = 2
s = strToDecode [ posOfSpace + 1 : ] # The part after the " " contains the EXI hex data.
s = s . replace ( " " , " " ) # Remove blanks
s = s . replace ( " \n " , " " ) # Remove line feeds
#print(s)
decoded = exiDecode ( s , " DD " )
print ( decoded )
print ( myLine . replace ( " \n " , " " ) + " means: " , file = fileOut )
print ( decoded , file = fileOut )
fileOut . close ( )
except :
print ( " Could not open " + strLogFileName )
if ( strLogFileName == " PevExiLog.txt " ) :
print ( " This is no problem. The PevExiLog.txt will be created when the pyPLC runs in PevMode, and can be decoded afterwards. " )
2022-12-09 11:06:10 +00:00
2022-11-20 18:13:41 +00:00
def testTimeConsumption ( ) :
strHex = " 809a001150400000c80006400000 "
pre = " DD "
tStart = time . time ( )
nRuns = 100
for i in range ( 0 , nRuns ) :
decoded = exiDecode ( strHex , pre )
tStop = time . time ( )
elapsed_time = tStop - tStart
print ( " Decoder: Execution time for " + str ( nRuns ) + " runs: " , elapsed_time , " seconds " )
tStart = time . time ( )
nRuns = 100
for i in range ( 0 , nRuns ) :
s = exiEncode ( " EDC_1122334455667788 " )
tStop = time . time ( )
elapsed_time = tStop - tStart
print ( " Encoder: Execution time for " + str ( nRuns ) + " runs: " , elapsed_time , " seconds " )
2022-11-08 21:53:18 +00:00
2022-11-07 12:38:06 +00:00
if __name__ == " __main__ " :
2022-11-08 21:53:18 +00:00
nFail = 0
2022-11-07 12:38:06 +00:00
print ( " Testing exiConnector... " )
2022-12-02 13:56:38 +00:00
if ( False ) :
testTimeConsumption ( )
exit ( )
2023-04-05 19:01:43 +00:00
if ( True ) :
2023-06-19 05:52:08 +00:00
testReadExiFromExiLogFile ( ' DemoExiLog.txt ' )
testReadExiFromExiLogFile ( ' PevExiLog.txt ' )
2022-12-02 13:56:38 +00:00
exit ( )
2022-11-08 21:53:18 +00:00
2022-11-09 18:08:02 +00:00
if ( False ) :
testDecoder ( " 8000ebab9371d34b9b79d189a98989c1d191d191818981d26b9b3a232b30010000040001b75726e3a64696e3a37303132313a323031323a4d73674465660020000100880 " , pre = " DH " , comment = " supportedAppProtocolReq " )
testDecoder ( " 80400040 " , pre = " DH " , comment = " supportedAppProtocolRes " )
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 " )
2022-11-09 20:00:50 +00:00
if ( False ) :
2022-11-09 18:08:02 +00:00
print ( " The request from the Ioniq after the EVSE sent ServicePaymentSelectionRes: " )
testDecoder ( " 809A00113020000A00000000 " , pre = " DD " , comment = " PowerDeliveryReq " )
2023-04-05 19:01:43 +00:00
if ( False ) :
2023-03-23 21:04:35 +00:00
#print("The session setup request of the Ioniq:")
#testDecoder("809A02000000000000000011D01811959401930C00", pre="DD", comment="SessionSetupReq")
print ( " Ioniq with pyPlc " )
testDecoder ( " 809a02004080c1014181c2107190000005004061a01e04070c84c02050a02000c2438368040309094820105e0a60 " , pre = " DD " ) # 2022-11-11, 25.315s ChargeParameterDiscoveryReq
#testDecoder("809a02004080c1014181c21080004820400000c99002062050193080c0c802064c8010190140c80a20", pre="DD") # 2022-11-11, 25.408s ChargeParamDisc Res
#testDecoder("809a02004080c1014181c210200200000000", pre="DD") # 2022-11-11, 26.32s CableCheckRes
#testDecoder("809a02004080c1014181c2116002000000320000", pre="DD") # 2022-11-11, 27.659s PrechargeRes
#print("A ChargeParameterDiscoveryReq")
#testDecoder("809a00107211400dc0c8c82324701900", pre="DD", comment="ChargeParameterDiscoveryReq")
2023-04-05 19:01:43 +00:00
if ( False ) :
2023-03-23 21:04:35 +00:00
print ( " From https://openinverter.org/forum/viewtopic.php?p=54692#p54692 " )
testDecoder ( " 809A0233EBC74AB099A6DC907191400500C8C82324701900 " , pre = " DD " ) # from https://openinverter.org/forum/viewtopic.php?p=54692#p54692
2023-03-23 07:50:53 +00:00
if ( False ) :
2022-11-09 20:00:50 +00:00
testDecoder ( " 80 9A 02 00 40 80 C1 01 41 81 C2 11 E0 00 00 80 " , pre = " DD " , comment = " SessionSetupRes " )
testDecoder ( " 80 9A 02 00 40 80 C1 01 41 81 C2 11 94 00 " , pre = " DD " , comment = " ServiceDiscoveryReq " )
testDecoder ( " 80 9A 02 00 40 80 C1 01 41 81 C2 11 A0 01 20 02 41 00 84 " , pre = " DD " , comment = " ServiceDiscoveryRes " )
testDecoder ( " 80 9A 02 00 40 80 C1 01 41 81 C2 11 B2 00 12 80 " , pre = " DD " , comment = " ServicePaymentSelectionReq " )
testDecoder ( " 80 9A 02 00 40 80 C1 01 41 81 C2 11 C0 00 " , pre = " DD " , comment = " ServicePaymentSelectionRes " )
print ( " The error response of the Ioniq with FAILED_ChargingSystemIncompatibility " )
testDecoder ( " 80 9A 02 00 40 80 C1 01 41 81 C2 11 30 20 00 0A 00 00 00 00 " , pre = " DD " , comment = " PowerDeliveryReq " )
2022-11-11 11:29:13 +00:00
print ( " The request of the Ioniq after ServicePaymentSelectionResponse " )
testDecoder ( " 80 9A 02 00 40 80 C1 01 41 81 C2 10 B8 " , pre = " DD " , comment = " ContractAuthenticationReq " )
2023-03-23 07:50:53 +00:00
if ( False ) :
2022-12-02 13:56:38 +00:00
print ( " The response of the Alpi chargeParameterDiscovery " )
testDecoder ( " 80 9A 02 00 00 00 00 03 1F DC 8B D0 80 02 00 00 00 00 00 10 00 2A 80 04 00 00 14 0C 00 40 80 E1 8A 3A 0A 0A 00 A0 60 60 00 08 0A 01 E2 30 30 06 10 " , pre = " DD " , comment = " ChargeParameterDiscoveryRes " )
2022-11-11 11:29:13 +00:00
2022-11-09 18:08:02 +00:00
if ( False ) :
testDecoder ( " 809a00113060 " , pre = " DD " , comment = " PowerDeliveryReq " )
testDecoder ( " 809a0011400420400000 " , pre = " DD " , comment = " PowerDeliveryRes " )
testDecoder ( " 809a0010d0400000c800410c8000 " , pre = " DD " , comment = " CurrentDemandReq " )
testDecoder ( " 809a0010e0020000003200019000000600 " , pre = " DD " , comment = " CurrentDemandRes " )
testDecoder ( " 809a001210400000 " , pre = " DD " , comment = " WeldingDetectionReq " )
testDecoder ( " 809a00122002000000320000 " , pre = " DD " , comment = " WeldingDetectionRes " )
testDecoder ( " 809a0011f0 " , pre = " DD " , comment = " SessionStopReq " )
testDecoder ( " 809a00120000 " , pre = " DD " , comment = " SessionStopRes " )
2022-11-08 21:53:18 +00:00
print ( " Number of fails: " + str ( nFail ) )
2022-11-07 12:38:06 +00:00
2022-11-08 21:53:18 +00:00
2022-11-06 21:47:32 +00:00
2022-11-08 21:53:18 +00:00
#print("Testing exiDecode with exiHexDemoSupportedApplicationProtocolRequestIoniq")
#print(exiDecode(exiHexDemoSupportedApplicationProtocolRequestIoniq))
#print("Testing exiDecode with exiHexDemoSupportedApplicationProtocolRequest2")
#strConverterResult = exiDecode(exiHexDemoSupportedApplicationProtocolRequest2)
#print(strConverterResult)
#strConverterResult = exiDecode(exiHexToByteArray(exiHexDemoSupportedApplicationProtocolRequest2))
#print(strConverterResult)
2022-11-20 13:23:37 +00:00