mirror of
https://github.com/uhi22/pyPLC.git
synced 2024-11-20 01:13:58 +00:00
rework of the SLAC sequencer, prepared modem detection
This commit is contained in:
parent
97d8a3435b
commit
32660368f9
1 changed files with 214 additions and 157 deletions
371
pyPlcHomeplug.py
371
pyPlcHomeplug.py
|
@ -73,6 +73,21 @@ MMTYPE_CNF = 0x0001
|
||||||
MMTYPE_IND = 0x0002
|
MMTYPE_IND = 0x0002
|
||||||
MMTYPE_RSP = 0x0003
|
MMTYPE_RSP = 0x0003
|
||||||
|
|
||||||
|
STATE_INITIAL = 0
|
||||||
|
STATE_MODEM_SEARCH_ONGOING = 1
|
||||||
|
STATE_READY_FOR_SLAC = 2
|
||||||
|
STATE_WAITING_FOR_MODEM_RESTARTED = 3
|
||||||
|
STATE_WAITING_FOR_SLAC_PARAM_CNF = 4
|
||||||
|
STATE_BEFORE_START_ATTEN_CHAR = 5
|
||||||
|
STATE_SOUNDING = 6
|
||||||
|
STATE_WAIT_FOR_ATTEN_CHAR_IND = 7
|
||||||
|
STATE_ATTEN_CHAR_IND_RECEIVED = 8
|
||||||
|
STATE_DELAY_BEFORE_MATCH = 9
|
||||||
|
STATE_WAITING_FOR_SLAC_MATCH_CNF = 10
|
||||||
|
STATE_WAITING_FOR_RESTART2 = 11
|
||||||
|
STATE_FIND_MODEMS2 = 12
|
||||||
|
STATE_WAITING_FOR_RESTART2 = 13
|
||||||
|
STATE_SDP = 14
|
||||||
|
|
||||||
|
|
||||||
class pyPlcHomeplug():
|
class pyPlcHomeplug():
|
||||||
|
@ -578,9 +593,9 @@ class pyPlcHomeplug():
|
||||||
# As PEV, we receive the first response from the charger.
|
# As PEV, we receive the first response from the charger.
|
||||||
self.addToTrace("received SLAC_PARAM.CNF")
|
self.addToTrace("received SLAC_PARAM.CNF")
|
||||||
if (self.iAmPev==1):
|
if (self.iAmPev==1):
|
||||||
if (self.pevSequenceState==1): # we were waiting for the SlacParamCnf
|
if (self.pevSequenceState==STATE_WAITING_FOR_SLAC_PARAM_CNF): # we were waiting for the SlacParamCnf
|
||||||
self.pevSequenceDelayCycles = 4 # original Ioniq is waiting 200ms
|
self.pevSequenceDelayCycles = 4 # original Ioniq is waiting 200ms
|
||||||
self.enterState(2) # enter next state. Will be handled in the cyclic runPevSequencer
|
self.enterState(self.pevSequenceState+1) # enter next state. Will be handled in the cyclic runPevSequencer
|
||||||
|
|
||||||
def evaluateMnbcSoundInd(self):
|
def evaluateMnbcSoundInd(self):
|
||||||
# We received MNBC_SOUND.IND from the PEV. Normally this happens 10times, with a countdown (remaining number of sounds)
|
# We received MNBC_SOUND.IND from the PEV. Normally this happens 10times, with a countdown (remaining number of sounds)
|
||||||
|
@ -598,7 +613,7 @@ class pyPlcHomeplug():
|
||||||
self.addToTrace("received ATTEN_CHAR.IND")
|
self.addToTrace("received ATTEN_CHAR.IND")
|
||||||
if (self.iAmPev==1):
|
if (self.iAmPev==1):
|
||||||
self.addToTrace("[PEVSLAC] received AttenCharInd in state " + str(self.pevSequenceState))
|
self.addToTrace("[PEVSLAC] received AttenCharInd in state " + str(self.pevSequenceState))
|
||||||
if (self.pevSequenceState==6): # we were waiting for the AttenCharInd
|
if (self.pevSequenceState==STATE_WAIT_FOR_ATTEN_CHAR_IND): # we were waiting for the AttenCharInd
|
||||||
# todo: Handle the case when we receive multiple responses from different chargers.
|
# todo: Handle the case when we receive multiple responses from different chargers.
|
||||||
# Wait a certain time, and compare the attenuation profiles. Decide for the nearest charger.
|
# Wait a certain time, and compare the attenuation profiles. Decide for the nearest charger.
|
||||||
# Take the MAC of the charger from the frame, and store it for later use.
|
# Take the MAC of the charger from the frame, and store it for later use.
|
||||||
|
@ -606,11 +621,11 @@ class pyPlcHomeplug():
|
||||||
self.evseMac[i] = self.myreceivebuffer[6+i] # source MAC starts at offset 6
|
self.evseMac[i] = self.myreceivebuffer[6+i] # source MAC starts at offset 6
|
||||||
self.addressManager.setEvseMac(self.evseMac)
|
self.addressManager.setEvseMac(self.evseMac)
|
||||||
self.AttenCharIndNumberOfSounds = self.myreceivebuffer[69]
|
self.AttenCharIndNumberOfSounds = self.myreceivebuffer[69]
|
||||||
self.addToTrace("number of sounds reported by the EVSE (should be 10): " + str(self.AttenCharIndNumberOfSounds))
|
self.addToTrace("[PEVSLAC] number of sounds reported by the EVSE (should be 10): " + str(self.AttenCharIndNumberOfSounds))
|
||||||
self.composeAttenCharRsp()
|
self.composeAttenCharRsp()
|
||||||
self.addToTrace("[PEVSLAC] transmitting ATTEN_CHAR.RSP...")
|
self.addToTrace("[PEVSLAC] transmitting ATTEN_CHAR.RSP...")
|
||||||
self.transmit(self.mytransmitbuffer)
|
self.transmit(self.mytransmitbuffer)
|
||||||
self.pevSequenceState=7 # enter next state. Will be handled in the cyclic runPevSequencer
|
self.pevSequenceState=STATE_ATTEN_CHAR_IND_RECEIVED # enter next state. Will be handled in the cyclic runPevSequencer
|
||||||
|
|
||||||
|
|
||||||
def evaluateSlacMatchReq(self):
|
def evaluateSlacMatchReq(self):
|
||||||
|
@ -648,8 +663,8 @@ class pyPlcHomeplug():
|
||||||
self.composeSetKey(0)
|
self.composeSetKey(0)
|
||||||
self.addToTrace("transmitting CM_SET_KEY.REQ")
|
self.addToTrace("transmitting CM_SET_KEY.REQ")
|
||||||
self.sniffer.sendpacket(bytes(self.mytransmitbuffer))
|
self.sniffer.sendpacket(bytes(self.mytransmitbuffer))
|
||||||
if (self.pevSequenceState==9): # we were waiting for finishing the SLAC_MATCH.CNF and SET_KEY.REQ
|
if (self.pevSequenceState==STATE_WAITING_FOR_SLAC_MATCH_CNF): # we were waiting for finishing the SLAC_MATCH.CNF and SET_KEY.REQ
|
||||||
self.pevSequenceState=10
|
self.enterState(STATE_WAITING_FOR_RESTART2)
|
||||||
|
|
||||||
def evaluateReceivedHomeplugPacket(self):
|
def evaluateReceivedHomeplugPacket(self):
|
||||||
mmt = self.getManagementMessageType()
|
mmt = self.getManagementMessageType()
|
||||||
|
@ -673,7 +688,9 @@ class pyPlcHomeplug():
|
||||||
if (mmt == CM_GET_SW + MMTYPE_CNF):
|
if (mmt == CM_GET_SW + MMTYPE_CNF):
|
||||||
self.evaluateGetSwCnf()
|
self.evaluateGetSwCnf()
|
||||||
|
|
||||||
|
def isEvseModemFound(self):
|
||||||
|
return 0 # todo: look whether the MAC of the EVSE modem is in the list of detected modems
|
||||||
|
|
||||||
def enterState(self, n):
|
def enterState(self, n):
|
||||||
print("[PEVSLAC] from " + str(self.pevSequenceState) + " entering " + str(n))
|
print("[PEVSLAC] from " + str(self.pevSequenceState) + " entering " + str(n))
|
||||||
self.pevSequenceState = n
|
self.pevSequenceState = n
|
||||||
|
@ -682,165 +699,206 @@ class pyPlcHomeplug():
|
||||||
def isTooLong(self):
|
def isTooLong(self):
|
||||||
# The timeout handling function.
|
# The timeout handling function.
|
||||||
return (self.pevSequenceCyclesInState > 500)
|
return (self.pevSequenceCyclesInState > 500)
|
||||||
|
|
||||||
def runPevSequencer(self):
|
def runPevSequencer(self):
|
||||||
# in PEV mode, initiate the SLAC sequence
|
# in PevMode, check whether homeplug modem is connected, run the SLAC and SDP
|
||||||
self.pevSequenceCyclesInState+=1
|
self.pevSequenceCyclesInState+=1
|
||||||
# Todo: timeout handling to be implemented
|
if (self.pevSequenceState==STATE_INITIAL): # Initial state.
|
||||||
if (self.iAmPev==1):
|
# In real life we would check whether we see 5% PWM on the pilot line. We skip this check.
|
||||||
if (self.pevSequenceState==0): # waiting for start condition
|
self.isSimulationMode = 0
|
||||||
# In real life we would check whether we see 5% PWM on the pilot line.
|
self.isSDPDone = 0
|
||||||
# Then we would maybe wait a little bit until the homeplug modems are awake.
|
self.numberOfFoundModems = 0
|
||||||
# Now sending the first packet for the SLAC sequence:
|
self.nEvseModemMissingCounter = 0
|
||||||
self.composeSlacParamReq()
|
# First action: find the connected homeplug modems, by sending a GET_KEY
|
||||||
self.addToTrace("[PEVSLAC] transmitting SLAC_PARAM.REQ...")
|
self.composeGetKey()
|
||||||
self.transmit(self.mytransmitbuffer)
|
self.addToTrace("[PEVSLAC] searching for modems, transmitting GET_KEY.REQ...")
|
||||||
self.enterState(1)
|
self.transmit(self.mytransmitbuffer)
|
||||||
return
|
self.enterState(STATE_MODEM_SEARCH_ONGOING)
|
||||||
if (self.pevSequenceState==1): # waiting for SLAC_PARAM.CNF
|
return
|
||||||
if (self.isTooLong()):
|
if (self.pevSequenceState==STATE_MODEM_SEARCH_ONGOING): # Waiting for the modems to answer.
|
||||||
self.enterState(0)
|
print("test")
|
||||||
return
|
if (self.pevSequenceCyclesInState>=10):
|
||||||
if (self.pevSequenceState==2): # received SLAC_PARAM.CNF
|
# It was sufficient time to get the answers from the modems.
|
||||||
# between the SLAC_PARAM.CNF and the first START_ATTEN_CHAR.IND the Ioniq waits 200ms
|
self.addToTrace("[PEVSLAC] It was sufficient time to get the answers from the modems.")
|
||||||
if (self.pevSequenceDelayCycles>0):
|
# Let's see what we received.
|
||||||
self.pevSequenceDelayCycles-=1
|
if (self.numberOfFoundModems==0):
|
||||||
|
self.addToTrace("[PEVSLAC] No modem connected. We assume, we run in a simulation environment.")
|
||||||
|
self.isSimulationMode = 1
|
||||||
|
self.enterState(STATE_READY_FOR_SLAC)
|
||||||
return
|
return
|
||||||
|
else:
|
||||||
|
# we have at least a local modem. Maybe more remote.
|
||||||
|
# We want to make sure, that the local modem is set to the "default key", so that
|
||||||
|
# it is possible to connect to the PLC network for development purposes.
|
||||||
|
# That's why we check the key, and if it is not the intended, we set the default.
|
||||||
|
if (self.isDefaultLocalKey):
|
||||||
|
self.enterState(STATE_READY_FOR_SLAC)
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
self.composeSetKey() # set the default ("developer") key
|
||||||
|
self.addToTrace("[PEVSLAC] setting the default developer key...")
|
||||||
|
self.transmit(self.mytransmitbuffer)
|
||||||
|
self.enterState(STATE_WAITING_FOR_MODEM_RESTARTED)
|
||||||
|
return
|
||||||
|
return
|
||||||
|
if (self.pevSequenceState==STATE_WAITING_FOR_MODEM_RESTARTED): # Waiting for the modem to restart after SetKey.
|
||||||
|
if (self.pevSequenceCyclesInState>=100):
|
||||||
|
self.addToTrace("[PEVSLAC] Assuming the modem is up again.")
|
||||||
|
self.enterState(STATE_READY_FOR_SLAC)
|
||||||
|
return
|
||||||
|
if (self.pevSequenceState==STATE_READY_FOR_SLAC):
|
||||||
|
self.addToTrace("[PEVSLAC] Sending SLAC_PARAM.REQ...")
|
||||||
|
self.composeSlacParamReq()
|
||||||
|
self.transmit(self.mytransmitbuffer)
|
||||||
|
self.enterState(STATE_WAITING_FOR_SLAC_PARAM_CNF)
|
||||||
|
return
|
||||||
|
if (self.pevSequenceState==STATE_WAITING_FOR_SLAC_PARAM_CNF): # Waiting for slac_param confirmation.
|
||||||
|
self.pevSequenceDelayCycles = 6 # 6*30=180ms as preparation for the next state.
|
||||||
|
# Between the SLAC_PARAM.CNF and the first START_ATTEN_CHAR.IND the Ioniq waits 200ms.
|
||||||
|
self.nRemainingStartAttenChar = 3 # There shall be 3 START_ATTEN_CHAR messages.
|
||||||
|
if (self.pevSequenceCyclesInState>=30):
|
||||||
|
# No response for 1s, this is an error.
|
||||||
|
self.addToTrace("[PEVSLAC] Timeout while waiting for SLAC_PARAM.CNF")
|
||||||
|
self.enterState(STATE_INITIAL)
|
||||||
|
# (the normal state transition is done in the reception handler)
|
||||||
|
return
|
||||||
|
if (self.pevSequenceState==STATE_BEFORE_START_ATTEN_CHAR): # received SLAC_PARAM.CNF. Multiple transmissions of START_ATTEN_CHAR.
|
||||||
|
if (self.pevSequenceDelayCycles>0):
|
||||||
|
self.pevSequenceDelayCycles-=1
|
||||||
|
return
|
||||||
|
# The delay time is over. Let's transmit.
|
||||||
|
if (self.nRemainingStartAttenChar>0):
|
||||||
|
self.nRemainingStartAttenChar-=1
|
||||||
self.composeStartAttenCharInd()
|
self.composeStartAttenCharInd()
|
||||||
self.addToTrace("[PEVSLAC] transmitting START_ATTEN_CHAR.IND...")
|
self.addToTrace("[PEVSLAC] transmitting START_ATTEN_CHAR.IND...")
|
||||||
self.transmit(self.mytransmitbuffer)
|
self.transmit(self.mytransmitbuffer)
|
||||||
self.enterState(3)
|
self.pevSequenceDelayCycles = 0 # original from ioniq is 20ms between the START_ATTEN_CHAR
|
||||||
self.pevSequenceDelayCycles = 0
|
|
||||||
return
|
return
|
||||||
if (self.pevSequenceState==3):
|
else:
|
||||||
if (self.pevSequenceDelayCycles>0):
|
# all three START_ATTEN_CHAR.IND are finished. Now we send 10 MNBC_SOUND.IND
|
||||||
self.pevSequenceDelayCycles-=1
|
self.pevSequenceDelayCycles = 1 # original from ioniq is 40ms after the last START_ATTEN_CHAR.IND
|
||||||
return
|
self.remainingNumberOfSounds = 10 # We shall transmit 10 sound messages.
|
||||||
self.composeStartAttenCharInd()
|
self.enterState(STATE_SOUNDING)
|
||||||
self.addToTrace("[PEVSLAC] transmitting START_ATTEN_CHAR.IND...") # original from ioniq is 20ms after the first
|
return
|
||||||
self.transmit(self.mytransmitbuffer)
|
if (self.pevSequenceState==STATE_SOUNDING): # Multiple transmissions of MNBC_SOUND.IND.
|
||||||
self.enterState(4)
|
if (self.pevSequenceDelayCycles>0):
|
||||||
self.pevSequenceDelayCycles = 0
|
self.pevSequenceDelayCycles-=1
|
||||||
return
|
return
|
||||||
if (self.pevSequenceState==4):
|
if (self.remainingNumberOfSounds>0):
|
||||||
if (self.pevSequenceDelayCycles>0):
|
self.remainingNumberOfSounds-=1
|
||||||
self.pevSequenceDelayCycles-=1
|
self.composeNmbcSoundInd()
|
||||||
return
|
self.addToTrace("[PEVSLAC] transmitting MNBC_SOUND.IND...") # original from ioniq is 40ms after the last START_ATTEN_CHAR.IND
|
||||||
self.composeStartAttenCharInd()
|
|
||||||
self.addToTrace("[PEVSLAC] transmitting START_ATTEN_CHAR.IND...") # original from ioniq is 20ms after the second
|
|
||||||
self.transmit(self.mytransmitbuffer)
|
|
||||||
self.enterState(5)
|
|
||||||
self.pevSequenceDelayCycles = 1
|
|
||||||
self.remainingNumberOfSounds = 10
|
|
||||||
return
|
|
||||||
if (self.pevSequenceState==5): # START_ATTEN_CHAR.IND are finished. Now we send 10 MNBC_SOUND.IND
|
|
||||||
if (self.pevSequenceDelayCycles>0):
|
|
||||||
self.pevSequenceDelayCycles-=1
|
|
||||||
return
|
|
||||||
if (self.remainingNumberOfSounds>0):
|
|
||||||
self.remainingNumberOfSounds-=1
|
|
||||||
self.composeNmbcSoundInd()
|
|
||||||
self.addToTrace("[PEVSLAC] transmitting MNBC_SOUND.IND...") # original from ioniq is 40ms after the last START_ATTEN_CHAR.IND
|
|
||||||
self.transmit(self.mytransmitbuffer)
|
|
||||||
if (self.remainingNumberOfSounds==0):
|
|
||||||
self.enterState(6) # move fast to the next state, so that a fast response is catched in the correct state
|
|
||||||
self.pevSequenceDelayCycles = 0 # original from ioniq is 20ms between the messages
|
|
||||||
return
|
|
||||||
if (self.pevSequenceState==6): # waiting for ATTEN_CHAR.IND
|
|
||||||
# todo: it is possible that we receive this message from multiple chargers. We need
|
|
||||||
# to select the charger with the loudest reported signals.
|
|
||||||
if (self.isTooLong()):
|
|
||||||
self.enterState(0)
|
|
||||||
return
|
|
||||||
if (self.pevSequenceState==7): # ATTEN_CHAR.IND was received and the nearest charger decided and the ATTEN_CHAR.RSP was sent.
|
|
||||||
self.enterState(8)
|
|
||||||
self.pevSequenceDelayCycles = 30 # original from ioniq is 860ms to 980ms from ATTEN_CHAR.RSP to SLAC_MATCH.REQ
|
|
||||||
return
|
|
||||||
if (self.pevSequenceState==8): # ATTEN_CHAR.RSP was transmitted. Next is SLAC_MATCH.REQ
|
|
||||||
if (self.pevSequenceDelayCycles>0):
|
|
||||||
self.pevSequenceDelayCycles-=1
|
|
||||||
return
|
|
||||||
self.composeSlacMatchReq()
|
|
||||||
self.addToTrace("[PEVSLAC] transmitting SLAC_MATCH.REQ...")
|
|
||||||
self.transmit(self.mytransmitbuffer)
|
|
||||||
self.enterState(9)
|
|
||||||
return
|
|
||||||
if (self.pevSequenceState==9): # waiting for SLAC_MATCH.CNF
|
|
||||||
if (self.isTooLong()):
|
|
||||||
self.enterState(0)
|
|
||||||
return
|
|
||||||
if (self.pevSequenceState==10): # SLAC is finished, SET_KEY.REQ is transmitted. Wait some time, until
|
|
||||||
# the homeplug modem made the reset and is ready with the new key.
|
|
||||||
self.addToTrace("[PEVSLAC] waiting until homeplug modem starts up with new key...")
|
|
||||||
if (self.isSimulationMode==0):
|
|
||||||
self.pevSequenceDelayCycles = 200 # long waiting time if we have real homeplug modems
|
|
||||||
else:
|
|
||||||
self.pevSequenceDelayCycles = 10 # short waiting in simulation
|
|
||||||
self.enterState(11)
|
|
||||||
return
|
|
||||||
if (self.pevSequenceState==11):
|
|
||||||
if (self.pevSequenceDelayCycles>0):
|
|
||||||
self.pevSequenceDelayCycles-=1
|
|
||||||
return
|
|
||||||
# modem should be ready with new key. AVLN should be established.
|
|
||||||
# To check this, we broadcast a software version request. All modems in the network should respond.
|
|
||||||
self.numberOfSoftwareVersionResponses = 0
|
|
||||||
self.composeGetSwReq()
|
|
||||||
self.addToTrace("[PEVSLAC] transmitting GetSwReq...")
|
|
||||||
self.transmit(self.mytransmitbuffer)
|
self.transmit(self.mytransmitbuffer)
|
||||||
self.pevSequenceDelayCycles = 20
|
if (self.remainingNumberOfSounds==0):
|
||||||
self.enterState(12)
|
self.enterState(STATE_WAIT_FOR_ATTEN_CHAR_IND) # move fast to the next state, so that a fast response is catched in the correct state
|
||||||
|
self.pevSequenceDelayCycles = 0 # original from ioniq is 20ms between the messages
|
||||||
|
return
|
||||||
|
if (self.pevSequenceState==STATE_WAIT_FOR_ATTEN_CHAR_IND): # waiting for ATTEN_CHAR.IND
|
||||||
|
# todo: it is possible that we receive this message from multiple chargers. We need
|
||||||
|
# to select the charger with the loudest reported signals.
|
||||||
|
if (self.isTooLong()):
|
||||||
|
self.enterState(STATE_INITIAL)
|
||||||
|
return
|
||||||
|
#(the normal state transition is done in the reception handler)
|
||||||
|
if (self.pevSequenceState==STATE_ATTEN_CHAR_IND_RECEIVED): # ATTEN_CHAR.IND was received and the
|
||||||
|
# nearest charger decided and the
|
||||||
|
# ATTEN_CHAR.RSP was sent.
|
||||||
|
self.enterState(STATE_DELAY_BEFORE_MATCH)
|
||||||
|
self.pevSequenceDelayCycles = 30 # original from ioniq is 860ms to 980ms from ATTEN_CHAR.RSP to SLAC_MATCH.REQ
|
||||||
|
return
|
||||||
|
if (self.pevSequenceState==STATE_DELAY_BEFORE_MATCH): # Waiting time before SLAC_MATCH.REQ
|
||||||
|
if (self.pevSequenceDelayCycles>0):
|
||||||
|
self.pevSequenceDelayCycles-=1
|
||||||
return
|
return
|
||||||
if (self.pevSequenceState==12):
|
self.composeSlacMatchReq()
|
||||||
if (self.pevSequenceDelayCycles>0):
|
self.addToTrace("[PEVSLAC] transmitting SLAC_MATCH.REQ...")
|
||||||
self.pevSequenceDelayCycles-=1
|
self.transmit(self.mytransmitbuffer)
|
||||||
|
self.enterState(STATE_WAITING_FOR_SLAC_MATCH_CNF)
|
||||||
|
return
|
||||||
|
if (self.pevSequenceState==STATE_WAITING_FOR_SLAC_MATCH_CNF): # waiting for SLAC_MATCH.CNF
|
||||||
|
if (self.isTooLong()):
|
||||||
|
self.enterState(STATE_INITIAL)
|
||||||
|
return
|
||||||
|
self.pevSequenceDelayCycles = 100 # 3s reset wait time (may be a little bit too short, need a retry)
|
||||||
|
# (the normal state transition is done in the receive handler of SLAC_MATCH.CNF,
|
||||||
|
# including the transmission of SET_KEY.REQ)
|
||||||
|
return
|
||||||
|
if (self.pevSequenceState==STATE_WAITING_FOR_RESTART2): # SLAC is finished, SET_KEY.REQ is
|
||||||
|
# transmitted. The homeplug modem makes
|
||||||
|
# the reset and we need to wait until it
|
||||||
|
# is up with the new key.
|
||||||
|
if (self.pevSequenceDelayCycles>0):
|
||||||
|
self.pevSequenceDelayCycles-=1
|
||||||
|
return
|
||||||
|
self.addToTrace("[PEVSLAC] Checking whether the pairing worked, by GET_KEY.REQ...")
|
||||||
|
self.composeGetKey()
|
||||||
|
self.transmit(self.mytransmitbuffer)
|
||||||
|
self.enterState(STATE_FIND_MODEMS2)
|
||||||
|
return
|
||||||
|
if (self.pevSequenceState==STATE_FIND_MODEMS2): # Waiting for the modems to answer.
|
||||||
|
if (self.pevSequenceCyclesInState>=10):
|
||||||
|
# It was sufficient time to get the answers from the modems.
|
||||||
|
# Let's see what we received.
|
||||||
|
if (not self.isEvseModemFound()):
|
||||||
|
self.nEvseModemMissingCounter+=1
|
||||||
|
if (self.nEvseModemMissingCounter>5):
|
||||||
|
if (self.isSimulationMode):
|
||||||
|
self.addToTrace("[PEVSLAC] No EVSE modem. But this is fine, we are in SimulationMode.")
|
||||||
|
else:
|
||||||
|
# We lost the connection to the EVSE modem. Back to the beginning.
|
||||||
|
self.addToTrace("[PEVSLAC] We lost the connection to the EVSE modem. Back to the beginning.")
|
||||||
|
self.enterState(STATE_INITIAL)
|
||||||
|
return
|
||||||
|
# The EVSE modem is (shortly) not seen. Ask again.
|
||||||
|
self.pevSequenceDelayCycles=30
|
||||||
|
self.enterState(STATE_WAITING_FOR_RESTART2)
|
||||||
return
|
return
|
||||||
# we should have received a software version response from at least two modems.
|
# The EVSE modem is present.
|
||||||
print("[PEVSLAC] Number of modems in the AVLN: " + str(self.numberOfSoftwareVersionResponses))
|
self.nEvseModemMissingCounter=0
|
||||||
if ((self.numberOfSoftwareVersionResponses<2) and (self.isSimulationMode==0)):
|
# The AVLN is established, we have at least two modems in the network.
|
||||||
print("[PEVSLAC] ERROR: There should be at least two modems, one from car and one from charger.")
|
# If we did not SDP up to now, let's do it.
|
||||||
self.callbackReadyForTcp(0) # report that we lost the connection
|
if (self.isSDPDone):
|
||||||
self.addressManager.setSeccIp("") # forget the IPv6 of the charger
|
# SDP is already done. No need to do it again. We are finished for the normal case.
|
||||||
self.enterState(0)
|
# But we want to check whether the connection is still alive, so we start the
|
||||||
else:
|
# modem-search from time to time.
|
||||||
# The AVLN is established, we have two modems in the network.
|
self.pevSequenceDelayCycles = 300 # e.g. 10s
|
||||||
# Next step is to discover the chargers communication controller (SECC) using discovery protocol (SDP).
|
self.enterState(STATE_WAITING_FOR_RESTART2)
|
||||||
self.pevSequenceDelayCycles=0
|
return
|
||||||
self.SdpRepetitionCounter = 50 # prepare the number of retries for the SDP. The more the better.
|
# SDP was not done yet. Now we start it.
|
||||||
self.enterState(13)
|
# Next step is to discover the chargers communication controller (SECC) using discovery protocol (SDP).
|
||||||
return
|
self.pevSequenceDelayCycles=0
|
||||||
|
self.SdpRepetitionCounter = 50 # prepare the number of retries for the SDP. The more the better.
|
||||||
|
self.enterState(STATE_SDP)
|
||||||
|
return
|
||||||
|
|
||||||
if (self.pevSequenceState==13): # SDP request transmission and waiting for SDP response.
|
if (self.pevSequenceState==STATE_SDP): # SDP request transmission and waiting for SDP response.
|
||||||
if (len(self.addressManager.getSeccIp())>0):
|
if (len(self.addressManager.getSeccIp())>0):
|
||||||
# we received an SDP response, and can start the high-level communication
|
# we received an SDP response, and can start the high-level communication
|
||||||
print("[PEVSLAC] Now we know the chargers IP.")
|
print("[PEVSLAC] Now we know the chargers IP.")
|
||||||
self.callbackReadyForTcp(1)
|
self.isSDPDone = 1
|
||||||
self.enterState(14)
|
self.callbackReadyForTcp(1)
|
||||||
return
|
# Continue with checking the connection, for the case somebody pulls the plug.
|
||||||
if (self.pevSequenceDelayCycles>0):
|
self.pevSequenceDelayCycles = 300 # e.g. 10s
|
||||||
# just waiting until next action
|
self.enterState(STATE_WAITING_FOR_RESTART2)
|
||||||
self.pevSequenceDelayCycles-=1
|
|
||||||
return
|
|
||||||
if (self.SdpRepetitionCounter>0):
|
|
||||||
# Reference: The Ioniq waits 4.1s from the slac_match.cnf to the SDP request.
|
|
||||||
# Here we send the SdpRequest. Maybe too early, but we will retry if there is no response.
|
|
||||||
self.ipv6.initiateSdpRequest()
|
|
||||||
self.SdpRepetitionCounter-=1
|
|
||||||
self.pevSequenceDelayCycles = 10 # e.g. half-a-second delay until re-try of the SDP
|
|
||||||
self.enterState(13) # stick in the same state
|
|
||||||
return
|
|
||||||
if (self.isTooLong()):
|
|
||||||
print("[PEVSLAC] ERROR: Did not receive SDP response. Starting from the beginning.")
|
|
||||||
self.enterState(0)
|
|
||||||
return
|
return
|
||||||
if (self.pevSequenceState==14): # AVLN is established. SDP finished. Nothing more to do, just wait until unplugging.
|
if (self.pevSequenceDelayCycles>0):
|
||||||
# Todo: if (self.isUnplugged()): self.pevSequenceState=0
|
# just waiting until next action
|
||||||
# Or we just check the connection cyclically by sending software version requests...
|
self.pevSequenceDelayCycles-=1
|
||||||
self.pevSequenceDelayCycles = 500
|
|
||||||
self.enterState(11)
|
|
||||||
return
|
return
|
||||||
# invalid state is reached. As robustness measure, go to initial state.
|
if (self.SdpRepetitionCounter>0):
|
||||||
self.enterState(0)
|
# Reference: The Ioniq waits 4.1s from the slac_match.cnf to the SDP request.
|
||||||
|
# Here we send the SdpRequest. Maybe too early, but we will retry if there is no response.
|
||||||
|
self.ipv6.initiateSdpRequest()
|
||||||
|
self.SdpRepetitionCounter-=1
|
||||||
|
self.pevSequenceDelayCycles = 15 # e.g. half-a-second delay until re-try of the SDP
|
||||||
|
self.enterState(STATE_SDP) # stick in the same state
|
||||||
|
return
|
||||||
|
# All repetitions are over, no SDP response was seen. Back to the beginning.
|
||||||
|
print("[PEVSLAC] ERROR: Did not receive SDP response. Starting from the beginning.")
|
||||||
|
self.enterState(STATE_INITIAL)
|
||||||
|
return
|
||||||
|
# invalid state is reached. As robustness measure, go to initial state.
|
||||||
|
self.enterState(STATE_INITIAL)
|
||||||
|
|
||||||
|
|
||||||
def findEthernetAdaptor(self):
|
def findEthernetAdaptor(self):
|
||||||
|
@ -937,11 +995,10 @@ class pyPlcHomeplug():
|
||||||
def mainfunction(self):
|
def mainfunction(self):
|
||||||
# https://stackoverflow.com/questions/31305712/how-do-i-make-libpcap-pcap-loop-non-blocking
|
# https://stackoverflow.com/questions/31305712/how-do-i-make-libpcap-pcap-loop-non-blocking
|
||||||
# Tell the sniffer to give max 100 received packets to the callback function:
|
# Tell the sniffer to give max 100 received packets to the callback function:
|
||||||
self.sniffer.dispatch(100, self.receiveCallback, None)
|
self.sniffer.dispatch(100, self.receiveCallback, None)
|
||||||
|
|
||||||
|
|
||||||
self.showStatus("nPacketsReceived=" + str(self.nPacketsReceived))
|
self.showStatus("nPacketsReceived=" + str(self.nPacketsReceived))
|
||||||
self.runPevSequencer() # run the message sequencer for the PEV side
|
if (self.iAmPev==1):
|
||||||
|
self.runPevSequencer() # run the message sequencer for the PEV side
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self.sniffer.close()
|
self.sniffer.close()
|
||||||
|
|
Loading…
Reference in a new issue