diff --git a/RFM69.py b/RFM69_POCSAG.py similarity index 58% rename from RFM69.py rename to RFM69_POCSAG.py index 9d06775..894a475 100644 --- a/RFM69.py +++ b/RFM69_POCSAG.py @@ -1,6 +1,6 @@ #!/usr/bin/env python2 -from RFM69registers import * +from RFM69_POCSAGregisters import * import spidev import RPi.GPIO as GPIO import time @@ -8,12 +8,12 @@ import time def chunks(l, n): n = max(1, n) return (l[i:i+n] for i in xrange(0, len(l), n)) -class RFM69(object): - def __init__(self, freqBand, nodeID, networkID, isRFM69HW = False, intPin = 18, rstPin = 29, spiBus = 0, spiDevice = 0): + +class RFM69_POCSAG(object): + def __init__(self, freqBand, pocsagBaudRate = 1200, isRFM69HW = False, intPin = 18, rstPin = 29, spiBus = 0, spiDevice = 0): self.freqBand = freqBand - self.address = nodeID - self.networkID = networkID + self.pocsagBaudRate = pocsagBaudRate self.isRFM69HW = isRFM69HW self.intPin = intPin self.rstPin = rstPin @@ -21,14 +21,8 @@ class RFM69(object): self.spiDevice = spiDevice self.intLock = False self.mode = "" - self.promiscuousMode = False self.DATASENT = False self.DATALEN = 0 - self.SENDERID = 0 - self.TARGETID = 0 - self.PAYLOADLEN = 0 - self.ACK_REQUESTED = 0 - self.ACK_RECEIVED = 0 self.RSSI = 0 self.DATA = [] self.sendSleepTime = 0.05 @@ -44,16 +38,17 @@ class RFM69(object): frfLSB = {RF69_315MHZ: RF_FRFLSB_315, RF69_433MHZ: RF_FRFLSB_433, RF69_868MHZ: RF_FRFLSB_868, RF69_915MHZ: RF_FRFLSB_915} + brMSB = { 512: 0xF4, 1200: RF_BITRATEMSB_1200, 2400: RF_BITRATEMSB_2400 } + brLSB = { 512: 0xF4, 1200: RF_BITRATELSB_1200, 2400: RF_BITRATELSB_2400 } + self.CONFIG = { 0x01: [REG_OPMODE, RF_OPMODE_SEQUENCER_ON | RF_OPMODE_LISTEN_OFF | RF_OPMODE_STANDBY], #no shaping 0x02: [REG_DATAMODUL, RF_DATAMODUL_DATAMODE_PACKET | RF_DATAMODUL_MODULATIONTYPE_FSK | RF_DATAMODUL_MODULATIONSHAPING_00], - #default:4.8 KBPS - 0x03: [REG_BITRATEMSB, RF_BITRATEMSB_1200], - 0x04: [REG_BITRATELSB, RF_BITRATELSB_1200], - #default:5khz, (FDEV + BitRate/2 <= 500Khz) - 0x05: [REG_FDEVMSB, RF_FDEVMSB_50000], - 0x06: [REG_FDEVLSB, RF_FDEVLSB_50000], + 0x03: [REG_BITRATEMSB, brMSB[self.pocsagBaudRate]], + 0x04: [REG_BITRATELSB, brLSB[self.pocsagBaudRate]], + 0x05: [REG_FDEVMSB, 0x00], # 4.5KHz for POCSAG + 0x06: [REG_FDEVLSB, 0x4a], 0x07: [REG_FRFMSB, frfMSB[freqBand]], 0x08: [REG_FRFMID, frfMID[freqBand]], @@ -79,9 +74,9 @@ class RFM69(object): #/* 0x2d */ { REG_PREAMBLELSB, RF_PREAMBLESIZE_LSB_VALUE } // default 3 preamble bytes 0xAAAAAA 0x2e: [REG_SYNCCONFIG, RF_SYNC_ON | RF_SYNC_FIFOFILL_AUTO | RF_SYNC_SIZE_2 | RF_SYNC_TOL_0], #attempt to make this compatible with sync1 byte of RFM12B lib - 0x2f: [REG_SYNCVALUE1, 0x2D], + 0x2f: [REG_SYNCVALUE1, 0x00], #NETWORK ID - 0x30: [REG_SYNCVALUE2, networkID], + 0x30: [REG_SYNCVALUE2, 0x00], 0x37: [REG_PACKETCONFIG1, RF_PACKET1_FORMAT_VARIABLE | RF_PACKET1_DCFREE_OFF | RF_PACKET1_CRC_ON | RF_PACKET1_CRCAUTOCLEAR_ON | RF_PACKET1_ADRSFILTERING_OFF], #in variable length mode: the max frame size, not used in TX @@ -98,6 +93,11 @@ class RFM69(object): 0x00: [255, 0] } + #rfmModule.writeReg(REG_OPMODE, RF_OPMODE_SEQUENCER_ON | RF_OPMODE_LISTEN_OFF | RF_OPMODE_TRANSMITTER) + #rfmModule.writeReg(REG_DATAMODUL, RF_DATAMODUL_DATAMODE_PACKET | RF_DATAMODUL_MODULATIONSHAPING_00) + #self.writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_00) + #self.writeReg(REG_DIOMAPPING2, RF_DIOMAPPING2_CLKOUT_OFF) + #initialize SPI self.spi = spidev.SpiDev() self.spi.open(self.spiBus, self.spiDevice) @@ -107,7 +107,7 @@ class RFM69(object): GPIO.output(self.rstPin, GPIO.HIGH); time.sleep(0.5) GPIO.output(self.rstPin, GPIO.LOW); - time.sleep(0.5) + time.sleep(0.1) #verify chip is syncing? while self.readReg(REG_SYNCVALUE1) != 0xAA: @@ -120,7 +120,12 @@ class RFM69(object): for value in self.CONFIG.values(): self.writeReg(value[0], value[1]) - self.encrypt(0) + #pocsag specific + self.writeReg(REG_PACKETCONFIG1, RF_PACKET1_FORMAT_FIXED | RF_PACKET1_DCFREE_OFF | RF_PACKET1_CRC_OFF | RF_PACKET1_CRCAUTOCLEAR_ON | RF_PACKET1_ADRSFILTERING_OFF) + self.writeReg(REG_PAYLOADLENGTH, 0x00) + self.writeReg(REG_FIFOTHRESH, RF_FIFOTHRESH_TXSTART_FIFONOTEMPTY | RF_FIFOTHRESH_VALUE) + self.writeReg(REG_PREAMBLELSB, 0x00) + self.writeReg(REG_IRQFLAGS2, RF_IRQFLAGS2_FIFOOVERRUN) self.setHighPower(self.isRFM69HW) # Wait for ModeReady while (self.readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00: @@ -133,7 +138,6 @@ class RFM69(object): self.writeReg(REG_FRFMSB, FRF >> 16) self.writeReg(REG_FRFMID, FRF >> 8) self.writeReg(REG_FRFLSB, FRF) - def setMode(self, newMode): if newMode == self.mode: return @@ -161,72 +165,20 @@ class RFM69(object): pass self.mode = newMode; - def sleep(self): self.setMode(RF69_MODE_SLEEP) - - def setAddress(self, addr): - self.address = addr - self.writeReg(REG_NODEADRS, self.address) - - def setNetwork(self, networkID): - self.networkID = networkID - self.writeReg(REG_SYNCVALUE2, networkID) - + def setBaudRate(self, baudRate): + brMSB = { 512: 0xF4, 1200: RF_BITRATEMSB_1200, 2400: RF_BITRATEMSB_2400 } + brLSB = { 512: 0xF4, 1200: RF_BITRATELSB_1200, 2400: RF_BITRATELSB_2400 } + self.pocsagBaudRate = baudRate + self.writeReg(REG_BITRATEMSB, brMSB[self.pocsagBaudRate]) + self.writeReg(REG_BITRATELSB, brLSB[self.pocsagBaudRate]) def setPowerLevel(self, powerLevel): if powerLevel > 31: powerLevel = 31 self.powerLevel = powerLevel self.writeReg(REG_PALEVEL, (self.readReg(REG_PALEVEL) & 0xE0) | self.powerLevel) - - def canSend(self): - if self.mode == RF69_MODE_STANDBY: - self.receiveBegin() - return True - #if signal stronger than -100dBm is detected assume channel activity - elif self.mode == RF69_MODE_RX and self.PAYLOADLEN == 0 and self.readRSSI() < CSMA_LIMIT: - self.setMode(RF69_MODE_STANDBY) - return True - return False - - def send(self, toAddress, buff = "", requestACK = False): - self.writeReg(REG_PACKETCONFIG2, (self.readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART) - now = time.time() - while (not self.canSend()) and time.time() - now < RF69_CSMA_LIMIT_S: - self.receiveDone() - self.sendFrame(toAddress, buff, requestACK, False) - -# to increase the chance of getting a packet across, call this function instead of send -# and it handles all the ACK requesting/retrying for you :) -# The only twist is that you have to manually listen to ACK requests on the other side and send back the ACKs -# The reason for the semi-automaton is that the lib is ingterrupt driven and -# requires user action to read the received data and decide what to do with it -# replies usually take only 5-8ms at 50kbps@915Mhz - - def sendWithRetry(self, toAddress, buff = "", retries = 3, retryWaitTime = 10): - for i in range(0, retries): - self.send(toAddress, buff, True) - sentTime = time.time() - while (time.time() - sentTime) * 1000 < retryWaitTime: - if self.ACKReceived(toAddress): - return True - return False - - def ACKReceived(self, fromNodeID): - if self.receiveDone(): - return (self.SENDERID == fromNodeID or fromNodeID == RF69_BROADCAST_ADDR) and self.ACK_RECEIVED - return False - - def ACKRequested(self): - return self.ACK_REQUESTED and self.TARGETID != RF69_BROADCAST_ADDR - - def sendACK(self, toAddress = 0, buff = ""): - toAddress = toAddress if toAddress > 0 else self.SENDERID - while not self.canSend(): - self.receiveDone() - self.sendFrame(toAddress, buff, False, True) def sendBuffer(self, buff): - #turn off receiver to prevent reception while filling fifo self.setMode(RF69_MODE_STANDBY) #wait for modeReady while (self.readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00: @@ -235,10 +187,7 @@ class RFM69(object): self.writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_00) transmitChunks = chunks(buff, 30) - """if (len(firstBuff) > RF69_MAX_DATA_LEN): - leftOverBuff = firstBuff[RF69_MAX_DATA_LEN:] - firstBuff = firstBuff[0:RF69_MAX_DATA_LEN] - leftOverChunks = chunks(leftOverBuff, 30)""" + self.spi.xfer2([REG_FIFO | 0x80] + transmitChunks.next()) self.DATASENT = False self.setMode(RF69_MODE_TX) @@ -260,107 +209,13 @@ class RFM69(object): if slept > 1.0: break self.setMode(RF69_MODE_RX) - def sendFrame(self, toAddress, buff, requestACK, sendACK): - #turn off receiver to prevent reception while filling fifo - self.setMode(RF69_MODE_STANDBY) - #wait for modeReady - while (self.readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00: - pass - # DIO0 is "Packet Sent" - self.writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_00) - - len = 0 - buflen = 0 - - - if (len(buff) > RF69_MAX_DATA_LEN): - buff = buff[0:RF69_MAX_DATA_LEN] - - ack = 0 - if sendACK: - ack = 0x80 - elif requestACK: - ack = 0x40 - if isinstance(buff, basestring): - self.spi.xfer2([REG_FIFO | 0x80, len(buff) + 3, toAddress, self.address, ack] + [int(ord(i)) for i in list(buff)]) - else: - self.spi.xfer2([REG_FIFO | 0x80, len(buff) + 3, toAddress, self.address, ack] + buff) - - self.DATASENT = False - self.setMode(RF69_MODE_TX) - slept = 0 - while not self.DATASENT: - time.sleep(self.sendSleepTime) - slept += self.sendSleepTime - if slept > 1.0: - break - self.setMode(RF69_MODE_RX) def interruptHandler(self, pin): self.intLock = True self.DATASENT = True - self.intLock = False - - def receiveBegin(self): - - while self.intLock: - time.sleep(.1) - self.DATALEN = 0 - self.SENDERID = 0 - self.TARGETID = 0 - self.PAYLOADLEN = 0 - self.ACK_REQUESTED = 0 - self.ACK_RECEIVED = 0 - self.RSSI = 0 - if (self.readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PAYLOADREADY): - # avoid RX deadlocks - self.writeReg(REG_PACKETCONFIG2, (self.readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART) - #set DIO0 to "PAYLOADREADY" in receive mode - self.writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_01) - self.setMode(RF69_MODE_RX) - - def receiveDone(self): - if (self.mode == RF69_MODE_RX or self.mode == RF69_MODE_STANDBY) and self.PAYLOADLEN > 0: - self.setMode(RF69_MODE_STANDBY) - return True - if self.readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_TIMEOUT: - # https://github.com/russss/rfm69-python/blob/master/rfm69/rfm69.py#L112 - # Russss figured out that if you leave alone long enough it times out - # tell it to stop being silly and listen for more packets - self.writeReg(REG_PACKETCONFIG2, (self.readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART) - elif self.mode == RF69_MODE_RX: - # already in RX no payload yet - return False - self.receiveBegin() - return False - - def readRSSI(self, forceTrigger = False): - rssi = 0 - if forceTrigger: - self.writeReg(REG_RSSICONFIG, RF_RSSI_START) - while self.readReg(REG_RSSICONFIG) & RF_RSSI_DONE == 0x00: - pass - rssi = self.readReg(REG_RSSIVALUE) * -1 - rssi = rssi >> 1 - return rssi - - def encrypt(self, key): - self.setMode(RF69_MODE_STANDBY) - if key != 0 and len(key) == 16: - self.spi.xfer([REG_AESKEY1 | 0x80] + [int(ord(i)) for i in list(key)]) - self.writeReg(REG_PACKETCONFIG2,(self.readReg(REG_PACKETCONFIG2) & 0xFE) | RF_PACKET2_AES_ON) - else: - self.writeReg(REG_PACKETCONFIG2,(self.readReg(REG_PACKETCONFIG2) & 0xFE) | RF_PACKET2_AES_OFF) - def readReg(self, addr): return self.spi.xfer([addr & 0x7F, 0])[1] - def writeReg(self, addr, value): - self.spi.xfer([addr | 0x80, value]) - - def promiscuous(self, onOff): - self.promiscuousMode = onOff - def setHighPower(self, onOff): if onOff: self.writeReg(REG_OCP, RF_OCP_OFF) @@ -370,7 +225,6 @@ class RFM69(object): self.writeReg(REG_OCP, RF_OCP_ON) #enable P0 only self.writeReg(REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | powerLevel) - def setHighPowerRegs(self, onOff): if onOff: self.writeReg(REG_TESTPA1, 0x5D) @@ -378,13 +232,11 @@ class RFM69(object): else: self.writeReg(REG_TESTPA1, 0x55) self.writeReg(REG_TESTPA2, 0x70) - def readAllRegs(self): results = [] for address in range(1, 0x50): results.append([str(hex(address)), str(bin(self.readReg(address)))]) return results - def readTemperature(self, calFactor): self.setMode(RF69_MODE_STANDBY) self.writeReg(REG_TEMP1, RF_TEMP1_MEAS_START) @@ -393,13 +245,10 @@ class RFM69(object): # COURSE_TEMP_COEF puts reading in the ballpark, user can add additional correction #'complement'corrects the slope, rising temp = rising val return (int(~self.readReg(REG_TEMP2)) * -1) + COURSE_TEMP_COEF + calFactor - - def rcCalibration(self): self.writeReg(REG_OSC1, RF_OSC1_RCCAL_START) while self.readReg(REG_OSC1) & RF_OSC1_RCCAL_DONE == 0x00: pass - def shutdown(self): self.setHighPower(False) self.sleep() diff --git a/RFM69registers.py b/RFM69_POCSAGregisters.py similarity index 100% rename from RFM69registers.py rename to RFM69_POCSAGregisters.py diff --git a/main.py b/main.py index de1411b..b3b6633 100644 --- a/main.py +++ b/main.py @@ -1,18 +1,16 @@ #!/usr/bin/env python2 -import RFM69 -from RFM69registers import * +import RFM69_POCSAG +from RFM69_POCSAGregisters import * import datetime import time +from ConfigParser import SafeConfigParser -rfmModule = RFM69.RFM69(RF69_433MHZ, 1, 1, True) -rfmModule.shutdown() +config = SafeConfigParser() + +rfmModule = RFM69_POCSAG.RFM69_POCSAG(RF69_433MHZ, pocsagBaudRate=1200, True) +#rfmModule.shutdown() -print "class initialized" -print "reading all registers" -results = rfmModule.readAllRegs() -for result in results: - print result print "Performing rcCalibration" rfmModule.writeReg(REG_FDEVMSB, 0x00) @@ -20,46 +18,13 @@ rfmModule.writeReg(REG_FDEVLSB, 0x4a) freqHz = 434790000 freqHz /= 61.03515625 # divide down by FSTEP to get FRF -freqHz = int(freqHz) + 35 -rfmModule.writeReg(REG_FRFMSB, freqHz >> 16) -rfmModule.writeReg(REG_FRFMID, freqHz >> 8) -rfmModule.writeReg(REG_FRFLSB, freqHz) - -rfmModule.writeReg(REG_OPMODE, RF_OPMODE_SEQUENCER_ON | RF_OPMODE_LISTEN_OFF | RF_OPMODE_TRANSMITTER) -rfmModule.writeReg(REG_DATAMODUL, RF_DATAMODUL_DATAMODE_PACKET | RF_DATAMODUL_MODULATIONSHAPING_00) -#rfmModule.writeReg(REG_BITRATEMSB, 0xF4) -#rfmModule.writeReg(REG_BITRATELSB, 0xF4) -rfmModule.writeReg(REG_BITRATEMSB, RF_BITRATEMSB_1200) -rfmModule.writeReg(REG_BITRATELSB, RF_BITRATELSB_1200) -#rfmModule.writeReg(REG_BITRATEMSB, 0xFF) -#rfmModule.writeReg(REG_BITRATELSB, 0xFF) - -rfmModule.writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_00) -rfmModule.writeReg(REG_DIOMAPPING2, RF_DIOMAPPING2_CLKOUT_OFF) +freqHz = int(freqHz) + 35 # offset per chip (you may have to calibrate) +rfmModule.setFreqeuncy(freqHz) -rfmModule.writeReg(REG_PACKETCONFIG1, RF_PACKET1_FORMAT_FIXED | RF_PACKET1_DCFREE_OFF | RF_PACKET1_CRC_OFF | RF_PACKET1_CRCAUTOCLEAR_ON | RF_PACKET1_ADRSFILTERING_OFF) -rfmModule.writeReg(REG_PAYLOADLENGTH, 0x00) -rfmModule.writeReg(REG_FIFOTHRESH, RF_FIFOTHRESH_TXSTART_FIFONOTEMPTY | RF_FIFOTHRESH_VALUE) -rfmModule.writeReg(REG_PREAMBLELSB, 0x00) -rfmModule.writeReg(REG_IRQFLAGS2, RF_IRQFLAGS2_FIFOOVERRUN) rfmModule.rcCalibration() -print "setting high power" rfmModule.setHighPower(True) -print "Checking temperature" -print rfmModule.readTemperature(0) -# print "setting encryption" -# rfmModule.encrypt("1234567891011121") -print "sending blah to 2" -rfmModule.setMode(RF69_MODE_SYNTH) -#wait for modeReady -time.sleep(10) -while (rfmModule.readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00: - pass - - import uuid - def my_random_string(string_length=10): """Returns a random string of length string_length.""" random = str(uuid.uuid4())+str(uuid.uuid4())+str(uuid.uuid4())+str(uuid.uuid4())+str(uuid.uuid4())+str(uuid.uuid4())+str(uuid.uuid4())+str(uuid.uuid4()) # Convert UUID format to a Python string. @@ -67,23 +32,16 @@ def my_random_string(string_length=10): random = random.replace("-","") # Remove the UUID '-'. return random[0:string_length] # Return the random string. - - - - from pocsag import encodeTXBatch - msgs = [] -#msgs.append([True, "133709", "1234567890U[]-"]) """ msgs.append([False, "133722", 'Zeile 1\nZeile 2\nZeile 3\nZeile 4']) msgs.append([False, "133742", '1234567890^12w3e4rt5zu