diff --git a/PSL/SENSORS/MF522.py b/PSL/SENSORS/MF522.py index f9bf1abc..f200c312 100644 --- a/PSL/SENSORS/MF522.py +++ b/PSL/SENSORS/MF522.py @@ -1 +1,512 @@ -#TODO +# -*- coding: utf-8 -*- +# MF522 - Software stack to access the MF522 RFID reader via FOSSASIA PSLab +# + + + +from __future__ import print_function +from PSL import sciencelab +import time +def connect(I,cs): + return MF522(I,cs) + +class MF522: + #Constants from https://github.com/miguelbalboa/rfid ( Open source License : UNLICENSE) + CommandReg = 0x01 << 1 # starts and stops command execution + ComIEnReg = 0x02 << 1 # enable and disable interrupt request control bits + DivIEnReg = 0x03 << 1 # enable and disable interrupt request control bits + ComIrqReg = 0x04 << 1 # interrupt request bits + DivIrqReg = 0x05 << 1 # interrupt request bits + ErrorReg = 0x06 << 1 # error bits showing the error status of the last command executed + Status1Reg = 0x07 << 1 # communication status bits + Status2Reg = 0x08 << 1 # receiver and transmitter status bits + FIFODataReg = 0x09 << 1 # input and output of 64 byte FIFO buffer + FIFOLevelReg = 0x0A << 1 # number of bytes stored in the FIFO buffer + WaterLevelReg = 0x0B << 1 # level for FIFO underflow and overflow warning + ControlReg = 0x0C << 1 # miscellaneous control registers + BitFramingReg = 0x0D << 1 # adjustments for bit-oriented frames + CollReg = 0x0E << 1 # bit position of the first bit-collision detected on the RF sciencelab + + ModeReg = 0x11 << 1 # defines general modes for transmitting and receiving + TxModeReg = 0x12 << 1 # defines transmission data rate and framing + RxModeReg = 0x13 << 1 # defines reception data rate and framing + TxControlReg = 0x14 << 1 # controls the logical behavior of the antenna driver pins TX1 and TX2 + TxASKReg = 0x15 << 1 # controls the setting of the transmission modulation + TxSelReg = 0x16 << 1 # selects the internal sources for the antenna driver + RxSelReg = 0x17 << 1 # selects internal receiver settings + RxThresholdReg = 0x18 << 1 # selects thresholds for the bit decoder + DemodReg = 0x19 << 1 # defines demodulator settings + MfTxReg = 0x1C << 1 # controls some MIFARE communication transmit parameters + MfRxReg = 0x1D << 1 # controls some MIFARE communication receive parameters + SerialSpeedReg = 0x1F << 1 # selects the speed of the serial UART sciencelab + + CRCResultRegH = 0x21 << 1 # shows the MSB and LSB values of the CRC calculation + CRCResultRegL = 0x22 << 1 + ModWidthReg = 0x24 << 1 # controls the ModWidth setting? + RFCfgReg = 0x26 << 1 # configures the receiver gain + GsNReg = 0x27 << 1 # selects the conductance of the antenna driver pins TX1 and TX2 for modulation + CWGsPReg = 0x28 << 1 # defines the conductance of the p-driver output during periods of no modulation + ModGsPReg = 0x29 << 1 # defines the conductance of the p-driver output during periods of modulation + TModeReg = 0x2A << 1 # defines settings for the internal timer + TPrescalerReg = 0x2B << 1 # the lower 8 bits of the TPrescaler value. The 4 high bits are in TModeReg. + TReloadRegH = 0x2C << 1 # defines the 16-bit timer reload value + TReloadRegL = 0x2D << 1 + TCounterValueRegH = 0x2E << 1 # shows the 16-bit timer value + TCounterValueRegL = 0x2F << 1 + + TestSel1Reg = 0x31 << 1 # general test signal configuration + TestSel2Reg = 0x32 << 1 # general test signal configuration + TestPinEnReg = 0x33 << 1 # enables pin output driver on pins D1 to D7 + TestPinValueReg = 0x34 << 1 # defines the values for D1 to D7 when it is used as an I/O bus + TestBusReg = 0x35 << 1 # shows the status of the internal test bus + AutoTestReg = 0x36 << 1 # controls the digital self test + VersionReg = 0x37 << 1 # shows the software version + AnalogTestReg = 0x38 << 1 # controls the pins AUX1 and AUX2 + TestDAC1Reg = 0x39 << 1 # defines the test value for TestDAC1 + TestDAC2Reg = 0x3A << 1 # defines the test value for TestDAC2 + TestADCReg = 0x3B << 1 # shows the value of ADC I and Q channels + + # MFRC522 commands. Described in chapter 10 of the datasheet. + PCD_Idle = 0x00 #no action, cancels current command execution + PCD_Mem = 0x01 #stores 25 bytes into the internal buffer + PCD_GenerateRandomID = 0x02 #generates a 10-byte random ID number + PCD_CalcCRC = 0x03 #activates the CRC coprocessor or performs a self test + PCD_Transmit = 0x04 # transmits data from the FIFO buffer + PCD_NoCmdChange = 0x07 + PCD_Receive = 0x08 #activates the receiver circuits + PCD_Transceive = 0x0C #transmits data from FIFO buffer to antenna and automatically activates the receiver after transmission + PCD_MFAuthent = 0x0E #performs the MIFARE standard authentication as a reader + PCD_SoftReset = 0x0F #resets the MFRC522 + + RxGain_18dB = 0x00 << 4 # 000b - 18 dB, minimum + RxGain_23dB = 0x01 << 4 # 001b - 23 dB + RxGain_18dB_2 = 0x02 << 4 # 010b - 18 dB, it seems 010b is a duplicate for 000b + RxGain_23dB_2 = 0x03 << 4 # 011b - 23 dB, it seems 011b is a duplicate for 001b + RxGain_33dB = 0x04 << 4 # 100b - 33 dB, average, and typical default + RxGain_38dB = 0x05 << 4 # 101b - 38 dB + RxGain_43dB = 0x06 << 4 # 110b - 43 dB + RxGain_48dB = 0x07 << 4 # 111b - 48 dB, maximum + RxGain_min = 0x00 << 4 # 000b - 18 dB, minimum, convenience for RxGain_18dB + RxGain_avg = 0x04 << 4 # 100b - 33 dB, average, convenience for RxGain_33dB + RxGain_max = 0x07 << 4 # 111b - 48 dB, maximum, convenience for RxGain_48dB + + # The commands used by the PCD to manage communication with several PICCs (ISO 14443-3, Type A, section 6.4) + PICC_CMD_REQA = 0x26 # REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection + PICC_CMD_WUPA = 0x52 # Wake-UP command, prepare for anticollision or selection. 7 bit frame. + PICC_CMD_CT = 0x88 # Cascade Tag. Not really a command, but used during anti collision. + PICC_CMD_SEL_CL1 = 0x93 # Anti collision/Select, Cascade Level 1 + PICC_CMD_SEL_CL2 = 0x95 # Anti collision/Select, Cascade Level 2 + PICC_CMD_SEL_CL3 = 0x97 # Anti collision/Select, Cascade Level 3 + PICC_CMD_HLTA = 0x50 # HaLT command, Type A. Instructs an ACTIVE PICC to go to state HALT. + # The commands used for MIFARE Classic (from http://www.mouser.com/ds/2/302/MF1S503x-89574.pdf, Section 9) + # Use PCD_MFAuthent to authenticate access to a sector, then use these commands to read/write/modify the blocks on the sector. + # The read/write commands can also be used for MIFARE Ultralight. + PICC_CMD_MF_AUTH_KEY_A = 0x60 # Perform authentication with Key A + PICC_CMD_MF_AUTH_KEY_B = 0x61 # Perform authentication with Key B + PICC_CMD_MF_READ = 0x30 # Reads one 16 byte block from the authenticated sector of the PICC. Also used for MIFARE Ultralight. + PICC_CMD_MF_WRITE = 0xA0 # Writes one 16 byte block to the authenticated sector of the PICC. Called "COMPATIBILITY WRITE" for MIFARE Ultralight. + PICC_CMD_MF_DECREMENT = 0xC0 # Decrements the contents of a block and stores the result in the internal data register. + PICC_CMD_MF_INCREMENT = 0xC1 # Increments the contents of a block and stores the result in the internal data register. + PICC_CMD_MF_RESTORE = 0xC2 # Reads the contents of a block into the internal data register. + PICC_CMD_MF_TRANSFER = 0xB0 # Writes the contents of the internal data register to a block. + + + + NRSTPD = 22 + MAX_LEN = 16 + MI_OK = 0 + MI_NOTAGERR = 1 + MI_ERR = 2 + + PCD_CALCCRC = 0x03 + + PICC_REQIDL = 0x26 + PICC_REQALL = 0x52 + PICC_ANTICOLL = 0x93 + PICC_SElECTTAG = 0x93 + PICC_AUTHENT1A = 0x60 + PICC_AUTHENT1B = 0x61 + PICC_READ = 0x30 + PICC_WRITE = 0xA0 + PICC_DECREMENT = 0xC0 + PICC_INCREMENT = 0xC1 + PICC_RESTORE = 0xC2 + PICC_TRANSFER = 0xB0 + PICC_HALT = 0x50 + + + + # The commands used for MIFARE Ultralight (from http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf, Section 8.6) + # The PICC_CMD_MF_READ and PICC_CMD_MF_WRITE can also be used for MIFARE Ultralight. + PICC_CMD_UL_WRITE = 0xA2 #Writes one 4 byte page to the PICC. + + MF_ACK = 0xA # The MIFARE Classic uses a 4 bit ACK/NAK. Any other value than 0xA is NAK. + MF_KEY_SIZE = 6 # A Mifare Crypto1 key is 6 bytes. + + + def __init__(self,I,cs='CS1'): + self.cs=cs + self.I = I + self.I.SPI.set_parameters(2,1,1,0) + if not self.reset(): + self.connected=False + return None + self.write(self.TModeReg, 0x80) + self.write(self.TPrescalerReg, 0xA9) + self.write(self.TReloadRegH, 0x03) + self.write(self.TReloadRegL, 0xE8) + + self.write(self.TxASKReg, 0x40) + self.write(self.ModeReg, 0x3D) + + #Enable the antenna + self.enableAntenna() + self.connected = True + + def MFRC522_Init(self): + GPIO.output(self.NRSTPD, 1) + self.MFRC522_Reset(); + self.write(self.TModeReg, 0x8D) + self.write(self.TPrescalerReg, 0x3E) + self.write(self.TReloadRegL, 30) + self.write(self.TReloadRegH, 0) + + self.write(self.TxAutoReg, 0x40) + self.write(self.ModeReg, 0x3D) + self.AntennaOn() + + def enableAntenna(self): + val = self.read(self.TxControlReg); + if ((val & 0x03) != 0x03): + self.write(self.TxControlReg, val | 0x03); + + def reset(self): + self.write(self.CommandReg,self.PCD_SoftReset) + s=time.time() + while (self.read(self.CommandReg) & (1<<4)): + print ('wait') + time.sleep(0.1) + if time.time() - s > .5: return False + return True + + def write(self,register,val): + self.I.SPI.set_cs(self.cs,0) + ret = self.I.SPI.send16(((register&0x7F)<<8)|val) + self.I.SPI.set_cs(self.cs,1) + return ret&0xFF + + def read(self,register): + self.I.SPI.set_cs(self.cs,0) + ret = self.I.SPI.send16((register|0x80)<<8) + self.I.SPI.set_cs(self.cs,1) + return ret&0xFF + + def readMany(self,register,total): + self.I.SPI.set_cs(self.cs,0) + self.I.SPI.send8(register) + vals = [] + for a in range(total-1): + vals.append( I.SPI.send8(register) ) + vals.append( I.SPI.send8(0) ) + self.I.SPI.set_cs(self.cs,1) + return vals + + + def getStatus(self): + return self.read(self.Status1Reg) + + def getVersion(self): + ver = self.read(self.VersionReg) + if ver==0x88: print ('Cloned version: Fudan Semiconductors') + elif ver==0x90: print ('version 1.0') + elif ver==0x91: print ('version 1.0') + elif ver==0x92: print ('version 2.0') + else: print ('Unknown version ',ver) + return ver + + + def SetBitMask(self, reg, mask): + tmp = self.read(reg) + self.write(reg, tmp | mask) + + def ClearBitMask(self, reg, mask): + tmp = self.read(reg); + self.write(reg, tmp & (~mask)) + + def MFRC522_ToCard(self,command,sendData): + returnedData = [] + backLen = 0 + status = self.MI_ERR + irqEn = 0x00 + waitIRq = 0x00 + lastBits = None + n = 0 + i = 0 + + if command == self.PCD_MFAuthent: + irqEn = 0x12 + waitIRq = 0x10 + if command == self.PCD_Transceive: + irqEn = 0x77 + waitIRq = 0x30 + + self.write(self.ComIEnReg, irqEn|0x80) + self.ClearBitMask(self.ComIrqReg, 0x80) + self.SetBitMask(self.FIFOLevelReg, 0x80) + + self.write(self.CommandReg, self.PCD_Idle); + + for a in sendData: + self.write(self.FIFODataReg, a) + self.write(self.CommandReg, command) + + if command == self.PCD_Transceive: + self.SetBitMask(self.BitFramingReg, 0x80) + + i = 2000 + while True: + n = self.read(self.ComIrqReg) + i = i - 1 + if ~((i!=0) and ~(n&0x01) and ~(n&waitIRq)): + break + + self.ClearBitMask(self.BitFramingReg, 0x80) + + if i != 0: + if (self.read(self.ErrorReg) & 0x1B)==0x00: + status = self.MI_OK + + if n & irqEn & 0x01: + status = self.MI_NOTAGERR + + if command == self.PCD_Transceive: + n = self.read(self.FIFOLevelReg) + lastBits = self.read(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= 0): + y-=1 + ddF_y += 2 + f += ddF_y + x+=1 + ddF_x += 2 + f += ddF_x + self.drawPixel(x0 + x, y0 + y, color) + self.drawPixel(x0 - x, y0 + y, color) + self.drawPixel(x0 + x, y0 - y, color) + self.drawPixel(x0 - x, y0 - y, color) + self.drawPixel(x0 + y, y0 + x, color) + self.drawPixel(x0 - y, y0 + x, color) + self.drawPixel(x0 + y, y0 - x, color) + self.drawPixel(x0 - y, y0 - x, color) + + + def drawLine(self,x0, y0, x1, y1, color): + steep = abs(y1 - y0) > abs(x1 - x0) + if (steep): + tmp = y0 + y0=x0 + x0=tmp + tmp = y1 + y1=x1 + x1=tmp + if (x0 > x1): + tmp = x1 + x1=x0 + x0=tmp + tmp = y1 + y1=y0 + y0=tmp + + dx = x1 - x0 + dy = abs(y1 - y0) + err = dx / 2 + + if (y0 < y1): + ystep = 1 + else: + ystep = -1 + + while(x0<=x1): + if (steep): self.drawPixel(y0, x0, color) + else: self.drawPixel(x0, y0, color) + err -= dy + if (err < 0): + y0 += ystep + err += dx + x0+=1 + + def drawRect(self,x, y, w,h,color): + self.drawFastHLine(x, y, w, color) + self.drawFastHLine(x, y+h-1, w, color) + self.drawFastVLine(x, y, h, color) + self.drawFastVLine(x+w-1, y, h, color) + + + def drawFastVLine(self,x, y, h, color): + self.drawLine(x, y, x, y+h-1, color) + + def drawFastHLine(self,x, y, w, color): + self.drawLine(x, y, x+w-1, y, color) + + + def fillRect(self, x, y, w, h, color): + for i in range(x,x+w): + self.drawFastVLine(i, y, h, color) + + + def writeString(self,s): + for a in s: self.writeChar(ord(a)) + + def writeChar(self,c): + if (c == '\n'): + cursor_y += textsize*8; + cursor_x = 0; + elif(c == '\r'): + pass + else: + self.drawChar(self.cursor_x, self.cursor_y, c, self.textcolor, self.textbgcolor, self.textsize) + self.cursor_x += self.textsize*6 + if (self.wrap and (self.cursor_x > (self._width - self.textsize*6))): + self.cursor_y += self.textsize*8 + self.cursor_x = 0 + + def drawChar(self, x, y, c,color, bg, size): + if((x >= self._width) or (y >= self._height) or ((x + 5 * size - 1) < 0) or ((y + 8 * size - 1) < 0)): + return; + for i in range(6): + if (i == 5): line = 0x0; + else: line = self.font[c*5+i]; + for j in range(8): + if (line & 0x1): + if (size == 1): self.drawPixel(x+i, y+j, color); + else: self.fillRect(x+(i*size), y+(j*size), size, size, color); + elif (bg != color): + if (size == 1): self.drawPixel(x+i, y+j, bg); + else: self.fillRect(x+i*size, y+j*size, size, size, bg); + line >>= 1 + + def setCursor(self, x, y): + self.cursor_x = x + self.cursor_y = y + + def setTextSize(self,s): + self.textsize = s if (s > 0) else 1 + + def setTextColor(self,c, b): + self.textcolor = c + self.textbgcolor = b + + + def setTextWrap(self,w): + self.wrap = w + + def scroll(self,arg): + if arg=='left': + self.SSD1306_command(0x27) #up-0x29 ,2A left-0x27 right0x26 + if arg=='right': + self.SSD1306_command(0x26) #up-0x29 ,2A left-0x27 right0x26 + if arg in ['topright','bottomright']: + self.SSD1306_command(0x29) #up-0x29 ,2A left-0x27 right0x26 + if arg in ['topleft','bottomleft']: + self.SSD1306_command(0x2A) #up-0x29 ,2A left-0x27 right0x26 + + if arg in ['left','right','topright','topleft','bottomleft','bottomright']: + self.SSD1306_command(0x00) #dummy + self.SSD1306_command(0x0) #start page + self.SSD1306_command(0x7) #time interval 0b100 - 3 frames + self.SSD1306_command(0xf) #end page + if arg in ['topleft','topright']: + self.SSD1306_command(0x02) #dummy 00 . xx for horizontal scroll (speed) + elif arg in ['bottomleft','bottomright']: + self.SSD1306_command(0xfe) #dummy 00 . xx for horizontal scroll (speed) + + if arg in ['left','right']: + self.SSD1306_command(0x02) #dummy 00 . xx for horizontal scroll (speed) + self.SSD1306_command(0xff) + + self.SSD1306_command(0x2F) + + if arg=='stop': + self.SSD1306_command(0x2E) + + + def pulseIt(self): + for a in range(2): + self.SSD1306_command(0xD6) + self.SSD1306_command(0x01) + time.sleep(0.1) + self.SSD1306_command(0xD6) + self.SSD1306_command(0x00) + time.sleep(0.1) + + + +if __name__ == "__main__": + from PSL import sciencelab + I= sciencelab.connect() + O=connect(I.I2C) + textbgcolor=0 + textcolor=1 + O.load('logo') + O.scroll('topright') + import time + time.sleep(2.8) + O.scroll('stop') + +