/******************************************************************************
*  Filename:       sbl_device_cc2538.cpp
*  Revised:        $Date$
*  Revision:       $Revision$
*
*  Description:    Serial Bootloader device file for CC2538
*
*  Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
*
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions
*  are met:
*
*    Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
*    Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
*
*    Neither the name of Texas Instruments Incorporated nor the names of
*    its contributors may be used to endorse or promote products derived
*    from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
*  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
*  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
*  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
*  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
*  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
*  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
*  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************/

#include <sbllib.h>
#include "sbl_device.h"
#include "sbl_device_cc2538.h"

#include <ComPort.h>

#include <vector>


/// Struct used when splitting long transfers
typedef struct {
    uint32_t startAddr;
    uint32_t byteCount;
    uint32_t startOffset;
    bool     bExpectAck;
} tTransfer;

//-----------------------------------------------------------------------------
/** \brief Constructor
 */
//-----------------------------------------------------------------------------
SblDeviceCC2538::SblDeviceCC2538()
{
    m_pageEraseSize = SBL_CC2538_PAGE_ERASE_SIZE;
    if(!m_pCom)
    {
        m_pCom = new ComPort();
    }
}

//-----------------------------------------------------------------------------
/** \brief Destructor
 */
//-----------------------------------------------------------------------------
SblDeviceCC2538::~SblDeviceCC2538()
{
}


//-----------------------------------------------------------------------------
/** \brief This function sends ping command to device.
 *
 * \return
 *      Returns SBL_SUCCESS, ...
 */
//-----------------------------------------------------------------------------
uint32_t
SblDeviceCC2538::ping()
{
    int retCode = SBL_SUCCESS;
    bool bResponse = false;

    if(!isConnected())
    {
        return SBL_PORT_ERROR;
    }

    //
    // Send command
    //
    if((retCode = sendCmd(SblDeviceCC2538::CMD_PING)) != SBL_SUCCESS)
    {
        return retCode;
    }

    //
    // Get response
    //
    if((retCode = getCmdResponse(bResponse)) != SBL_SUCCESS)
    {
        return retCode;
    }

    return (bResponse) ? SBL_SUCCESS : SBL_ERROR;
}


//-----------------------------------------------------------------------------
/** \brief This function gets status from device.
 *
 * \param[out] pStatus
 *      Pointer to where status is stored.
 * \return
 *      Returns SBL_SUCCESS, ...
 */
//-----------------------------------------------------------------------------
uint32_t
SblDeviceCC2538::readStatus(uint32_t *pui32Status)
{
    uint32_t retCode = SBL_SUCCESS;
    bool bSuccess = false;

    if(!isConnected())
    {
        return SBL_PORT_ERROR;
    }

    //
    // Send command
    //
    if((retCode = sendCmd(SblDeviceCC2538::CMD_GET_STATUS)) != SBL_SUCCESS)
    {
        return retCode;        
    }

    //
    // Receive command response
    //
    if((retCode = getCmdResponse(bSuccess)) != SBL_SUCCESS)
    {
        return retCode;
    }

    if(!bSuccess)
    {
        return SBL_ERROR;
    }

    //
    // Receive command response data
    //
    char status = 0;
    uint32_t ui32NumBytes = 1;
    if((retCode = getResponseData(&status, ui32NumBytes)) != SBL_SUCCESS)
    {
        //
        // Respond with NAK
        //
        sendCmdResponse(false);
        return retCode;
    }

    //
    // Respond with ACK
    //
    sendCmdResponse(true);

    m_lastDeviceStatus = status;
    *pui32Status = status;
    return SBL_SUCCESS;
}


//-----------------------------------------------------------------------------
/** \brief This function reads device ID.
 *
 * \param[out] pui32DeviceId
 *      Pointer to where device ID is stored.
 * \return
 *      Returns SBL_SUCCESS, ...
 */
//-----------------------------------------------------------------------------
uint32_t 
SblDeviceCC2538::readDeviceId(uint32_t *pui32DeviceId)
{
    int retCode = SBL_SUCCESS;
    bool bSuccess = false;

    if(!isConnected())
    {
        return SBL_PORT_ERROR;
    }

    //
    // Send command
    //
    if((retCode = sendCmd(SblDeviceCC2538::CMD_GET_CHIP_ID)) != SBL_SUCCESS)
    {
        return retCode;        
    }

    //
    // Receive command response (ACK/NAK)
    //
    if((retCode = getCmdResponse(bSuccess)) != SBL_SUCCESS)
    {
        return retCode;
    }
    if(!bSuccess)
    {
        return SBL_ERROR;
    }

    //
    // Receive response data
    //
    char pId[4];
    memset(pId, 0, 4);
    uint32_t numBytes = 4;
    if((retCode = getResponseData(pId, numBytes)) != SBL_SUCCESS)
    {
        //
        // Respond with NAK
        //
        sendCmdResponse(false);
        return retCode;
    }

    if(numBytes != 4)
        {
            //
            // Respond with NAK
            //
            sendCmdResponse(false);
            setState(SBL_ERROR, "Didn't receive 4 B.\n");
            return SBL_ERROR;
        }

    //
    // Respond with ACK
    //
    sendCmdResponse(true);

    //
    // Store retrieved ID and report success
    //
    *pui32DeviceId = charArrayToUL(pId);
    m_deviceId = *pui32DeviceId;
    return SBL_SUCCESS;
}


//-----------------------------------------------------------------------------
/** \brief This function reads device FLASH size in bytes.
 *
 * \param[out] pui32FlashSize
 *      Pointer to where FLASH size is stored.
 * \return
 *      Returns SBL_SUCCESS, ...
 */
