mirror of
https://github.com/uhi22/pyPLC.git
synced 2024-11-20 01:13:58 +00:00
robustness improved
This commit is contained in:
parent
aab380706f
commit
0edea0bc25
5 changed files with 65 additions and 9 deletions
21
fsmEvse.py
21
fsmEvse.py
|
@ -28,6 +28,8 @@ class fsmEvse():
|
|||
|
||||
def enterState(self, n):
|
||||
self.addToTrace("from " + str(self.state) + " entering " + str(n))
|
||||
if (self.state!=0) and (n==0):
|
||||
self.publishStatus("Waiting f AppHandShake")
|
||||
self.state = n
|
||||
self.cyclesInState = 0
|
||||
|
||||
|
@ -55,7 +57,7 @@ class fsmEvse():
|
|||
|
||||
def stateFunctionWaitForSessionSetupRequest(self):
|
||||
if (len(self.rxData)>0):
|
||||
self.addToTrace("In state stateFunctionWaitForSessionSetupRequest, received " + prettyHexMessage(self.rxData))
|
||||
self.addToTrace("In state WaitForSessionSetupRequest, received " + prettyHexMessage(self.rxData))
|
||||
exidata = removeV2GTPHeader(self.rxData)
|
||||
self.rxData = []
|
||||
strConverterResult = exiDecode(exidata, "DD")
|
||||
|
@ -213,6 +215,21 @@ class fsmEvse():
|
|||
self.state = 0
|
||||
self.cyclesInState = 0
|
||||
self.rxData = []
|
||||
self.Tcp.resetTheConnection()
|
||||
|
||||
def socketStateNotification(self, notification):
|
||||
if (notification==0):
|
||||
# The TCP informs us, that the connection is broken.
|
||||
# Let's restart the state machine.
|
||||
self.publishStatus("TCP conn broken")
|
||||
self.addToTrace("re-initializing fsmEvse due to broken connection")
|
||||
self.reInit()
|
||||
if (notification==1):
|
||||
# The TCP informs us, that it is listening, means waiting for incoming connection.
|
||||
self.publishStatus("Listening TCP")
|
||||
if (notification==2):
|
||||
# The TCP informs us, that a connection is established.
|
||||
self.publishStatus("TCP connected")
|
||||
|
||||
def __init__(self, addressManager, callbackAddToTrace, hardwareInterface, callbackShowStatus):
|
||||
self.callbackAddToTrace = callbackAddToTrace
|
||||
|
@ -224,7 +241,7 @@ class fsmEvse():
|
|||
if (self.faultInjectionDelayUntilSocketOpen_s>0):
|
||||
self.addToTrace("Fault injection: waiting " + str(self.faultInjectionDelayUntilSocketOpen_s) + " s until opening the TCP socket.")
|
||||
time.sleep(self.faultInjectionDelayUntilSocketOpen_s)
|
||||
self.Tcp = pyPlcTcpSocket.pyPlcTcpServerSocket(self.callbackAddToTrace)
|
||||
self.Tcp = pyPlcTcpSocket.pyPlcTcpServerSocket(self.callbackAddToTrace, self.socketStateNotification)
|
||||
self.state = 0
|
||||
self.cyclesInState = 0
|
||||
self.rxData = []
|
||||
|
|
3
pyPlc.py
3
pyPlc.py
|
@ -93,6 +93,9 @@ lblUInlet.pack()
|
|||
lblMode = tk.Label(root, text="(mode)")
|
||||
lblMode.pack()
|
||||
|
||||
if (myMode != C_PEV_MODE):
|
||||
lblUInlet['text']= ""
|
||||
|
||||
nKeystrokes=0
|
||||
# Bind the keyboard handler to all relevant elements:
|
||||
root.bind('<Key>', storekeyname)
|
||||
|
|
|
@ -630,6 +630,7 @@ class pyPlcHomeplug():
|
|||
self.showStatus(prettyMac(self.pevMac), "pevmac")
|
||||
# If we want to emulate an EVSE, we want to answer.
|
||||
if (self.iAmEvse==1):
|
||||
self.showStatus("SLAC started", "evseState")
|
||||
self.composeSlacParamCnf()
|
||||
self.addToTrace("[EVSE] transmitting CM_SLAC_PARAM.CNF")
|
||||
self.sniffer.sendpacket(bytes(self.mytransmitbuffer))
|
||||
|
@ -648,6 +649,7 @@ class pyPlcHomeplug():
|
|||
# to answer with a ATTEN_CHAR.IND, which normally contains the attenuation for 10 sounds, 58 groups.
|
||||
self.addToTrace("received MNBC_SOUND.IND")
|
||||
if (self.iAmEvse==1):
|
||||
self.showStatus("SLAC 2", "evseState")
|
||||
countdown = self.myreceivebuffer[38]
|
||||
if (countdown == 0):
|
||||
self.composeAttenCharInd()
|
||||
|
@ -678,6 +680,7 @@ class pyPlcHomeplug():
|
|||
# If we are EVSE, we send the response.
|
||||
self.addToTrace("received SLAC_MATCH.REQ")
|
||||
if (self.iAmEvse==1):
|
||||
self.showStatus("SLAC match", "evseState")
|
||||
self.composeSlacMatchCnf()
|
||||
self.addToTrace("[EVSE] transmitting SLAC_MATCH.CNF")
|
||||
self.sniffer.sendpacket(bytes(self.mytransmitbuffer))
|
||||
|
@ -1069,7 +1072,7 @@ class pyPlcHomeplug():
|
|||
self.evseMac = [0x55, 0x56, 0x57, 0xAA, 0xAA, 0xAA ] # a default evse MAC. Will be overwritten later.
|
||||
self.myMAC = self.addressManager.getLocalMacAddress()
|
||||
self.runningCounter=0
|
||||
self.ipv6 = pyPlcIpv6.ipv6handler(self.transmit, self.addressManager)
|
||||
self.ipv6 = pyPlcIpv6.ipv6handler(self.transmit, self.addressManager, self.callbackShowStatus)
|
||||
self.ipv6.ownMac = self.myMAC
|
||||
self.udplog = udplog.udplog(self.transmit, self.addressManager)
|
||||
self.udplog.log("Test message to verify the syslog. pyPlcHomeplug.py is in the init function.")
|
||||
|
|
|
@ -144,8 +144,8 @@ class ipv6handler():
|
|||
if ((self.destinationport == 15118) or (self.sourceport == 15118)): # port for the SECC
|
||||
if ((self.udpPayload[0]==0x01) and (self.udpPayload[1]==0xFE)): # protocol version 1 and inverted
|
||||
# it is a V2GTP message
|
||||
if (self.iAmEvse):
|
||||
# if we are the charger, lets save the cars IP for later use.
|
||||
if (self.iAmEvse) and (self.destinationport == 15118):
|
||||
# if we are the charger, and it is a message from car to charger, lets save the cars IP for later use.
|
||||
self.EvccIp = self.sourceIp
|
||||
self.addressManager.setPevIp(self.EvccIp)
|
||||
showAsHex(self.udpPayload, "V2GTP ")
|
||||
|
@ -170,6 +170,7 @@ class ipv6handler():
|
|||
# This was a valid SDP request. Let's respond, if we are the charger.
|
||||
if (self.iAmEvse==1):
|
||||
print("Ok, this was a valid SDP request. We are the SECC. Sending SDP response.")
|
||||
self.callbackShowStatus("SDP 2", "evseState")
|
||||
self.sendSdpResponse()
|
||||
else:
|
||||
print("v2gptPayloadLen on SDP request is " + str(v2gptPayloadLen) + " not supported")
|
||||
|
@ -353,11 +354,12 @@ class ipv6handler():
|
|||
if (self.nextheader == 0x06): # it is an TCP frame
|
||||
self.evaluateTcpPacket()
|
||||
|
||||
def __init__(self, transmitCallback, addressManager):
|
||||
def __init__(self, transmitCallback, addressManager, callbackShowStatus):
|
||||
self.enterEvseMode()
|
||||
#self.enterListenMode()
|
||||
self.transmit = transmitCallback
|
||||
self.addressManager = addressManager
|
||||
self.callbackShowStatus = callbackShowStatus
|
||||
#self.exiLogFile = open('SnifferExiLog.txt', 'w')
|
||||
# 16 bytes, a default IPv6 address for the charging station
|
||||
# self.SeccIp = [ 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0x06, 0xaa, 0xaa, 0xff, 0xfe, 0, 0xaa, 0xaa ]
|
||||
|
|
|
@ -144,8 +144,9 @@ class pyPlcTcpClientSocket():
|
|||
return d
|
||||
|
||||
class pyPlcTcpServerSocket():
|
||||
def __init__(self, callbackAddToTrace):
|
||||
def __init__(self, callbackAddToTrace, callbackStateNotification):
|
||||
self.callbackAddToTrace = callbackAddToTrace
|
||||
self.callbackStateNotification = callbackStateNotification
|
||||
# Todo: find the link-local IPv6 address automatically.
|
||||
#self.ipAdress = 'fe80::e0ad:99ac:52eb:85d3'
|
||||
#self.ipAdress = 'fe80::c690:83f3:fbcb:980e%15'
|
||||
|
@ -162,6 +163,29 @@ class pyPlcTcpServerSocket():
|
|||
self.ourSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
self.ourSocket.bind((self.ipAdress, self.tcpPort))
|
||||
self.ourSocket.listen(1)
|
||||
self.callbackStateNotification(1) # inform the higher level state machines, that TCP is listening
|
||||
self.addToTrace("pyPlcTcpSocket listening on port " + str(self.tcpPort))
|
||||
hostname=socket.gethostname()
|
||||
IPAddr=socket.gethostbyname(hostname)
|
||||
addressInfo = socket.getaddrinfo(hostname, None, socket.AF_INET6)
|
||||
#print("Your Computer Name is:"+hostname)
|
||||
self.addToTrace("The socket is linked the following IP addresses:")
|
||||
for i in range(0, len(addressInfo)):
|
||||
#fe80::4c46:fea5:b6c9:25a9
|
||||
IPv6Addr = addressInfo[i][4][0]
|
||||
self.addToTrace(IPv6Addr)
|
||||
self.read_list = [self.ourSocket]
|
||||
self.rxData = []
|
||||
|
||||
def resetTheConnection(self):
|
||||
# in case of a broken connection, here we try to start it again
|
||||
self.addToTrace("Trying to reset the TCP socket")
|
||||
# Todo: how to "reset" the socket?
|
||||
self.ourSocket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM, 0)
|
||||
self.ourSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
self.ourSocket.bind((self.ipAdress, self.tcpPort))
|
||||
self.ourSocket.listen(1)
|
||||
self.callbackStateNotification(1) # inform the higher level state machines, that TCP is listening
|
||||
self.addToTrace("pyPlcTcpSocket listening on port " + str(self.tcpPort))
|
||||
hostname=socket.gethostname()
|
||||
IPAddr=socket.gethostbyname(hostname)
|
||||
|
@ -194,10 +218,12 @@ class pyPlcTcpServerSocket():
|
|||
return -1
|
||||
# Simplification: We will send to the FIRST open connection, even we would have more connections open. This is
|
||||
# ok, because in our use case we have exactly one client.
|
||||
# Improvement: Instead of using the first (oldest(?)) connection, lets use the last. This helps for the case, that one
|
||||
# connection has crashed and the charger makes a new connection.
|
||||
totalsent = 0
|
||||
MSGLEN = len(txMessage)
|
||||
while totalsent < MSGLEN:
|
||||
sent = self.read_list[1].send(txMessage[totalsent:])
|
||||
sent = self.read_list[numberOfSockets-1].send(txMessage[totalsent:])
|
||||
if sent == 0:
|
||||
self.addToTrace("socket connection broken")
|
||||
return -1
|
||||
|
@ -217,6 +243,7 @@ class pyPlcTcpServerSocket():
|
|||
# and we append this new socket to the list of sockets, which in the next loop will be handled by the select.
|
||||
self.read_list.append(client_socket)
|
||||
self.addToTrace("Connection from " + str(address))
|
||||
self.callbackStateNotification(2) # inform the higher level state machines, that the connection is established.
|
||||
else:
|
||||
# It is not the "listener socket", it is an above created "client socket" for talking with a client.
|
||||
# Let's take the data from it:
|
||||
|
@ -232,7 +259,11 @@ class pyPlcTcpServerSocket():
|
|||
else:
|
||||
self.addToTrace("connection closed")
|
||||
s.close()
|
||||
self.callbackStateNotification(0) # inform the higher level state machines, that the connection is gone.
|
||||
try:
|
||||
self.read_list.remove(s)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue