/*  *********************************************************************
    *  ASTRIS - Remote JTAG probe
    *
    *  Top-level API header			File: astris_api.h
    *
    *  Astris' public API is defined here
    *
    *********************************************************************
    *
    *  Copyright (C) 2009-2019 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_API_H
#define _ASTRIS_API_H

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <assert.h>
#include <sys/cdefs.h>
#include <unistd.h>
#include <pthread.h>
#ifdef INCLUDE_KEXT_CONNECT
#include <IOKit/IOKitLib.h>
#endif /* INCLUDE_KEXT_CONNECT */

#include <os/log.h>
#include <Availability.h>

__BEGIN_DECLS

/*  *********************************************************************
    *  Astris version info
    ********************************************************************* */

#define ASTRIS_EXPORT __attribute__((visibility("default")))
#define ASTRIS_HIDE   __attribute__((visibility("hidden")))

#define ASTRIS_VERSION_MAJOR 2
#define ASTRIS_VERSION_MINOR 13
#define ASTRIS_VERSION_MONAD 0

#define __ASTRIS_VERSION(major, minor, monad) "" #major "." #minor "." #monad ""
#define _ASTRIS_VERSION(major, minor, monad)  __ASTRIS_VERSION(major, minor, monad)

#define ASTRIS_VERSION _ASTRIS_VERSION(ASTRIS_VERSION_MAJOR, ASTRIS_VERSION_MINOR, ASTRIS_VERSION_MONAD)

extern const char *libAstrisVersion;

/*  *********************************************************************
    *  Astris GPIO Kext info
    ********************************************************************* */

#define kAppleAstrisGpioProbeClassName "AppleAstrisGpioProbe"

enum _AppleAstrisGpioProbeIOCtrlMethod {
    kAppleAstrisGpioProbeIOCtrlMethodWiggle,
    kAppleAstrisGpioProbeIOCtrlMethodClock,
    kAppleAstrisGpioProbeIOCtrlMethodCSCommands,
    kAppleAstrisGpioProbeIOCtrlProbePortNumber,

    kAppleAstrisGpioProbeIOCtrlMethodCount
};

/*  *********************************************************************
    *  Astris TCP info
    ********************************************************************* */

#define ASTRIS_PROBE_MAP_PORT   6160
#define ASTRIS_PROBE_RELAY_PORT 6161
#define ASTRIS_TCP_PORT         7777

/*
 * Types of data structures:
 *
 * AXconn_t - Astris Connection
 * AXchip_t - Chip along the connected JTAG chain (can be a single SWD entry)
 * AXdp_t   - ARM debug port associated with chip
 * AXap_t   - ARM acccess port connected to debug port
 * AXmemap_t - Mem-AP (subclass of AX_ap_t)
 * AXjtagap_t - JTAG-AP (subclass of AX_ap_t)
 * AXportal_t - Portal to be be used with KIS specific APIs.
 */

typedef struct AXconn_s        AXconn_t;
typedef struct AXdp_s          AXdp_t;
typedef struct AXap_s          AXap_t;
typedef struct AXtgt_s         AXtgt_t;
typedef struct AXcpu_s         AXcpu_t;
typedef struct AXchip_s        AXchip_t;
typedef struct AXmemap_s       AXmemap_t;
typedef struct AXjtagap_s      AXjtagap_t;
typedef struct AXjtagap_port_s AXjtagap_port_t;
typedef struct AXmeta_s        AXmeta_t;
typedef struct AXvar_entry_s   AXvar_entry_t;
typedef struct AXportal_s      AXportal_t;

typedef uint64_t AXmemaddr_t;
typedef uint64_t AXregaddr_t;
typedef uint64_t AXregval_t;
typedef int32_t  AXregid_t;

// AXcpu_list_t - holds list of AXcpu_t pointers
typedef struct AXcpu_list_s {
    AXcpu_t **ax_cpus; // array of AXcpu_t *
    size_t ncpus; // total number of cpus in ax_cpus
} AXcpu_list_t;

/*  *********************************************************************
    *  Error codes
    *
    *  When adding new error codes,
    *  please update api/src/astris_misccmds.c:axstrerror_map[]
    *  and consider whether an entry is needed in:
    *    api/src/astris_connect.c: conn_connect_msg[]
    *
    ********************************************************************* */

#define ASTRIS_ERR_OK            0   /* no error */
#define ASTRIS_ERR_NOMEM         -1  /* no MEMAP access */
#define ASTRIS_ERR_NOTCONN       -2  /* not connected */
#define ASTRIS_ERR_ISCONN        -3  /* already connected */
#define ASTRIS_ERR_BADHOST       -4  /* invalid host name or port */
#define ASTRIS_ERR_WAIT          -5  /* operation still in progress */
#define ASTRIS_ERR_INVAL         -6  /* invalid parameter */
#define ASTRIS_ERR_TGTOFF        -7  /* target power is OFF */
#define ASTRIS_ERR_CPUNOTHALTED  -8  /* CPU is not halted */
#define ASTRIS_ERR_CPUHALTED     -9  /* CPU is halted */
#define ASTRIS_ERR_JTAGERROR     -10 /* some generic JTAG hardware fault */
#define ASTRIS_ERR_NOTEXPLORED   -11 /* JTAG chain not yet explored */
#define ASTRIS_ERR_TIMEOUT       -12 /* command timed out */
#define ASTRIS_ERR_BADFIRMWARE   -13 /* firmware version is too old DEPRECATED */
#define ASTRIS_ERR_BADPROTOCOL   -14 /* protocol version is too old */
#define ASTRIS_ERR_TGTLOST       -15 /* target no longer responding */
#define ASTRIS_ERR_PROBEINUSE    -16 /* remote probe is currently in use */
#define ASTRIS_ERR_PROBEEOF      -17 /* remote probe closed connection */
#define ASTRIS_ERR_EENOTFOUND    -18 /* remote EEPROM not found */
#define ASTRIS_ERR_VARNOTFOUND   -19 /* environment variable not found */
#define ASTRIS_ERR_BADENV        -20 /* invalid environment variable */
#define ASTRIS_ERR_NOTFOUND      -21 /* file/object not found */
#define ASTRIS_ERR_NOTSUPPORTED  -22 /* operation not supported */
#define ASTRIS_ERR_NOBOARDINFO   -23 /* no board info file loaded */
#define ASTRIS_ERR_IGNORED       -24 /* probe refused to process the command */
#define ASTRIS_ERR_NODP          -25 /* no DP (Debug Port) */
#define ASTRIS_ERR_NOAP          -26 /* no AP (Access Port) */
#define ASTRIS_ERR_NOTUNIQUE     -27 /* more than one when unique required */
#define ASTRIS_ERR_TGTSTATE      -28 /* target not in appropriate state for action */
#define ASTRIS_ERR_BADPARAM      -29 /* bad parameter(s) specified */
#define ASTRIS_ERR_IFSTATE       -30 /* interface not in appropriate state for action */
#define ASTRIS_ERR_ANOMALY       -31 /* anomaly detected */
#define ASTRIS_ERR_PROBECOMMAND  -32 /* unable to transfer command to/from remote probe */
#define ASTRIS_ERR_TOOMANY       -33 /* too many of something */
#define ASTRIS_ERR_PROBED        -34 /* generic error injected by probed */
#define ASTRIS_ERR_SLEEPING      -35 /* host is going to sleep */
#define ASTRIS_ERR_LOSTCONN      -36 /* connection to probe is lost */
#define ASTRIS_ERR_NOTOPEN       -37 /* connection not currently open */
#define ASTRIS_ERR_NODEVICE      -38 /* no device when sending request */
#define ASTRIS_ERR_EXPIRED       -39 /* timeout or watchdog expired */
#define ASTRIS_ERR_EMPTY         -40 /* empty request encountered */
#define ASTRIS_ERR_NOCPU         -41 /* specified CPU is not available */
#define ASTRIS_ERR_INVALCOMMAND  -42 /* invalid command */
#define ASTRIS_ERR_PROBEERROR    -43 /* general error reported by probe */
#define ASTRIS_ERR_PROBETIMEOUT  -44 /* time out reported by probe */
#define ASTRIS_ERR_PROBEHWERR    -45 /* hardware error reported by probe */
#define ASTRIS_ERR_MISSINGPARAM  -46 /* required parameter is missing */
#define ASTRIS_ERR_RESETTING     -47 /* target is probably resetting */
#define ASTRIS_ERR_FAILURE       -48 /* general-purpose failure */
#define ASTRIS_ERR_MISMATCH      -49 /* mismatch detected */
#define ASTRIS_ERR_OUTOFMEMORY   -50 /* out of memory */
#define ASTRIS_ERR_NODATA        -51 /* no data when data expected */
#define ASTRIS_ERR_USB_NOTOPEN   -52 /* USB connection not currently open */
#define ASTRIS_ERR_USB_PROBED    -53 /* generic probed USB error */
#define ASTRIS_ERR_USB_NODEVICE  -54 /* no USB device */
#define ASTRIS_ERR_USB_EXPIRED   -55 /* probed USB transaction timer expired */
#define ASTRIS_ERR_USB_EMPTY     -56 /* empty USB packet encountered */
#define ASTRIS_ERR_NOSOC         -57 /* no SOC object available */
#define ASTRIS_ERR_HTTP_FAILURE  -58 /* HTTP transaction failed */
#define ASTRIS_ERR_HTTP_PENDING  -59 /* HTTP transaction running in background */
#define ASTRIS_ERR_STOPCLOCK     -60 /* SoC clocks are stopped. No MEMAPs allowed */
#define ASTRIS_ERR_NOPORTAL      -61 /* No Portal */
#define ASTRIS_ERR_BLOCKED       -62 /* Access to SoC is blocked */
#define ASTRIS_ERR_NOTPRESENT    -63 /* Component is not present */
#define ASTRIS_ERR_PORTAL_STATUS -64 /* Error in Portal Status */
#define ASTRIS_ERR_DISASM        -65 /* Error in Disassembly */
#define ASTRIS_ERR_FDSETOVERFLOW -66 /* Too many open files */

/*  *********************************************************************
    *  Error code indications
    *
    *  Each Astris error code implies a set of error indications.
    *  Use the AXerror_indications function to obtain the set of
    *  these indications that apply to a specific error code.
    *
    ********************************************************************* */
#define ASTRIS_INDIC_TARGET_LOST   (1ull << 0) /* connection to target has been lost */
#define ASTRIS_INDIC_PROBE_GONE    (1ull << 1) /* connection to probe is gone */
#define ASTRIS_INDIC_NOT_CONNECTED (1ull << 2) /* no connection currently exists */
#define ASTRIS_INDIC_ABSENT        (1ull << 3) /* component not currently detected */
#define ASTRIS_INDIC_COMPONENT     (1ull << 4) /* error communicating with component */
#define ASTRIS_INDIC_IGNORED       (1ull << 5) /* request has been ignored */
#define ASTRIS_INDIC_UNRESPONSIVE  (1ull << 6) /* connection currently unresponsive */
#define ASTRIS_INDIC_SLEEPING      (1ull << 7) /* host is going to sleep */
#define ASTRIS_INDIC_BLOCKED       (1ull << 8) /* request has been blocked */

/* Indication groups:
 *   MAJOR = indication of unreachable device
 *   MINOR = indication of component-level or temporary device-level failure
 *   (every indication falls into either MAJOR or MINOR group)
 */
#define ASTRIS_INDIC_MAJOR (ASTRIS_INDIC_TARGET_LOST | \
                            ASTRIS_INDIC_PROBE_GONE |  \
                            ASTRIS_INDIC_NOT_CONNECTED)
#define ASTRIS_INDIC_MINOR (ASTRIS_INDIC_ABSENT |       \
                            ASTRIS_INDIC_COMPONENT |    \
                            ASTRIS_INDIC_IGNORED |      \
                            ASTRIS_INDIC_UNRESPONSIVE | \
                            ASTRIS_INDIC_SLEEPING)
#define ASTRIS_INDIC_ALL   (ASTRIS_INDIC_MAJOR | ASTRIS_INDIC_MINOR)

/*  *********************************************************************
    *  Public API
    ********************************************************************* */

/* Board types (must match csprotocol.h) */
#define ASTRIS_PROBETYPE_ASTRIS     1
#define ASTRIS_PROBETYPE_PERSEIS    2
#define ASTRIS_PROBETYPE_SIMULATOR  3
#define ASTRIS_PROBETYPE_VIEW       4
#define ASTRIS_PROBETYPE_MINI_SWD   5
#define ASTRIS_PROBETYPE_GORILLA    ASTRIS_PROBETYPE_MINI_SWD
#define ASTRIS_PROBETYPE_KONG       6
#define ASTRIS_PROBETYPE_KANZI      8
#define ASTRIS_PROBETYPE_FLAMINGO   9
#define ASTRIS_PROBETYPE_CHIMP      10
#define ASTRIS_PROBETYPE_POODLE     11
#define ASTRIS_PROBETYPE_PARROT     12
#define ASTRIS_PROBETYPE_KIS        13
#define ASTRIS_PROBETYPE_BITBOX     14
#define ASTRIS_PROBETYPE_PORTBRIDGE 15
#define ASTRIS_PROBETYPE_KIS_STM    16
#define ASTRIS_PROBETYPE_KOKO       17
#define ASTRIS_PROBETYPE_KOBA       18
#define ASTRIS_PROBETYPE_PLAYER     20
#define ASTRIS_PROBETYPE_HIDBRIDGE  21
#define ASTRIS_PROBETYPE_EMUL_SWD   22
#define ASTRIS_PROBETYPE_TOTO       23
#define ASTRIS_PROBETYPE_HPM        24

struct AXcsversion_s {
    uint16_t csv_board_type;
    uint16_t csv_board_serial;
    uint16_t csv_firmware_version;
    uint8_t  csv_board_revision;
    uint8_t  csv_protocol_version;
    uint8_t  csv_protocol_revision;
    uint8_t  csv_protocol_flags1;
    uint8_t  csv_protocol_flags2;
    uint8_t  csv_macaddr[6];
    uint8_t  csv_fwvers_extra[3];
    uint16_t csv_maxscan;
    uint16_t csv_maxbuf;
};

typedef struct AXcsversion_s AXcsversion_t;

/*

    New Info:
    This is now larger than some probes advertise, which is fine. This
    has to be equal to OR larger than what probes advertise as csv_maxbug.

    Old Info:
    Sized to match chipserver maxbuf, should be runtime checked.
    This is the csv_maxbuf, in WORDS (4bytes). Internal buffers of our
    AP and MEMAP commands have this max. JTAG does not have such a limit
    that is controlled by csv_maxscan, and ASTRISPROBED_MAX_DATA.

    #define AXDPAP_MAXDATA 1024

    This is in WORDS (4 bytes)
*/
#define AXDPAP_MAXDATA 8192

/*
    Max data the server can take, some probes will take less
    but no probe should advertise bigger than this many bytes in either
    csv_maxscan and csv_maxbuf of AXcsversion_t

    This is in BYTES, should match what we have above in bytes.

*/
#define ASTRISPROBED_MAX_DATA 32768

/*
 * API functions applicable to all Astris layers
 */
const char *AXstrerror(int astrisErr);
const char *AXstrerror_text(int astrisErr);
const char *AXstr_cs_error(uint16_t csError);
const char *AXstr_translation_error(int tranErr);
int         AXerror_code(const char *astrisErrName, bool *validCode);
uint64_t    AXerror_indications(int astrisErr);
void        AXversion_name_set(char *baseName);
const char *AXversion_name_get(void);
const char *AXversion_min_get(void);
const char *AXversion_src_short_get(void);

/*
 * API side of the "var" command interface.
 */
typedef enum {
    AXVAR_ID_UNDEFINED = -1,
    AXVAR_ID_IGNORE_DAPCMD_ERROR,
} AXvar_id_t;

typedef enum AXvar_type {
    AXVAR_TYPE_UNDEFINED = -1,
    AXVAR_TYPE_BOOL,
} AXvar_type_t;

AXvar_id_t   AXvar_find(const char *name);
const char  *AXvar_name(AXvar_id_t id);
AXvar_type_t AXvar_type(AXvar_id_t id);
const char  *AXvar_type_string(AXvar_id_t id);

int AXvar_get_bool(AXconn_t *info, AXvar_id_t id, bool *value);
int AXvar_set_bool(AXconn_t *info, AXvar_id_t id, bool value);

/*
 * APIs dealing with connections to Astris probes
 */

/*
 * Probe Connection Status Information
 */

/* Probe Connection Status values */
typedef enum {
    PROBE_STAT_NONE = 0, /* connection to probe no longer exists */
    PROBE_STAT_IDLE = 1, /* connection to probe is currently idle */
    PROBE_STAT_BUSY = 2  /* connection to probe is currently in use */
} AXProbeStatus_t;

typedef struct AXprobe_s {
    char           *probeName;   /* name of the probe */
    AXProbeStatus_t probeStatus; /* status of the probe connection */
    int             probePort;   /* port number probe server is listening on */
    char           *usbcPort;    /* !!! Internal Only Don't Use !!! */
} AXprobe_t;

typedef struct AXprobeV2_s AXprobeV2_t;

#define AXPROBED_MAXINFO 256 /* astrisprobed will never fill in more than 255 bytes of info in a response message */

/* KIS STM dockchannel struct */
typedef struct AXkisdockchannel_s {
    char    *name;
    uint32_t bypass_channel;
    uint32_t ap_select;
    uint64_t dock_channel_addr;
} AXkisdockchannel_t;

const char *AXconn_identify(AXconn_t *info);
const char *AXconn_identify_gpu(AXconn_t *info);
const char *AXconn_identify_rev(AXconn_t *info);
/*!
 @function AXconn_identify_soc_collateral
 @discussion Returns the name of the SoC as EH/FWAM would name. This includes variant naming
 @param info Connection to the primate
 @result name of the soc as EH/FWAM is expecting, capitalization or lower case is not garaunteed.
 */
const char *AXconn_identify_soc_collateral(AXconn_t *info);
int         AXconn_probelist(AXconn_t *info, const char *host, AXprobe_t **probelist, int *probecount);
void        AXconn_probelist_free(AXprobe_t *probelist, int probecount);
const char *AXconn_probestatus_name(AXProbeStatus_t probestatus);
int         AXconn_connect(AXconn_t *info, const char *host, int port, unsigned int flags);
int         AXconn_get_pid_bid(AXconn_t *info, uint64_t *pid, uint32_t *bid);

int         AXconn_probelistV2(AXconn_t *info, const char *host, AXprobeV2_t **probelist, int *probecount);
void        AXconn_probelistV2_free(AXprobeV2_t *probelist, int probecount);

/*!
 @function AXconn_probev2_get_v1
 @discussion Convert a AXprobeV2_t pointer to a probev1 pointer. You can then access
             struct variables as you would on older probe structs. AXprobeV2_t has
             the same data as AXprobe_t and more. To get the historic information
             old struct had, this method should be used.
 @param probe AXprobeV2_t gotten via AXconn_probelistV2
 @result Pointer to AXprobe_t struct for the probe given.
 */
AXprobe_t *AXconn_probev2_get_v1(AXprobeV2_t *probe);

/*!
 @function AXconn_probev2_get_primate_loc
 @discussion Get primate Astris interface location id.
 @param probe AXprobeV2_t gotten via AXconn_probelistV2
 @result Either location id or 0 if we failed to find a location id.
 */
uint32_t AXconn_probev2_get_primate_loc(AXprobeV2_t *probe);

/*!
 @function AXconn_probev2_get_primate_hub_loc
 @discussion Get primate hub that is associated with the Astris priamte connection.
 @param probe AXprobeV2_t gotten via AXconn_probelistV2
 @result Either location id or 0 if we failed to find a location id.
 */
uint32_t AXconn_probev2_get_primate_hub_loc(AXprobeV2_t *probe);

/*!
 @function AXconn_probev2_get_kis_loc
 @discussion Get the kis connection location id.
 @param probe AXprobeV2_t gotten via AXconn_probelistV2
 @result Either location id or 0 if we failed to find a location id.
 */
uint32_t AXconn_probev2_get_kis_loc(AXprobeV2_t *probe);

/*!
 @function AXconn_probev2_get_kis_hub_loc
 @discussion Get the kis hub location id. This is the probe device hub, so this
             will either be the same output as AXconn_probev2_get_primate_hub_loc
             if a regular primate is backing the KIS connection. If the probe that
             is bringing out KIS is like Gordo, which is just a hub that brings out KIS
             and Mission USB, but no SWD connectivity this will be filled out with that hub,
             and AXconn_probev2_get_primate_hub_loc will actually be 0.
 @param probe AXprobeV2_t gotten via AXconn_probelistV2
 @result Either location id or 0 if we failed to find a location id.
 */
uint32_t AXconn_probev2_get_kis_hub_loc(AXprobeV2_t *probe);

/*!
 @function AXconn_switch_gateways
 @discussion This command switches between two gateways if you are connected to a KIS device.
             Gateways ways are SWD/JTAG (Primate Probe) and KIS. This command will tell the daemon to start
             sending your packets to the other gateway.
             If you have already explored, you NEED to re-explore after calling this function.
 @param conn Conn struct that could be gotten via AXconn_create
 @result astris error code
 */
int AXconn_switch_gateways(AXconn_t *conn);

typedef enum {
    GATEWAY_KIS,
    GATEWAY_PRIMATE
} AXGatewayType_t;

/*!
 @function AXconn_choose_gateway
 @discussion Same things as AXconn_switch_gateways , but with a helper that checks if the gateway
             requested is the one currently it used, if it is the function returns, if different gateway
             is requested then it calls into AXconn_switch_gateways
 @param conn Conn struct that could be gotten via AXconn_create
 @result astris error code , you are already using the gateway requested ASTRIS_ERR_ISCONN is returned
         other wise treat the error as if it came from AXconn_switch_gateway
 */
int AXconn_choose_gateway(AXconn_t *conn, AXGatewayType_t gateway);

/*!
 @function AXconn_prefs_init
 @discussion This command switches between two gateways if you are connected to a KIS device.
             Gateways are represented as different probes, so if you are currently connected to
             a device via Kanzi and KIS probe is present, it will switch your connection to the KIS
             probe; vica-versa is also going to happen if you start on KIS it will switch to primate.
             This function DOES sever your connection with the currently conencted probe, and establishes
             connection with a new probe.
             If you have already explored, you NEED to re-explore.
 @param conn Conn struct that could be gotten via AXconn_create
 @param prefs_path Path to the astris preference plist
 @result astris error code
 */
int AXconn_prefs_init(AXconn_t *conn, const char *prefs_path);

/* Runtime Environments */
typedef enum {
    kSilicon,
    kFpga,
    kEmuFpga,
    kPxp,
    kFastsim,
    kHybrid,
    kNoSoC,
} AXruntime_env_t;

/*
 * Public Portal API
 * [!!! WARNING !!!]
 * DO NOT USE THIS API, UNLESS YOU ARE ON THE ASTRIS TEAM
 * THIS API HAS MOVED TO PUBLIC ONLY SO THAT ITS EASIER TO TEST OUT THE
 * IMPLEMENTATION USING TEST TOOLS. THERE IS NO GUARANTEE ANY OF THESE TO WORK,
 * DO NOT FILE RADARS AGAINST US FOR THESE, YOU ARE ON YOUR OWN UNTIL THIS WARNING
 * IS DELETED.
 * [!!! WARNING !!!]
 */

typedef enum AXportal_name_s {
    AXPORTAL_NAME_UNKNOWN = -1, /* ID Explore Portal Type */
    AXPORTAL_NAME_IDE     = 0,  /* ID Explore Portal Type */
    AXPORTAL_NAME_DCM,          /* Debug Control Master Type */
    AXPORTAL_NAME_SAM,          /* SoC Access Master Type */
    AXPORTAL_NAME_SAM2,         /* SoC Access Master Type */
    AXPORTAL_NAME_LAM,          /* Local Access Master Type */
    AXPORTAL_NAME_STM,          /* SWD Target Master Type */
    AXPORTAL_NAME_JAM,          /* JTAG Access Master Type */
    AXPORTAL_NAME_RSM,          /* Restore Master Type */
    AXPORTAL_NAME_PAM,          /* Production Master Type */
    AXPORTAL_NAME_RPM,          /* Restore Push Master Type */
    AXPORTAL_NAME_PPM,          /* Production Push Master Type */
} AXportal_name_t;

/*[TODO] What do we do if we have multiple of the same time, ala SAM
 *should this function be something like AXconn_enumcpu where we enumerate?
 */

/*!
 * @function AXportal_get_portal_for_name
 * @abstract Get a portal struct of a certain name
 * @discussion Given a portal name, Astris will populate the pointer provided to
 * point to the specific struct. This struct can then be used with various AXportal
 * API below.
 * @param conn   Astris connection struct
 * @param name   TODO
 */
AXportal_t *AXportal_get_portal_for_name(AXconn_t *conn, int name);

/*!
 * @function AXportal_cfg_read_reg32
 * @abstract Read a configuration register of a portal
 * @discussion This function reads one configuration of the portal, at the index specified.
 * Configuration registers are 32bit wide.
 * @param portal Portal to read a 32bit register of.
 * @param reg_index Offset of the configuration register to read.
 * @param regval Pointer to a 32bit value that will be populated with the value of the
 * register.
 */
int AXportal_cfg_read_reg32(AXconn_t *conn, AXportal_t *portal, int reg_index, uint32_t *regval);

/*!
 * @function AXportal_cfg_write_reg32
 * @abstract Write a configuration register of a portal
 * @discussion This function writes to one configuration of the portal, at the index specified.
 * Configuration registers are 32bit wide.
 * @param portal Portal to write a 32bit register of.
 * @param reg_index Offset of the configuration register to write.
 * @param regval A 32bit value that will be writen to the specified register.
 */
int AXportal_cfg_write_reg32(AXconn_t *conn, AXportal_t *portal, int reg_index, uint32_t regval);

/*!
 * @function AXportal_cfg_read_vals32
 * @abstract Read multiple configuration registers of a portal
 * @discussion This reads multiple configuration registers, starting from
 * reg index and reads the following reg_count amount of registers. This means that
 * regvals should be a array of 32bit unsigned integers that can hold reg_count amount
 * of 32bit unsigned integers.
 * @param conn   Astris connection struct
 * @param portal Portal to read multiple 32bit registers of.
 * @param reg_index Offset of the configuration register where the read starts.
 * @param reg_count Total number of registers to read starting from reg_index.
 * @param regvals A pointer to an array of 32bit values that will be populated
 * with the values of read out. This array needs to be preallocated by the
 * user of this API.
 */
int AXportal_cfg_read_vals32(AXconn_t *conn, AXportal_t *portal, int reg_index, int reg_count, uint32_t *regvals);

/*!
 * @function AXportal_cfg_write_vals32
 * @abstract Write multiple configuration registers of a portal
 * @discussion This writes multiple configuration registers, starting from
 * reg index and writes to the following reg_count amount of registers.
 * This means that regvals should be a array of 32bit unsigned integers that has
 * reg_count of 32bit unsigned integers inside of it.
 * @param conn      Astris connection struct
 * @param portal    Portal to write the multiple 32bit values to.
 * @param reg_index Offset of the configuration register where the write starts.
 * @param reg_count Total number of registers to write starting from reg_index.
 * @param regvals   A pointer to an array of 32bit values that are populated
 * with the values to write into registers.
 */
int AXportal_cfg_write_vals32(AXconn_t *conn, AXportal_t *portal, int reg_index, int reg_count, uint32_t *regvals);

/*!
 * @function AXportal_access_read_reg32
 * @abstract Read a 32bit register at given address.
 * @discussion If a portal supports it, this function allows you to read
 * a 32bit register using the portal.
 * @param conn   Astris connection struct
 * @param portal Portal to use to do the read.
 * @param addr   Address of the register to read from.
 * @param val    Pointer to a 32bit value that will be populated with the
 * value of the register at the address.
 */
int AXportal_access_read_reg32(AXconn_t *conn, AXportal_t *portal, AXregaddr_t addr, uint32_t *val);

/*!
 * @function AXportal_access_write_reg32
 * @abstract Write a 32bit value to a given address.
 * @discussion If a portal supports it, this function allows you to write
 * to a 32bit register a 32bit value.
 * @param conn    Astris connection struct
 * @param portal  Portal to use to do the read.
 * @param addr    Address of the register to write to.
 * @param val     A 32bit value that will be writen to a register at a given address.
 */
int AXportal_access_write_reg32(AXconn_t *conn, AXportal_t *portal, AXmemaddr_t addr, uint32_t val);

/*!
 * @function AXportal_access_read_reg64
 * @abstract Read a 64bit register at given address.
 * @discussion If a portal supports it, this function allows you to read
 * a 64bit register using the portal.
 * @param conn   Astris connection struct
 * @param portal Portal to use to do the read.
 * @param addr   Address of the register to read from.
 * @param val    Pointer to a 64it value that will be populated with the
 * value of the register at the address.
 */
int AXportal_access_read_reg64(AXconn_t *conn, AXportal_t *portal, AXmemaddr_t addr, uint64_t *val);

/*!
 * @function AXportal_access_write_reg64
 * @abstract Write a 64it value to a given address.
 * @discussion If a portal supports it, this function allows you to write
 * a 64bit value to a 64bit register.
 * @param conn    Astris connection struct
 * @param portal  Portal to use to do the write.
 * @param addr    Address of the register to write to.
 * @param val     A 64bit value that will be writen to a register at a given address.
 */
int AXportal_access_write_reg64(AXconn_t *conn, AXportal_t *portal, AXmemaddr_t addr, uint64_t val);

/*!
 * @function AXportal_read_vals
 * @abstract Read size*count amount of data in size chunks starting at addr.
 * @discussion This function starts reading at addr, copying the read values into the vals buffer. There are count
 * amount of reads done, each read is of size bytes. The fifo flag can be used to read vals
 * to a single address; this can be useful for things such as PCtrace or reading out of trace buffers.
 * @param conn   Astris connection struct
 * @param portal A portal to use to do the read.
 * @param addr   Starting address of the read.
 * @param fifo   If fifo is true, the read will be done to a single address. This is useful when you are
 *               trying to read a fifo on the system, and not advance the address after each read.
 * @param size   Size in bytes of the chunk size. This value should be either 4 or 8.
 * @param count  Count is amount of chunks that should be read. Each chunk being the size of the variable size. Count is a pointer
 *               to the 32bit value, when the function returns count will be pointing to the actual amount of chunks read. The user
                 can then check the value that count is pointing to see how many chunks were actaully read.
 * @param vals   Vals is a pointer to a preallocated buffer of (length x size) size into which the values will be copied into.
 *
 */
int AXportal_read_vals(AXconn_t *conn, AXportal_t *portal, AXmemaddr_t addr, bool fifo, int size, uint32_t *count, uint8_t *vals);

/*!
 * @function AXportal_write_vals
 * @abstract Write size*count amount of data in size chunks starting at addr.
 * @discussion This function starts writing at addr the vals buffer. There are count
 * amount of chunks done, each chunk is of size bytes. The fifo flag can be used to write vals
 * to a single address.
 * @param conn   Astris connection struct
 * @param portal A portal to use to do the write.
 * @param addr   Starting address of the write.
 * @param fifo   If fifo is true, the write will be done to a single address. This is useful when you are
 *               trying to write to a fifo on the system, and not advance the address after each write.
 * @param size   Size in bytes of the chunk size. This value should be either 4 or 8.
 * @param count  Count is amount of chunks that should be writen. Each chunk being the size of the variable size. Count is a pointer
 *               to the 32bit value, when the function returns count will be pointing to the actual amount of chunks writen. The user
                 of this function can then check the value that count is pointing to see how many chunks were actaully writen.
 * @param vals   Vals is a preallocated buffer that has the values to be writen. The size in bytes of this buffer should be at least
 *               (length x size).
 */
int AXportal_write_vals(AXconn_t *conn, AXportal_t *portal, AXmemaddr_t addr, bool fifo, int size, uint32_t *count, uint8_t *vals);

/*!
 * @function AXportal_dfu_dcm
 * @discussion Put the device into DFU via DCM. This works only on few SoCs where DCM
 * DFU GPIO connection available but it always try to assert DCM DFU pin
 * and won't return NOTSUPPORTED error.
 * @param conn   Astris connection struct0
 * @param dfu_val value should be either 0 or 1
 *                dcm dfu is controlled by GPIO. value should be given depending on how GPIO is hooked up.
 *                Usually value = 1 means to set DFU.
 */
int AXportal_dfu_dcm(AXconn_t *conn, uint32_t dfu_val);

/*!
 * @function AXportal_reset_dcm
 * @discussion reset via DCM. This works only on few SoCs where DCM reset GPIO connection
 * available but it always try to assert/deassert DCM reset pin and won't return
 * NOTSUPPORTED error.
 * @param conn   Astris connection struct
 */
int AXportal_reset_dcm(AXconn_t *conn);

/*!
 * @function AXportal_stm_dockch_create
 * @discussion Creates STM Dock Channel.
 * @param conn                  Astris connection struct
 * @param dock_ch               It has info to create dock channel like bypass_channel, AP select,
                                dock channel base address
 * @param polling_delay         delay in polling dock channel
 */

int AXportal_stm_dockch_create(AXconn_t *conn, AXkisdockchannel_t *dock_ch, uint32_t polling_delay);

/*!
 * @function AXportal_stm_dockch_destroy
 * @discussion Destroys STM Dock Channel.
 * @param conn                  Astris connection struct
 * @param bypass_channel        Bypass select of dock channel to be destroyed
 */
int AXportal_stm_dockch_destroy(AXconn_t *conn, uint32_t bypass_channel);

/*
 * Booster API and Helper Variables
 */
#define ASTRIS_BOOSTERPACK_PATH      "/usr/local/share/astris/boosterpack"
#define ASTRIS_BOOSTERPACK_MAX_PATHS 10

/*!
 * @function AXbooster_init
 * @abstract Initializes the Astris Plugin system
 * @discussion This function should be called as one of the first things you do
 * and before you actually expore/connect. This function gets all the plugins available
 * and will be able to match agains them when explore happens.
 * @param conn AXconn_t object provided by AXconn_create
 */
int AXbooster_init(AXconn_t *conn);

/*!
 * @function AXbooster_init_with_paths
 * @abstract Initializes the Astris Plugin system
 * @discussion This function should be called as one of the first things you do
 * and before you actually expore/connect. This function gets all the plugins available
 * and will be able to match agains them when explore happens.
 * @param boosterpack_paths array of absolute paths, where astris should look for
 * plugins in
 * @param conn AXconn_t object provided by AXconn_create
 * @param len the length of the boosterpack_paths array
 * @see AXbooster_init
 */
int AXbooster_init_with_paths(AXconn_t *conn, char *boosterpack_paths[], int len);

/*!
 * @function AXbooster_cleanup
 * @abstract Cleans up the Astris plugin system
 * @discussion Cleans up the Astris plugin system, by cleaning up internal objects.
 * This function should be called, after your code disconnects from the probe and before
 * your program exits/stops using Astris API.
 * @param conn AXconn_t object provided by AXconn_create
 */
int AXbooster_cleanup(AXconn_t *conn);

/*!
 * @function AXbooster_refresh
 * @abstract Make each BoosterManager refetch its boosters.
 * @discussion This function iterates over each BoosterManager, first clears each array of
 * boosters that were found and then makes the BoosterManager re populate the array. This
 * function can hopefully be used more in the future where you can hot load boosters. Right
 * now this function does not server a huge function.
 * @param conn AXconn_t object provided by AXconn_create
 */
int AXbooster_refresh(AXconn_t *conn);

/*!
 * @function AXbooster_print_all_booster_managers
 * @abstract Prints all BoosterManagers
 * @discussion This iterates, and internal dictionary and prints out names of all the
 * current available BoosterManagers.
 * @param conn AXconn_t object provided by AXconn_create
 */
int AXbooster_print_all_booster_managers(AXconn_t *conn);

/*!
 * @function AXbooster_get_all_boostermanagers
 * @abstract Returns a list of BoosterManager types.
 * @discussion Given a reference to a double pointer, and a reference to an int, this
 * function returns a list of char * that is list of the BoosterManager types available.
 * You can then use the BoosterManager types in AXbooster_get_all_boosters and
 * AXbooster_get_loaded_boosters. Allocating is done by this function, that means
 * you will need to use free this using AXbooster_destroy_list.
 * @param conn AXconn_t object provided by AXconn_create
 * @param bm_list Reference to an array of char * thus a char ***. You dont need to
 * allocate the pointers, the function will malloc the memory you will need to free it.
 * This list will be populated with a list of char * that are BoosterManager type.
 * @param list_length Reference to an integer, this will be filled with the size of bm_list
 * you can use this to see how much to iterate over the bm_list
 * @code char ** bm_list; int bm_count = 0; AXbooster_get_all_boostermanagers(&bm_list, &bm_count);
 * @see AXbooster_get_all_boosters
 * @see AXbooster_get_loaded_boosters
 * @see AXbooster_destroy_list
 */
int AXbooster_get_all_boostermanagers(AXconn_t *conn, char ***bm_list, int *list_length);

/*!
 * @function AXbooster_get_all_boosters
 * @abstract Returns a list of all Boosters of a certain types.
 * @discussion Given a Booster type, which can be retrieved via
 * AXbooster_get_all_boostermanagers, a pointer to an array of char * and reference
 * to an integer, this function populates the booster list with all the boosters
 * that the BoosterManager found. You will need to free booster_list using AXbooster_destroy_list
 * @param conn AXconn_t object provided by AXconn_create
 * @param bm_type BoosterManger type.
 * @param booster_list Reference to an array of char * thus a char ***. You dont need to
 * allocate the pointers, the function will malloc the memory you will need to free it.
 * This list will be populated with a list of char * that are booster bundle ids.
 * @param list_length Reference to an integer, this will be filled with the size of booster_list
 * you can use this to see how much to iterate over the booster_list
 * @code char ** bundles; int bundles_count;  AXbooster_get_all_boosters("CPU", &bundles, &bundles_count);
 * @see AXbooster_get_all_boostermanagers
 * @see AXbooster_destroy_list
 */
int AXbooster_get_all_boosters(AXconn_t *conn, const char *bm_type, char ***booster_list, int *list_length);

/*!
 * @function AXbooster_get_loaded_boosters
 * @abstract Returns a list of only loaded Boosters of a certain types.
 * @discussion Given a Booster type, which can be retrieved via
 * AXbooster_get_all_boostermanagers, a pointer to an array of char * and reference
 * to an integer, this function populates the booster list with loaded boosters of
 * BoosterManger type provided. You will need to free booster_list using AXbooster_destroy_list
 * @param conn AXconn_t object provided by AXconn_create
 * @param bm_type BoosterManger type.
 * @param booster_list Reference to an array of char * thus a char ***. You dont need to
 * allocate the pointers, the function will malloc the memory you will need to free it.
 * This list will be populated with a list of char * that are booster bundle ids.
 * @param list_length Reference to an integer, this will be filled with the size of booster_list
 * you can use this to see how much to iterate over the booster_list
 * @code char ** loaded_bundles; int loaded_bundles_count;  AXbooster_get_loaded_boosters("CPU", &loaded_bundles, &loaded_bundles_count);
 * @see AXbooster_get_all_boostermanagers
 * @see AXbooster_get_all_boosters
 * @see AXbooster_destroy_list
 */
int AXbooster_get_loaded_boosters(AXconn_t *conn, const char *bm_type, char ***booster_list, int *list_length);

/*!
 * @function AXbooster_destroy_list
 * @abstract Destroys a given list, used in Booster api functions.
 * @discussion Helper function to free lists in the AXbooster_get_
 * Please use this function once you are done with the allocated array.
 * @param list A list to free
 * @param list_length The length of the list to free
 * @see AXbooster_get_all_boostermanagers
 * @see AXbooster_get_loaded_boosters
 * @see AXbooster_get_all_boosters
 */
int AXbooster_destroy_list(char **list, int list_length);

/*!
 * @function AXbooster_print_boosters
 * @abstract Prints plugins of a given PluginManager (PM), or all plugins.
 * @discussion Prints plugins of a given PluginManager or if NULL is given
 * then this function will iterate over every PM and print plugins that
 * each PM knows about.
 * @param conn AXconn_t object provided by AXconn_create
 * @param bm_type A string which is a name of PM, or NULL to print every
 * plugin.
 * @see AXbooster_print_all_booster_managers to get PMs available.
 */
int AXbooster_print_boosters(AXconn_t *conn, const char *bm_type);

/*!
 * @function AXbooster_print_loaded_boosters
 * @abstract Prints loaded plugins of a given PluginManager (PM), or all loaded plugins.
 * @discussion Prints loaded plugins of a given PluginManager or if NULL is given
 * then this function will iterate over every PM and print loaded plugins that
 * each PM knows about.
 * @param conn AXconn_t object provided by AXconn_create
 * @param bm_type A string which is a name of PM, or NULL to print every loaded
 * plugin.
 * @see AXbooster_print_all_booster_managers to get PMs available.
 */
int AXbooster_print_loaded_boosters(AXconn_t *conn, const char *bm_type);

/*!
 * @function AXbooster_printBoostersDetailed
 * @abstract Prints plugins of a given PluginManager (PM), or of every PM in great detail.
 * @discussion This function will print out the name of a plugin and each of its keys.
 * If PM is given then it will only iterate over the plugins of that particular PM.
 * If PM is NULL, then it will iterate over every PM and print detailed information
 * about each PM's plugins.
 * @param conn AXconn_t object provided by AXconn_create
 * @param bm_type A string which is a name of PM, or NULL to iterate over every
 * PM.
 * @see AXbooster_printAllPluginManagers to get PMs available.
 */
int AXbooster_print_boosters_detailed(AXconn_t *conn, const char *bm_type);

/*!
 * @function AXbooster_get_ctx
 * @abstract Returns a void pointer which is the booster global that is of type
 * BoosterManagerUtility.
 * @discussion This function returns a void * that is g_booster_utility of the current
 * Astris API. This function should only be used inside of main Astris API when you are
 * creating a AXbooster_handoff_info_t (see astris_booster_api.h) this context will
 * then be used with AXbooster_init_with_ctx by a booster creator to make sure that
 * their booster is using the main Astris's API booster context. There cannot be multiple
 * booster contexts running ala a booster cannot load another booster, main Astris's API
 * instance has all the boosters.
 * @param conn AXconn_t object provided by AXconn_create
 * @see AXbooster_init_with_ctx
 * @see AXbooster_handoff_info_t
 * @see AXbooster_interface_init_astris_api
 */
void *AXbooster_get_ctx(AXconn_t *conn);

/*!
 * @function AXbooster_init_with_ctx
 * @abstract Takes a booster_ctx that is usually gotten from AXbooster_get_ctx
 * and AXbooster_handoff_info_t.
 * @discussion This function will initialize the current Astris's API global
 * booster context with the one that is passed in. This function should only be used
 * by a booster in order to make sure that the booster uses the main Astris's API
 * global booster instance. Usually this function is called inside of
 * AXbooster_interface_init_astris_api (astris_booster_api.h) that a booster writer
 * has implemented.
 * @param conn AXconn_t object provided by AXconn_create
 * @param booster_ctx instance usually gotten from AXbooster_get_ctx
 * @see AXbooster_interface_init_astris_api
 * @see AXbooster_handoff_info_t
 * @see AXbooster_get_ctx
 */
int AXbooster_init_with_ctx(AXconn_t *conn, void *booster_ctx);

/*
 * SWDFlash API, That Uses The SWDFlash Boosters
 */
typedef struct AXswdflash_info_s {
    const char *soc_id;        /* name of soc to flash */
    int         aod_type;      /* aod type of the chip */
    int         preflash_type; /* preflash type of the chip */
} AXswdflash_info_t;

int  AXswdflash_writeflash(AXswdflash_info_t *chip_info, AXconn_t *info, AXmemaddr_t address, uint32_t length, void *data);
int  AXswdflash_readflash(AXswdflash_info_t *chip_info, AXconn_t *info, AXmemaddr_t address, uint32_t length, void *data);
int  AXswdflash_eraseflash(AXswdflash_info_t *chip_info, AXconn_t *info, AXmemaddr_t address, uint32_t length);
int  AXswdflash_preflash(AXswdflash_info_t *chip_info, AXconn_t *info);
int  AXswdflash_postflash(AXswdflash_info_t *chip_info, AXconn_t *info);
void AXswdflash_cleanup();

void AXswdflash_chips_supported(AXconn_t *conn);
bool AXswdflash_is_chip_supported(AXconn_t *conn, AXswdflash_info_t *chip_info);

#ifdef INCLUDE_KEXT_CONNECT
int AXconn_connect_kext(AXconn_t *info, unsigned int flags, io_service_t service);

#endif /* INCLUDE_KEXT_CONNECT */
int         AXconn_kick(AXconn_t *info, const char *host, unsigned int flags);
int         AXconn_probed_command(AXconn_t *info, const char *host, int argc, char **argv, char **result);
int         AXconn_disconnect(AXconn_t *info);
int         AXconn_remaddr(AXconn_t *info, void *remohst);
int         AXconn_lcladdr(AXconn_t *info, void *remohst);
AXconn_t   *AXconn_create(void);
int         AXconn_destroy(AXconn_t *info);
bool        AXconn_connected(AXconn_t *info);
int         AXconn_version(AXconn_t *info, AXcsversion_t *vers);
int         AXconn_ping(AXconn_t *info, int len);
int         AXconn_probe_status(AXconn_t *info);
bool        AXconn_kick_requested(AXconn_t *info);
int         AXconn_kick_info(AXconn_t *info, char *buf, int *len);
int         AXconn_sleep_control(AXconn_t *info, bool allow);
int         AXconn_spew(AXconn_t *info, int spew);
void        AXconn_filespew(AXconn_t *info);
int         AXconn_lcdmessage(AXconn_t *info, char *line0, char *line1);
const char *AXconn_process_output_dir_path(const char *dir_path);
int         AXconn_lcdpage(AXconn_t *info, int page);
int         AXconn_fwupdate(AXconn_t *info);
int         AXconn_compatvers(int *protovers, int *protorev);
void        AXconn_fwvers(AXcsversion_t *vers, char *buffer, int len);
const char *AXconn_hostname(AXconn_t *info);
const char *AXconn_showname(AXconn_t *info);
const char *AXconn_conndesc(AXconn_t *info);
const char *AXconn_logkey(AXconn_t *info);
void        AXconn_perror(AXconn_t *info, const char *prefix);
void        AXconn_crash_on_probetimeout(AXconn_t *conn);

/*!
 * @function AXconn_set_xfertimeout
 * @abstract Changes the internal transfer timeout.
 * @discussion Sometimes when dealing with simulation the simulation can take a
 * long time to respond back. Usually a transactor is used to wait for a response
 * however, then Astris it self times out waiting for the transactor to get back
 * to it. This command can be used to set a really long time for Astris to hear back
 * from the probedserver/transactor.
 * Default Timeout: 30 secs; for ASTRIS_PROBETYPE_SIMULATOR probes 60 seconds.
 * @param conn AXconn_t connection created with AXconn_create
 * @param timeout Number of seconds for the timeout to be. Putting -1, will reset
 * the default to the original value. 0 timeout is not allowed.
 * @see AXconn_create
 * @see AXconn_connect
 * @returns Return an ASTRIS_ERR_OK if everything went fine.
 */
int AXconn_set_xfertimeout(AXconn_t *conn, int timeout);

/*!
 * @function AXconn_kis_swd_setup
 * @abstract Sets up KIS to bypass.
 * @discussion This command first calls AXjtag_release, to clean up connection before
 * its fine if nothing was connected before. Then it does the set up needed to make
 * sure KIS can talk to the bypass_channel (TMS line) you need to.
 * This function should be called after AXconn_connect with AXCONN_FLG_CONN_SHOW_KIS_STM
 * flag. Then call this function, after you can call AXjtag_explore to explore
 * behind the TMS line.
 * This function can also be used to switch between the bypass_channels by just
 * calling this function again with the channel you want and then AXjtag_explore.
 * As mentioned above this function will clean up before setting up for bypass
 * @param conn AXconn_t connection created with AXconn_create
 * @param bypass_channel The TMS line you want us to bypass to.
 * @see AXconn_connect
 * @returns Return an ASTRIS_ERR_OK if everything went fine.
 */
int AXconn_kis_swd_setup(AXconn_t *conn, int bypass_channel);

/*!
 * @function AXconn_kis_swd_set_bypassch
 * @abstract Sets up bypass channel for KIS STM.
 * @discussion This function should be called before AXconn_connect
 * This will setup bypass channel needed for AXconn_connect
 * @param conn AXconn_t connection created with AXconn_create
 * @param bypass_channel The TMS line you want us to bypass to.
 * @see AXconn_connect
 */
void AXconn_kis_swd_set_bypassch(AXconn_t *conn, int bypass_channel);

/*!
 * @function AXconn_kis_swd_set_no_force_pins
 * @abstract Sets up bypass channel for KIS STM to know whether to force_pins
 * @discussion This function should be called before AXconn_connect
 * This will setup bypass channel needed for AXconn_connect
 * @param conn AXconn_t connection created with AXconn_create
 * @param no_force_pins If you want us to NOT configure PS,TMS & TCK for you.
 * @see AXconn_connect
 */
void AXconn_kis_swd_set_no_force_pins(AXconn_t *conn, bool no_force_pins);

/*!
 * @function AXconn_kis_get_stm_probename
 * @abstract This command will get KIS-STM probename that corresponds to bypass_channel
 * @param conn AXconn_t connection created with AXconn_create
 * @param bypass_channel TMS line to which KIS-STM probename should be returned
 * @param kis_stm_name KIS-STM probename that is identified using pid, bid and bypass_device_name
 */
int AXconn_kis_get_stm_probename(AXconn_t *conn, uint32_t bypass_channel, char **kis_stm_name);

/*!
* @function AXchip_bypass
* @discussion This function will do the first steps if setting up PS,TCK, TMS
* for a given bypass_sel just like setup_bypass but then it will also do the
* procedure of breaking the connection and bypassing to the given line
* @param chip Chip struct that could be gotten via AXchip_enum, AXchip_findidcode, or AXchip_find_dap
* @param bypass_sel The TMS line you want us to bypass to.
* @param force_pins If you want us to configure PS,TMS & TCK for you.
* @result An ASTRIS_ERR code
*/
int AXchip_bypass(AXchip_t *chip, uint32_t bypass_sel, bool force_pins);

/*!
* @function AXchip_setup_bypass
* @discussion Sets up the PS, TCK and TMS pins.
* @param chip Chip struct that could be gotten via AXchip_enum, AXchip_findidcode, or AXchip_find_dap
* @param bypass_sel This is either the TMS line you need us to configure
* or you can give -1 as a special arugment to enable all the TMS lines.
* @result An ASTRIS_ERR code
*/
int AXchip_setup_bypass(AXchip_t *chip, uint32_t bypass_sel);

/*!
* @function AXchip_get_stm_dockch_list
* @discussion Returns list of KIS-STM dock channel config.
* @param chip Chip struct that could be gotten via AXchip_enum, AXchip_findidcode, or AXchip_find_dap
* @param dockch_list pointer contains dock channel configuration of SoC
* @param dockch_count number of stm dock channels
* @result An ASTRIS_ERR code
*/
int AXchip_get_stm_dockch_list(AXchip_t *chip, AXkisdockchannel_t **dockch_list, uint32_t *dockch_count);

/*!
 @function AXchip_free_stm_dockch_list
 @discussion It will free pointer of AXkisdockchannel_t structure
 */
void AXchip_free_stm_dockch_list(AXkisdockchannel_t *dockch_list);

/*!
* @function AXconn_disable_bypass
* @discussion Sets up the break sequence to use to break bypass;
* @param conn AXconn_t connection created with AXconn_create
* @param break_seq a 32bit integer that is the sequence we should write when bypassing.
* Set break_seq to 0 for default unless you configured a break sequence.
* @see AXconn_create
* @see AXconn_connect
* @result An ASTRIS_ERR code
*/
int AXconn_disable_bypass(AXconn_t *conn, uint32_t break_seq);

/* Batch Attitude adjustments */
int AXconn_batch_attitude_attach(AXconn_t *info);
int AXconn_batch_attitude_detach(AXconn_t *info);
int AXconn_batch_attitude_cop(AXconn_t *info);
int AXconn_batch_attitude_lose(AXconn_t *info);
int AXconn_batch_attitude_suspend(AXconn_t *info);
int AXconn_batch_attitude_resume(AXconn_t *info);
int AXconn_batch_attitude_relax(AXconn_t *info);

