/*****************************************************************************
 * Copyright (c) 2006 Rowley Associates Limited.                             *
 *                                                                           *
 * This file may be distributed under the terms of the License Agreement     *
 * provided with this software.                                              *
 *                                                                           *
 * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING THE   *
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *
 *****************************************************************************/

#ifndef libmem_loader_h
#define libmem_loader_h

/*! \file libmem_loader.h
 *
 *  The main header file for LIBMEM loaders.
 *
 *  This header file contains all the definitions and declarations for writing
 *  loader programs that use the LIBMEM library.
 */

/*! \brief
 *    Start up a LIBMEM loader that uses direct RPC (remote procedure calls).
 *
 *  \param comm_buffer_start
 *    A pointer to the start of an area of RAM that can be used by the host to
 *    store data passed to the remotely called libmem functions.
 *
 *  \param comm_buffer_end
 *    A pointer to the last byte of the of an area of RAM that can be used by
 *    the host to store data passed to the remotely called libmem functions.
 *
 *  Example:
 *
 *  \code
 *  static unsigned char buffer[256];
 *
 *  int main(void)
 *  {
 *    uint8_t *flash1_start = (uint8_t *)0x10000000;
 *    const int flash1_max_geometry_regions = 4;
 *    libmem_driver_handle_t flash1_handle;
 *    libmem_geometry_t flash1_geometry[flash1_max_geometry_regions];
 *    libmem_flash_info_t flash1_info;
 *
 *    // Register FLASH driver.
 *    libmem_register_cfi_driver(&flash1_handle, 
 *                                flash1_start,
 *                                flash1_geometry,
 *                                flash1_max_geometry_regions, 
 *                                &flash1_info);
 *
 *    // Run the loader 
 *    libmem_rpc_loader_start(buffer, buffer + sizeof(buffer) - 1);
 *
 *    return 0;
 *  }
 *  \endcode
 *
 *  This function starts up a LIBMEM loader that uses direct remote procedure
 *  calls of the LIBMEM library. This form of loader should run on all ARM
 *  targets.
 *
 *  The advantage of this loader mechanism is that as it uses direct remote 
 *  procedure calls and therefore has no server code saving a significant 
 *  amount of memory. It works by the host locating the addresses of the
 *  LIBMEM functions in memory by examining the symbols in the loader's
 *  binary file and then calling them directly using the debug interface.
 *
 *  A communication buffer is required to store the parameters passed
 *  to the LIBMEM functions, this buffer is specified using the
 *  \a comm_buffer_start and anf \a comm_buffer_end parameters. The
 *  buffer must be at least 8 bytes in length, however you will find
 *  the bigger the buffer is the more performant the loader will be
 *  as less RPC calls will required.
 *
 *  The host loader application adapts how it carries out the download
 *  by the set of LIBMEM functions that are linked into the loader
 *  application. The only two required functions are \a libmem_write()
 *  and \a libmem_erase(), \a libmem_unlock() is only required if
 *  the erase or write functions return a \a LIBMEM_STATUS_LOCKED
 *  result. Everything else can be done by accessing memory directly
 *  however you will get a performance increase when verifying
 *  if you link in \a libmem_crc32(). If any of the memory programmed
 *  by the LIBMEM drivers cannot be accessed directly you will also
 *  need to link in \a libmem_read(), note that if all memory can be
 *  accessed directly you should not link this in as using this
 *  function will reduce performance.
 *
 *  As the loader application usually makes no direct calls to the LIBMEM
 *  functions they will by default be discarded by the linker, you therefore
 *  need to make sure the required LIBMEM functions are linked into your
 *  loader using the "Linker | Keep Symbols" project property.
 *
 *  To use this form of loader the "Target | Loader File Type" project
 *  property must be set to "LIBMEM RPC Loader".
 *
 *  Optional parameters can be passed to the loader using CrossStudio's 
 *  "Target | Loader Parameter" project property which holds a 32 bit 
 *  integer value. When using an RPC loader this value is passed in 
 *  register R0 as the loader starts up.
 */
void libmem_rpc_loader_start(void *comm_buffer_start, void *comm_buffer_end);

