123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589 |
- import spidev
- import time
- class TICC1101(object):
- WRITE_SINGLE_BYTE = 0x00
- WRITE_BURST = 0x40
- READ_SINGLE_BYTE = 0x80
- READ_BURST = 0xC0
- # Configuration Register Details - Registers with preserved values in SLEEP state
- # TI-CC1101 Datasheet
- IOCFG2 = 0x00 # GDO2 Output Pin Configuration
- IOCFG1 = 0x01 # GDO1 Output Pin Configuration
- IOCFG0 = 0x02 # GDO0 Output Pin Configuration
- FIFOTHR = 0x03 # RX FIFO and TX FIFO Thresholds
- SYNC1 = 0x04 # Sync Word, High Byte
- SYNC0 = 0x05 # Sync Word, Low Byte
- PKTLEN = 0x06 # Packet Length
- PKTCTRL1 = 0x07 # Packet Automation Control
- PKTCTRL0 = 0x08 # Packet Automation Control
- ADDR = 0x09 # Device Address
- CHANNR = 0x0A # Channel Number
- FSCTRL1 = 0x0B # Frequency Synthesizer Control
- FSCTRL0 = 0x0C # Frequency Synthesizer Control
- FREQ2 = 0x0D # Frequency Control Word, High Byte
- FREQ1 = 0x0E # Frequency Control Word, Middle Byte
- FREQ0 = 0x0F # Frequency Control Word, Low Byte
- MDMCFG4 = 0x10 # Modem Configuration
- MDMCFG3 = 0x11 # Modem Configuration
- MDMCFG2 = 0x12 # Modem Configuration
- MDMCFG1 = 0x13 # Modem Configuration
- MDMCFG0 = 0x14 # Modem Configuration
- DEVIATN = 0x15 # Modem Deviation Setting
- MCSM2 = 0x16 # Main Radio Control State Machine Configuration
- MCSM1 = 0x17 # Main Radio Control State Machine Configuration
- MCSM0 = 0x18 # Main Radio Control State Machine Configuration
- FOCCFG = 0x19 # Frequency Offset Compensation Configuration
- BSCFG = 0x1A # Bit Synchronization Configuration
- AGCCTRL2 = 0x1B # AGC Control
- AGCCTRL1 = 0x1C # AGC Control
- AGCCTRL0 = 0x1D # AGC Control
- WOREVT1 = 0x1E # High Byte Event0 Timeout
- WOREVT0 = 0x1F # Low Byte Event0 Timeout
- WORCTRL = 0x20 # Wake On Radio Control
- FREND1 = 0x21 # Front End RX Configuration
- FREND0 = 0x22 # Front End TX Configuration
- FSCAL3 = 0x23 # Frequency Synthesizer Calibration
- FSCAL2 = 0x24 # Frequency Synthesizer Calibration
- FSCAL1 = 0x25 # Frequency Synthesizer Calibration
- FSCAL0 = 0x26 # Frequency Synthesizer Calibration
- RCCTRL1 = 0x27 # RC Oscillator Configuration
- RCCTRL0 = 0x28 # RC Oscillator Configuration
- # Configuration Register Details - Registers that Loose Programming in SLEEP State
- FSTEST = 0x29 # Frequency Synthesizer Calibration Control
- PTEST = 0x2A # Production Test
- AGCTEST = 0x2B # AGC Test
- TEST2 = 0x2C # Various Test Settings
- TEST1 = 0x2D # Various Test Settings
- TEST0 = 0x2E # Various Test Settings
- # Command Strobe Registers
- SRES = 0x30 # Reset chip
- SFSTXON = 0x31 # Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1).
- # If in RX (with CCA): Go to a wait state where only the synthesizer
- # is running (for quick RX / TX turnaround).
- SXOFF = 0x32 # Turn off crystal oscillator.
- SCAL = 0x33 # Calibrate frequency synthesizer and turn it off.
- # SCAL can be strobed from IDLE mode without setting manual calibration mode.
- SRX = 0x34 # Enable RX. Perform calibration first if coming from IDLE and MCSM0.FS_AUTOCAL=1.
- STX = 0x35 # In IDLE state: Enable TX. Perform calibration first
- # if MCSM0.FS_AUTOCAL=1.
- # If in RX state and CCA is enabled: Only go to TX if channel is clear.
- SIDLE = 0x36 # Exit RX / TX, turn off frequency synthesizer and exit Wake-On-Radio mode if applicable.
- SWOR = 0x38 # Start automatic RX polling sequence (Wake-on-Radio)
- # as described in Section 19.5 if WORCTRL.RC_PD=0.
- SPWD = 0x39 # Enter power down mode when CSn goes high.
- SFRX = 0x3A # Flush the RX FIFO buffer. Only issue SFRX in IDLE or RXFIFO_OVERFLOW states.
- SFTX = 0x3B # Flush the TX FIFO buffer. Only issue SFTX in IDLE or TXFIFO_UNDERFLOW states.
- SWORRST = 0x3C # Reset real time clock to Event1 value.
- SNOP = 0x3D # No operation. May be used to get access to the chip status byte.
- PATABLE = 0x3E # PATABLE
- TXFIFO = 0x3F # TXFIFO
- RXFIFO = 0x3F # RXFIFO
- # Status Register Details
- PARTNUM = 0xF0 # Chip ID
- VERSION = 0xF1 # Chip ID
- FREQEST = 0xF2 # Frequency Offset Estimate from Demodulator
- LQI = 0xF3 # Demodulator Estimate for Link Quality
- RSSI = 0xF4 # Received Signal Strength Indication
- MARCSTATE = 0xF5 # Main Radio Control State Machine State
- WORTIME1 = 0xF6 # High Byte of WOR Time
- WORTIME0 = 0xF7 # Low Byte of WOR Time
- PKTSTATUS = 0xF8 # Current GDOx Status and Packet Status
- VCO_VC_DAC = 0xF9 # Current Setting from PLL Calibration Module
- TXBYTES = 0xFA # Underflow and Number of Bytes
- RXBYTES = 0xFB # Overflow and Number of Bytes
- RCCTRL1_STATUS = 0xFC # Last RC Oscillator Calibration Result
- RCCTRL0_STATUS = 0xFD # Last RC Oscillator Calibration Result
- def __init__(self, bus=0, device=0, speed=50000, debug=True):
- try:
- self.debug = debug
- self._spi = spidev.SpiDev()
- self._spi.open(bus, device)
- self._spi.max_speed_hz = speed
- except Exception as e:
- print e
- def _usDelay(self, useconds):
- time.sleep(useconds / 1000000.0)
- def _writeSingleByte(self, address, byte_data):
- return self._spi.xfer([self.WRITE_SINGLE_BYTE | address, byte_data])
- def _readSingleByte(self, address):
- return self._spi.xfer([self.READ_SINGLE_BYTE | address, 0x00])[1]
- def _readBurst(self, start_address, length):
- buff = []
- ret = []
- for x in range(length + 1):
- addr = (start_address + (x * 8)) | self.READ_BURST
- buff.append(addr)
- ret = self._spi.xfer(buff)[1:]
- if self.debug:
- print "_readBurst | start_address = %x, length = %x" % (start_address, length)
- return ret
- def _writeBurst(self, address, data):
- data.insert(0, (self.WRITE_BURST | address))
- return self._spi.xfer(data)
- def reset(self):
- return self._strobe(self.SRES)
- def _strobe(self, address):
- return self._spi.xfer([address, 0x00])
- def selfTest(self):
- part_number = self._readSingleByte(self.PARTNUM)
- component_version = self._readSingleByte(self.VERSION)
- # These asserts are based on the documentation
- # Section 29.3 "Status Register Details"
- # On reset PARTNUM == 0x00
- # On reset VERSION == 0x14
- assert part_number == 0x00
- assert component_version == 0x14
- if self.debug:
- print "Part Number: %x" % part_number
- print "Component Version: %x" % component_version
- print "Self test OK"
- def sidle(self):
- self._strobe(self.SIDLE)
- while (self._readSingleByte(self.MARCSTATE) != 0x01):
- self._usDelay(100)
- self._strobe(self.SFTX)
- self._usDelay(100)
- def powerDown(self):
- self.sidle()
- self._strobe(self.SPWD)
- def setCarrierFrequency(self, freq=433):
- # Register values extracted from SmartRF Studio 7
- if freq == 433:
- self._writeSingleByte(self.FREQ2, 0x10)
- self._writeSingleByte(self.FREQ1, 0xA7)
- self._writeSingleByte(self.FREQ0, 0x62)
- else:
- raise Exception("Only 433MHz is currently supported")
- def setChannel(self, channel=0x00):
- self._writeSingleByte(self.CHANNR, channel)
- def setSyncWord(self, sync_word="FAFA"):
- assert len(sync_word) == 4
- self._writeSingleByte(self.SYNC1, int(sync_word[:2], 16))
- self._writeSingleByte(self.SYNC0, int(sync_word[2:], 16))
- def getRegisterConfiguration(self, register, showConfig=True):
- def toBits(byte):
- return bin(byte)[2:].zfill(8)
- if register == "PKTCTRL1":
- bits = toBits(self._readSingleByte(self.PKTCTRL1))
- if showConfig:
- print "PKTCTRL1"
- print "PQT[7:5] = %s" % bits[:3]
- print "CRC_AUTOFLUSH = %s" % bits[4]
- print "APPEND_STATUS = %s" % bits[5]
- print "ADR_CHK[1:0] = %s" % bits[6:]
- elif register == "PKTCTRL0":
- bits = toBits(self._readSingleByte(self.PKTCTRL0))
- if showConfig:
- print "PKTCTRL0"
- print "WHITE_DATA = %s" % bits[1]
- print "PKT_FORMAT[1:0] = %s" % bits[2:4]
- print "CRC_EN = %s" % bits[5]
- print "LENGTH_CONFIG[1:0] = %s" % bits[6:]
- elif register == "ADDR":
- bits = toBits(self._readSingleByte(self.ADDR))
- if showConfig:
- print "ADDR"
- print "DEVICE_ADDR = %s" % bits
- elif register == "CHANNR":
- bits = toBits(self._readSingleByte(self.CHANNR))
- if showConfig:
- print "CAHNNR"
- print "CHAN = %s" % bits
- elif register == "PKTSTATUS":
- bits = toBits(self._readSingleByte(self.CHANNR))
- if showConfig:
- print "PKTSTATUS"
- print "CRC_OK = %s" % bits[0]
- print "CS = %s" % bits[1]
- print "PQT_REACHED = %s" % bits[2]
- print "CCA = %s" % bits[3]
- print "SFD = %s" % bits[4]
- print "GDO2 = %s" % bits[5]
- print "GDO0 = %s" % bits[7]
- elif register == "MDMCFG2":
- bits = toBits(self._readSingleByte(self.MDMCFG2))
- if showConfig:
- print "MDMCFG2"
- print "DEM_DCFILT_OFF = %s" % bits[0]
- print "MOD_FORMAT = %s" % bits[1:4]
- print "MANCHESTER_EN = %s" % bits[4]
- print "SYNC_MODE = %s" % bits[5:]
- elif register == "MDMCFG1":
- bits = toBits(self._readSingleByte(self.MDMCFG1))
- if showConfig:
- print "MDMCFG1"
- print "FEC_EN = %s" % bits[0]
- print "NUM_PREAMBLE = %s" % bits[1:4]
- print "CHANSPC_E = %s" % bits[6:]
- return bits
- def setDefaultValues(self, version=1):
- # Default values extracted from Smart RF Studio 7
- self._writeSingleByte(self.IOCFG2, 0x2E) # Panstamp
- self._writeSingleByte(self.IOCFG1, 0x2E) # Panstamp
- self._writeSingleByte(self.IOCFG0, 0x06) # Panstamp
- self._writeSingleByte(self.FIFOTHR, 0x07) # Panstamp
- self._writeSingleByte(self.PKTLEN, 20)
- self._writeSingleByte(self.PKTCTRL1, 0x06) # Panstamp
- self._writeSingleByte(self.PKTCTRL0, 0x04) # Panstamp
- self.setSyncWord()
- self.setChannel()
- self.configureAddressFiltering()
- self._writeSingleByte(self.FSCTRL1, 0x08) # Panstamp
- self._writeSingleByte(self.FSCTRL0, 0x00) # Panstamp
- self.setCarrierFrequency()
- self._writeSingleByte(self.MDMCFG4, 0xCA) # Panstamp
- self._writeSingleByte(self.MDMCFG3, 0x83) # Panstamp
- self._writeSingleByte(self.MDMCFG2, 0x93) # Panstamp
- self._writeSingleByte(self.MDMCFG1, 0x22)
- self._writeSingleByte(self.MDMCFG0, 0xF8)
- self._writeSingleByte(self.DEVIATN, 0x35) # Panstamp
- self._writeSingleByte(self.MCSM2, 0x07)
- self._writeSingleByte(self.MCSM1, 0x20) # Panstamp
- self._writeSingleByte(self.MCSM0, 0x18)
- self._writeSingleByte(self.FOCCFG, 0x16)
- self._writeSingleByte(self.BSCFG, 0x6C)
- self._writeSingleByte(self.AGCCTRL2, 0x43) # Panstamp
- self._writeSingleByte(self.AGCCTRL1, 0x40)
- self._writeSingleByte(self.AGCCTRL0, 0x91)
- self._writeSingleByte(self.WOREVT1, 0x87)
- self._writeSingleByte(self.WOREVT0, 0x6B)
- self._writeSingleByte(self.WORCTRL, 0xFB)
- self._writeSingleByte(self.FREND1, 0x56)
- self._writeSingleByte(self.FREND0, 0x10)
- self._writeSingleByte(self.FSCAL3, 0xE9)
- self._writeSingleByte(self.FSCAL2, 0x2A)
- self._writeSingleByte(self.FSCAL1, 0x00)
- self._writeSingleByte(self.FSCAL0, 0x1F)
- self._writeSingleByte(self.RCCTRL1, 0x41)
- self._writeSingleByte(self.RCCTRL0, 0x00)
- self._writeSingleByte(self.FSTEST, 0x59)
- self._writeSingleByte(self.PTEST, 0x7F)
- self._writeSingleByte(self.AGCTEST, 0x3F)
- self._writeSingleByte(self.TEST2, 0x81)
- self._writeSingleByte(self.TEST1, 0x35)
- self._writeSingleByte(self.TEST0, 0x09)
- self._writeSingleByte(0x3E, 0xC0) # Power 10dBm
- return
- def setModulation(self, modulation):
- regVal = list(self.getRegisterConfiguration("MDMCFG2"))
- if modulation == "2-FSK":
- modVal = "000"
- elif modulation == "GFSK":
- modVal = "001"
- elif modulation == "ASK" or modulation == "OOK":
- modVal = "011"
- elif modulation == "4-FSK":
- modVal = "100"
- elif modulation == "MSK":
- modVal = "111"
- else:
- raise Exception("Modulation type NOT SUPPORTED!")
- regVal[1:4] = modVal
- regVal = int("".join(regVal), 2)
- self._writeSingleByte(self.MDMCFG2, regVal)
- def _flushRXFifo(self):
- self._strobe(self.SFRX)
- self._usDelay(2)
- def _flushTXFifo(self):
- self._strobe(self.SFTX)
- self._usDelay(2)
- def _setTXState(self):
- self._strobe(self.STX)
- self._usDelay(2)
- def _setRXState(self):
- self._strobe(self.SRX)
- self._usDelay(2)
- def getRSSI(self):
- return self._readSingleByte(self.RSSI)
- def _getMRStateMachineState(self):
- # The &0x1F works as a mask due to the fact
- # that the MARCSTATE register only uses the
- # first 5 bits
- return (self._readSingleByte(self.MARCSTATE) & 0x1F)
- def getPacketConfigurationMode(self):
- pktCtrlVal = self.getRegisterConfiguration("PKTCTRL0", False)
- if pktCtrlVal[6:] == "00": # Packet len is fixed
- return "PKT_LEN_FIXED"
- elif pktCtrlVal[6:] == "01": # Packet len is variable
- return "PKT_LEN_VARIABLE"
- elif pktCtrlVal[6:] == "10": # Infinite packet len mode
- return "PKT_LEN_INFINITE"
- def setPacketMode(self, mode="PKT_LEN_VARIABLE"):
- regVal = list(self.getRegisterConfiguration("PKTCTRL0", False))
- if mode == "PKT_LEN_FIXED":
- val = "00"
- elif mode == "PKT_LEN_VARIABLE":
- val = "01"
- elif mode == "PKT_LEN_INFINITE":
- val = "10"
- else:
- raise Exception("Packet mode NOT SUPPORTED!")
- regVal[6:] = val
- regVal = int("".join(regVal), 2)
- self._writeSingleByte(self.PKTCTRL0, regVal)
- def setFilteringAddress(self, address=0x0E):
- self._writeSingleByte(self.ADDR, address)
- def configureAddressFiltering(self, value="DISABLED"):
- regVal = list(self.getRegisterConfiguration("PKTCTRL1", False))
- if value == "DISABLED":
- val = "00"
- elif value == "ENABLED_NO_BROADCAST":
- val = "01"
- elif value == "ENABLED_00_BROADCAST":
- val = "10"
- elif value == "ENABLED_00_255_BROADCAST":
- val = "11"
- else:
- raise Exception("Address filtering configuration NOT SUPPORTED!")
- regVal[6:] = val
- regVal = int("".join(regVal), 2)
- self._writeSingleByte(self.PKTCTRL1, regVal)
- def sendData(self, dataBytes):
- self._setRXState()
- marcstate = self._getMRStateMachineState()
- dataToSend = []
- while ((marcstate & 0x1F) != 0x0D):
- if self.debug:
- print "marcstate = %x" % marcstate
- print "waiting for marcstate == 0x0D"
- if marcstate == 0x11:
- self._flushRXFifo()
- marcstate = self._getMRStateMachineState()
- if len(dataBytes) == 0:
- if self.debug:
- print "sendData | No data to send"
- return False
- sending_mode = self.getPacketConfigurationMode()
- data_len = len(dataBytes)
- if sending_mode == "PKT_LEN_FIXED":
- if data_len > self._readSingleByte(self.PKTLEN):
- if self.debug:
- print "Len of data exceeds the configured packet len"
- return False
- if self.getRegisterConfiguration("PKTCTRL1", False)[6:] != "00":
- dataToSend.append(self._readSingleByte(self.ADDR))
- dataToSend.extend(dataBytes)
- dataToSend.extend([0] * (self._readSingleByte(self.PKTLEN) - len(dataToSend)))
- if self.debug:
- print "Sending a fixed len packet"
- print "data len = %d" % (data_len)
- elif sending_mode == "PKT_LEN_VARIABLE":
- dataToSend.append(data_len)
- if self.getRegisterConfiguration("PKTCTRL1", False)[6:] != "00":
- dataToSend.append(self._readSingleByte(self.ADDR))
- dataToSend[0] += 1
- dataToSend.extend(dataBytes)
- if self.debug:
- print "Sending a variable len packet"
- print "Length of the packet is: %d" % data_len
- elif sending_mode == "PKT_LEN_INFINITE":
- # ToDo
- raise Exception("MODE NOT IMPLEMENTED")
- print dataToSend
- self._writeBurst(self.TXFIFO, dataToSend)
- self._usDelay(2000)
- self._setTXState()
- marcstate = self._getMRStateMachineState()
- if marcstate not in [0x13, 0x14, 0x15]: # RX, RX_END, RX_RST
- self.sidle()
- self._flushTXFifo()
- self._setRXState()
- if self.debug:
- print "senData | FAIL"
- print "sendData | MARCSTATE: %x" % self._readSingleByte(self.MARCSTATE)
- return False
- remaining_bytes = self._readSingleByte(self.TXBYTES) & 0x7F
- while remaining_bytes != 0:
- self._usDelay(1000)
- remaining_bytes = self._readSingleByte(self.TXBYTES) & 0x7F
- if self.debug:
- print "Waiting until all bytes are transmited, remaining bytes: %d" % remaining_bytes
- if (self._readSingleByte(self.TXBYTES) & 0x7F) == 0:
- if self.debug:
- print "Packet sent!"
- return True
- else:
- if self.debug:
- print self._readSingleByte(self.TXBYTES) & 0x7F
- print "sendData | MARCSTATE: %x" % self._getMRStateMachineState()
- self.sidle()
- self._flushTXFifo()
- time.sleep(5)
- self._setRXState()
- return False
- def recvData(self):
- rx_bytes_val = self._readSingleByte(self.RXBYTES)
- #if rx_bytes_val has something and Underflow bit is not 1
- if (rx_bytes_val & 0x7F and not (rx_bytes_val & 0x80)):
- sending_mode = self.getPacketConfigurationMode()
- if sending_mode == "PKT_LEN_FIXED":
- data_len = self._readSingleByte(self.PKTLEN)
- elif sending_mode == "PKT_LEN_VARIABLE":
- max_len = self._readSingleByte(self.PKTLEN)
- data_len = self._readSingleByte(self.RXFIFO)
- if data_len > max_len:
- if self.debug:
- print "Len of data exceeds the configured maximum packet len"
- return False
- if self.debug:
- print "Receiving a variable len packet"
- print "max len: %d" % max_len
- print "Packet length: %d" % data_len
- elif sending_mode == "PKT_LEN_INFINITE":
- # ToDo
- raise Exception("MODE NOT IMPLEMENTED")
- data = self._readBurst(self.RXFIFO, data_len)
- valPktCtrl1 = self.getRegisterConfiguration("PKTCTRL1", False)
- if valPktCtrl1[5] == "1": # PKTCTRL1[5] == APPEND_STATUS
- # When enabled, two status bytes will be appended to the payload of the
- # packet. The status bytes contain RSSI and LQI values, as well as CRC OK.
- rssi = self._readSingleByte(self.RXFIFO)
- val = self._readSingleByte(self.RXFIFO)
- lqi = val & 0x7f
- if self.debug and valPktCtrl1[5] == "1":
- print "Packet information is enabled"
- print "RSSI: %d" % (rssi)
- print "VAL: %d" % (val)
- print "LQI: %d" % (lqi)
- print "Data: " + str(data)
- self._flushRXFifo()
- return data
|