/* helper macros for performing AXconn logkey based printing to stdout / stderr */
#define AXCPRINTF(info, args...) do {ax_os_log(AXconn_logkey(info), AXL_U_STD, args);} while (0)
#define AXCSTDERR(info, args...) do {ax_os_log(AXconn_logkey(info), AXL_U_ERR, args);} while (0)

#define AXCONN_FLG_CONN_PROT_OK           0x00000001 /* Permit protocol mismatch; client beware */
#define AXCONN_FLG_CONN_FORCE_KICK        0x00000002 /* force kick of any current owner of probe */
#define AXCONN_FLG_CONN_INHIBIT_ASK       0x00000004 /* inhibit asking user any questions */
#define AXCONN_FLG_CONN_DESC_DETAILS      0x00000008 /* provide full details in any descriptions */
#define AXCONN_FLG_CONN_KIS               0x00000010 /* Connect to the KIS probe behind the Kanzi [Not in Use Right Now] */
#define AXCONN_FLG_CONN_SHOW_KIS_STM      0x00000020 /* [FILTER FLAG] Show KIS-STM Probes ONLY */
#define AXCONN_FLG_CONN_NO_KIS            0x00000040 /* [FILTER FLAG] Dont show any KIS probes */
#define AXCONN_FLG_CONN_PRIMATE           0x00000080 /* Connect to the primate behind KIS */
#define AXCONN_FLG_CONN_SSO_NOPROMPT      0x00000100 /* Do not prompt for AppleConnect credentials. */
#define AXCONN_FLG_CONN_ENABLE_STM_DOCKCH 0x00000200 /* Enable STM dock channel while connecting to KIS-STM Probe*/
#define AXCONN_FLG_CONN_KIS_NAMED_STM     0x00000400 /* Helps to connect to right probe for named KIS-STM bypass connection*/
#define AXCONN_FLG_CONN_ONLY_HPM          0x00000800 /* [FILTER FLAG] Show only HPM connections */
#define AXCONN_FLG_CONN_NO_OPEN_LOG_FILE  0x00001000 /* Do not re-open a new log file. */
#define AXCONN_FLG_CONN_NO_FORCE_PINS     0x00002000 /* Tell KIS-STM bypass not to force pin-config */

#define AXCONN_FLG_DEBUG_CONNECT 0x00000001
#define AXCONN_FLG_DEBUG_AP      0x00000002
#define AXCONN_FLG_DEBUG_DP      0x00000004
#define AXCONN_FLG_DEBUG_CPU     0x00000008
#define AXCONN_FLG_DEBUG_JTAG    0x00000010
#define AXCONN_FLG_DEBUG_EICE    0x00000020
#define AXCONN_FLG_DEBUG_MEMAP   0x00000080
#define AXCONN_FLG_DEBUG_MINISWD 0x00000100
#define AXCONN_FLG_DEBUG_XACT    0x00000200
#define AXCONN_FLG_DEBUG__MAX    AXCONN_FLG_DEBUG_XACT /* maximum debug flag */

/*
 * When dealing with broken parts, sometimes we need to tread lightly.
 * We have a way to say "avoid X."
 */

#define AXJTAG_AVOID_NONE     0 /* Erase all previously stored avoid blocks */
#define AXJTAG_AVOID_APSEL    1 /* Avoid this AP SELECT index */
#define AXJTAG_AVOID_ROMTABLE 2 /* Avoid this ROM table entry/index (and what it points at) */
#define AXJTAG_AVOID_JTAGAP   3 /* Avoid this JTAG-AP port */
#define AXJTAG_AVOID_CPU      4 /* Avoid the specified CPU */
/* More possibilities:  Avoid certain IDCODEs, CPU types, etc? */

int AXjtag_avoid(AXconn_t *info, int what, unsigned int arg);
int AXjtag_shouldavoid(AXconn_t *info, int what, unsigned int arg);

/*
 * APIs dealing with raw JTAG
 *
 * Some of these need to support operating on TAPs behind a JTAG-AP, while others don't.
 * Functions which take an 'AXchip_t *' can target ports of a JTAG-AP.
 */
#define AXJTAG_SRST_DONTCHANGE     -1
#define AXJTAG_TRST_DONTCHANGE     -1
#define AXJTAG_SRSTMODE_DONTCHANGE -1

#define AXJTAG_MODE_JTAG       0
#define AXJTAG_MODE_SWD        1
#define AXJTAG_MODE_DONTCHANGE -1

/* Values for SRST Mode */
#define AXJTAG_SRSTMODE_OPENDRAIN 0
#define AXJTAG_SRSTMODE_DRIVE     1

#define AXJTAG_EXPLORE_JTAGONLY               0x00000001 /* Don't probe behind DAPs */
#define AXJTAG_EXPLORE_GENTLY                 0x00000002 /* Try not to re-probe */
#define AXJTAG_EXPLORE_JTAGAP                 0x00000004 /* Also probe behind JTAG-APs */
#define AXJTAG_EXPLORE_DAPONLY                0x00000008 /* Probe DAP but not behind APs */
#define AXJTAG_EXPLORE_APONLY                 0x00000010 /* Probe DAPs and AP, but not behind APs */
#define AXJTAG_EXPLORE_SET_MODE               0x00000020 /* Tell the firmware to re-set the SWD/JTAG mode */
#define AXJTAG_EXPLORE_FULL                   0x00000040 /* Full explore, skip the ID-based instantiation */
#define AXJTAG_EXPLORE_NOCLEAN                0x00000080 /* Skip cleanup if a release is performed */
#define AXJTAG_EXPLORE_WITH_AVE               0x00000100 /* Allow AVE coprocessors (certain SoCs only) */
#define AXJTAG_EXPLORE_IN_PROG                0x00000200 /* Explore currently in progress */
#define AXJTAG_EXPLORE_LOST                   0x00000400 /* Hidden flag, target lost re-explore */
#define AXJTAG_EXPLORE_PWRGATE                0x00000800 /* Allow all power-/clock-gating (certain SoCs only) */
#define AXJTAG_EXPLORE_NOPWRGATE              0x00001000 /* Prevent any power-/clock-gating (certain SoCs only) */
#define AXJTAG_EXPLORE_WITH_DISPLAY           0x00002000 /* Allow Display coprocessor (certain SoCs only) WARNING: Use --with-disp at your own risk, this option can damage the display hw */
#define AXJTAG_EXPLORE_JTAG_NO_BOUNDARY_SCAN  0x00004000 /* Explore JTAG without boundary scan */
#define AXJTAG_EXPLORE_WITH_SISP              0x00008000 /* Explore SISP coprocessors */
#define AXJTAG_EXPLORE_FC_JTAGAP              0x00010000 /* Probe forcefully behind the JTAG-APs */
#define AXJTAG_EXPLORE_IDENTIFY_SOC_ONLY      0x00020000 /* Identify the SoC but no more. In certain scenarios (i.e. isPanic), we don't want to be any more invasive than we have to be. */
#define AXJTAG_EXPLORE_WITHOUT_PIO_SAFEGUARDS 0x00040000 /* Tells the API to disable PIO safeguards (SoC specific) */
#define AXJTAG_EXPLORE_WITH_SEP_DEBUG         0x00080000 /* Show Specific SEP M3s */
#define AXJTAG_EXPLORE_SEP_NOPWRGATE          0x00100000 /* Set corenpdnrq on SEP to NOT powergate */
#define AXJTAG_EXPLORE_WITH_AUDIO             0x00200000 /* Explore Audio/DSP coprocessors (certain SoCs only) - Workaround for W2 "All CPUs Impeded" bug */
#define AXJTAG_EXPLORE_WITH_DCS               0x00400000 /* Show DCS coprocessors */
#define AXJTAG_EXPLORE_ONE_DIE                0x00800000 /* in multiple die configuration explore only the die astris is connecting to */

/* set of explore flags that imply no MEMAP accesses allowed */
#define AXJTAG_EXPLORE_NO_MEMAP (          \
        AXJTAG_EXPLORE_JTAGONLY            \
        | AXJTAG_EXPLORE_DAPONLY           \
        | AXJTAG_EXPLORE_APONLY            \
        | AXJTAG_EXPLORE_IDENTIFY_SOC_ONLY \
                                )

/* Default tckrate for probes */
#define KANZI_DEFAULT_TCKRATE     4420000               /* Default tckrate for Kanzi Probe */
#define KONG_DEFAULT_TCKRATE      1950000               /* Default tckrate for Kong Probe */
#define GORILLA_DEFAULT_TCKRATE   976000                /* Default tckrate for Gorilla Probe */
#define CHIMP_DEFAULT_TCKRATE     KANZI_DEFAULT_TCKRATE /* Default tckrate for Chimp Probe */
#define POODLE_DEFAULT_TCKRATE    KANZI_DEFAULT_TCKRATE /* Default tckrate for Poodle Probes */
#define KOBA_DEFAULT_TCKRATE      KANZI_DEFAULT_TCKRATE /* Default tckrate for Koba Probes */
#define PARROT_DEFAULT_TCKRATE    KANZI_DEFAULT_TCKRATE /* Default tckrate for Parrot Probes */
#define HIDBRIDGE_DEFAULT_TCKRATE KANZI_DEFAULT_TCKRATE /* Default tckrate for HIDBridge Probes */

/* Note about TARGETSEL (for SWD Multi-Drop support, a la ADI v5.2):
 * By default, any SWD DP comes out of SWD-Reset in a state where it is ready to
 * interact with a debugger. On a multi-drop SWD bus, it is necessary to tell
 * all-but-one DP to stop interacting (= go into the de-selected state) so that
 * we only interact with a single target DP at a time on the bus.
 * AXjtag_targetsel tells the probe to write a certain 32-bit pattern after it
 * sends SWD Reset, to de-select anyone other than the desired target. There are
 * two special values (see csprotocol.h):
 *
 *    0 indicates "do not write to TARGETSEL at all" (leave any SWD target selected)
 *    K_SWD_TARGETSEL_DONTCHANGE indicates "just tell me the probe's current value"
 *
 * It is fine not to ever call AXjtag_targetsel, if you are not on a multi-drop bus.
 */

int  AXjtag_chipcnt(AXconn_t *info, int *cnt);
int  AXjtag_explore(AXconn_t *info, unsigned int flags);
void AXjtag_release(AXconn_t *info, bool lost_target);
int  AXjtag_settck(AXconn_t *info, uint32_t newtck, uint32_t *oldtck);
int  AXjtag_targetsel(AXconn_t *info, uint32_t targetsel, uint32_t *oldtargetsel);
int  AXjtag_mode(AXconn_t *info, int newval);
int  AXjtag_swdreset(AXconn_t *info);
int  AXjtag_tgtstatus(AXconn_t *info);
int  AXjtag_spixact(AXconn_t *info, int cnt, uint8_t *inbits, uint8_t *outbits);
int  AXjtag_srst_mode(AXconn_t *info, AXchip_t *chip, int newval);

int AXjtag_gototlr(AXconn_t *info, AXchip_t *chip);
int AXjtag_gotorti(AXconn_t *info, AXchip_t *chip);
int AXjtag_idle(AXconn_t *info, AXchip_t *chip, int ncycles);
int AXjtag_pzdr(AXconn_t *info, AXchip_t *chip, int ncycles);
int AXjtag_srst(AXconn_t *info, AXchip_t *chip, int newval);
int AXjtag_trst(AXconn_t *info, AXchip_t *chip, int newval);
int AXjtag_setclr(AXconn_t *info, AXchip_t *chip, int cnt, uint8_t *outbits, uint8_t *setbits, uint8_t *clrbits);

/*!
* @function AXjtag_irscan
* @discussion This command moves the TAP to SHIFT_IR , scans the data in, and
* then place the TAP FSM in EXIT1_IR.
* @param info AXconn_t connection created with AXconn_create
* @param chip Chip repesenting the TAP interface
* @param cnt  The amount of bits to shift
* @param bits The data to shift into IR register
* @see AXconn_create
* @result An ASTRIS_ERR code
*/
int AXjtag_irscan(AXconn_t *info, AXchip_t *chip, int cnt, uint8_t *bits);
int AXjtag_sdscycle(AXconn_t *info, AXchip_t *chip, int ncycles);

#define AXJTAG_SCAN_IN1      0x04            /* Must match constants in csprotocol.h */
#define AXJTAG_SCAN_IN0      0x00
#define AXJTAG_SCAN_LOOPBACK 0x08

/*!
* @function AXjtag_scanout
* @discussion Scan out many bits, either scanning a constant value
* or looping TDO back as we go. The flag selects if you want to constantly scan
* in 0, or if you want to constantly scan in 1 (AXJTAG_SCAN_IN0 or AXJTAG_SCAN_IN1)
* or you can ask for loopback by giving AXJTAG_SCAN_LOOPBACK as the flag bit.
* In the end the TAP FSM will go EXIT1_DR.
* @param info AXconn_t connection created with AXconn_create
* @param chip Chip repesenting the TAP interface
* @param cnt  The amount of bits to shift
* @param outbits Buffer that will hold the data we shifted out
* @param flags One of the flag bits defined above in AXJTAG_SCAN_XXX
* @see AXconn_create
* @result An ASTRIS_ERR code
*/
int AXjtag_scanout(AXconn_t *info, AXchip_t *chip, int cnt, uint8_t *outbits, int flags);

/*!
* @function AXjtag_scan
* @discussion Cause TAP FSM to go to SHIFT_DR, scan data in/out
* then leave the TAP FSM in EXIT1_DR.
* You can also request to do a Capture -> Update DR by providing 0 to cnt.
* This will cause us to go CAPTURE_DR -> EXIT1_DR -> UPDATE_DR -> RTI
* @param info AXconn_t connection created with AXconn_create
* @param chip Chip repesenting the TAP interface
* @param cnt  The amount of bits to shift
* @param inbits The data to into the selected data registers
* @param outbits Buffer that will hold the data we shifted out
* @see AXconn_create
* @result An ASTRIS_ERR code
*/
int AXjtag_scan(AXconn_t *info, AXchip_t *chip, int cnt, uint8_t *inbits, uint8_t *outbits);

/*!
* @function AXjtag_scan_stay
* @discussion Same as AXjtag_scan but leave the TAP FSM in SHIFT_DR
* @param info AXconn_t connection created with AXconn_create
* @param chip Chip repesenting the TAP interface
* @param cnt  The amount of bits to shift
* @param inbits The data to into the selected data registers
* @param outbits Buffer that will hold the data we shifted out
* @see AXconn_create
* @result An ASTRIS_ERR code
*/
int AXjtag_scan_stay(AXconn_t *info, AXchip_t *chip, int cnt, uint8_t *inbits, uint8_t *outbits);

#define AXJTAG_XMITRAW_MAX 32
int AXjtag_transmitraw(AXconn_t *info, uint32_t *payload, uint32_t nbits);

/*
 * JTAG-AP stuff
 */

int AXjtagap_explore(AXap_t *ap, int port);

/* Panic API (note: panicstring will be allocated and caller must free, or it will be set to NULL)*/
int AXjtag_isPanic(AXconn_t *info, char **panicstring);
int AXjtag_isPanic_no_explore(AXconn_t *info, char **panicstring);
int AXjtag_isPanic_saveStackshot(AXconn_t *info, char **panicstring, char *output_dir_path);
int AXjtag_isPanic_saveStackshot_no_explore(AXconn_t *info, char **panicstring, char *output_dir_path);
int AXjtag_isPanic_noExplore(AXconn_t *info, AXchip_t *dapchip, char **panicstring, char *output_dir_path);
int AXjtag_Query_GreatDane(AXconn_t *info, char **gd_info_string);

/*
 * APIs for dealing with debug ports
 */

int     AXdp_scan(AXchip_t *chip, unsigned int flags);
void    AXdp_reinit(AXchip_t *chip);
int     AXdp_release(AXdp_t *dp, bool lost_target);
AXdp_t *AXdp_enum(AXconn_t *info, int idx);
AXdp_t *AXdp_fromchip(AXchip_t *chip);
int     AXdp_abort(AXdp_t *dp);
int     AXdp_write(AXdp_t *dp, uint32_t regaddr, uint32_t regval);
int     AXdp_read(AXdp_t *dp, uint32_t regaddr, uint32_t *regval);
int     AXdp_write_with_recovery(AXdp_t *dp, uint32_t regaddr, uint32_t regval);
int     AXdp_read_with_recovery(AXdp_t *dp, uint32_t regaddr, uint32_t *regval);
int     AXdp_readap(AXdp_t *dp, unsigned int select, unsigned int reg, uint32_t *regval);
int     AXdp_writeap(AXdp_t *dp, unsigned int select, unsigned int reg, uint32_t regval);

/*
 * APIs for dealing with individual chips on the chain
 */

AXchip_t *AXchip_enum(AXconn_t *info, int idx);
AXchip_t *AXchip_findidcode(AXconn_t *info, uint32_t idcode, int instance);

/*!
 @function AXchip_find_dap
 @discussion Get the chip struct that represents the DAP
 @param conn the connection handle for the session
 @param dap the DAP handle to be returned
 @result astris error code
 */
int AXchip_find_dap(AXconn_t *conn, AXchip_t **dap);

/*
    These are the type of things you can query with
    AXchip_getinfo. This is what you can pass into
    "info" variable in that function.
*/
#define AXCHIP_IDCODE   0
#define AXCHIP_HANDLE   1
#define AXCHIP_IRLEN    2
#define AXCHIP_IRBEFORE 3
#define AXCHIP_IRAFTER  4
#define AXCHIP_DRBEFORE 5
#define AXCHIP_DRAFTER  6
#define AXCHIP_FLAGS    7

/*
    These are the flags you can test against when using
    AXCHIP_FLAGS with AXchip_getinfo.
*/
#define AXCHIP_HAS_SWD_DP  0x00000001 /* Kinda not really JTAG chip related */
#define AXCHIP_HAS_JTAG_DP 0x00000002 /* XXX combine into HAS_DAP? */
#define AXCHIP_HAS_EICE    0x00000004
#define AXCHIP_HAS_DBGTAP  0x00000008
#define AXCHIP_HAS_KIS     0x00000010
#define AXCHIP_HAS_DPV3    0x00000020 /* Could infer this from version field but nice to be explict */

uint32_t AXchip_getinfo(AXchip_t *chip, int info);

typedef enum AXAXdfu_type_t {
    RELAY_DFU = 0,
    SPMI_DFU,
    DCM_DFU, /* Use KIS DCM Portal to drive GPIOs to PMU */
    EAM_DFU, /* Use External Authentication Module to allow Relay-DFU */
    MAX_DFU_TYPE
} AXdfu_type_t;

typedef struct AXproduct_info_s {
    const char  *product_name;
    const char  *pmu_name;
    AXdfu_type_t dfu_mode;
    bool         hard_dfu_support;
    uint32_t     board_id;
} AXproduct_info_t;

/*!
 @function AXproduct_get_info
 @discussion Retrieves product information about the device currently connected to and explored.
            This function works on only newer SoCs, if used with older SoC, it will return an error.
 @param chip Chip struct that could be gotten via AXchip_find_dap
 @param product_info pointer to a AXproduct_info_t structure that we will fill out with
        data.
 @result astris error code, will return not ASTRIS_ERR_NOTFOUND, if the currently connected
         device does not support this feature.
 */
int AXproduct_get_info(AXchip_t *chip, AXproduct_info_t *product_info);

/*!
 @function AXproduct_get_info_for_product
 @discussion Retrieves product information about the device given in product_name
 @param chip Chip struct that could be gotten via AXchip_find_dap
 @param product_name name of the product, this includes the form factor if the product you want has that.
        For example: "XYZ AP" or "XYZ DEV" should be how product_name looks like.
 @param product_info pointer to a AXproduct_info_t structure that we will fill out with
        data.
 @result astris error code, will return not ASTRIS_ERR_NOTFOUND, if the currently connected
         device does not support this feature OR if the product_name given is not valid.
 */
int AXproduct_get_info_for_product(AXchip_t *chip, const char *product_name, AXproduct_info_t *product_info);

typedef struct AXbypass_config_s {
    char    *device_name;
    uint32_t channel;
    uint32_t targetid;
    uint32_t instance;
} AXbypass_config_t;

/*!
 @function AXproduct_copy_bypass_info
 @discussion Copies bypass config of the product to AXbypass_config_t structure **configs
 @param chip Chip struct that could be gotten via AXchip_find_dap
 @param configs It holds pointer to AXbypass_config_t structure that we fill out
 @param len number of bypass targets
 @result astris error code, will return not ASTRIS_ERR_NOTFOUND, if the currently connected
         device does not support this feature.
 */
int AXproduct_copy_bypass_info(AXchip_t *chip, AXbypass_config_t **configs, int *len);

/*!
 @function AXproduct_copy_bypass_info_for_bid
 @discussion Copies bypass config of the product corresponds to given bid to configs
 @param chip Chip struct that could be gotten via AXchip_find_dap
 @param bid Board id that will be used to identify product to which bypass config is needed
 @param configs It holds pointer to AXbypass_config_t structure that we fill out
 @param len number of bypass targets
 @result astris error code, will return not ASTRIS_ERR_NOTFOUND, if the currently connected
         device does not support this feature.
 */
int AXproduct_copy_bypass_info_for_bid(AXchip_t *chip, uint32_t bid, AXbypass_config_t **configs, int *len);

/*!
 @function AXproduct_copy_bypass_info
 @discussion It will free pointer of AXbypass_config_t structure
 */
void AXproduct_free_bypass_info(AXbypass_config_t *configs);

/*!
 @function AXchip_bypass_with_name
 @discussion This function will do the first steps if setting up PS,TCK, TMS
 for a given bypass target just like setup_bypass but then it will also do the
 procedure of breaking the connection and bypassing to the given target
 @param chip Chip struct that could be gotten via AXchip_find_dap
 @param bypass_target_name name of bypass target you want us to bypass to.
 @param force_pins If you want us to configure PS,TMS & TCK for you.
 @param override_targetsel If you want us to override targetsel.
 @result astris error code, will return not ASTRIS_ERR_NOTFOUND, if the currently connected
         device does not support this feature OR if the name given is not valid.
*/
int AXchip_bypass_with_name(AXchip_t *chip, const char *bypass_target_name, bool force_pins, bool override_targetsel);

// Target OS types for an Apple SoC
typedef enum AXtargetos_e {
    ASTRIS_TARGET_OS_XNU,
    ASTRIS_TARGET_OS_RTKOS,
    ASTRIS_TARGET_OS_IBOOT,
    ASTRIS_TARGET_OS_OTHER,
} AXtargetos_t;

int AXchip_xnu_coredump_info(AXchip_t *chip, AXtargetos_t *target_os, AXmemaddr_t *base_addr, AXmemaddr_t *max_len, AXmemaddr_t *base_addr_sram, AXmemaddr_t *max_len_sram, bool *is_arm64,
                             bool *sys_snoop_cpu);
AXmemaddr_t AXchip_consistent_debug_root_register(AXchip_t *chip);

/*!
 @function AXchip_consistent_debug_find_record_address
 @discussion This function searches the Consistent Debug Registry for a record whose
             record-ID matches the ID passed in to it (first occurence only), and if
             such a record is found, the physical-address pointer passed in will
             get set to the PA in the Registry.
             The caller must specify which MEM-AP to go through (typically the
             AXI AP) when accessing the Registry (it lives in DRAM, and the SoC
             will have the root address in a PMGR scratch-register).
             If no matching registry record pointer is found, pa_ptr gets set to NULL.
             If there is an error (unable to access the registry) pa_ptr is not written,
             and a nonzero error code is returned.
 @param chip           Chip struct that could be gotten via AXchip_enum, AXchip_findidcode, or AXchip_find_dap
 @param ap                Which MEM-AP to use
 @param record_id 8-byte RecordID value to search for (normally ASCII, but not required to be)
 @param pa_ptr       Physical Address pointer to set if accessing Registry succeeds
 @result         astris error code , ASTRIS_ERR_OK if everything went fine
 */
int AXchip_consistent_debug_find_record_address(AXchip_t *chip, AXap_t *ap, uint64_t record_id, AXmemaddr_t *pa_ptr);

/*!
 @function AXchip_kis_enable_power
 @discussion This function is deprecated and not needed anymore.
             OLD INFO:
             This command is only needed and supported on few SoCs. Its job is to get
             the device in such a state that someone can switch and connect to KIS.
 @param chip Chip struct that could be gotten via AXchip_enum, AXchip_findidcode, or AXchip_find_dap
 @param force_wake Bool that represents if Astris should forcefully wake up the SoC
        if its already not in awake state.
 @result astris error code
 */
int AXchip_kis_enable_power(AXchip_t *chip, bool force_wake);

/*!
 @function AXchip_kis_disable_power
 @discussion This function is deprecated and not needed anymore.
             OLD INFO:
             This command is only needed and supported on few SoCs. Its job is to get
             return the device to such a state that power management behaves normally.
 @param chip Chip struct that could be gotten via AXchip_enum, AXchip_findidcode, or AXchip_find_dap
 @result astris error code
 */
int AXchip_kis_disable_power(AXchip_t *chip);

/*!
 @function AXconn_kis_enable
 @discussion This function brings out KIS on the particular device. You need to
             be connected to the primate probe that is connected to a KIS supported device,
             to call this function. Calling it while you are connected to KIS probe will get
             get you an error.
             On some SoCs this function will mean loosing mission USB, so know that.
             This function will call into AXchip_kis_enable_power as well, so dont need to call that before hand.
             The function will sever your explore, so act as if AXjtag_release got called
             when using this function, and re-explore if you want to keep talking to same probe.
             Your connection to the probe will remain.
 @param conn Connection object.
 @param force_wake A Bool that will get pased down to AXchip_kis_enable_power, option
                   is deprecated.
 @result astris error code , ASTRIS_ERR_OK everything went fine.
 */
int AXconn_kis_enable(AXconn_t *conn, bool force_wake);

/*!
 @function AXconn_kis_disable
 @discussion This function disable/put away KIS on the particular device. You need to
             be connected to the primate probe that is connected to a KIS supported device,
             to call this function. Calling it while you are connected to KIS probe will get
             you some bad results.
             On some SoCs this function will mean bring back mission USB.
             This function will call into AXchip_kis_disable_power as well, so dont need to call that before hand.
             The function will sever your explore, so act as if AXjtag_release got called.
             When using this function, and re-explore if you want to keep talking to same probe.
 @param conn Connection object.
 @result astris error code , ASTRIS_ERR_OK everything went fine.
 */
