Skip to content

Commit

Permalink
revised USB comminucation 2
Browse files Browse the repository at this point in the history
  • Loading branch information
zonoskar committed Nov 19, 2017
1 parent a5ff9af commit 859a654
Show file tree
Hide file tree
Showing 4 changed files with 268 additions and 72 deletions.
2 changes: 1 addition & 1 deletion __main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def mainloop( goodwe, pvoutput, csv, process):
process = processData.processData( pvoutput)

if config.get_input_source() == 'USB':
goodwe = goodweUsb.goodweUsb( ' ', ' ', 0x0084)
goodwe = goodweUsb.goodweUsb( 'test', ' ', 0x0084)
try:
goodwe.initialize()
print "USB connection initialized"
Expand Down
172 changes: 103 additions & 69 deletions goodweUsb.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import zlib
import enum

import testUsb
import goodweSample
import iGoodwe

Expand All @@ -26,16 +27,17 @@ class FC:
# Register function codes
offline = 0x00
allocreg = 0x01
query = 0x01
remreg = 0x02
regreq = 0x80
addconf = 0x81
remconf = 0x82

# Read function codes
query = 0x01
query_id = 0x02
query_stt = 0x03
# Read function codes
regreq = 0x80
result = 0x81
addconf = 0x81
result_id = 0x82
remconf = 0x82
result_stt = 0x83


Expand All @@ -56,6 +58,7 @@ def __init__(self, url, login_url, station_id):
self.m_dev = None
self.m_epi = None
self.m_initialized = False
self.m_emulated = "test" in url