/*! \brief
 *    Start up a LIBMEM loader that uses remote procedure calls via the
 *    ARM's debug comms channel.
 *
 *  \param comm_buffer_start
 *    A pointer to the start of an area of RAM that can be used by the host
 *    to store data passed to the remotely called libmem functions.
 *
 *  \param comm_buffer_end
 *    A pointer to the last byte of the of an area of RAM that can be used by
 *    the host to store data passed to the remotely called libmem functions.
 *
 *  Example:
 *
 *  \code
 *  static unsigned char buffer[256];
 *
 *  int main(void)
 *  {
 *    uint8_t *flash1_start = (uint8_t *)0x10000000;
 *    const int flash1_max_geometry_regions = 4;
 *    libmem_driver_handle_t flash1_handle;
 *    libmem_geometry_t flash1_geometry[flash1_max_geometry_regions];
 *    libmem_flash_info_t flash1_info;
 *
 *    // Register FLASH driver.
 *    libmem_register_cfi_driver(&flash1_handle, 
 *                                flash1_start,
 *                                flash1_geometry,
 *                                flash1_max_geometry_regions, 
 *                                &flash1_info);
 *
 *    // Run the loader 
 *    libmem_dcc_rpc_loader_start(buffer, buffer + sizeof(buffer) - 1);
 *
 *    return 0;
 *  }
 *  \endcode
 *
 *  This function starts up a LIBMEM loader that uses remote procedure calls
 *  of the LIBMEM library executed via the ARM's debug comms channel.
 *  This form of loader will only run on ARM7 and ARM9s with the debug comms
 *  channel. It offers some performance advantage over the direct RPC loader.
 *
 *  The advantage of this loader mechanism is that it can be quicker 
 *  than the direct RPC loader as it uses the ARM debug comms channel
 *  for memory access rather tham accessing the memory directly 
 *  reducing significantly the number of JTAG operations required to
 *  carry out each operation.
 *  It works by the host locating the addresses of the
 *  LIBMEM functions in memory by examining the symbols in the loader's
 *  binary file and then calling them directly via a simple server
 *  handling commands over the ARM debug comms channel.
 *
 *  A communication buffer is required to store the parameters passed
 *  to the LIBMEM functions, this buffer is specified using the
 *  \a comm_buffer_start and anf \a comm_buffer_end parameters. The
 *  buffer must be at least 8 bytes in length, however you will find
 *  the bigger the buffer is the more performant the loader will be
 *  as less RPC calls will required.
 *
 *  The host loader application adapts how it carries out the download
 *  by the set of LIBMEM functions that are linked into the loader
 *  application. The only two required functions are \a libmem_write()
 *  and \a libmem_erase(), \a libmem_unlock() is only required if
 *  the erase or write functions return a \a LIBMEM_STATUS_LOCKED
 *  result. Everything else can be done by accessing memory directly
 *  however you will get a performance increase when verifying
 *  if you link in \a libmem_crc32(). If any of the memory programmed
 *  by the LIBMEM drivers cannot be accessed directly you will also
 *  need to link in \a libmem_read(), note that if all memory can be
 *  accessed directly you should not link this in as using this
 *  function will reduce performance.
 *
 *  As the loader application usually makes no direct calls to the LIBMEM
 *  functions they will by default be discarded by the linker, you therefore
 *  need to make sure the required LIBMEM functions are linked into your
 *  loader using the "Linker | Keep Symbols" project property.
 *
 *  To use this form of loader the "Target | Loader File Type" project
 *  property must be set to "LIBMEM RPC Loader".
 *
 *  Optional parameters can be passed to the loader using CrossStudio's 
 *  "Target | Loader Parameter" project property which holds a 32 bit 
 *  integer value. When using an RPC loader this value is passed in 
 *  register R0 as the loader starts up.
 */
void libmem_dcc_rpc_loader_start(void *comm_buffer_start, void *comm_buffer_end);

/*! \brief
 *    A function pointer type for a function that handles loader set parameter
 *    transactions.
 *
 *  \param parameter
 *    The parameter number to set.
 *
 *  \param value
 *    The value to set the parameter to.
 */
typedef int (*libmem_dcc_loader_set_param_fn_t)(unsigned int parameter, unsigned int value);

