AVED Programming Control (APC) Proxy Driver

Overview

The APC proxy driver binds in the FAL provided in initialization. Internally, it also creates a number of resources including two mutexes for protection, a mailbox to handle asynchronous responses, and a task to handle the interaction with the FAL.

The APC task will:

  • Pend to its mailbox, and handle the incoming messages.

  • Download new images to flash and update metadata.

  • Copy images from one partition to another.

  • Select partition to boot from next.

The API consists of a number of functions to download/copy an image to a location in flash memory, select boot partition and receive Flash Partition Table (FPT) data. The flash APIs will post an internal message with the required data onto the mailbox. The APC proxy task will service this mailbox and make the appropriate calls to the FAL to download/copy an image or select a new boot partition.

The API also provides two debug functions to display and clear of the stat/error counters.

Enums

APC proxy driver event IDs.

APC_PROXY_DRIVER_EVENTS

/**
 * @enum    APC_PROXY_DRIVER_EVENTS
 * @brief   Events raised by this proxy driver
 */
typedef enum APC_PROXY_DRIVER_EVENTS
{
    APC_PROXY_DRIVER_E_DOWNLOAD_STARTED = 0,
    APC_PROXY_DRIVER_E_DOWNLOAD_COMPLETE,
    APC_PROXY_DRIVER_E_DOWNLOAD_BUSY,
    APC_PROXY_DRIVER_E_DOWNLOAD_FAILED,
    APC_PROXY_DRIVER_E_FPT_UPDATE,
    APC_PROXY_DRIVER_E_COPY_STARTED,
    APC_PROXY_DRIVER_E_COPY_COMPLETE,
    APC_PROXY_DRIVER_E_COPY_BUSY,
    APC_PROXY_DRIVER_E_COPY_FAILED,
    APC_PROXY_DRIVER_E_PARTITION_SELECTED,
    APC_PROXY_DRIVER_E_PARTITION_SELECTION_FAILED,

    MAX_APC_PROXY_DRIVER_EVENTS

} APC_PROXY_DRIVER_EVENTS;

Boot device IDs.

APC_BOOT_DEVICES

/**
 * @enum    APC_BOOT_DEVICES
 * @brief   Enumeration of boot devices available
 */
typedef enum
{
    APC_BOOT_DEVICE_PRIMARY = 0,
    APC_BOOT_DEVICE_SECONDARY,

    MAX_APC_BOOT_DEVICES

} APC_BOOT_DEVICES;

Structs

Device FPT headers.

APC_PROXY_DRIVER_FPT_HEADER

/**
 * @struct  APC_PROXY_DRIVER_FPT_HEADER
 * @brief   Structure to hold the FPT Header
 */
typedef struct APC_PROXY_DRIVER_FPT_HEADER
{
    uint32_t    ulMagicNum;
    uint8_t     ucFptVersion;
    uint8_t     ucFptHeaderSize;
    uint8_t     ucEntrySize;
    uint8_t     ucNumEntries;

} APC_PROXY_DRIVER_FPT_HEADER;

Device FPT partitions.

APC_PROXY_DRIVER_FPT_PARTITION

/**
 * @struct  APC_PROXY_DRIVER_FPT_PARTITION
 * @brief   Structure to hold a single FPT partition
 */
typedef struct APC_PROXY_DRIVER_FPT_PARTITION
{
    uint32_t    ulPartitionType;
    uint32_t    ulPartitionBaseAddr;
    uint32_t    ulPartitionSize;

} APC_PROXY_DRIVER_FPT_PARTITION;

API

Initialise the APC proxy driver

This will open the FAL using the provided handle and make use of the OSAL to create two mutexes, a mailbox, and the proxy task.

iAPC_Initialise

/**
 * @brief   Main initialisation point for the APC Proxy Driver
 *
 * @param   ucProxyId       Unique ID for this Proxy driver
 * @param   pxPrimaryFwIf   Handle to the primary Firmware Interface to use
 * @param   pxSecondaryFwIf Handle to the secondary Firmware Interface to use
 * @param   ulTaskPrio      Priority of the Proxy driver task (if RR disabled)
 * @param   ulTaskStack     Stack size of the Proxy driver task
 *
 * @return  OK          Proxy driver initialised correctly
 *          ERROR       Proxy driver not initialised, or was already initialised
 *
 * @note    A Primary Firmware Interface handle must be passed to iAPC_Initialise,
 *          the secondary Firmware Interface handle however is optional
 *          and can be set to NULL.
 *
 */
