DW1000 UWB driver based on work of Matthias Grob & Manuel Stalder - ETH Zürich - 2015

Dependencies:   BurstSPI

Files at this revision

API Documentation at this revision

Comitter:
AndyA
Date:
Wed Apr 20 11:03:41 2016 +0000
Parent:
8:0b408e77b701
Child:
10:f1e3c04080d6
Child:
11:b4ea3e12f15e
Commit message:
Finished moving configuration information into setup object.; Added documentation.

Changed in this revision

DW1000.cpp Show annotated file Show diff for this revision Revisions of this file
DW1000.h Show annotated file Show diff for this revision Revisions of this file
DW1000Setup.cpp Show annotated file Show diff for this revision Revisions of this file
DW1000Setup.h Show annotated file Show diff for this revision Revisions of this file
--- a/DW1000.cpp	Mon Apr 18 16:58:27 2016 +0000
+++ b/DW1000.cpp	Wed Apr 20 11:03:41 2016 +0000
@@ -3,33 +3,46 @@
 #define SPIRATE_PLL (10*1000*1000)
 #define SPIRATE_OSC (2*1000*1000)
 
-DW1000::DW1000(UWBMode setup, PinName MOSI, PinName MISO, PinName SCLK, PinName CS, PinName IRQ) : irq(IRQ), spi(MOSI, MISO, SCLK), cs(CS)
+DW1000::DW1000(PinName MOSI, PinName MISO, PinName SCLK, PinName CS, PinName IRQ) : irq(IRQ), spi(MOSI, MISO, SCLK), cs(CS)
 {
     setCallbacks(NULL, NULL);
-    DW1000Setup newSetup(DW1000Setup::fastLocationC5);
+    DW1000Setup newSetup(DW1000Setup::tunedDefault);
     systemConfig.applyConfig(&newSetup);
 
     deselect();                         // Chip must be deselected first
     spi.format(8,0);                    // Setup the spi for standard 8 bit data and SPI-Mode 0 (GPIO5, GPIO6 open circuit or ground on DW1000)
     spi.frequency(SPIRATE_PLL);             // with a 1MHz clock rate (worked up to 49MHz in our Test)
 
-    resetAll();                         // we do a soft reset of the DW1000 everytime the driver starts
-setupRadio();
-            setTxPower(250,250,250+30,250+60); // power = 23dB gain
+    setupRadio();
 
-            setRxDelay(0);
-            setTxDelay(0);
-
-    irq.rise(this, &DW1000::ISR);       // attach interrupt handler to rising edge of interrupt pin from DW1000
+    setRxDelay(0);
+    setTxDelay(0);
 }
 
 
-DW1000Setup* DW1000::getSetup() {
+DW1000Setup* DW1000::getSetup()
+{
     return &systemConfig;
+}
+
+bool DW1000::applySetup(DW1000Setup *setup)
+{
+
+    if (setup->check()) {
+        systemConfig.applyConfig(setup);
+        setupRadio();
+        spi.frequency(SPIRATE_PLL);             // with a 1MHz clock rate (worked up to 49MHz in our Test)
+        return true;
     }
+    return false;
+}
 
 void DW1000::setupRadio()
 {
+    irq.rise(NULL);       // attach interrupt handler to rising edge of interrupt pin from DW1000
+
+    stopTRX();
+    resetAll();                         // we do a soft reset of the DW1000 to get to a known state. Without this we lose comms.
     setupAGC();
     setupRxConfig();
     setupLDE();
@@ -39,7 +52,51 @@
     setupTxCalibration();
     setupTxFrameCtrl();
     setupSystemConfig();
+    setupGPIO();
+    setupPower();
 
+    irq.rise(this, &DW1000::ISR);       // attach interrupt handler to rising edge of interrupt pin from DW1000
+}
+
+
+void DW1000::setupGPIO()
+{
+// not done in a loop because bits 7 and 8 are the inverse, a value of 01 indicates GPIO
+    uint32_t value = 0;
+    uint32_t pinMask = systemConfig.getGPIO();
+    if (pinMask & (0x01<<0))
+        value |= 1<<6;
+
+    if (pinMask & (0x01<<1))
+        value |= 1<<8;
+
+    if (pinMask & (0x01<<2))
+        value |= 1<<10;
+
+    if (pinMask & (0x01<<3))
+        value |= 1<<12;
+
+    if (pinMask & (0x01<<4))
+        value |= 1<<14;
+
+    if (pinMask & (0x01<<5))
+        value |= 1<<16;
+
+    if (pinMask & (0x01<<6))
+        value |= 1<<18;
+
+    if (!(pinMask & (0x01<<7)))
+        value |= 1<<20;
+
+    if (!(pinMask & (0x01<<8)))
+        value |= 1<<22;
+
+    writeRegister32(DW1000_GPIO_CTRL, 0, value); // set time to 400ms, enable blink and flash all LEDs
+
+    if (pinMask & 0x000f) { // some LEDs are active
+        writeRegister32(DW1000_PMSC,DWPMSC_PMSC_CTRL0,readRegister32(DW1000_PMSC,DWPMSC_PMSC_CTRL0) | 1<<23 | 1<<18);
+        writeRegister32(DW1000_PMSC, DWPMSC_PMSC_LEDC, 0x00000120); // set time to 400ms, enable blink and flash all LEDs
+    }
 }
 
 void DW1000::setupAGC()
@@ -278,65 +335,105 @@
 }
 
 
-uint8_t DW1000::powerToRegValue(uint16_t powercB)
+uint8_t DW1000::powerToRegValue(float powerdB)
 {
-
     // course power control - 0 = 18dB, 6 = 0dB in 3dB steps.
-    uint8_t course = powercB / 30;
+    uint8_t course = powerdB / 3;
 
     if(course > 6)
         course = 6;
 
     // remaining power
-    powercB -= course * 30;
+    powerdB -= course * 3;
 
     // value in reg is inverse.
     course = 6-course;
 
     // fine control in steps of 0.5dB
-    uint8_t fine =  powercB / 5;
+    uint8_t fine =  powerdB / 0.5f;
     if (fine > 31)
         fine = 31;
 
+    return (course << 5) | fine;
+}
 
-    return (course << 5) | fine;
+
+float DW1000::regToPowerValue(uint8_t powerVal)
+{
+
+    int course = powerVal >> 5;
+    if (course==7) // off
+        return 0;
+
+    course = (6-course)*3;
+
+    int fine = (powerVal & 0x1f);
 
+    return course + fine/2.0f;
+}
+
+
+void DW1000::setupPower()
+{
+    const float *powerPtr = systemConfig.getTxPowers();
+
+    uint32_t powerReg = powerToRegValue(*powerPtr);
+    powerReg |= powerToRegValue(*(powerPtr+1)) << 8;
+    powerReg |= powerToRegValue(*(powerPtr+2)) << 16;
+    powerReg |= powerToRegValue(*(powerPtr+3)) << 24;
+    writeRegister32(DW1000_TX_POWER,0,powerReg);
 }
 
 // transmit power: 0 to 33.5 dB gain in steps of 0.5. Inputs are in 10ths of a dB (0 to 335)