//-----------------------------------------------------------------------------
uint32_t 
SblDeviceCC2538::readFlashSize(uint32_t *pui32FlashSize)
{
    uint32_t retCode = SBL_SUCCESS;

    //
    // Read CC2538 DIECFG0 (contains FLASH size information)
    //
    uint32_t addr = SBL_CC2538_DIECFG0;
    uint32_t value;
    if((retCode = readMemory32(addr, 1, &value)) != SBL_SUCCESS)
    {
        setState((tSblStatus)retCode, "Failed to read device FLASH size: %s", getLastError().c_str());
        return retCode;
    }

    //
    // Calculate FLASH size (FLASH size bits are at bits [6:4])
    //
    value = ((value >> 4) & 0x07);
    switch(value)
    {
    case 1: *pui32FlashSize = 0x20000; break;   // 128 KB
    case 2: *pui32FlashSize = 0x40000; break;   // 256 KB
    case 3: *pui32FlashSize = 0x60000; break;   // 384 KB
    case 4: *pui32FlashSize = 0x80000; break;   // 512 KB
    case 0:                                 //  64 KB
    default:*pui32FlashSize = 0x10000; break;   // All invalid values are interpreted as 64 KB
    }

    m_flashSize = *pui32FlashSize;

    return SBL_SUCCESS;
}


//-----------------------------------------------------------------------------
/** \brief This function reads device RAM size in bytes.
 *
 * \param[out] pui32RamSize
 *      Pointer to where RAM size is stored.
 * \return
 *      Returns SBL_SUCCESS, ...
 */
//-----------------------------------------------------------------------------
uint32_t 
SblDeviceCC2538::readRamSize(uint32_t *pui32RamSize)
{
    int retCode = SBL_SUCCESS;

    //
    // Read CC2538 DIECFG0 (contains RAM size information
    //
    uint32_t addr = SBL_CC2538_DIECFG0;
    uint32_t value;
    if((retCode = readMemory32(addr, 1, &value)) != SBL_SUCCESS)
    {
        setState(retCode, "Failed to read device RAM size: %s", getLastError().c_str());
        return retCode;
    }

    //
    // Calculate RAM size in bytes (Ram size bits are at bits [9:7])
    //
    value = ((value >> 7) & 0x07);
    switch(value)
    {
    case 4: *pui32RamSize = 0x8000; break;    // 32 KB
    case 0: *pui32RamSize = 0x4000; break;    // 16 KB
    case 1: *pui32RamSize = 0x2000; break;    // 8 KB
    default:*pui32RamSize = 0x2000; break;    // All invalid values are interpreted as 8 KB
    }

    m_ramSize = *pui32RamSize;

    return retCode;
}


//-----------------------------------------------------------------------------
/** \brief This function makes the device run from the address given by
 *      \u ui32Address, transferring execution control away from the 
 *      bootloader. No further bootloader access will be possible.
 *
 * \parameter[in] ui32Address
 *      The device address where execution will be transferred to.
 * \return
 *      Returns SBL_SUCCESS, ...
 */
//-----------------------------------------------------------------------------
uint32_t
SblDeviceCC2538::run(uint32_t ui32Address)
{
    int retCode = SBL_SUCCESS;
    bool bSuccess = false;

    if(!isConnected())
    {
        return SBL_PORT_ERROR;
    }

    //
    // Generate payload
    // - 4B address
    //
    char pcPayload[4];
    ulToCharArray(ui32Address, &pcPayload[0]);

    //
    // Send command
    //
    if((retCode = sendCmd(SblDeviceCC2538::CMD_RUN, pcPayload, 4)) != SBL_SUCCESS)
    {
        return retCode;        
    }

    //
    // Receive command response (ACK/NAK)
    //
    if((retCode = getCmdResponse(bSuccess)) != SBL_SUCCESS)
    {
        return retCode;
    }
    if(!bSuccess)
    {
        setState(SBL_ERROR, "Run command NAKed by device.\n");
        return SBL_ERROR;
    }

    m_bCommInitialized = false;
    return SBL_SUCCESS;

}

//-----------------------------------------------------------------------------
/** \brief This function reset the device. Communication to the device must be 
 *      reinitialized after calling this function.
 *
 * \return
 *      Returns SBL_SUCCESS, ...
 */
//-----------------------------------------------------------------------------
uint32_t
SblDeviceCC2538::reset()
{
    int retCode = SBL_SUCCESS;
    bool bSuccess = false;

    if(!isConnected())
    {
        return SBL_PORT_ERROR;
    }

    //
    // Send command
    //
    if((retCode = sendCmd(SblDeviceCC2538::CMD_RESET)) != SBL_SUCCESS)
    {
        return retCode;        
    }

    //
    // Receive command response (ACK/NAK)
    //
    if((retCode = getCmdResponse(bSuccess)) != SBL_SUCCESS)
    {
        return retCode;
    }
    if(!bSuccess)
    {
        setState(SBL_ERROR, "Reset command NAKed by device.\n");
        return SBL_ERROR;
    }

    m_bCommInitialized = false;
    return SBL_SUCCESS;
}


//-----------------------------------------------------------------------------
/** \brief This function erases device flash pages. Starting page is the page 
 *      that includes the address in \e startAddress. Ending page is the page 
 *      that includes the address <startAddress + byteCount>. CC2538 erase 
 *      size is 2KB.
 *
 * \param[in] ui32StartAddress
 *      The start address in flash.
 * \param[in] ui32ByteCount
 *      The number of bytes to erase.
 *
 * \return
 *      Returns SBL_SUCCESS, ...
 */
//-----------------------------------------------------------------------------
uint32_t
SblDeviceCC2538::eraseFlashRange(uint32_t ui32StartAddress, 
                                 uint32_t ui32ByteCount)
{
    uint32_t retCode = SBL_SUCCESS;
    bool bSuccess = false;
    char pcPayload[8];
    uint32_t devStatus;

    //
    // Initial check
    // 
    if(!isConnected())
    {
        return SBL_PORT_ERROR;
    }

    //
    // Calculate retry count
    //
    uint32_t ui32PageCount = ui32ByteCount / SBL_CC2538_PAGE_ERASE_SIZE;
    if( ui32ByteCount % SBL_CC2538_PAGE_ERASE_SIZE) ui32PageCount ++;
    uint32_t ui32TryCount = (((ui32PageCount * SBL_CC2538_PAGE_ERASE_TIME_MS) / \
                             SBL_DEFAULT_READ_TIMEOUT) + 1);

    //
    // Build payload
    // - 4B address (MSB first)
    // - 4B byte count (MSB first)
    //
    ulToCharArray(ui32StartAddress, &pcPayload[0]);
    ulToCharArray(ui32ByteCount, &pcPayload[4]);

    //
    // Set progress
    //
    setProgress(0);

    //
    // Send command
    //
    if((retCode = sendCmd(SblDeviceCC2538::CMD_ERASE, pcPayload, 8)) != SBL_SUCCESS)
    {
        return retCode;        
    }

    //
    // Receive command response (ACK/NAK)
    //
    if((retCode = getCmdResponse(bSuccess, ui32TryCount)) != SBL_SUCCESS)
    {
        return retCode;
    }
    if(!bSuccess)
    {
        return SBL_ERROR;
    }

    //
    // Check device status (Flash failed if page(s) locked)
    //
    readStatus(&devStatus);
    if(devStatus != SblDeviceCC2538::CMD_RET_SUCCESS)
    {
        setState(SBL_ERROR, "Flash erase failed. (Status 0x%02X = '%s'). Flash pages may be locked.\n", devStatus, getCmdStatusString(devStatus).c_str());
        return SBL_ERROR;
    }

    //
    // Set progress
    //
    setProgress(100);

    return SBL_SUCCESS;
}


