예제 #1
0
class WS2812:
    # values to put inside the SPI register for each bit of color
    bits = (0xE0, 0xFC)

    def __init__(self, nleds=1):
        # params: * nleds = number of LEDs

        self.buf = bytearray(nleds * 3 * 8)  # 1 byte per bit
        # spi init
        # bus 0, 8MHz => 125 ns by bit, each transfer is 10 cycles long due to the
        # CC3200 spi dead cycles, therefore => 125*10=1.25 us as required by the
        # WS2812. Don't do the automatic pin assigment since we only need MOSI
        self.spi = SPI(0, SPI.MASTER, baudrate=8000000, pins=None)
        Pin('GP16', mode=Pin.ALT, pull=Pin.PULL_DOWN, alt=7)
        # turn all the LEDs off
        self.show([])

    def _send(self):
        # send the buffer over SPI.

        disable_irq()
        self.spi.write(self.buf)
        enable_irq()

    def show(self, data):
        # show RGB data on the LEDs. Expected data = [(R, G, B), ...] where
        # R, G and B are the intensities of the colors in the range 0 to 255.
        # the number of tuples may be less than the number of connected LEDs.

        self.fill(data)
        self._send()

    def update(self, data, start=0):
        # fill a part of the buffer with RGB data.
        # Returns the index of the first unfilled LED.

        buf = self.buf
        bits = self.bits
        idx = start * 24
        for colors in data:
            for c in (1, 0, 2): # the WS2812 requires GRB
                color = colors[c]
                for bit in range (0, 8):
                    buf[idx + bit] = bits[color >> (7 - bit) & 0x01]
                idx += 8
        return idx // 24

    def fill(self, data):
        # fill the buffer with RGB data.
        # all the LEDs after the data are turned off.

        end = self.update(data)
        buf = self.buf
        off = self.bits[0]
        for idx in range(end * 24, len(self.buf)):
            buf[idx] = off
예제 #2
0
class LedStrip:
    """
    Driver for APA102C ledstripes (Adafruit Dotstars) on the Wipy
    Connect
    CLK <---> GP14 (yellow cable)
    DI  <---> GP16 (green cable)
    """

    def __init__(self, leds):
        """
        :param int leds: number of LEDs on strio
        """
        self.ledcount = leds
        self.buffersize = self.ledcount * 4
        self.buffer = bytearray(self.ledcount * 4)
        self.emptybuffer = bytearray(self.ledcount * 4)
        for i in range(0, self.buffersize, 4):
            self.emptybuffer[i] = 0xFF
            self.emptybuffer[i + 1] = 0x0
            self.emptybuffer[i + 2] = 0x0
            self.emptybuffer[i + 3] = 0x0
        self.startframe = bytes([0x00, 0x00, 0x00, 0x00])
        self.endframe = bytes([0xFF, 0xFF, 0xFF, 0xFF])
        self.spi = SPI(0, mode=SPI.MASTER, baudrate=4000000, polarity=0, phase=0, bits=8, firstbit=SPI.MSB)
        self.clear()

    def clear(self):
        self.buffer = self.emptybuffer[:]

    def set(self, led, red=0, green=0, blue=0, bri=0x1F):
        """
        :param int led: Index of LED
        :param int red, green, blue: 0-255
        :param int bri: Brightness 0-31
        """
        if led > self.ledcount:
            led %= self.ledcount

        if led < 0:
            led += self.ledcount

        frameheader = (0x07 << 5) | bri

        offset = led * 4
        self.buffer[offset] = frameheader
        self.buffer[offset + 1] = blue
        self.buffer[offset + 2] = green
        self.buffer[offset + 3] = red

    def send(self):
        self.spi.write(self.startframe + self.buffer)
예제 #3
0
class DotStars:


    def __init__(self, leds):
        self.ledcount = leds
        self.buffersize = self.ledcount * 4
        self.buffer = bytearray(self.ledcount * 4)
        self.emptybuffer = bytearray(self.ledcount * 4)
        for i in range(0, self.buffersize, 4):
            self.emptybuffer[i] = 0xff
            self.emptybuffer[i + 1] = 0x0
            self.emptybuffer[i + 2] = 0x0
            self.emptybuffer[i + 3] = 0x0   
        self.startframe = bytes([0x00, 0x00, 0x00, 0x00])
        self.endframe   = bytes([0xff, 0xff, 0xff, 0xff])
        self.spi = SPI(0, mode=SPI.MASTER, baudrate=8000000, polarity=0, phase=0,bits=8, firstbit=SPI.MSB)
        self.clearleds()

       
    #init empty self.buffer
    def clearleds(self):
        self.buffer = self.emptybuffer[:]

    def setled(self, led, red=0, green=0, blue=0, bri=0x1f):
        if (led > self.ledcount):
            led=led % self.ledcount
        
        if (led < 0):
            led = self.ledcount + led
        
        frameheader = (0x07 << 5) | bri
        offset = led * 4
        self.buffer[offset] = frameheader
        self.buffer[offset + 1] = blue
        self.buffer[offset + 2] = green
        self.buffer[offset + 3] = red

    def send(self):
        #self.spi.write(self.startframe + self.buffer + self.endframe)
        self.spi.write(self.startframe + self.buffer)