int AXconn_kis_disable(AXconn_t *conn);

/*!
 @function AXchip_kis_supported
 @discussion This function lets you know if the device supports KIS.
             A minimum explore is needed to at least find the type of SoC. You can use
             (AXJTAG_EXPLORE_SET_MODE | AXJTAG_EXPLORE_IDENTIFY_SOC_ONLY) flags
             with AXjtag_explore to do the minimum explore.
 @param chip Chip struct that could be gotten via AXchip_enum, AXchip_findidcode, or AXchip_find_dap
 @result astris error code , ASTRIS_ERR_OK if supported, other if it does not
 */
int AXchip_kis_supported(AXchip_t *chip);

/*!
 @function AXchip_get_board_id
 @discussion Get the board ID. This is currently supported on few SoCs.
 @param chip the chip to query
 @param board_id storage for the board ID
 @result astris error code
 */
int AXchip_get_board_id(AXchip_t *chip, uint32_t *board_id);

/*!
 @function AXchip_get_ecid
 @discussion Get ecid of the currently explored chip. Getting ECID is relied upon
 the authentication block. If you are connected to older SoC that does not have
 authentication or downstream SoC that maybe does not do auth, this function will
 return ASTRIS_ERR_NOTSUPPORTED.
 Even if authentication is supported ecid might return 0, if you have not
 authenticated enough, this is expected behavior, on some systems you have to auth
 for ECID to be visible.
 @param chip the chip to query
 @param ecid ECID of the currently explored SoC.
 @result astris error code. Will return ASTRIS_ERR_NOTSUPPORTED if the chip does
 not support auth. If not applesoc, it will return ASTRIS_ERR_BADPARAM.
 */
int AXchip_get_ecid(AXchip_t *chip, uint64_t *ecid);

/*!
 @function AXchip_get_sdom
 @discussion Get SECURITY_DOMAIN of the currently explored chip. Getting SDOM
 requires the authentication block. If you are connected to older SoC that does not have
 authentication or downstream SoC that maybe does not do auth, this function will
 return ASTRIS_ERR_NOTSUPPORTED.
 @param chip the chip to query
 @param sdom SECURITY_DOMAIN of the currently explored SoC.
 @result astris error code. Will return ASTRIS_ERR_NOTSUPPORTED if the chip does
 not support auth. If not applesoc, it will return ASTRIS_ERR_BADPARAM.
 */
int AXchip_get_sdom(AXchip_t *chip, uint8_t *sdom);

/*!
 @function AXchip_setup_coredump
 @discussion Setup the SoC for taking coredump like increasing clk.
             After taking coredump, AXchip_cleanup_coredump need to
             be called to restore SoC back to original state
 @param chip the chip to query
 @param cpuname name of cpu to which setup should be done.
 @result astris error code
 */
int AXchip_setup_coredump(AXchip_t *chip, const char *cpuname);

/*!
 @function AXchip_cleanup_coredump
 @discussion Should be used only after AXchip_setup_coredump to restore SoC to original state.
 @param chip the chip to query
 @param cpuname name of cpu to which cleanup should be done.
 @result astris error code
 */
int AXchip_cleanup_coredump(AXchip_t *chip, const char *cpuname);

/*!
 @function AXchip_switch_acg
 @discussion Turn off automatic clock gating chip wide, this
             only happens on certain SoCs. After calling this function,
             you have to call AXchip_restore_acg to put the original value,
             then you can call this function again.
 @param chip the chip to query
 @param on true will turn acg on, false will turn it off.
 @result astris error code. If the chip does not support it, then ASTRIS_ERR_NOTSUPPORTED
         is returned. If you call this function, after calling it already but before calling restore,
         ASTRIS_ERR_INVAL is returned, all other errors are for the transactions that this function creates.
 */
int AXchip_switch_acg(AXchip_t *chip, bool on);

/*!
 @function AXchip_restore_acg
 @discussion Should be used only after AXchip_switch_acg to restore the value.
 @param chip the chip to query
 @result astris error code. If the chip does not support it, then ASTRIS_ERR_NOTSUPPORTED
         is returned.
 */
int AXchip_restore_acg(AXchip_t *chip);

/*!
 @function AXchip_dfu
 @discussion Put the device into DFU, using method defined in SoC class.
 @param chip the chip handle
 @result astris error code
 */
int AXchip_dfu(AXchip_t *chip);

/*!
 @function AXchip_dfu_spmi
 @discussion Put the device into DFU via SPMI.
 @param chip the chip handle
 @result astris error code
 */
int AXchip_dfu_spmi(AXchip_t *chip);

/*!
 @function AXchip_dfu_eam
 @discussion Put the device into DFU via EAM.
 @param chip the chip handle
 @result astris error code
 */
int AXchip_dfu_eam(AXchip_t *chip);

/*!
 @function AXchip_nmi
 @discussion Put the device into NMI (AP Panic). This is currently supported on some SoCs,
             and OS version that is being run. Please use AXjtag_isPanic to check
             if NMI actually occured. This only works after booting.
 @param chip the chip handle
 @result astris error code
 */
int AXchip_nmi(AXchip_t *chip);

/*!
 @function AXchip_nmi_smc
 @discussion NMI the SMC causing an RTKit panic and dump to happen, little bit different
             then regular NMI. This is currently supported on some SoCs,
             and OS version that is being run. Please use AXjtag_isPanic to check
             if NMI actually occured. This only works after booting.
 @param chip the chip handle
 @result astris error code
 */
int AXchip_nmi_smc(AXchip_t *chip);

/*!
 @function AXchip_nmi_ap_watchdog
 @discussion Signal the AP Watchdog via the SMC to detect an iOS panic and generate a SOCD, if possible
             Please use AXjtag_isPanic to check if the watchdog was detected and SOCD was generated
             This only works after booting, with software and hardware support in the SoC and OS
 @param chip the chip handle
 @result astris error code
 */
int AXchip_nmi_ap_watchdog(AXchip_t *chip);

/*!
 @function AXchip_is_stop_clocked
 @discussion This function checks for the stop clocked condition of a given chip.
 @param chip the chip to query
 @result astris error code. ASTRIS_ERR_OK is returned if NOT stop clocked, ASTRIS_ERR_STOPCLOCK if stop clock IS detected and
        if the chip does not support it, then ASTRIS_ERR_NOTSUPPORTED is returned.
 */
int AXchip_is_stop_clocked(AXchip_t *chip);

/*!
 @function AXchip_is_dfu
 @discussion This function checks device is in DFU
 @param chip the chip to query
 @result astris error code. ASTRIS_ERR_OK is returned if chip has DFU_STATUS register,
         if the chip does not support it, then ASTRIS_ERR_NOTSUPPORTED is returned.
         isdfu will be true if device is in DFU
 */
int AXchip_is_dfu(AXchip_t *chip, bool *isdfu);

/*!
 @function AXchip_get_current_die
 @discussion If the chip as SoC and it is AppleSoC, then, for multi-die SoC current_die is set to the connected die index.
 @param chip the chip to query
 @param current_die output die index
 @result astris error code. ASTRIS_ERR_OK indicates that current_die was set. If SoC does not support multiple dies
         ASTRIS_ERR_NOTSUPPORTED is returned. If chip is NULL or chip->soc is NULL, then  ASTRIS_ERR_BADPARAM
         is returned.
 */
int AXchip_get_current_die(AXchip_t *chip, int *current_die);

/*!
 @function AXchip_switch_taps
 @discussion If the SoC supports multiple dies, then this function will configure JTAG bypass to sepecified tap.
 @param chip the chip to switch taps on.
 @param tap_to_switch_to tap number to switch to, allowed values are SoC specific.
 @result astris error code. ASTRIS_ERR_OK indicates that the TAP switch was successful. If SoC does not support multiple dies
         ASTRIS_ERR_NOTSUPPORTED is returned. If chip is NULL, chip->soc is NULL or target TAP is out of range, then
         ASTRIS_ERR_BADPARAM is returned.
 */
int AXchip_switch_taps(AXchip_t *chip, unsigned int tap_to_switch_to);

/*!
* @function AXchip_is_prod_fused
* @discussion This function will let you know if a device is production fused or not.
* The function only will work on newer SoCs that have debug auth, will error if
* older SoC.
* @param chip Chip struct that could be gotten via AXchip_enum, AXchip_findidcode, or AXchip_find_dap
* @param is_prod This will be filled with true or false based if the device is prod fused.
* @result An ASTRIS_ERR code. Will return ASTRIS_ERR_NOTSUPPORTED if the device is too old.
*/
int AXchip_is_prod_fused(AXchip_t *chip, bool *is_prod);

typedef enum {
    ASTRIS_DOCK_DISCONNECT_GET = 0,
    ASTRIS_DOCK_DISCONNECT_AUTOMATIC,
    ASTRIS_DOCK_DISCONNECT_DISABLE,
    ASTRIS_DOCK_DISCONNECT_FORCE
} ax_dock_operation_t;

/*!
 @function AXchip_dock_disconnect_mode
 @discussion If the SoC uses relays to trigger dock disconnect, this function allows obtaining current mode and/or set the new mode value.
 @param[in] chip the chip to set the dock disconnect mode for.
 @param[in] operation operation to perform.
 @param[out] previous value of the setting prior to this call
 @result astris error code. ASTRIS_ERR_OK indicates that the setting operation was performed successfully. If SoC does not support dock disconnect
         ASTRIS_ERR_NOTSUPPORTED is returned. If chip is NULL, chip->soc is NULL or target TAP is out of range, then
         ASTRIS_ERR_BADPARAM is returned.
 */
int AXchip_dock_disconnect_mode(AXchip_t *chip, ax_dock_operation_t operation, ax_dock_operation_t *previous);

/*
 * APIs for dealing with access ports
 */

AXap_t *AXap_by_select(AXdp_t *dp, int select);
AXap_t *AXap_by_type(AXdp_t *dp, int type);
AXap_t *AXap_system_bus(AXdp_t *dp);
int     AXap_select(AXap_t *ap);
int     AXap_get_type(AXap_t *ap);
int     AXap_read(AXap_t *ap, uint32_t regaddr, uint32_t *regval);
int     AXap_write(AXap_t *ap, uint32_t regaddr, uint32_t regval);
int     AXap_readbuf(AXap_t *ap, uint32_t regaddr, uint32_t *regval, int nwords);
int     AXap_writebuf(AXap_t *ap, uint32_t regaddr, uint32_t *regval, int nwords);

/*
 * MEM-AP specific APIs
 */

/*
 * Talking to the thing behind the MEM-AP (APB/AHB/AXI bus)
 */
int AXmemap_read(AXap_t *ap, AXmemaddr_t regaddr, uint32_t *regval);
int AXmemap_write(AXap_t *ap, AXmemaddr_t regaddr, uint32_t regval);
int AXmemap_read64(AXap_t *ap, AXmemaddr_t regaddr, uint64_t *regval);
int AXmemap_write64(AXap_t *ap, AXmemaddr_t regaddr, uint64_t regval);
int AXmemap_readmemblock(AXap_t *ap, AXmemaddr_t address, uint32_t *length, uint8_t *buffer);
int AXmemap_writememblock(AXap_t *ap, AXmemaddr_t address, uint32_t *length, uint8_t *buffer);
int AXmemap_readvals(AXap_t *ap, AXmemaddr_t busaddr, uint8_t *vals, int size, uint32_t *count, bool fifo);
int AXmemap_writevals(AXap_t *ap, AXmemaddr_t busaddr, uint8_t *vals, int size, uint32_t *count, bool fifo);

/*!
 * @function AXmemap_read_get_field
 * @abstract Helper function that can be used to extract a specific field from a
 * address.
 * @discussion This function is AXmemap_read, but instead of giving you the whole
 * value it just extracts a specific field from the value
 * @param ap   AP object that can be gotten with functions like AXap_by_select or
 * AXap_system_bus.
 * @param regaddr Address on the AP bus given.
 * @param field_val Reference to a uint32_t that will be filled out on return
 * @param field_width The width of the field to extract.
 * @param field_offset The start of the field to extract.
 * @param desc Optional description string of the register or value, this is used for
 * internal logging, you can just provide NULL if this is not wanted.
 * @return An Astris error code.
 */
int AXmemap_read_get_field(AXap_t *ap, AXregaddr_t regaddr, uint32_t *field_val, uint32_t field_width, uint32_t field_offset, const char *desc);

/*!
 * @function AXmemap_read_modify_write
 * @abstract Helper function that can be used to do a read modify write of a
 * register.
 * @discussion This function is AXmemap_write, but instead of overwriting the
 * whole value it can write to a specified bit field of the register. This is
 * accomplished by first reading the address, clearing the field, and then
 * masking and shifting the value in. Finally writing the new value back into
 * given address.
 * @param ap AP object that can be gotten with functions like AXap_by_select or
 * AXap_system_bus.
 * @param regaddr Address on the AP bus given.
 * @param field_val The value you want to write into the specified field
 * @param field_width The width of the field to extract.
 * @param field_offset The start of the field to extract.
 * @param desc Optional description string of the register or value, this is used for
 * internal logging, you can just provide NULL if this is not wanted.
 * @return An Astris error code.
 */
int AXmemap_read_modify_write(AXap_t *ap, AXregaddr_t regaddr, uint32_t field_val, uint32_t field_width, uint32_t field_offset, const char *desc);

/*
 * Flasher Astris API
*/
int AXmemap_lmflash(AXap_t *ap, uint32_t flashbase, uint32_t flashcmd, uint32_t offset, uint32_t *data, int nwords);
int AXmemap_adiflash(AXap_t *ap, AXmemaddr_t addr, uint32_t len, void *buf, bool eraseall, bool quiet);
int AXmemap_stmflash(AXap_t *ap, AXmemaddr_t addr, uint32_t len, void *buf, bool eraseall, bool quiet, uint32_t flashByteWidth);
int AXmemap_adierase(AXap_t *ap, AXmemaddr_t addr, uint32_t len, bool eraseall, bool quiet);
int AXmemap_stmerase(AXap_t *ap, AXmemaddr_t addr, uint32_t len, bool eraseall, bool quiet);
int AXmemap_nxpflash(AXap_t *ap, AXmemaddr_t addr, uint32_t len, void *buf, bool eraseall, bool quiet);
int AXmemap_nxpflashInternal(AXap_t *ap, AXmemaddr_t addr, uint32_t len, void *buf, bool eraseall, bool quiet, bool verify, bool addChecksum);
int AXmemap_nxperase(AXap_t *ap, AXmemaddr_t addr, uint32_t len, bool eraseall, bool quiet);

/*!
 * @function AXmemap_read_aligning
 * @abstract Helper function that can take unaligned address, and bytes to read from
 * that address
 * @discussion This is a helper function that ends up using AXmemap_readvals.
 * The function is able to take an address thats not aligned to width and bytes to read.
 * Bytes to read also does not need to be in intervals of width.
 * Example you can ask to read 7 bytes with width 4 that starts at 0x80e00c003, and this function will
 * Read 1 byte at 0x80e00c003, then read 4 bytes at 0x80e00c004, and then 2 bytes
 * at 0x80e00c008.
 * @param ap   AP object that can be gotten with functions like AXap_by_select or
 * AXap_system_bus.
 * @param pa Address on the AP bus given.
 * @param width Width of the access should be either 4 or 8. This will also be used
 * as the alignment for the address.
 * @param length Pointer to the total BYTES to read. On return if result == ASTRIS_ERR_OK
 * this will be filled out with the number of bytes read.
 * @param buffer Preallocated buffer, where this function will store the read bytes into
 * @return An Astris error code.
 */
int AXmemap_read_aligning(AXap_t *ap, AXmemaddr_t pa, uint32_t width, uint32_t *length, uint8_t *buffer);

// For Now These Are Hardcoded For CCG2

typedef struct AXmemap_cyflash_params_s {
    void       *buffer;
    size_t      buffer_size;
    AXmemaddr_t dest;
} AXmemap_cyflash_params_t;

int AXmemap_cyerase(AXconn_t *info, AXap_t *ap);
int AXmemap_cyflash(AXconn_t *info, AXap_t *ap, void *buffer, size_t buff_size, bool eraseall);
int AXmemap_cyacquire(AXconn_t *info, AXap_t *ap);

/* Currently this method is only supported for PSOC6 2M */
int AXmemap_cyflash_advance(AXconn_t *info, AXap_t *ap, AXmemap_cyflash_params_t params, bool eraseall);

/*
 * Nordic Semiconductor nRF528XX APIs
 */
int AXmemap_nrfcheckapprotect(AXconn_t *conn, AXap_t *ap, bool *approtect);
int AXmemap_nrferaseallapprotect(AXconn_t *conn, AXap_t *ap);
int AXmemap_nrferaseall(AXconn_t *conn, AXap_t *ap);
int AXmemap_nrfflash(AXconn_t *conn, AXap_t *ap, AXmemaddr_t addr, void *buf, uint32_t len, bool eraseall, bool verify);

/*
 * TI BQ7037 APIs
 */
int AXmemap_tiflash_bq7037(AXconn_t *info, AXap_t *ap, AXmemaddr_t addr, uint32_t len, void *buf, bool verify, bool eraseChip);

/*
 * Talking to things behind a MEM-AP (in its subordinate APB).
 * This variant adds in the debug base for the specific device
 * behind the Mem-AP we're after
 */
int AXdebug_write(AXtgt_t *tgt, AXregaddr_t regaddr, uint32_t regval);
int AXdebug_read(AXtgt_t *tgt, AXregaddr_t regaddr, uint32_t *regval);
int AXdebug_writebuf(AXtgt_t *tgt, AXregaddr_t regaddr, uint32_t *regval, int *nwords);
int AXdebug_readbuf(AXtgt_t *tgt, AXregaddr_t regaddr, uint32_t *regval, int *nwords);

/*
 * 1500 APB Bridge APIs
 */

/*!
 @function AX1500_listbridges
 @abstract Print the names and address ranges of all 1500 bridges to the console
 @param domain The Astris log domain, e.g. AXLOG_M_MEM1500
 @param category The Astris log category, e.g. AXL_U_ERR
 @param conn Astris connection object for the session
 @return The number of bridges, or an Astris error code
 */
int AX1500_listbridges(const char *domain, unsigned long long category, AXconn_t *conn);

/*!
 @function AX1500_transact
 @abstract Read/write data over a 1500-2-APB bridge
 @param conn Astris connection object for the session
 @param name The name of the bridge to use (optional)
 @param address The starting address for the transaction
 @param data A pointer to the preallocated data buffer
 @param write True for writes, false for reads
 @param width The word size in bytes
 @param count The number of words to transfer
 @param fifo Don't increment the address after each word
 @result An Astris error code
 */
int AX1500_transact(AXconn_t *conn, const char *name, AXregaddr_t address, void *data, bool write, int width, size_t count, bool fifo);

/*
 * Target, CPU enumeration
 */
AXtgt_t *AXconn_enumtgt(AXconn_t *conn, int idx);
AXcpu_t *AXconn_enumcpu(AXconn_t *conn, int idx);
AXcpu_t *AXconn_getcpubyname(AXconn_t *info, const char *cpuname);

/*!
 @function AXconn_getcpu_in_group
 @discussion Get CPU in group, this function is useful to get CPUs in a particular
 group, for example the main cores are usually in group 0, so if you want to get
 first core of the group 0, you would put group=0,idx=0.
 @param conn Connection object you get from AXconn_create
 @param group CPU group to get the CPU from.
 @param idx The index of the CPU within the group. Idx starts with zero as first.
 @result pointer to AXcpu_t structure, will return NULL if did not find matching
 cpu
 */
AXcpu_t *AXconn_getcpu_in_group(AXconn_t *conn, uint32_t group, uint32_t idx);

/*
 * ARM7-specific APIs
 */
int AXarm7_dbgwrite(AXchip_t *chip, uint32_t regno, uint32_t val);
int AXarm7_dbgread(AXchip_t *chip, uint32_t regno, uint32_t *val);
int AXarm7_dbgscan(AXchip_t *chip, uint32_t outbreak, uint32_t outval, uint32_t *inbreak, uint32_t *inval, unsigned int flags);

/*
 * Relays
 */
#define AXRELAY_NAMELEN 16
int AXrelay_get(AXconn_t *info, const char *name);
int AXrelay_set(AXconn_t *info, const char *name, int val);
int AXrelay_enum(AXconn_t *info, int ridx, char *name, int *val);

/*
 * Bitstring
 */

typedef struct AXbits_s {
    int     nbits;       /* # of bits */
    void   *description; /* points to abstract description, tbd */
    uint8_t bits[];      /* bits go here */
} AXbits_t;

AXbits_t *AXbits_new(int nbits);

/*!
 @function AXbits_new_with_bits
 @discussion This is just like AXbits_new but will copy the byte array given
 into the bits here so if you already have a created byte array you can just
 use it here without needing to use AXbits_replace or AXbits_pack_field to
 fill the bits out.
 @param nbits Number of bits this bit object should hold
 @param bits Byte array that will be copied and be used as initial data for AXbits
 @result pointer to AXbits structure described above.
 */
AXbits_t          *AXbits_new_with_bits(int nbits, uint8_t *bits);
void               AXbits_destroy(AXbits_t *bits);
void               AXbits_clear(AXbits_t *bits);
int                AXbits_get(const AXbits_t *bits, int idx);
int                AXbits_format(const AXbits_t *bits, char *str, int len, bool reverse);
void               AXbits_replace(AXbits_t *bits, int idx, int width, unsigned long long val, int reverse);
unsigned long long AXbits_extract(const AXbits_t *bits, int idx, int width, int reverse);
void               AXbits_pack_field(AXbits_t *bits, int *idx, int width, unsigned long long val, bool reverse);
unsigned long long AXbits_unpack_field(const AXbits_t *bits, int *idx, int width, bool reverse);
void               AXbits_log(const char *domain, unsigned long long category, const char *prefix, const AXbits_t *bits);

/*
 * CPU API
 */
// Array index enums for astris_cpu.cpp:: static const char *astris_cpu_cache_shared_name[AXCPU_CACHE_SHARED_COUNT]
typedef enum {
    AXCPU_CACHE_SHARED_NONE      = 0, /* CPU has no cache at the given cache level */
    AXCPU_CACHE_SHARED_DEDICATED = 1, /* CPU has a dedicated cache (not shared outside given CPU) */
    AXCPU_CACHE_SHARED_GROUP     = 2, /* CPU has a cache that is shared with other CPUs of the group */
    AXCPU_CACHE_SHARED_COHERENT  = 3, /* CPU has a cache that is coherent with higher memory layers */
    AXCPU_CACHE_SHARED_COUNT     = 4
} AXcpu_cache_shared_t;

// Array index enums for astris_cpu.cpp:: static const char *astris_cpu_cache_level_name[AXCPU_CACHE_LEVEL_COUNT]
typedef enum {
    AXCPU_CACHE_LEVEL_1_INSTR = 0, /* L1 instruction cache is represented as cache level 0 */
    AXCPU_CACHE_LEVEL_1_DATA  = 1, /* L1 data cache */
    AXCPU_CACHE_LEVEL_2       = 2, /* L2 cache */
    AXCPU_CACHE_LEVEL_3       = 3, /* L3 cache */
    AXCPU_CACHE_LEVEL_COUNT   = 4
} AXcpu_cache_level_t;

typedef struct AXcachelevel_s {
    AXcpu_cache_shared_t shared; /* type of cache sharing at given level */
} AXcachelevel_t;

typedef struct AXcacheinfo_s {
    AXcachelevel_t level[AXCPU_CACHE_LEVEL_COUNT]; /* information about each cache level applicable to given CPU */
} AXcacheinfo_t;

const char *AXcpu_name(AXcpu_t *cpu);
int         AXcpu_index(AXcpu_t *cpu);
int         AXcpu_group(AXcpu_t *cpu);

int AXcpu_halt(AXcpu_t *cpu);
int AXcpu_collect(AXcpu_t *cpu, int timeout);

/*!
@function AXcpu_resume
@discussion This command just resumes the core, keeping watchpoints and breakpoints
    in place.
*/
int AXcpu_resume(AXcpu_t *cpu);
int AXcpu_sstep(AXcpu_t *cpu);

/*!
@function AXcpu_go
@discussion This function unlike resume, actually goes and turns off
    breakpoints and watchpoints, singlesteps, and then puts back bp, wps and
    finally resumes the core.
*/
int AXcpu_go(AXcpu_t *cpu);

int AXcpu_status(AXcpu_t *cpu);

/*!
 @function AXcpu_halted
 @discussion Returns whether cpu is in halted debug state
 Valid states are: AXCPU_STATUS_HALT, AXCPU_STATUS_SWBP, AXCPU_STATUS_HWBP, AXCPU_STATUS_HWWP,
 AXCPU_STATUS_VECT, AXCPU_STATUS_STEP, AXCPU_STATUS_EXC
 CPU needs to be in halted/ halted debug state before performing memory accesses
 @param cpu CPU that we want to check is in halted debug state
 @result returns true if cpu is in halted debug state, false if not
*/
bool AXcpu_halted(AXcpu_t *cpu);

const char *AXcpu_status_name(int status);
const char *AXcpu_status_name_detailed(int status, uint32_t flags);
int         AXcpu_abandon(AXcpu_t *cpu);

/*!
     @struct AXcpu_status_s
     @abstract Struct that contains the detailed status. Only newer ASC cores
     we will be able to fill out the pmgr and asc fields.
     @field standard One of the defines from AXCPU_STATUS_XXX
     @field pmgr One of defines AXCPU_PMGR_XXX
     @field asc One of defines AXCPU_PMGR_XXX
     @field indicators One of defines AXCPU_STFLAG_XXX
*/
typedef struct AXcpu_status_s {
    uint32_t standard;
    uint32_t pmgr;
    uint32_t asc;
    uint32_t indicators;
} AXcpu_status_t;

#define AXCPU_PMGR_OFF     0
#define AXCPU_PMGR_CG      1
#define AXCPU_PMGR_RUN     3
#define AXCPU_PMGR_OFFLINE 4
#define AXCPU_PMGR_INVALID (-1)