int iAPC_Initialise( uint8_t ucProxyId, FW_IF_CFG *pxPrimaryFwIf, FW_IF_CFG *pxSecondaryFwIf, uint32_t ulTaskPrio, uint32_t ulTaskStack );

Bind Callbacks

This API can be used to bind into a callback to be notified of events generated by the APC proxy using the EVL library. The current supported events are:

  • APC_PROXY_DRIVER_E_DOWNLOAD_STARTED

  • APC_PROXY_DRIVER_E_DOWNLOAD_COMPLETE

  • APC_PROXY_DRIVER_E_DOWNLOAD_BUSY

  • APC_PROXY_DRIVER_E_DOWNLOAD_FAILED

  • APC_PROXY_DRIVER_E_COPY_STARTED

  • APC_PROXY_DRIVER_E_COPY_COMPLETE

  • APC_PROXY_DRIVER_E_COPY_BUSY

  • APC_PROXY_DRIVER_E_COPY_FAILED

  • APC_PROXY_DRIVER_E_PARTITION_SELECTED

  • APC_PROXY_DRIVER_E_PARTITION_SELECTION_FAILED


iAPC_BindCallback

/**
 * @brief   Bind into this proxy driver
 *
 * @param   pxCallback  Callback to bind into the proxy driver
 *
 * @return  OK          Callback successfully bound
 *          ERROR       Callback not bound
 *
 */
int iAPC_BindCallback( EVL_CALLBACK *pxCallback );

Download Image

This will post a message (APC_MSG_TYPE_DOWNLOAD_PDI) onto the APC mailbox to be handled within the internal APC task to download an image to a location in NV memory.

iAPC_DownloadImage

/**
 * @brief   Download an image to a location in NV memory
 *
 * @param   pxSignal     Current event occurance (used for tracking)
 * @param   xBootDevice  Target boot device
 * @param   iPartition   The partition in the FPT to store this image in
 * @param   ulSrcAddr    Address (in RAM) to read the image from
 * @param   ulImageSize  Size of image (in bytes)
 * @param   usPacketNum  Image packet number
 * @param   usPacketSize Size of image packet (in KB)
 *
 * @return  OK           Image downloaded successfully
 *          ERROR        Image not downloaded successfully
 *
 */
int iAPC_DownloadImage( EVL_SIGNAL *pxSignal, APC_BOOT_DEVICES xBootDevice, int iPartition, uint32_t ulSrcAddr,
                        uint32_t ulImageSize, uint16_t usPacketNum, uint16_t usPacketSize );

Update FPT

This will post a message (APC_MSG_TYPE_DOWNLOAD_PDI) onto the APC mailbox to be handled within the internal APC task to download an image to a location in NV memory and update the FPT.

iAPC_UpdateFpt

/**
 * @brief   Download an image with an FPT to a location in NV memory
 *
 * @param   pxSignal     Current event occurance (used for tracking)
 * @param   xBootDevice  Target boot device
 * @param   ulSrcAddr    Address (in RAM) to read the image from
 * @param   ulImageSize  Size of image (in bytes)
 * @param   usPacketNum  Image packet number
 * @param   usPacketSize Size of image packet (in KB)
 * @param   iLastPacket  Boolean indicating if this is the last data packet
 *
 * @return  OK           Image downloaded successfully
 *          ERROR        Image not downloaded successfully
 *
 */
int iAPC_UpdateFpt( EVL_SIGNAL *pxSignal, APC_BOOT_DEVICES xBootDevice, uint32_t ulSrcAddr, uint32_t ulImageSize,
                    uint16_t usPacketNum, uint16_t usPacketSize, int iLastPacket );

Copy Image

This will post a message (APC_MSG_TYPE_COPY_PDI) onto the APC mailbox to be handled within the internal APC task to copy an image from one partition to another.

iAPC_CopyImage

