Update rflib to support YARD Stick One

master
Sebastian Kinne 2015-10-05 13:55:56 -07:00
parent 923647f50d
commit 0cbaa989a9
8 changed files with 4197 additions and 2561 deletions

View File

@ -1,9 +1,12 @@
#!/usr/bin/env ipython #!/usr/bin/env ipython -i --no-banner
from chipcon_nic import * from chipcon_nic import *
import rflib.bits as rfbits
RFCAT_START_SPECAN = 0x40 RFCAT_START_SPECAN = 0x40
RFCAT_STOP_SPECAN = 0x41 RFCAT_STOP_SPECAN = 0x41
MAX_FREQ = 936e6
class RfCat(FHSSNIC): class RfCat(FHSSNIC):
def RFdump(self, msg="Receiving", maxnum=100, timeoutms=1000): def RFdump(self, msg="Receiving", maxnum=100, timeoutms=1000):
try: try:
@ -23,7 +26,7 @@ class RfCat(FHSSNIC):
print "Scanning range: " print "Scanning range: "
while not keystop(): while not keystop():
try: try:
print print "(press Enter to quit)"
for freq in xrange(int(basefreq), int(basefreq+(inc*count)), int(inc)): for freq in xrange(int(basefreq), int(basefreq+(inc*count)), int(inc)):
print "Scanning for frequency %d..." % freq print "Scanning for frequency %d..." % freq
self.setFreq(freq) self.setFreq(freq)
@ -40,14 +43,13 @@ class RfCat(FHSSNIC):
freq, delta = self._doSpecAn(basefreq, inc, count) freq, delta = self._doSpecAn(basefreq, inc, count)
import rflib.ccspecan as rfspecan import rflib.ccspecan as rfspecan
if not hasattr(self, "_qt_app") or self._qt_app is None: rfspecan.ensureQapp()
self._qt_app = rfspecan.QtGui.QApplication([])
fhigh = freq + (delta*(count+1)) fhigh = freq + (delta*(count+1))
window = rfspecan.Window(self, freq, fhigh, delta, 0) window = rfspecan.Window(self, freq, fhigh, delta, 0)
window.show() window.show()
self._qt_app.exec_() rfspecan._qt_app.exec_()
def _doSpecAn(self, basefreq, inc, count): def _doSpecAn(self, basefreq, inc, count):
''' '''
@ -55,6 +57,9 @@ class RfCat(FHSSNIC):
''' '''
if count>255: if count>255:
raise Exception("sorry, only 255 samples per pass... (count)") raise Exception("sorry, only 255 samples per pass... (count)")
if (count * inc) + basefreq > MAX_FREQ:
raise Exception("Sorry, %1.3f + (%1.3f * %1.3f) is higher than %1.3f" %
(basefreq, count, inc))
self.getRadioConfig() self.getRadioConfig()
self._specan_backup_radiocfg = self.radiocfg self._specan_backup_radiocfg = self.radiocfg
@ -79,7 +84,9 @@ class RfCat(FHSSNIC):
def rf_configure(*args, **k2args): def rf_configure(*args, **k2args):
pass pass
def rf_redirection(self, fdtup): def rf_redirection(self, fdtup, use_rawinput=False, printable=False):
buf = ''
if len(fdtup)>1: if len(fdtup)>1:
fd0i, fd0o = fdtup fd0i, fd0o = fdtup
else: else:
@ -90,12 +97,15 @@ class RfCat(FHSSNIC):
if hasattr(fd0i, 'recv'): if hasattr(fd0i, 'recv'):
fdsock = True fdsock = True
try:
while True: while True:
x,y,z = select.select([fd0i ], [], [], .1)
#if self._pause: #if self._pause:
# continue # continue
try:
x,y,z = select.select([fd0i ], [], [], .1)
if fd0i in x: if fd0i in x:
# FIXME: make this aware of VLEN/FLEN and the proper length
if fdsock: if fdsock:
data = fd0i.recv(self.max_packet_size) data = fd0i.recv(self.max_packet_size)
else: else:
@ -104,17 +114,66 @@ class RfCat(FHSSNIC):
if not len(data): # terminated socket if not len(data): # terminated socket
break break
buf += data
pktlen, vlen = self.getPktLEN()
if vlen:
pktlen = ord(buf[0])
#FIXME: probably want to take in a length struct here and then only send when we have that many bytes...
data = buf[:pktlen]
if use_rawinput:
data = eval('"%s"'%data)
if len(buf) >= pktlen:
self.RFxmit(data) self.RFxmit(data)
except ChipconUsbTimeoutException:
pass
try: try:
data = self.RFrecv(0) data, time = self.RFrecv(1)
if printable:
data = "\n"+str(time)+": "+repr(data)
else:
data = struct.pack("<L", time) + struct.pack("<H", len(data)) + data
if fdsock: if fdsock:
fd0o.sendall(data) fd0o.sendall(data)
else: else:
fd0o.write(data) fd0o.write(data)
except ChipconUsbTimeoutException: except ChipconUsbTimeoutException:
pass pass
#special handling of specan dumps... somewhat set in solid jello
try:
data, time = self.recv(APP_SPECAN, 1, 1)
data = struct.pack("<L", time) + struct.pack("<H", len(data)) + data
if fdsock:
fd0o.sendall(data)
else:
fd0o.write(data)
except ChipconUsbTimeoutException:
#print "this is a valid exception, run along... %x"% APP_SPECAN
pass
except KeyboardInterrupt:
self.setModeIDLE()
class InverseCat(RfCat):
def setMdmSyncWord(self, word, radiocfg=None):
FHSSNIC.setMdmSyncWord(self, word ^ 0xffff, radiocfg)
def RFrecv(self, timeout=1000):
global data
data,timestamp = RfCat.RFrecv(self, timeout)
return rfbits.invertBits(data),timestamp
def RFxmit(self, data):
return RfCat.RFxmit(self, rfbits.invertBits(data) )
def cleanupInteractiveAtExit(): def cleanupInteractiveAtExit():
try: try:
if d.getDebugCodes(): if d.getDebugCodes():
@ -141,6 +200,14 @@ def interactive(idx=0, DongleClass=RfCat, intro=''):
print intro print intro
ipsh.mainloop(intro) ipsh.mainloop(intro)
except ImportError, e:
try:
from IPython.terminal.interactiveshell import TerminalInteractiveShell
ipsh = TerminalInteractiveShell()
ipsh.user_global_ns.update(gbls)
ipsh.user_global_ns.update(lcls)
ipsh.autocall = 2 # don't require parenthesis around *everything*. be smart!
ipsh.mainloop(intro)
except ImportError, e: except ImportError, e:
try: try:
from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell

View File

@ -1,5 +1,76 @@
import struct import struct
fmtsLSB = [None, "B", "<H", "<I", "<I", "<Q", "<Q", "<Q", "<Q"]
fmtsMSB = [None, "B", ">H", ">I", ">I", ">Q", ">Q", ">Q", ">Q"]
sizes = [ 0, 1, 2, 4, 4, 8, 8, 8, 8]
masks = [ (1<<(8*i))-1 for i in xrange(9) ]
def wtfo(string):
outstr = []
bitlen = len(outstr) * 8
for x in range(8):
outstr.append(shiftString(string, x))
string = strBitReverse(string)
for x in range(8):
outstr.append(shiftString(string, x))
return outstr
def strBitReverse(string):
# FIXME: this is really dependent upon python's number system. large strings will not convert well.
# FIXME: break up array of 8-bit numbers and bit-swap in the array
num = 0
bits = len(string)*8
# convert to MSB number
for x in range(len(string)):
ch = string[x]
#num |= (ord(ch)<<(8*x)) # this is LSB
num <<= 8
num |= ord(ch)
print (hex(num))
rnum = bitReverse(num, bits)
print (hex(rnum))
# convert back from MSB number to string
out = []
for x in range(len(string)):
out.append(chr(rnum&0xff))
rnum >>= 8
out.reverse()
print(''.join(out).encode('hex'))
return ''.join(out)
def strXorMSB(string, xorval, size):
'''
lsb
pads end of string with 00
'''
out = []
strlen = len(string)
string += "\x00" * sizes[size]
for idx in range(0, strlen, size):
tempstr = string[idx:idx+sizes[size]]
temp, = struct.unpack( fmtsMSB[size], tempstr )
temp ^= xorval
temp &= masks[size]
tempstr = struct.pack( fmtsMSB[size], temp )[-size:]
out.append(tempstr)
return ''.join(out)
def bitReverse(num, bitcnt):
newnum = 0
for idx in range(bitcnt):
newnum <<= 1
newnum |= num&1
num >>= 1
return newnum
def shiftString(string, bits): def shiftString(string, bits):
carry = 0 carry = 0
news = [] news = []
@ -10,15 +81,66 @@ def shiftString(string, bits):
news.append("%c"%newc) news.append("%c"%newc)
return "".join(news) return "".join(news)
def findDword(byts, inverted=False): def getNextByte_feedbackRegister7bitsMSB():
'''
this returns a byte of a 7-bit feedback register stemming off bits 4 and 7
the register is 7 bits long, but we return a more usable 8bits (ie.
'''
global fbRegister
retval = 0
for x in range(8): #MSB,
retval <<= 1
retval |= (fbRegister >> 6) # start with bit 7
nb = ( ( fbRegister>>3) ^ (fbRegister>>6)) &1
fbRegister = ( ( fbRegister << 1 ) | nb ) & 0x7f # do shifting
#print "retval: %x fbRegister: %x bit7: %x nb: %x" % (retval, fbRegister, (fbRegister>>6), nb)
return retval
def getNextByte_feedbackRegister7bitsLSB():
'''
this returns a byte of a 7-bit feedback register stemming off bits 4 and 7
the register is 7 bits long, but we return a more usable 8bits (ie.
'''
global fbRegister
retval = 0
for x in range(8): #MSB,
retval >>= 1
retval |= ((fbRegister << 1)&0x80) # start with bit 7
nb = ( ( fbRegister>>3) ^ (fbRegister>>6)) &1
fbRegister = ( ( fbRegister << 1 ) | nb ) & 0x7f # do shifting
#print "retval: %x fbRegister: %x bit7: %x nb: %x" % (retval, fbRegister, (fbRegister>>6), nb)
return retval
def whitenData(data, seed=0xffff, getNextByte=getNextByte_feedbackRegister7bitsMSB):
global fbRegister
fbRegister = seed
carry = 0
news = []
for x in xrange(len(data)-1):
newc = ((ord(data[x]) ^ getNextByte() ) & 0xff)
news.append("%c"%newc)
return "".join(news)
def findSyncWord(byts, sensitivity=4, minpreamble=2):
'''
seek SyncWords from a raw bitstream.
assumes we capture at least two (more likely 3 or more) preamble bytes
'''
possDwords = [] possDwords = []
# find the preamble (if any) # find the preamble (if any)
while True: while True: # keep searching through string until we don't find any more preamble bits to pick on
sbyts = byts sbyts = byts
pidx = byts.find("\xaa\xaa") pidx = byts.find("\xaa"*minpreamble)
if pidx == -1: if pidx == -1:
pidx = byts.find("\x55\x55") pidx = byts.find("\x55"*minpreamble)
byts = shiftString(byts,1) byts = shiftString(byts, 1)
if pidx == -1: if pidx == -1:
return possDwords return possDwords
@ -57,7 +179,8 @@ def findDword(byts, inverted=False):
# bits1 >>= 2 # bits1 >>= 2
#print "bits: %x" % (bits1) #print "bits: %x" % (bits1)
for frontbits in xrange((0,1)[inverted], 17, 2): bitcount = min( 2 * sensitivity, 17 )
for frontbits in xrange( bitcount ): # with so many bit-inverted systems, let's not assume we know anything about the bit-arrangement. \x55\x55 could be a perfectly reasonable preamble.
poss = (bits1 >> frontbits) & 0xffff poss = (bits1 >> frontbits) & 0xffff
if not poss in possDwords: if not poss in possDwords:
possDwords.append(poss) possDwords.append(poss)
@ -65,7 +188,7 @@ def findDword(byts, inverted=False):
return possDwords return possDwords
def findDwordDoubled(byts): def findSyncWordDoubled(byts):
possDwords = [] possDwords = []
# find the preamble (if any) # find the preamble (if any)
bitoff = 0 bitoff = 0
@ -345,3 +468,29 @@ def reprBitArray(bitAry, width=194):
bots = "".join(bot) bots = "".join(bot)
return "\n".join([tops, mids, bots]) return "\n".join([tops, mids, bots])
def invertBits(data):
output = []
ldata = len(data)
off = 0
if ldata&1:
output.append( chr( ord( data[0] ) ^ 0xff) )
off = 1
if ldata&2:
output.append( struct.pack( "<H", struct.unpack( "<H", data[off:off+2] )[0] ^ 0xffff) )
off += 2
#method 1
#for idx in xrange( off, ldata, 4):
# output.append( struct.pack( "<I", struct.unpack( "<I", data[idx:idx+4] )[0] & 0xffff) )
#method2
count = ldata / 4
#print ldata, count
numlist = struct.unpack( "<%dI" % count, data[off:] )
modlist = [ struct.pack("<L", (x^0xffffffff) ) for x in numlist ]
output.extend(modlist)
return ''.join(output)