//-----------------------------------------------------------------------------
/** \brief This function reads \e ui32UnitCount (32 bit) words of data from 
 *      device. Destination array is 32 bit wide. The start address must be 4 
 *      byte aligned.
 *
 * \param[in] ui32StartAddress
 *      Start address in device (must be 4 byte aligned).
 * \param[in] ui32UnitCount
 *      Number of data words to read.
 * \param[out] pcData
 *      Pointer to where read data is stored.
 * \return
 *      Returns SBL_SUCCESS, ...
 */
//-----------------------------------------------------------------------------
uint32_t 
SblDeviceCC2538::readMemory32(uint32_t ui32StartAddress, uint32_t ui32UnitCount, 
                              uint32_t *pui32Data)
{
    int retCode = SBL_SUCCESS;
    bool bSuccess = false;

    //
    // Check input arguments
    //
    if((ui32StartAddress & 0x03))
    {
        setState(SBL_ARGUMENT_ERROR, "readMemory32(): Start address (0x%08X) must be a multiple of 4.\n", ui32StartAddress);
        return SBL_ARGUMENT_ERROR;
    }

    //
    // Set progress
    //
    setProgress(0);

    if(!isConnected())
    {
        return SBL_PORT_ERROR;
    }

    char pcPayload[5];
    uint32_t recvCount = 0;
    for(uint32_t i = 0; i < ui32UnitCount; i++)
    {
        //
        // Build payload
        // - 4B address (MSB first)
        // - 1B access width
        //
        ulToCharArray((ui32StartAddress + (i*4)), &pcPayload[0]);
        pcPayload[4] = SBL_CC2538_ACCESS_WIDTH_4B;

        //
        // Set progress
        //
        setProgress( ((100 * i)/ui32UnitCount) );

        //
        // Send command
        //
        if((retCode = sendCmd(SblDeviceCC2538::CMD_MEMORY_READ, pcPayload, 5)) != SBL_SUCCESS)
        {
            return retCode;        
        }

        //
        // Receive command response (ACK/NAK)
        //
        if((retCode = getCmdResponse(bSuccess)) != SBL_SUCCESS)
        {
            return retCode;
        }
        if(!bSuccess)
        {
            return SBL_ERROR;
        }

        //
        // Receive 4B response
        //
        recvCount = 4;
        if((retCode = getResponseData(pcPayload, recvCount)) != SBL_SUCCESS)
        {
            //
            // Respond with NAK
            //
            sendCmdResponse(false);
            return retCode;            
        }
        if(recvCount != 4)
        {
            //
            // Respond with NAK
            //
            sendCmdResponse(false);
            setState(SBL_ERROR, "Didn't receive 4 B.\n");
            return SBL_ERROR;
        }
        pui32Data[i] = charArrayToUL(pcPayload);

        //
        // Respond with ACK
        //
        sendCmdResponse(true);
    }

    //
    // Set progress
    //
    setProgress(100);

    return SBL_SUCCESS;
}


//-----------------------------------------------------------------------------
/** \brief This function reads \e unitCount bytes of data from device. 
 *      Destination array is 8 bit wide.
 *
 * \param[in] ui32StartAddress
 *      Start address in device.
 * \param[in] ui32UnitCount
 *      Number of bytes to read.
 * \param[out] pcData
 *      Pointer to where read data is stored.
 * \return
 *      Returns SBL_SUCCESS, ...
 */
//-----------------------------------------------------------------------------
uint32_t 
SblDeviceCC2538::readMemory8(uint32_t ui32StartAddress, uint32_t ui32UnitCount, 
                             char *pcData)
{
    int retCode = SBL_SUCCESS;
    bool bSuccess = false;

    //
    // Using 4B access width. Expanding byte count to include bytes at start 
    // and end of sequence.
    //
    uint32_t begCnt = ui32StartAddress % 4;
    uint32_t endCnt = (ui32StartAddress + ui32UnitCount) % 4;
    if(endCnt) { endCnt = 4 - endCnt; }
    uint32_t totByteCnt = begCnt + ui32UnitCount + endCnt;


    //
    // Word align start address
    //
    ui32StartAddress -= begCnt;

    //
    // Create temporary vector with enough space.
    //
    std::vector<char> tmpBuf (totByteCnt);

    //
    // Set progress
    //
    setProgress(0);

    if(!isConnected())
    {
        return SBL_PORT_ERROR;
    }

    char pcPayload[5];
    uint32_t recvCount = 0;
    for(uint32_t i = 0; i < totByteCnt/4; i++)
    {
        //
        // Build payload
        // - 4B address (MSB first)
        // - 1B access width
        //
        ulToCharArray((ui32StartAddress + (i*4)), &pcPayload[0]);
        pcPayload[4] = SBL_CC2538_ACCESS_WIDTH_4B;

        //
        // Set progress
        //
        setProgress( ((100 * i)/(totByteCnt/4)) );

        //
        // Send command
        //
        if((retCode = sendCmd(SblDeviceCC2538::CMD_MEMORY_READ, pcPayload, 5)) != SBL_SUCCESS)
        {
            return retCode;        
        }

        //
        // Receive command response (ACK/NAK)
        //
        if((retCode = getCmdResponse(bSuccess)) != SBL_SUCCESS)
        {
            return retCode;
        }
        if(!bSuccess)
        {
            return SBL_ERROR;
        }

        //
        // Receive 4B response
        //
        recvCount = 4;
        if((retCode = getResponseData(pcPayload, recvCount)) != SBL_SUCCESS)
        {
            //
            // Respond with NAK
            //
            sendCmdResponse(false);
            return retCode;
        }
        if(recvCount != 4)
        {
            //
            // Respond with NAK
            //
            sendCmdResponse(false);
            setState(SBL_ERROR, "Didn't receive 4 B.\n");
            return SBL_ERROR;
        }
        byteSwap(pcPayload);
        memcpy(&tmpBuf[4*i], pcPayload, 4);

        //
        // Respond with ACK
        //
        sendCmdResponse(true);
    }

    //
    // Copy wanted data to pcData
    //
    for(uint32_t i = 0; i < ui32UnitCount; i++) 
    {
        pcData[i] = tmpBuf.at(i + begCnt);
    }

    //
    // Set progress
    //
    setProgress(100);

    return SBL_SUCCESS;
}