/**
 * @brief   Copy an image from one partition to another
 *
 * @param   pxSignal        Current event occurance (used for tracking)
 * @param   xSrcBootDevice  Target boot device to copy from
 * @param   iSrcPartition   The partition in the FPT to copy this image from
 * @param   xDestBootDevice Target boot device to copy to
 * @param   iDestPartition  The partition in the FPT to copy this image to
 * @param   ulCpyAddr       Address (in RAM) to copy the source partition to before writing it
 * @param   ulAllocatedSize Maximum size available to copy
 *
 * @return  OK          Image copied successfully
 *          ERROR       Image not copied successfully
 *
 */
int iAPC_CopyImage( EVL_SIGNAL *pxSignal, APC_BOOT_DEVICES xSrcBootDevice, int iSrcPartition,
                    APC_BOOT_DEVICES xDestBootDevice, int iDestPartition, uint32_t ulCpyAddr, uint32_t ulAllocatedSize );

Set Next Partition

This will post a message (APC_MSG_TYPE_PARTITION_SELECT) onto the APC mailbox to be handled within the internal APC task to select which partition to boot from.

iAPC_SetNextPartition

/**
 * @brief   Select which partition to boot from
 *
 * @param   pxSignal    Current event occurance (used for tracking)
 * @param   iPartition  The partition to boot from on the next reset
 *
 * @return  OK          Partition successfully selected
 *          ERROR       Partition not selected
 */
int iAPC_SetNextPartition( EVL_SIGNAL *pxSignal, int iPartition );

Enable Hot Reset

This will post a message (APC_MSG_TYPE_ENABLE_HOT_RESET) onto the APC mailbox to be handled within the internal APC task to enable the hot reset capability.

iAPC_EnableHotReset

/**
 * @brief   Enable the hot reset capability
 *
 * @param   pxSignal    Current event occurance (used for tracking)
 *
 * @return  OK          Hot reset successfully enabled
 *          ERROR       Hot reset not enabled
 */
int iAPC_EnableHotReset( EVL_SIGNAL *pxSignal );

Get FPT Header

This will copy the locally stored Flash Partition Table (FPT) header data into the passed FPT header struct. This process is mutex protected.

iAPC_GetFptHeader

/**
 * @brief   Get the Flash Partition Table (FPT) Header
 *
 * @param   xBootDevice     Target boot device
 * @param   pxFptHeader     Pointer to the FPT header data
 *
 * @return  OK              FPT header retrieved successfully
 *          ERROR           FPT header not retrieved successfully
 *
 */
int iAPC_GetFptHeader( APC_BOOT_DEVICES xBootDevice, APC_PROXY_DRIVER_FPT_HEADER *pxFptHeader );

Get FPT Partition

This will copy the locally stored Flash Partition Table (FPT) partition data into the passed FPT partition struct. This process is mutex protected.

iAPC_GetFptPartition

/**
 * @brief   Get a Flash Partition Table (FPT) Partition
 *
 * @param   xBootDevice     Target boot device
 * @param   iPartition      Index of partition to retrieve (0 is the 1st partition)
 * @param   pxFptPartition  Pointer to the FPT partition data
 *
 * @return  OK              FPT partition retrieved successfully
 *          ERROR           FPT partition not retrieved successfully
 *
 */
int iAPC_GetFptPartition( APC_BOOT_DEVICES xBootDevice, int iPartition, APC_PROXY_DRIVER_FPT_PARTITION *pxFptPartition );

Clear Statistics

Debug function used to clear the all statistics counters back to zero.

iAPC_ClearStatistics

/**
 * @brief   Clear all the stats in the proxy driver
 *
 * @return  OK          Stats cleared successfully
 *          ERROR       Stats not cleared successfully
 *
 */
int iAPC_ClearStatistics( void );

Get State

Gets current state of APC proxy driver

iAPC_GetState

/**
 * @brief   Gets the current state of the proxy driver
 *
 * @param   pxState         Pointer to the state
 *
 * @return  OK              If successful
 *          ERROR           If not successful
 */
int iAPC_GetState( MODULE_STATE *pxState );

Sequence Diagrams

APC Proxy Initialization

Two APC API functions are called from the AMC main task (iAPC_Initialise and iAPC_BindCallback), in order to initialize the proxy.

iAPC_Initialise will call into the FAL to open with the provided handle, create two shared proxy mutexes, create a proxy mailbox and create the proxy task.

iAPC_BindCallback will bind the appropriate top-level callback function.

image1

APC Proxy Task