예제 #4
0
파일: epd.py 프로젝트: widget/iot-display
class EPD(object):
    MAX_READ = 45
    SW_NORMAL_PROCESSING = 0x9000
    EP_FRAMEBUFFER_SLOT_OVERRUN = 0x6a84 # too much data fed in
    EP_SW_INVALID_LE = 0x6c00 # Wrong expected length
    EP_SW_INSTRUCTION_NOT_SUPPORTED = 0x6d00 # bad instr
    EP_SW_WRONG_PARAMETERS_P1P2 = 0x6a00
    EP_SW_WRONG_LENGTH = 0x6700

    DEFAULT_SLOT=0 # always the *oldest*, should wear-level then I think

    def __init__(self, debug=False, baud=100000):
        # From datasheet
        # Bit rate – up to 12 MHz1
        # ▪ Polarity – CPOL = 1; clock transition high-to-low on the leading edge and low-to-high on the
        #   trailing edge
        # ▪ Phase – CPHA = 1; setup on the leading edge and sample on the trailing edge
        # ▪ Bit order – MSB first
        # ▪ Chip select polarity – active low
        self.spi = SPI(0)
        try:
            self.spi.init(mode=SPI.MASTER, baudrate=baud, bits=8,
                          polarity=1, phase=1, firstbit=SPI.MSB,
                          pins=('GP31', 'GP16', 'GP30')) # CLK, MOSI, MISO
        except AttributeError:
            self.spi.init(baudrate=baud, bits=8,
                          polarity=1, phase=1, firstbit=SPI.MSB,
                          pins=('GP31', 'GP16', 'GP30')) # CLK, MOSI, MISO

        # These are all active low!
        self.tc_en_bar = Pin('GP4', mode=Pin.OUT)

        self.disable()

        self.tc_busy_bar = Pin('GP5', mode=Pin.IN)
        self.tc_busy_bar.irq(trigger=Pin.IRQ_RISING) # Wake up when it changes
        self.tc_cs_bar = Pin('GP17', mode=Pin.ALT, alt=7)

        self.debug = debug

    def enable(self):
        self.tc_en_bar.value(0) # Power up
        time.sleep_ms(5)
        while self.tc_busy_bar() == 0:
            machine.idle() # will it wake up here?
        # /tc_busy goes high during startup, low during init, then high when not busy

    def disable(self):
        self.tc_en_bar.value(1) # Off

    def send_command(self, ins, p1, p2, data=None, expected=None):

        # These command variables are always sent
        cmd = struct.pack('3B', ins, p1, p2)

        # Looks like data is only sent with the length (Lc)
        if data:
            assert len(data) <= 251 # Thus speaks the datasheet
            cmd += struct.pack('B', len(data))
            cmd += data

        # Expected data is either not present at all, 0 for null-terminated, or a number for fixed
        if expected is not None:
            cmd += struct.pack('B', expected)

        if self.debug:
            print("Sending: " + hexlify(cmd).decode())

        self.spi.write(cmd)

        # Wait for a little while
        time.sleep_us(15) # This should take at most 14.5us
        while self.tc_busy_bar() == 0:
            machine.idle()

        # Request a response
        if expected is not None:
            if expected > 0:
                result_bytes = self.spi.read(2 + expected)
            else:
                result_bytes = self.spi.read(EPD.MAX_READ)
                strlen = result_bytes.find(b'\x00')
                result_bytes = result_bytes[:strlen] + result_bytes[strlen+1:strlen+3]
        else:
            result_bytes = self.spi.read(2)

        if self.debug:
            print("Received: " + hexlify(result_bytes).decode())

        (result,) = struct.unpack_from('>H', result_bytes[-2:])

        if result != EPD.SW_NORMAL_PROCESSING:
            raise ValueError("Bad result code: 0x%x" % result)

        return result_bytes[:-2]

    @staticmethod
    def calculate_checksum(data, skip=16):
        """
        Initial checksum value is 0x6363

        :param data:
        :param skip: Skip some data as slices are expensive
        :return:
        """
        acc = 0x6363
        for byte in data:
            if skip > 0:
                skip -= 1
            else:
                acc ^= byte
                acc = ((acc >> 8) | (acc << 8)) & 0xffff
                acc ^= ((acc & 0xff00) << 4) & 0xffff
                acc ^= (acc >> 8) >> 4
                acc ^= (acc & 0xff00) >> 5
        return acc

    def get_sensor_data(self):
        # GetSensorData
        val = self.send_command(0xe5, 1, 0, expected=2)
        (temp,) = struct.unpack(">H", val)
        return temp

    def get_device_id(self):
        return self.send_command(0x30, 2, 1, expected=0x14)

    def get_system_info(self):
        return self.send_command(0x31, 1, 1, expected=0)

    def get_system_version_code(self):
        return self.send_command(0x31, 2, 1, expected=0x10)

    def display_update(self, slot=0, flash=True):
        cmd = 0x86
        if flash:
            cmd = 0x24
        self.send_command(cmd, 1, slot)

    def reset_data_pointer(self):
        self.send_command(0x20, 0xd, 0)

    def image_erase_frame_buffer(self, slot=0):
        self.send_command(0x20, 0xe, slot)

    def get_checksum(self, slot):
        cksum_val = self.send_command(0x2e, 1, slot, expected=2)
        (cksum,) = struct.unpack(">H", cksum_val)
        return cksum

    def upload_image_data(self, data, slot=0, delay_us=1000):
        self.send_command(0x20, 1, slot, data)
        time.sleep_us(delay_us)

    def upload_whole_image(self, img, slot=0):
        """
        Chop up chunks and send it
        :param img: Image to send in EPD format
        :param slot: Slot framebuffer number to use
        :param delay_us: Delay between packets? 450us and the Tbusy line never comes back
        :return:
        """
        total = len(img)
        idx = 0
        try:
            while idx < total - 250:
                chunk = img[idx:idx+250]
                self.upload_image_data(chunk, slot)
                del chunk
                idx += 250
            self.upload_image_data(img[idx:], slot)
        except KeyboardInterrupt:
            print("Stopped at user request at position: %d (%d)" % (idx, (idx // 250)))
        except ValueError as e:
            print("Stopped at position: %d (%d) - %s" % (idx, (idx // 250), e))
예제 #5
0
파일: spi.py 프로젝트: BVH-ESL/MQTTProject
from machine import Pin, SPI
import time
import ubinascii
hspi = SPI(1, baudrate=1000000, polarity=0, phase=0)
# hspi.init()
while 1:
    hspi.write(b'\x05')     # write 5 bytes on MOSI
    time.sleep(1)
예제 #6
0
class MFRC522:

    DEBUG = False
    OK = 0
    NOTAGERR = 1
    ERR = 2

    REQIDL = 0x26
    REQALL = 0x52
    AUTHENT1A = 0x60
    AUTHENT1B = 0x61

    PICC_ANTICOLL1 = 0x93
    PICC_ANTICOLL2 = 0x95
    PICC_ANTICOLL3 = 0x97

    def __init__(self, sck, mosi, miso, rst, cs, baudrate=1000000, spi_id=0):

        self.sck = Pin(sck, Pin.OUT)
        self.mosi = Pin(mosi, Pin.OUT)
        self.miso = Pin(miso)
        self.rst = Pin(rst, Pin.OUT)
        self.cs = Pin(cs, Pin.OUT)

        self.rst.value(0)
        self.cs.value(1)

        board = uname()[0]

        if board == 'WiPy' or board == 'LoPy' or board == 'FiPy':
            self.spi = SPI(0)
            self.spi.init(SPI.MASTER,
                          baudrate=1000000,
                          pins=(self.sck, self.mosi, self.miso))
        elif (board == 'esp8266') or (board == 'esp32'):
            self.spi = SPI(baudrate=100000,
                           polarity=0,
                           phase=0,
                           sck=self.sck,
                           mosi=self.mosi,
                           miso=self.miso)
            self.spi.init()
        elif board == 'rp2':
            self.spi = SPI(spi_id,
                           baudrate=baudrate,
                           sck=self.sck,
                           mosi=self.mosi,
                           miso=self.miso)
        else:
            raise RuntimeError("Unsupported platform")

        self.rst.value(1)
        self.init()

    def _wreg(self, reg, val):

        self.cs.value(0)
        self.spi.write(b'%c' % int(0xff & ((reg << 1) & 0x7e)))
        self.spi.write(b'%c' % int(0xff & val))
        self.cs.value(1)

    def _rreg(self, reg):

        self.cs.value(0)
        self.spi.write(b'%c' % int(0xff & (((reg << 1) & 0x7e) | 0x80)))
        val = self.spi.read(1)
        self.cs.value(1)

        return val[0]

    def _sflags(self, reg, mask):
        self._wreg(reg, self._rreg(reg) | mask)

    def _cflags(self, reg, mask):
        self._wreg(reg, self._rreg(reg) & (~mask))

    def _tocard(self, cmd, send):

        recv = []
        bits = irq_en = wait_irq = n = 0
        stat = self.ERR

        if cmd == 0x0E:
            irq_en = 0x12
            wait_irq = 0x10
        elif cmd == 0x0C:
            irq_en = 0x77
            wait_irq = 0x30

        self._wreg(0x02, irq_en | 0x80)
        self._cflags(0x04, 0x80)
        self._sflags(0x0A, 0x80)
        self._wreg(0x01, 0x00)

        for c in send:
            self._wreg(0x09, c)
        self._wreg(0x01, cmd)

        if cmd == 0x0C:
            self._sflags(0x0D, 0x80)

        i = 2000
        while True:
            n = self._rreg(0x04)
            i -= 1
            if ~((i != 0) and ~(n & 0x01) and ~(n & wait_irq)):
                break

        self._cflags(0x0D, 0x80)

        if i:
            if (self._rreg(0x06) & 0x1B) == 0x00:
                stat = self.OK

                if n & irq_en & 0x01:
                    stat = self.NOTAGERR
                elif cmd == 0x0C:
                    n = self._rreg(0x0A)
                    lbits = self._rreg(0x0C) & 0x07
                    if lbits != 0:
                        bits = (n - 1) * 8 + lbits
                    else:
                        bits = n * 8

                    if n == 0:
                        n = 1
                    elif n > 16:
                        n = 16

                    for _ in range(n):
                        recv.append(self._rreg(0x09))
            else:
                stat = self.ERR

        return stat, recv, bits

    def _crc(self, data):

        self._cflags(0x05, 0x04)
        self._sflags(0x0A, 0x80)

        for c in data:
            self._wreg(0x09, c)

        self._wreg(0x01, 0x03)

        i = 0xFF
        while True:
            n = self._rreg(0x05)
            i -= 1
            if not ((i != 0) and not (n & 0x04)):
                break

        return [self._rreg(0x22), self._rreg(0x21)]

    def init(self):

        self.reset()
        self._wreg(0x2A, 0x8D)
        self._wreg(0x2B, 0x3E)
        self._wreg(0x2D, 30)
        self._wreg(0x2C, 0)
        self._wreg(0x15, 0x40)
        self._wreg(0x11, 0x3D)
        self.antenna_on()

    def reset(self):
        self._wreg(0x01, 0x0F)

    def antenna_on(self, on=True):

        if on and ~(self._rreg(0x14) & 0x03):
            self._sflags(0x14, 0x03)
        else:
            self._cflags(0x14, 0x03)

    def request(self, mode):

        self._wreg(0x0D, 0x07)
        (stat, recv, bits) = self._tocard(0x0C, [mode])

        if (stat != self.OK) | (bits != 0x10):
            stat = self.ERR

        return stat, bits

    def anticoll(self, anticolN):

        ser_chk = 0
        ser = [anticolN, 0x20]

        self._wreg(0x0D, 0x00)
        (stat, recv, bits) = self._tocard(0x0C, ser)

        if stat == self.OK:
            if len(recv) == 5:
                for i in range(4):
                    ser_chk = ser_chk ^ recv[i]
                if ser_chk != recv[4]:
                    stat = self.ERR
            else:
                stat = self.ERR

        return stat, recv

    def PcdSelect(self, serNum, anticolN):
        backData = []
        buf = []
        buf.append(anticolN)
        buf.append(0x70)
        #i = 0
        ###xorsum=0;
        for i in serNum:
            buf.append(i)
        #while i<5:
        #    buf.append(serNum[i])
        #    i = i + 1
        pOut = self._crc(buf)
        buf.append(pOut[0])
        buf.append(pOut[1])
        (status, backData, backLen) = self._tocard(0x0C, buf)
        if (status == self.OK) and (backLen == 0x18):
            return 1
        else:
            return 0

    def SelectTag(self, uid):
        byte5 = 0

        #(status,puid)= self.anticoll(self.PICC_ANTICOLL1)
        #print("uid",uid,"puid",puid)
        for i in uid:
            byte5 = byte5 ^ i
        puid = uid + [byte5]

        if self.PcdSelect(puid, self.PICC_ANTICOLL1) == 0:
            return (self.ERR, [])
        return (self.OK, uid)

    def tohexstring(self, v):
        s = "["
        for i in v:
            if i != v[0]:
                s = s + ", "
            s = s + "0x{:02X}".format(i)
        s = s + "]"
        return s

    def SelectTagSN(self):
        valid_uid = []
        (status, uid) = self.anticoll(self.PICC_ANTICOLL1)
        #print("Select Tag 1:",self.tohexstring(uid))
        if status != self.OK:
            return (self.ERR, [])

        if self.DEBUG: print("anticol(1) {}".format(uid))
        if self.PcdSelect(uid, self.PICC_ANTICOLL1) == 0:
            return (self.ERR, [])
        if self.DEBUG: print("pcdSelect(1) {}".format(uid))

        #check if first byte is 0x88
        if uid[0] == 0x88:
            #ok we have another type of card
            valid_uid.extend(uid[1:4])
            (status, uid) = self.anticoll(self.PICC_ANTICOLL2)
            #print("Select Tag 2:",self.tohexstring(uid))
            if status != self.OK:
                return (self.ERR, [])
            if self.DEBUG: print("Anticol(2) {}".format(uid))
            rtn = self.PcdSelect(uid, self.PICC_ANTICOLL2)
            if self.DEBUG:
                print("pcdSelect(2) return={} uid={}".format(rtn, uid))
            if rtn == 0:
                return (self.ERR, [])
            if self.DEBUG: print("PcdSelect2() {}".format(uid))
            #now check again if uid[0] is 0x88
            if uid[0] == 0x88:
                valid_uid.extend(uid[1:4])
                (status, uid) = self.anticoll(self.PICC_ANTICOLL3)
                #print("Select Tag 3:",self.tohexstring(uid))
                if status != self.OK:
                    return (self.ERR, [])
                if self.DEBUG: print("Anticol(3) {}".format(uid))
                if self.MFRC522_PcdSelect(uid, self.PICC_ANTICOLL3) == 0:
                    return (self.ERR, [])
                if self.DEBUG: print("PcdSelect(3) {}".format(uid))
        valid_uid.extend(uid[0:5])
        # if we are here than the uid is ok
        # let's remove the last BYTE whic is the XOR sum

        return (self.OK, valid_uid[:len(valid_uid) - 1])
        #return (self.OK , valid_uid)

    def auth(self, mode, addr, sect, ser):
        return self._tocard(0x0E, [mode, addr] + sect + ser[:4])[0]

    def authKeys(self, uid, addr, keyA=None, keyB=None):
        status = self.ERR
        if keyA is not None:
            status = self.auth(self.AUTHENT1A, addr, keyA, uid)
        elif keyB is not None:
            status = self.auth(self.AUTHENT1B, addr, keyB, uid)
        return status

    def stop_crypto1(self):
        self._cflags(0x08, 0x08)

    def read(self, addr):

        data = [0x30, addr]
        data += self._crc(data)
        (stat, recv, _) = self._tocard(0x0C, data)
        return stat, recv

    def write(self, addr, data):

        buf = [0xA0, addr]
        buf += self._crc(buf)
        (stat, recv, bits) = self._tocard(0x0C, buf)

        if not (stat == self.OK) or not (bits == 4) or not (
            (recv[0] & 0x0F) == 0x0A):
            stat = self.ERR
        else:
            buf = []
            for i in range(16):
                buf.append(data[i])
            buf += self._crc(buf)
            (stat, recv, bits) = self._tocard(0x0C, buf)
            if not (stat == self.OK) or not (bits == 4) or not (
                (recv[0] & 0x0F) == 0x0A):
                stat = self.ERR
        return stat

    def writeSectorBlock(self, uid, sector, block, data, keyA=None, keyB=None):
        absoluteBlock = sector * 4 + (block % 4)
        if absoluteBlock > 63:
            return self.ERR
        if len(data) != 16:
            return self.ERR
        if self.authKeys(uid, absoluteBlock, keyA, keyB) != self.ERR:
            return self.write(absoluteBlock, data)
        return self.ERR

    def readSectorBlock(self, uid, sector, block, keyA=None, keyB=None):
        absoluteBlock = sector * 4 + (block % 4)
        if absoluteBlock > 63:
            return self.ERR, None
        if self.authKeys(uid, absoluteBlock, keyA, keyB) != self.ERR:
            return self.read(absoluteBlock)
        return self.ERR, None

    def MFRC522_DumpClassic1K(self,
                              uid,
                              Start=0,
                              End=64,
                              keyA=None,
                              keyB=None):
        for absoluteBlock in range(Start, End):
            status = self.authKeys(uid, absoluteBlock, keyA, keyB)
            # Check if authenticated
            print("{:02d} S{:02d} B{:1d}: ".format(absoluteBlock,
                                                   absoluteBlock // 4,
                                                   absoluteBlock % 4),
                  end="")
            if status == self.OK:
                status, block = self.read(absoluteBlock)
                if status == self.ERR:
                    break
                else:
                    for value in block:
                        print("{:02X} ".format(value), end="")
                    print("  ", end="")
                    for value in block:
                        if (value > 0x20) and (value < 0x7f):
                            print(chr(value), end="")
                        else:
                            print('.', end="")
                    print("")
            else:
                break
        if status == self.ERR:
            print("Authentication error")
            return self.ERR
        return self.OK
예제 #7
0
파일: spi.py 프로젝트: 19emtuck/micropython
print(spi)
spi = SPI(0, SPI.MASTER, baudrate=5000000, bits=32, polarity=1, phase=0)
print(spi)
spi = SPI(0, SPI.MASTER, baudrate=10000000, polarity=1, phase=1)
print(spi)
spi.init(baudrate=20000000, polarity=0, phase=0)
print(spi)
spi=SPI()
print(spi)
SPI(mode=SPI.MASTER)
SPI(mode=SPI.MASTER, pins=spi_pins)
SPI(id=0, mode=SPI.MASTER, polarity=0, phase=0, pins=('GP14', 'GP16', 'GP15'))
SPI(0, SPI.MASTER, polarity=0, phase=0, pins=('GP31', 'GP16', 'GP15'))

spi = SPI(0, SPI.MASTER, baudrate=10000000, polarity=0, phase=0, pins=spi_pins)
print(spi.write('123456') == 6)
buffer_r = bytearray(10)
print(spi.readinto(buffer_r) == 10)
print(spi.readinto(buffer_r, write=0x55) == 10)
read = spi.read(10)
print(len(read) == 10)
read = spi.read(10, write=0xFF)
print(len(read) == 10)
buffer_w = bytearray([1, 2, 3, 4, 5, 6, 7, 8, 9, 0])
print(spi.write_readinto(buffer_w, buffer_r) == 10)
print(buffer_w == buffer_r)

# test all polaritiy and phase combinations
spi.init(polarity=1, phase=0, pins=None)
buffer_r = bytearray(10)
spi.write_readinto(buffer_w, buffer_r)
예제 #8
0
from machine import Pin, SPI
import time
import ubinascii

vref = 3.3
cs = Pin(15, Pin.OUT)
cs.high()
hspi = SPI(1, baudrate=1600000, polarity=0, phase=0)
value = bytearray(2)

while True:
    data = bytearray(2)
    wget = b'\xA0\x00'
    cs.low()
    hspi.write(b'\x01')
    hspi.write(b'\xA0')
    data = hspi.read(1)
    # data = hspi.write_readinto(wget, data)
    cs.high()
    print(str(int(ubinascii.hexlify(data & b'\x0fff'))*vref/4096))
    time.sleep(1)
    # data = data*vref/4096
    # time.sleep(1)
    # print(str(data & b'\x0fff'))
from fpioa_manager import fm

mosi = 8
miso = 15
cs = 20
clk = 21

spi = SPI(SPI.SPI_SOFT,
          mode=SPI.MODE_MASTER,
          baudrate=400 * 1000,
          polarity=0,
          phase=0,
          bits=8,
          firstbit=SPI.MSB,
          sck=clk,
          mosi=mosi,
          miso=miso)
fm.register(cs, fm.fpioa.GPIO6, force=True)
cs = GPIO(GPIO.GPIO6, GPIO.OUT)

# read spi flash id
while True:
    cs.value(0)
    write_data = bytearray([0x90, 0x00, 0x00, 0x00])
    spi.write(write_data)
    id_buf = bytearray(2)
    spi.readinto(id_buf, write=0xff)
    work_data = id_buf
    cs.value(1)
    print(work_data)
예제 #10
0
class spiram:
    def __init__(self):
        self.led = Pin(5, Pin.OUT)
        self.led.off()
        self.spi_channel = const(2)
        self.init_pinout_sd()
        self.spi_freq = const(4000000)
        self.hwspi = SPI(self.spi_channel,
                         baudrate=self.spi_freq,
                         polarity=0,
                         phase=0,
                         bits=8,
                         firstbit=SPI.MSB,
                         sck=Pin(self.gpio_sck),
                         mosi=Pin(self.gpio_mosi),
                         miso=Pin(self.gpio_miso))

    @micropython.viper
    def init_pinout_sd(self):
        self.gpio_sck = const(16)
        self.gpio_mosi = const(4)
        self.gpio_miso = const(12)

    # read from file -> write to SPI RAM
    def load_stream(self, filedata, addr=0, maxlen=0x10000, blocksize=1024):
        block = bytearray(blocksize)
        # Request load
        self.led.on()
        self.hwspi.write(
            bytearray([
                0, (addr >> 24) & 0xFF, (addr >> 16) & 0xFF,
                (addr >> 8) & 0xFF, addr & 0xFF
            ]))
        bytes_loaded = 0
        while bytes_loaded < maxlen:
            if filedata.readinto(block):
                self.hwspi.write(block)
                bytes_loaded += blocksize
            else:
                break
        self.led.off()

    # read from SPI RAM -> write to file
    def save_stream(self, filedata, addr=0, length=1024, blocksize=1024):
        bytes_saved = 0
        block = bytearray(blocksize)
        # Request save
        self.led.on()
        self.hwspi.write(
            bytearray([
                1, (addr >> 24) & 0xFF, (addr >> 16) & 0xFF,
                (addr >> 8) & 0xFF, addr & 0xFF, 0
            ]))
        while bytes_saved < length:
            self.hwspi.readinto(block)
            filedata.write(block)
            bytes_saved += len(block)
        self.led.off()

    def ctrl(self, i):
        self.led.on()
        self.hwspi.write(bytearray([0, 0xFF, 0xFF, 0xFF, 0xFF, i]))
        self.led.off()

    def cpu_halt(self):
        self.ctrl(2)

    def cpu_continue(self):
        self.ctrl(0)

    def store_rom(self, length=32):
        self.stored_code = bytearray(length)
        self.led.on()
        self.hwspi.write(
            bytearray([
                1, 0, 0, (self.code_addr >> 8) & 0xFF, self.code_addr & 0xFF, 0
            ]))
        self.hwspi.readinto(self.stored_code)
        self.led.off()
        self.stored_vector = bytearray(2)
        self.led.on()
        self.hwspi.write(
            bytearray([
                1, 0, 0, (self.vector_addr >> 8) & 0xFF,
                self.vector_addr & 0xFF, 0
            ]))
        self.hwspi.readinto(self.stored_vector)
        self.led.off()

    def restore_rom(self):
        self.led.on()
        self.hwspi.write(
            bytearray(
                [0, 0, 0, (self.code_addr >> 8) & 0xFF,
                 self.code_addr & 0xFF]))
        self.hwspi.write(self.stored_code)
        self.led.off()
        self.led.on()
        self.hwspi.write(
            bytearray([
                0, 0, 0, (self.vector_addr >> 8) & 0xFF,
                self.vector_addr & 0xFF
            ]))
        self.hwspi.write(self.stored_vector)
        self.led.off()

    def patch_rom(self, regs):
        # regs   = 0:A 1:X 2:Y 3:P 4:S 5-6:PC
        # overwrite with register restore code
        self.led.on()
        self.hwspi.write(
            bytearray([
                0, 0, 0, (self.vector_addr >> 8) & 0xFF,
                self.vector_addr & 0xFF, self.code_addr & 0xFF,
                (self.code_addr >> 8) & 0xFF
            ]))  # overwrite reset vector at 0xFFFC
        self.led.off()
        self.led.on()
        self.hwspi.write(
            bytearray(
                [0, 0, 0, (self.code_addr >> 8) & 0xFF,
                 self.code_addr & 0xFF]))  # overwrite code
        self.hwspi.write(
            bytearray([
                0x78, 0xA2, regs[4], 0x9A, 0xA2, regs[1], 0xA0, regs[2], 0xA9,
                regs[3], 0x48, 0x28, 0xA9, regs[0], 0x4C, regs[5], regs[6]
            ]))
        self.led.off()
        self.led.on()
예제 #11
0
class WS2812:
    """
    Driver for WS2812 RGB LEDs. May be used for controlling single LED or chain
    of LEDs.

    Example of use:

        chain = WS2812(ledNumber=4)
        data = [
            (255, 0, 0),    # red
            (0, 255, 0),    # green
            (0, 0, 255),    # blue
            (85, 85, 85),   # white
        ]
        chain.show(data)

    Version: 1.0
    """
    # Values to put inside SPi register for each color's bit
    buf_bytes = (0xE0E0, 0xFCE0, 0xE0FC, 0xFCFC)

    def __init__(self, ledNumber=1, brightness=100, dataPin='P22'):
        """
        Params:
        * ledNumber = count of LEDs
        * brightness = light brightness (integer : 0 to 100%)
        * dataPin = pin to connect data channel (LoPy only)
        """
        self.ledNumber = ledNumber
        self.brightness = brightness

        # Prepare SPI data buffer (8 bytes for each color)
        self.buf_length = self.ledNumber * 3 * 8
        self.buf = bytearray(self.buf_length)

        # SPI init
        # Bus 0, 8MHz => 125 ns by bit, 8 clock cycle when bit transfert+2 clock cycle between each transfert
        # => 125*10=1.25 us required by WS2812
        if uname().sysname == 'LoPy':
            self.spi = SPI(0,
                           SPI.MASTER,
                           baudrate=8000000,
                           polarity=0,
                           phase=1,
                           pins=(None, dataPin, None))
            # Enable pull down
            Pin(dataPin, mode=Pin.OUT, pull=Pin.PULL_DOWN)
        else:  #WiPy
            self.spi = SPI(0,
                           SPI.MASTER,
                           baudrate=8000000,
                           polarity=0,
                           phase=1)
            # Enable pull down
            Pin('GP16', mode=Pin.ALT, pull=Pin.PULL_DOWN)

        # Turn LEDs off
        self.show([])

    def show(self, data):
        """
        Show RGB data on LEDs. Expected data = [(R, G, B), ...] where R, G and B
        are intensities of colors in range from 0 to 255. One RGB tuple for each
        LED. Count of tuples may be less than count of connected LEDs.
        """
        self.fill_buf(data)
        self.send_buf()

    def send_buf(self):
        """
        Send buffer over SPI.
        """
        disable_irq()
        self.spi.write(self.buf)
        enable_irq()
        gc.collect()

    def update_buf(self, data, start=0):
        """
        Fill a part of the buffer with RGB data.

        Order of colors in buffer is changed from RGB to GRB because WS2812 LED
        has GRB order of colors. Each color is represented by 4 bytes in buffer
        (1 byte for each 2 bits).

        Returns the index of the first unfilled LED

        Note: If you find this function ugly, it's because speed optimisations
        beated purity of code.
        """

        buf = self.buf
        buf_bytes = self.buf_bytes
        brightness = self.brightness

        index = start * 24
        for red, green, blue in data:
            red = int(red * brightness // 100)
            green = int(green * brightness // 100)
            blue = int(blue * brightness // 100)

            buf[index] = buf_bytes[green >> 6 & 0x03]
            buf[index + 2] = buf_bytes[green >> 4 & 0x03]
            buf[index + 4] = buf_bytes[green >> 2 & 0x03]
            buf[index + 6] = buf_bytes[green & 0x03]

            buf[index + 8] = buf_bytes[red >> 6 & 0x03]
            buf[index + 10] = buf_bytes[red >> 4 & 0x03]
            buf[index + 12] = buf_bytes[red >> 2 & 0x03]
            buf[index + 14] = buf_bytes[red & 0x03]

            buf[index + 16] = buf_bytes[blue >> 6 & 0x03]
            buf[index + 18] = buf_bytes[blue >> 4 & 0x03]
            buf[index + 20] = buf_bytes[blue >> 2 & 0x03]
            buf[index + 22] = buf_bytes[blue & 0x03]

            index += 24

        return index // 24

    def fill_buf(self, data):
        """
        Fill buffer with RGB data.

        All LEDs after the data are turned off.
        """
        end = self.update_buf(data)

        # Turn off the rest of the LEDs
        buf = self.buf
        off = self.buf_bytes[0]
        for index in range(end * 24, self.buf_length):
            buf[index] = off
            index += 2

    def set_brightness(self, brightness):
        """
        Set brighness of all leds
        """
        self.brightness = brightness
예제 #12
0
class Accelerometer:
    def __init__(self,
                 cs_pin=5,
                 scl_pin=18,
                 sda_pin=23,
                 sdo_pin=19,
                 spi_freq=5000000):
        """
    Class for fast SPI comunications between an ESP32 flashed with MicroPython and an Analog Devices ADXL345
      accelerometer
    :param cs_pin: MCU pin number at which accelerometer's CS wire is connected
    :param scl_pin: MCU pin number at which accelerometer's SCL wire is connected (SCK)
    :param sda_pin: MCU pin number at which accelerometer's SDA wire is connected (MOSI)
    :param sdo_pin: MCU pin number at which accelerometer's SDO wire is connected (MISO)
    :param spi_freq: frequency of SPI comunications
    """

        # valid inputs
        if spi_freq > 5000000:
            spi_freq = 5000000
            print('max spi clock frequency for adxl355 is 5Mhz')

        # constants
        self.standard_g = 9.80665  # m/s2
        self.read_mask = const(0x80)
        self.multibyte_mask = const(0x40)
        self.nmaxvalues_infifo = 32
        self.bytes_per_3axes = 6  # 2 bytes * 3 axes
        self.device_id = 0xE5

        # register addresses
        self.addr_device = const(0x53)
        self.regaddr_devid = const(0x00)
        self.regaddr_acc = const(0x32)
        self.regaddr_freq = const(0x2C)
        self.regaddr_pwr = const(0x2D)
        self.regaddr_intsource = const(0x30)
        self.regaddr_grange = const(0x31)
        self.regaddr_fifoctl = const(0x38)
        self.regaddr_fifostatus = const(0x39)

        # SPI pins
        self.cs_pin = cs_pin
        self.scl_pin = scl_pin
        self.sdo_pin = sdo_pin
        self.sda_pin = sda_pin
        self.spi_freq = spi_freq

        # allowed values
        self.power_modes = {'standby': 0x00, 'measure': 0x08}
        self.g_ranges = {2: 0x00, 4: 0x01, 8: 0x10, 16: 0x11}
        self.device_sampling_rates = {
            1.56: 0x04,
            3.13: 0x05,
            6.25: 0x06,
            12.5: 0x07,
            25: 0x08,
            50: 0x09,
            100: 0x0a,
            200: 0x0b,
            400: 0x0c,
            800: 0x0d,
            1600: 0x0e,
            3200: 0x0f
        }

    def __del__(self):
        self.spi.deinit()

    # == general purpose ==
    def init_spi(self):
        self.spi = SPI(2,
                       sck=Pin(self.scl_pin, Pin.OUT),
                       mosi=Pin(self.sda_pin, Pin.OUT),
                       miso=Pin(self.sdo_pin),
                       baudrate=self.spi_freq,
                       polarity=1,
                       phase=1,
                       bits=8,
                       firstbit=SPI.MSB)
        time.sleep(0.2)
        self.cs = Pin(self.cs_pin, Pin.OUT, value=1)
        time.sleep(0.2)
        if not self.is_spi_communcation_working():
            print('SPI communication is not working: '
                  '\n\t* wrong wiring?'
                  '\n\t* reinitialised SPI?'
                  '\n\t* broken sensor (test I2C to be sure)')
        return self

    def deinit_spi(self):
        self.spi.deinit()
        return self

    def write(self, regaddr: int, the_byte: int):
        """
    write byte into register address
    :param regaddr: register address to write
    :param bt: byte to write
    """
        self.cs.value(0)
        self.spi.write(bytearray((regaddr, the_byte)))
        self.cs.value(1)
        return self

    @micropython.native
    def read(self, regaddr: int, nbytes: int) -> bytearray or int:
        """
    read bytes from register
    :param regaddr: register address to read
    :param nbytes: number of bytes to read
    :return: byte or bytes read
    """
        wbyte = regaddr | self.read_mask
        if nbytes > 1:
            wbyte = wbyte | self.multibyte_mask
        self.cs.value(0)
        value = self.spi.read(nbytes + 1, wbyte)[1:]
        self.cs.value(1)
        return value

    @micropython.native
    def read_into(self, buf: bytearray, regaddr: int) -> bytearray:
        """
    read bytes from register into an existing bytearray, generally faster than normal read
    :param rbuf: bytearray where read values will be assigned to
    :param regaddr: register address to read
    :return: modified input bytearray
    """
        wbyte = regaddr | self.read_mask | self.multibyte_mask
        self.cs.value(0)
        self.spi.readinto(buf, wbyte)
        self.cs.value(1)
        return buf

    @micropython.native
    def remove_first_bytes_from_bytearray_of_many_transactions(
            self, buf: bytearray) -> bytearray:
        """
    remove first byte of SPI transaction (which is irrelevant) from a buffer read through spi.readinto
    :param buf: bytearray of size multiple of (self.bytes_per_3axes + 1)
    :return: bytearray of size multiple of self.bytes_per_3axes
    """
        bytes_per_3axes = self.bytes_per_3axes
        return bytearray(
            [b for i, b in enumerate(buf) if i % (bytes_per_3axes + 1) != 0])

    # == settings ==
    def set_power_mode(self, mode: str):
        """
    set the power mode of the accelerometer
    :param mode: {'measure', 'standby'}
    """
        print('set power mode to %s' % (mode))
        self.write(self.regaddr_pwr, self.power_modes[mode])
        self.power_mode = mode
        return self

    def set_g_range(self, grange: int):
        """
    set the scale of output acceleration data
    :param grange: {2, 4, 8, 16}
    """
        print('set range to pm %s' % (grange))
        self.write(self.regaddr_grange, self.g_ranges[grange])
        self.g_range = grange
        return self

    def set_sampling_rate(self, sr: int):
        """
    :param sr: sampling rate of the accelerometer can be {1.56, 3.13, 6.25, 12.5, 25, 50, 100, 200, 400, 800, 1600, 3200}
    """
        print('set sampling rate to %s' % (sr))
        self.write(self.regaddr_freq, self.device_sampling_rates[sr])
        self.sampling_rate = sr
        return self

    def set_fifo_mode(self, mode: str, watermark_level: int = 16):
        """
    :param mode: in 'stream' mode the fifo is on, in 'bypass' mode the fifo is off
    :param watermark_level: see set_watermark_level method
    """
        self.fifo_mode = mode
        self.watermark_level = watermark_level
        if mode == 'bypass':
            b = 0x00
            print("set fifo in bypass mode")
        else:  # stream mode
            stream_bstr = '100'
            wm_bstr = bin(watermark_level).split('b')[1]
            bstr = '0b' + stream_bstr + '{:>5}'.format(wm_bstr).replace(
                ' ', '0')
            b = int(bstr, 2)
            print("set fifo in stream mode")
        self.write(self.regaddr_fifoctl, b)
        return self

    def set_watermark_level(self, nrows: int = 16):
        """
    set the number of new measures (xyz counts 1) after which the watermark is triggered
    """
        print('set watermark to %s rows' % (nrows))
        self.fifo_mode = 'stream'
        self.watermark_level = nrows
        stream_bstr = '100'
        wm_bstr = bin(nrows).split('b')[1]
        bstr = '0b' + stream_bstr + '{:>5}'.format(wm_bstr).replace(' ', '0')
        b = int(bstr, 2)
        self.write(self.regaddr_fifoctl, b)
        return self

    # == readings ==
    def is_spi_communcation_working(self) -> bool:
        if self.read(self.regaddr_devid, 1)[0] == self.device_id:
            return True
        else:
            print(self.read(self.regaddr_devid, 1))
            return False

    def clear_fifo(self):
        """
    Clears all values in fifo: usefull to start reading FIFO when expected, otherwise the first values were
    recorded before actually starting the measure
    """
        self.set_fifo_mode('bypass')
        self.set_fifo_mode('stream')

    def clear_isdataready(self):
        _ = self.read(self.regaddr_acc, 6)

    @micropython.native
    def is_watermark_reached(self) -> bool:
        """
    :return: 1 if watermark level of measures was reached since last reading, 0 otherwise
    """
        return self.read(self.regaddr_intsource, 1)[0] >> 1 & 1  # second bit

    @micropython.native
    def is_data_ready(self) -> bool:
        """
    :return: 1 if a new measure has arrived since last reading, 0 otherwise
    """
        return self.read(self.regaddr_intsource, 1)[0] >> 7 & 1  # eighth bit

    @micropython.native
    def get_nvalues_in_fifo(self) -> int:
        """
    :return: number of measures (xyz counts 1) in the fifo since last reading
    """
        return self.read(self.regaddr_fifostatus,
                         1)[0] & 0x3f  # first six bits to int

    # == continuos readings able to reach 3.2 kHz ==
    @micropython.native
    def read_many_xyz(self, n: int) -> tuple:
        """
    :param n: number of xyz accelerations to read from the accelerometer
    return: (
        bytearray containing 2 bytes for each of the 3 axes multiplied by the fractions of the sampling rate contained in the acquisition time,
        array of times at which each sample was recorded in microseconds
    )
    """
        print("Measuring %s samples at %s Hz, range %sg" %
              (n, self.sampling_rate, self.g_range))
        # local variables and functions are MUCH faster
        regaddr_acc = self.regaddr_acc | self.read_mask | self.multibyte_mask
        regaddr_intsource = self.regaddr_intsource | self.read_mask
        spi_readinto = self.spi.readinto
        cs = self.cs
        ticks_us = time.ticks_us
        bytes_per_3axes = self.bytes_per_3axes
        read = self.spi.read
        # definitions
        n_exp_meas = n
        n_exp_bytes = (self.bytes_per_3axes + 1) * n_exp_meas
        T = [0] * (int(n_exp_meas * 1.5))
        buf = bytearray(int(n_exp_bytes * 1.5))
        m = memoryview(buf)
        # set up device
        self.set_fifo_mode('bypass')
        gc.collect()
        # measure
        n_act_meas = 0
        self.set_power_mode('measure')
        while n_act_meas < n_exp_meas:
            start_index = n_act_meas * (bytes_per_3axes + 1)
            stop_index = n_act_meas * (bytes_per_3axes + 1) + (
                bytes_per_3axes + 1)
            cs.value(0)
            is_data_ready = read(2, regaddr_intsource)[1] >> 7 & 1
            cs.value(1)
            if not is_data_ready:
                continue
            cs.value(0)
            spi_readinto(m[start_index:stop_index], regaddr_acc)
            cs.value(1)
            T[n_act_meas] = ticks_us()
            n_act_meas += 1
        self.set_power_mode('standby')
        # final corrections
        buf = self.remove_first_bytes_from_bytearray_of_many_transactions(buf)
        buf = buf[:n_exp_meas * bytes_per_3axes]  # remove exceeding values
        T = T[:n_exp_meas]  # remove exceeding values
        # debug
        actual_acq_time = (T[-1] - T[0]) / 1000000
        print('measured for %s seconds, expected %s seconds' %
              (actual_acq_time, n_exp_meas / self.sampling_rate))
        print('avg sampling rate = ' + str(n_act_meas / actual_acq_time) +
              ' Hz')
        # TODO: send error to webapp when actual acquisition time is different from expected
        gc.collect()
        return buf, T

    @micropython.native
    def read_many_xyz_fromfifo(self, n: int) -> tuple:
        """
    read many measures of accaleration on the 3 axes from the fifo register
    :param n: number of measures to read (xyz counts 1)
    return: (
        bytearray containing 2 bytes for each of the 3 axes multiplied by the fractions of the sampling rate contained in the acquisition time,
        array of times at which each sample was recorded in microseconds
    )
    """
        print("Measuring %s samples at %s Hz, range %sg" %
              (n, self.sampling_rate, self.g_range))
        # local variables and functions are MUCH faster
        regaddr_acc = self.regaddr_acc | self.read_mask | self.multibyte_mask
        spi_readinto = self.spi.readinto
        cs = self.cs
        get_nvalues_in_fifo = self.get_nvalues_in_fifo
        bytes_per_3axes = self.bytes_per_3axes
        # definitions
        n_exp_meas = n
        n_exp_bytes = (bytes_per_3axes + 1) * n_exp_meas
        buf = bytearray(int(n_exp_bytes * 1.5))
        m = memoryview(buf)
        # set up device
        self.set_fifo_mode('stream')
        gc.collect()
        # measure
        n_act_meas = 0
        self.set_power_mode('measure')
        self.clear_fifo()
        t_start = time.ticks_us()
        while n_act_meas < n_exp_meas:
            nvalues_infifo = get_nvalues_in_fifo()
            for _ in range(
                    nvalues_infifo
            ):  # it is impossible to read a block of measures from fifo
                cs.value(0)
                spi_readinto(
                    m[n_act_meas * (bytes_per_3axes + 1):n_act_meas *
                      (bytes_per_3axes + 1) + (bytes_per_3axes + 1)],
                    regaddr_acc)
                cs.value(1)
                n_act_meas += 1
        t_stop = time.ticks_us()
        self.set_power_mode('standby')
        # final corrections
        buf = self.remove_first_bytes_from_bytearray_of_many_transactions(buf)
        buf = buf[:n_exp_meas * bytes_per_3axes]  # remove exceeding values
        actual_acq_time = (t_stop - t_start) / 1000000
        actual_sampling_rate = n_act_meas / actual_acq_time
        T = [(i + 1) / actual_sampling_rate for i in range(n_exp_meas)]
        # debug
        print('measured for %s seconds, expected %s seconds' %
              (actual_acq_time, n / self.sampling_rate))
        print('actual sampling rate = ' + str(n_act_meas / actual_acq_time) +
              ' Hz')
        # TODO: send error to webapp when actual acquisition time is different from expected
        gc.collect()
        return buf, T

    @micropython.native
    def read_continuos_xyz(self, acquisition_time: int) -> tuple:
        """
    read for the provided amount of time from the acceleration register, saving the value only if a new measure is
    available since last reading
    :param acquisition_time: seconds the acquisition should last
    :return: (
        bytearray containing 2 bytes for each of the 3 axes multiplied by the fractions of the sampling rate contained in the acquisition time,
        array of times at which each sample was recorded in microseconds
    )
    """
        n_exp_meas = int(acquisition_time * self.sampling_rate)
        buf, T = self.read_many_xyz(n_exp_meas)
        return buf, T

    @micropython.native
    def read_continuos_xyz_fromfifo(self, acquisition_time: int) -> tuple:
        """
    read for the provided amount of time all the values contained in the fifo register (if any)
    :param acquisition_time:
    :return: (
        bytearray containing 2 bytes for each of the 3 axes multiplied by the fractions of the sampling rate contained in the acquisition time,
        array of times at which each sample was recorded in microseconds
    )
    """
        n_exp_meas = int(acquisition_time * self.sampling_rate)
        buf, T = self.read_many_xyz_fromfifo(n_exp_meas)
        return buf, T

    # == conversions ==
    def xyzbytes2g(self, buf: bytearray) -> tuple:
        """
    convert a bytearray of measures on the three axes xyz in three lists where the acceleration is in units of
        gravity on the sealevel (g)
    :param buf: bytearray of 2 bytes * 3 axes * nvalues
    :return: 3 lists of ints corresponding to x, y, z values of acceleration in units of g
    """
        gc.collect()
        n_act_meas = int(len(buf) / self.bytes_per_3axes)
        acc_x, acc_y, acc_z = zip(*[
            ustruct.unpack('<HHH', buf[i:i + self.bytes_per_3axes])
            for i in range(n_act_meas) if i % self.bytes_per_3axes == 0
        ])
        # negative values rule
        acc_x = [x if x <= 32767 else x - 65536 for x in acc_x]
        acc_y = [y if y <= 32767 else y - 65536 for y in acc_y]
        acc_z = [z if z <= 32767 else z - 65536 for z in acc_z]
        gc.collect()
        return acc_x, acc_y, acc_z
예제 #13
0
class Display:
    """
    This class creates the interface between the main code and
    the EPaper display on the ESPaper from Thingpulse.

    Display model: GooDisplay 2.9 inch e-paper display GDEH029A1

    The pins on this module are fixed as shown below, since the
    display is attached to the ESP8266 through the ESPaper board.

    Pinout:
      | NAME  | PIN     | DESCRIPTION                                      |
      | DC    | 5       | LOW will write COMMANDS, HIGH will write DATA    |
      | RESET | 2       | LOW will enable the RESET                        |
      | CS    | 14      | LOW will enable comminucation to the Display     |
      | BUSY  | 4       | is HIGH when Display is busy, LOW when IDLE      |
      | SPI   | default | 4-wire communication using the SPI1 from ESP8266 |

    Args:
      portrait (bool): Set the (0, 0) position on the top-right corner.
      fast (bool): Set the display for partial / fast refresh.
    """
    def __init__(self, portrait=False, fast=False):
        # Screen size (x, y)
        self.portrait = portrait
        if self.portrait:
            self.size = (128, 296)
        else:
            self.size = (296, 128)

        # Image size, pre-alocation and lookup table
        self.n_bytes = self.size[0] * self.size[1] // 8
        self.blank_image()
        if fast:
            self.lut = (b'\x10\x18\x18\x08\x18\x18'
                        b'\x08\x00\x00\x00\x00\x00'
                        b'\x00\x00\x00\x00\x00\x00'
                        b'\x00\x00\x13\x14\x44\x12'
                        b'\x00\x00\x00\x00\x00\x00')
        else:
            self.lut = (b'\x50\xaa\x55\xaa\x11\x00'
                        b'\x00\x00\x00\x00\x00\x00'
                        b'\x00\x00\x00\x00\x00\x00'
                        b'\x00\x00\xff\xff\x1f\x00'
                        b'\x00\x00\x00\x00\x00\x00')

        # Pins definition
        self.dc = Pin(5, Pin.OUT)
        self.rst = Pin(2, Pin.OUT)
        self.cs = Pin(15, Pin.OUT)
        self.busy = Pin(4, Pin.IN)

        # SPI definition
        self.spi = SPI(1, baudrate=4000000, polarity=0, phase=0)

        # Display first cycle
        self.dc.on()
        self.cs.on()
        self.rst.on()
        self.reset()
        self.init()

    def reset(self):
        """Display reset cycle."""
        self.rst.off()
        sleep_ms(10)
        self.rst.on()
        sleep_ms(10)

    def blank_image(self, black=False):
        """
        Set a blank image with the desired color.

        args:
          - black (bool): black image when True, white image when False
        """
        self.image = bytearray()
        if black:
            self.image = bytearray(b'\x00' * self.n_bytes)
        else:
            self.image = bytearray(b'\xff' * self.n_bytes)

    def wait_until_idle(self):
        """Display idle check to avoid sending commands when busy."""
        while self.busy.value() == 1:
            sleep_ms(10)

    def write_cmd(self, cmd):
        """
        Prepare the display then send the command to it.

        args:
          - cmd (bytearray): command to be sent to the display.
        """
        self.wait_until_idle()
        self.cs.off()
        self.dc.off()
        self.spi.write(cmd)
        self.cs.on()

    def write_data(self, data):
        """
        Prepare the display then send the data to it.

        args:
          - data (bytearray): data to be sent to the display.
        """
        self.wait_until_idle()
        self.cs.off()
        self.dc.on()
        self.spi.write(data)
        self.cs.on()

    def set_memory_area(self):
        """
        Set the position to write in the RAM.
        """
        # Set RAM-X Address Start-End Position
        self.write_cmd(b'\x44')
        if self.portrait:
            self.write_data(b'\x00\x0f')
        else:
            self.write_data(b'\x0f\x00')
        # Set RAM-Y Address Start-End Position
        self.write_cmd(b'\x45')
        if self.portrait:
            self.write_data(b'\x00\x00\x27\x01')
        else:
            self.write_data(b'\x27\x01\x00\x00')

    def set_memory_pointer(self):
        """
        Set the memory pointer position to write to the RAM.
        """
        # Set RAM-X Address count
        self.write_cmd(b'\x4e')
        if self.portrait:
            self.write_data(b'\x00')
        else:
            self.write_data(b'\x0f')
        # Set RAM-Y Address count
        self.write_cmd(b'\x4f')
        if self.portrait:
            self.write_data(b'\x00\x00')
        else:
            self.write_data(b'\x27\x01')

    def init(self):
        """
        Prepare the display for normal operation.

        The basic sequence of commands is found on the
        datasheet of the display.
        """
        # Driver Output Control
        self.write_cmd(b'\x01')
        self.write_data(b'\x27\x01\x00')
        # Booster soft start
        self.write_cmd(b'\x0C')
        self.write_data(b'\xd7\xd6\x9d')
        # VCOM Voltage
        self.write_cmd(b'\x2c')
        self.write_data(b'\xa8')
        # Dummy Line
        self.write_cmd(b'\x3a')
        self.write_data(b'\x1a')
        # Gate Time
        self.write_cmd('\x3b')
        self.write_data('\x08')
        # Data Entry Mode
        self.write_cmd(b'\x11')
        if self.portrait:
            self.write_data(b'\x03')
        else:
            self.write_data(b'\x04')
        # Write LUT (LookUpTable)
        self.write_cmd(b'\x32')
        self.write_data(self.lut)
        # Border Wave Form
        # self.write_cmd(b'\x3c')
        # self.write_data(b'\x33')

    def write_image(self):
        """
        Write the image to the Display RAM.

        Send the command to write data to RAM then send
        the IMAGE to it.
        """
        self.set_memory_area()
        self.set_memory_pointer()
        self.write_cmd(b'\x24')
        self.write_data(self.image)

    def update(self):
        """
        Show the image from RAM on the display.

        Send the command to update the display then send
        the command to activate it.
        """
        self.write_cmd(b'\x22')
        self.write_data(b'\xc4')
        self.write_cmd(b'\x20')
        self.write_cmd(b'\xff')

    def full_refresh(self):
        """
        Implementation of a full refresh to be used in fast mode.

        Will set the image to a black screen, wait for 300ms,
        then set it again to white screen, clearing the ghost effect.
        """
        self.blank_image(True)
        self.write_image()
        self.update()
        sleep_ms(300)
        self.blank_image()
        self.write_image()
        self.update()
예제 #14
0
class Screen(Canvas):
    def __init__(self,
                 sck=None,
                 mosi=None,
                 miso=None,
                 spi=None,
                 resetDisplayPin=None,
                 slaveSelectPin=None,
                 baudrate=1800000):

        self.cmdbuf = bytearray(
            33
        )  # enough for 1 header byte plus 16 graphic bytes encoded as two bytes each
        self.cmdmv = memoryview(self.cmdbuf)

        if spi is not None:
            self.spi = spi
        else:
            polarity = 0
            phase = 0
            if sck or mosi or miso:  # any pins are identified - wire up as software SPI
                if not (sck and mosi and miso):
                    raise AssertionError(
                        "All SPI pins sck, mosi and miso need to be specified")
                self.spi = SPI(-1,
                               baudrate=baudrate,
                               polarity=polarity,
                               phase=phase,
                               sck=sck,
                               mosi=mosi,
                               miso=miso)
            else:
                self.spi = SPI(1,
                               baudrate=baudrate,
                               polarity=polarity,
                               phase=phase)

        # allocate frame buffer just once, use memoryview-wrapped bytearrays for rows
        self.fbuff = [
            memoryview(bytearray(colBound)) for rowPos in range(rowBound)
        ]

        self.resetDisplayPin = resetDisplayPin
        if self.resetDisplayPin is not None:
            self.resetDisplayPin.init(mode=Pin.OUT)

        self.slaveSelectPin = slaveSelectPin
        if self.slaveSelectPin is not None:
            self.slaveSelectPin.init(mode=Pin.OUT)

        self.set_rotation(0)  # rotate to 0 degrees

        self.config()

    def config(self):
        self.reset()

        self.select(True)

        self.send_flag(0x30)  # basic instruction set
        self.send_flag(0x30)  # repeated
        self.send_flag(0x0C)  # display on

        self.send_flag(0x34)  # enable RE mode
        self.send_flag(0x34)
        self.send_flag(0x36)  # enable graphics display

        self.select(False)

    # slave select surprisingly? is active high +V means active
    def select(self, selected):
        if self.slaveSelectPin:
            self.slaveSelectPin.value(1 if selected else 0)

    # reset logic untested
    def reset(self):
        if self.resetDisplayPin is not None:
            # pulse active low to reset screen
            self.resetDisplayPin.value(0)
            sleep(0.1)
            self.resetDisplayPin.value(1)

    def set_rotation(self, rot):
        if rot == 0 or rot == 2:
            self.width = 128
            self.height = 64
        elif rot == 1 or rot == 3:
            self.width = 64
            self.height = 128
        self.rot = rot

    def clear_bytes(self, count):
        for pos in range(count):
            self.cmdbuf[pos] = 0

    def send_flag(self, b):
        count = 3
        pos = 0
        while pos < count:
            self.cmdbuf[pos] = 0
            pos += 1
        self.cmdbuf[0] = 0b11111000  # rs = 0
        self.cmdbuf[1] = b & 0xF0
        self.cmdbuf[2] = (b & 0x0F) << 4
        submv = self.cmdmv[:count]
        self.spi.write(submv)
        del submv

    def send_address(self, b1, b2):
        count = 5
        pos = 0
        while pos < count:
            self.cmdbuf[pos] = 0
            pos += 1
        self.cmdbuf[0] = 0b11111000  # rs = 0
        self.cmdbuf[1] = b1 & 0xF0
        self.cmdbuf[2] = (b1 & 0x0F) << 4
        self.cmdbuf[3] = b2 & 0xF0
        self.cmdbuf[4] = (b2 & 0x0F) << 4
        submv = self.cmdmv[:count]
        self.spi.write(submv)
        del submv

    def send_data(self, arr):
        arrlen = len(arr)
        count = 1 + (arrlen << 1)
        pos = 0
        while pos < count:
            self.cmdbuf[pos] = 0
            pos += 1
        self.cmdbuf[0] = 0b11111000 | 0x02  # rs = 1
        pos = 0
        while pos < arrlen:  # inlined code from marshal_byte
            self.cmdbuf[1 + (pos << 1)] = arr[pos] & 0xF0
            self.cmdbuf[2 + (pos << 1)] = (arr[pos] & 0x0F) << 4
            pos += 1
        submv = self.cmdmv[:count]
        self.spi.write(submv)
        del submv

    def clear(self):
        rowPos = 0
        while rowPos < rowBound:
            row = self.fbuff[rowPos]
            colPos = 0
            while colPos < colBound:
                row[colPos] = 0
                colPos += 1
            rowPos += 1

    def create_plotter(self, write=True):
        if write:
            if self.rot == 0:

                def plot(x, y):
                    self.fbuff[y][x // 8] |= 1 << (7 - (x % 8))
            elif self.rot == 1:

                def plot(x, y):
                    self.fbuff[x][15 - (y // 8)] |= 1 << (y % 8)
            elif self.rot == 2:

                def plot(x, y):
                    self.fbuff[63 - y][15 - (x // 8)] |= 1 << (x % 8)
            elif self.rot == 3:

                def plot(x, y):
                    self.fbuff[63 - x][y // 8] |= 1 << (7 - (y % 8))
        else:
            if self.rot == 0:

                def plot(x, y):
                    self.fbuff[y][x // 8] &= ~(1 << (7 - (x % 8)))
            elif self.rot == 1:

                def plot(x, y):
                    self.fbuff[x][15 - (y // 8)] &= ~(1 << (y % 8))
            elif self.rot == 2:

                def plot(x, y):
                    self.fbuff[63 - y][15 - (x // 8)] &= ~(1 << (x % 8))
            elif self.rot == 3:

                def plot(x, y):
                    self.fbuff[63 - x][y // 8] &= ~(1 << (7 - (y % 8)))

        return plot

    def redraw(self, dx1=None, dy1=None, dx2=None, dy2=None):
        """
        # TODO CH bug here? (inherited from https://github.com/JMW95/pyST7920 ) buffer address ranges calculated incorrect for (bottom-right?) rectangles
        # TODO CH HACK uncomment 4 lines below for redraw rectangle to be ignored
        dx1 = 0
        dy1 = 0
        dx2 = 127
        dy2 = 63
        """
        # TODO CH consider more efficient bounds checking
        if dx1 is None:
            dx1 = 0
        else:
            dx1 = max(0, dx1)
            dx1 = min(127, dx1)
        if dx2 is None:
            dx2 = 127
        else:
            dx2 = max(0, dx2)
            dx2 = min(127, dx2)
        if dy1 is None:
            dy1 = 0
        else:
            dy1 = max(0, dy1)
            dy1 = min(63, dy1)
        if dy2 is None:
            dy2 = 63
        else:
            dy2 = max(0, dy2)
            dy2 = min(63, dy2)
        try:
            self.select(True)
            i = dy1
            while i < dy2 + 1:
                self.send_address(0x80 + i % 32,
                                  0x80 + ((dx1 // 16) + (8 if i >= 32 else 0)))
                self.send_data(self.fbuff[i][dx1 // 16:(dx2 // 8) + 1])
                i += 1
        finally:
            self.select(False)
예제 #15
0
class WS2812:
    """
    Driver for WS2812 RGB LEDs. May be used for controlling single LED or chain
    of LEDs.

    Example of use:

        chain = WS2812(ledNumber=4)
        data = [
            (255, 0, 0),    # red
            (0, 255, 0),    # green
            (0, 0, 255),    # blue
            (85, 85, 85),   # white
        ]
        chain.show(data)

    Version: 1.0
    """
    # Values to put inside SPi register for each color's bit
    buf_bytes = (0xE0E0, 0xFCE0, 0xE0FC, 0xFCFC)

    def __init__(self, ledNumber=1, brightness=100, dataPin='P22'):
        """
        Params:
        * ledNumber = count of LEDs
        * brightness = light brightness (integer : 0 to 100%)
        * dataPin = pin to connect data channel (LoPy only)
        """
        self.ledNumber = ledNumber
        self.brightness = brightness

        # Prepare SPI data buffer (8 bytes for each color)
        self.buf_length = self.ledNumber * 3 * 8
        self.buf = bytearray(self.buf_length)

        # SPI init
        # Bus 0, 8MHz => 125 ns by bit, 8 clock cycle when bit transfert+2 clock cycle between each transfert
        # => 125*10=1.25 us required by WS2812
        if uname().sysname == 'LoPy':
            self.spi = SPI(0, SPI.MASTER, baudrate=8000000, polarity=0, phase=1, pins=(None, dataPin, None))
             # Enable pull down
	    Pin(dataPin, mode=Pin.OUT, pull=Pin.PULL_DOWN)
	else: #WiPy
            self.spi = SPI(0, SPI.MASTER, baudrate=8000000, polarity=0, phase=1)
            # Enable pull down
            Pin('GP16', mode=Pin.ALT, pull=Pin.PULL_DOWN)
        
        # Turn LEDs off
        self.show([])

    def show(self, data):
        """
        Show RGB data on LEDs. Expected data = [(R, G, B), ...] where R, G and B
        are intensities of colors in range from 0 to 255. One RGB tuple for each
        LED. Count of tuples may be less than count of connected LEDs.
        """
        self.fill_buf(data)
        self.send_buf()

    def send_buf(self):
        """
        Send buffer over SPI.
        """
        disable_irq()
        self.spi.write(self.buf)
        enable_irq()
        gc.collect()

    def update_buf(self, data, start=0):
        """
        Fill a part of the buffer with RGB data.

        Order of colors in buffer is changed from RGB to GRB because WS2812 LED
        has GRB order of colors. Each color is represented by 4 bytes in buffer
        (1 byte for each 2 bits).

        Returns the index of the first unfilled LED

        Note: If you find this function ugly, it's because speed optimisations
        beated purity of code.
        """

        buf = self.buf
        buf_bytes = self.buf_bytes
        brightness = self.brightness

        index = start * 24
        for red, green, blue in data:
            red = int(red * brightness // 100)
            green = int(green * brightness // 100)
            blue = int(blue * brightness // 100)

            buf[index] = buf_bytes[green >> 6 & 0x03]
            buf[index+2] = buf_bytes[green >> 4 & 0x03]
            buf[index+4] = buf_bytes[green >> 2 & 0x03]
            buf[index+6] = buf_bytes[green & 0x03]

            buf[index+8] = buf_bytes[red >> 6 & 0x03]
            buf[index+10] = buf_bytes[red >> 4 & 0x03]
            buf[index+12] = buf_bytes[red >> 2 & 0x03]
            buf[index+14] = buf_bytes[red & 0x03]

            buf[index+16] = buf_bytes[blue >> 6 & 0x03]
            buf[index+18] = buf_bytes[blue >> 4 & 0x03]
            buf[index+20] = buf_bytes[blue >> 2 & 0x03]
            buf[index+22] = buf_bytes[blue & 0x03]

            index += 24

        return index // 24

    def fill_buf(self, data):
        """
        Fill buffer with RGB data.

        All LEDs after the data are turned off.
        """
        end = self.update_buf(data)

        # Turn off the rest of the LEDs
        buf = self.buf
        off = self.buf_bytes[0]
        for index in range(end * 24, self.buf_length):
            buf[index] = off
            index += 2
            
    def set_brightness(self, brightness):
        """
        Set brighness of all leds
        """
        self.brightness = brightness
예제 #16
0
class MFRC522:
  RESET = 'GP22'
  CLK = 'GP14'
  MISO = 'GP15'
  MOSI = 'GP16'
  CS = 'GP17'

  MAX_LEN = 16
  
  PCD_IDLE       = 0x00
  PCD_AUTHENT    = 0x0E
  PCD_TRANSCEIVE = 0x0C
  PCD_RESETPHASE = 0x0F
  PCD_CALCCRC    = 0x03

  PICC_REQIDL    = 0x26
  PICC_REQALL    = 0x52
  PICC_ANTICOLL  = 0x93
  PICC_SElECTTAG = 0x93
  PICC_AUTHENT1A = 0x60
  PICC_READ      = 0x30
  PICC_WRITE     = 0xA0
  
  MI_OK       = 0
  MI_NOTAGERR = 1
  MI_ERR      = 2
  MI_AUTH_ERROR_STATUS2REG = 3

  CommandReg     = 0x01
  CommIEnReg     = 0x02
  CommIrqReg     = 0x04
  DivIrqReg      = 0x05
  ErrorReg       = 0x06
  Status2Reg     = 0x08
  FIFODataReg    = 0x09
  FIFOLevelReg   = 0x0A
  WaterLevelReg  = 0x0B
  ControlReg     = 0x0C
  BitFramingReg  = 0x0D
  
  ModeReg        = 0x11
  TxControlReg   = 0x14
  TxAutoReg      = 0x15
  
  CRCResultRegM     = 0x21
  CRCResultRegL     = 0x22
  TModeReg          = 0x2A
  TPrescalerReg     = 0x2B
  TReloadRegH       = 0x2C
  TReloadRegL       = 0x2D
    
  serNum = []

  def __init__(self, spd=1000000):
    # first assign CLK, MISO, MOSI, CS to the correct pins
    self.pin_clk = Pin(self.CLK, mode=Pin.OUT)    # CLK
    self.pin_miso = Pin(self.MISO)    # MISO
    self.pin_mosi = Pin(self.MOSI, mode=Pin.OUT)    # MOSI
    self.pin_cs = Pin(self.CS, mode=Pin.OUT)    # NSS/CS
    self.pin_reset = Pin(self.RESET, mode=Pin.OUT)

    self.pin_reset.value(0)
    self.pin_cs.value(1)

    self.spi = SPI(0)
    self.spi.init(mode=SPI.MASTER, baudrate=spd, pins=(self.CLK, self.MOSI, self.MISO))
    
    self.pin_reset.value(1)

    self.MFRC522_Init()
  
  def MFRC522_Reset(self):
    self.Write_MFRC522(self.CommandReg, self.PCD_RESETPHASE)
  
  def Write_MFRC522(self, addr, val):
    self.pin_cs.value(0)
    # 0(MSB = Write) ADDR1 ADDR2 ADDR3 ADDR4 ADDR5 ADDR6 0(LSB = 0) DATA
    spiBytes = bytearray(2)
    spiBytes[0] = ((addr<<1)&0x7E) 
    spiBytes[1] = val
    self.spi.write(spiBytes)
    self.pin_cs.value(1)
  
  def Read_MFRC522(self, addr):
    self.pin_cs.value(0)
    # 1(MSB = Read) ADDR1 ADDR2 ADDR3 ADDR4 ADDR5 ADDR6 0(LSB = 0)
    self.spi.write((addr<<1)&0x7E|0x80)
    data = self.spi.read(1)
    self.pin_cs.value(1)
    return data[0]
  
  def SetBitMask(self, reg, mask):
    tmp = self.Read_MFRC522(reg)
    self.Write_MFRC522(reg, tmp | mask)
    
  def ClearBitMask(self, reg, mask):
    tmp = self.Read_MFRC522(reg);
    self.Write_MFRC522(reg, tmp & (~mask))
  
  def AntennaOn(self):
    temp = self.Read_MFRC522(self.TxControlReg)
    if(~(temp & 0x03)):
      self.SetBitMask(self.TxControlReg, 0x03)

  
  def AntennaOff(self):
    self.ClearBitMask(self.TxControlReg, 0x03)
  
  def MFRC522_ToCard(self,command,sendData):
    backData = []
    backLen = 0
    status = self.MI_ERR
    irqEn = 0x00
    waitIRq = 0x00
    lastBits = None
    n = 0
    i = 0
    
    if command == self.PCD_AUTHENT:
      irqEn = 0x12
      waitIRq = 0x10
    if command == self.PCD_TRANSCEIVE:
      irqEn = 0x77
      waitIRq = 0x30

    self.Write_MFRC522(self.CommIEnReg, irqEn|0x80)
    self.ClearBitMask(self.CommIrqReg, 0x80)
    self.SetBitMask(self.FIFOLevelReg, 0x80)
    self.Write_MFRC522(self.CommandReg, self.PCD_IDLE);  

    while(i<len(sendData)):
      self.Write_MFRC522(self.FIFODataReg, sendData[i])
      i = i+1
    self.Write_MFRC522(self.CommandReg, command)

    if command == self.PCD_TRANSCEIVE:
      self.SetBitMask(self.BitFramingReg, 0x80)
    
    i = 2000
    while True:
      n = self.Read_MFRC522(self.CommIrqReg)
      i = i - 1
      if ~((i!=0) and ~(n&0x01) and ~(n&waitIRq)):
        break
    
    self.ClearBitMask(self.BitFramingReg, 0x80)
  
    if i != 0:
      st = self.Read_MFRC522(self.ErrorReg)
      if (st & 0x1B)==0x00:
        status = self.MI_OK

        if n & irqEn & 0x01:
          status = self.MI_NOTAGERR
        elif command == self.PCD_TRANSCEIVE:
          n = self.Read_MFRC522(self.FIFOLevelReg)
          lastBits = self.Read_MFRC522(self.ControlReg) & 0x07
          if lastBits != 0:
            backLen = (n-1)*8 + lastBits
          else:
            backLen = n*8
          
          if n == 0:
            n = 1
          if n > self.MAX_LEN:
            n = self.MAX_LEN
    
          i = 0
          while i<n:
            backData.append(self.Read_MFRC522(self.FIFODataReg))
            i = i + 1;
      else:
        status = self.MI_ERR
    return (status,backData,backLen)
  
  
  def MFRC522_Request(self, reqMode):
    status = None
    backBits = None
    TagType = [reqMode]

    self.Write_MFRC522(self.BitFramingReg, 0x07)

    (status,backData,backBits) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, TagType)
    if ((status != self.MI_OK) | (backBits != 0x10)):
      status = self.MI_ERR
      
    return (status,backBits)
  
  
  def MFRC522_Anticoll(self):
    backData = []
    serNumCheck = 0
    
    serNum = [self.PICC_ANTICOLL, 0x20]
  
    self.Write_MFRC522(self.BitFramingReg, 0x00)
    
    (status,backData,backBits) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE,serNum)
    
    if(status == self.MI_OK):
      i = 0
      if len(backData)==5:
        while i<4:
          serNumCheck = serNumCheck ^ backData[i]
          i = i + 1
        if serNumCheck != backData[i]:
          status = self.MI_ERR
      else:
        status = self.MI_ERR
  
    return (status,backData)
  
  def CalulateCRC(self, pIndata):
    self.ClearBitMask(self.DivIrqReg, 0x04)
    self.SetBitMask(self.FIFOLevelReg, 0x80);
    i = 0
    while i<len(pIndata):
      self.Write_MFRC522(self.FIFODataReg, pIndata[i])
      i = i + 1
    self.Write_MFRC522(self.CommandReg, self.PCD_CALCCRC)
    i = 0xFF
    while True:
      n = self.Read_MFRC522(self.DivIrqReg)
      i = i - 1
      if not ((i != 0) and not (n&0x04)):
        break
    pOutData = []
    pOutData.append(self.Read_MFRC522(self.CRCResultRegL))
    pOutData.append(self.Read_MFRC522(self.CRCResultRegM))
    return pOutData
  
  def MFRC522_SelectTag(self, serNum):
    backData = []
    buf = [self.PICC_SElECTTAG, 0x70] + serNum[:5]

    buf += self.CalulateCRC(buf)
    (status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buf)
    
    if (status == self.MI_OK) and (backLen == 0x18):
      return self.MI_OK
    else:
      return self.MI_ERR
  
  def MFRC522_Auth(self, authMode, BlockAddr, Sectorkey, serNum):
    #First byte should be the authMode (A or B)
    #Second byte is the trailerBlock (usually 7)
    #Now we need to append the authKey which usually is 6 bytes of 0xFF
    #Next we append the first 4 bytes of the UID
    buff = [authMode, BlockAddr] + Sectorkey + serNum[:4]

    # Now we start the authentication itself
    (status, backData, backLen) = self.MFRC522_ToCard(self.PCD_AUTHENT,buff)

    # Check if an error occurred


    # Return the status
    return status
  
  def MFRC522_StopCrypto1(self):
    self.ClearBitMask(self.Status2Reg, 0x08)

  def MFRC522_Read(self, blockAddr):
    recvData = [self.PICC_READ, blockAddr]
    recvData += self.CalulateCRC(recvData)

    (status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, recvData)
    return (status, backData)
  
  def MFRC522_Write(self, blockAddr, writeData):
    buff = [self.PICC_WRITE, blockAddr]
    buff += self.CalulateCRC(buff)
    (status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buff)
    if not(status == self.MI_OK) or not(backLen == 4) or not((backData[0] & 0x0F) == 0x0A):
        status = self.MI_ERR
    
    if status == self.MI_OK:
        i = 0
        buf = []
        while i < 16:
            buf.append(writeData[i])
            i = i + 1
        buf += self.CalulateCRC(buf)
        (status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE,buf)
        if not(status == self.MI_OK) or not(backLen == 4) or not((backData[0] & 0x0F) == 0x0A):
            status = self.MI_ERR

    return status

  def MFRC522_Init(self):
    self.MFRC522_Reset();
    
    self.Write_MFRC522(self.TModeReg, 0x8D)
    self.Write_MFRC522(self.TPrescalerReg, 0x3E)
    self.Write_MFRC522(self.TReloadRegL, 30)
    self.Write_MFRC522(self.TReloadRegH, 0)
    self.Write_MFRC522(self.TxAutoReg, 0x40)
    self.Write_MFRC522(self.ModeReg, 0x3D)
    self.AntennaOn()
예제 #17
0
class LCD_1inch14(framebuf.FrameBuffer):
    def __init__(self):
        self.width = 240
        self.height = 135
        
        self.cs = Pin(CS,Pin.OUT)
        self.rst = Pin(RST,Pin.OUT)
        
        self.cs(1)
        self.spi = SPI(1)
        self.spi = SPI(1,1000_000)
        self.spi = SPI(1,10000_000,polarity=0, phase=0,sck=Pin(SCK),mosi=Pin(MOSI),miso=None)
        self.dc = Pin(DC,Pin.OUT)
        self.dc(1)
        self.buffer = bytearray(self.height * self.width * 2)
        super().__init__(self.buffer, self.width, self.height, framebuf.RGB565)
        self.init_display()
        
        self.red   =   0x07E0
        self.green =   0x001f
        self.blue  =   0xf800
        self.white =   0xffff
        self.black =   0x0000
        
    def write_cmd(self, cmd):
        self.cs(1)
        self.dc(0)
        self.cs(0)
        self.spi.write(bytearray([cmd]))
        self.cs(1)

    def write_data(self, buf):
        self.cs(1)
        self.dc(1)
        self.cs(0)
        self.spi.write(bytearray([buf]))
        self.cs(1)

    def init_display(self):
        """Initialize dispaly"""  
        self.rst(1)
        self.rst(0)
        self.rst(1)
        
        self.write_cmd(0x36)
        self.write_data(0x70)

        self.write_cmd(0x3A) 
        self.write_data(0x05)

        self.write_cmd(0xB2)
        self.write_data(0x0C)
        self.write_data(0x0C)
        self.write_data(0x00)
        self.write_data(0x33)
        self.write_data(0x33)

        self.write_cmd(0xB7)
        self.write_data(0x35) 

        self.write_cmd(0xBB)
        self.write_data(0x19)

        self.write_cmd(0xC0)
        self.write_data(0x2C)

        self.write_cmd(0xC2)
        self.write_data(0x01)

        self.write_cmd(0xC3)
        self.write_data(0x12)   

        self.write_cmd(0xC4)
        self.write_data(0x20)

        self.write_cmd(0xC6)
        self.write_data(0x0F) 

        self.write_cmd(0xD0)
        self.write_data(0xA4)
        self.write_data(0xA1)

        self.write_cmd(0xE0)
        self.write_data(0xD0)
        self.write_data(0x04)
        self.write_data(0x0D)
        self.write_data(0x11)
        self.write_data(0x13)
        self.write_data(0x2B)
        self.write_data(0x3F)
        self.write_data(0x54)
        self.write_data(0x4C)
        self.write_data(0x18)
        self.write_data(0x0D)
        self.write_data(0x0B)
        self.write_data(0x1F)
        self.write_data(0x23)

        self.write_cmd(0xE1)
        self.write_data(0xD0)
        self.write_data(0x04)
        self.write_data(0x0C)
        self.write_data(0x11)
        self.write_data(0x13)
        self.write_data(0x2C)
        self.write_data(0x3F)
        self.write_data(0x44)
        self.write_data(0x51)
        self.write_data(0x2F)
        self.write_data(0x1F)
        self.write_data(0x1F)
        self.write_data(0x20)
        self.write_data(0x23)
        
        self.write_cmd(0x21)

        self.write_cmd(0x11)

        self.write_cmd(0x29)

    def show(self):
        self.write_cmd(0x2A)
        self.write_data(0x00)
        self.write_data(0x28)
        self.write_data(0x01)
        self.write_data(0x17)
        
        self.write_cmd(0x2B)
        self.write_data(0x00)
        self.write_data(0x35)
        self.write_data(0x00)
        self.write_data(0xBB)
        
        self.write_cmd(0x2C)
        
        self.cs(1)
        self.dc(1)
        self.cs(0)
        self.spi.write(self.buffer)
        self.cs(1)
예제 #18
0
class ILI9341:
    def __init__(self, width, height):
        self.width = width
        self.height = height
        self.pages = self.height // 8
        self.buffer = bytearray(self.pages * self.width)
        self.framebuf = framebuf.FrameBuffer(self.buffer, self.width, self.height, framebuf.MONO_VLSB)

        self.spi = SPI(0)
        # chip select
        self.cs = Pin("P16", mode=Pin.OUT, pull=Pin.PULL_UP)
        # command
        self.dc = Pin("P17", mode=Pin.OUT, pull=Pin.PULL_UP)
        
        # initialize all pins high
        self.cs.high()
        self.dc.high()

        self.spi.init(baudrate=8000000, phase=0, polarity=0)

        self.init_display()
        

    def init_display(self):
        time.sleep_ms(500)
        
        self.write_cmd(0x01)
        
        time.sleep_ms(200)
    
        self.write_cmd(0xCF)
        self.write_data(bytearray([0x00, 0x8B, 0x30]))
    
        self.write_cmd(0xED)
        self.write_data(bytearray([0x67, 0x03, 0x12, 0x81]))

        self.write_cmd(0xE8)
        self.write_data(bytearray([0x85, 0x10, 0x7A]))
    
        self.write_cmd(0xCB)
        self.write_data(bytearray([0x39, 0x2C, 0x00, 0x34, 0x02]))
    
        self.write_cmd(0xF7)
        self.write_data(bytearray([0x20]))

        self.write_cmd(0xEA)
        self.write_data(bytearray([0x00, 0x00]))

        # Power control
        self.write_cmd(0xC0)
        # VRH[5:0]
        self.write_data(bytearray([0x1B]))
        
        # Power control
        self.write_cmd(0xC1)
        # SAP[2:0];BT[3:0]
        self.write_data(bytearray([0x10]))
        
        # VCM control
        self.write_cmd(0xC5)
        self.write_data(bytearray([0x3F, 0x3C]))
    
        # VCM control2
        self.write_cmd(0xC7)
        self.write_data(bytearray([0xB7]))
    
        # Memory Access Control
        self.write_cmd(0x36)
        self.write_data(bytearray([0x08]))
    
        self.write_cmd(0x3A)
        self.write_data(bytearray([0x55]))
    
        self.write_cmd(0xB1)
        self.write_data(bytearray([0x00, 0x1B]))
        
        # Display Function Control
        self.write_cmd(0xB6)
        self.write_data(bytearray([0x0A, 0xA2]))
    
        # 3Gamma Function Disable
        self.write_cmd(0xF2)
        self.write_data(bytearray([0x00]))
        
        # Gamma curve selected
        self.write_cmd(0x26)
        self.write_data(bytearray([0x01]))
    
        # Set Gamma
        self.write_cmd(0xE0)
        self.write_data(bytearray([0x0F, 0x2A, 0x28, 0x08, 0x0E, 0x08, 0x54, 0XA9, 0x43, 0x0A, 0x0F, 0x00, 0x00, 0x00, 0x00]))
    
        # Set Gamma
        self.write_cmd(0XE1)
        self.write_data(bytearray([0x00, 0x15, 0x17, 0x07, 0x11, 0x06, 0x2B, 0x56, 0x3C, 0x05, 0x10, 0x0F, 0x3F, 0x3F, 0x0F]))
        
        # Exit Sleep
        self.write_cmd(0x11)
        time.sleep_ms(120)
        
        # Display on
        self.write_cmd(0x29)
        time.sleep_ms(500)
        self.fill(0)

    def show(self):
        # set col
        self.write_cmd(0x2A)
        self.write_data(bytearray([0x00, 0x00]))
        self.write_data(bytearray([0x00, 0xef]))
        
        # set page 
        self.write_cmd(0x2B)
        self.write_data(bytearray([0x00, 0x00]))
        self.write_data(bytearray([0x01, 0x3f]))

        self.write_cmd(0x2c);

        num_of_pixels = self.height * self.width

        for row in range(0, self.pages):
            for pixel_pos in range(0, 8):
                for col in range(0, self.width):
                    compressed_pixel = self.buffer[row * 240 + col]
                    if ((compressed_pixel >> pixel_pos) & 0x1) == 0:
                        self.write_data(bytearray([0x00, 0x00]))
                    else:
                        self.write_data(bytearray([0xFF, 0xFF]))

    def fill(self, col):
        self.framebuf.fill(col)

    def pixel(self, x, y, col):
        self.framebuf.pixel(x, y, col)

    def scroll(self, dx, dy):
        self.framebuf.scroll(dx, dy)

    def text(self, string, x, y, col=1):
        self.framebuf.text(string, x, y, col)

    def write_cmd(self, cmd):
        self.dc.low()
        self.cs.low()
        self.spi.write(bytearray([cmd]))
        self.cs.high()
        
    def write_data(self, buf):
        self.dc.high()
        self.cs.low()
        self.spi.write(buf)
        self.cs.high()
예제 #19
0
class EPD(framebuf.FrameBuffer):
    def __init__(self, width, height):

        self.spi = SPI(1,
                       baudrate=20000000,
                       polarity=0,
                       phase=0,
                       sck=Pin(18),
                       mosi=Pin(23),
                       miso=Pin(19))
        #self.spi = SPI(1, 10000000, sck=Pin(14), mosi=Pin(13), miso=Pin(12))
        self.spi.init()
        dc = Pin(27)
        cs = Pin(5)
        rst = Pin(14)
        busy = Pin(4)

        self.cs = cs
        self.dc = dc
        self.rst = rst
        self.busy = busy
        self.cs.init(self.cs.OUT, value=1)
        self.dc.init(self.dc.OUT, value=0)
        self.rst.init(self.rst.OUT, value=0)
        self.busy.init(self.busy.IN)
        self.width = width
        self.height = height
        self.pages = self.height // 8
        self.buffer = bytearray(self.pages * self.width)
        super().__init__(self.buffer, self.width, self.height,
                         framebuf.MONO_VLSB)
        self.init_display()

    def init_display(self):
        #Reset EPD Driver IC
        self.reset()

        #Booster soft start
        self._command(BOOSTER_SOFT_START_CONTROL, b'\x17\x17\x17')

        #Power setting
        self._command(POWER_SETTING, b'\x03\x00\x2B\x2B\x09')

        #Power on
        self._command(POWER_ON)

        #Check busy pin and proceed if idle
        self.wait_until_idle()

        #Panel setting - B&W and full resolution
        self._command(PANEL_SETTING, b'\x1F')

        #PLL control - Set to 100Hz, default is 50Hz
        self._command(PLL_CONTROL, b'\x3A')

        #Resolution setting
        self._command(RES_SETTING, b'\x01\x90\x01\x2C')

        #VCM_DC setting - Currently set to -1V, default is -0.1V i.e. b'\x00'
        self._command(VCM_DC_SETTING, b'\x12')

        #VCOM and Data Interval setting
        self._command(VCOM_DATA_INT_SETTING, b'\x87')

        #Finish initialisation with refresh of a blank screen
        self.fill(0)
        self.show()

    def poweroff(self):
        self._command(POWER_OFF)

    def poweron(self):
        self._command(POWER_ON)

    def show(self):
        self._command(START_TRANSMISSION_2)
        self._data(self.buffer)
        self._command(DATA_STOP)
        self._command(DISP_REFRESH)
        self.wait_until_idle()

    # To display your own buffer, instead of the framebuf buffer
    def show_buffer(self, buf):
        self.wait_until_idle()
        self._command(START_TRANSMISSION_2)
        for i in range(0, len(buf)):
            self._data(bytearray([buf[i]]))
        self._command(DATA_STOP)
        self._command(DISP_REFRESH)
        self.wait_until_idle()

    def _command(self, command, data=None):
        self.cs(1)  # according to LOLIN_EPD
        self.dc(0)
        self.cs(0)
        self.spi.write(bytearray([command]))
        self.cs(1)
        if data is not None:
            self._data(data)

    def _data(self, data):
        self.cs(1)  # according to LOLIN_EPD
        self.dc(1)
        self.cs(0)
        self.spi.write(data)
        self.cs(1)

    def wait_until_idle(self):
        while self.busy == 0:
            pass
        return

    def reset(self):
        self.rst(1)
        sleep_ms(1)

        self.rst(0)
        sleep_ms(10)

        self.rst(1)

    # to wake call reset() or init()
    def sleep(self):
        self._command(bytearray([DEEP_SLEEP_MODE]))
        self.wait_until_idle()
예제 #20
0
class MFRC522:

	OK = 0
	NOTAGERR = 1
	ERR = 2

	REQIDL = 0x26
	REQALL = 0x52
	AUTHENT1A = 0x60
	AUTHENT1B = 0x61

	def __init__(self, sck, mosi, miso, rst, cs):

		self.sck = Pin(sck, Pin.OUT)
		self.mosi = Pin(mosi, Pin.OUT)
		self.miso = Pin(miso)
		self.rst = Pin(rst, Pin.OUT)
		self.cs = Pin(cs, Pin.OUT)

		self.rst.value(0)
		self.cs.value(1)

		if uname()[0] == 'WiPy':
			self.spi = SPI(0)
			self.spi.init(SPI.MASTER, baudrate=1000000, pins=(self.sck, self.mosi, self.miso))
		elif uname()[0] == 'esp8266':
			self.spi = SPI(baudrate=100000, polarity=0, phase=0, sck=self.sck, mosi=self.mosi, miso=self.miso)
			self.spi.init()
		else:
			raise RuntimeError("Unsupported platform")

		self.rst.value(1)
		self.init()

	def _wreg(self, reg, val):

		self.cs.value(0)
		self.spi.write(b'%c' % int(0xff & ((reg << 1) & 0x7e)))
		self.spi.write(b'%c' % int(0xff & val))
		self.cs.value(1)

	def _rreg(self, reg):

		self.cs.value(0)
		self.spi.write(b'%c' % int(0xff & (((reg << 1) & 0x7e) | 0x80)))
		val = self.spi.read(1)
		self.cs.value(1)

		return val[0]

	def _sflags(self, reg, mask):
		self._wreg(reg, self._rreg(reg) | mask)

	def _cflags(self, reg, mask):
		self._wreg(reg, self._rreg(reg) & (~mask))

	def _tocard(self, cmd, send):

		recv = []
		bits = irq_en = wait_irq = n = 0
		stat = self.ERR

		if cmd == 0x0E:
			irq_en = 0x12
			wait_irq = 0x10
		elif cmd == 0x0C:
			irq_en = 0x77
			wait_irq = 0x30

		self._wreg(0x02, irq_en | 0x80)
		self._cflags(0x04, 0x80)
		self._sflags(0x0A, 0x80)
		self._wreg(0x01, 0x00)

		for c in send:
			self._wreg(0x09, c)
		self._wreg(0x01, cmd)

		if cmd == 0x0C:
			self._sflags(0x0D, 0x80)

		i = 2000
		while True:
			n = self._rreg(0x04)
			i -= 1
			if ~((i != 0) and ~(n & 0x01) and ~(n & wait_irq)):
				break

		self._cflags(0x0D, 0x80)

		if i:
			if (self._rreg(0x06) & 0x1B) == 0x00:
				stat = self.OK

				if n & irq_en & 0x01:
					stat = self.NOTAGERR
				elif cmd == 0x0C:
					n = self._rreg(0x0A)
					lbits = self._rreg(0x0C) & 0x07
					if lbits != 0:
						bits = (n - 1) * 8 + lbits
					else:
						bits = n * 8

					if n == 0:
						n = 1
					elif n > 16:
						n = 16

					for _ in range(n):
						recv.append(self._rreg(0x09))
			else:
				stat = self.ERR

		return stat, recv, bits

	def _crc(self, data):

		self._cflags(0x05, 0x04)
		self._sflags(0x0A, 0x80)

		for c in data:
			self._wreg(0x09, c)

		self._wreg(0x01, 0x03)

		i = 0xFF
		while True:
			n = self._rreg(0x05)
			i -= 1
			if not ((i != 0) and not (n & 0x04)):
				break

		return [self._rreg(0x22), self._rreg(0x21)]

	def init(self):

		self.reset()
		self._wreg(0x2A, 0x8D)
		self._wreg(0x2B, 0x3E)
		self._wreg(0x2D, 30)
		self._wreg(0x2C, 0)
		self._wreg(0x15, 0x40)
		self._wreg(0x11, 0x3D)
		self.antenna_on()

	def reset(self):
		self._wreg(0x01, 0x0F)

	def antenna_on(self, on=True):

		if on and ~(self._rreg(0x14) & 0x03):
			self._sflags(0x14, 0x03)
		else:
			self._cflags(0x14, 0x03)

	def request(self, mode):

		self._wreg(0x0D, 0x07)
		(stat, recv, bits) = self._tocard(0x0C, [mode])

		if (stat != self.OK) | (bits != 0x10):
			stat = self.ERR

		return stat, bits

	def anticoll(self):

		ser_chk = 0
		ser = [0x93, 0x20]

		self._wreg(0x0D, 0x00)
		(stat, recv, bits) = self._tocard(0x0C, ser)

		if stat == self.OK:
			if len(recv) == 5:
				for i in range(4):
					ser_chk = ser_chk ^ recv[i]
				if ser_chk != recv[4]:
					stat = self.ERR
			else:
				stat = self.ERR

		return stat, recv

	def select_tag(self, ser):

		buf = [0x93, 0x70] + ser[:5]
		buf += self._crc(buf)
		(stat, recv, bits) = self._tocard(0x0C, buf)
		return self.OK if (stat == self.OK) and (bits == 0x18) else self.ERR

	def auth(self, mode, addr, sect, ser):
		return self._tocard(0x0E, [mode, addr] + sect + ser[:4])[0]

	def stop_crypto1(self):
		self._cflags(0x08, 0x08)

	def read(self, addr):

		data = [0x30, addr]
		data += self._crc(data)
		(stat, recv, _) = self._tocard(0x0C, data)
		return recv if stat == self.OK else None

	def write(self, addr, data):

		buf = [0xA0, addr]
		buf += self._crc(buf)
		(stat, recv, bits) = self._tocard(0x0C, buf)

		if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A):
			stat = self.ERR
		else:
			buf = []
			for i in range(16):
				buf.append(data[i])
			buf += self._crc(buf)
			(stat, recv, bits) = self._tocard(0x0C, buf)
			if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A):
				stat = self.ERR

		return stat
예제 #21
0
class SevenSegment:
    def __init__(self,
                 digits=8,
                 scan_digits=MAX7219_DIGITS,
                 baudrate=SPI_BAUDRATE,
                 cs=SPI_CS):
        """
        Constructor:
        `digits` should be the total number of individual digits being displayed
        `cs` is the GPIO port to use for the chip select line of the SPI bus - defaults to GPIO 0 / D3
        `scan_digits` is the number of digits each individual max7219 displays
        `baudrate` defaults to 100KHz, note that excessive rates may result in instability (and is probably unnecessary)
        """

        self.digits = digits
        self.devices = -(-digits // scan_digits)  # ceiling integer division
        self.scan_digits = scan_digits
        self._buffer = [0] * digits
        self._spi = SPI(SPI_BUS, baudrate=baudrate, polarity=0, phase=0)
        self._cs = Pin(cs, Pin.OUT, value=1)

        self.command(MAX7219_REG_SCANLIMIT,
                     scan_digits - 1)  # digits to display on each device  0-7
        self.command(MAX7219_REG_DECODEMODE, 0)  # use segments (not digits)
        self.command(MAX7219_REG_DISPLAYTEST, 0)  # no display test
        self.command(MAX7219_REG_SHUTDOWN, 1)  # not blanking mode
        self.brightness(7)  # intensity: range: 0..15
        self.clear()

    def command(self, register, data):
        """Sets a specific register some data, replicated for all cascaded devices."""
        self._write([register, data] * self.devices)

    def _write(self, data):
        """Send the bytes (which should comprise of alternating command, data values) over the SPI device."""
        self._cs.off()
        self._spi.write(bytes(data))
        self._cs.on()

    def clear(self, flush=True):
        """Clears the buffer and if specified, flushes the display."""
        self._buffer = [0] * self.digits
        if flush:
            self.flush()

    def flush(self):
        """For each digit, cascade out the contents of the buffer cells to the SPI device."""
        for dev in range(self.devices):
            for pos in range(self.scan_digits):
                self._write([
                    pos +
                    MAX7219_REG_DIGIT0, self._buffer[pos +
                                                     (dev * self.scan_digits)]
                ] + ([MAX7219_REG_NOOP, 0] * dev))

    def brightness(self, intensity):
        """Sets the brightness level of all cascaded devices to the same intensity level, ranging from 0..15."""
        self.command(MAX7219_REG_INTENSITY, intensity)

    def letter(self, position, char, dot=False, flush=True):
        """Looks up the appropriate character representation for char and updates the buffer, flushes by default."""
        value = get_char2(char) | (dot << 7)
        self._buffer[position] = value

        if flush:
            self.flush()

    def text(self, text):
        """Outputs the text (as near as possible) on the specific device."""
        self.clear(False)
        text = text[:self.digits]  # make sure we don't overrun the buffer
        for pos, char in enumerate(text):
            self.letter(pos, char, flush=False)

        self.flush()

    def number(self, val):
        """Formats the value according to the parameters supplied, and displays it."""
        self.clear(False)
        strval = ''
        if isinstance(val, (int, float)):
            strval = str(val)
        elif isinstance(val, str):
            if val.replace('.', '', 1).strip().isdigit():
                strval = val

        if '.' in strval:
            strval = strval[:self.digits + 1]
        else:
            strval = strval[:self.digits]

        pos = 0
        for char in strval:
            dot = False
            if char == '.':
                continue
            else:
                if pos < len(strval) - 1:
                    if strval[pos + 1] == '.':
                        dot = True
                self.letter(pos, char, dot, False)
                pos += 1

        self.flush()

    def scroll(self, rotate=True, reverse=False, flush=True):
        """Shifts buffer contents left or right (reverse), with option to wrap around (rotate)."""
        if reverse:
            tmp = self._buffer.pop()
            if rotate:
                self._buffer.insert(0, tmp)
            else:
                self._buffer.insert(0, 0x00)
        else:
            tmp = self._buffer.pop(0)
            if rotate:
                self._buffer.append(tmp)
            else:
                self._buffer.append(0x00)

        if flush:
            self.flush()

    def message(self, text, delay=0.4):
        """Transitions the text message across the devices from left-to-right."""
        self.clear(False)
        for char in text:
            time.sleep(delay)
            self.scroll(rotate=False, flush=False)
            self.letter(self.digits - 1, char)