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 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): """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 == Status.NoMoreItemsFound: self.stop = True raise StopIteration() Status.check (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)) Status.check (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)) Status.check (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()