The Task within APC has a number of responsibilities:

  • Pend to its mailbox, and handle the incoming messages.

  • Download new image to flash and update metadata.

  • Copy image from one partition to another.

  • Select partition to boot from next.

The sequence flow diagram below outline the top-level functionality of the APC proxy task. Some complexity has been hidden within local functions, namely iDownloadImage(), iCopyImage() and iSelectPartition().

image2

Examples

Initialize Driver

This function should only be called once. It requires an unique ID for the proxy, used for signaling new events from the proxy, along with a handle to a FW_IF (already created and initialized), proxy driver task priority and stack size.

iAPC_Initialise Example

if( OK == iAPC_Initialise( AMC_EVENT_UNIQUE_ID_APC, &xPrimaryIf, &xSecondaryIf, AMC_TASK_PRIO_DEFAULT, AMC_APC_TASK_STACK ) )
{
    AMC_PRINTF( "APC Proxy Driver initialised\r\n" );
}
else
{
    AMC_PRINTF( "Error initialising APC Proxy Driver\r\n" );
}

Register For Callback

Define a function based on the function pointer prototype and bind in using the API.

iAPC_BindCallback Example

/* Define a callback to handle the events */
static int iApcCallback( EVL_SIGNAL *pxSignal )
{
    int iStatus = ERROR;

    if( ( NULL != pxSignal ) && ( AMC_EVENT_UNIQUE_ID_APC == pxSignal->ucModule ) )
    {
        switch( pxSignal->ucEventType )
        {
            case APC_PROXY_DRIVER_E_DOWNLOAD_STARTED:
            case APC_PROXY_DRIVER_E_DOWNLOAD_COMPLETE:
            case APC_PROXY_DRIVER_E_DOWNLOAD_FAILED:
            case APC_PROXY_DRIVER_E_DOWNLOAD_BUSY:
            case APC_PROXY_DRIVER_E_COPY_STARTED:
            case APC_PROXY_DRIVER_E_COPY_COMPLETE:
            case APC_PROXY_DRIVER_E_COPY_FAILED:
            case APC_PROXY_DRIVER_E_COPY_BUSY:
            case APC_PROXY_DRIVER_E_PARTITION_SELECTED:
            case APC_PROXY_DRIVER_E_PARTITION_SELECTION_FAILED:
                /* TODO: handle events */
                iStatus = OK;
                break;

            default:
                break;
        }
    }

    return iStatus;
}


/* Bind into the callback during the application initialisation */
if( OK == iAPC_BindCallback( &iApcCallback ) )
{
    AMC_PRINTF( "APC Proxy Driver initialised and bound\r\n" );
}
else
{
    AMC_PRINTF( "Error binding to Proxy Driver\r\n" );
}

Download image

Example of downloading an image to flash.

iAPC_DownloadImage Example

int iInstance         = 0; /* set to desired request instance */
int iPartition        = 0; /* set to desired partition number */
int iImageSize        = 0; /* set to desired image size (bytes) */
uint32_t ulSrcAddr    = 0; /* set to desired source (RAM) address */
uint16_t usPacketNum  = 0; /* set to desired packet number */
uint16_t usPacketSize = 0; /* set to desired packet size */
APC_BOOT_DEVICES xBootDev = APC_BOOT_DEVICE_PRIMARY;
EVL_SIGNAL xSignal = { 0 };
xSignal.ucInstance = iInstance;

if( OK != iAPC_DownloadImage( &xSignal, xBootDev, iPartition, ulSrcAddr, ( uint32_t )iImageSize, usPacketNum, usPacketSize ) )
{
    APC_DBG_PRINTF( "Error writing %d bytes to partition %d\r\n", iImageSize, iPartition );
}
else
{
    APC_DBG_PRINTF( "%d bytes written from 0x%08X to partition %d\r\n",
                    iImageSize, ulSrcAddr, iPartition );
}

Copy image

Example of copying an image to flash.

iAPC_CopyImage Example

int iInstance      = 0; /* set to desired request instance */
int iSrcPartition  = 0; /* set to desired source partition number */
int iDestPartition = 0; /* set to desired destination partition number */
int iImageSize     = 0; /* set to desired image size (max num bytes) */
uint32_t ulSrcAddr = 0; /* set to desired source (RAM) address */
APC_BOOT_DEVICES xBootDev = APC_BOOT_DEVICE_PRIMARY;
EVL_SIGNAL xSignal = { 0 };