self.cc_reg_switch = {FC.offline: self._skip_message,
FC.regreq: self._reg_received_registration,
Expand Down Expand Up @@ -146,32 +149,29 @@ def is_online( self):
#--------------------------------------------------------------------------
def read_sample_data( self):
'''Read a data sample.'''
print "Read sample data. State=" + str(self.m_state)
try:
self.state_switch[self.m_state]()
expectAnswer = True
while expectAnswer:
print "Switch state. State=" + str(self.m_state)
expectAnswer = self.state_switch[self.m_state]()
print "Read the response. State=" + str(self.m_state)
self._read_data_goodwe()
print "Answer read."
except Exception, ex:
raise IOError( "Cannot read from GoodweUSB in state %s: %s" % str(self.m_state), str(ex))


#--------------------------------------------------------------------------
def _read_data( self):
try:
data = self._read_data_goodwe()
self._convert_data( data)
print self.m_sample.to_string()
except Exception, ex:
print "Error, set offline"
# self.m_sample.set_online( 'Offline')
raise IOError( "Cannot read from GoodweUSB: " + str(ex))

return self.m_sample


#--------------------------------------------------------------------------
# internal functions
#--------------------------------------------------------------------------
def _usb_init( self):
'''This initialises the USB device'''
self.m_dev = usb.core.find(idVendor = self.m_deviceId)
if self.m_emulated:
self.m_dev = testUsb.testUsb( self.m_deviceId)
else:
print "find USB connection"
self.m_dev = usb.core.find(idVendor = self.m_deviceId)

if self.m_dev:
self.m_dev.reset()
Expand All @@ -191,28 +191,31 @@ def _usb_init( self):

try:
print "Claiming USB interface."
usb.util.claim_interface( self.m_dev, 0)
if not self.m_emulated:
usb.util.claim_interface( self.m_dev, 0)
except:
raise ValueError('Error claiming USB interface')

print "Getting active USB configuration."
cfg = self.m_dev.get_active_configuration()
intf = cfg[(0, 0)]
print intf

# get the BULK IN descriptor
self.m_epi = usb.util.find_descriptor(
intf,
# match our first out endpoint
custom_match= \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_IN)
if not self.m_emulated:
intf = cfg[(0, 0)]
print intf

# get the BULK IN descriptor
self.m_epi = usb.util.find_descriptor(
intf,
# match our first out endpoint
custom_match= \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_IN)

#--------------------------------------------------------------------------
def _terminate_usb( self):
'''This terminates the USB driver'''
usb.util.dispose_resources( self.m_dev)
if not self.m_emulated:
usb.util.dispose_resources( self.m_dev)
self.m_dev = None
self.m_epi = None
self.m_initialized = False
Expand All @@ -228,34 +231,44 @@ def _read_data_goodwe( self):
dataPtr = 0
lastByte = 0x00
inBuffer = ''

print "Read data from Goodwe."

while more:
try:
dataStream = self.m_dev.read( self.m_epi, 8, 1000)
# self._hexprint("Received:", dataStream)
except Exception, ex:
raise IOError(" Unable to read 8 bytes from USB: " + str(ex))

for byte in dataStream:
if chr(byte) == 0x55 and lastByte == 0xAA:
startFound = True
dataPtr = 0
dataLen = 0
lastByte = 0x00
inBuffer = chr(lastByte) + chr(byte)

if startFound:
if dataLen > 0 or self.dataPtr < 5:
inBuffer += chr(byte)
# print "dataLen:" + str(dataLen)
# print "dataPtr:" + str(dataPtr)
if dataLen > 0 or dataPtr < 5:
inBuffer += byte
dataPtr += 1
if dataPtr == 5:
dataLen = ord(byte) + 2
elif dataPtr > 5:
dataLen -= 1

if dataPtr >= 5 and dataLen == 0:
self._hexprint("inBuffer:", inBuffer)
startFound = False
self._check_crc_and_update_state( inBuffer)
more = False

# print "Check %d and %d" % (int(byte), int(lastByte))
if byte == chr(0x55) and lastByte == chr(0xAA):
# print "start found"
startFound = True
dataPtr = 0
dataLen = 0
inBuffer=''.join(chr(x) for x in [ord(lastByte), ord(byte)])
lastByte = 0x00

# print "Store lastbyte"

lastByte = byte

return inBuffer
Expand All @@ -270,21 +283,28 @@ def _check_crc_and_update_state( self, inBuffer):
lB = inBuffer[len(inBuffer)-1]
hC,lC = self._calc_crc16( inBuffer, len(inBuffer)-2)

if not (hB == hC and lB == lC):
if not ((ord(hB) == hC) and (ord(lB) == lC)):
raise ValueError("Calculated CRC doesn't match message CRC")

src = inBuffer[0]
dst = inBuffer[1]
cc = inBuffer[2]
fc = inBuffer[3]
leng = inBuffer[4]
data = inBuffer[5:]

src = ord(inBuffer[0])
dst = ord(inBuffer[1])
cc = ord(inBuffer[2])
fc = ord(inBuffer[3])
lenn =ord(inBuffer[4])
data = inBuffer[5:]

print "Src: " +str(src)
print "dst: " +str(src)
print "cc: " +str(cc)
print "fc: " +str(fc)
print "lenn: " +str(lenn)
# Call the reply function for the received message
if cc == CC.reg:
self.cc_reg_switch[fc]( src, leng, inBuffer)
print "Registration"
self.cc_reg_switch[fc]( src, lenn, inBuffer)
elif cc == CC.read:
self.cc_read_switch[fc]( src, leng, inBuffer)
print "Read"
self.cc_read_switch[fc]( src, lenn, inBuffer)

#--------------------------------------------------------------------------
def _calc_crc16( self, buffer, length):
Expand All @@ -300,27 +320,27 @@ def _calc_crc16( self, buffer, length):
return high, low

#--------------------------------------------------------------------------
def _skip_message( self, src, leng, inBuffer):
def _skip_message( self, src, lenn, inBuffer):
'''Not all possible messages have been implemented/can be received. This
handles thos messages.'''
print "An unused state was received: " + str(self.m_state) + "."

#--------------------------------------------------------------------------
def _reg_received_confirm_removal( self, src, leng, inBuffer):
def _reg_received_confirm_removal( self, src, lenn, inBuffer):
'''When the inverter sends the removal confirm message.'''
print "Inverter removed."
self.m_serialBuffer = ''
self.m_inverter_adr_confirmed = False

#--------------------------------------------------------------------------
def _reg_received_registration( self, src, leng, inBuffer):
def _reg_received_registration( self, src, lenn, inBuffer):
'''When the inverter sends the registration message.'''
print "Inverter registration received."
self.m_serialBuffer = inBuffer[0:16]
self.m_state = State.ALLOC

#--------------------------------------------------------------------------
def _reg_received_confirm_registration( self, src, leng, inBuffer):
def _reg_received_confirm_registration( self, src, lenn, inBuffer):
'''When th einverter sends the registration confirmation message.'''
print "Inverter registration confirmation received."
if self.m_inverter_adr == src:
Expand All @@ -330,9 +350,9 @@ def _reg_received_confirm_registration( self, src, leng, inBuffer):
self.m_state = State.OFFLINE

#--------------------------------------------------------------------------
def _read_received_message( self, src, leng, inBuffer):
def _read_received_message( self, src, lenn, inBuffer):
'''When the inverter sends the sample data.'''
self._convert_data( inBuffer, leng == 66)
self._convert_data( inBuffer, lenn == 66)

#--------------------------------------------------------------------------
def _scale_data( self, indata, offset, length, factor):
Expand Down Expand Up @@ -396,14 +416,20 @@ def _convert_data( self, indata, isDTseries):
def _remove_registration( self):
'''Function to handle the message state machine. This function handles
the removal of the registration state. No action is needed.'''
print "Remove registration"
print "Remove registration."
self._goodwe_send( self.m_inverter_adr, CC.reg, FC.remreg)
self.m_state = State.DISCOVER
return False

#--------------------------------------------------------------------------
def _discover_goodwe( self):
'''Function to handle the message state machine. This function handles
the discovery of the inverter. A message is sent.'''
print "Discover Goodwe."
if not self.m_inverter_adr_confirmed:
self._goodwe_send( 0x7F, CC.reg, FC.offline)
return False
return True

#--------------------------------------------------------------------------
def _alloc_register( self):
Expand All @@ -415,11 +441,13 @@ def _alloc_register( self):

self._goodwe_send( 0x7F, CC.reg, FC.allocreg, serial)
self.m_state = State.ALLOC_CONF
return False

#--------------------------------------------------------------------------
def _no_action( self):
'''Function to skip a certain state.'''
print "An unused state was received: " + str(self.m_state) + "."
return True

#--------------------------------------------------------------------------
def _read_data_init( self):
Expand All @@ -428,6 +456,7 @@ def _read_data_init( self):
previously negotiated inverter address.'''
self._goodwe_send( self.m_inverter_adr, CC.read, FC.query)
self.m_state = State.RUNNING
return True

#--------------------------------------------------------------------------
def _read_data( self):
Expand All @@ -436,21 +465,26 @@ def _read_data( self):
previously negotiated inverter address.'''
if self.m_inverter_adr_confirmed:
self._goodwe_send( self.m_inverter_adr, CC.read, FC.query)
return True
else:
raise IOError("Inverter not online, or address unkown. Cannot read.")

#--------------------------------------------------------------------------
def _goodwe_send( self, address, cc, fc, leng, data = None):
sendBuffer=''.join([0xAA, 0x55, 0x80, address, cc, fc])
def _goodwe_send( self, address, cc, fc, data = None):
print "Creating sendbuffer."
buf=''.join(chr(x) for x in [0xAA, 0x55, 0x80, address, cc, fc])

if data:
sendBuffer+=data
h,l=self._calc_crc16(sendBuffer, len(sendBuffer))
sendBuffer=sendBuffer + ''.join( [chr(h),chr(l)])
sendBuffer=''.join( chr(x) for x in [0xCC, 0x99, len(sendBuffer)])
self._hexprint("goodwe send", senfBuffer)
buf+=data
self._hexprint("goodwe added data", buf)

h,l = self._calc_crc16(buf, len(buf))
buf+=''.join(chr(x) for x in [h,l])
sendBuffer=''.join(chr(x) for x in [0xCC, 0x99, len(buf)]) + buf
self._hexprint("goodwe send", sendBuffer)

lenn = self.m_dev.ctrl_transfer( 0x21, 0x09, 0, 0, sendBuffer)

print lenn
if lenn != len(sendBuffer):
print 'received length ' + str(lenn) + ' is not ' + str(len(sendBuffer)) + '.'

Expand Down
6 changes: 4 additions & 2 deletions processNone.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ class processNone :

#--------------------------------------------------------------------------
def __init__( self, pvoutput):
pass
self.m_pvoutput = pvoutput


#--------------------------------------------------------------------------
Expand All @@ -13,7 +13,9 @@ def reset( self):

#--------------------------------------------------------------------------
def processSample( self, gw):
pass
if self.m_pvoutput:
self.m_pvoutput.post_data( gw)
print "Logging: " + gw.to_short_string()


#---------------- End of file ------------------------------------------------
Loading

0 comments on commit 859a654

Please sign in to comment.