From c0b69fdc4ad7125c12674d1fbff94b394e573878 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Thu, 3 Mar 2011 08:34:53 +0800 Subject: fixed some logical errors wrt fantom status handling --- FantomModule/FantomModule.cpp | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/FantomModule/FantomModule.cpp b/FantomModule/FantomModule.cpp index 34767a0..b3380f1 100644 --- a/FantomModule/FantomModule.cpp +++ b/FantomModule/FantomModule.cpp @@ -193,6 +193,7 @@ PyObject *FantomModule::find_bricks(PyObject *py_self, PyObject *py_args) { ViChar nxtName[FANTOM_NXTNAME_LEN]; nFANTOM100::iNXT* aNXT = NULL; + nxtIteratorPtr->getName(nxtName, status); std::cout << "Found: " << nxtName << std::endl; aNXT = nxtIteratorPtr->getNXT(status); @@ -200,14 +201,21 @@ PyObject *FantomModule::find_bricks(PyObject *py_self, PyObject *py_args) { FantomModule *aFantomObject = new FantomModule; aFantomObject->nxtPtr = aNXT; - if (strlcpy(aFantomObject->pairedResourceName, nxtName,FANTOM_NXTNAME_LEN) >= FANTOM_NXTNAME_LEN) + aFantomObject->status.assign(status); + if (strlcpy(aFantomObject->pairedResourceName, nxtName, FANTOM_NXTNAME_LEN) >= FANTOM_NXTNAME_LEN) + { // Exceeded Name Length - exit; - - // FIXME: Append to Python list - /* - return Py_BuildValue("i", sts); - */ + std::cout << "NXTName Length Exceeded: " << nxtName << std::endl; + delete aFantomObject; + } + else + { + // FIXME: Append to Python list + /* + return Py_BuildValue("i", sts); + */ + } + } nxtIteratorPtr->advance(status); @@ -223,7 +231,8 @@ ViBoolean FantomModule::socket(ViBoolean enableBT, ViConstString BTkey) // Internal class object setup nxtPtr = NULL; useBT = enableBT; - strlcpy(passkey, BTkey, FANTOM_PASSKEY_LEN); + if (strlcpy(passkey, BTkey, FANTOM_PASSKEY_LEN) >= FANTOM_PASSKEY_LEN) + return false; return true; } -- cgit v1.2.3 From 3a2966f08eba8bc6a9fe63650b42c4f1a024fdfa Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Tue, 8 Mar 2011 09:14:17 +0800 Subject: python fantom wrapper using ctypes --- PyFantom/pyfantom.py | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 PyFantom/pyfantom.py diff --git a/PyFantom/pyfantom.py b/PyFantom/pyfantom.py new file mode 100644 index 0000000..ba3eedd --- /dev/null +++ b/PyFantom/pyfantom.py @@ -0,0 +1,109 @@ +from ctypes import * +import ctypes.util +import platform + +# Check platform. +if platform.system() == 'Darwin': + import sys + if sys.maxsize > 2**32: + raise RuntimeError("fantom drivers not available in 64 bit mode.\n" + "You can run python in 32 bit mode using:\n" + "arch -i386 python2.6\n") + libpath = '/Library/Frameworks/Fantom.framework/Fantom' + #libpath = ctypes.util.find_library('Fantom') +else: + raise RuntimeError('unsupported platform') + +# Load library. +dll = cdll.LoadLibrary(libpath) +dll.nFANTOM100_createNXTIterator.argtypes = [c_ushort, c_uint, POINTER(c_int)] +dll.nFANTOM100_createNXTIterator.restype = c_uint +dll.nFANTOM100_destroyNXTIterator.argtypes = [c_int, POINTER(c_int)] +dll.nFANTOM100_destroyNXTIterator.restype = None +dll.nFANTOM100_iNXTIterator_advance.argtypes = [c_uint, POINTER(c_int)] +dll.nFANTOM100_iNXTIterator_advance.restype = None +dll.nFANTOM100_iNXTIterator_getNXT.argtypes = [c_uint, POINTER(c_int)] +dll.nFANTOM100_iNXTIterator_getNXT.restype = c_uint +dll.nFANTOM100_iNXTIterator_getName.argtypes = [c_uint, c_char_p, POINTER(c_int)] +dll.nFANTOM100_iNXTIterator_getName.restype = None + +# Status codes. +StatusOffset = -142000 +StatusNoMoreItemsFound = StatusOffset - 17 +StatusSuccess = 0 + +def check_status (status): + """Check status, raise on error.""" + if status.value < StatusSuccess: + raise FantomException('bad status') + +class FantomException(RuntimeError): + pass + +class NXTIterator: + """Interface to an iterator, to find connected NXT.""" + + def __init__(self, search_bluetooth, + bluetooth_search_timeout_in_seconds = 5): + """Initialize iterator.""" + self.search_bluetooth = search_bluetooth + self.bluetooth_search_timeout_in_seconds = \ + bluetooth_search_timeout_in_seconds + self.handle = None + self.stop = False + + def __iter__(self): + """Return the iterator object itself.""" + return self + + def next(self): + """Implement the iterator protocol.""" + if self.stop: + raise StopIteration() + # Find first, or find next. + status = c_int(0) + if self.handle is None: + handle = dll.nFANTOM100_createNXTIterator(self.search_bluetooth, + self.bluetooth_search_timeout_in_seconds, byref(status)) + else: + handle = self.handle + dll.nFANTOM100_iNXTIterator_advance(handle, byref(status)) + # Check result. + if status.value == StatusNoMoreItemsFound: + self.stop = True + raise StopIteration() + check_status (status) + self.handle = handle + # Return itself (not part of the protocol, but it has get_nxt and + # get_name). + return self + + def get_nxt(self): + """Get the NXT instance.""" + if self.handle is None or self.stop: + raise FantomException('invalid iterator') + status = c_int(0) + nxt = dll.nFANTOM100_iNXTIterator_getNXT(self.handle, byref(status)) + check_status (status) + # XXX + return nxt.value + + def get_name(self): + """Get the NXT resource name.""" + if self.handle is None or self.stop: + raise FantomException('invalid iterator') + status = c_int(0) + name = create_string_buffer (256) + dll.nFANTOM100_iNXTIterator_getName(self.handle, name, byref(status)) + check_status (status) + return name.value + + def __del__(self): + """Destroy iterator.""" + if self.handle is not None: + status = c_int(0) + dll.nFANTOM100_destroyNXTIterator(self.handle, byref(status)) + +if __name__ == '__main__': + for i in NXTIterator(False): + print i.get_name() -- cgit v1.2.3 From 7955334371d0992439c5b9c1cc73fc221fe9c9ff Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Tue, 8 Mar 2011 09:15:09 +0800 Subject: added authors file --- PyFantom/AUTHORS | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 PyFantom/AUTHORS diff --git a/PyFantom/AUTHORS b/PyFantom/AUTHORS new file mode 100644 index 0000000..5c680ea --- /dev/null +++ b/PyFantom/AUTHORS @@ -0,0 +1,5 @@ +The following people have contributed code, in various quantities, to armdebug. +A big thanks to all of them, armdebug is what it is in part thanks to each of +them. In alphabetical order: + +Nicolas Schodet -- cgit v1.2.3 From 257fba8e02efa921eea848fe554be553286629af Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Mon, 14 Mar 2011 08:56:40 +0800 Subject: updated --- PyFantom/pyfantom.py | 312 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 281 insertions(+), 31 deletions(-) diff --git a/PyFantom/pyfantom.py b/PyFantom/pyfantom.py index ba3eedd..46367b1 100644 --- a/PyFantom/pyfantom.py +++ b/PyFantom/pyfantom.py @@ -1,21 +1,23 @@ -from ctypes import * +"""NXT Fantom driver wrapper.""" +from ctypes import c_int, c_uint, c_ushort, c_ubyte, c_char_p, byref, POINTER import ctypes.util import platform +import collections # Check platform. if platform.system() == 'Darwin': import sys if sys.maxsize > 2**32: - raise RuntimeError("fantom drivers not available in 64 bit mode.\n" - "You can run python in 32 bit mode using:\n" - "arch -i386 python2.6\n") + raise RuntimeError("fantom drivers not available in 64 bit mode.\n" + "You can run python in 32 bit mode using:\n" + "arch -i386 python2.6\n") libpath = '/Library/Frameworks/Fantom.framework/Fantom' #libpath = ctypes.util.find_library('Fantom') else: raise RuntimeError('unsupported platform') # Load library. -dll = cdll.LoadLibrary(libpath) +dll = ctypes.cdll.LoadLibrary(libpath) dll.nFANTOM100_createNXTIterator.argtypes = [c_ushort, c_uint, POINTER(c_int)] dll.nFANTOM100_createNXTIterator.restype = c_uint dll.nFANTOM100_destroyNXTIterator.argtypes = [c_int, POINTER(c_int)] @@ -24,31 +26,152 @@ dll.nFANTOM100_iNXTIterator_advance.argtypes = [c_uint, POINTER(c_int)] dll.nFANTOM100_iNXTIterator_advance.restype = None dll.nFANTOM100_iNXTIterator_getNXT.argtypes = [c_uint, POINTER(c_int)] dll.nFANTOM100_iNXTIterator_getNXT.restype = c_uint -dll.nFANTOM100_iNXTIterator_getName.argtypes = [c_uint, c_char_p, POINTER(c_int)] +dll.nFANTOM100_iNXTIterator_getName.argtypes = [c_uint, c_char_p, + POINTER(c_int)] dll.nFANTOM100_iNXTIterator_getName.restype = None - -# Status codes. -StatusOffset = -142000 -StatusNoMoreItemsFound = StatusOffset - 17 -StatusSuccess = 0 - -def check_status (status): - """Check status, raise on error.""" - if status.value < StatusSuccess: - raise FantomException('bad status') +dll.nFANTOM100_createNXT.argtypes = [c_char_p, POINTER(c_int), c_ushort] +dll.nFANTOM100_createNXT.restype = c_uint +dll.nFANTOM100_destroyNXT.argtypes = [c_uint, POINTER(c_int)] +dll.nFANTOM100_destroyNXT.restype = None +dll.nFANTOM100_iNXT_getFirmwareVersion.argtypes = [c_uint, POINTER(c_ubyte), + POINTER(c_ubyte), POINTER(c_ubyte), POINTER(c_ubyte), POINTER(c_int)] +dll.nFANTOM100_iNXT_getFirmwareVersion.argtypes = None +dll.nFANTOM100_iNXT_getDeviceInfo.argtypes = [c_uint, c_char_p, + POINTER(c_ubyte), POINTER(c_ubyte), POINTER(c_uint), POINTER(c_int)] +dll.nFANTOM100_iNXT_write.argtypes = [c_uint, c_char_p, c_uint, + POINTER(c_int)] +dll.nFANTOM100_iNXT_write.restype = c_uint +dll.nFANTOM100_iNXT_read.argtypes = [c_uint, c_char_p, c_uint, + POINTER(c_int)] +dll.nFANTOM100_iNXT_read.restype = c_uint +dll.nFANTOM100_iNXT_getDeviceInfo.restype = None +dll.nFANTOM100_iNXT_getResourceString.argtypes = [c_uint, c_char_p, + POINTER(c_int)] +dll.nFANTOM100_iNXT_getResourceString.restype = None class FantomException(RuntimeError): + """Exception thrown on Fantom library error.""" pass +class Status: + """Status codes used by Fantom library.""" + + # Status codes. {{{ + Success = 0 + Offset = -142000 + PairingFailed = Offset - 5 + BluetoothSearchFailed = Offset - 6 + SystemLibraryNotFound = Offset - 7 + UnpairingFailed = Offset - 8 + InvalidFilename = Offset - 9 + InvalidIteratorDereference = Offset - 10 + LockOperationFailed = Offset - 11 + SizeUnknown = Offset - 12 + DuplicateOpen = Offset - 13 + EmptyFile = Offset - 14 + FirmwareDownloadFailed = Offset - 15 + PortNotFound = Offset - 16 + NoMoreItemsFound = Offset - 17 + TooManyUnconfiguredDevices = Offset - 18 + CommandMismatch = Offset - 19 + IllegalOperation = Offset - 20 + BluetoothCacheUpdateFailed = Offset - 21 + NonNXTDeviceSelected = Offset - 22 + RetryConnection = Offset - 23 + PowerCycleNXT = Offset - 24 + FeatureNotImplemented = Offset - 99 + FWIllegalHandle = Offset - 189 + FWIllegalFileName = Offset - 190 + FWOutOfBounds = Offset - 191 + FWModuleNotFound = Offset - 192 + FWFileExists = Offset - 193 + FWFileIsFull = Offset - 194 + FWAppendNotPossible = Offset - 195 + FWNoWriteBuffers = Offset - 196 + FWFileIsBusy = Offset - 197 + FWUndefinedError = Offset - 198 + FWNoLinearSpace = Offset - 199 + FWHandleAlreadyClosed = Offset - 200 + FWFileNotFound = Offset - 201 + FWNotLinearFile = Offset - 202 + FWEndOfFile = Offset - 203 + FWEndOfFileExpected = Offset - 204 + FWNoMoreFiles = Offset - 205 + FWNoSpace = Offset - 206 + FWNoMoreHandles = Offset - 207 + FWUnknownErrorCode = Offset - 208 + # }}} + + # Text description. {{{ + description = { + Success: "No error", + PairingFailed: "Bluetooth pairing operation failed.", + BluetoothSearchFailed: "Bluetooth search failed.", + SystemLibraryNotFound: "System library not found.", + UnpairingFailed: "Bluetooth unpairing operation failed.", + InvalidFilename: "Invalid filename specified.", + InvalidIteratorDereference: "Invalid iterator dereference.", + LockOperationFailed: "Resource locking operation failed.", + SizeUnknown: "Could not determine the requested size.", + DuplicateOpen: "Cannot open two objects at once.", + EmptyFile: "File is empty.", + FirmwareDownloadFailed: "Firmware download failed.", + PortNotFound: "Could not locate virtual serial port.", + NoMoreItemsFound: "No more items found.", + TooManyUnconfiguredDevices: "Too many unconfigured devices.", + CommandMismatch: "Command mismatch in firmware response.", + IllegalOperation: "Illegal operation.", + BluetoothCacheUpdateFailed: "Could not update local Bluetooth" + " cache with new name.", + NonNXTDeviceSelected: "Selected device is not an NXT.", + RetryConnection: "Communication error. Retry the operation.", + PowerCycleNXT: "Could not connect to NXT. Turn the NXT off and" + " then back on before continuing.", + FeatureNotImplemented: "This feature is not yet implemented.", + FWIllegalHandle: "Firmware reported an illegal handle.", + FWIllegalFileName: "Firmware reported an illegal file name.", + FWOutOfBounds: "Firmware reported an out of bounds reference.", + FWModuleNotFound: "Firmware could not find module.", + FWFileExists: "Firmware reported that the file already exists.", + FWFileIsFull: "Firmware reported that the file is full.", + FWAppendNotPossible: "Firmware reported the append operation is" + " not possible.", + FWNoWriteBuffers: "Firmware has no write buffers available.", + FWFileIsBusy: "Firmware reported that file is busy.", + FWUndefinedError: "Firmware reported the undefined error.", + FWNoLinearSpace: "Firmware reported that no linear space is" + " available.", + FWHandleAlreadyClosed: "Firmware reported that handle has already" + " been closed.", + FWFileNotFound: "Firmware could not find file.", + FWNotLinearFile: "Firmware reported that the requested file is" + " not linear.", + FWEndOfFile: "Firmware reached the end of the file.", + FWEndOfFileExpected: "Firmware expected an end of file.", + FWNoMoreFiles: "Firmware cannot handle more files.", + FWNoSpace: "Firmware reported the NXT is out of space.", + FWNoMoreHandles: "Firmware could not create a handle.", + FWUnknownErrorCode: "Firmware reported an unknown error code.", + } + # }}} + + @staticmethod + def check(status): + """Check status, raise on error.""" + if status.value < Status.Success: + if status.value in Status.description: + description = Status.description[status.value] + else: + description = 'error %d' % status.value + raise FantomException(description) + class NXTIterator: """Interface to an iterator, to find connected NXT.""" - def __init__(self, search_bluetooth, - bluetooth_search_timeout_in_seconds = 5): + def __init__(self, search_bluetooth, bluetooth_search_timeout_s=5): """Initialize iterator.""" self.search_bluetooth = search_bluetooth - self.bluetooth_search_timeout_in_seconds = \ - bluetooth_search_timeout_in_seconds + self.bluetooth_search_timeout_s = bluetooth_search_timeout_s self.handle = None self.stop = False @@ -61,18 +184,18 @@ class NXTIterator: if self.stop: raise StopIteration() # Find first, or find next. - status = c_int(0) + status = c_int(0) if self.handle is None: handle = dll.nFANTOM100_createNXTIterator(self.search_bluetooth, - self.bluetooth_search_timeout_in_seconds, byref(status)) + self.bluetooth_search_timeout_s, byref(status)) else: handle = self.handle dll.nFANTOM100_iNXTIterator_advance(handle, byref(status)) # Check result. - if status.value == StatusNoMoreItemsFound: + if status.value == Status.NoMoreItemsFound: self.stop = True raise StopIteration() - check_status (status) + Status.check(status) self.handle = handle # Return itself (not part of the protocol, but it has get_nxt and # get_name). @@ -83,27 +206,154 @@ class NXTIterator: if self.handle is None or self.stop: raise FantomException('invalid iterator') status = c_int(0) - nxt = dll.nFANTOM100_iNXTIterator_getNXT(self.handle, byref(status)) - check_status (status) - # XXX - return nxt.value + handle = dll.nFANTOM100_iNXTIterator_getNXT(self.handle, byref(status)) + Status.check(status) + return NXT(handle) def get_name(self): """Get the NXT resource name.""" if self.handle is None or self.stop: raise FantomException('invalid iterator') status = c_int(0) - name = create_string_buffer (256) + name = ctypes.create_string_buffer(256) dll.nFANTOM100_iNXTIterator_getName(self.handle, name, byref(status)) - check_status (status) + Status.check(status) return name.value + get_resource_string = get_name + def __del__(self): """Destroy iterator.""" if self.handle is not None: status = c_int(0) dll.nFANTOM100_destroyNXTIterator(self.handle, byref(status)) +class NXT: + """Interface to the NXT brick.""" + + DeviceInfo = collections.namedtuple('DeviceInfo', + 'name bluetooth_address signal_strength available_flash') + + def __init__(self, name_or_handle): + """Initialize interface.""" + if isinstance(name_or_handle, basestring): + status = c_int(0) + handle = dll.nFANTOM100_createNXT(name_or_handle, byref(status), + True) + Status.check(status) + self.handle = handle + else: + self.handle = name_or_handle + + def get_firmware_version(self): + """Get protocol and firmware versions installed on this NXT.""" + status = c_int(0) + protocol_major = c_ubyte(0) + protocol_minor = c_ubyte(0) + firmware_major = c_ubyte(0) + firmware_minor = c_ubyte(0) + dll.nFANTOM100_iNXT_getFirmwareVersion(self.handle, + byref(protocol_major), byref(protocol_minor), + byref(firmware_major), byref(firmware_minor), + byref(status)) + Status.check(status) + return (protocol_major.value, protocol_minor.value, + firmware_major.value, firmware_minor.value) + + def write(self, data): + """Write, in a generic fashion, to this NXT.""" + status = c_int(0) + data_buffer = ctypes.create_string_buffer(data) + ret = dll.nFANTOM100_iNXT_write(self.handle, data_buffer, len(data), + byref(status)) + Status.check(status) + return ret + + def read(self, length): + """Read, in a generic fashion, from this NXT.""" + status = c_int(0) + data_buffer = ctypes.create_string_buffer(length) + ret = dll.nFANTOM100_iNXT_write(self.handle, data_buffer, length, + byref(status)) + Status.check(status) + assert ret <= length + return data_buffer.raw[0:ret] + + def get_device_info(self): + """Get basic information about this NXT.""" + status = c_int(0) + name = ctypes.create_string_buffer(16) + bluetooth_address = (c_ubyte * 7)() + signal_strength = (c_ubyte * 4)() + available_flash = c_uint(0) + dll.nFANTOM100_iNXT_getDeviceInfo(self.handle, name, + bluetooth_address, signal_strength, byref(available_flash), + byref(status)) + return self.DeviceInfo( + name = name.value, + bluetooth_address = ':'.join('%02x' % c + for c in bluetooth_address[0:5]), + signal_strength = tuple(c for c in signal_strength), + available_flash = available_flash.value, + ) + + def get_resource_string(self): + """Get the NXT resource name.""" + status = c_int(0) + name = ctypes.create_string_buffer(256) + dll.nFANTOM100_iNXT_getResourceString(self.handle, name, + byref(status)) + Status.check(status) + return name.value + + def __del__(self): + """Destroy interface.""" + if self.handle is not None: + status = c_int(0) + dll.nFANTOM100_destroyNXT(self.handle, byref(status)) + if __name__ == '__main__': + get_info = False + write_read = True for i in NXTIterator(False): - print i.get_name() + if get_info: + print "name:", i.get_name() + print "resource string:", i.get_resource_string() + print "get_nxt:" + nxt = i.get_nxt() + print " firmware version:", nxt.get_firmware_version() + print " get device info:", nxt.get_device_info() + rs = nxt.get_resource_string() + print " resource string:", rs + del nxt + print "NXT():" + nxt = NXT(rs) + print " resource string:", nxt.get_resource_string() + del nxt + if write_read: + nxt = i.get_nxt() + import struct + # Write VERSION SYS_CMD. + # Query: + # SYS_CMD: 0x01 + # VERSION: 0x88 + cmd = struct.pack('2B', 0x01, 0x88) + r = nxt.write(cmd) + print "wrote", r + # Response: + # REPLY_CMD: 0x02 + # VERSION: 0x88 + # SUCCESS: 0x00 + # PROTOCOL_VERSION minor + # PROTOCOL_VERSION major + # FIRMWARE_VERSION minor + # FIRMWARE_VERSION major + rep = nxt.read(7) + print "read", struct.unpack('%dB' % len(rep), rep) + # Same thing, without response. + cmd = struct.pack('2B', 0x81, 0x88) + r = nxt.write(cmd) + print "wrote", r + rep = nxt.read(7) + print struct.unpack('%dB' % len(rep), rep) + del nxt -- cgit v1.2.3 From d8032b84775430ff132f136371c95a045b401595 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Mon, 14 Mar 2011 17:54:16 +0800 Subject: must preserve lr in routine --- Debugger/debug_runlooptasks.S | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Debugger/debug_runlooptasks.S b/Debugger/debug_runlooptasks.S index 24f8bfe..fd17412 100644 --- a/Debugger/debug_runlooptasks.S +++ b/Debugger/debug_runlooptasks.S @@ -79,8 +79,9 @@ dbg__runloopTasks: .extern cCommCtrl dbg__runloopTasks: + push {lr} /* FIXME: Add necessary cXXXCtrl calls here */ bl cCommCtrl /* OSWatchdogWrite is a NULL function in the NXT Firmware?! */ - bx lr + pop {pc} #endif -- cgit v1.2.3