xSignal.ucInstance = iInstance;

if( OK != iAPC_CopyImage( &xSignal,  xBootDev, iSrcPartition, iDestPartition, ulSrcAddr, ( uint32_t )iImageSize ) )
{
    APC_DBG_PRINTF( "Error copying partition %d partition %d\r\n", iSrcPartition, iDestPartition );
}
else
{
    APC_DBG_PRINTF( "Partition %d copied to partition %d\r\n",
                    iSrcPartition, iDestPartition );
}

Sets

Set next partition

Example of selecting the next boot partition.

iAPC_SetNextPartition Example

int iInstance  = 0; /* set to desired request instance */
int iPartition = 0; /* set to desired partition number */

EVL_SIGNAL xSignal = { 0 };
xSignal.ucInstance = iInstance;

if( OK != iAPC_SetNextPartition( &xSignal, iPartition ) )
{
    APC_DBG_PRINTF( "Error selecting partition %d\r\n", iPartition );
}
else
{
    APC_DBG_PRINTF( "Selected partition %d\r\n", iPartition );
}

Enable hot reset

Example of enabling hot rest capability.

iAPC_EnableHotReset Example

int iInstance  = 0; /* set to desired request instance */

EVL_SIGNAL xSignal = { 0 };
xSignal.ucInstance = iInstance;

if( OK != iAPC_EnableHotReset( &xSignal ) )
{
    PLL_DAL( APC_DBG_NAME, "Error enabling hot reset\r\n" );
}
else
{
    PLL_DAL( APC_DBG_NAME, "Hot reset enabled\r\n" );
}

Gets

Get FPT header

Example of retrieving the FPT header.

iAPC_GetFptHeader Example

APC_PROXY_DRIVER_FPT_HEADER xFptHeader = { 0 };
APC_BOOT_DEVICES xBootDev = APC_BOOT_DEVICE_PRIMARY;

if( OK != iAPC_GetFptHeader(  xBootDev, &xFptHeader ) )
{
    APC_DBG_PRINTF( "Error retrieving FPT header\r\n" );
}
else
{
    APC_DBG_PRINTF( "======================================================================\r\n" );
    APC_DBG_PRINTF( "FPT header:\r\n" );
    APC_DBG_PRINTF( "\tMagic number . . . . . : 0x%08X\r\n", xFptHeader.ulMagicNum );
    APC_DBG_PRINTF( "\tFPT version. . . . . . : 0x%02X\r\n", xFptHeader.ucFptVersion );
    APC_DBG_PRINTF( "\tFPT header size. . . . : 0x%02X\r\n", xFptHeader.ucFptHeaderSize );
    APC_DBG_PRINTF( "\tEntry size . . . . . . : 0x%02X\r\n", xFptHeader.ucEntrySize );
    APC_DBG_PRINTF( "\tNum entries. . . . . . : 0x%02X\r\n", xFptHeader.ucNumEntries );
    APC_DBG_PRINTF( "======================================================================\r\n" );
}

Get FPT partition

Example of retrieving an FPT partition.

iAPC_GetFptPartition Example

int iPartition = 0; /* set to desired partition number */
APC_PROXY_DRIVER_FPT_PARTITION xFptPartition = { 0 };
APC_BOOT_DEVICES xBootDev = APC_BOOT_DEVICE_PRIMARY;

if( OK != iAPC_GetFptPartition( xBootDev, iPartition, &xFptPartition ) )
{
    APC_DBG_PRINTF( "Error retrieving FPT Partition %d\r\n", iPartition );
}
else
{
    APC_DBG_PRINTF( "======================================================================\r\n" );
    APC_DBG_PRINTF( "FPT partition %d:\r\n", iPartition );
    APC_DBG_PRINTF( "\tPartition type . . . . : 0x%08X\r\n", xFptPartition.ulPartitionType );
    APC_DBG_PRINTF( "\tPartition base address : 0x%08X\r\n", xFptPartition.ulPartitionBaseAddr );
    APC_DBG_PRINTF( "\tPartition size . . . . : 0x%08X\r\n", xFptPartition.ulPartitionSize );
    APC_DBG_PRINTF( "======================================================================\r\n" );
}

Page Revision: v. 32