-void DW1000::setTxPower(uint16_t normalPowercB, uint16_t boost500, uint16_t boost250, uint16_t boost125)
+void DW1000::setTxPower(float normalPowerdB, float boost500, float boost250, float boost125)
 {
+   
+    if(normalPowerdB > 33.5)
+        normalPowerdB = 33.5;
 
-    if(normalPowercB > 335)
-        normalPowercB = 335;
-
-    if (boost500 < normalPowercB)
-        boost500 = normalPowercB;
-    if(boost500 > 335)
-        boost500 = 335;
+    if (boost500 < normalPowerdB)
+        boost500 = normalPowerdB;
+    if(boost500 > 33.5)
+        boost500 = 33.5;
 
     if (boost250 < boost500)
         boost250 = boost500;
-    if(boost250 > 335)
-        boost250 = 335;
+    if(boost250 > 33.5)
+        boost250 = 33.5;
 
     if (boost125 < boost250)
         boost125 = boost250;
-    if(boost125 > 335)
-        boost125 = 335;
+    if(boost125 > 33.5)
+        boost125 = 33.5;
 
     if (systemConfig.getSmartPower() == false) {
-        boost500 = normalPowercB;
-        boost250 = normalPowercB;
-        boost125 = normalPowercB;
+        boost500 = normalPowerdB;
+        boost250 = normalPowerdB;
+        boost125 = normalPowerdB;
     }
 
-    uint32_t powerReg = powerToRegValue(normalPowercB);
+    uint32_t powerReg = powerToRegValue(normalPowerdB);
     powerReg |= powerToRegValue(boost500) << 8;
     powerReg |= powerToRegValue(boost250) << 16;
     powerReg |= powerToRegValue(boost125) << 24;
-    writeRegister32(DW1000_TX_POWER, 0, powerReg);
+    writeRegister32(DW1000_TX_POWER,0,powerReg);
+    
+    systemConfig.setSmartTxPower(normalPowerdB,boost500,boost250,boost125); // update the systemConfig
+}
+
+uint32_t DW1000::getTxPower(float *power,float *boost500, float *boost250, float*boost125)
+{
 
+    uint32_t value = readRegister32(DW1000_TX_POWER,0);
+    if (power)
+        *power = regToPowerValue(value&0x000000ff);
+    if (boost500)
+        *boost500 = regToPowerValue((value&0x0000ff00)>>8);
+    if (boost250)
+        *boost250 = regToPowerValue((value&0x00ff0000)>>16);
+    if (boost125)
+        *boost125 = regToPowerValue((value&0xff000000)>>24);
+    return value;
 }
 
 void DW1000::setupAnalogRF()
@@ -491,6 +588,68 @@
     writeRegister32(DW1000_TX_FCTRL,0,frameCtrlValue);
 }
 
