/*  *********************************************************************
 *  ASTRIS - Remote JTAG probe
 *
 *  Public API header			File: astris_swdflash.h
 *
 *  SWDFlasher Booster API/Interface Defined Here
 *
 *********************************************************************
 *
 *  Copyright (C) 2015-2016 Apple, Inc. All rights reserved.
 *
 *  This document is the property of Apple Inc.
 *  It is considered confidential and proprietary.
 *
 *  This document may not be reproduced or transmitted in any form,
 *  in whole or in part, without the express written permission of
 *  Apple Inc.
 ********************************************************************* */

#ifndef ASTRIS_SWDFLASH_H
#define ASTRIS_SWDFLASH_H

#include "astris_api.h"

#pragma mark - SWDFlasher_t Base Class
/*****************************************************************************
 * SWDFlasher_t - abstract class for a SWDFlasher Boosters
 *
 * Your flasher class should inherit from this abstract class.
 *
 * writeflash and eraseflash MUST be overridden, they are completely abstract
 *
 * readflash, preflash, postflash have defaults that will be used if not overridden.
 *
 * preflash and postflash are based of STM pre/postflash sequences
 *
 *****************************************************************************/
class SWDFlasher_t {
public:
    SWDFlasher_t();
    virtual ~SWDFlasher_t();

    /*!
     * @function writeflash
     * @abstract Write given data to a given address.
     * @discussion This function must be implemented by SWDFlasher_t subclass.
     * Writeflash will first probably break up the data into chunks and
     * use AXmemap_write or AXmemap_writevals to do the writes.
     * Specific MCU documentation should describe the size of the writes that are expected.
     * conn_to_sysap helper function provided will be useful here inorder to get the AP object
     * from AXconn_t that will need to be used for AXmemap_ commands.
     * @param info Pointer to AXconn_t struct, which represents the current connection to a probe.
     * This struct is created via AXconn_create and filled out via AXconn_connect.
     * @param address Starting address of the write that is about to be performed.
     * @param length The length of the write that is about to be performed, it should in bytes.
     * @param data A pointer to a pre-allocated buffer of size length, that contains the data
     * that will be written.
     * @return ASTRIS_ERR_OK if everything went well and appropriate Astris error code
     * for the actual errors that might have come up.
    */
    virtual int writeflash(AXconn_t *info, AXmemaddr_t address, uint32_t length, void *data) = 0;

    /*!
     * @function eraseflash
     * @abstract Erase the memory, starting at an address for a certain length
     * @discussion This function must be implemented by SWDFlasher_t subclass.
     * It should erase the region of memory starting from address to address + length. If
     * the MCU supports erasing part of the memory.
     * conn_to_sysap helper function provided will be useful here inorder to get the AP object
     * from AXconn_t that will need to be used for AXmemap_ commands.
     * @param info Pointer to AXconn_t struct, which represents the current connection to a probe.
     * This struct is created via AXconn_create and filled out via AXconn_connect.
     * @param address Starting address of the erase that is about to be performed.
     * @param length The length of the erase that is about to be performed, it should in bytes.
     * @return ASTRIS_ERR_OK if everything went well and appropriate Astris error code
     * for the actual errors that might have come up.
     */
    virtual int eraseflash(AXconn_t *info, AXmemaddr_t address, uint32_t length) = 0;

    /*!
     * @function readflash
     * @abstract Read the memory starting at address for a certain length, into the provided buffer.
     * @discussion This function reads the memory of the MCU, it will be used after writing to
     * validate the write. This function should read from address provided, for the certain length
     * and put the data into the provided buffer which should have been pre allocated. The default
     * readflash, reads using AXmemap_readvals, 4 bytes at a time.
     * conn_to_sysap helper function provided will be useful here inorder to get the AP object
     * from AXconn_t that will need to be used for AXmemap_ commands.
     * @param info Pointer to AXconn_t struct, which represents the current connection to a probe.
     * This struct is created via AXconn_create and filled out via AXconn_connect.
     * @param address Starting address of the read that is about to be performed.
     * @param length The length of the read that is about to be performed, it should in bytes.
     * @param data A pointer to a pre-allocated buffer of size length, where the read data
     * will be put into.
     * @return ASTRIS_ERR_OK if everything went well and appropriate Astris error code
     * for the actual errors that might have come up.
     */
    virtual int readflash(AXconn_t *info, AXmemaddr_t address, uint32_t length, void *data);

