def get_device_info(self): """ Return information about the device. :return: A list containing board type, major and minor firmware versions, 16 byte unique identifier, \ microcontroller part and bootcode version numbers. """ sfp_code, args = decode_sfp(self.low_level_io(1, encode_sfp(255, []))) if sfp_code != 255: errmsg("IoTPy error: get_device_info wrong code.") # raise IoTPy_APIError("") device_data = args if device_data[0] >> 24 != 0x55: # 0x55 = 'U' print("IoTPy error: getDeviceInfo unknown device/firmware type") # return device_info = { 'fw_maj': (device_data[0] & 0x00ff0000) >> 16, # Firmware major version number 'fw_min': device_data[0] & 0x0000ffff, # Firmware minor version number 'uid': UUID(bytes=device_data[1]), # 128bit unique ID 'cpu_id': device_data[2], # UPER LPC CPU part number 'boot': device_data[3], # UPER LPC CPU bootload code version } return device_info
def transaction(self, address, write_data, read_length): """ Perform I2C data transaction. I2C data transaction consists of (optional) write transaction, followed by (optional) read transaction. :param address: I2C device address. :type address: int :param write_data: A byte sequence to be transmitted. If write_data is empty string, no write transaction \ will be executed. :type write_data: str :param read_length: A number of bytes to be received. If read_length is 0, no read transaction will be executed. :type read_length: int :return: Received data and I2C transaction status/error code. :rtype: (str, int) :raise: IoTPy_APIError, IoTPy_ThingError """ try: result = decode_sfp(self.board.low_level_io(1, encode_sfp(41, [address, write_data, read_length]))) except IoTPy_APIError: errmsg("UPER API: I2C bus not connected.") raise IoTPy_IOError("I2C bus not connected.") return result[1][1], result[1][2] # return read buffer and error
def set_pulse_time(self, pulse_us): """ Set PWM high (on state) time. :param pulse_us: Pulse time in microseconds. :type pulse_us: int :raise: IoTPy_APIError """ if self.primary: self.board.low_level_io(0, encode_sfp( 2, [self.logical_pin])) # set pin secondary function self.primary = False if 0 <= pulse_us <= PWM_PORT_RUNNING[self.pwm_port]['period']: self.pulse_time = pulse_us high_time = pulse_us if self.polarity == 0: high_time = PWM_PORT_RUNNING[ self.pwm_port]['period'] - pulse_us self.board.low_level_io( 0, encode_sfp(PWM._PWM_PORT_FUNCTIONS[self.pwm_port][1], [self.pwm_pin, high_time])) else: errmsg( "UPER error: PWM high time is out of range on logical pin %d." % self.logical_pin) raise IoTPy_APIError("PWM high time is out of range.")
def interrupt_handler(self): with self.irq_available: while self.alive: self.irq_available.wait(0.05) while len(self.irq_requests): interrupt = self.irq_requests.pop(0) try: self.callback(interrupt[1]) except Exception as e: errmsg("IoTPy: Interrupt callback error (%s)" % e) self.alive = False
def __init__(self, board, pin): self.board = board if self.board.pinout[pin].capabilities & CAP_ADC: self.logical_pin = self.board.pinout[pin].pinID else: errmsg("IO API: Pin "+str(pin)+" is not an ADC pin.") raise IoTPy_APIError("Trying to assign ADC function to non ADC pin.") self.adc_pin = self.board.pinout[pin].extra[0] self.board.low_level_io(0, encode_sfp(3, [self.logical_pin, 0])) # set GPIO to HIGH_Z self.board.low_level_io(0, encode_sfp(2, [self.logical_pin])) # set secondary pin function self.primary = False
def __init__(self, board, pin): self.board = board if self.board.pinout[pin].capabilities & CAP_ADC: self.logical_pin = self.board.pinout[pin].pinID else: errmsg("IO API: Pin " + str(pin) + " is not an ADC pin.") raise IoTPy_APIError( "Trying to assign ADC function to non ADC pin.") self.adc_pin = self.board.pinout[pin].extra[0] self.board.low_level_io(0, encode_sfp( 3, [self.logical_pin, 0])) # set GPIO to HIGH_Z self.board.low_level_io(0, encode_sfp( 2, [self.logical_pin])) # set secondary pin function self.primary = False
def __init__(self, board, pin, freq=100, polarity=1): self.board = board if self.board.pinout[pin].capabilities & CAP_PWM: self.logical_pin = self.board.pinout[pin].pinID else: errmsg("UPER API: Pin No:%d is not a PWM pin.", pin) raise IoTPy_APIError("Trying to assign PWM function to non PWM pin.") self.pwm_port = self.board.pinout[pin].extra[0] self.pwm_pin = self.board.pinout[pin].extra[1] self.primary = True self.pulse_time = 0 self.polarity = polarity PWM_PORT_RUNNING[self.pwm_port]["channels"] += 1 if PWM_PORT_RUNNING[self.pwm_port]["channels"] == 1: self.set_frequency(freq)
def internal_call_back(self, interrupt_data): """ :param interrupt_data: :return: """ interrupt_event = {'id': interrupt_data[0], 'type': interrupt_data[1] & 0xFF, 'values': interrupt_data[1] >> 8} callback_entry = self.callbackdict[self.interrupts[interrupt_event['id']]] try: callback_entry['callback'](interrupt_event, callback_entry['userobject']) except Exception as e: errmsg("IoTPy Interrupt callback exception: %s" % e) return
def __init__(self, board, pin, freq=100, polarity=1): self.board = board if self.board.pinout[pin].capabilities & CAP_PWM: self.logical_pin = self.board.pinout[pin].pinID else: errmsg("UPER API: Pin No:%d is not a PWM pin.", pin) raise IoTPy_APIError( "Trying to assign PWM function to non PWM pin.") self.pwm_port = self.board.pinout[pin].extra[0] self.pwm_pin = self.board.pinout[pin].extra[1] self.primary = True self.pulse_time = 0 self.polarity = polarity PWM_PORT_RUNNING[self.pwm_port]['channels'] += 1 if PWM_PORT_RUNNING[self.pwm_port]['channels'] == 1: self.set_frequency(freq)
def scan(self): """ Scan I2C interface for connected devices. :return: A list of active I2C device addresses. :rtype: list """ dev_list = [] for address in range(1, 128): try: result = self.board.low_level_io(1, encode_sfp(41, [address, b'', 0])) if result[-1] == 'X': dev_list.append(address) except IoTPy_APIError: errmsg("UPER API: I2C bus not connected.") raise IoTPy_IOError("I2C bus not connected.") return dev_list
def __init__(self, board, pin): self.board = board if self.board.pinout[pin].capabilities & CAP_GPIO: self.logical_pin = self.board.pinout[pin].pinID else: errmsg("UPER API: Pin No:%d is not GPIO pin.", pin) raise IoTPy_APIError( "Trying to assign GPIO function to non GPIO pin.") # Configure default state to be input with pull-up resistor self.board.low_level_io(0, encode_sfp(1, [self.logical_pin])) # set primary self.direction = self.INPUT self.resistor = self.PULL_UP self.setup( self.direction, self.resistor) # default GPIO pin state is INPUT and PULL_UP
def set_period(self, period_us): """ Set PWM period. :param period_us: PWM signal period in microseconds. :type period_us: int :raise: IoTPy_APIError """ if 0 <= period_us <= self._PWM_PORT_MAX[self.pwm_port]: if PWM_PORT_RUNNING[self.pwm_port]["period"] != period_us: self.board.low_level_io(0, encode_sfp(self._PWM_PORT_FUNCTIONS[self.pwm_port][0], [period_us])) PWM_PORT_RUNNING[self.pwm_port]["period"] = period_us else: errmsg( "UPER API: PWM period for port %d can be only between 0-%d" % (self.pwm_port, self._PWM_PORT_MAX[self.pwm_port]) ) raise IoTPy_APIError("PWM period is out of range.")
def attach_irq(self, event, callback=None, user_object=None, debounce_time=50): """ Attach (enable) or reconfigure GPIO interrupt event. :param event: GPIO interrupt event. Can have one of these values: GPIO.RISE, GPIO.FALL, GPIO.CHANGE, \ GPIO.LOW or GPIO.HIGH. :param callback: User callback function. This function is executed when the interrupt event is received. \ It should take two arguments: interrupt event description and user object. Interrupt event descriptor is \ dictionary with three fields: 'id' - the interrupt ID (interrupt channel), 'event' - interrupt event type \ and 'values' - the logical values on each of interrupt channel (N-th bit represents logical pin value of \ interrupt channel N). User object is the same object as user_object. :param user_object: User defined object, which will be passed back to the callback function. Optional, \ default is None. :param debounce_time: Interrupt disable time in milliseconds after the triggering event. This is used to \ "debounce" buttons or to protect communication channel from data flood. Optional, default is 50ms. :return: Logical interrupt ID :rtype: int :raise: IoTPy_APIError """ try: irq_id = self.board.interrupts.index(self.logical_pin) self.board.low_level_io(0, encode_sfp(7, [irq_id])) # detach interrupt except ValueError: try: irq_id = self.board.interrupts.index(None) self.board.interrupts[irq_id] = self.logical_pin except ValueError: errmsg("UPER API: more than 8 interrupts requested") raise IoTPy_APIError("Too many interrupts.") self.board.callbackdict[self.logical_pin] = { 'mode': event, 'callback': callback, 'userobject': user_object } self.board.low_level_io( 0, encode_sfp(6, [irq_id, self.logical_pin, event, debounce_time])) return irq_id
def set_period(self, period_us): """ Set PWM period. :param period_us: PWM signal period in microseconds. :type period_us: int :raise: IoTPy_APIError """ if 0 <= period_us <= self._PWM_PORT_MAX[self.pwm_port]: if PWM_PORT_RUNNING[self.pwm_port]['period'] != period_us: self.board.low_level_io( 0, encode_sfp(self._PWM_PORT_FUNCTIONS[self.pwm_port][0], [period_us])) PWM_PORT_RUNNING[self.pwm_port]['period'] = period_us else: errmsg( "UPER API: PWM period for port %d can be only between 0-%d" % (self.pwm_port, self._PWM_PORT_MAX[self.pwm_port])) raise IoTPy_APIError("PWM period is out of range.")
def __init__(self, board, port=0, divider=1, mode=MODE_0): divider = min(max(divider, 1), 256) self.board = board self.port = port self.divider = divider self.mode = mode if self.port == 1: self.board.low_level_io(0, encode_sfp(2, [4])) self.board.low_level_io(0, encode_sfp(2, [5])) self.board.low_level_io(0, encode_sfp(2, [11])) self.board.low_level_io(0, encode_sfp(30, [self.divider, self.mode])) elif self.port == 0: self.board.low_level_io(0, encode_sfp(2, [12])) self.board.low_level_io(0, encode_sfp(2, [13])) self.board.low_level_io(0, encode_sfp(2, [14])) self.board.low_level_io(0, encode_sfp(20, [self.divider, self.mode])) else: errmsg("UPER API: Wrong SPI port number.", self.port) raise IoTPy_APIError("SPI port must be 0 or 1, trying to assign something else.")
def internal_call_back(self, interrupt_data): """ :param interrupt_data: :return: """ interrupt_event = { 'id': interrupt_data[0], 'type': interrupt_data[1] & 0xFF, 'values': interrupt_data[1] >> 8 } callback_entry = self.callbackdict[self.interrupts[ interrupt_event['id']]] try: callback_entry['callback'](interrupt_event, callback_entry['userobject']) except Exception as e: errmsg("IoTPy Interrupt callback exception: %s" % e) return
def set_pulse_time(self, pulse_us): """ Set PWM high (on state) time. :param pulse_us: Pulse time in microseconds. :type pulse_us: int :raise: IoTPy_APIError """ if self.primary: self.board.low_level_io(0, encode_sfp(2, [self.logical_pin])) # set pin secondary function self.primary = False if 0 <= pulse_us <= PWM_PORT_RUNNING[self.pwm_port]["period"]: self.pulse_time = pulse_us high_time = pulse_us if self.polarity == 0: high_time = PWM_PORT_RUNNING[self.pwm_port]["period"] - pulse_us self.board.low_level_io(0, encode_sfp(PWM._PWM_PORT_FUNCTIONS[self.pwm_port][1], [self.pwm_pin, high_time])) else: errmsg("UPER error: PWM high time is out of range on logical pin %d." % self.logical_pin) raise IoTPy_APIError("PWM high time is out of range.")