//-----------------------------------------------------------------------------
/** \brief This function writes \e unitCount words of data to device SRAM. 
 *      Source array is 32 bit wide. \e ui32StartAddress must be 4 byte
 *      aligned.
 *
 * \param[in] ui32StartAddress
 *      Start address in device.
 * \param[in] ui32UnitCount
 *      Number of data words (32bit) to write.
 * \param[in] pui32Data
 *      Pointer to source data.
 * \return
 *      Returns SBL_SUCCESS, ...
 */
//-----------------------------------------------------------------------------
uint32_t 
SblDeviceCC2538::writeMemory32(uint32_t ui32StartAddress, 
                               uint32_t ui32UnitCount, 
                               const uint32_t *pui32Data)
{
    uint32_t retCode = SBL_SUCCESS;
    bool bSuccess = false;
    char pcPayload[9];
    uint32_t recvCount = 0;
    uint32_t currAddr;

    //
    // Check input arguments
    //
    if(!addressInRam(ui32StartAddress, ui32UnitCount*4))
    {
        setState(SBL_ARGUMENT_ERROR, "writeMemory32(): Address range (0x%08X + %d bytes) is not in device RAM.\n", ui32StartAddress, ui32UnitCount*4);
        return SBL_ARGUMENT_ERROR;
    }
    if((ui32StartAddress & 0x03))
    {
        setState(SBL_ARGUMENT_ERROR, "writeMemory32(): Start address (0x%08X) must be a multiple of 4.\n", ui32StartAddress);
        return SBL_ARGUMENT_ERROR;
    }

    if(!isConnected())
    {
        return SBL_PORT_ERROR;
    }

    //
    // Set progress
    //
    setProgress(0);

    for(uint32_t i = 0; i < ui32UnitCount; i++)
    {
        currAddr = ui32StartAddress + (i * 4);
        //
        // Build payload
        // - 4B address (MSB first)
        // - 4B data value (MSB first)
        // - 1B access width
        //
        ulToCharArray(currAddr, &pcPayload[0]);
        ulToCharArray(pui32Data[i], &pcPayload[4]);
        pcPayload[8] = SBL_CC2538_ACCESS_WIDTH_4B;

        //
        // Set progress
        //
        setProgress( ((100 * i)/ui32UnitCount) );

        //
        // Send command
        //
        if((retCode = sendCmd(SblDeviceCC2538::CMD_MEMORY_WRITE, pcPayload, 9)) != SBL_SUCCESS)
        {
            return retCode;        
        }

        //
        // Receive command response (ACK/NAK)
        //
        if((retCode = getCmdResponse(bSuccess, 5)) != SBL_SUCCESS)
        {
            return retCode;
        }
        if(!bSuccess)
        {
            setState(SBL_ERROR, "Device NAKed read command for address 0x%08X.\n", currAddr);
            return SBL_ERROR;
        }
    }

    //
    // Set progress
    //
    setProgress(100);

    return SBL_SUCCESS;
}


//-----------------------------------------------------------------------------
/** \brief This function writes \e unitCount words of data to device SRAM. 
 *      Source array is 8 bit wide. Parameters \e startAddress and \e unitCount 
 *      must be a a multiple of 4.
 *
 * \param[in] ui32StartAddress
 *      Start address in device.
 * \param[in] ui32UnitCount
 *      Number of bytes to write.
 * \param[in] pcData
 *      Pointer to source data.
 * \return
 *      Returns SBL_SUCCESS, ...
 */
//-----------------------------------------------------------------------------
uint32_t 
SblDeviceCC2538::writeMemory8(uint32_t ui32StartAddress, 
                              uint32_t ui32UnitCount, 
                              const char *pcData)
{
    uint32_t retCode = SBL_SUCCESS;
    bool bSuccess = false;
    char pcPayload[9];
    uint32_t recvCount = 0;
    uint32_t currAddr;

    //
    // Check input arguments
    //
    if(!addressInRam(ui32StartAddress, ui32UnitCount))
    {
        setState(SBL_ARGUMENT_ERROR, "writeMemory8(): Address range (0x%08X + %d bytes) is not in device RAM.\n", ui32StartAddress, ui32UnitCount*4);
        return SBL_ARGUMENT_ERROR;
    }
    if((ui32StartAddress & 0x03) || (ui32UnitCount & 0x03))
    {
        setState(SBL_ARGUMENT_ERROR, "writeMemory8(): Start address (0x%08X) and byte count (%d) must be a multiple of 4.\n", ui32StartAddress, ui32UnitCount);
        return SBL_ARGUMENT_ERROR;
    }

    if(!isConnected())
    {
        return SBL_PORT_ERROR;
    }

    //
    // Set progress
    //
    setProgress(0);

    for(uint32_t i = 0; i < ui32UnitCount/4; i++)
    {
        currAddr = ui32StartAddress + (i * 4);
        //
        // Build payload
        // - 4B address (MSB first)
        // - 4B data value (MSB first)
        // - 1B access width
        //
        ulToCharArray(currAddr, &pcPayload[0]);
        memcpy(&pcPayload[4], &pcData[(i * 4)], 4);
        pcPayload[8] = SBL_CC2538_ACCESS_WIDTH_4B;

        //
        // Set progress
        //
        setProgress( ((100 * i) / (ui32UnitCount / 4)) );

        //
        // Send command
        //
        if((retCode = sendCmd(SblDeviceCC2538::CMD_MEMORY_WRITE, pcPayload, 9)) != SBL_SUCCESS)
        {
            return retCode;        
        }

        //
        // Receive command response (ACK/NAK)
        //
        if((retCode = getCmdResponse(bSuccess, 5)) != SBL_SUCCESS)
        {
            return retCode;
        }
        if(!bSuccess)
        {
            setState(SBL_ERROR, "Device NAKed read command for address 0x%08X.\n", currAddr);
            return SBL_ERROR;
        }
    }

    //
    // Set progress
    //
    setProgress(100);

    return SBL_SUCCESS;
}