#define AXCPU_ASC_OFF     0
#define AXCPU_ASC_RUN     1
#define AXCPU_ASC_WAKE    2
#define AXCPU_ASC_WFI     3
#define AXCPU_ASC_INVALID (-1)

/*!
 * @function AXcpu_detailed_status
 * @abstract Get detailed CPU status.
 * @discussion This function provides detailed status for newer ASC cores.
 * If you call this function on a core that does not support detailed status
 * pmgr and asc fields would be set to invalid. User should check these fields
 * before using them.
 * @param cpu   Astris connection struct
 * @param detailed_status A reference to a struct that will get filled out.
 * @return If less than 0 its an error, else its the same as the AXcpu_status
 *         which equals to detailed_status.standard value.
 *         Caller of this function should check if less than 0, then values
 *         in detailed_status are not valid.
 *         Only some CPUs fill out pmgr and asc portion of the struct so user
 *.        of this function should check that they are not set to INVALID.
 */
int AXcpu_detailed_status(AXcpu_t *cpu, AXcpu_status_t *detailed_status);

const char *AXcpu_status_pmgr(int pmgr);
const char *AXcpu_status_asc(int asc);

// XXX encode these so "halted", "unknown", ?? are easy
#define AXCPU_STATUS_RESET    0
#define AXCPU_STATUS_RUN      1
#define AXCPU_STATUS_HALT     2
#define AXCPU_STATUS_SWBP     3
#define AXCPU_STATUS_HWBP     4
#define AXCPU_STATUS_HWWP     5
#define AXCPU_STATUS_VECT     6
#define AXCPU_STATUS_OFF      7
#define AXCPU_STATUS_STEP     8
#define AXCPU_STATUS_EXC      9
#define AXCPU_STATUS_NEW      10
#define AXCPU_STATUS_PWRGATED 11
#define AXCPU_STATUS_INVALID  (-1)

/* Status flags */
#define AXCPU_STFLAG_PWROFF     1
#define AXCPU_STFLAG_RESET      2
#define AXCPU_STFLAG_WAKE       4
#define AXCPU_STFLAG_ACC_LOCKED 8

#define AXCPU_HAS_POWERTRANSITIONED ( \
        AXCPU_STFLAG_PWROFF           \
        | AXCPU_STFLAG_RESET          \
        | AXCPU_STFLAG_WAKE           \
        | AXCPU_STFLAG_ACC_LOCKED     \
                                    )

#define AXCPU_DEFAULT_TIMEOUT 3 // default seconds before CPU operation timeout

int AXcpu_readreg(AXcpu_t *cpu, AXregid_t regno, AXregval_t *regval);
int AXcpu_writereg(AXcpu_t *cpu, AXregid_t regno, AXregval_t regval);
int AXcpu_readreg_vals(AXcpu_t *cpu, AXregid_t regno, uint8_t *buffer, uint32_t *reg_size);
int AXcpu_writereg_vals(AXcpu_t *cpu, AXregid_t regno, uint8_t *buffer, uint32_t *reg_size);

// Error code for address translation function
#define TRANSLATION_ERR_L0 1 /* VA to PA translation failed at Level 0 */
#define TRANSLATION_ERR_L1 2 /* VA to PA translation failed at Level 1 */
#define TRANSLATION_ERR_L2 3 /* VA to PA translation failed at Level 2 */
#define TRANSLATION_ERR_L3 4 /* VA to PA translation failed at Level 3 */

// return code indicates error in performing address translation and 'result' indicates error code in PAR register after performing address translation
// On failure, return code will be one of ASTRIS_ERR_XXX and 'result' will be either one of ASTRIS_ERR_XXX or one of TRANSLATION_ERR_XXX.
// On success, both return code and 'result' will be ASTRIS_ERR_OK
int AXcpu_translate_par(AXcpu_t *cpu, AXmemaddr_t va, AXregval_t *par, bool write, int *result);
int AXcpu_translate(AXcpu_t *cpu, AXmemaddr_t va, AXmemaddr_t *pa, bool write, int *result);
int AXcpu_translate_with_stage(AXcpu_t *cpu, AXmemaddr_t va, AXmemaddr_t *pa, bool write, uint8_t stage, int *result);

int AXcpu_readmem(AXcpu_t *cpu, AXmemaddr_t address, uint32_t *length, uint8_t *buffer);
int AXcpu_writemem(AXcpu_t *cpu, AXmemaddr_t address, uint32_t *length, uint8_t *buffer, int iflush);
int AXcpu_writemem_width(AXcpu_t *cpu, AXmemaddr_t address, uint32_t *length, uint8_t *buffer, int iflush, int width);
int AXcpu_flush_icache(AXcpu_t *cpu, AXmemaddr_t address, uint32_t length);
int AXcpu_clean_dcache(AXcpu_t *cpu, AXmemaddr_t address, uint32_t length);
int AXcpu_cleaninv_dcache(AXcpu_t *cpu, AXmemaddr_t address, uint32_t length);
int AXcpu_cache_info(AXcpu_t *cpu, AXcacheinfo_t *info);
int AXcpu_cache_clean(AXcpu_t *cpu, AXcpu_cache_level_t cache_level);
int AXcpu_cache_cleaninv(AXcpu_t *cpu, AXcpu_cache_level_t cache_level);

const char *AXcpu_cache_shared_name(AXcpu_cache_shared_t shared);
const char *AXcpu_cache_level_name(AXcpu_cache_level_t level);

int AXcpu_suspend_translation(AXcpu_t *cpu);
int AXcpu_resume_translation(AXcpu_t *cpu);

int AXcpu_getmode(AXcpu_t *cpu, const char **mode, uint32_t cpsr);
int AXcpu_read_dcc(AXcpu_t *cpu, int *got_val, uint32_t *val);

// This struct a copy of rtxcid_t
typedef struct AXrtxcid_s {
    uint32_t magic;
    uint32_t version;
    uint32_t rtxc_version;   // RTKit Version Build String
    uint32_t client_version; // DISP 6.2
    uuid_t   uuid;
    uint64_t aslr_slide;
} __attribute__((packed)) AXrtxcid_t;

int AXcpu_get_rtxcid(AXcpu_t *cpu, AXrtxcid_t *out_sw_info);

int AXcpu_getinfo(AXcpu_t *cpu, int whichinfo, unsigned whichspecific, void *info);

#define AXCPUINFO_TYPE       0
#define AXCPUINFO_ARCH       1
#define AXCPUINFO_BP_COUNT   2
#define AXCPUINFO_WP_COUNT   3
#define AXCPUINFO_BP_MASK    4
#define AXCPUINFO_WP_MASK    5
#define AXCPUINFO_REGWIDTH   6
#define AXCPUINFO_ADDRESS    7
#define AXCPUINFO_BP_ENABLED 8
#define AXCPUINFO_WP_ENABLED 9

#define AXCPUTYPE_CORTEX_A8   0
#define AXCPUTYPE_CORTEX_A9   1
#define AXCPUTYPE_CORTEX_A5   2
#define AXCPUTYPE_CORTEX_M3   3
#define AXCPUTYPE_ARM7        4
#define AXCPUTYPE_ARM11       5
#define AXCPUTYPE_SWIFT       6
#define AXCPUTYPE_CORTEX_M0   7
#define AXCPUTYPE_UNKNOWN     8
#define AXCPUTYPE_CORTEX_M4   9
#define AXCPUTYPE_CYCLONE     10
#define AXCPUTYPE_CORTEX_A7   11
#define AXCPUTYPE_CORTEX_R5   12
#define AXCPUTYPE_TYPHOON     13
#define AXCPUTYPE_TWISTER     14
#define AXCPUTYPE_BIGLITTLE   15
#define AXCPUTYPE_CORTEX_M7   16
#define AXCPUTYPE_MARIN       17
#define AXCPUTYPE_MONSOON     18
#define AXCPUTYPE_MISTRAL     19
#define AXCPUTYPE_CHINOOK     20
#define AXCPUTYPE_VORTEX      21
#define AXCPUTYPE_TEMPEST     22
#define AXCPUTYPE_HIFI3       23
#define AXCPUTYPE_CHINOOKASC3 24
#define AXCPUTYPE_LIGHTNING   25
#define AXCPUTYPE_THUNDER     26
#define AXCPUTYPE_FIRESTORM   27
#define AXCPUTYPE_ICESTORM    28
#define AXCPUTYPE_CHINOOKASC4 29
#define AXCPUTYPE_TEMPESTASC4 30
#define AXCPUTYPE_CORTEX_M33  31
#define AXCPUTYPE_CORTEX_A53  32
#define AXCPUTYPE_CHINOOKASC5 33
#define AXCPUTYPE_TEMPESTASC5 34
#define AXCPUTYPE_BLIZZARD    35
#define AXCPUTYPE_AVALANCHE   36
#define AXCPUTYPE_CHINOOKASC6 37
#define AXCPUTYPE_TEMPESTASC6 38
#define AXCPUTYPE_SAWTOOTH    39
#define AXCPUTYPE_EVEREST     40
#define AXCPUTYPE_CORTEX_M23  41
#define AXCPUTYPE_ARC_DSP     42
#define AXCPUTYPE_LACC        43
#define AXCPUTYPE_ACCE_H16G   44
#define AXCPUTYPE_ACCP_H16G   45
#define AXCPUTYPE_CHINOOKASC7 46
#define AXCPUTYPE_TEMPESTASC7 47

#define AXCPUARCH_ARMV7   0
#define AXCPUARCH_ARMV7M  1
#define AXCPUARCH_ARMV4   2
#define AXCPUARCH_ARMV6   3
#define AXCPUARCH_ARMV6M  4
#define AXCPUARCH_UNKNOWN 5
#define AXCPUARCH_ARMV8   6
#define AXCPUARCH_ARMV7EM 7
#define AXCPUARCH_XTENSA  8
#define AXCPUARCH_ARMV8M  9
#define AXCPUARCH_ARC     10
#define AXCPUARCH_LACC    11

/*
 * Breakpoints and watchpoints
 */

typedef enum lacc_bp_type_s {
    PC = 0,
    DA,
    STAT,
    COUNT,
    SUSPEND
} lacc_bp_type_t;

typedef enum pipe_stage_s {
    F1 = 0,
    F2,
    AD,
    DC,
    E1,
    E2,
    V1,
    V2,
    V3,
    V4,
    VW
} pipe_stage_t;

// AXdbgwrap_block_t is for accessing debug features of ASC or ACC in dbgwrap
typedef enum AXdbgwrap_block_s {
    DBGWRAP_ACC = 0,
    DBGWRAP_ASC,
    DBGWRAP_NONE
} AXdbgwrap_block_t;

typedef struct bpwp_info_s {
    AXmemaddr_t address;
    int         index;
    uint32_t    size;
    uint32_t    flags;
    uint32_t    data;
    bool        enabled;
} bpwp_info_t;

/* Access modes for watchpoint matching
   These are put in the flags section
*/
#define AXCPUWP_RDWR_LOAD  0
#define AXCPUWP_RDWR_STORE 1
#define AXCPUWP_RDWR_ANY   2
#define AXCPUWP_RDWR_KINDS 3

/* Breakpoint */
int AXcpu_hwbp_info(AXcpu_t *cpu, int index, bpwp_info_t *info);
int AXcpu_hwbp_insert(AXcpu_t *cpu, AXmemaddr_t address);
int AXcpu_hwbp_remove(AXcpu_t *cpu, int which_bp);
int AXcpu_hwbp_enable(AXcpu_t *cpu, int index);
int AXcpu_hwbp_disable(AXcpu_t *cpu, int index);

int AXcpu_lacc_status_insert(AXcpu_t *cpu, int status, uint32_t mask);
int AXcpu_lacc_status_remove(AXcpu_t *cpu, int status, uint32_t mask);
int AXcpu_lacc_count_insert(AXcpu_t *cpu, uint32_t packet_count);
int AXcpu_lacc_count_remove(AXcpu_t *cpu);
int AXcpu_lacc_count_clear(AXcpu_t *cpu);
int AXcpu_lacc_count_read(AXcpu_t *cpu, uint32_t *count);
int AXcpu_lacc_pipe_set(AXcpu_t *cpu, lacc_bp_type_t bp_type, bool pipe);
int AXcpu_lacc_bp_status(AXcpu_t *cpu, lacc_bp_type_t bp_type, uint32_t *reach);
int AXcpu_lacc_pc_status(AXcpu_t *cpu, pipe_stage_t stage, uint32_t *pc);

/* Watchpoint */
int AXcpu_hwwp_info(AXcpu_t *cpu, int index, bpwp_info_t *info);
int AXcpu_hwwp_enable(AXcpu_t *cpu, int index);
int AXcpu_hwwp_disable(AXcpu_t *cpu, int index);
int AXcpu_hwwp_insert(AXcpu_t *cpu, AXmemaddr_t address, uint32_t len, int rdwr);
int AXcpu_hwwp_remove(AXcpu_t *cpu, uint32_t which_wp);

/* Software breakpoint */
int AXcpu_swbp_info(AXcpu_t *cpu, int index, bpwp_info_t *info);
int AXcpu_swbp_insert(AXcpu_t *cpu, AXmemaddr_t address, int len);
int AXcpu_swbp_remove(AXcpu_t *cpu, int which_bp);

/*
 * CPU complex API
 */

/*!
 @function AXcomplex_halt
 @discussion Halt the CPUs in the given complex
 @param conn Connection for the session
 @param complex the name of the complex
 @param dump_regs Dump important registers to stdout after collection
 @param force_halt Forcibly halt all of the CPUs in the complex
 @result astris error code
 */
int AXcomplex_halt(AXconn_t *conn, const char *complex, bool dump_regs, bool force_halt);

/*!
 @function AXcomplex_go
 @discussion Resume the CPUs in the given complex
 @param conn Connection for the session
 @param complex_id the name of the complex
 @result astris error code
 */
int AXcomplex_go(AXconn_t *conn, const char *complex_id);

/*!
 @function AXdbgwrap_block_get_cpus
 @discussion Get the list of cpus that are present in the given dbgwrap block type. Allocation
 of cpu_list is done by this function so need to free it using AXdbgwrap_block_destroy_list
 @param chip AXchip_t That maps to the DAP/SoC you are talking to. This can be
 retrieved by AXchip_find_dap
 @param dbgwrap_block the AXdbgwrap_block_t type, DBGWRAP_ACC or DBGWRAP_ASC
 @param cpu_list Reference to array of AXcpu_t * that are present in the dbgwrap block
 @result astris error code
 */
int AXdbgwrap_block_get_cpus(AXchip_t *chip, AXdbgwrap_block_t dbgwrap_block, AXcpu_list_t *cpu_list);

/*!
 @function AXdbgwrap_block_destroy_list
 @discussion It will destroy CPU list created by AXdbgwrap_block_get_cpus
 @param cpu_list Reference to array of AXcpu_t *
 */
void AXdbgwrap_block_destroy_list(AXcpu_list_t *cpu_list);

/*!
 @function AXdbgwrap_block_halt
 @discussion Halt the ACC or ASC CPUs using EDBGRQ register in dbgwrap
 @param chip AXchip_t That maps to the DAP/SoC you are talking to. This can be
 retrieved by AXchip_find_dap
 @param dbgwrap_block the AXdbgwrap_block_t type, DBGWRAP_ACC or DBGWRAP_ASC
 @param dump_regs Dump important registers to stdout after collection
 @param force_halt Forcibly halt all of the CPUs in the ACC or ASC block
 @result astris error code
 */
int AXdbgwrap_block_halt(AXchip_t *chip, AXdbgwrap_block_t dbgwrap_block, bool dump_regs, bool force_halt);

/*!
 @function AXdbgwrap_block_go
 @discussion Resume the ACC or ASC CPUs using DBGRESTART register in dbgwrap
 @param chip AXchip_t That maps to the DAP/SoC you are talking to. This can be
 retrieved by AXchip_find_dap
 @param dbgwrap_block the AXdbgwrap_block_t type, DBGWRAP_ACC or DBGWRAP_ASC
 @result astris error code
 */
int AXdbgwrap_block_go(AXchip_t *chip, AXdbgwrap_block_t dbgwrap_block);

// TODO: We really need API functions to list all of the complexs for an SoC. But alas, we have no real SoC API...

typedef struct AXdart_entry_s {
    AXmemaddr_t pa;
    AXmemaddr_t va;
    AXmemaddr_t size;
    bool        rd_prot;
    bool        wr_prot;

    AXmemaddr_t region_start;
    AXmemaddr_t region_end;
    uint8_t     sid;
} AXdart_entry_t;

typedef struct AXdart_info_s {
    uint64_t pa_addr_width;
    uint64_t va_addr_width;

    uint64_t page_size;

    uint64_t page_addr_width;
    uint64_t ttbr_width;
    uint64_t sgmt_width;
} AXdart_info_t;

/*!
 @function AXdart_walk
 @discussion Walk one DVA to a PA.
 @param dart_base Address of where the dart block starts
 @param dart_type If NULL, will try to pick the right Dart style based on SoC.
                  The valid types are based on names of SoCs that they are shipped with.
 @param ap AP to use to address the base and do the walk
 @param va An address we need to translate from DVA to PA
 @param pa Reference to an address, this address will be filled out if the walk succeeds.
 @result astris error code
 */
int AXdart_walk(AXmemaddr_t dart_base, const char *dart_type, AXap_t *ap, AXmemaddr_t va, AXmemaddr_t *pa, uint32_t sid);

/*!
 @function AXdart_dump
 @discussion Walk the whole DART, then printing out the whole translation table.
             This function can take some time, so please be patient.
 @param dart_base Address of where the dart block starts
 @param dart_type If NULL, will try to pick the right Dart style based on SoC.
                  The valid types are based on names of SoCs that they are shipped wit
 @param ap AP to use to address the base and do the walk
 @result astris error code
 */
int AXdart_dump(AXmemaddr_t dart_base, const char *dart_type, AXap_t *ap);

/*!
 @function AXdart_get_table
 @discussion Walk the whole DART, then put together an array of dart table entries
             and return that to the user.
 @param dart_base Address of where the dart block starts
 @param dart_type If NULL, will try to pick the right Dart style based on SoC.
                  The valid types are based on names of SoCs that they are shipped wit
 @param ap AP to use to address the base and do the walk
 @param dart_table Reference to an array of struct AXdart_entry_t. This array of
        dart entries will get filled out by the function. Table entries will tell you how
        big the array is so you can walk it. It is up to the caller to free the array.
 @param table_entries Reference to an integer, that will get filled out to say how
        many entries in the array of dart_table there are.
 @result astris error code
 */
int AXdart_get_table(AXmemaddr_t dart_base, const char *dart_type, AXap_t *ap, AXdart_entry_t **dart_table, int *table_entries);

/*!
 @function AXdart_get_table
 @discussion Walk the whole DART, then put together an array of dart table entries
             and return that to the user.
 @param dart_base Address of where the dart block starts
 @param dart_type If NULL, will try to pick the right Dart style based on SoC.
                  The valid types are based on names of SoCs that they are shipped wit
 @param ap AP to use to address the base and do the walk
 @param dart_info Reference to a  AXdart_info_t struct that will get filed out on
        function success.
 @result astris error code
 */
int AXdart_get_info(AXmemaddr_t dart_base, const char *dart_type, AXap_t *ap, AXdart_info_t *dart_info);

/* These functions are exactly like the ones above but work on a CPUs DART*/
int AXcpu_dart_walk(AXcpu_t *cpu, AXmemaddr_t va, AXmemaddr_t *pa);
int AXcpu_dart_dump(AXcpu_t *cpu);
int AXcpu_dart_get_table(AXcpu_t *cpu, AXdart_entry_t **dart_table, int *table_entries);
int AXcpu_dart_get_info(AXcpu_t *cpu, AXdart_info_t *dart_info);

/*!
 @function AXcpu_has_dart
 @discussion Given a CPU, this function will tell you if there is a
             DART associated with the CPU
 @param cpu CPU to check.
 @result boolean that is true, if there is a DART present.
 */
bool AXcpu_has_dart(AXcpu_t *cpu);

int AXcpu_get_dart_addr(AXcpu_t *cpu, AXmemaddr_t *dart_addr);

/*!
 @function AXapf_dump
 @discussion Walk the whole APF, then printing out the mappings.
 @param apf_base Address of where the APF block starts
 @param apf_type This should be NULL for now, its not used, meant for future.
 @param apf_count Number of APF entries to print.
 @param ap AP to use to address the base and do the walk
 @param category Logging level for the print to happen at for example: AXL_U_STD
                 or AXL_U_ERR, mean print to standard out or standard error.
 @result astris error code
 */
int AXapf_dump(AXmemaddr_t apf_base, const char *apf_type, uint32_t apf_count, AXap_t *ap, uint64_t category);

/*!
 @function AXapf_walk
 @discussion Translate an address using the APF mappings
 @param apf_base Address of where the APF block starts
 @param apf_type This should be NULL for now, its not used, meant for future.
 @param apf_count Number of APF entries to walk, in order to translate the given address.
 @param ap AP to use to address the base and do the walk
 @param va An address we need to translate.
 @param pa Reference to an address, this address will be filled out if the walk succeeds.
 @result astris error code
 */
int AXapf_walk(AXmemaddr_t apf_base, const char *apf_type, uint32_t apf_count, AXap_t *ap, AXmemaddr_t va, AXmemaddr_t *pa);

/*
 * META CPU routines
 */
AXmeta_t   *AXmeta_enum(AXconn_t *conn, int index);
AXmeta_t   *AXmeta_by_name(AXconn_t *conn, const char *name);
const char *AXmeta_name(AXmeta_t *meta);

int AXmeta_readreg(AXmeta_t *meta, int regno, uint32_t *regval);
int AXmeta_writereg(AXmeta_t *meta, int regno, uint32_t regval);

int AXmeta_readblock(AXmeta_t *meta, uint32_t address, uint32_t nwords, uint8_t *data);
int AXmeta_writeblock(AXmeta_t *meta, uint32_t address, uint32_t nwords, uint8_t *data);

int AXmeta_set_thread(AXmeta_t *meta, int thread_id);

/*
 * GDB server
 */

typedef enum {
    AXGDB_PRECEDENCE_OFF       = 0,
    AXGDB_PRECEDENCE_PRIMARY   = 1,
    AXGDB_PRECEDENCE_SECONDARY = 2,
    AXGDB_PRECEDENCE_TERTIARY  = 3,
    AXGDB_PRECEDENCE_EXCLUSIVE = 4,
    AXGDB_PRECEDENCE_COUNT     = 5
} AXgdb_precedence_t;

typedef enum {
    AXGDB_SOURCE_NONE   = 0,
    AXGDB_SOURCE_DEVICE = 1,
    AXGDB_SOURCE_CORE   = 2,
    AXGDB_SOURCE_LOG    = 3,
    AXGDB_SOURCE_QUERY  = 4,
    AXGDB_SOURCE_PLAYER = 5,
    AXGDB_SOURCE_COUNT  = 6
} AXgdb_source_t;

#define GDBSRV_DFLT_PORT -1
int         AXgdbsrv_start(AXconn_t *, uint32_t, const char *);
const char *AXgdbsrv_refresh(AXconn_t *, uint32_t, const char *);
int         AXgdbsrv_stop(AXconn_t *);
bool        AXgdbsrv_running(AXconn_t *);
const char *AXgdbsrv_info(AXconn_t *, bool);
int         AXgdbsrv_suspend(AXconn_t *);
int         AXgdbsrv_resume(AXconn_t *);
const char *AXgdbsrv_render(AXconn_t *info, AXgdb_source_t source, AXgdb_precedence_t precedence, const char *filename);

#define GDB_OPT_NOGROUPS 0x0001
void AXgdbsrv_setopt(AXconn_t *, unsigned, unsigned);

/*
 * USB probe firmware update
 */
typedef enum {
    kUSBUpdateSuccess = 0,

    // These could be destructive failures
    kUSBUpdateUnknownError = -1,
    kUSBUpdateTimeOut      = -2,

    // These are non-destructive update errors (ie the device should power cycle itself and try again)
    kUSBUpdateNonDestructiveFail = -100,
    kUSBUpdateConnectFailure     = -101,

    kUSBUpdateIOKitUnableToCreatePlugin               = -110,
    kUSBUpdateIOKitUnableToGetDeviceInterface         = -111,
    kUSBUpdateIOKitUnableToGetDeviceInterfaceIterator = -112,
    kUSBUpdateIOKitUnableToCreateInterfacePlugin      = -113,
    kUSBUpdateIOKitUnableToGetInterfaceInterface      = -114,
    kUSBUpdateIOKitUnableToOpenInterface              = -115,

    kUSBUpdateDiskDescFail         = -129,
    kUSBUpdateNoModelFail          = -130,
    kUSBUpdateNoVendorFail         = -131,
    kUSBUpdateNoVolumeNameFail     = -132,
    kUSBUpdateNoVolumePathFail     = -133,
    kUSBUpdatePathTooLongFail      = -134,
    kUSBUpdateOpenFirmwareFileFail = -135,
    kUSBUpdateGetStartBlockFail    = -136,
    kUSBUpdateGetBlockDeviceFail   = -137,
    kUSBUpdateNoProbeFail          = -138,
    kUSBUpdateBlockSizeFail        = -139,
    kUSBUpdateGetFilePathFail      = -140,
    kUSBUpdateSourceOpenFail       = -141,
    kUSBUpdateBlockDevOpenFail     = -142,
    kUSBUpdateNoPermission         = -143,
    kUSBUpdateMallocFail           = -144,

    // Theses are destructive (ie will require cp -X to recover)
    kUSBUpdateFatalError       = -200,
    kUSBUpdateBlockReadError   = -201,
    kUSBUpdateBlockWriteError  = -202,
    kUSBUpdateDeviceDisconnect = -203,
    kUSBUpdateUSBTimeout       = -204,
    kUSBUpdateVerifyFail       = -205,

} USBUpdateErrorCode_t;

typedef void (*progressCallback_t)(const char *, double, void *refcon);
int GorUpdateProgress(AXconn_t *info, const char *filename, progressCallback_t callback, void *refcon);
int GorUpdate(AXconn_t *info, const char *fname);
int KanziUpdateProgress(AXconn_t *info, uint32_t serialNum, const char *filename, progressCallback_t callback, void *refcon);

/*
 * Front-panel I2C interface (on a black-box Astris probe)
 */

