From 7709570a1640165f33552ce52284c4fca2a54d91 Mon Sep 17 00:00:00 2001 From: bx-s Date: Fri, 29 Mar 2013 14:46:14 +0000 Subject: [PATCH] Bug fixes and new features added to zigduino firmware and client. New features include: - auto checksum support added - auto checksum can be enabled and diabled - support for radio's extended operating mode (AACK mode for research purposes, disabled by default) - client code cleaned up and argument processing simplified git-svn-id: https://svn.code.sf.net/p/goodfet/code/trunk@1562 12e2690d-a6be-4b82-a7b7-67c4a43b65c8 --- client/GoodFETatmel128.py | 279 +++++++++++++++++------------ client/goodfet.zigduino | 67 +++---- firmware/apps/radios/atmel_radio.c | 175 ++++++++++++------ firmware/include/atmel_radio.h | 19 +- 4 files changed, 337 insertions(+), 203 deletions(-) diff --git a/client/GoodFETatmel128.py b/client/GoodFETatmel128.py index 876725c..903603b 100644 --- a/client/GoodFETatmel128.py +++ b/client/GoodFETatmel128.py @@ -1,4 +1,4 @@ -# GoodFET client to interface zigduino/atmel128 radio +# GoodFETclient to interface zigduino/atmel128 radio # forked by bx from code by neighbor Travis Goodspeed from GoodFETAVR import GoodFETAVR import sys, binascii, os, array, time, glob, struct @@ -7,96 +7,109 @@ fmt = ("B", " 0: - port = glob_list[0]; - else: - port = os.environ.get("GOODFET"); - if port is None: - glob_list = glob.glob("/dev/tty.usbserial*"); - if len(glob_list) > 0: - port = glob_list[0]; - if port is None: - glob_list = glob.glob("/dev/ttyUSB*"); - if len(glob_list) > 0: - port = glob_list[0]; - if port is None: - glob_list = glob.glob("/dev/ttyU0"); - if len(glob_list) > 0: - port = glob_list[0]; - if port is None and os.name=='nt': - from scanwin32 import winScan; - scan=winScan(); - for order,comport,desc,hwid in sorted(scan.comports()): - try: - if hwid.index('FTDI')==0: - port=comport; - #print "Using FTDI port %s" % port - except: - #Do nothing. - a=1; - - baud=115200; - self.serialport = serial.Serial( - port, - baud, - parity = serial.PARITY_NONE, - timeout=timeout - ) - - self.verb=0; - self.data="" - attempts=0; - connected=0; - - while connected==0: - while self.verb!=0x7F or self.data!="http://goodfet.sf.net/": - if attemptlimit is not None and attempts >= attemptlimit: - return - elif attempts==2 and os.environ.get("board")!='telosb': - print "See the GoodFET FAQ about missing info flash."; - self.serialport.setTimeout(0.2); - #Explicitly set RTS and DTR to halt board. - self.serialport.setRTS(1); - self.serialport.setDTR(1); - #Drop DTR, which is !RST, low to begin the app. - self.serialport.setDTR(0); - - attempts=attempts+1; - self.readcmd(); #Read the first command. - if self.verbose: - print "Got %02x,%02x:'%s'" % (self.app,self.verb,self.data); - - #Here we have a connection, but maybe not a good one. - #print "We have a connection." - for foo in range(1,30): - time.sleep(1) - if not self.monitorecho(): - connected = 0 - if self.verbose: - print "Comm error on try %i." % (foo) + if self.connected == 0: + if (not (attemptlimit == None)) and (attemptlimit <= 1): + # it always takes at least 2 tries + attemptlimit == 2 + + # Make timeout None to wait forever, 0 for non-blocking mode. + import serial; + + if os.name=='nt' and sys.version.find('64 bit')!=-1: + print "WARNING: PySerial requires a 32-bit Python build in Windows."; + + if port is None and os.environ.get("GOODFET")!=None: + glob_list = glob.glob(os.environ.get("GOODFET")); + if len(glob_list) > 0: + port = glob_list[0]; else: - connected = 1 - break - if self.verbose: - print "Connected after %02i attempts." % attempts; - self.serialport.setTimeout(12); + port = os.environ.get("GOODFET"); + if port is None: + glob_list = glob.glob("/dev/tty.usbserial*"); + if len(glob_list) > 0: + port = glob_list[0]; + if port is None: + glob_list = glob.glob("/dev/ttyUSB*"); + if len(glob_list) > 0: + port = glob_list[0]; + if port is None: + glob_list = glob.glob("/dev/ttyU0"); + if len(glob_list) > 0: + port = glob_list[0]; + if port is None and os.name=='nt': + from scanwin32 import winScan; + scan=winScan(); + for order,comport,desc,hwid in sorted(scan.comports()): + try: + if hwid.index('FTDI')==0: + port=comport; + #print "Using FTDI port %s" % port + except: + #Do nothing. + a=1; + + baud=115200; + + self.serialport = serial.Serial( + port, + baud, + parity = serial.PARITY_NONE, + timeout=timeout + ) + + self.verb=0; + self.data="" + attempts=0; + self.connected=0; + + while self.connected==0: + self.serialport.setDTR(False) + while self.verb!=0x7F or self.data!="http://goodfet.sf.net/": + if attemptlimit is not None and attempts >= attemptlimit: + return + + attempts=attempts+1; + self.readcmd(); #Read the first command. + if self.verbose: + print "Got %02x,%02x:'%s'" % (self.app,self.verb,self.data); + + #Here we have a connection, but maybe not a good one. + #print "We have a connection." + for foo in range(1,30): + time.sleep(1) + if not self.monitorecho(): + self.connected = 0 + if self.verbose: + print "Comm error on try %i." % (foo) + else: + self.connected = 1 + break + if self.verbose: + print "Connected after %02i attempts." % attempts; + self.serialport.setTimeout(12); + + def serClose(self): + self.connected = 0 + self.serialport.close() def writecmd(self, app, verb, count=0, data=[]): """Write a command and some data to the GoodFET.""" self.serialport.write(chr(app)); self.serialport.write(chr(verb)); - + if self.verbose: + print "Tx: ( 0x%02x, 0x%02x, %d )" % ( app, verb, count ) if count > 0: if(isinstance(data,list)): old = data @@ -107,29 +120,31 @@ class GoodFETatmel128rfa1(GoodFETAVR): #little endian 16-bit length count = len(outstr) - self.serialport.write(chr(count&0xFF)); - self.serialport.write(chr(count>>8)); + self.serialport.write(chr(count&0xFF)); + self.serialport.write(chr(count>>8)); + if count > 0: if self.verbose: - print "Tx: ( 0x%02x, 0x%02x, %d )" % ( app, verb, count ) print "sending: %s" %outstr.encode("hex") - self.serialport.write(outstr); - else: # count == 0 - self.serialport.write("\x00") - self.serialport.write("\x00") + if not self.besilent: out = self.readcmd() - #if out: - # print "read: " + out + if out and self.verbose: + print "read: " + out.encode("hex") return out else: - return [] + return None def readcmd(self): + """Read a reply from the GoodFET.""" app = self.serialport.read(1) + if len(app) < 1: + if self.verbose: + print "Rx: None" + self.app = 0 self.verb = 0 self.count = 0 @@ -137,10 +152,19 @@ class GoodFETatmel128rfa1(GoodFETAVR): return self.app=ord(app); - self.verb=ord(self.serialport.read(1)); - - self.count= ord(self.serialport.read(1)) + (ord(self.serialport.read(1))<<8) + v = self.serialport.read(1); + if v: + self.verb = ord(v) + else: + self.verb = 0 + + c1 = self.serialport.read(1) + c2 = self.serialport.read(1) + if (c1 and c2): + self.count= ord(c1) + (ord(c2)<<8) + else: + self.count = 0 if self.verbose: print "Rx: ( 0x%02x, 0x%02x, %i )" % ( self.app, self.verb, self.count ) @@ -164,13 +188,14 @@ class GoodFETatmel128rfa1(GoodFETAVR): else: self.poke(0x8, chan) - def peek(self,reg,bytes=-1): + def peek(self,reg,bytes=1): """Read a Register. """ #Automatically calibrate the len. - if bytes==-1: - bytes=1; - #if reg==0x0a or reg==0x0b or reg==0x10: bytes=5; - data = [reg, 0, bytes%255, bytes>>8] + ([0]*bytes) + if bytes != 1: + print "Warning, currently cannot poke more than 1 byte" + bytes = 1 + data = [reg, 0, bytes%255, bytes>>8] #+ ([0]*bytes) + self.data = None self.writecmd(self.ATMELRADIOAPP,0x02,len(data),data); toret=0; #print self.data.encode("hex") @@ -183,26 +208,28 @@ class GoodFETatmel128rfa1(GoodFETAVR): else: return -1 - def poke(self,reg,val,bytes=-1): + def poke(self,reg,val,bytes=1): # todo, support >1 byte """Write an Register.""" + data = [reg, 0] #+ ([0]*bytes) data=[reg, 0] - - #Automatically calibrate the len. - if bytes==-1: - bytes=1; - #if reg==0x0a or reg==0x0b or reg==0x10: bytes=5; + if bytes != 1: + print "Warning, currently cannot poke more than 1 byte" + bytes = 1 for i in range(0,bytes): data=data+[(val>>(8*i))&0xFF]; self.writecmd(self.ATMELRADIOAPP,0x03,len(data),data); - if self.peek(reg,bytes)!=val: + newval = self.peek(reg,bytes) + if newval!=val: print "Warning, failed to set r%02x=%02x, got %02x." %( reg, val, - self.peek(reg,bytes)); + newval); return; + def setup(self): + self.RF_setup() def RF_setup(self): self.writecmd(self.ATMELRADIOAPP, 0x10, 0, None) @@ -218,5 +245,37 @@ class GoodFETatmel128rfa1(GoodFETAVR): else: return None - def RX_txpacket(self, payload): - self.writecmd(self.ATMELRADIOAPP, 0x81, len(payload)+1,chr(len(payload))+payload) + def RF_txpacket(self, payload): + if type(payload) == list: #convert to string + import array + payload = array.array('B', payload).tostring() + self.writecmd(self.ATMELRADIOAPP, 0x81, len(payload), payload) + + + def RF_getrssi(self): + """Returns the received signal strength""" + base = -90 + val = self.peek(0x7) & 0x7f # read rssi bits + if val == 0: + return base - 1 + elif val < 0x53: + return val + base + else: + return 0x53 + base + + def RF_enable_AACK(self, enable = True): + if (enable and (not self.enable_AACK)): + self.enable_AACK = True + self.writecmd(self.ATMELRADIOAPP, 0x84) + elif ((not enable) and self.enable_AACK): + self.enable_AACK = False + self.writecmd(self.ATMELRADIOAPP, 0x85) + + + def RF_autocrc(self, autocrc=1): + self.autocrc = autocrc + if autocrc: + self.writecmd(self.ATMELRADIOAPP, 0x86) + else: + self.writecmd(self.ATMELRADIOAPP, 0x87) + diff --git a/client/goodfet.zigduino b/client/goodfet.zigduino index 2a84888..ca5ed35 100755 --- a/client/goodfet.zigduino +++ b/client/goodfet.zigduino @@ -2,7 +2,7 @@ #GoodFET zigduino client #forked from code by neighbor Travis Goodspeed by bx -import sys, binascii, os, array, time, glob +import sys, binascii, os, array, time, glob, argparse from GoodFETatmel128 import GoodFETatmel128rfa1 from intelhex import IntelHex; @@ -18,55 +18,60 @@ def printpacket(packet): print "%s" % s; -mskbstring=""; -oldseq=-1; +commands=["sniff", "beaconreq"] +parser = argparse.ArgumentParser(description="Simple GoodFET running on Zigduino tools.") +subparsers = parser.add_subparsers(help='sub-command help') +p_sniff = subparsers.add_parser('sniff', help='Sniff for packets') +p_sniff.add_argument("-f", action="store", dest="channel", help="channel") +p_sniff.add_argument("-i", action="store", dest="interface", + default="/dev/ttyUSB0", help="interface (ie. /dev/ttyUSB0") +p_sniff.set_defaults(name="sniff") +p_br = subparsers.add_parser('beaconreq', help= 'Send out beacon requests') +p_br.add_argument("-f", action="store", dest="channel", help="channel") +p_br.add_argument("-c", action="store_true", dest="autocrc", help="Sends beacon requests with autocrc enabled.") +p_br.add_argument("-i", action="store", dest="interface", + default="/dev/ttyUSB0", help="interface (ie. /dev/ttyUSB0") -#def printconfig(): -# print "Encoding %s" % client.RF_getenc(); -# print "Freq %10i MHz" % (client.RF_getfreq()/10**6); -# print "Rate %10i kbps" % (client.RF_getrate()/1000); -# print "PacketLen %02i bytes" % client.RF_getpacketlen(); -# #print "MacLen %2i bytes" % client.RF_getmaclen(); -# print "SMAC 0x%010x" % client.RF_getsmac(); -# print "TMAC 0x%010x" % client.RF_gettmac(); +p_br.set_defaults(name="beaconreq") - -if(len(sys.argv)==1): - print "Usage: %s verb [objects]\n" % sys.argv[0]; - #print "%s info" % sys.argv[0]; - print "%s sniff [channel]\n\tSniffs packets." % sys.argv[0]; - print "%s beaconreq [channel]\n\tSends out beacons requests" % sys.argv[0]; - sys.exit(); +args = parser.parse_args() #Initialize FET and set baud rate client=GoodFETatmel128rfa1() #client.verbose = True -client.serInit() +client.serInit(args.interface) #if(sys.argv[1ce]=="info"): # printconfig(); -if(sys.argv[1]=="sniff"): +if(args.name=="sniff"): client.RF_setup() - if len(sys.argv)>2: - print "Set channel to %s" % sys.argv[2]; - client.RF_setchannel(int(sys.argv[2])); + if args.channel: + print "Set channel to %s" % args.channel + client.RF_setchannel(int(args.channel)) #Now we're ready to get packets. - while 1: packet=None; while packet==None: packet=client.RF_rxpacket(); - time.sleep(0.4) + time.sleep(.5) printpacket(packet); sys.stdout.flush(); -if (sys.argv[1]=="beaconreq"): +if (args.name=="beaconreq"): + if (args.autocrc): + autocrc = 1 + else: + autocrc = 0 client.RF_setup() - if len(sys.argv)>2: - print "Set channel to %s" % sys.argv[2]; - client.RF_setchannel(int(sys.argv[2])); - packet="\x03\x08\x46\xff\xff\xff\xff\x07\x13\x33" + if args.channel: + print "Set channel to %s" % args.channel + client.RF_setchannel(int(args.channel)) + client.RF_autocrc(autocrc) + if autocrc: + packet="\x03\x08\x46\xff\xff\xff\xff\x07\x00\x00" + else: + packet="\x03\x08\x46\xff\xff\xff\xff\x07\x13\x33" while 1: - client.RX_txpacket(packet) + client.RF_txpacket(chr(len(packet))+packet) time.sleep(1) diff --git a/firmware/apps/radios/atmel_radio.c b/firmware/apps/radios/atmel_radio.c index c1cd4ab..a81ccdf 100644 --- a/firmware/apps/radios/atmel_radio.c +++ b/firmware/apps/radios/atmel_radio.c @@ -8,15 +8,16 @@ #include "platform.h" #include "command.h" -#include //added for itoa #include "atmel_radio.h" #include "spi.h" +uint8_t AACK_enabled; + //! Handles a Chipcon SPI command. void atmel_radio_handle_fn( uint8_t const app, uint8_t const verb, - uint32_t const len); + uint32_t const datalen32); // define the atmel_radio app's app_t app_t const atmel_radio_app = { @@ -44,6 +45,7 @@ inline u8 reg_read(u16 addr) { return *(u8*)(TRX_REGISTER_BASEADDR + addr); } + inline void reg_bit_write(u16 addr, u8 pos, u8 value) { u8 old, mask; @@ -53,8 +55,12 @@ inline void reg_bit_write(u16 addr, u8 pos, u8 value) reg_write(addr, old); //write byte } +void atmel_radio_clear_frame_buffer() { + TRXFBST = 0; //reset the frame buffer pointer to signal it was read (resets the PHR - length value) +} + -void atmel_radio_set_state(u8 state) //based on zigduino-radio, radio_rfa.c +u16 atmel_radio_set_state(u8 state) //based on zigduino-radio, radio_rfa.c { u8 cmd, retries; /* ensure not in state transition */ @@ -69,13 +75,19 @@ void atmel_radio_set_state(u8 state) //based on zigduino-radio, radio_rfa.c case BUSY_TX: cmd = CMD_TX_START; break; - default: //doesn't exist - cmd = CMD_RX_ON; + case RX_ON: + default: + if (AACK_enabled) { + cmd = CMD_RX_AACK_ON; + state = RX_AACK_ON; + } else { + cmd = CMD_RX_ON; + } break; } TRX_STATE = cmd; - retries = 140; /* enough to receive ongoing frame */ + retries = 180; // enough to receive ongoing frame do { if (state == (state & TRX_STATUS)) { break; @@ -83,10 +95,15 @@ void atmel_radio_set_state(u8 state) //based on zigduino-radio, radio_rfa.c retries--; _delay_ms(32); } while (retries); + if (state != (state & TRX_STATUS)) { + return (state & TRX_STATUS); + }else{ + return 0; + } } -void atmel_radiosetup(){ - u8 status; +u16 atmel_radiosetup(){ + u16 status; /* initialize transceiver code based on zigduino-radio */ @@ -106,15 +123,36 @@ void atmel_radiosetup(){ /* clear IRQ history by reading status*/ status = IRQ_STATUS; } + atmel_radio_set_state(TRX_OFF); + + /* setup options for extended operating sniffing mode */ + + // disable auto ack + CSMA_SEED_1 &= 0xEF & ~(1 << AACK_DIS_ACK); + + // disable filtering of reserved frame types and reserve frame type processing + XAH_CTRL_1 &= 0xDF & ~(1 << AACK_FLTR_RES_FT); + XAH_CTRL_1 &= 0xEF & ~(1 << AACK_UPLD_RES_FT); + + // enable promiscuous mode + XAH_CTRL_1 |= 1 << AACK_PROM_MODE; + + + // disable frame protection + TRX_CTRL_2 &= 0x7F & ~(1 << RX_SAFE_MODE); // unset auto crc TRX_CTRL_1 &= 0xDF & ~(1 << TX_AUTO_CRC_ON); - /* enter TRX_OFF state */ - atmel_radio_set_state(TRX_OFF); + + atmel_radio_clear_frame_buffer(); + + // extended operation mode disabled by default + AACK_enabled = 0; + /* enter RX_ON state */ - atmel_radio_set_state(RX_ON); + return atmel_radio_set_state(RX_ON); } @@ -145,86 +183,121 @@ void atmel_radio_peekram(u16 addr, u8 *data, u16 len){ } int atmel_radio_is_frame_buffer_empty() { - return TRXFBST == 0; + return 0 == TRXFBST; } -void atmel_radio_clear_frame_buffer() { - TRXFBST = 0; //reset the frame buffer pointer to signal it was read -} -//! Handles a Chipcon SPI command. void atmel_radio_handle_fn( uint8_t const app, uint8_t const verb, - uint32_t const len){ - - u16 length; - u8 len8; - + uint32_t const datalen32){ + + // cmddata -> byte + // cmddataword -> int + // cmddatalong -> long + u16 readlen16; + u16 ret; + u8 retries; + uint8_t framelen8; switch(verb){ case PEEK: - - case READ: - length=cmddataword[1]; // Backup length. Second byte + //case READ: + readlen16 = cmddataword[1]; // Backup length. Second byte atmel_radio_peekram(cmddataword[0], // First word is address cmddata, // Return in same buffer - length); - txdata(app,verb,length); + readlen16); // length + txdata(app,verb,readlen16); break; - case WRITE: + //case WRITE: case POKE: atmel_radio_pokeram(cmddataword[0], // First word is address cmddata+2, // Remainder of buffer is data - len-2); //Length implied by packet length - txdata(app,verb,len-2); //return number of poked bytes + (u16) datalen32-2); //Length implied by packet length + txdata(app,verb, datalen32-2); //return number of poked bytes break; case SETUP: - atmel_radiosetup(); - txdata(app,verb,0); + ret = atmel_radiosetup(); + txdata(app, verb, ret); break; case ATMEL_RADIO_RX: - - // set to PLL_ON so frame buffer isn't clobbered + // ensure radio is not in the middle or receiving a packet + atmel_radio_set_state(RX_ON); + // set state to PLL_ON so frame buffer isn't clobbered atmel_radio_set_state(PLL_ON); - len8 = 8; + if (!atmel_radio_is_frame_buffer_empty()) { //only if we recieved something new - len8 = TST_RX_LENGTH; //register contains frame length - - if ((len8 > 0x80) ) { //frame too big - txdata(app,verb,0); - } else { - memcpy(cmddata, (void *) &TRXFBST, len8); //return in same buffer - atmel_radio_clear_frame_buffer(); - txdata(app, verb, len8); + framelen8 = TST_RX_LENGTH; //register contains frame length + if ((framelen8 > 127) ) { //frame too big + framelen8 = 127; } - }else{ - // didn't recieve anything new - txdata(app,verb,0); + memcpy(cmddata, (void *) &TRXFBST, framelen8); //return in same buffer + atmel_radio_clear_frame_buffer(); + } else { + framelen8 = 0; //didn't receive anything new } // receive packets again atmel_radio_set_state(RX_ON); + txdata(app, verb, framelen8); break; case ATMEL_RADIO_TX: //prevent radio from recieving new packets atmel_radio_set_state(PLL_ON); - if (cmddata[0] > 127) { //truncate too long packets - cmddata[0] = 127; + uint8_t maxlen = 127; + if (cmddata[0] > maxlen) { //truncate too long packets + cmddata[0] = maxlen; } - memcpy((void *) &TRXFBST, cmddata, cmddata[0]+1); //copy length + packet + memcpy((void *) &TRXFBST, cmddata, datalen32); //copy length + packet atmel_radio_set_state(BUSY_TX); //send packet + while (PLL_ON != (PLL_ON & TRX_STATUS)) {} //wait for TX done //reset the frame buffer pointer to signal it was read atmel_radio_clear_frame_buffer(); atmel_radio_set_state(RX_ON); - txdata(app, verb, len8); + txdata(app, verb, 0); break; + case ATMEL_RADIO_AACK_ON: + if (!AACK_enabled) { + AACK_enabled = 1; + /* enter PLL_ON state */ + atmel_radio_set_state(PLL_ON); + /* enter RX_ON state */ + atmel_radio_set_state(RX_ON); + } + txdata(app, verb, 0); + break; + case ATMEL_RADIO_AACK_OFF: + if (AACK_enabled) { + AACK_enabled = 0; + /* enter PLL_ON state */ + atmel_radio_set_state(PLL_ON); + /* enter RX_ON state */ + atmel_radio_set_state(RX_ON); + } + txdata(app, verb, 0); + break; + case ATMEL_RADIO_AUTOCRC_ON: + if (0 == (TRX_CTRL_1 & (1 << TX_AUTO_CRC_ON))) { //not enabled + atmel_radio_set_state(TRX_OFF); + // can only be safely set in TRX_OFF mode + TRX_CTRL_1 |= 1 << TX_AUTO_CRC_ON; + atmel_radio_set_state(RX_ON); + } - case ATMEL_RADIO_RX_FLUSH: - case ATMEL_RADIO_TX_FLUSH: + txdata(app, verb, 0); + break; + case ATMEL_RADIO_AUTOCRC_OFF: + if (TRX_CTRL_1 & (1 << TX_AUTO_CRC_ON)) { //enabled + atmel_radio_set_state(TRX_OFF); + // can only be safely set in TRX_OFF mode + TRX_CTRL_1 &= 0xDF & ~(1 << TX_AUTO_CRC_ON); + atmel_radio_set_state(RX_ON); + } + txdata(app, verb, 0); + break; default: debugstr("Not yet supported in ATMEL_RADIO"); txdata(app,verb,-1); diff --git a/firmware/include/atmel_radio.h b/firmware/include/atmel_radio.h index b16116e..d043201 100644 --- a/firmware/include/atmel_radio.h +++ b/firmware/include/atmel_radio.h @@ -20,17 +20,14 @@ #define ATMEL_RADIO_RX_FLUSH 0x82 //Flush TX #define ATMEL_RADIO_TX_FLUSH 0x83 - - -//Nordic RF SPI Instructions -#define ATMEL_RADIO_R_REGISTER 0x00 -#define ATMEL_RADIO_W_REGISTER 0x20 -#define ATMEL_RADIO_R_RX_PAYLOAD 0x61 -#define ATMEL_RADIO_W_TX_PAYLOAD 0xA0 -#define ATMEL_RADIO_FLUSH_TX 0xE1 -#define ATMEL_RADIO_FLUSH_RX 0xE2 -#define ATMEL_RADIO_REUSE_TX_PL 0xE3 -#define ATMEL_RADIO_NOP 0xFF +//Start sniffing in extented oparating (AACK) mode +#define ATMEL_RADIO_AACK_ON 0x84 +//Sopt sniffing in extented oparating (AACK) mode, sniff in basic operating mode +#define ATMEL_RADIO_AACK_OFF 0x85 +// enable auto CRC generation +#define ATMEL_RADIO_AUTOCRC_ON 0x86 +// diasble auto CRC generation (disabled by default) +#define ATMEL_RADIO_AUTOCRC_OFF 0x87 //ATMEL_RADIO24L01+ Registers -- 2.20.1