//-----------------------------------------------------------------------------
/** \brief This function calculates CRC over \e byteCount bytes on the device, 
 *      starting at address \e startAddress.
 *
 * \param[in] ui32StartAddress
 *      Start address in device.
 * \param[in] ui32ByteCount
 *      Number of bytes to calculate CRC32 over.
 * \param[out] pui32Crc
 *      Pointer to where checksum from device is stored.
 * \return
 *      Returns SBL_SUCCESS, ...
 */
//-----------------------------------------------------------------------------
uint32_t 
SblDeviceCC2538::calculateCrc32(uint32_t ui32StartAddress, 
                                uint32_t ui32ByteCount, uint32_t *pui32Crc)
{
    uint32_t retCode = SBL_SUCCESS;
    bool bSuccess = false;
    char pcPayload[8];
    uint32_t ui32RecvCount = 0;

    //
    // Check input arguments
    //
    if(!addressInFlash(ui32StartAddress, ui32ByteCount) &&
       !addressInRam(ui32StartAddress, ui32ByteCount))
    {
        setState(SBL_ARGUMENT_ERROR, "Specified address range (0x%08X + %d bytes) is not in device FLASH nor RAM.\n", ui32StartAddress, ui32ByteCount);
        return SBL_ARGUMENT_ERROR;
    }

    if(!isConnected())
    {
        return SBL_PORT_ERROR;
    }

    //
    // Set progress
    //
    setProgress(0);

    //
    // Build payload
    // - 4B address (MSB first)
    // - 4B byte count(MSB first)
    //
    ulToCharArray(ui32StartAddress, &pcPayload[0]);
    ulToCharArray(ui32ByteCount, &pcPayload[4]);

    //
    // Send command
    //
    if((retCode = sendCmd(SblDeviceCC2538::CMD_CRC32, pcPayload, 8)) != SBL_SUCCESS)
    {
        return retCode;        
    }

    //
    // Receive command response (ACK/NAK)
    //
    if((retCode = getCmdResponse(bSuccess, 5)) != SBL_SUCCESS)
    {
        return retCode;
    }
    if(!bSuccess)
    {
        setState(SBL_ERROR, "Device NAKed CRC32 command.\n");
        return SBL_ERROR;
    }

    //
    // Get data response
    //
    ui32RecvCount = 4;
    if((retCode = getResponseData(pcPayload, ui32RecvCount)) != SBL_SUCCESS)
    {
        sendCmdResponse(false);
        return retCode;
    }
    *pui32Crc = charArrayToUL(pcPayload);

    //
    // Send ACK/NAK to command
    //
    bool bAck = (ui32RecvCount == 4) ? true : false;
    sendCmdResponse(bAck);

    //
    // Set progress
    //
    setProgress(100);

    return SBL_SUCCESS;
}



//-----------------------------------------------------------------------------
/** \brief This function writes \e unitCount words of data to device FLASH. 
 *      Source array is 8 bit wide. Parameters \e startAddress and \e unitCount 
 *      must be a a multiple of 4. This function does not erase the flash 
 *      before writing data, this must be done using e.g. eraseFlashRange().
 *
 * \param[in] ui32StartAddress
 *      Start address in device. Must be a multiple of 4.
 * \param[in] ui32ByteCount
 *      Number of bytes to program. Must be a multiple of 4.
 * \param[in] pcData
 *      Pointer to source data.
 * \return
 *      Returns SBL_SUCCESS, ...
 */