#define AXGENI2C_NOSTOP 1
int AXgeni2c_speed(AXconn_t *info, int speed);
int AXgeni2c_send(AXconn_t *info, uint8_t addr, uint8_t *data, int len, unsigned int flags);
int AXgeni2c_recv(AXconn_t *info, uint8_t addr, uint8_t *data, int len, unsigned int flags);
int AXgeni2c_poll(AXconn_t *info, uint8_t addr, unsigned int flags);
int AXgeni2c_eewrite(AXconn_t *info, uint8_t eeaddr, unsigned int offset, uint8_t *data, int len);
int AXgeni2c_eeread(AXconn_t *info, uint8_t eeaddr, unsigned int offset, uint8_t *data, int len);

/*
 * SPMI operations (PMU connected to the SoC)
 * Right now our support if exists handles the SPMI interface that connects to the PMU.
 */

typedef uint8_t  astris_spmi_dev_addr_t; // Device addresses are 8 bits
typedef uint16_t astris_spmi_reg_addr_t; // An SPMI device has a 16-bit address map

int AXspmi_read(AXchip_t *chip, astris_spmi_dev_addr_t dev_addr, astris_spmi_reg_addr_t reg_addr, uint64_t *value, uint8_t count);
int AXspmi_write(AXchip_t *chip, astris_spmi_dev_addr_t dev_addr, astris_spmi_reg_addr_t reg_addr, uint64_t value, uint8_t count);
int AXspmi_read_bus(AXchip_t *chip, uint8_t bus_sel, astris_spmi_dev_addr_t dev_addr, astris_spmi_reg_addr_t reg_addr, uint64_t *value, uint8_t count);
int AXspmi_write_bus(AXchip_t *chip, uint8_t bus_sel, astris_spmi_dev_addr_t dev_addr, astris_spmi_reg_addr_t reg_addr, uint64_t value, uint8_t count);

/*
 * AWL operations
 */
typedef struct AXawl_tgt_info_s {
    char   *name;
    uint8_t tgt_num;
    uint8_t die_id;
} AXawl_tgt_info_t;

/*!
 @function AXawl_list
 @brief This function will return a list of known AWL targets. To note this function
 allocates an array of AXawl_tgt_info_t structs for the caller and its up to them to free it
 after use.
 @param chip AXchip_t That maps to the DAP/SoC you are talking to. This can be
 retrieved by AXchip_find_dap
 @param tgts This is a reference to a pointer. On return of this function the
 array will be filled out with AXawl_tgt_info_t stucts that the caller now owns.
 @param tgt_count reference to an int that will be filled out on return to let the
 caller know the array count
 @return ASTRIS_ERR_XYZ code
 */
int AXawl_list(AXchip_t *chip, AXawl_tgt_info_t **tgts, int *tgt_count);

/*!
 @function AXawl_list_free
 @brief Helper function to free list of targets retrieved via AXawl_list function.
 @param tgts Pointer to array of tgts
 @param tgt_count Count of targets that are in the array.
 */
void AXawl_list_free(AXawl_tgt_info_t *tgts, uint8_t tgt_count);

/*!
 @function AXawl_send
 @brief This function will allow the user to do a raw send to the AWL bus.
 @param chip AXchip_t That maps to the DAP/SoC you are talking to. This can be
 retrieved by AXchip_find_dap
 @param tgt This is a pointer to an AWL target you want to send the data to. Please
 note that tgt given does not need to come from AXawl_list command. You can and should just create
 a local struct and pass it along to this method describing which target you want to talk to.
 @param cmd 32bit word array of the data that will be sent with the first word describing the LSB
 of the data to write out to. So cmd[0] represents the lowest bits and msg[count-1] represents the highest
 bits to write in.
 @param count The length of the cmd array given.
 @return ASTRIS_ERR_XYZ code
 */
int AXawl_send(AXchip_t *chip, AXawl_tgt_info_t *tgt, uint32_t *cmd, uint8_t count);

/*!
 @function AXawl_receive
 @brief This function will allow the user to do a raw receive of the AWL bus.
 @param chip AXchip_t That maps to the DAP/SoC you are talking to. This can be
 retrieved by AXchip_find_dap
 @param tgt This is a pointer to an AWL target you want to send the data to. Please
 note that tgt given does not need to come from AXawl_list command. You can and should just create
 a local struct and pass it along to this method describing which target you want to talk to.
 @param output reference to a 32bit pointer that will be filled out on function return. It is
 up to the caller to then free this array.
 @param count The length in 32bits words of the output array that is returned.
 @return ASTRIS_ERR_XYZ code
 */
int AXawl_receive(AXchip_t *chip, AXawl_tgt_info_t *tgt, uint32_t **output, uint8_t *count);

/*!
 @function AXawl_cpu_power_status
 @brief Helper command that will do a send followed by a receive on the AWL bus.
 The command that will be encoded is the CPU Power Status command.
 @param chip AXchip_t That maps to the DAP/SoC you are talking to. This can be
 retrieved by AXchip_find_dap
 @param tgt This is a pointer to an AWL target you want to send the data to. Please
 note that tgt given does not need to come from AXawl_list command. You can and should just create
 a local struct and pass it along to this method describing which target you want to talk to.
 @param output reference to a 32bit pointer that will be filled out on function return. It is
 up to the caller to then free this array.
 @param count The length in 32bits words of the output array that is returned.
 @return ASTRIS_ERR_XYZ code
 */
int AXawl_cpu_power_status(AXchip_t *chip, AXawl_tgt_info_t *tgt, uint32_t **output, uint8_t *count);

/*!
 @function AXawl_cpu_dvfm
 @brief Helper command that will do a send followed by a receive on the AWL bus.
 The command that will be encoded is the CPU DVFM command. Please note that reading,
 CPU registers via AWL require special order; refer to the manual on the order.
 @param chip AXchip_t That maps to the DAP/SoC you are talking to. This can be
 retrieved by AXchip_find_dap
 @param tgt This is a pointer to an AWL target you want to send the data to. Please
 note that tgt given does not need to come from AXawl_list command. You can and should just create
 a local struct and pass it along to this method describing which target you want to talk to.
 @param output reference to a 32bit pointer that will be filled out on function return. It is
 up to the caller to then free this array.
 @param count The length in 32bits words of the output array that is returned.
 @return ASTRIS_ERR_XYZ code
 */
int AXawl_cpu_dvfm(AXchip_t *chip, AXawl_tgt_info_t *tgt, uint32_t **output, uint8_t *count);

/*!
 @function AXawl_cpu_dvfm
 @brief Helper command that will do a send followed by a receive on the AWL bus.
 The command that will be encoded is the CPU DVFM command. Please note that reading,
 CPU registers via AWL require special order; refer to the manual on the order.
 @param chip AXchip_t That maps to the DAP/SoC you are talking to. This can be
 retrieved by AXchip_find_dap
 @param tgt This is a pointer to an AWL target you want to send the data to. Please
 note that tgt given does not need to come from AXawl_list command. You can and should just create
 a local struct and pass it along to this method describing which target you want to talk to.
 @param array_index Index that you would like to fetch.
 @param output Reference to a 32bit pointer that will be filled out on function return. It is
 up to the caller to then free this array.
 @param count The length in 32bits words of the output array that is returned.
 @return ASTRIS_ERR_XYZ code
 */
int AXawl_cpu_prb_dsb(AXchip_t *chip, AXawl_tgt_info_t *tgt, uint32_t array_index, uint32_t **output, uint8_t *count);

typedef enum {
    AXAWL_CPU_SCRATCH0,
    AXAWL_CPU_SCRATCH1,
    AXAWL_CPU_RETIREPC,
    AXAWL_CPU_PSTATE,
    AXAWL_CPU_ESR_EL1,
    AXAWL_CPU_ESR_EL2,
    AXAWL_CPU_FAR_EL1,
    AXAWL_CPU_FAR_EL2,
    AXAWL_CPU_ELR_EL1,
    AXAWL_CPU_ELR_EL2,
    AXAWL_CPU_VTTBR_EL2,
    AXAWL_CPU_HCR_EL2,
    AXAWL_CPU_VTCR_EL2
} AXawl_cpu_reg_t;

/*!
 @function AXawl_cpu_reg
 @brief Helper command that will do a send followed by a receive on the AWL bus.
 The command that will be encoded is the CPU register read of a given register. Note
 that not all registers are supported by all CPU AWL targets. Please note that reading,
 CPU registers via AWL require special order; refer to the manual on the order.
 @param chip AXchip_t That maps to the DAP/SoC you are talking to. This can be
 retrieved by AXchip_find_dap
 @param tgt This is a pointer to an AWL target you want to send the data to. Please
 note that tgt given does not need to come from AXawl_list command. You can and should just create
 a local struct and pass it along to this method describing which target you want to talk to.
 @param core Core number in the CPU cluster that you are selecting via tgt
 @param reg_name Register you would like to be read out.
 @param output Reference to a 32bit pointer that will be filled out on function return. It is
 up to the caller to then free this array.
 @param count The length in 32bits words of the output array that is returned.
 @return ASTRIS_ERR_XYZ code
 */
int AXawl_cpu_reg(AXchip_t *chip, AXawl_tgt_info_t *tgt, uint32_t core, AXawl_cpu_reg_t reg_name, uint32_t **output, uint8_t *count);

/*!
 @function AXawl_pms_read
 @brief Helper command that will do a send followed by a receive on the AWL bus.
 The command that will be encoded is a PMS read.
 @param chip AXchip_t That maps to the DAP/SoC you are talking to. This can be
 retrieved by AXchip_find_dap
 @param tgt This is a pointer to an AWL target you want to send the data to. Please
 note that tgt given does not need to come from AXawl_list command. You can and should just create
 a local struct and pass it along to this method describing which target you want to talk to.
 @param pms_reg The SoC address in PMS space to be read. This variable can be the full
 address within the PMS region and the function will correctly mask the address before sending it
 over the bus.
 @param output Reference to a 32bit pointer that will be filled out on function return. It is
 up to the caller to then free this array.
 @param count The length in 32bits words of the output array that is returned.
 @return ASTRIS_ERR_XYZ code
 */
int AXawl_pms_read(AXchip_t *chip, AXawl_tgt_info_t *tgt, AXmemaddr_t pms_reg, uint32_t **output, uint8_t *count);

/*
 * SMBus operations ("I2C" devices connected to the SoC)
 */
/*!
 @function AXsmb_read
 @discussion Use the hardware SMB (I2C) registers on an SoC to read from
             a specified device on a specified bus. It is the caller's responsibility to
             halt CPUs if necessary to allow Astris to use the registers that
             correpsond to that bus.
 @param chip SoC control structure to handle specifics like GPIO pins and mapping to SMB registers
 @param bus Index of which SMBus to use
 @param dev_addr device address (10-bit address not currently supported).
            NOTE: the 7 address bits should be in bits [7:1] of the address, since bit 0 is
            the R/nW bit of the SMBus/I2C command.
 @param reg_addr contains the bytes for a "Dummy Write" (if requested)
 @param addr_len should be:
            0 if no "Dummy Write" should be transmitted (so `reg_addr` ignored),
            1 if one byte of register address should be dummy-written prior to Read,
            2 if two bytes should be transmitted during the "Dummy Write" prior to Read
              (a 16-bit register address is transmitted High byte first, then Low byte).
 @param data pointer to where the received bytes should be saved
 @param count (in/out) number of bytes to attempt to read - must be 0 to 255. The caller is
            responsible for making sure the device's internal address pointer does not
            wrap around and cause the wrong locations to be read (usually this means
            not straddling a 256-byte-aligned boundary, but YMMV for your device).
            Since a transaction can fail partway through, count is in/out and will
            return the number of successfully-read bytes (or 0 if none were read).
 @return Astris error code
 @result Parameter count will be updated to reflect the number of bytes successfully transferred
 */
int AXsmb_read(AXchip_t *chip, uint8_t bus, uint32_t dev_addr, uint32_t reg_addr, uint8_t addr_len, uint8_t *data, size_t *count);

/*!
 @function AXsmb_write
 @discussion Use the hardware SMB (I2C) registers on an SoC to write to
             a specified device on a specified bus. It is the caller's responsibility to
             halt CPUs if necessary to allow Astris to use the registers that
             correpsond to that bus.
             NOTE:  All bytes pointed to by `data` will be transmitted in order after the
             SMB write-command byte. Some devices interpret the first one or two bytes as a
             register-address, but that depends on the type of device.
 @param chip SoC control structure to handle specifics like GPIO pins and mapping to SMB registers
 @param bus Index of which SMBus to use
 @param dev_addr device address (10-bit address not currently supported).
            NOTE: the 7 address bits should be in bits [7:1] of the address, since bit 0 is
            the R/nW bit of the SMBus transaction.
 @param data pointer to where the received bytes should be saved
 @param count (in/out) number of bytes to attempt to write - must be 0 to 255. The caller is
            responsible for making sure the device's internal address pointer does not
            wrap around and cause the wrong locations to be written (usually this means
            not straddling a 256-byte-aligned boundary, but YMMV for your device)
            Since a transaction can fail partway through, count is in/out and will
            return the number of successfully-written bytes (or 0 if none were written).
 @return Astris error code
 @result Parameter count will be updated to reflect the number of bytes successfully transferred
 */
int AXsmb_write(AXchip_t *chip, uint8_t bus, uint32_t dev_addr, uint8_t *data, size_t *count);


/*!
 @function AXbreadcrumbs_read
 @discussion Read all SoC breadcrumbs
 @param chip SoC control structure to read crumbs from
 @param crumbs_info_string string to read in breadcrumbs info
 @return Astris error code
 */
int AXbreadcrumbs_read(AXchip_t *chip, char **crumbs_info_string);

/*!
 @function AXbreadcrumbs_clear
 @discussion Clear all SoC breadcrumbs
 @param chip SoC control structure to clear crumbs from
 @return Astris error code
 */
int AXbreadcrumbs_clear(AXchip_t *chip);

/*
 * EEPROM services
 */
#define AXENVSET_TARGET        0
#define AXENVSET_INTERPOSER    1
#define AXENVSET_DAUGHTERBOARD 2
#define AXENVSET_PREAMP        3
#define AXENVSET_COUNT         4

typedef struct AXenvset_s AXenvset_t;
int   AXeeprom_load(AXconn_t *info, int envidx);
int   AXeeprom_ispresent(AXconn_t *info, int envidx);
int   AXeeprom_saveenv(AXconn_t *info, int envidx);
int   AXeeprom_getenv(AXconn_t *info, int envidx, char *name, char **value);
int   AXeeprom_delenv(AXconn_t *info, int envidx, char *name);
int   AXeeprom_setenv(AXconn_t *info, int envidx, char *name, char *value);
int   AXeeprom_init(AXconn_t *info, int envidx);
int   AXeeprom_enumenv(AXconn_t *info, int envidx, int idx, char **name, char **value);
void *AXeeprom_iterator(AXconn_t *info, int envidx, void *position, char **name, char **value);
void  AXeeprom_free_env(AXconn_t *info, int envidx);
void  AXeeprom_free_all(AXconn_t *info);

/*
 * Interfaces for SMC SOC Diagostic Info (SOCD)
 */

#define SOCD_MAX_CONTAINERS 2

typedef struct {
    bool     pri_valid;
    uint32_t pri_size;
    bool     sec_valid;
    uint32_t sec_size;
} AXsocd_info_t;

/*!
 @function AXsocd_info
 @discussion Access SOCD header(s) to read magic word and size
 @param[in] info   Pointer to Astris connection context object
 @param[in,out] socd_info SOCD info structure with valid and size in bytes of the corresponding PMU SOCD region
 @note array size is SOCD_MAX_CONTAINERS
 @return Astris return code
 */
int AXsocd_info(AXconn_t *info, AXsocd_info_t *socd_info);

/*!
@function AXsocd_extract
@discussion Read SOCD region(s) into (a) file(s)
@param[in] info Astris connection context object
@param[in] output_dir_path path to save SOCD data
@param[in,out] count number of SOCD containers written
@return Astris return code
*/
int AXsocd_extract(AXconn_t *info, const char *output_dir_path, uint8_t *count);

/*!
@function AX_socd_invalidate
@discussion Write to SOCD header(s) to invalidate the SOCD magic word(s) in the system
@param[in] info Astris connection context object
@return Astris return code
*/
int AXsocd_invalidate(AXconn_t *info);

typedef struct AXhang_info_s {
    AXmemaddr_t address;
    char       *description;
    char       *radar_info;
    bool        dumped_to_user;
} AXhang_info_t;

/*!
@function AXhang_info_get
@discussion Get hang info
@param chip The AXchip_t object for the DAP can be gotten with
            AXchip_find_dap command
@param info reference to a AXhang_info_t pointer, on return the
            pointer will either be NULL or point to a valid AXhang_info_t
            struct. Caller of the API does not own the struct, and should not
            free it under Astris API.
@return Astris return code, either ASTRIS_ERR_OK if parameter is good, or
        ASTRIS_ERR_BADPARAM if chip is NULL. The caller should get if info pointer
        to see if its NULL on ASTRIS_ERR_OK to tell if a hang has been detected.
*/
int AXhang_info_get(AXchip_t *chip, AXhang_info_t **info);

/*!
@function AXhang_info_print
@discussion Print hang info the same way that we would to the user when the hang
            was originall detected.
@param chip The AXchip_t object for the DAP can be gotten with
            AXchip_find_dap command
@param log_category An astris log category, AXL_STD, AXL_U_ERR, etc.
@return Astris return code, either ASTRIS_ERR_OK if parameter is good, or
        ASTRIS_ERR_BADPARAM if chip is NULL.
*/
int AXhang_info_print(AXchip_t *chip, uint64_t log_category);

/*
 * Assertion, Abort and Exit handling
 *
 * The AXassert macros and functions perform a specific type of verification.
 * If the given verification fails then actions are taken to collect as much
 * information as possible about what led up to the problem.
 *
 * A category mask is used to specify the types of modules that are involved in
 * the given verification. If the verification fails then all registered
 * assertion handlers are upcalled as a trigger to dump out any information that
 * could be helpful in diagnosing the root cause of the problem.
 *
 * Types of 'assertions':
 *   assert: perform a check - if the check fails then dump info and terminate
 *   abort: dump info and terminate by calling abort
 *   exit: dump info and terminate by calling exit(1)
 */

/*---------------------------------------------------------------------------*
 * Assertion Termination Reasons
 *---------------------------------------------------------------------------*/
typedef enum {
    AXA_TERM_NORMAL = 0, /* normal termination (no failed assert/abort/exit(n) */
    AXA_TERM_ASSERT = 1, /* terminating due to failed assertion */
    AXA_TERM_ABORT  = 2, /* terminating due to an abort call */
    AXA_TERM_EXIT   = 3  /* terminating due to a non-zero exit call  */
} axa_term_t;

/*---------------------------------------------------------------------------*
 * Assertion Base Areas - each defined to act as base for area-specific
 * extensions of up to 7 other values within area.
 *
 * The breakdown is purely a guide to help identify a specific area such that
 * intelligent data collection can occur during handling of a termination event.
 *---------------------------------------------------------------------------*/
#define AXA_AREA_CPU     (1ull << 56) /* CPU control / handling */
#define AXA_AREA_SOC     (1ull << 48) /* SoC level handling */
#define AXA_AREA_DAP     (1ull << 40) /* DAP/TAP SoC Access Point handling */
#define AXA_AREA_CONNECT (1ull << 32) /* connection (client-server;app-probe) */
#define AXA_AREA_DB      (1ull << 24) /* database related */
#define AXA_AREA_GDB     (1ull << 16) /* GDB server / protocol related */
#define AXA_AREA_APP     (1ull << 8)  /* overall application level */
#define AXA_AREA_GENERAL (1ull << 0)  /* general area for any other usage */
#define AXA_AREA_ALL     0xFFFFFFFFFFFFFFFF

/*---------------------------------------------------------------------------*
 * Assertion Termination Upcall
 *
 * These routines are registered when passed to AXassert_register.
 * Whenever any AXassert function determines that the application will terminate
 * every registered assertion termination handler will be called as a trigger
 * to dump out any potentially helpful diagnostic information.
 *
 * Inputs provided to the assert termination handler:
 *   owner_key - key provided at registration time under caller's control
 *   term_cause - overall cause of the abnormal termination
 *   exit_value - when termination cause is exit this is the exit value
 *   area - set of AXA_AREA_xxx areas that apply to assertion
 *---------------------------------------------------------------------------*/
typedef void (*AXassertCallback)(void *owner_key, axa_term_t term_cause, int exit_value, uint64_t area);

/*****************************************************************************
 * AXassert_register - Register an upcall routine called when any assert
 * check has determined that calling application should terminate unexpectedly.
 *
 * inputs:
 *   func - name of the function that triggered the termination
 *   owner_key - key (under caller's control) that will be provided to upcall
 *   area - set of AXA_AREA_xxx areas that directly apply to assertion
 *   assert_upcall - upcall function to be called on any abmormal termination
 *****************************************************************************/
void AXassert_register(const char *func, void *owner_key, uint64_t area, AXassertCallback assert_upcall);

/*****************************************************************************
 * AXassert_bool - Check assertion that a boolean is true
 *
 * inputs:
 *   domain - logging domain of code making the assertion
 *   area - set of AXA_AREA_xxx areas that directly apply to assertion
 *   assertion - boolean to be checked: true = NO OP; false triggers termination
 *   fmt ... - detailed description of the assertion that is being verified
 *****************************************************************************/
void AXassert_bool(const char *domain, uint64_t area, bool assertion, const char *fmt, ...) __printflike(4, 5);

/*****************************************************************************
 * AXassert_code - Check assertion that an Astris error code is OK
 *
 * inputs:
 *   domain - logging domain of code making the assertion
 *   area - set of AXA_AREA_xxx areas that directly apply to assertion
 *   result - Astris error code result to be compared to ASTRIS_ERR_OK
 *   fmt ... - detailed description of the assertion that is being verified
 *****************************************************************************/
void AXassert_code(const char *domain, uint64_t area, int result, const char *fmt, ...) __printflike(4, 5);

/*****************************************************************************
 * AXassert_abort - Terminate execution by calling abort
 *
 * inputs:
 *   domain - logging domain of code issuing the abort
 *   area - set of AXA_AREA_xxx areas that directly apply to abort
 *   fmt ... - detailed description of the reason for the abort
 *****************************************************************************/
void AXassert_abort(const char *domain, uint64_t area, const char *fmt, ...) __printflike(3, 4);

/*****************************************************************************
 * AXassert_exit - Terminate execution by calling exit
 *
 * inputs:
 *   domain - logging domain of code issuing the exit
 *   area - set of AXA_AREA_xxx areas that directly apply to exit
 *   exit_value - exit value that is used on the eventual call to exit
 *   file_radar - whether operator should be asked to file a radar
 *   fmt ... - detailed description of the reason for the abort
 *****************************************************************************/
void AXassert_exit(const char *domain, uint64_t area, int exit_value, bool file_radar, const char *fmt, ...) __printflike(5, 6);

/*****************************************************************************
 * AXassert_cause_name - provide ASCII name of abnormal termination cause
 *
 * inputs:
 *   term_cause - abnormal termination cause value to get name for
 *****************************************************************************/
const char *AXassert_cause_name(axa_term_t term_cause);

/*---------------------------------------------------------------------------*
 * Assertion Macros
 *
 * Usage of these macros requires the definition of __CLASS__ as an identifier
 * of the module or C++ class that the given function belongs to.
 *---------------------------------------------------------------------------*/