    /*!
     * @function preflash
     * @abstract Preflash sequence to perform for the MCU.
     * @discussion This is the preflash sequence that should be performed, to
     * get the chip ready to be flashed. It should set everything up so that
     * the next command can be writeflash, readflash, or eraseflash. This usually means
     * toggling jtag srst to power up the chip, and writing to a few registers. The default
     * preflash is made for Cortex-M series chips, and sets the CPU into VectorCatch.
     * @param info Pointer to AXconn_t struct, which represents the current connection to a probe.
     * This struct is created via AXconn_create and filled out via AXconn_connect.
     * @return ASTRIS_ERR_OK if everything went well and appropriate Astris error code
     * for the actual errors that might have come up.
     */
    virtual int preflash(AXconn_t *info);

    /*!
     * @function postflash
     * @abstract Postflash sequence to perform for the MCU.
     * @discussion This is the postflash sequence that will be performed, after
     * writeflash, readflash, or eraseflash. Goal of this sequence is to put the MCU
     * into a state where it can be reconnected to. The default sequence toggles
     * jtag srst.
     * @param info Pointer to AXconn_t struct, which represents the current connection to a probe.
     * This struct is created via AXconn_create and filled out via AXconn_connect.
     * @return ASTRIS_ERR_OK if everything went well and appropriate Astris error code
     * for the actual errors that might have come up.
     */
    virtual int postflash(AXconn_t *info);

};

typedef SWDFlasher_t *(*createSWDFlasher_t)();

#pragma mark - SWDFlasher Booster Helpers

/*****************************************************************************
 * Helpers for ARM Cortex-M Chips
 *
 * Common ARM Cortex-M register addresses
 *****************************************************************************/

const uint32_t           MAX_HALT_ATTEMPTS = 3;
static const AXmemaddr_t R_AIRCR           = 0xE000ED0C;
static const AXmemaddr_t R_DEMCR           = 0xE000EDFC;
static const AXmemaddr_t R_DHCSR           = 0xE000EDF0;

/*!
 * @function quiesce
 * @abstract Quiesces the connect MCU.
 * @discussion This helper function for Cortex-M3.
 * The function first connects to an AP does the following sequence:
 *
 * Halt -> Clear Fault (AIRCR) -> Turns On Reset Catch (DEMCR) -> Externel Reset (AIRCR)
 *
 * This helper function is commonly used in preflash.
 * @param info Pointer to AXconn_t struct, which represents the current connection to a probe.
 * This struct is created via AXconn_create and filled out via AXconn_connect.
 * @return ASTRIS_ERR_OK if everything went well and appropriate Astris error code
 * for the actual errors that might have come up.
 */
int quiesce(AXconn_t *info);

/*!
 * @function revive
 * @abstract Revives the connect MCU.
 * @discussion This helper function for Cortex-M3.
 * The function does the  following sequence:
 *
 * Disable reset catch using DEMCR, and if noreset is false, then requests
 * exernal reset via AIRCR.
 * This helper function is commonly used in postflash.
 * @param ap Pointer to AXap_t struct, which represents the AP that is going to be
 * used to try to revive the M3. You can get this struct using a function described
 * below: conn_to_sysap.
 * @param noreset If false, an external reset will be requested, otherwise no reset.
 * @return ASTRIS_ERR_OK if everything went well and appropriate Astris error code
 * for the actual errors that might have come up.
 */
int revive(AXap_t *ap, bool noreset);

/*!
 * @function conn_to_sysap
 * @abstract Takes an AXconn_t returns the AP for the connected system.
 * @discussion This helper function takes an AXconn_t struct, gets the first chip
 * then gets the dp from the chip, and then asks for the system bus of the dp, and returns
 * the system ap to use. This is a very useful helper function which is used throughout the
 * flasher booster.
 * @param info Pointer to AXconn_t struct, which represents the current connection to a probe.
 * This struct is created via AXconn_create and filled out via AXconn_connect.
 * @return NULL if something went wrong, or the AP to use when performing
 * memap API calls.
 */
AXap_t *conn_to_sysap(AXconn_t *info);

#endif /* ASTRIS_SWDFLASH_H */