//-----------------------------------------------------------------------------
uint32_t 
SblDeviceCC2538::writeFlashRange(uint32_t ui32StartAddress, 
                                 uint32_t ui32ByteCount, const char *pcData)
{
    uint32_t devStatus = SblDeviceCC2538::CMD_RET_UNKNOWN_CMD;
    uint32_t retCode = SBL_SUCCESS;
    uint32_t bytesLeft, dataIdx, bytesInTransfer;
    uint32_t transferNumber = 1;
    bool bIsRetry = false;
    bool bBlToBeDisabled = false;
    std::vector<tTransfer> pvTransfer;
    uint32_t ui32TotChunks = (ui32ByteCount / SBL_CC2538_MAX_BYTES_PER_TRANSFER);
    if(ui32ByteCount % SBL_CC2538_MAX_BYTES_PER_TRANSFER) ui32TotChunks++;
    uint32_t ui32CurrChunk = 0;

    //
    // Calculate BL configuration address (depends on flash size)
    //
    uint32_t ui32BlCfgAddr = getBootloaderEnableAddress();

    //
    // Calculate BL configuration buffer index
    //
    uint32_t ui32BlCfgDataIdx = ui32BlCfgAddr - ui32StartAddress;

    //
    // Is BL configuration part of buffer?
    //
    if(ui32BlCfgDataIdx <= ui32ByteCount)
    {
        if((pcData[ui32BlCfgDataIdx] & SBL_CC2538_BL_CONFIG_ENABLED_BM) == 0)
        {
            bBlToBeDisabled = true;
            setState(SBL_SUCCESS, "Warning: Bootloader will be disabled.\n");
        }
    }

    if(bBlToBeDisabled)
    {
        //
        // Split into two transfers
        //
        pvTransfer.resize(2);

        //
        // Main transfer (before lock bit)
        //
        pvTransfer[0].bExpectAck  = true;
        pvTransfer[0].startAddr   = ui32StartAddress;
        pvTransfer[0].byteCount   = (ui32BlCfgAddr - ui32StartAddress) & (~0x03);
        pvTransfer[0].startOffset = 0;

        //
        // The transfer locking the backdoor
        //
        pvTransfer[1].bExpectAck  = false;
        pvTransfer[1].startAddr   = ui32BlCfgAddr - (ui32BlCfgAddr % 4);
        pvTransfer[1].byteCount   = ui32ByteCount - pvTransfer[0].byteCount;
        pvTransfer[1].startOffset = ui32BlCfgDataIdx - (ui32BlCfgDataIdx % 4);

    }
    else
    {
        pvTransfer.resize(1);
        pvTransfer[0].bExpectAck  = true;
        pvTransfer[0].byteCount = ui32ByteCount;
        pvTransfer[0].startAddr = ui32StartAddress;
        pvTransfer[0].startOffset = 0;
    }

    //
    // For each transfer
    //
    for(uint32_t i = 0; i < pvTransfer.size(); i++)
    {
        //
        // Sanity check
        //
        if(pvTransfer[i].byteCount == 0)
        {
            continue;
        }
        
        //
        // Set progress
        //
        //setProgress(addressToPage(pvTransfer[i].startAddr));

        //
        // Send download command
        //
        if((retCode = cmdDownload(pvTransfer[i].startAddr, 
                                  pvTransfer[i].byteCount)) != SBL_SUCCESS)
        {
            return retCode;
        }

        //
        // Check status after download command
        //
        retCode = readStatus(&devStatus);
        if(retCode != SBL_SUCCESS)
        {
            setState(retCode, "Error during download initialization. Failed to read device status after sending download command.\n");
            return retCode;
        }
        if(devStatus != SblDeviceCC2538::CMD_RET_SUCCESS)
        {
            setState(SBL_ERROR, "Error during download initialization. Device returned status %d (%s).\n", devStatus, getCmdStatusString(devStatus).c_str());
            return SBL_ERROR;
        }

        //
        // Send data in chunks
        //
        bytesLeft = pvTransfer[i].byteCount;
        dataIdx   = pvTransfer[i].startOffset;
        while(bytesLeft)
        {
            //
            // Set progress
            //
            //setProgress(addressToPage(ui32StartAddress + dataIdx));
            setProgress( ((100*(++ui32CurrChunk))/ui32TotChunks) );

            //
            // Limit transfer count
            //
            bytesInTransfer = min(SBL_CC2538_MAX_BYTES_PER_TRANSFER, bytesLeft);

            //
            // Send Data command
            //
            if(retCode = cmdSendData(&pcData[dataIdx], bytesInTransfer) != SBL_SUCCESS)
            {
                setState(retCode, "Error during flash download. \n- Start address 0x%08X (page %d). \n- Tried to transfer %d bytes. \n- This was transfer %d.\n", 
                         (ui32StartAddress+dataIdx), 
                         addressToPage(ui32StartAddress+dataIdx),
                         bytesInTransfer, 
                         (transferNumber));
                return retCode;
            }

            if(pvTransfer[i].bExpectAck)
            {
                //
                // Check status after send data command
                //
                devStatus = 0;
                retCode = readStatus(&devStatus);
                if(retCode != SBL_SUCCESS)
                {
                    setState(retCode, "Error during flash download. Failed to read device status.\n- Start address 0x%08X (page %d). \n- Tried to transfer %d bytes. \n- This was transfer %d in chunk %d.\n", 
                                 (ui32StartAddress+dataIdx), 
                                 addressToPage(ui32StartAddress + dataIdx),
                                 (bytesInTransfer), (transferNumber), 
                                 (i));
                    return retCode;
                }
                if(devStatus != SblDeviceCC2538::CMD_RET_SUCCESS)
                {
                    setState(SBL_SUCCESS, "Device returned status %s\n", getCmdStatusString(devStatus).c_str());
                    if(bIsRetry)
                    {
                        //
                        // We have failed a second time. Aborting.
                        setState(SBL_ERROR, "Error retrying flash download.\n- Start address 0x%08X (page %d). \n- Tried to transfer %d bytes. \n- This was transfer %d in chunk %d.\n", 
                                 (ui32StartAddress+dataIdx), 
                                 addressToPage(ui32StartAddress + dataIdx),
                                 (bytesInTransfer), (transferNumber), 
                                 (i));
                        return SBL_ERROR;
                    }

                    //
                    // Retry to send data one more time.
                    //
                    bIsRetry = true;
                    continue;
                }
            }
            else
            {
                //
                // We're locking device and will lose access
                //
                m_bCommInitialized = false;

            }

            //
            // Update index and bytesLeft
            //
            bytesLeft -= bytesInTransfer;
            dataIdx += bytesInTransfer;
            transferNumber++;
            bIsRetry = false;
        }
    }

    return SBL_SUCCESS;
}


//-----------------------------------------------------------------------------
/** \brief This function sends the specified bootloader command.
 *
 * \param[in] ui32Cmd
 *      The command to send.
 * \param[in] pcSendData
 *      Pointer to the data to send with the command.
 * \param[in] ui32SendLen
 *      The number of bytes to send from \e pcSendData.
 * \return
 *      Returns SBL_SUCCESS, ...
 */
//-----------------------------------------------------------------------------
uint32_t 
SblDeviceCC2538::sendCmd(uint32_t ui32Cmd, const char *pcSendData/* = NULL*/, 
                         uint32_t ui32SendLen/* = 0*/)
{
    //
    // Initial checks
    //
    if(!m_pCom->isInitiated())
    { 
        return SBL_PORT_ERROR; 
    }

    unsigned char pktLen = ui32SendLen + 3; // +3 => <1b Length>, <1B checksum>, <1B cmd>
    std::vector<char> pvPkt((pktLen));
    unsigned char pktSum = generateCheckSum(ui32Cmd, pcSendData, ui32SendLen);

    //
    // Build packet
    //
    pvPkt.at(0) = pktLen;
    pvPkt.at(1) = pktSum;
    pvPkt.at(2) = (unsigned char)ui32Cmd;
    if(ui32SendLen)
    {
        memcpy(&pvPkt[3], pcSendData, ui32SendLen);
    }

    //
    // Send packet
    //
    if(m_pCom->writeBytes(&pvPkt[0], pvPkt.size()) != pvPkt.size())
    {
        setState(SBL_PORT_ERROR, "Writing to device failed (Command '%s').\n", getCmdString(ui32Cmd).c_str());
        return SBL_PORT_ERROR;
    }
    

    //
    // Empty and deallocate vector
    //
    pvPkt.clear();
    std::vector<char>().swap(pvPkt);    
        
    return SBL_SUCCESS;
}