File diff suppressed because it is too large Load Diff

View File

@ -29,6 +29,10 @@ import cPickle as pickle
from PySide import QtCore, QtGui from PySide import QtCore, QtGui
from PySide.QtCore import Qt, QPointF, QLineF from PySide.QtCore import Qt, QPointF, QLineF
def ensureQapp():
global _qt_app
if not globals().get("_qt_app"):
_qt_app = QtGui.QApplication([])
APP_SPECAN = 0x43 APP_SPECAN = 0x43

File diff suppressed because it is too large Load Diff

965
rflib/chipcon_usb.py Normal file
View File

@ -0,0 +1,965 @@
#!/usr/bin/env ipython
import sys, threading, time, struct, select
import usb
import bits
from chipcondefs import *
from rflib_version import *
DEFAULT_USB_TIMEOUT = 1000
EP_TIMEOUT_IDLE = 400
EP_TIMEOUT_ACTIVE = 10
USB_MAX_BLOCK_SIZE = 512
USB_RX_WAIT = 1000
USB_TX_WAIT = 10000
USB_BM_REQTYPE_TGTMASK =0x1f
USB_BM_REQTYPE_TGT_DEV =0x00
USB_BM_REQTYPE_TGT_INTF =0x01
USB_BM_REQTYPE_TGT_EP =0x02
USB_BM_REQTYPE_TYPEMASK =0x60
USB_BM_REQTYPE_TYPE_STD =0x00
USB_BM_REQTYPE_TYPE_CLASS =0x20
USB_BM_REQTYPE_TYPE_VENDOR =0x40
USB_BM_REQTYPE_TYPE_RESERVED =0x60
USB_BM_REQTYPE_DIRMASK =0x80
USB_BM_REQTYPE_DIR_OUT =0x00
USB_BM_REQTYPE_DIR_IN =0x80
USB_GET_STATUS =0x00
USB_CLEAR_FEATURE =0x01
USB_SET_FEATURE =0x03
USB_SET_ADDRESS =0x05
USB_GET_DESCRIPTOR =0x06
USB_SET_DESCRIPTOR =0x07
USB_GET_CONFIGURATION =0x08
USB_SET_CONFIGURATION =0x09
USB_GET_INTERFACE =0x0a
USB_SET_INTERFACE =0x11
USB_SYNCH_FRAME =0x12
APP_GENERIC = 0x01
APP_DEBUG = 0xfe
APP_SYSTEM = 0xff
SYS_CMD_PEEK = 0x80
SYS_CMD_POKE = 0x81
SYS_CMD_PING = 0x82
SYS_CMD_STATUS = 0x83
SYS_CMD_POKE_REG = 0x84
SYS_CMD_GET_CLOCK = 0x85
SYS_CMD_BUILDTYPE = 0x86
SYS_CMD_BOOTLOADER = 0x87
SYS_CMD_RFMODE = 0x88
SYS_CMD_PARTNUM = 0x8e
SYS_CMD_RESET = 0x8f
EP0_CMD_GET_DEBUG_CODES = 0x00
EP0_CMD_GET_ADDRESS = 0x01
EP0_CMD_POKEX = 0x01
EP0_CMD_PEEKX = 0x02
EP0_CMD_PING0 = 0x03
EP0_CMD_PING1 = 0x04
EP0_CMD_RESET = 0xfe
DEBUG_CMD_STRING = 0xf0
DEBUG_CMD_HEX = 0xf1
DEBUG_CMD_HEX16 = 0xf2
DEBUG_CMD_HEX32 = 0xf3
DEBUG_CMD_INT = 0xf4
EP5OUT_MAX_PACKET_SIZE = 64
EP5IN_MAX_PACKET_SIZE = 64
# EP5OUT_BUFFER_SIZE must match firmware/include/chipcon_usb.h definition
EP5OUT_BUFFER_SIZE = 516
LC_USB_INITUSB = 0x2
LC_MAIN_RFIF = 0xd
LC_USB_DATA_RESET_RESUME = 0xa
LC_USB_RESET = 0xb
LC_USB_EP5OUT = 0xc
LC_RF_VECTOR = 0x10
LC_RFTXRX_VECTOR = 0x11
LCE_USB_EP5_TX_WHILE_INBUF_WRITTEN = 0x1
LCE_USB_EP0_SENT_STALL = 0x4
LCE_USB_EP5_OUT_WHILE_OUTBUF_WRITTEN = 0x5
LCE_USB_EP5_LEN_TOO_BIG = 0x6
LCE_USB_EP5_GOT_CRAP = 0x7
LCE_USB_EP5_STALL = 0x8
LCE_USB_DATA_LEFTOVER_FLAGS = 0x9
LCE_RF_RXOVF = 0x10
LCE_RF_TXUNF = 0x11
LCS = {}
LCES = {}
lcls = locals()
for lcl in lcls.keys():
if lcl.startswith("LCE_"):
LCES[lcl] = lcls[lcl]
LCES[lcls[lcl]] = lcl
if lcl.startswith("LC_"):
LCS[lcl] = lcls[lcl]
LCS[lcls[lcl]] = lcl
CHIPS = {
0x91: "CC2511",
0x81: "CC2510",
0x11: "CC1111",
0x01: "CC1110",
}
def keystop(delay=0):
return len(select.select([sys.stdin],[],[],delay)[0])
def getRfCatDevices():
'''
returns a list of USB device objects for any rfcats that are plugged in
NOTE: if any rfcats are in bootloader mode, this will cause python to Exit
'''
rfcats = []
for bus in usb.busses():
for dev in bus.devices:
# OpenMoko assigned or Legacy TI
if (dev.idVendor == 0x0451 and dev.idProduct == 0x4715) or (dev.idVendor == 0x1d50 and (dev.idProduct == 0x6047 or dev.idProduct == 0x6048 or dev.idProduct == 0x605b)):
rfcats.append(dev)
elif (dev.idVendor == 0x1d50 and (dev.idProduct == 0x6049 or dev.idProduct == 0x604a)):
print "Already in Bootloader Mode... exiting"
exit(0)
return rfcats
class ChipconUsbTimeoutException(Exception):
def __str__(self):
return "Timeout waiting for USB response."
direct=False
class USBDongle:
######## INITIALIZATION ########
def __init__(self, idx=0, debug=False, copyDongle=None, RfMode=RFST_SRX):
self.rsema = None
self.xsema = None
self._bootloader = False
self._init_on_reconnect = True
self._do = None
self.idx = idx
self.cleanup()
self._debug = debug
self._quiet = False
self._threadGo = threading.Event()
self._recv_time = 0
self.radiocfg = RadioConfig()
self._rfmode = RfMode
self._radio_configured = False
self.ctrl_thread = threading.Thread(target=self.run_ctrl)
self.ctrl_thread.setDaemon(True)
self.ctrl_thread.start()
self.recv_thread = threading.Thread(target=self.runEP5_recv)
self.recv_thread.setDaemon(True)
self.recv_thread.start()
self.send_thread = threading.Thread(target=self.runEP5_send)
self.send_thread.setDaemon(True)
self.send_thread.start()
self.resetup(copyDongle=copyDongle)
self.max_packet_size = USB_MAX_BLOCK_SIZE
def cleanup(self):
self._usberrorcnt = 0;
self.recv_queue = ''
self.recv_mbox = {}
self.recv_event = threading.Event()
self.xmit_event = threading.Event()
self.reset_event = threading.Event()
self.xmit_queue = []
self.xmit_event.clear()
self.reset_event.clear()
self.trash = []
def setRFparameters(self):
pass
def run_ctrl(self):
'''
we wait for reset events and run resetup
'''
while True:
self.reset_event.wait()
self.resetup(False)
self.reset_event.clear()
time.sleep(4)
def setup(self, console=True, copyDongle=None):
global dongles
if copyDongle is not None:
self.devnum = copyDongle.devnum
self._d = copyDongle._d
self._do = copyDongle._do
self._usbmaxi = copyDongle._usbmaxi
self._usbmaxo = copyDongle._usbmaxo
self._usbcfg = copyDongle._usbcfg
self._usbintf = copyDongle._usbintf
self._usbeps = copyDongle._usbeps
self._threadGo.set()
self.ep5timeout = EP_TIMEOUT_ACTIVE
copyDongle._threadGo.clear() # we're taking over from here.
self.rsema = copyDongle.rsema
self.xsema = copyDongle.xsema
return
dongles = []
self.ep5timeout = EP_TIMEOUT_ACTIVE
for dev in getRfCatDevices():
if self._debug: print >>sys.stderr,(dev)
do = dev.open()
iSN = do.getDescriptor(1,0,50)[16]
devnum = dev.devnum
dongles.append((devnum, dev, do))
dongles.sort()
if len(dongles) == 0:
raise(Exception("No Dongle Found. Please insert a RFCAT dongle."))
self.rsema = threading.Lock()
self.xsema = threading.Lock()
# claim that interface!
do = dongles[self.idx][2]
try:
do.claimInterface(0)
except Exception,e:
if console or self._debug: print >>sys.stderr,("Error claiming usb interface:" + repr(e))
self.devnum, self._d, self._do = dongles[self.idx]
self._usbmaxi, self._usbmaxo = (EP5IN_MAX_PACKET_SIZE, EP5OUT_MAX_PACKET_SIZE)
self._usbcfg = self._d.configurations[0]
self._usbintf = self._usbcfg.interfaces[0][0]
self._usbeps = self._usbintf.endpoints
for ep in self._usbeps:
if ep.address & 0x80:
self._usbmaxi = ep.maxPacketSize
else:
self._usbmaxo = ep.maxPacketSize
self._threadGo.set()
self.getRadioConfig()
chip = self.getPartNum()
chipstr = CHIPS.get(chip)
self.chipnum = chip
self.chipstr = chipstr
if chip == None:
print "Older firmware, consider upgrading."
else:
self.chipstr = "unrecognized dongle: %s" % chip
if self._init_on_reconnect:
if self._radio_configured:
self._clear_buffers()
self.setRadioConfig()
else:
self.setRFparameters()
self._radio_configured = True
def resetup(self, console=True, copyDongle=None):
self._do=None
if self._bootloader:
return
#self._threadGo = True
if self._debug: print >>sys.stderr,("waiting (resetup) %x" % self.idx)
while (self._do==None):
try:
self.setup(console, copyDongle)
if copyDongle is None:
self._clear_buffers(False)
self.ping(3, wait=10, silent=True)
self.setRfMode(self._rfmode)
except Exception, e:
#if console: sys.stderr.write('.')
if not self._quiet:
print >>sys.stderr,("Error in resetup():" + repr(e))
#if console or self._debug: print >>sys.stderr,("Error in resetup():" + repr(e))
time.sleep(1)
######## BASE FOUNDATIONAL "HIDDEN" CALLS ########
def _sendEP0(self, request=0, buf=None, value=0x200, index=0, timeout=DEFAULT_USB_TIMEOUT):
if buf == None:
buf = 'HELLO THERE'
#return self._do.controlMsg(USB_BM_REQTYPE_TGT_EP|USB_BM_REQTYPE_TYPE_VENDOR|USB_BM_REQTYPE_DIR_OUT, request, "\x00\x00\x00\x00\x00\x00\x00\x00"+buf, value, index, timeout), buf
return self._do.controlMsg(USB_BM_REQTYPE_TGT_EP|USB_BM_REQTYPE_TYPE_VENDOR|USB_BM_REQTYPE_DIR_OUT, request, buf, value, index, timeout), buf
def _recvEP0(self, request=0, length=64, value=0, index=0, timeout=100):
retary = ["%c"%x for x in self._do.controlMsg(USB_BM_REQTYPE_TGT_EP|USB_BM_REQTYPE_TYPE_VENDOR|USB_BM_REQTYPE_DIR_IN, request, length, value, index, timeout)]
if len(retary):
return ''.join(retary)
return ""
def _sendEP5(self, buf=None, timeout=DEFAULT_USB_TIMEOUT):
global direct
if (buf==None):
buf = "\xff\x82\x07\x00ABCDEFG"
if direct:
self._do.bulkWrite(5, buf, timeout)
return
while (len(buf)>0):
drain = buf[:self._usbmaxo]
buf = buf[self._usbmaxo:]
if self._debug: print >>sys.stderr,"XMIT:"+repr(drain)
try:
self._do.bulkWrite(5, drain, timeout)
except Exception, e:
if self._debug: print >>sys.stderr,"requeuing on error '%s' (%s)" % (repr(drain), e)
self.xsema.acquire()
msg = self.xmit_queue.insert(0, drain)
self.xmit_event.set()
self.xsema.release()
if self._debug: print >>sys.stderr, repr(self.xmit_queue)
'''
drain = buf[:self._usbmaxo]
buf = buf[self._usbmaxo:]
if len(buf):
if self._debug: print >>sys.stderr,"requeuing '%s'" % repr(buf)
self.xsema.acquire()
msg = self.xmit_queue.insert(0, buf)
self.xsema.release()
if self._debug: print >>sys.stderr, repr(self.xmit_queue)
if self._debug: print >>sys.stderr,"XMIT:"+repr(drain)
try:
self._do.bulkWrite(5, drain, timeout)
except Exception, e:
if self._debug: print >>sys.stderr,"requeuing on error '%s' (%s)" % (repr(drain), e)
self.xsema.acquire()
msg = self.xmit_queue.insert(0, drain)
self.xsema.release()
if self._debug: print >>sys.stderr, repr(self.xmit_queue)
---
while (len(buf)>0):
drain = buf[:self._usbmaxo]
buf = buf[self._usbmaxo:]
if self._debug: print >>sys.stderr,"XMIT:"+repr(drain)
self._do.bulkWrite(5, drain, timeout)
time.sleep(1)
---
if (len(buf) > self._usbmaxo):
drain = buf[:self._usbmaxo]
buf = buf[self._usbmaxo:]
self.xsema.acquire()
msg = self.xmit_queue.insert(0, buf)
self.xsema.release()
else:
drain = buf[:]
if self._debug: print >>sys.stderr,"XMIT:"+repr(drain)
self._do.bulkWrite(5, drain, timeout)
---
while (len(buf)>0):
if (len(buf) > self._usbmaxo):
drain = buf[:self._usbmaxo]
buf = buf[self._usbmaxo:]
else:
drain = buf[:]
if self._debug: print >>sys.stderr,"XMIT:"+repr(drain)
self._do.bulkWrite(5, drain, timeout)
time.sleep(1)
'''
def _recvEP5(self, timeout=100):
retary = ["%c"%x for x in self._do.bulkRead(0x85, 500, timeout)]
if self._debug: print >>sys.stderr,"RECV:"+repr(retary)
if len(retary):
return ''.join(retary)
return ''
def _clear_buffers(self, clear_recv_mbox=False):
threadGoSet = self._threadGo.isSet()
self._threadGo.clear()
if self._debug:
print >>sys.stderr,("_clear_buffers()")
if clear_recv_mbox:
for key in self.recv_mbox.keys():
self.trash.extend(self.recvAll(key))
elif self.recv_mbox.get(APP_SYSTEM) != None:
self.trash.extend(self.recvAll(APP_SYSTEM))
self.trash.append((time.time(),self.recv_queue))
self.recv_queue = ''
# self.xmit_queue = [] # do we want to keep this?
if threadGoSet: self._threadGo.set()
######## TRANSMIT/RECEIVE THREADING ########
def runEP5_send(self):
msg = ''
self.send_threadcounter = 0
while True:
self._threadGo.wait()
self.send_threadcounter = (self.send_threadcounter + 1) & 0xffffffff
#### transmit stuff. if any exists in the xmit_queue
self.xmit_event.wait() # event driven xmit
msgsent = False
try:
if len(self.xmit_queue):
self.xsema.acquire()
msg = self.xmit_queue.pop(0)
if not len(self.xmit_queue): # if there was only one message
self.xmit_event.clear() # clear the queue, within the lock
self.xsema.release()
self._sendEP5(msg)
msgsent = True
else:
if self._debug>3: sys.stderr.write("NoMsgToSend ")
except:
sys.excepthook(*sys.exc_info())
def runEP5_recv(self):
msg = ''
self.recv_threadcounter = 0
while True:
self._threadGo.wait()
if self._debug>3: sys.stderr.write(".")
self.recv_threadcounter = (self.recv_threadcounter + 1) & 0xffffffff
msgrecv = False
#### handle debug application
try:
q = None
b = self.recv_mbox.get(APP_DEBUG, None)
if (b != None):
for cmd in b.keys():
q = b[cmd]
if len(q):
buf,timestamp = q.pop(0)
if self._debug > 1: print >>sys.stderr,("recvthread: buf length: %x\t\t cmd: %x\t\t(%s)"%(len(buf), cmd, repr(buf)))
if (cmd == DEBUG_CMD_STRING):
if (len(buf) < 4):
if (len(q)):
buf2 = q.pop(0)
buf += buf2
q.insert(0,buf)
if self._debug: sys.stderr.write('*')
else:
length, = struct.unpack("<H", buf[2:4])
if self._debug >1: print >>sys.stderr,("len=%d"%length)
if (len(buf) < 4+length):
if (len(q)):
buf2 = q.pop(0)
buf += buf2
q.insert(0,buf)
if self._debug: sys.stderr.write('&')
else:
printbuf = buf[4:4+length]
requeuebuf = buf[4+length:]
if len(requeuebuf):
if self._debug>1: print >>sys.stderr,(" - DEBUG..requeuing %s"%repr(requeuebuf))
q.insert(0,requeuebuf)
print >>sys.stderr,("DEBUG: (%.3f) %s" % (timestamp, repr(printbuf)))
elif (cmd == DEBUG_CMD_HEX):
#print >>sys.stderr, repr(buf)
print >>sys.stderr, "DEBUG: (%.3f) %x"%(timestamp, struct.unpack("B", buf[4:5])[0])
elif (cmd == DEBUG_CMD_HEX16):
#print >>sys.stderr, repr(buf)
print >>sys.stderr, "DEBUG: (%.3f) %x"%(timestamp, struct.unpack("<H", buf[4:6])[0])
elif (cmd == DEBUG_CMD_HEX32):
#print >>sys.stderr, repr(buf)
print >>sys.stderr, "DEBUG: (%.3f) %x"%(timestamp, struct.unpack("<L", buf[4:8])[0])
elif (cmd == DEBUG_CMD_INT):
print >>sys.stderr, "DEBUG: (%.3f) %d"%(timestamp, struct.unpack("<L", buf[4:8])[0])
else:
print >>sys.stderr,('DEBUG COMMAND UNKNOWN: %x (buf=%s)'%(cmd,repr(buf)))
except:
sys.excepthook(*sys.exc_info())
#### receive stuff.
if self._debug>2: print >> sys.stderr, "recvthread: Doing receiving...",self.ep5timeout
try:
#### first we populate the queue
msg = self._recvEP5(timeout=self.ep5timeout)
if len(msg) > 0:
self.recv_queue += msg
msgrecv = True
except usb.USBError, e:
#sys.stderr.write(repr(self.recv_queue))
#sys.stderr.write(repr(e))
errstr = repr(e)
if self._debug>4: print >>sys.stderr,repr(sys.exc_info())
if ('No error' in errstr):
pass
elif ('Connection timed out' in errstr):
pass
elif ('Operation timed out' in errstr):
pass
else:
if ('could not release intf' in errstr):
if self._debug: print "skipping"
pass
elif ('No such device' in errstr):
self._threadGo.clear()
#self.resetup(False) ## THIS IS A PROBLEM.
self.reset_event.set()
print "===== RESETUP set from recv thread"
elif ('Input/output error' in errstr): # USBerror 5
self._threadGo.clear()
#self.resetup(False) ## THIS IS A PROBLEM.
self.reset_event.set()
print "===== RESETUP set from recv thread"
else:
if self._debug: print "Error in runEP5() (receiving): %s" % errstr
if self._debug>2: sys.excepthook(*sys.exc_info())
self._usberrorcnt += 1
pass
except AttributeError,e:
if "'NoneType' object has no attribute 'bInterfaceNumber'" in str(e):
print "Error: dongle went away. USB bus problems?"
self._threadGo.clear()
#self.resetup(False)
self.reset_event.set()
except:
sys.excepthook(*sys.exc_info())
if self._debug>2: print >> sys.stderr, "recvthread: Sorting mail..."
#### parse, sort, and deliver the mail.
try:
# FIXME: is this robust? or just overcomplex?
if len(self.recv_queue):
idx = self.recv_queue.find('@')
if (idx==-1):
if self._debug > 3:
sys.stderr.write('@')
else:
if (idx>0):
if self._debug: print >>sys.stderr,("runEP5(): idx>0?")
self.trash.append(self.recv_queue[:idx])
self.recv_queue = self.recv_queue[idx:]
# recv_queue is vulnerable here, but it's ok because we only modify it earlier in this same thread
# DON'T CHANGE recv_queue from other threads!
msg = self.recv_queue
msglen = len(msg)
#if self._debug > 2: print >> sys.stderr, "Sorting msg", len(msg), msg.encode("hex")
while (msglen>=5): # if not enough to parse length... we'll wait.
if not self._recv_time: # should be 0 to start and when done with a packet
self._recv_time = time.time()
app = ord(msg[1])
cmd = ord(msg[2])
length, = struct.unpack("<H", msg[3:5])
if self._debug>1: print>>sys.stderr,("recvthread: app=%x cmd=%x len=%x"%(app,cmd,length))
if (msglen >= length+5):
#### if the queue has enough characters to handle the next message... chop it and put it in the appropriate recv_mbox
msg = self.recv_queue[1:length+5] # drop the initial '@' and chop out the right number of chars
self.recv_queue = self.recv_queue[length+5:] # chop it out of the queue
b = self.recv_mbox.get(app,None)
if self.rsema.acquire(): # THREAD SAFETY DANCE
try:
if (b == None):
b = {}
self.recv_mbox[app] = b
except:
sys.excepthook(*sys.exc_info())
finally:
self.rsema.release() # THREAD SAFETY DANCE COMPLETE
q = b.get(cmd)
if self.rsema.acquire(): # THREAD SAFETY DANCE
try:
if (q is None):
q = []
b[cmd] = q
q.append((msg, self._recv_time))
# notify receivers that a new msg is available
self.recv_event.set()
self._recv_time = 0 # we've delivered the current message
except:
sys.excepthook(*sys.exc_info())
finally:
self.rsema.release() # THREAD SAFETY DANCE COMPLETE
else:
if self._debug>1: sys.stderr.write('=')
msg = self.recv_queue
msglen = len(msg)
# end of while loop
except:
sys.excepthook(*sys.exc_info())
if self._debug>2: print >> sys.stderr, "readthread: Loop finished"
if not (msgrecv or len(msg)) :
#time.sleep(.1)
self.ep5timeout = EP_TIMEOUT_IDLE
else:
self.ep5timeout = EP_TIMEOUT_ACTIVE
if self._debug > 5: sys.stderr.write(" %s:%d .-P."%(msgrecv,len(msg)))
######## APPLICATION API ########
def recv(self, app, cmd=None, wait=USB_RX_WAIT):
'''
high-level USB EP5 receive.
checks the mbox for app "app" and command "cmd" and returns the next one in the queue
if any of this does not exist yet, wait for a RECV event until "wait" times out.
RECV events are generated by the low-level recv thread "runEP5_recv()"
'''
startTime = time.time()
self.recv_event.clear() # an event is only interesting if we've already failed to find our message
while (time.time() - startTime)*1000 < wait:
try:
b = self.recv_mbox.get(app)
if b:
if self._debug: print>>sys.stderr, "Recv msg",app,b,cmd
if cmd is None:
keys = b.keys()
if len(keys):
cmd = b.keys()[-1] # just grab one. no guarantees on the order
if b is not None and cmd is not None:
q = b.get(cmd)
if self._debug: print >>sys.stderr,"debug(recv) q='%s'"%repr(q)
if q is not None and self.rsema.acquire(False):
if self._debug>3: print ("rsema.UNlocked", "rsema.locked")[self.rsema.locked()],2
try:
resp, rt = q.pop(0)
self.rsema.release()
if self._debug>3: print ("rsema.UNlocked", "rsema.locked")[self.rsema.locked()],2
# bring it on home... this is the way out.
return resp[4:], rt
except IndexError:
pass
except AttributeError:
sys.excepthook(*sys.exc_info())
pass
self.rsema.release()
self.recv_event.wait((wait - (time.time() - startTime)*1000)/1000) # wait on recv event, with timeout of remaining time
self.recv_event.clear() # clear event, if it's set
except KeyboardInterrupt:
sys.excepthook(*sys.exc_info())
break
except:
sys.excepthook(*sys.exc_info())
time.sleep(0.001)
raise(ChipconUsbTimeoutException())
def recvAll(self, app, cmd=None):
retval = self.recv_mbox.get(app,None)
if retval is not None:
if cmd is not None:
b = retval
if self.rsema.acquire():
#if self._debug: print ("rsema.UNlocked", "rsema.locked")[self.rsema.locked()],3
try:
retval = b.get(cmd)
b[cmd]=[]
if len(retval):
retval = [ (d[4:],t) for d,t in retval ]
except:
sys.excepthook(*sys.exc_info())
finally:
self.rsema.release()
#if self._debug: print ("rsema.UNlocked", "rsema.locked")[self.rsema.locked()],3
else:
if self.rsema.acquire():
#if self._debug: print ("rsema.UNlocked", "rsema.locked")[self.rsema.locked()],4
try:
self.recv_mbox[app]={}
finally:
self.rsema.release()
#if self._debug: print ("rsema.UNlocked", "rsema.locked")[self.rsema.locked()],4
return retval
def send(self, app, cmd, buf, wait=USB_TX_WAIT):
msg = "%c%c%s%s"%(app,cmd, struct.pack("<H",len(buf)),buf)
self.xsema.acquire()
self.xmit_queue.append(msg)
self.xmit_event.set()
self.xsema.release()
if self._debug: print "Sent Msg",msg.encode("hex")
return self.recv(app, cmd, wait)
def getDebugCodes(self, timeout=100):
x = self._recvEP0(timeout=timeout)
if (x != None and len(x)==2):
return struct.unpack("BB", x)
else:
return x
def ep0GetAddr(self):
addr = self._recvEP0(request=EP0_CMD_GET_ADDRESS)
return addr
def ep0Reset(self):
x = self._recvEP0(request=0xfe, value=0x5352, index=0x4e54)
return x
def ep0Peek(self, addr, length, timeout=100):
x = self._recvEP0(request=EP0_CMD_PEEKX, value=addr, length=length, timeout=timeout)
return x#x[3:]
def ep0Poke(self, addr, buf='\x00', timeout=100):
x = self._sendEP0(request=EP0_CMD_POKEX, buf=buf, value=addr, timeout=timeout)
return x
def ep0Ping(self, count=10):
good=0
bad=0
for x in range(count):
#r = self._recvEP0(3, 10)
try:
r = self._recvEP0(request=2, value=count, length=count, timeout=DEFAULT_USB_TIMEOUT)
print "PING: %d bytes received: %s"%(len(r), repr(r))
except ChipconUsbTimeoutException, e:
r = None
print "Ping Failed.",e
if r==None:
bad+=1
else:
good+=1
return (good,bad)
def debug(self, delay=1):
while True:
"""
try:
print >>sys.stderr, ("DONGLE RESPONDING: mode :%x, last error# %d"%(self.getDebugCodes()))
except:
pass
print >>sys.stderr,('recv_queue:\t\t (%d bytes) "%s"'%(len(self.recv_queue),repr(self.recv_queue)[:len(self.recv_queue)%39+20]))
print >>sys.stderr,('trash: \t\t (%d bytes) "%s"'%(len(self.trash),repr(self.trash)[:len(self.trash)%39+20]))
print >>sys.stderr,('recv_mbox \t\t (%d keys) "%s"'%(len(self.recv_mbox),repr(self.recv_mbox)[:len(repr(self.recv_mbox))%79]))
for x in self.recv_mbox.keys():
print >>sys.stderr,(' recv_mbox %d\t (%d records) "%s"'%(x,len(self.recv_mbox[x]),repr(self.recv_mbox[x])[:len(repr(self.recv_mbox[x]))%79]))
"""
print self.reprRadioState()
print self.reprClientState()
x,y,z = select.select([sys.stdin],[],[], delay)
if sys.stdin in x:
sys.stdin.read(1)
break
def getPartNum(self):
try:
r = self.send(APP_SYSTEM, SYS_CMD_PARTNUM, "", 10000)
r,rt = r
except ChipconUsbTimeoutException, e:
r = None
print "SETUP Failed.",e
return ord(r)
def ping(self, count=10, buf="ABCDEFGHIJKLMNOPQRSTUVWXYZ", wait=DEFAULT_USB_TIMEOUT, silent=False):
good=0
bad=0
start = time.time()
for x in range(count):
istart = time.time()
try:
r = self.send(APP_SYSTEM, SYS_CMD_PING, buf, wait)
r,rt = r
istop = time.time()
if not silent:
print "PING: %d bytes transmitted, received: %s (%f seconds)"%(len(buf), repr(r), istop-istart)
except ChipconUsbTimeoutException, e:
r = None
if not silent:
print "Ping Failed.",e
if r==None:
bad+=1
else:
good+=1
stop = time.time()
return (good,bad,stop-start)
def bootloader(self):
'''
switch to bootloader mode. based on Fergus Noble's CC-Bootloader (https://github.com/fnoble/CC-Bootloader)
this allows the firmware to be updated via USB instead of goodfet/ccdebugger
'''
try:
self._bootloader = True
r = self.send(APP_SYSTEM, SYS_CMD_BOOTLOADER, "", wait=1)
except ChipconUsbTimeoutException:
pass
def RESET(self):
try:
r = self.send(APP_SYSTEM, SYS_CMD_RESET, "RESET_NOW\x00")
except ChipconUsbTimeoutException:
pass
def peek(self, addr, bytecount=1):
r, t = self.send(APP_SYSTEM, SYS_CMD_PEEK, struct.pack("<HH", bytecount, addr))
return r
def poke(self, addr, data):
r, t = self.send(APP_SYSTEM, SYS_CMD_POKE, struct.pack("<H", addr) + data)
return r
def pokeReg(self, addr, data):
r, t = self.send(APP_SYSTEM, SYS_CMD_POKE_REG, struct.pack("<H", addr) + data)
return r
def getBuildInfo(self):
r, t = self.send(APP_SYSTEM, SYS_CMD_BUILDTYPE, '')
return r
def getInterruptRegisters(self):
regs = {}
# IEN0,1,2
regs['IEN0'] = self.peek(IEN0,1)
regs['IEN1'] = self.peek(IEN1,1)
regs['IEN2'] = self.peek(IEN2,1)
# TCON
regs['TCON'] = self.peek(TCON,1)
# S0CON
regs['S0CON'] = self.peek(S0CON,1)
# IRCON
regs['IRCON'] = self.peek(IRCON,1)
# IRCON2
regs['IRCON2'] = self.peek(IRCON2,1)
# S1CON
regs['S1CON'] = self.peek(S1CON,1)
# RFIF
regs['RFIF'] = self.peek(RFIF,1)
# DMAIE
regs['DMAIE'] = self.peek(DMAIE,1)
# DMAIF
regs['DMAIF'] = self.peek(DMAIF,1)
# DMAIRQ
regs['DMAIRQ'] = self.peek(DMAIRQ,1)
return regs
def reprHardwareConfig(self):
output= []
hardware= self.getBuildInfo()
output.append("Dongle: %s" % hardware.split(' ')[0])
try:
output.append("Firmware rev: %s" % hardware.split('r')[1])
except:
output.append("Firmware rev: Not found! Update needed!")
# see if we have a bootloader by loooking for it's recognition semaphores
# in SFR I2SCLKF0 & I2SCLKF1
if(self.peek(0xDF46,1) == '\xF0' and self.peek(0xDF47,1) == '\x0D'):
output.append("Bootloader: CC-Bootloader")
else:
output.append("Bootloader: Not installed")
return "\n".join(output)
def reprSoftwareConfig(self):
output= []
output.append("rflib rev: %s" % RFLIB_VERSION)
return "\n".join(output)
def printClientState(self, width=120):
print self.reprClientState(width)
def reprClientState(self, width=120):
output = ["="*width]
output.append(' client thread cycles: %d/%d' % (self.recv_threadcounter,self.send_threadcounter))
output.append(' client errored cycles: %d' % self._usberrorcnt)
output.append(' recv_queue: (%d bytes) %s'%(len(self.recv_queue),repr(self.recv_queue)[:width-42]))
output.append(' trash: (%d blobs) "%s"'%(len(self.trash),repr(self.trash)[:width-44]))
output.append(' recv_mbox (%d keys) "%s"'%(len(self.recv_mbox),repr([hex(x) for x in self.recv_mbox.keys()])[:width-44]))
for app in self.recv_mbox.keys():
appbox = self.recv_mbox[app]
output.append(' app 0x%x (%d records)'%(app,len(appbox)))
for cmd in appbox.keys():
output.append(' [0x%x] (%d frames) "%s"'%(cmd, len(appbox[cmd]), repr(appbox[cmd])[:width-36]))
output.append('')
return "\n".join(output)
def unittest(self, mhz=24):
print "\nTesting USB ping()"
self.ping(3)
print "\nTesting USB ep0Ping()"
self.ep0Ping()
print "\nTesting USB enumeration"
print "getString(0,100): %s" % repr(self._do.getString(0,100))
print "\nTesting USB EP MAX_PACKET_SIZE handling (ep0Peek(0xf000, 100))"
print repr(self.ep0Peek(0xf000, 100))
print "\nTesting USB EP MAX_PACKET_SIZE handling (peek(0xf000, 300))"
print repr(self.peek(0xf000, 400))
print "\nTesting USB poke/peek"
data = "".join([chr(c) for c in xrange(120)])
where = 0xf300
self.poke(where, data)
ndata = self.peek(where, len(data))
if ndata != data:
print " *FAILED*\n '%s'\n '%s'" % (data.encode("hex"), ndata.encode("hex"))
raise(Exception(" *FAILED*\n '%s'\n '%s'" % (data.encode("hex"), ndata.encode("hex"))))
else:
print " passed '%s'" % (ndata.encode("hex"))
if __name__ == "__main__":
idx = 0
if len(sys.argv) > 1:
idx = int(sys.argv.pop())
d = USBDongle(idx=idx, debug=False)

1131
rflib/intelhex.py Normal file

File diff suppressed because it is too large Load Diff

1
rflib/rflib_version.py Normal file
View File

@ -0,0 +1 @@
RFLIB_VERSION=323