/*! \brief
 *    Start up a LIBMEM loader that uses the "Comms Channel Loader" protocol.
 *
 *  \param set_param_fn
 *    A pointer to the function to call when a loader set parameter message is
 *    received or NULL if not required.
 *
 *  Example:
 *
 *  \code
 *  int set_param_fn(unsigned int parameter, unsigned int value)
 *  {
 *    return 1;
 *  }
 *
 *  int main(void)
 *  {
 *    uint8_t *flash1_start = (uint8_t *)0x10000000;
 *    const int flash1_max_geometry_regions = 4;
 *    libmem_driver_handle_t flash1_handle;
 *    libmem_geometry_t flash1_geometry[flash1_max_geometry_regions];
 *    libmem_flash_info_t flash1_info;
 *
 *    // Register FLASH driver.
 *    libmem_register_cfi_driver(&flash1_handle, 
 *                                flash1_start,
 *                                flash1_geometry,
 *                                flash1_max_geometry_regions, 
 *                                &flash1_info);
 *
 *    // Run the loader 
 *    libmem_dcc_loader_start(set_param_fn);
 *
 *    return 0;
 *  }
 *  \endcode
 *
 *  This function starts up a LIBMEM loader that uses the older "Comms Channel
 *  Loader" protocol, this function has been provided for backward compatibility
 *  with earlier products. This form of loader will only run on ARM7 and ARM9s
 *  with the debug comms channel. 
 *
 *  To use this form of loader the "Target | Loader File Type" project
 *  property must be set to "Comms Channel Loader".
 *
 *  Optional parameters can be passed to the loader using CrossStudio's 
 *  "Target | Loader Parameter" project property which holds a 32 bit 
 *  integer value. If a parameter value has been set the function
 *  \a set_param_fn will be called when the set parameter message has 
 *  been received.
 */
void libmem_dcc_loader_start(libmem_dcc_loader_set_param_fn_t set_param_fn);

/*! \def LIBMEM_RPC_LOADER_MAGIC_NUMBER
 *
 *  Defines the magic number used by host to identify the loader as a LIBMEM
 *  loader.
 */
#define LIBMEM_RPC_LOADER_MAGIC_NUMBER 0x76E9C416

/*! \mainpage LIBMEM Loader Library Reference
 *
 *  The aim of the LIBMEM loader library is to be an add on to the LIBMEM
 *  library that simplies the writing of loader applications.
 *
 *  To write a loader application all you need to do is register the LIBMEM
 *  drivers you require and then call the appropriate loader start function
 *  for the communication mechanism you wish to use. 
 *
 *  For example the following code is an example of a LIMBMEM loader, it 
 *  registers one LIBMEM FLASH driver and starts up a LIBMEM loader using
 *  direct remote procedure calls of the LIBMEM library:
 *
 *  \code
 *  static unsigned char buffer[256];
 *
 *  int main(void)
 *  {
 *    uint8_t *flash1_start = (uint8_t *)0x10000000;
 *    const int flash1_max_geometry_regions = 4;
 *    libmem_driver_handle_t flash1_handle;
 *    libmem_geometry_t flash1_geometry[flash1_max_geometry_regions];
 *    libmem_flash_info_t flash1_info;
 *
 *    // Register FLASH driver.
 *    libmem_register_cfi_driver(&flash1_handle, 
 *                                flash1_start,
 *                                flash1_geometry,
 *                                flash1_max_geometry_regions, 
 *                                &flash1_info);
 *
 *    // Run the loader 
 *    libmem_rpc_loader_start(buffer, buffer + sizeof(buffer) - 1);
 *
 *    return 0;
 *  }
 *  \endcode
 *
 *  Essentially, a LIBMEM loader is just a standard RAM based application
 *  that registers the LIBMEM drivers required by the loader and then
 *  calls the appropriate loader start function for the communication 
 *  mechanism being used.
 *
 *  The LIBMEM loader library currently supports three different loader
 *  communication mechanisms. You select which one to use by calling
 *  \a libmem_rpc_loader_start(), \a libmem_dcc_rpc_loader_start() or
 *  \a libmem_dcc_loader_start() to start the loader. The documentation
 *  for each of these functions describes how each of these communication
 *  mechanisms work.
 *
 *  A significant difference between LIBMEM loader applications and
 *  regular applications is that once the loader start function is called
 *  it is no longer possible to debug the application using the debugger.
 *  Therefore if you need to debug your loader application using the 
 *  debugger you can do it by simply adding calls to the functions
 *  you wish to debug in place of the loader start call.
 */

#endif