//-----------------------------------------------------------------------------
/** \brief This function initializes connection to the CC2538 device. 
 *
 * \param[in] bSetXosc
 *      If true, try to enable device XOSC.
 * \return
 *      Returns SBL_SUCCESS, ...
 */
//-----------------------------------------------------------------------------
uint32_t
SblDeviceCC2538::initCommunication(bool bSetXosc)
{
    bool bSuccess, bBaudSetOk;
    int retCode = SBL_ERROR;

    if(!m_pCom->isInitiated())
    {
        setState(SBL_PORT_ERROR, "COM port not initiated.\n");
        return SBL_PORT_ERROR;
    }

    //
    // Send dummy command to see if device is already initialized at
    // this baud rate.
    //
    if(sendCmd(0) != SBL_SUCCESS)
    {
        return SBL_ERROR;
    }

    //
    // Do we get a response (ACK/NAK)?
    //
    bSuccess = false;
    if(getCmdResponse(bSuccess, SBL_DEFAULT_RETRY_COUNT, true) != SBL_SUCCESS)
    {
        //
        // No response received. Try auto baud
        //
        if(retCode = sendAutoBaud(bBaudSetOk) != SBL_SUCCESS)
        {
            return retCode;
        }
    }

    if(bSetXosc)
    {
        setState(SBL_SUCCESS, "Trying to set device XOSC.\n");
        //
        // Try to enable XOSC
        //
        if((retCode = setXosc()) != SBL_SUCCESS)
        {
            //
            // setXosc returned error
            //
            setState(retCode, "Failed to activate device XOSC.\n");
            return retCode;
        }

        //
        // Send dummy command
        //
        bSuccess = false;
        sendCmd(0);
        if(retCode = getCmdResponse(bSuccess, SBL_DEFAULT_RETRY_COUNT, true) != SBL_SUCCESS)
        {
            //
            // Send auto baud again
            //
            if((retCode = sendAutoBaud(bBaudSetOk)) != SBL_SUCCESS)
            {
                setState((tSblStatus)retCode, "Auto baud detection failed after starting XOSC.\n");
                return retCode;
            }
            setState(SBL_SUCCESS, "Device XOSC activated.\n");
        }
    }

    m_bCommInitialized = true;
    return SBL_SUCCESS;
}


//-----------------------------------------------------------------------------
/** \brief This function returns a string representation of the \e ui32Cmd
 *      command.
 *
 * \param[out] ui32Cmd
 *      The serial bootloader command.
 * \return
 *      Returns std::string with name of device command.
 */
//-----------------------------------------------------------------------------
std::string
SblDeviceCC2538::getCmdString(uint32_t ui32Cmd)
{
    switch(ui32Cmd)
    {
    case SblDeviceCC2538::CMD_PING:         return "CMD_PING"; break;
    case SblDeviceCC2538::CMD_CRC32:        return "CMD_CRC32"; break;
    case SblDeviceCC2538::CMD_DOWNLOAD:     return "CMD_DOWNLOAD"; break;
    case SblDeviceCC2538::CMD_ERASE:        return "CMD_ERASE"; break;
    case SblDeviceCC2538::CMD_GET_CHIP_ID:  return "CMD_GET_CHIP_ID"; break;
    case SblDeviceCC2538::CMD_GET_STATUS:   return "CMD_GET_STATUS"; break;
    case SblDeviceCC2538::CMD_MEMORY_READ:  return "CMD_MEMORY_READ"; break;
    case SblDeviceCC2538::CMD_MEMORY_WRITE: return "CMD_MEMORY_WRITE"; break;
    case SblDeviceCC2538::CMD_RESET:        return "CMD_RESET"; break;
    default: return "Unknown command"; break;
    }
}


//-----------------------------------------------------------------------------
/** \brief This function returns a string representation of the 
 *      \e ui32Status serial bootloader status value.
 *
 * \param[out] ui32Status
 *      The serial bootloader status value.
 * \return
 *      Returns std::string of device status.
 */
//-----------------------------------------------------------------------------
std::string
SblDeviceCC2538::getCmdStatusString(uint32_t ui32Status)
{
    switch(ui32Status)
    {
    case SblDeviceCC2538::CMD_RET_FLASH_FAIL:   return "FLASH_FAIL"; break;
    case SblDeviceCC2538::CMD_RET_INVALID_ADR:  return "INVALID_ADR"; break;
    case SblDeviceCC2538::CMD_RET_INVALID_CMD:  return "INVALID_CMD"; break;
    case SblDeviceCC2538::CMD_RET_SUCCESS:      return "SUCCESS"; break;
    case SblDeviceCC2538::CMD_RET_UNKNOWN_CMD:  return "UNKNOWN_CMD"; break;
    default: return "Unknown status"; break;
    }
}


//-----------------------------------------------------------------------------
/** \brief This function sends the CC2538 download command and handles the
 *      device response. \e ui32ByteCount must be a multiple of 4.
 *
 * \param[in] ui32Address
 *      The start address in CC2538 flash.
 * \param[in] ui32ByteCount
 *      The total number of bytes to program on the device.
 *
 * \return
 *      Returns SBL_SUCCESS if command and response was successful.
 */