#define AXASSERT_BOOL(domain, area, assertion, fmt, ...)                  \
    do {AXassert_bool(domain, area, assertion,                            \
                      "{%s::%s@%d} [FALSE] " fmt "\n",                    \
                      __CLASS__, __FUNCTION__, __LINE__, ## __VA_ARGS__); \
        assert(assertion);                                                \
    } while (0)

#define AXASSERT_CODE(domain, area, result, fmt, ...)      \
    do {AXassert_code(domain, area, result,                \
                      "{%s::%s@%d} [%s] " fmt "\n",        \
                      __CLASS__, __FUNCTION__, __LINE__,   \
                      AXstrerror(result), ## __VA_ARGS__); \
        assert(result == ASTRIS_ERR_OK);                   \
    } while (0)

#define AXASSERT_ABORT(domain, area, fmt, ...)                             \
    do {AXassert_abort(domain, area,                                       \
                       "{%s::%s@%d} [ABORT] " fmt "\n",                    \
                       __CLASS__, __FUNCTION__, __LINE__, ## __VA_ARGS__); \
        abort();                                                           \
    } while (0)

#define AXASSERT_EXIT(domain, area, exitval, fmt, ...)    \
    do {AXassert_exit(domain, area, exitval, exitval,     \
                      "{%s::%s@%d} [EXIT(%d)] " fmt "\n", \
                      __CLASS__, __FUNCTION__, __LINE__,  \
                      exitval, ## __VA_ARGS__);           \
        exit(exitval);                                    \
    } while (0)

/*---------------------------------------------------------------------------*
 * Assertion with Action Macros
 *
 * These variants of the above assertion macros also take an action, in the
 * form of a statement, that will be executed in context before the specific
 * form of the assertion is performed.
 *
 * For the variants of assertion forms which are conditional, the action
 * will only be executed if the assertion itself would be triggered.
 *---------------------------------------------------------------------------*/
#define AXASSERT_BOOL_ACTION(domain, area, assertion, action, fmt, ...) \
    do {                                                                \
        if (!assertion) {action;}                                       \
        AXASSERT_BOOL(domain, area, assertion, fmt, ## __VA_ARGS__);    \
    } while (0)

#define AXASSERT_CODE_ACTION(domain, area, result, action, fmt, ...) \
    do {                                                             \
        if (result != ASTRIS_ERR_OK) {action;}                       \
        AXASSERT_CODE(domain, area, result, fmt, ## __VA_ARGS__);    \
    } while (0)

#define AXASSERT_ABORT_ACTION(domain, area, action, fmt, ...) \
    do {                                                      \
        action;                                               \
        AXASSERT_ABORT(domain, area, fmt, ## __VA_ARGS__);    \
    } while (0)

#define AXASSERT_EXIT_ACTION(domain, area, exitval, action, fmt, ...) \
    do {                                                              \
        action;                                                       \
        AXASSERT_EXIT(domain, area, exitval, fmt, ## __VA_ARGS__);    \
    } while (0)

/*
 * Check, Verify and Require handling
 *
 * All AXCHECK macros behave based on whether built for debug.
 * If built for release then the checks do nothing and produce no code.
 * if built for debug then the checks perform a test and log if the test fails.
 *
 * All AXVERIFY macros and functions perform a test and log if the test fails.
 *
 * All AXREQUIRE macros perform a test. If the test fails then
 * a log is generated and a goto is performed (to the exception label provided).
 *
 * The category used for any issued log is controlled by the caller.
 */

/*****************************************************************************
 * AXverify_bool - Verify that boolean is true else issue log
 *
 * inputs:
 *   domain - logging domain of function checking the boolean
 *   check - boolean to be checked - if false then log issued
 *   fmt ... - description of the location where the verification is being made
 *****************************************************************************/
void AXverify_bool(const char *domain, uint64_t category, bool check, const char *fmt, ...) __printflike(4, 5);

/*****************************************************************************
 * AXverify_bool_err - Verify boolean is true else issue log and set error code
 *
 * inputs:
 *   domain - logging domain of function checking the boolean
 *   check - boolean to be checked - if false then log issued and result set
 *   err - location to hold error code [if check false]
 *   code - code to set err to [if check false]
 *   fmt ... - description of the location where the verification is being made
 *****************************************************************************/
void AXverify_bool_err(const char *domain, uint64_t category, bool check, int *err, int code, const char *fmt, ...) __printflike(6, 7);

/*****************************************************************************
 * AXverify_code - Verify that code equals ASTRIS_ERR_OK else issue log
 *
 * inputs:
 *   domain - logging domain of function checking the result code
 *   result - Astris error code result to be compared to ASTRIS_ERR_OK
 *   fmt ... - description of the location where the result code was encountered
 *****************************************************************************/
void AXverify_code(const char *domain, uint64_t category, int code, const char *fmt, ...) __printflike(4, 5);

/*****************************************************************************
 * AXverify_radar_request - Make a one-shot request that user file a radar
 *
 * inputs:
 *   domain - logging domain of function that encountered the problem
 *   filename = name of the file holding the code that detected the problem
 *   function - name of the function that detected the problem
 *   line - line number where the problem was detected
 *****************************************************************************/
void AXverify_radar_request(const char *domain, const char *filename, const char *function, int line, const char *fmt, ...) __printflike(5, 6);

/*---------------------------------------------------------------------------*
 * Check, Verify and Require Macros
 *---------------------------------------------------------------------------*/

#if DEBUG
#define AXCHECK_CODE(domain, category, code, fmt, ...) \
    AXverify_code(domain, category, code,              \
                  "{%s:%s@%d} [%s] " fmt "\n",         \
                  __FILE__, __FUNCTION__, __LINE__,    \
                  AXstrerror(code), ## __VA_ARGS__)
#else /* DEBUG */
#define AXCHECK_CODE(domain, category, code, fmt, ...)
#endif /* DEBUG */

#define AXVERIFY_BOOL(domain, category, check, fmt, ...) \
    AXverify_bool(domain, category, check,               \
                  "{%s:%s@%d} " fmt "\n",                \
                  __FILE__, __FUNCTION__, __LINE__,      \
                  ## __VA_ARGS__)

#define AXVERIFY_BOOL_ERR(domain, category, check, err, code, fmt, ...) \
    AXverify_bool_err(domain, category, check, err, code,               \
                      "{%s:%s@%d} [%s] " fmt "\n",                      \
                      __FILE__, __FUNCTION__, __LINE__,                 \
                      AXstrerror(code), ## __VA_ARGS__)

#define AXVERIFY_CODE(domain, category, code, fmt, ...) \
    AXverify_code(domain, category, code,               \
                  "{%s:%s@%d} [%s] " fmt "\n",          \
                  __FILE__, __FUNCTION__, __LINE__,     \
                  AXstrerror(code), ## __VA_ARGS__)

#define AXREQUIRE_BOOL(domain, category, check, label, fmt, ...) \
    do {                                                         \
        AXverify_bool(domain, category, check,                   \
                      "{%s:%s@%d} " fmt "\n",                    \
                      __FILE__, __FUNCTION__, __LINE__,          \
                      ## __VA_ARGS__);                           \
        if (!(check)) {                                          \
            goto label;                                          \
        }                                                        \
    } while (0)

#define AXREQUIRE_BOOL_ERR(domain, category, check, err, code, label, fmt, ...) \
    do {                                                                        \
        AXverify_bool_err(domain, category, check, err, code,                   \
                          "{%s:%s@%d} " fmt "\n",                               \
                          __FILE__, __FUNCTION__, __LINE__,                     \
                          ## __VA_ARGS__);                                      \
        if (!(check)) {                                                         \
            goto label;                                                         \
        }                                                                       \
    } while (0)

#define AXREQUIRE_CODE(domain, category, code, label, fmt, ...) \
    do {                                                        \
        AXverify_code(domain, category, code,                   \
                      "{%s:%s@%d} [%s] " fmt "\n",              \
                      __FILE__, __FUNCTION__, __LINE__,         \
                      AXstrerror(code), ## __VA_ARGS__);        \
        if (code != ASTRIS_ERR_OK) {                            \
            goto label;                                         \
        }                                                       \
    } while (0)

/*---------------------------------------------------------------------------*
 * Require (with one-shot request to file radar) Macros
 *---------------------------------------------------------------------------*/

#define AXREQUEST_RADAR(domain, fmt, ...)                            \
    AXverify_radar_request(domain, __FILE__, __FUNCTION__, __LINE__, \
                           "!!!! Critical Error: " fmt " !!!!\n", ## __VA_ARGS__)

#define AXREQUIRE_BOOL_RADAR(domain, category, check, label, fmt, ...)    \
    do {                                                                  \
        AXverify_bool(domain, category, check,                            \
                      "{%s:%s@%d} " fmt "\n",                             \
                      __FILE__, __FUNCTION__, __LINE__,                   \
                      ## __VA_ARGS__);                                    \
        if (!(check)) {                                                   \
            AXverify_radar_request(domain, __FILE__,                      \
                                   __FUNCTION__, __LINE__,                \
                                   "!!!! Critical Error: " fmt " !!!!\n", \
                                   ## __VA_ARGS__);                       \
            goto label;                                                   \
        }                                                                 \
    } while (0)

#define AXREQUIRE_BOOL_ERR_RADAR(domain, category, check, err, code, label, fmt, ...) \
    do {                                                                              \
        AXverify_bool_err(domain, category, check, err, code,                         \
                          "{%s:%s@%d} " fmt "\n",                                     \
                          __FILE__, __FUNCTION__, __LINE__,                           \
                          ## __VA_ARGS__);                                            \
        if (!(check)) {                                                               \
            AXverify_radar_request(domain, __FILE__,                                  \
                                   __FUNCTION__, __LINE__,                            \
                                   "!!!! Critical Error: " fmt " !!!!\n",             \
                                   ## __VA_ARGS__);                                   \
            goto label;                                                               \
        }                                                                             \
    } while (0)

#define AXREQUIRE_CODE_RADAR(domain, category, code, label, fmt, ...)     \
    do {                                                                  \
        AXverify_code(domain, category, code,                             \
                      "{%s:%s@%d} [%s] " fmt "\n",                        \
                      __FILE__, __FUNCTION__, __LINE__,                   \
                      AXstrerror(code), ## __VA_ARGS__);                  \
        if (code != ASTRIS_ERR_OK) {                                      \
            AXverify_radar_request(domain, __FILE__,                      \
                                   __FUNCTION__, __LINE__,                \
                                   "!!!! Critical Error: " fmt " !!!!\n", \
                                   ## __VA_ARGS__);                       \
            goto label;                                                   \
        }                                                                 \
    } while (0)

/*****************************************************************************
 * AXLOG: Astris Logging Interface
 *
 * All logging messages issued within Astris itself or by Astris utilities
 * should use the AXLOG API which acts as a front end to the asl (Apple syslog)
 * API. The AXLOG API should also be used for all other text-based output
 * generated from within Astris so that output can be better collected/managed.
 *
 * Details related to AXLOG entries passed to asl:
 *   Usage of each pre-defined key [as-is = using default asl functionality]:
 *     ASL_KEY_TIME      "Time"       as-is: time the message send routine was called
 *     ASL_KEY_HOST      "Host"       as-is: name of the host that message was sent from
 *     ASL_KEY_SENDER    "Sender"     as-is: process name
 *     ASL_KEY_FACILITY  "Facility"   Astris domain (identifies specific Astris module)
 *     ASL_KEY_PID       "PID"        as-is: process ID of thread issuing log
 *     ASL_KEY_UID       "UID"        as-is:
 *     ASL_KEY_GID       "GID"        as-is:
 *     ASL_KEY_LEVEL     "Level"      Logging level as determined by category
 *
 *   Tags: Category bit values are converted to a set of tags ("#Tag")
 *****************************************************************************/

/*****************************************************************************
 * Logging Facility (type of module that is logging)
 *
 * The module name provided whenever a new logging context is created
 * is prepended with "Astris." and the resulting name is used as the
 * ASL_KEY_FACILITY ("Facility") in messages logged using that context.
 *
 * Suggested module names for Astris components are defined below.
 *****************************************************************************/

/*---------------------------------------------------------------------------*
 * Host-Based Modules
 *
 * Modules are defined with a name and a description.
 * The following modules perform logging from host-side code
 * (via API / Console / Utilities):
 *---------------------------------------------------------------------------*/
#define AXLOG_MD_DEFAULT "Astris default logging context"

#define AXLOG_M_MAIN  "Main"
#define AXLOG_MD_MAIN "main Astris console execution"

#define AXLOG_M_GDB  "GDB"
#define AXLOG_MD_GDB "GDB Server Threads"

#define AXLOG_M_CONNECT  "Connect"
#define AXLOG_MD_CONNECT "high level connection to probe [connect state/status]"

#define AXLOG_M_LOCK  "LOCK"
#define AXLOG_MD_LOCK "Lock protection"

#define AXLOG_M_PCOMM  "P-Comm"
#define AXLOG_MD_PCOMM "raw USB|socket communication with the probe"

#define AXLOG_M_DAP  "DAP"
#define AXLOG_MD_DAP "control flow at the Debug Access Port level"

#define AXLOG_M_SCAN  "Scan"
#define AXLOG_MD_SCAN "JTAG scan chain traversal"

#define AXLOG_M_SWD  "SWD"
#define AXLOG_MD_SWD "raw SWD(or JTAG) level communication"

#define AXLOG_M_DB  "DB"
#define AXLOG_MD_DB "Astris DB accesses"

#define AXLOG_M_CMD  "Cmd"
#define AXLOG_MD_CMD "Astris console commands"

#define AXLOG_M_SHELLCMD  "ShellCmd"
#define AXLOG_MD_SHELLCMD "Astris console shell command"

#define AXLOG_M_SHELLPRIM  "ShellPrim"
#define AXLOG_MD_SHELLPRIM "Astris console shell primitive"

#define AXLOG_M_PRIMLOG  "PrimLog"
#define AXLOG_MD_PRIMLOG "Astris primitives supporting log control"

#define AXLOG_M_API  "API."  /* should always be followed by usage */
#define AXLOG_MD_API "Astris API usage [sub-divided by controlling utility]"

#define AXLOG_M_ATTITUDE  "Attitude"
#define AXLOG_MD_ATTITUDE "Batch Attitude"

#define AXLOG_M_EXPLORE  "Explore"
#define AXLOG_MD_EXPLORE "device exploration"

#define AXLOG_M_JTAG  "JTAG"
#define AXLOG_MD_JTAG "JTAG level control"

#define AXLOG_M_AP  "AP"
#define AXLOG_MD_AP "Access Port"

#define AXLOG_M_DP  "DP"
#define AXLOG_MD_DP "Debug Port"

#define AXLOG_M_MEMAP  "MEMAP"
#define AXLOG_MD_MEMAP "Memory Access Port"

#define AXLOG_M_MEM1500    "MEM1500"
#define AXLOG_MD_MEMAP1500 "1500APB Bridge memory transaction"

#define AXLOG_M_XACT  "XACT"
#define AXLOG_MD_XACT "Transaction"

#define AXLOG_M_CSPDATA  "CSPDATA"
#define AXLOG_MD_CSPDATA "CS Protocol Data"

#define AXLOG_M_EICE  "EICE"
#define AXLOG_MD_EICE "EICE"

#define AXLOG_M_MINISWD  "MINISWD"
#define AXLOG_MD_MINISWD "MiniSWD (USB Comm)"

#define AXLOG_M_DG  "DG"
#define AXLOG_MD_DG "data gatherer"

#define AXLOG_M_CPU  "CPU"
#define AXLOG_MD_CPU "CPU-level (general and architecture-specific)"

#define AXLOG_M_CPUSTATE  "CPUstate"
#define AXLOG_MD_CPUSTATE "CPU state"

#define AXLOG_M_CPUSTATUS  "CPUstatus"
#define AXLOG_MD_CPUSTATUS "CPU status"

#define AXLOG_M_CACHE  "CACHE"
#define AXLOG_MD_CACHE "Cache Control"

#define AXLOG_M_BP  "BP"
#define AXLOG_MD_BP "Breakpoint Management"

#define AXLOG_M_SOC  "SoC"
#define AXLOG_MD_SOC "SoC-specific information"

#define AXLOG_M_INDICATION  "Indication"
#define AXLOG_MD_INDICATION "Indication handling"

#define AXLOG_M_CONSISTDBG  "ConsistDbg"
#define AXLOG_MD_CONSISTDBG "consistent debug"

#define AXLOG_M_PERSIUS  "Persius"
#define AXLOG_MD_PERSIUS "Persius extension capbilities [Acquisition, v5 FPGA, etc.]"

#define AXLOG_M_CORE  "Core"
#define AXLOG_MD_CORE "core dump progress"

#define AXLOG_M_COREFILE  "CoreFile"
#define AXLOG_MD_COREFILE "core dump file reader"

#define AXLOG_M_GPUDUMP  "GPUDump"
#define AXLOG_MD_GPUDUMP "GPU dump progress"

#define AXLOG_M_LOGFILE  "LogFile"
#define AXLOG_MD_LOGFILE "log file reader"

#define AXLOG_M_XFER  "Xfer"
#define AXLOG_MD_XFER "transferring of image file"

#define AXLOG_M_KICK  "Kick"
#define AXLOG_MD_KICK "Kick handling"

#define AXLOG_M_POWER  "Power"
#define AXLOG_MD_POWER "Power management"

#define AXLOG_M_PROBESRV  "ProbeSrv"
#define AXLOG_MD_PROBESRV "probe server"

#define AXLOG_M_PROBEMAP  "ProbeMap"
#define AXLOG_MD_PROBEMAP "probe map"

#define AXLOG_M_PROBEDEV  "ProbeDev"
#define AXLOG_MD_PROBEDEV "abstract probe device"

#define AXLOG_M_PROBEDEVUSB  "ProbeDevUsb"
#define AXLOG_MD_PROBEDEVUSB "usb-based probe device"

#define AXLOG_M_PROBEDEVUSBKIS  "ProbeDevUsbKis"
#define AXLOG_MD_PROBEDEVUSBKIS "usb-based KIS probe device"

#define AXLOG_M_PROBEDEVGPIO  "ProbeDevGpio"
#define AXLOG_MD_PROBEDEVGPIO "gpio-based probe device"

#define AXLOG_M_PROBEDEVTCP  "ProbeDevTcp"
#define AXLOG_MD_PROBEDEVTCP "tcp-based probe device"

#define AXLOG_M_PROBEDEVHPM  "ProbeDevHpm"
#define AXLOG_MD_PROBEDEVHPM "hpm-based probe device"

#define AXLOG_M_PROBENAV  "ProbeNav"
#define AXLOG_MD_PROBENAV "probe navigator"

#define AXLOG_M_PROBERELAY  "ProbeRelay"
#define AXLOG_MD_PROBERELAY "probe message relay"

#define AXLOG_M_GDB_PCAP  "Pcap"
#define AXLOG_MD_GDB_PCAP "Capture and record gdbserver remote protocol commands"

#define AXLOG_M_GDB_RENDER  "Render"
#define AXLOG_MD_GDB_RENDER "Rendering of response to GDB client"

#define AXLOG_M_UPDATEAGENT  "UpdateAgent"
#define AXLOG_MD_UPDATEAGENT "Astris update agent"

#define AXLOG_M_HOSTINFO  "HostInfo"
#define AXLOG_MD_HOSTINFO "Information about the host"

#define AXLOG_M_HTTP  "HTTP"
#define AXLOG_MD_HTTP "Information about the HTTP transactions"

#define AXLOG_M_BM  "BoosterManager"
#define AXLOG_MD_PM "BoosterManager Info"

#define AXLOG_M_SWDFLASH  "SWDFlasher"
#define AXLOG_MD_SWDFLASH "SWDFlasher Information"

#define AXLOG_M_KIS  "KIS"
#define AXLOG_MD_KIS "KIS Specific API Information"

#define AXLOG_M_KIS_XLATOR  "KIS-XLATOR"
#define AXLOG_MD_KIS_XLATOR "KIS Translator Information"

#define AXLOG_M_TOPOLOGY  "Topology"
#define AXLOG_MD_TOPOLOGY "Topology descriptor"

#define AXLOG_M_DEBUGCOMPONENT  "DebugComponent"
#define AXLOG_MD_DEBUGCOMPONENT "Debug component descriptor"

#define AXLOG_M_OSLOG  "OSLOG"
#define AXLOG_MD_OSLOG "Info related to the interface to the unified logging subsystem"

#define AXLOG_M_DISASM  "DISASM"
#define AXLOG_MD_DISASM "Information related to instruction disassembly"

#define AXLOG_M_DART  "DART"
#define AXLOG_MD_DART "DART Info"

#define AXLOG_M_AWL  "AWL"
#define AXLOG_MD_AWL "AWL Info"

#define AXLOG_M_SPMI  "SPMI"
#define AXLOG_MD_SPMI "SPMI driver logs"

#define AXLOG_M_APF  "APF"
#define AXLOG_MD_APF "APF Info"

/*****************************************************************************
 * Type of Logging (Log Level)
 *****************************************************************************/

/*---------------------------------------------------------------------------*
 * Types of logging performed throughout Astris modules
 *
 * Astris issues AXLOG messages as one of the following basic types.
 * This type is represented to asl as a single bit that is set in the
 * asl filter mask [which is converted into an ASL_KEY_LEVEL ("Level") value].
 *
 * By default, all log messages other than LOW and RAW are passed to
 * asl. LOW / RAW message passing would require additional control via the
 * AXLOG API to activate so these should be considered reserved for future use.
 *
 * The value in square backets shows the bit set as ASL_FILTER_MASK_xxx
 * that asl maps to the "Level" key value.
 * Whenever multiple types apply, the AXLOG API selects the level associated
 * with the enumerated type having the highest value.
 *---------------------------------------------------------------------------*/
typedef enum {
    AXLOG_NONE  = 0, /* type has no associated level */
    AXLOG_RAW   = 1, /* [DEBUG]   potentially verbose raw-level debug info */
    AXLOG_LOW   = 2, /* [INFO]    low-level info normally not desired */
    AXLOG_STD   = 3, /* [NOTICE]  default type - standard logging */
    AXLOG_WARN  = 4, /* [WARNING] detection of a recoverable problem */
    AXLOG_ERR   = 5, /* [ERR]     error reporting */
    AXLOG_CRASH = 6, /* [CRIT]    false assert | detection of crashed device */
    AXLOG_TEMP  = 7, /* [ALERT]   temporary log [never in submitted code] */
    AXLOG_RSRVD = 8, /* [EMERG]   reserved for future use */
    AXLOG_INVAL = 9  /* used as indication of invalid log level */
} axl_type_t;
#define AXLOG_COUNT AXLOG_INVAL

/*****************************************************************************
 * Astris Log Category
 *
 * Each usage of the Astris log can specify a set of category definitions.
 * The set of categories that are indicated in a log request are converted
 * into asl Tags of the form " #Category".
 * Tags can be used in the asl Console to filter which messages are shown.
 * Multiple categories can be used for a single log entry.
 * The set of tags defined below is always available as category choices.
 * When a new logging context is opened, additional categories can be defined
 * that are specific to the calling module.
 *
 * A category has an associated log type.
 * Whenever a log is issued, the categories are used to determine the reported
 * level - the highest type indicated by category is reported as Level.
 *
 * Common category bit values are defined from the high order bit position
 * so that module-specific definitions can begin at 0.
 *****************************************************************************/

/*---------------------------------------------------------------------------*
 * Categories involving additional processing within the AXLOG implementation
 *
 * AXL_USER Indicates when a message represents something normally intended for
 *          visibility to the user (operator). AXLOG performs additional
 *          processing on messages that include the AXL_USER category based
 *          on the other special handling categories described below.
 *          If AXL_USER isn't set then no additional processing occurs.
 *
 * AXL_IN   User input is any command entered at a prompt or as command line arg
 *          (to either the Astris console or an Astris utility).
 *          AXLOG currently performs no additional processing based on the
 *          AXL_IN category. Future extensions (script creation, etc.) possible.
 *
 * AXL_OUT  User output is any text normally destined for the user (stdout)
 *          [other than for status/state information or prompt generation].
 *          AXLOG forks AXL_OUT messages to stdout by default.
 *
 * AXL_STA  Logs providing status/state updates should include AXL_OUT|AXL_STA.
 *          AXLOG will accumulate status/state text until an entry ending with
 *          \n (or AXL_END set) is encountered before considering whether to
 *          forward to asl. AXLOG only passes a complete status/state message
 *          to asl when the text has changed from the last message sent to asl.
 *
 * AXL_PROMPT   Logs representing a prompt should include AXL_OUT|AXL_PRMPT.
 *              AXLOG handles prompt text as described for AXL_STA.
 *
 * AXL_STD  Logs paralleling output to stdout (printf, puts, etc.)
 *          should include AXL_OUT|AXL_STD.
 *          AXLOG will fork these messages to stdout by default.
 *
 * AXL_ERR  Logs describing an error condition (paralleling an application
 *          writing to stderr) should include AXL_OUT|AXL_ERR.
 *          AXLOG will fork these messages to stderr by default.
 *---------------------------------------------------------------------------*/
#define AXL_USER  (1ull << 63) /* #User    [STD]   User interaction */
#define AXL_IN    (1ull << 62) /* #Input   [STD]   Input */
#define AXL_OUT   (1ull << 61) /* #Output  [STD]   Output */
#define AXL_STA   (1ull << 60) /* #Status  [LOW]   Status/State */
#define AXL_PRMPT (1ull << 59) /* #Prompt  [LOW]   Prompt */
#define AXL_STD   (1ull << 58) /* #Std     [STD]   Standard */
#define AXL_ERR   (1ull << 57) /* #Error   [ERR]   Error detected */
#define AXL_BEGIN (1ull << 56) /* #Begin   [STD]   Beginning of set */
#define AXL_END   (1ull << 55) /* #End     [STD]   End of set */
#define AXL_WARN  (1ull << 54) /* #Warn    [WARN]  Warning */
#define AXL_BUG   (1ull << 53) /* #Bug     [CRASH] Bug detected */
#define AXL_DEBUG (1ull << 52) /* #Debug   [LOW]   Debug assistance */

/*---------------------------------------------------------------------------*
 * Categories mapping to each possible log Level (no associated Tag)
 *---------------------------------------------------------------------------*/
#define AXL_LVL_TEMP  (1ull << 51) /*          [TEMP]  Temporary level */
#define AXL_LVL_CRASH (1ull << 50) /*          [CRASH] Crash level */
#define AXL_LVL_ERR   (1ull << 49) /*          [ERR]   Error level */
#define AXL_LVL_WARN  (1ull << 48) /*          [WARN]  Warning level */
#define AXL_LVL_STD   (1ull << 47) /*          [STD]   Standard level */
#define AXL_LVL_LOW   (1ull << 46) /*          [LOW]   Low level */
#define AXL_LVL_RAW   (1ull << 45) /*          [RAW]   Raw level */

/*---------------------------------------------------------------------------*
 * Category sets describing log conditions involving user interaction
 *---------------------------------------------------------------------------*/
#define AXL_U_OUT   (AXL_USER | AXL_OUT)             /* User Output */
#define AXL_U_STA   (AXL_USER | AXL_OUT | AXL_STA)   /* User State/Status Info */
#define AXL_U_PRMPT (AXL_USER | AXL_OUT | AXL_PRMPT) /* User Prompt */
#define AXL_U_STD   (AXL_USER | AXL_OUT | AXL_STD)   /* User Standard Out Msg */
#define AXL_U_ERR   (AXL_USER | AXL_OUT | AXL_ERR)   /* User Error Message */
#define AXL_U_WARN  (AXL_USER | AXL_OUT | AXL_WARN)  /* User Warning Message */

/*---------------------------------------------------------------------------*
 * Base values suggested for category sets beyond AXLOG-specific processing
 *
 * Additional categories can be defined via AXlog_categories.
 *---------------------------------------------------------------------------*/
#define AXL_SH_CONNECT 0  /* base suggested for Connection categories */
#define AXL_SH_GDB     12 /* base suggested for GDB server categories */
#define AXL_SH_OTHER   32 /* base suggested for all other categories */

#define AXL_CHECK_HISTORY_FREE   (1 << 0) /* check for walk on freed history entry */
#define AXL_CHECK_HISTORY_LOCK   (1 << 1) /* scan history for walk on mutex lock */
#define AXL_CHECK_HISTORY_UNLOCK (1 << 2) /* scan history for walk on mutex unlock */
#define AXL_CHECK_DEFAULT        (AXL_CHECK_HISTORY_LOCK)

#define AXL_HISTORY_MAX       1024 /* default max depth of log history queue */
#define AXLOG_HISTORY_NOLIMIT -1   /* no limit to history queue depth */

/*---------------------------------------------------------------------------*
 * Module-Specific Category Definition
 * (use bitValue of 0 to indicate end of list)
 *
 * If a bitValue matches one of the asl-suggested categories
 * then the asl-suggested Tag will be replaced for the given log context.
 * Bit values with special handling cannot be replaced.
 *---------------------------------------------------------------------------*/
typedef struct {
    uint64_t   bitValue; /* bit that is used to indicate the category */
    axl_type_t logType;  /* log type (log level) associated with category */
    char      *tagName;  /* OPTIONAL name used as the Tag for the category */
    char      *tagDesc;  /* OPTIONAL description of Tag */
} axl_category_t;

// New logging API (oslog incorporation)

/*!
 @enum astris_os_log_src_t
 Supported log source types

 @const ASTRIS_OS_LOG_SRC_DEFAULT
 Default log source type (maps to OS_LOG_DEFAULT)

 @const ASTRIS_OS_LOG_SRC_USER
 Source for logging related to user-initiated activities

 @const ASTRIS_OS_LOG_SRC_GDB
 Source for LLDB-related logging

 @const ASTRIS_OS_LOG_SRC_EXPLORE
 Source for explore-related logging

 @const ASTRIS_OS_LOG_SRC_STATUS
 Source for logging on the status polling path

 @const ASTRIS_OS_LOG_SRC_CONNECT
 Source for connection-related logging

 @const ASTRIS_OS_LOG_SRC_BOOSTER
 Source for booster-related logging

 @const ASTRIS_OS_LOG_SRC_RPC
 Source for RPC-related logging

 @const ASTRIS_OS_LOG_SRC_PROBED
 Source for probed-related logging

 @const ASTRIS_OS_LOG_SRC_LAST
 Denotes the number of source types
 */
typedef enum {
    ASTRIS_OS_LOG_SRC_DEFAULT,
    ASTRIS_OS_LOG_SRC_USER,
    ASTRIS_OS_LOG_SRC_GDB,
    ASTRIS_OS_LOG_SRC_EXPLORE,
    ASTRIS_OS_LOG_SRC_STATUS,
    ASTRIS_OS_LOG_SRC_CONNECT,
    ASTRIS_OS_LOG_SRC_BOOSTER,
    ASTRIS_OS_LOG_SRC_RPC,
    ASTRIS_OS_LOG_SRC_PROBED,

    ASTRIS_OS_LOG_SRC_LAST // leave last val as a count
} astris_os_log_src_t;

/*!
 @defined ASTRIS_OS_LOG_SRC_COUNT  Number of defined log sources
 */
#define ASTRIS_OS_LOG_SRC_COUNT (int)ASTRIS_OS_LOG_SRC_LAST

/*!
 @typedef astris_os_log_src_token_t
 @discussion Token to use for source manipulation of the current activity
 @field is_focus Whether the current source (activity) has focus
 */
typedef struct {
    bool is_focus;
} astris_os_log_src_token_t;

/*!
 @defined ASTRIS_OS_LOG_SRC_TOKEN_INITIALIZER Initializer for an astris_os_log_src_token_t
 */
#define ASTRIS_OS_LOG_SRC_TOKEN_INITIALIZER {false, }

/*!
 @function AXoslog_is_enabled
 @discussion Determine whether oslog is the active logging subsystem (as
 opposed to ASL).
 @result boolean indicating enabled or disabled
 */
bool AXoslog_is_enabled(void);

/*!
 @function AXoslog_disable
 @discussion Disable oslog as the underlying interface to the system log.
 This *must* happen before AXlog has been initialized, as we don't support
 dynamic switching between logging modes. An ASTRIS_ERR_INVAL error code will
 be returned if this is attempted.
 @result astris error code
 */
int AXoslog_disable(void);

/*!
 @function _astris_os_log_is_available
 @discussion Determine if oslog is currently enabled.
 @result boolean
 */
bool _astris_os_log_is_available(void);

/*!
 @function AXlog_get_src
 @discussion Gets the log source object for the calling thread
 @result the os_log_t for the calling thread to use
 */
os_log_t AXoslog_obj_get(void);

/*!
 @function AXoslog_src_push
 @discussion Push a source onto the source stack.
 @param src Source to push
 @result Log source token
 */
astris_os_log_src_token_t AXoslog_src_push(astris_os_log_src_t src);

/*!
 @function AXoslog_src_pop
 @discussion Pop and return the current source from the source stack. This will
 return ASTRIS_OS_LOG_SRC_DEFAULT if the stack is empty.
 @param ptok Pointer to an astris_os_log_src_token_t received from a call to AXoslog_src_push
 @result the current source
 */
astris_os_log_src_t AXoslog_src_pop(astris_os_log_src_token_t *ptok);

/*!
 @function AXoslog_src_retain
 @discussion Push a source onto the source stack if and only if a source isn't
 already set.  A situation in which this might be useful would be when we want
 to use the EXPLORE soource for a status poll that's triggered during explore.
 @param src Source to push
 */
astris_os_log_src_token_t AXoslog_src_retain(astris_os_log_src_t src);

/*!
 @function AXoslog_src_release
 @discussion Pop and return the current source from the stack if and only if a
 source has been set through a call to astris_os_log_src_retain.
 @param ptok Pointer to an astris_os_log_src_token_t received from a call to AXoslog_src_retain
 @result the previous source
 */
astris_os_log_src_t AXoslog_src_release(astris_os_log_src_token_t *ptok);

/*!
 @function AXoslog_src_peek
 @discussion Get the current souce without removing it from the source stack.
 This will return ASTRIS_OS_LOG_SRC_DEFAULT if the stack is empty.
 @result the os_log_t for the calling thread to use
 */
astris_os_log_src_t AXoslog_src_peek(void);

/*!
 @function _astris_os_log_obj_get
 @discussion Gets the log source object for the calling thread
 *** Only to be used by ax_os_log macro defined below. For general use, see AXlog_*
 APIs above. ***
 @result boolean value
 */
os_log_t _astris_os_log_obj_get();

/*!
 @function _astris_os_log_level_for_category
 @discussion Get the oslog type for the axlog level. *** Only to be used
 *** Only to be used by ax_os_log macro defined below. For general use, see AXlog_*
 APIs above. ***
 @param cat axlog category
 @result oslog type
 */
os_log_type_t _astris_os_log_level_for_category(uint64_t cat);

/*!
 @defined ASTRIS_OS_LOG_AVAILABLE
 @discussion Set to 1 is oslog is available, 0 otherwise. This is a pretty
 hacky way of determining oslog availability, so we may want to explore whether
 there's a better way.
 */

#ifdef os_log_with_type
#define ASTRIS_OS_LOG_AVAILABLE 1
#else
#define ASTRIS_OS_LOG_AVAILABLE 0
#endif

/*!
 @defined ax_os_log
 @discussion Log a message to the astris log. If oslog is available then use
 that interface, otherwise fall back to old school ASL.
 @param domain Log domain for the message
 @param category Category for the message
 @param fmt Format string for the message
 */

#if  defined(ASTRIS_OS_LOG_AVAILABLE) && !defined(ASTRIS_DAEMON)
// os_log APIs are only available in 10.12 and later
#define ax_os_log(domain, category, fmt, ...)                             \
    do {                                                                  \
        if (_astris_os_log_is_available()) {                              \
            os_log_with_type(_astris_os_log_obj_get(),                    \
                             _astris_os_log_level_for_category(category), \
                             fmt, ## __VA_ARGS__);                        \
        }                                                                 \
        AXlog(domain, category, fmt, ## __VA_ARGS__);                     \
    } while (0)
#elif defined(ASTRIS_OS_LOG_AVAILABLE) // If daemon dont use the logging system
#define ax_os_log(domain, category, fmt, ...)                             \
    do {                                                                  \
        if (_astris_os_log_is_available() && domain) {                    \
            os_log_with_type(_astris_os_log_obj_get(),                    \
                             _astris_os_log_level_for_category(category), \
                             fmt, ## __VA_ARGS__);                        \
        }                                                                 \
    } while (0)
#else // Otherwise, send it to good ol' AXlog
#define ax_os_log(domain, category, fmt, ...) \
    AXlog(domain, category, fmt, ## __VA_ARGS__)
#endif // ifdef ASTRIS_OS_LOG_AVAILABLE

/*!
 @defined LOG_SRC_SET
 @discussion Set the log source for the current activity
 @param tok astris_os_log_src_token_t for the current frame
 @param src New source value
 */
#define ax_os_log_src_set(tok, src) \
    tok = AXoslog_src_push(src)

/*!
 @defined LOG_SRC_UNSET
 @discussion Unset the log source for the current activity
 @param ptok Pointer to an astris_os_log_src_token_t received from a call to LOG_SRC_SET
 */
#define ax_os_log_src_unset(ptok) \
    AXoslog_src_pop(ptok)

/*!
 @defined LOG_SRC_RETAIN
 @discussion Conditionally sets log source to 'src' if it's not already set
 @param tok astris_os_log_src_token_t for the current frame
 @param src New source value
 */
#define ax_os_log_src_retain(tok, src) \
    tok = AXoslog_src_retain(src)

/*!
 @defined LOG_SRC_RELEASE
 @discussion Conditionally unsets log source if it wasn't already set with a
 a call to LOG_SRC_RETAIN
 @param ptok Pointer to an astris_os_log_src_token_t received from a call to LOG_SRC_RETAIN
 */
#define ax_os_log_src_release(ptok) \
    AXoslog_src_release(ptok)

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*
 *
 * Astris Log Prototypes
 *
 *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

/*****************************************************************************
 * AXlog_init - initialize the Astris logging interface (default configuration)
 *
 * WARNING: As of May 2017, we require that users use the above macros
 *  (ax_os_log) for their logging - you WILL NOT be able to see your logs
 *  otherwise . The new APIs take advantage of the new logging subsystem (os_log)
 *  which has many benefits over the old subsystem (asl). To view your logs
 *  you'll need to use the Console application or the 'log' terminal command as
 *  we no longer generate dedicated astris log files.
 *
 * inputs:
 *   base_name - OPTIONAL base name for all log files; NULL = "astris"
 *   log_default - true = default (unnamed) log entries are written to log file
 *                 This option should normally be false since multiple
 *                 utilities using the AXLOG API can overlap default access.
 *****************************************************************************/
int AXlog_init(char *base_name, bool log_default);

/*****************************************************************************
 * AXlog_init_dir - initialize the Astris logging interface (specific directory)
 *
 * inputs:
 *   base_dir    - base directory path that log files are created under
 *   base_name   - OPTIONAL base name for all log files; NULL = "astris"
 *   log_default - true = default (unnamed) log entries are written to log file
 *                 This option should normally be false since multiple
 *                 utilities using the AXLOG API can overlap default access.
 *****************************************************************************/
int AXlog_init_dir(char *base_dir, char *base_name, bool log_default);

/*****************************************************************************
 * AXlog_init_with_ctx - initialize the Astris logging using a previously
 *                       initialized logging context
 *
 * inputs:
 *   ctx - The logging context you want to use, instead of a brand new one.
 *****************************************************************************/
int AXlog_init_with_ctx(void *ctx);

/*****************************************************************************
 * AXlog_get_ctx - Get the current logging context.
 *
 * inputs:
 *   ctx - The logging context you want to use, instead of a brand new one.
 *****************************************************************************/
void *AXlog_get_ctx(void);

/*****************************************************************************
 * AXlog_setup_default - make sure default logging destination is setup
 *
 * inputs: NONE
 *
 * return: setup result as standard error number [not Astris error code]
 *****************************************************************************/
int AXlog_setup_default(void);

/*****************************************************************************
 * AXlog_categories - define additional log categories
 *
 * inputs:
 *   categories - set of category descriptors
 *****************************************************************************/
int AXlog_categories(axl_category_t *categories);

/*****************************************************************************
 * AXlog_level_category - get category that maps to a log type (level)
 *
 * inputs:
 *   level - log level to get associated category for
 *
 * result: category that maps to log level
 *****************************************************************************/
uint64_t AXlog_level_category(axl_type_t level);

/*****************************************************************************
 * AXlog_name - change the name of the file that log entries are written to
 *
 * inputs:
 *   name     - name identifying the file that logs are written to
 *              [NULL = use the default log file name]
 *****************************************************************************/
int AXlog_name(const char *name);

/*****************************************************************************
 * AXlog_fname_get - get filename that log entries are currently written to
 *
 * inputs: NONE
 *
 * return: ASCII string providing fully qualified log file name
 *****************************************************************************/
char *AXlog_fname_get(void);

/*****************************************************************************
 * AXlog_thread_detail - control level of detail provided in thread names
 *
 * inputs: full_name - true = provide full name of thread in each log entry
 *                     false = use name provided to AXlog_thread_name (or use ID)
 *****************************************************************************/
void AXlog_thread_detail(bool full_name);

/*****************************************************************************
 * AXlog_thread_name - set the name to be used when this thread issues a log
 *
 * inputs: name - name to report as the thread name
 *                NULL = remove any name to be reported as thread name
 *****************************************************************************/
void AXlog_thread_name(const char *name);

/*****************************************************************************
 * AXlog_hardware_model - log the host hardware model
 *
 * inputs: None
 *
 * return: None
 *****************************************************************************/
void AXlog_hardware_model(void);

/*****************************************************************************
 * AXlog_os_build - log the host OS build version
 *
 * inputs: None
 *
 * return: None
 *****************************************************************************/
void AXlog_os_build(void);

/*****************************************************************************
 * AXlog - make a log entry to asl (when appropriate) [printf-style parameters]
 *
 * WARNING: As of May 2017, we require that users use the above macros
 *  (ax_os_log) for their logging - you WILL NOT be able to see your logs
 *  otherwise . The new APIs take advantage of the new logging subsystem (os_log)
 *  which has many benefits over the old subsystem (asl). To view your logs
 *  you'll need to use the Console application or the 'log' terminal command as
 *  we no longer generate dedicated astris log files.
 *
 * inputs:
 *   axldomain - domain name log is to come from; NULL = default domain
 *   category - set of category bits log applies to [determines Tags & Level]
 *   fmt ...  - printf style format string and associated number of arguments
 *****************************************************************************/
int AXlog(const char *axldomain, uint64_t category, const char *fmt, ...) __printflike(3, 4);

#define AXlog_trace(_axldomain, _category, _fmt, ...) \
    ax_os_log(_axldomain, _category, "{%s@%d} " _fmt, __FUNCTION__, __LINE__, ## __VA_ARGS__)

#define AXlog_trace_method(_axldomain, _category, _fmt, ...) \
    ax_os_log(_axldomain, _category, "{%s::%s@%d} " _fmt, __CLASS__, __FUNCTION__, __LINE__, ## __VA_ARGS__)

#define AXlog_err(_axldomain, _fmt, ...) \
    AXlog_trace(_axldomain, AXL_ERR, _fmt, ## __VA_ARGS__)

#define AXlog_bug(_axldomain, _fmt, ...) \
    AXlog_trace(_axldomain, AXL_BUG, _fmt, ## __VA_ARGS__)

/*****************************************************************************
 * AXlogv - make a log entry to asl (when appropriate) [variable argument list]
 *
 * WARNING: As of May 2017, we require that users use the above macros
 *  (ax_os_log) for their logging - you WILL NOT be able to see your logs
 *  otherwise . The new APIs take advantage of the new logging subsystem (os_log)
 *  which has many benefits over the old subsystem (asl). To view your logs
 *  you'll need to use the Console application or the 'log' terminal command as
 *  we no longer generate dedicated astris log files.
 *
 * inputs:
 *   axldomain - domain name log is to come from; NULL = default domain
 *   category - set of category bits log applies to [determines Tags & Level]
 *   fmt      - printf style format string
 *   arglist  - variable set of arguments to be applied to format string
 *****************************************************************************/
int AXlogv(const char *axldomain, uint64_t category, const char *fmt, va_list arglist);

/*****************************************************************************
 * AXlog_stdout_get - get current categories that fork logs to stdout
 *
 * inputs: NONE
 *
 * return: current stdout category mask
 *****************************************************************************/
uint64_t AXlog_stdout_get(void);

/*****************************************************************************
 * AXlog_stdout_set - set categories that fork logs to stdout
 *
 * inputs:
 *   new_stdout - bit mask of categories that should be forked to stdout
 *
 * return: old stdout category mask
 *****************************************************************************/
uint64_t AXlog_stdout_set(uint64_t new_stdout);

/*****************************************************************************
 * AXlog_stderr_get - get the log level that triggers fork to stderr
 *
 * inputs: NONE
 *
 * return: log level that triggers fork to stderr
 *****************************************************************************/
axl_type_t AXlog_stderr_get(void);

/*****************************************************************************
 * AXlog_stderr_set - set the log level that triggers fork to stderr
 *
 * inputs:
 *   new_stderr - log level that triggers fork to stderr
 *
 * return: old fork-to-stderr level
 *****************************************************************************/
axl_type_t AXlog_stderr_set(axl_type_t new_stderr);

/*****************************************************************************
 * AXlog_asl_get - get the log level that triggers forward to ASL
 *
 * inputs: NONE
 *
 * return: log level that triggers forward to ASL
 *****************************************************************************/
axl_type_t AXlog_asl_get(void);

/*****************************************************************************
 * AXlog_asl_set - set the log level that triggers forward to ASL
 *
 * inputs:
 *   new_asl - log level that triggers forward to ASL
 *
 * return: old forward-to-ASL level
 *****************************************************************************/
axl_type_t AXlog_asl_set(axl_type_t new_asl);

/*****************************************************************************
 * AXlog_check_get - get current mask of log sanity checks
 *
 * inputs: NONE
 *
 * return: current log sanity check mask
 *****************************************************************************/
uint32_t AXlog_check_get(void);

/*****************************************************************************
 * AXlog_check_set - set mask of log sanity checks
 *
 * inputs:
 *   new_check - bit mask of sanity checks performed during logging activities
 *
 * return: old sanity check mask
 *****************************************************************************/
uint32_t AXlog_check_set(uint32_t new_check);

/*****************************************************************************
 * AXlog_level_get - get the log type (level) that category maps to
 *
 * inputs:
 *   category   - set of category bits to determine log type (level) for
 *
 * return: current log type (level) associated with category
 *****************************************************************************/
axl_type_t AXlog_level_get(uint64_t category);

/*****************************************************************************
 * AXlog_level_set - set the log type (level) that category maps to
 *
 * inputs:
 *   category   - set of category bits to change log type (level) for
 *   new_type   - log type (level) that each category should be set to
 *
 * return: old log type (level) that category was associated with
 *****************************************************************************/
axl_type_t AXlog_level_set(uint64_t category, axl_type_t new_type);

/*****************************************************************************
 * AXlog_domain_get - get log type (level) associated with domain
 *
 * inputs:
 *   axldomain - domain name to get current log level for
 *
 * return: log type (level) associated with domain
 *****************************************************************************/
axl_type_t AXlog_domain_get(const char *axldomain);

/*****************************************************************************
 * AXlog_domain_set - define or update a logging domain (logs at given level)
 *
 * inputs:
 *   axldomain - domain name log is to come from; NULL = default domain
 *   level     - log type (level) associated with domain
 *****************************************************************************/
int AXlog_domain_set(const char *axldomain, axl_type_t level);

/*****************************************************************************
 * AXlog_domain_list - list all currently defined logging domains
 *
 * inputs: NONE
 *
 * return: ASCII string providing space-separated list of defined domains
 *         NULL = no domains currently defined (or shutdown or out of mem)
 * Returned string must be freed by caller
 *****************************************************************************/
char *AXlog_domain_list(void);

/*****************************************************************************
 * AXlog_domain_category - get the category of a defined logging domain
 *
 * The optional tag of a defined category is considered to be that category's
 * associated domain.
 *
 * inputs:
 *   domain - domain to get the category for; NULL = get category of all domains
 *
 * return: category mask associated with domain(s); 0 = domain(s) not found
 *****************************************************************************/
uint64_t AXlog_domain_category(char *domain);

/*****************************************************************************
 * AXlog_history_depth_get - get the depth (max entries) of the history queue
 *
 * inputs: NONE
 * return: maximum number of entries that will be held in the history queue
 *****************************************************************************/
int AXlog_history_depth_get(void);

/*****************************************************************************
 * AXlog_history_depth_set - set the depth (max entries) of the history queue
 *
 * inputs:
 *   depth - max number of entries that will be held in the history queue
 * return: previous history queue depth setting
 *****************************************************************************/
int AXlog_history_depth_set(int depth);

/*****************************************************************************
 * AXlog_history_active_get - get whether the history queue is currently active
 *
 * inputs: NONE
 * return: indication of whether the history is actively collecting entries
 *****************************************************************************/
bool AXlog_history_active_get(void);

/*****************************************************************************
 * AXlog_history_filter_add - add domain to set being filtered from history log
 *
 * inputs:
 *   domain - domain to be filtered (entries not added to the history log)
 *            NULL = filter all currently defined domains from the history log
 * return: result of adding the filter
 *****************************************************************************/
int AXlog_history_filter_add(char *domain);

/*****************************************************************************
 * AXlog_history_filter_remove - remove domain from set filtered from history
 *
 * inputs:
 *   domain - domain to no longer be filtered; NULL = remove all filters
 * return: result of removing the filter
 *****************************************************************************/
int AXlog_history_filter_remove(char *domain);

/*****************************************************************************
 * AXlog_history_filter_list - list domains being filtered from history log
 *
 * inputs: NONE
 *
 * return: ASCII string providing space-separated list of domains being filtered
 *         NULL = no domains currently being filtered (or shutdown or out of mem)
 * Returned string must be freed by caller
 *****************************************************************************/
char *AXlog_history_filter_list(void);

/*****************************************************************************
 * AXlog_history_active_set - set whether the history queue is currently active
 *
 * inputs:
 *   active - true = history queue will collect entries; false = no collection
 * return: previous history queue active setting
 *****************************************************************************/
bool AXlog_history_active_set(bool active);

/*****************************************************************************
 * AXlog_history_count_get - get the current count of entries in the history log
 *
 * inputs: NONE
 * return: current count of entries in the history log
 *****************************************************************************/
int AXlog_history_count(void);

/*****************************************************************************
 * AXlog_history_clear - clear out log history queue
 *
 * inputs: NONE
 *****************************************************************************/
void AXlog_history_clear(void);

/*****************************************************************************
 * AXlog_history_dump - dump out (send to ASL) all entries from history queue
 *
 * inputs:
 *   bannerType  - type to use when outputting history queue banner messages
 *   dump_stdout - whether to dump the history log to stdout
 *   dump_file   - whether to dump each history log entry to its associated file
 *****************************************************************************/
void AXlog_history_dump(axl_type_t bannerType, bool dump_stdout, bool dump_file);

/*****************************************************************************
 * AXlog_history_save - save [append] all entries from history queue to file
 *
 * inputs:
 *   filename   - name of file to dump history entries to
 * return: result of file save
 *****************************************************************************/
int AXlog_history_save(const char *filename);

/*****************************************************************************
 * AXlog_snapshot_create - create a snapshot of the current history log
 *
 * [Any currently existing snapshot is quietly freed]
 *
 * inputs:
 *   NONE
 * return: result of snapshot creation
 *****************************************************************************/
int AXlog_snapshot_create(void);

/*****************************************************************************
 * AXlog_snapshot_first - return pointer to first log entry in snapshot
 *
 * inputs:
 *   NONE
 * return: pointer to first entry in snapshot; NULL if no entries available
 *****************************************************************************/
const char *AXlog_snapshot_first(void);

/*****************************************************************************
 * AXlog_snapshot_next - return pointer to next log entry in snapshot
 *
 * [snapshot traversal is assumed to be controlled by a single master]
 *
 * inputs:
 *   NONE
 * return: pointer to next entry in snapshot; NULL if no more entries
 *****************************************************************************/
const char *AXlog_snapshot_next(void);

/*****************************************************************************
 * AXlog_snapshot_destroy - destroy any snapshot of the history log
 *
 * inputs:
 *   NONE
 * return: result of snapshot destruction
 *****************************************************************************/
int AXlog_snapshot_destroy(void);

/*****************************************************************************
 * AXlog_perror - log an error message and fork to stderr [unless capturing]
 *
 * inputs:
 *   axldomain - domain name that error should be logged from
 *   prefix    - OPTIONAL prefix string to be issued before error message string
 *****************************************************************************/
void AXlog_perror(const char *axldomain, const char *prefix);

/*****************************************************************************
 * AXlog_shutdown - shutdown the Astris logging interface
 *
 * Normally, usage of the AXLOG API ends with a call to AXlog_shutdown
 * which closes any log file and renames that file from "_current" name
 * to a name indicating the date and time of the last entry in the log.
 *****************************************************************************/
void AXlog_shutdown(void);

/*****************************************************************************
 * AXlog_terminate - terminate the Astris logging interface
 *
 * The AXLOG API is terminated to show that the owning application
 * ended abnormally. In that case AXlog_terminate is called with an indication
 * of the type of termination cause. The AXLOG API will be shut down from
 * within AXlog_terminate (after any final log handling has been performed).
 *
 * inputs:
 *   term_cause - overall cause of the termination
 *   file_radar - indication of whether operator should be asked to file a radar
 *****************************************************************************/
void AXlog_terminate(axa_term_t term_cause, bool file_radar);

/*****************************************************************************
 * AXlog_output_enable - allow AXL_OUT log to fork into stdout/stderr
 *
 * inputs: None
 *****************************************************************************/
void AXlog_output_enable();

/*****************************************************************************
 * AXlog_output_disable - prevent AXL_OUT log to fork into stdout/stderr
 *
 * inputs: None
 *****************************************************************************/
void AXlog_output_disable();

////////////////////////////////////////////////////////////////////////////////
#pragma mark Disassembly

/*!
 @typedef instr_t
 @discussion 8, 16, 32 bit versions of an instruction
 @field v32 32-bit version
 @field v16 16-bit version
 @field v8 8-bit version
 */
typedef union instr_u {
    uint32_t v32;
    uint16_t v16[2];
    uint8_t  v8[4];
} instr_t;

/*!
 @function AXdisassemble_init
 @discussion Initialize the disassembler.
 */
void AXdisassemble_init();

/*!
 @function AXdisassemble_at_addr
 @discussion Disassemble the memory at address using the given CPU.
 @param cpu CPU to use for memory access
 @param addr Address to disassemble at
 @param mode Disassembly mode to use
 @param assembly Storage for assembly instruction
 @param instr Storage for instruction
 @param instr_width Storage for the instruction width
 @param thumb_offset Offset for Thumb instructions
 @result astris error code
 */
int AXdisassemble_at_addr(AXcpu_t *cpu, AXmemaddr_t addr, const char *mode, char *assembly, instr_t *instr, uint32_t *instr_width, uint16_t *thumb_offset);

__END_DECLS

#endif /* _ASTRIS_API_H */