+
+#define SQR(x) ((float)(x) * (float)(x))
+
+void DW1000::getRxSignalPower(float *direct, float *total)
+{
+    uint16_t firstPathAmp1 = readRegister16(DW1000_RX_TIME,7);
+    uint16_t firstPathAmp2 = readRegister16(DW1000_RX_FQUAL,2);
+    uint16_t firstPathAmp3 = readRegister16(DW1000_RX_FQUAL,4);
+    uint16_t preambleAcc = readRegister16(DW1000_RX_FINFO,4) >> 4;
+    uint16_t preambleAccNoSat = readRegister16(DW1000_DRX_CONF,DWDRX_RXPAC_NOSAT);
+    uint16_t channelImpulse = readRegister16(DW1000_RX_FQUAL,6);
+
+    if (preambleAcc == preambleAccNoSat) {
+        if (systemConfig.getSfd() == DW1000Setup::standard) {
+            if (systemConfig.getDataRate() == DW1000Setup::kbps110)
+                preambleAcc += -64;
+            else
+                preambleAcc += -5;
+        } else {
+            if (systemConfig.getDataRate() == DW1000Setup::kbps110)
+                preambleAcc += -82;
+            else
+                preambleAcc += -10;
+        }
+    }
+
+
+    float directPower = 10*log10(  (SQR(firstPathAmp1) + SQR(firstPathAmp2) + SQR(firstPathAmp3))/SQR(preambleAcc));
+
+    float rxSignalPower = 10*log10( ((float)channelImpulse * (1<<17))/SQR(preambleAcc) );
+
+    if (systemConfig.getPRF() == DW1000Setup::prf16MHz) {
+        directPower -= 113.77;
+        rxSignalPower -= 113.77;
+    } else {
+        directPower -= 121.74;
+        rxSignalPower -= 121.74;
+    }
+
+    *direct = directPower;
+    *total = rxSignalPower;
+
+}
+
+
+float DW1000::getRxQuality(uint16_t *sigAmp, uint16_t *noiseAmp)
+{
+    uint16_t firstPathAmp2 = readRegister16(DW1000_RX_FQUAL,2);
+    uint16_t noise = readRegister16(DW1000_RX_FQUAL,0);
+    if (sigAmp)
+        *sigAmp = firstPathAmp2;
+    if (noiseAmp)
+        *noiseAmp = noise;
+
+    if (noise > 0)
+        return SQR(firstPathAmp2)/(noise*100000.0f);
+    else
+        return 100;
+}
+#undef SQR
+
+
 void DW1000::setRxDelay(uint16_t ticks)
 {
     writeRegister16(DW1000_LDE_CTRL, DWLDE_LDE_RXANTD, ticks);
--- a/DW1000.h	Mon Apr 18 16:58:27 2016 +0000
+++ b/DW1000.h	Wed Apr 20 11:03:41 2016 +0000
@@ -15,9 +15,12 @@
 #define c_mPerTick  (c_mmPerTick/1000)
 
 
-typedef enum {minPacketSize, tunedDefault, user110k} UWBMode;
 
 /** A DW1000 driver
+*
+* It is expected that the protocol implimentation above this will inherit this object.
+* If not using this structure then move the protected functions to being public.
+* 
 */
 class DW1000
 {
@@ -25,36 +28,10 @@
 
     /** Constructor.
     *
-    *  @param setup The radio mode to configure the unit to use.
-    *
-    *  Valid setup values are defaultConfig, tunedDefault, user110k
+    *  The radio will default to DW1000Setup::tunedDefault until you call applySetup() with a new configuration.
     */
-    DW1000(UWBMode setup, PinName MOSI, PinName MISO, PinName SCLK, PinName CS, PinName IRQ);              // constructor, uses SPI class
-
-    /**
-    * Sets the callbacks on packet Rx and Tx
-    * @param callbackRX The function to call on packet Rx complete
-    * @param callbackTX The function to call on packet Tx complete
-    *
-    * set either or both to null to disable the appropriate interupt
-    */
-    void setCallbacks(void (*callbackRX)(void), void (*callbackTX)(void));                  // setter for callback functions, automatically enables interrupt, if NULL is passed the coresponding interrupt gets disabled
+    DW1000(PinName MOSI, PinName MISO, PinName SCLK, PinName CS, PinName IRQ);              // constructor, uses SPI class
 
-    /**
-    * c++ version of setCallbacks()
-    * @param tptr object for callbacks
-    * @param mptrRX method to call on packet Rx complete
-    * @param mptrTX method to call on packet Tx complete
-    *
-    */
-    template<typename T>
-    void setCallbacks(T* tptr, void (T::*mptrRX)(void), void (T::*mptrTX)(void)) {      // overloaded setter to treat member function pointers of objects
-        callbackRX.attach(tptr, mptrRX);                                                    // possible client code: dw.setCallbacks(this, &A::callbackRX, &A::callbackTX);
-        callbackTX.attach(tptr, mptrTX);                                                    // concept seen in line 100 of http://developer.mbed.org/users/mbed_official/code/mbed/docs/4fc01daae5a5/InterruptIn_8h_source.html
-        setInterrupt(true,true);
-    }
-
-    // Device API
     /** Read the device ID
     * @return the device ID (0xDECA0130)
     */
@@ -97,6 +74,132 @@
     */
     uint64_t getStatus();                                                                   // get the 40 bit device status
 
+
+    /** Set receive antenna delay
+    * @param ticks Delay in system clock cycles
+    */
+    void setRxDelay(uint16_t ticks);
+    /** Set transmit antenna delay
+    * @param ticks Delay in system clock cycles
+    */
+    void setTxDelay(uint16_t ticks);
+
+    /** Set receive antenna delay in meters
+    * @param errorDistance Delay in meters at speed of light
+    */
+    void setRxDelayDistance(double errorDistance) {
+        setRxDelay(errorDistance/c_mPerTick);
+    };
+
+    /** Set transmit antenna delay  in meters
+    * @param errorDistance Delay in meters at speed of light
+    */
+    void setTxDelayDistance(double errorDistance) {
+        setTxDelay(errorDistance/c_mPerTick);
+    };
+
+    /** Read a value from the OTP memory
+    * @param word_address The OTP memory address to read.
+    * @return The 32 bit value at that address.
+    *
+    * See Section 6.3.1 of the user manual for the memory map.
+    */
+    uint32_t readOTP (uint16_t word_address);
+
+    /** Write a value to the OTP memory
+    * @param word_address The OTP memory address to read.
+    * @param data The value to write
+    * @return True if the write was sucessful.
+    *
+    * Writes the supplied data to the OTP memory and then reads it back to verify it was sucessfully programmed.
+    * WARNING - this is a one time operation for each memory address.
+    * See Section 6.3.1 of the user manual for the memory map.
+    * It is recommened that the device is reset or power cycled after programing.
+    */
+    bool writeOTP(uint16_t word_address,uint32_t data);                                          // program a value in the OTP. It is recommended to reset afterwards.
+
+    /** get the current radio configuration
+    * @return A pointer to a DW1000Setup object of the current setup.
+    *
+    * Note to change the setup you must make a copy of the current setup and then pass that to applySetup().
+    */
+    DW1000Setup *getSetup();
+
+    /** Get the current Transmit gain settings.
+    *
+    * @param power Optional, is set to the first power in dBm
+    * @param boost500 Optional, is set to the second power in dBm
+    * @param boost250 Optional, is set to the third power in dBm
+    * @param boost125 Optional, is set to the forth power in dBm
+    * @return The raw transmit gain register value
+    *
+    * If smart power is on then power represents the normal transmit power,
+    * boost500-boost125 indicates the power used for packets of that number of us or less.
+    *
+    * If smart power is off then boost500 represents the gain for the PHY header, boost250 the gain for the main message.
+    * power and boost125 are not used.
+    */
+    uint32_t getTxPower(float *power = NULL, float *boost500 = NULL, float *boost250 = NULL, float *boost125 = NULL);
+
+    /** Set Transmit gain
+    *
+    * @param normalPowercB Normal transmit gain to use.
+    * @param boost500 Gain to use for 6.8Mb/s packets of under 500ms.
+    * @param boost250 Gain to use for 6.8Mb/s packets of under 250ms.
+    * @param boost125 Gain to use for 6.8Mb/s packets of under 125ms.
+    *
+    * All gains are in dB. Gains can be between 0 and 33.5dB.
+    * Boost gains are optional, if not specified boost gains are set to the power for the lower rate (e.g. boost125 is set to the boost250 level).
+    * If smart power is disabled then the normal gain is used for all settings.
+    * The values in the internal DW1000Setup are updated to reflect the configured powers.
+    */
+    void setTxPower(float normalPowerdB, float boost500 = 0, float boost250 = 0, float boost125 = 0);
+
+    /** Get the rx signal power for the last packet
+    *
+    * @param direct Is set to the direct path Rx power in dBm
+    * @param total Is set to the total Rx power in dBm
+    *
+    * According to the DW1000 manual if the direct path power is within 6dB of the total then it was probably a LoS measurment.
+    * If there is more than 10dB difference then it's probably an indirect path.
+    */
+    void getRxSignalPower(float *direct, float *total);
+
+    /** Get a metric of timestamp accuracy
+    *
+    * @param sigAmp Optional location to return the raw signal amplitude
+    * @param noiseAmp Optional location to return the raw channel noise level
+    * @return Timestamp quality metric
+    *
+    * The quality metric is a somewhat arbitary number based on channel noise and direct path strength
+    */
+    float getRxQuality(uint16_t *sigAmp = NULL, uint16_t *noiseAmp = NULL);
+
+protected:
+
+    /**
+    * Sets the callbacks on packet Rx and Tx
+    * @param callbackRX The function to call on packet Rx complete
+    * @param callbackTX The function to call on packet Tx complete
+    *
+    * set either or both to null to disable the appropriate interupt
+    */
+    void setCallbacks(void (*callbackRX)(void), void (*callbackTX)(void));                  // setter for callback functions, automatically enables interrupt, if NULL is passed the coresponding interrupt gets disabled
+
+    /**
+    * c++ version of setCallbacks()
+    * @param tptr object for callbacks
+    * @param mptrRX method to call on packet Rx complete
+    * @param mptrTX method to call on packet Tx complete
+    *
+    */
+    template<typename T>
+    void setCallbacks(T* tptr, void (T::*mptrRX)(void), void (T::*mptrTX)(void)) {      // overloaded setter to treat member function pointers of objects
+        callbackRX.attach(tptr, mptrRX);                                                    // possible client code: dw.setCallbacks(this, &A::callbackRX, &A::callbackTX);
+        callbackTX.attach(tptr, mptrTX);                                                    // concept seen in line 100 of http://developer.mbed.org/users/mbed_official/code/mbed/docs/4fc01daae5a5/InterruptIn_8h_source.html
+        setInterrupt(true,true);
+    }
+
     /** Get the last packet recieve time
     * @return the internal time stamp for the last packet Rx
     *
@@ -119,6 +222,8 @@
     *
     * The supplied packet is transmitted as soon as possible and the reciever re-enabled once transmission is complete.
     * Maximum packet size is 125 bytes.
+    *
+    * The receiver is re-activated as soon as packet transmission is complete.
     */
     void sendFrame(uint8_t* message, uint16_t length);                                      // send a raw frame (length in bytes)
 
@@ -132,6 +237,9 @@
     * Rx is disabled as soon as this command is issued and re-enabled once transmission is complete.
     * Note - 9 LSBs are ignored so timings are only accurate to ~8ns. For more accurate timing check the
     * tx timestamp after transmission is complete.
+    *
+    * The receiver is re-activated as soon as packet transmission is complete.
+    *
     */
     void sendDelayedFrame(uint8_t* message, uint16_t length, uint64_t TxTimestamp);
 
@@ -149,10 +257,23 @@
     * On the next rising edge of the sync line the transmitter will be activated.
     * The packet must have previously been set up using setupSyncedFrame()
     *
-    * Rx is disabled until transmission is complete.
+    * Rx is disabled until transmission is complete and then re-enabled.
     */
     void armSyncedFrame();
 
+    /** Get last packet size
+    * @return The length in bytes of the last packet received
+    */
+    uint16_t getFramelength();                                                              // to get the framelength of the received frame from the PHY header
+
+    /** Get last recieved packet
+    * @param buffer The location to put the received data
+    * @param length The number of bytes to read
+    */
+    void readRxBuffer( uint8_t *buffer, int length ) {
+        readRegister(DW1000_RX_BUFFER, 0, buffer, length);
+    }
+
     /** Enable reciever
     *
     * This is automatically done after each Tx completes but can also be forced manually
@@ -166,84 +287,6 @@
     */
     void stopTRX();                                                                         // disable tranceiver go back to idle mode
 
-    /** Set receive antenna delay
-    * @param ticks Delay in system clock cycles
-    */
-    void setRxDelay(uint16_t ticks);
-    /** Set transmit antenna delay
-    * @param ticks Delay in system clock cycles
-    */
-    void setTxDelay(uint16_t ticks);
-
-
-    /** Set receive antenna delay in meters
-    * @param errorDistance Delay in meters at speed of light
-    */
-    void setRxDelayDistance(double errorDistance) {
-        setRxDelay(errorDistance/c_mPerTick);
-    };
-
-    /** Set transmit antenna delay  in meters
-    * @param errorDistance Delay in meters at speed of light
-    */
-    void setTxDelayDistance(double errorDistance) {
-        setTxDelay(errorDistance/c_mPerTick);
-    };
-
-    /** Get last packet size
-    * @return The length in bytes of the last packet received
-    */
-    uint16_t getFramelength();                                                              // to get the framelength of the received frame from the PHY header
-
-    /** Get last recieved packet
-    * @param buffer The location to put the received data
-    * @param length The number of bytes to read
-    */
-    void readRxBuffer( uint8_t *buffer, int length ) {
-        readRegister(DW1000_RX_BUFFER, 0, buffer, length);
-    }
-
-    /** Read a value from the OTP memory
-    * @param word_address The OTP memory address to read.
-    * @return The 32 bit value at that address.
-    *
-    * See Section 6.3.1 of the user manual for the memory map.
-    */
-    uint32_t readOTP (uint16_t word_address);
-
-    /** Write a value to the OTP memory
-    * @param word_address The OTP memory address to read.
-    * @param data The value to write
-    * @return True if the write was sucessful.
-    *
-    * Writes the supplied data to the OTP memory and then reads it back to verify it was sucessfully programmed.
-    * Note - this is a one time operation for each memory address.
-    * See Section 6.3.1 of the user manual for the memory map.
-    * It is recommened that the device is reset or power cycled after programing.
-    */
-    bool writeOTP(uint16_t word_address,uint32_t data);                                          // program a value in the OTP. It is recommended to reset afterwards.
-
-    /** get the current radio configuration
-    * @return A pointer to a DW1000Setup object of the current setup.
-    *
-    * Note to change the setup you must make a copy of the current setup and then pass that to applySetup().
-    */
-    DW1000Setup *getSetup();
-
-    /** apply a new radio setup to the UWB system
-    * @param setup The new settings to use
-    * @return true if the setup was applied.
-    *
-    * The setup object supplied is copied and can be disposed of after the call.
-    * If the supplied setup fails DW1000Setup::check() then it is ignored and the function returns false.
-    */
-//    bool applySetup(DW1000Setup *setup);
-
-
-    uint32_t readRegister32(uint8_t reg, uint16_t subaddress);
-    void setTxPower(uint16_t normalPowercB, uint16_t boost500 = 0, uint16_t boost250 = 0, uint16_t boost125 = 0);
-
-protected:
     /** Reset the reciever logic
     *
     * This should be done after any receive errors
@@ -259,19 +302,16 @@
     */
     void setInterrupt(bool RX, bool TX);                                                    // set Interrupt for received a good frame (CRC ok) or transmission done
 
-    /** Set Transmit gain
-    *
-    * @param normalPowercB Normal transmit gain to use.
-    * @param boost500 Gain to use for 6.8Mb/s packets of under 500ms.
-    * @param boost250 Gain to use for 6.8Mb/s packets of under 250ms.
-    * @param boost125 Gain to use for 6.8Mb/s packets of under 125ms.
+   
+    /** apply a new radio setup to the UWB system
+    * @param setup The new settings to use
+    * @return true if the setup was applied.
     *
-    * All gains are in cB (dB * 10). Gains can be between 0 and 335 (33.5dB).
-    * Boost gains are optional, if not specified boost gains are set to the power for the lower rate (e.g. boost125 is set to the boost250 level).
+    * The setup object supplied is copied and can be disposed of after the call.
+    * If the supplied setup fails DW1000Setup::check() then it is ignored and the function returns false.
+    * Note - this will reset the radio. You must re-enable interupts, receiver etc. after calling it. 
     */
-//    void setTxPower(uint16_t normalPowercB, uint16_t boost500 = 0, uint16_t boost250 = 0, uint16_t boost125 = 0);
-
-    
+    bool applySetup(DW1000Setup *setup);
 
 private:
     void resetAll();                                                                        // soft reset the entire DW1000 (some registers stay as they were see User Manual)
@@ -279,6 +319,7 @@
     void setupRadio();
 
     // system register setup functions
+    void setupGPIO();
     void setupAGC();
     void setupRxConfig();
     void setupLDE();
@@ -288,15 +329,16 @@
     void setupFreqSynth();
     void setupTxCalibration();
     void setupSystemConfig();
+    void setupPower();
+
     void loadLDE();                                                                         // load the leading edge detection algorithm to RAM, [IMPORTANT because receiving malfunction may occur] see User Manual LDELOAD on p22 & p158
     void loadLDOTUNE();                                                                     // load the LDO tuning as set in the factory
 
-    uint8_t powerToRegValue(uint16_t powercB);
+    uint8_t powerToRegValue(float powerdB);
+    float regToPowerValue(uint8_t powerVal);
 
     DW1000Setup systemConfig;
 
-
-
     // Interrupt
     InterruptIn irq;                                                                        // Pin used to handle Events from DW1000 by an Interrupthandler
     FunctionPointer callbackRX;                                                             // function pointer to callback which is called when successfull RX took place
@@ -309,7 +351,7 @@
 
     uint8_t readRegister8(uint8_t reg, uint16_t subaddress);                                // expressive methods to read or write the number of bits written in the name
     uint16_t readRegister16(uint8_t reg, uint16_t subaddress);
-//    uint32_t readRegister32(uint8_t reg, uint16_t subaddress);
+    uint32_t readRegister32(uint8_t reg, uint16_t subaddress);
     uint64_t readRegister40(uint8_t reg, uint16_t subaddress);
     uint64_t readRegister64(uint8_t reg, uint16_t subaddress);
     void writeRegister8(uint8_t reg, uint16_t subaddress, uint8_t buffer);
--- a/DW1000Setup.cpp	Mon Apr 18 16:58:27 2016 +0000
+++ b/DW1000Setup.cpp	Wed Apr 20 11:03:41 2016 +0000
@@ -3,6 +3,7 @@
 
 DW1000Setup::DW1000Setup(UWBMode modeToUse)
 {
+    setGPIO(0x0180);
     switch (modeToUse) {
         case user110k:  // values from Matthias Grob & Manuel Stalder - ETH Zürich - library
 
@@ -13,7 +14,7 @@
             setPreambleLength(pre1024);
             setPreambleCode(3);
             setSmartPower(false);
-//            setTxPower(18);
+            setTxPower(18);
             break;
         case tunedDefault:    // User Manual "2.5.5 Default Configurations that should be modified" p. 22
         default:
@@ -24,7 +25,7 @@
             setPreambleLength(pre128);
             setPreambleCode(3);
             setSmartPower(false);
-//            setTxPower(18);
+            setTxPower(18);
             break;
         case fastLocationC5:
             setChannel(5);
@@ -34,7 +35,7 @@
             setPreambleLength(pre64);
             setPreambleCode(10);
             setSmartPower(true);
-//            setTxPower(18);
+            setTxPower(18);
             break;
         case fastLocationC4:
             setChannel(4);
@@ -44,7 +45,7 @@
             setPreambleLength(pre64);
             setPreambleCode(18);
             setSmartPower(true);
-//            setTxPower(18);
+            setTxPower(18);
             break;
         case rangeRateCompromise:
             setChannel(4);
@@ -54,7 +55,7 @@
             setPreambleLength(pre256);
             setPreambleCode(18);
             setSmartPower(false);
-//            setTxPower(18);
+            setTxPower(18);
             break;
     }
 }
@@ -212,14 +213,15 @@
             break;
     }
 
-    snprintf(buffer,len,"Channel:\t%u\r\nPRF:\t%s\r\nData Rate:\t%s\r\nPreamble length:\t%s\r\nPreamble code:\t%u\r\nSmart power:\t%s\r\nSFD:\t%s\r\n",
+    snprintf(buffer,len,"Channel:\t%u\r\nPRF:\t%s\r\nData Rate:\t%s\r\nPreamble length:\t%s\r\nPreamble code:\t%u\r\nSmart power:\t%s\r\nSFD:\t%s\r\nTx Gain:\t%.1f,%.1f,%.1f,%.1f\r\n",
              channel,
              (prf == prf16MHz)?"16 MHz":"64 MHz",
              dataRateString,
              preambleString,
              preambleCode,
              enableSmartPower?"Enabled":"Disabled",
-             (sfd == standard)?"Standard":"Non-standard");
+             (sfd == standard)?"Standard":"Non-standard",
+             powers[0],powers[1],powers[2],powers[3]);
 }
 
     bool DW1000Setup::setSmartTxPower(float powerdBm,float power500us,float power250us,float power125us) {
--- a/DW1000Setup.h	Mon Apr 18 16:58:27 2016 +0000
+++ b/DW1000Setup.h	Wed Apr 20 11:03:41 2016 +0000
@@ -135,15 +135,17 @@
     /** Set the Preamble code
     * @return true if a valid option
     *
-    * note - not all codes are valid for all channels
-    *
-    *channel 16MHzPrf    64MHzPrf
-    1       1,2         9, 10, 11, 12
-    2       3, 4        9, 10, 11, 12
-    3       5, 6        9, 10, 11, 12
-    4       7, 8        17, 18, 19, 20
-    5       3, 4        9, 10, 11, 12
-    7       7, 8        17, 18, 19, 20
+    * @note Not all codes are valid for all channels, see the table below
+
+<table>
+<tr><th>channel</th><th>16MHzPrf</th><th>64MHzPrf</th></tr>
+<tr><td>1</td><td>1, 2</td><td>9, 10, 11, 12</td></tr>
+<tr><td>2</td><td>3, 4</td><td>9, 10, 11, 12</td></tr>
+<tr><td>3</td><td>5, 6</td><td>9, 10, 11, 12</td></tr>
+<tr><td>4</td><td>7, 8</td><td>17, 18, 19, 20</td></tr>
+<tr><td>5</td><td>3, 4</td><td>9, 10, 11, 12</td></tr>
+<tr><td>7</td><td>7, 8</td><td>17, 18, 19, 20</td></tr>
+</table>
 
     */
     bool setPreambleCode(unsigned char newCode) {