//-----------------------------------------------------------------------------
uint32_t 
SblDeviceCC2538::cmdDownload(uint32_t ui32Address, uint32_t ui32Size)
{
    int retCode = SBL_SUCCESS;
    bool bSuccess = false;


    //
    // Check input arguments
    //
    if(!addressInFlash(ui32Address, ui32Size))
    {
        setState(SBL_ARGUMENT_ERROR, "Flash download: Address range (0x%08X + %d bytes) is not in device FLASH nor RAM.\n", ui32Address, ui32Size);
        return SBL_ARGUMENT_ERROR;
    }
    if(ui32Size & 0x03)
    {
        setState(SBL_ARGUMENT_ERROR, "Flash download: Byte count must be a multiple of 4\n");
        return SBL_ARGUMENT_ERROR;
    }

    //
    // Generate payload
    // - 4B Program address
    // - 4B Program size
    //
    char pcPayload[8];
    ulToCharArray(ui32Address, &pcPayload[0]);
    ulToCharArray(ui32Size, &pcPayload[4]);

    //
    // Send command
    //
    if((retCode = sendCmd(SblDeviceCC2538::CMD_DOWNLOAD, pcPayload, 8)) != SBL_SUCCESS)
    {
        return retCode;        
    }

    //
    // Receive command response (ACK/NAK)
    //
    if((retCode = getCmdResponse(bSuccess)) != SBL_SUCCESS)
    {
        return retCode;
    }

    //
    // Return command response
    //
    return (bSuccess) ? SBL_SUCCESS : SBL_ERROR;
}


//-----------------------------------------------------------------------------
/** \brief This function sends the CC2538 SendData command and handles the
 *      device response. \e ui32ByteCount is limited by 
 *      SBL_CC2538_MAX_BYTES_PER_TRANSFER.
 *
 * \param[in] pcData
 *      Pointer to the data to send.
 * \param[in] ui32ByteCount
 *      The number of bytes to send.
 *
 * \return
 *      Returns SBL_SUCCESS if command and response was successful.
 */
//-----------------------------------------------------------------------------
uint32_t
SblDeviceCC2538::cmdSendData(const char *pcData, uint32_t ui32ByteCount)
{   
    uint32_t retCode = SBL_SUCCESS;
    bool bSuccess = false;

    //
    // Check input arguments
    //
    if(ui32ByteCount > SBL_CC2538_MAX_BYTES_PER_TRANSFER)
    {
        setState(SBL_ERROR, "Error: Byte count (%d) exceeds maximum transfer size %d.\n", ui32ByteCount, SBL_CC2538_MAX_BYTES_PER_TRANSFER);
        return SBL_ERROR;
    }

    //
    // Send command
    //
    if((retCode = sendCmd(SblDeviceCC2538::CMD_SEND_DATA, pcData, ui32ByteCount)) != SBL_SUCCESS)
    {
        return retCode;        
    }

    //
    // Receive command response (ACK/NAK)
    //
    if((retCode = getCmdResponse(bSuccess, 3)) != SBL_SUCCESS)
    {
        return retCode;
    }
    if(!bSuccess)
    {
        return SBL_ERROR;
    }

    return SBL_SUCCESS;
}


//-----------------------------------------------------------------------------
/** \brief This function returns the FLASH address of the bootloader enable
*      configuration.
*
* \return
*      Returns true if the address/range is within the device RAM.
*/
//-----------------------------------------------------------------------------
uint32_t SblDeviceCC2538::getBootloaderEnableAddress()
{
    return (SBL_CC2538_FLASH_START_ADDRESS + getFlashSize() - getPageEraseSize() + SBL_CC2538_BL_CONFIG_PAGE_OFFSET);
}

//-----------------------------------------------------------------------------
/** \brief This function sends the CC2538 SetXosc command and handles the 
 *      response from the device.
 *
 * \return
 *      Returns SBL_SUCCESS if command and response was successful.
 */
//-----------------------------------------------------------------------------
uint32_t 
SblDeviceCC2538::setXosc()
{
    int retCode = SBL_SUCCESS;
    bool bSuccess = false;

    //
    // Send command
    //
    if((retCode = sendCmd(SblDeviceCC2538::CMD_SET_XOSC)) != SBL_SUCCESS)
    {
        return retCode;        
    }

    //
    // Receive command response (ACK/NAK)
    //
    if((retCode = getCmdResponse(bSuccess, 5, true)) != SBL_SUCCESS)
    {
        return retCode;
    }
    if(!bSuccess)
    {
        return SBL_ERROR;
    }

    return SBL_SUCCESS;
}


//-----------------------------------------------------------------------------
/** \brief This function returns the address within which the specified
 *      \e ui32Address is  located.
 *
 * \return
 *      Returns the flash page within which an address is located.
 */
//-----------------------------------------------------------------------------
uint32_t
SblDeviceCC2538::addressToPage(uint32_t ui32Address)
{
    return ((ui32Address - SBL_CC2538_FLASH_START_ADDRESS) /                  \
            SBL_CC2538_PAGE_ERASE_SIZE);
}


//-----------------------------------------------------------------------------
/** \brief This function checks if the specified \e ui32StartAddress (or range)
 *      is located within the device RAM area.
 *
 * \return
 *      Returns true if the address/range is within the device RAM.
 */
//-----------------------------------------------------------------------------
bool 
SblDeviceCC2538::addressInRam(uint32_t ui32StartAddress, 
                              uint32_t ui32ByteCount/* = 1*/)
{
    uint32_t ui32EndAddr = ui32StartAddress + ui32ByteCount;

    if(ui32StartAddress < SBL_CC2538_RAM_START_ADDRESS)
    {
        return false;
    }
    if(ui32EndAddr > (SBL_CC2538_RAM_START_ADDRESS + getRamSize()))
    {
        return false;
    }
    return true;
}


//-----------------------------------------------------------------------------
/** \brief This function checks if the specified \e ui32StartAddress (or range)
 *      is located within the device FLASH area.
 *
 * \return
 *      Returns true if the address/range is within the device FLASH.
 */
//-----------------------------------------------------------------------------
bool
SblDeviceCC2538::addressInFlash(uint32_t ui32StartAddress, 
                                         uint32_t ui32ByteCount/* = 1*/)
{
    uint32_t ui32EndAddr = ui32StartAddress + ui32ByteCount;

    if(ui32StartAddress < SBL_CC2538_FLASH_START_ADDRESS)
    {
        return false;
    }
    if(ui32EndAddr > (SBL_CC2538_FLASH_START_ADDRESS + getFlashSize()))
    {
        return false;
    }
    
    return true;
}
