/*  *********************************************************************
 *  ASTRIS - Remote JTAG probe
 *
 *  Astris.framework - C++ API
 *
 *  File: NewApi.hpp
 *
 ***********************************************************************
 *
 *  Copyright (C) 2021-2023 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 NewApi_hpp
#define NewApi_hpp

#include "astris_api.h"

#include <memory>
#include <string>

#include "NewAPI_Pointers.hpp"
#include "NewAPI_Ranges.hpp"
#include "NewAPI_Maybe.hpp"
#include "NewAPI_Memory.hpp"

// This is automatically generated file for architectural register IDs.
#include "NewAPI_CPURegisters.hpp"

namespace AstrisAPI {

typedef struct APIVersion {
    unsigned long major;
    unsigned long minor;
    unsigned long patch;
    const char *suffix;
} APIVersion_t;

enum class cpu_arch_e {
    ARMV4 = AXCPUARCH_ARMV4,
    ARMV6 = AXCPUARCH_ARMV6,
    ARMV6M = AXCPUARCH_ARMV6M,
    ARMV7 = AXCPUARCH_ARMV7,
    ARMV7M = AXCPUARCH_ARMV7M,
    ARMV7EM = AXCPUARCH_ARMV7EM,
    ARMV8 = AXCPUARCH_ARMV8,
    ARMV8M = AXCPUARCH_ARMV8M,
    XTENSA = AXCPUARCH_XTENSA,
    ARC = AXCPUARCH_ARC,
    LACC = AXCPUARCH_LACC,
    UNKNOWN = AXCPUARCH_UNKNOWN,
};

enum class cpu_type_e {
    CORTEX_A8 = AXCPUTYPE_CORTEX_A8,
    CORTEX_A9 = AXCPUTYPE_CORTEX_A9,
    CORTEX_A5 = AXCPUTYPE_CORTEX_A5,
    CORTEX_A7 = AXCPUTYPE_CORTEX_A7,
    CORTEX_M0 = AXCPUTYPE_CORTEX_M0,
    CORTEX_M3 = AXCPUTYPE_CORTEX_M3,
    CORTEX_M4 = AXCPUTYPE_CORTEX_M4,
    CORTEX_M7 = AXCPUTYPE_CORTEX_M7,
    CORTEX_M33 = AXCPUTYPE_CORTEX_M33,
    CORTEX_R5 = AXCPUTYPE_CORTEX_R5,
    ARM7 = AXCPUTYPE_ARM7,
    ARM11 = AXCPUTYPE_ARM11,
    HIFI3 = AXCPUTYPE_HIFI3,
    SWIFT = AXCPUTYPE_SWIFT,
    CYCLONE = AXCPUTYPE_CYCLONE,
    TYPHOON = AXCPUTYPE_TYPHOON,
    TWISTER = AXCPUTYPE_TWISTER,
    BIGLITTLE = AXCPUTYPE_BIGLITTLE,
    MARIN = AXCPUTYPE_MARIN,
    MONSOON = AXCPUTYPE_MONSOON,
    MISTRAL = AXCPUTYPE_MISTRAL,
    CHINOOK = AXCPUTYPE_CHINOOK,
    VORTEX = AXCPUTYPE_VORTEX,
    TEMPEST = AXCPUTYPE_TEMPEST,
    CHINOOKASC3 = AXCPUTYPE_CHINOOKASC3,
    LIGHTNING = AXCPUTYPE_LIGHTNING,
    THUNDER = AXCPUTYPE_THUNDER,
    FIRESTORM = AXCPUTYPE_FIRESTORM,
    ICESTORM = AXCPUTYPE_ICESTORM,
    CHINOOKASC4 = AXCPUTYPE_CHINOOKASC4,
    TEMPESTASC4 = AXCPUTYPE_TEMPESTASC4,
    CHINOOKASC5 = AXCPUTYPE_CHINOOKASC5,
    TEMPESTASC5 = AXCPUTYPE_TEMPESTASC5,
    BLIZZARD = AXCPUTYPE_BLIZZARD,
    AVALANCHE = AXCPUTYPE_AVALANCHE,
    CHINOOKASC6 = AXCPUTYPE_CHINOOKASC6,
    TEMPESTASC6 = AXCPUTYPE_TEMPESTASC6,
    SAWTOOTH = AXCPUTYPE_SAWTOOTH,
    EVEREST = AXCPUTYPE_EVEREST,
    CORTEX_A53 = AXCPUTYPE_CORTEX_A53,
    CORTEX_M23 = AXCPUTYPE_CORTEX_M23,
    ARC_DSP = AXCPUTYPE_ARC_DSP,
    LACC = AXCPUTYPE_LACC,
    ACCE_H16G = AXCPUTYPE_ACCE_H16G,
    ACCP_H16G = AXCPUTYPE_ACCP_H16G,
    CHINOOKASC7 = AXCPUTYPE_CHINOOKASC7,
    TEMPESTASC7 = AXCPUTYPE_TEMPESTASC7,
    UNKNOWN = AXCPUTYPE_UNKNOWN,
};

struct CpuInfo
{
    // cpuinfo
    cpu_arch_e arch = cpu_arch_e::UNKNOWN;
    cpu_type_e type = cpu_type_e::UNKNOWN;
};

enum class cpuwp_access_e {
    LOAD = 1,
    STORE,
    ALL
};

// TODO: how to handle coredumps
class ASTRIS_EXPORT CPU: public ObjectBase
{
public:
    using ptr_t = RetainablePtr<CPU>;
    using bpwp_info_map_t = DictRange<int, bpwp_info_t>;
    using regval_t = AXregval_t;
    
    virtual ~CPU();
    
    virtual const char* getName() = 0;
    virtual bool isRunning() const = 0;
    virtual bool isHalted() const = 0;
    virtual err_t halt() = 0;
    virtual err_t go() = 0;
    
    virtual Maybe<CpuInfo> getCpuInfo() const = 0;
    virtual err_t getStatus() const = 0;
    virtual err_t getDetailedStatus(AXcpu_status_t &status) const = 0;
    virtual err_t group() const = 0;
    virtual Maybe<AXmemaddr_t> address() const = 0;
    virtual const char* subsystem() const  = 0;
    
    // TODO: Should have a way to either get the AP select, or readMemory via its select
    // I think the second method would be too confusing aka whats readMemory vs readMemoryAP
    // Why this is helpful is because sometimes you want to access the PIO space where the CPU
    // lives via system bus. So getting AP select helps here. We use this for our CPU registers
    
    // TODO:    Range containers are best suited for returning static collections,
    //          but breakpoints and watchpoints are dynamic (volatile), since those
    //          can change via outside influence.
    //          Perhaps it would be better to use a child objects to represent these
    //          collections and individual *points?
    //          It can still retain range and iterator semantics.
    // Breakpoints/watchpoints
    virtual Maybe<bpwp_info_map_t> getBreakpoints() = 0;
    virtual err_t setBreakpoint(AXmemaddr_t address) = 0;
    virtual err_t enableBreakpoint(unsigned int idx) = 0;
    virtual err_t disableBreakpoint(unsigned int idx) = 0;
    virtual err_t deleteBreakpoint(unsigned int idx) = 0;
    virtual Maybe<bpwp_info_map_t> getWatchpoints() = 0;
    virtual err_t setWatchPoint(AXmemaddr_t address, unsigned int width, cpuwp_access_e access) = 0;
    virtual err_t enableWatchpoint(unsigned int idx) = 0;
    virtual err_t disableWatchpoint(unsigned int idx) = 0;
    virtual err_t deleteWatchpoint(unsigned int idx) = 0;

    virtual Maybe<size_t> readMemory(AXmemaddr_t address, uint8_t *buffer, size_t length) = 0;
    virtual Maybe<size_t> writeMemory(AXmemaddr_t address, const uint8_t *buffer, size_t length, bool iflush) = 0;
    
    // For all registers (including non-architectural registers)
    virtual Maybe<RegisterId> lookupRegister(const char *name) = 0;
    virtual err_t readRegister(const char *registerName, regval_t &val) = 0;
    virtual err_t writeRegister(const char *registerName, regval_t val) = 0;
    virtual err_t readRegister(RegisterId regid, regval_t &val) = 0;
    virtual err_t writeRegister(RegisterId regid, regval_t val) = 0;

    virtual err_t step() = 0;

protected:
    CPU();
};

class ASTRIS_EXPORT TAP: public ObjectBase
{
public:
    using ptr_t = RetainablePtr<TAP>;
    
    virtual ~TAP();

    virtual Maybe<uint32_t> getIdcode() = 0;
    virtual Maybe<uint32_t> getIRLen() = 0;
    virtual Maybe<uint32_t> getIRBefore() = 0;
    virtual Maybe<uint32_t> getIRAfter() = 0;
    virtual Maybe<uint32_t> getDRBefore() = 0;
    virtual Maybe<uint32_t> getDRAfter() = 0;
    virtual Maybe<uint32_t> getFlags() = 0;

    // JTAG Scan IR
    virtual err_t doJTAGScanIR(uint8_t *data, uint32_t bitcount) = 0;
    virtual err_t doJTAGScanIRExit1(uint8_t *data, uint32_t bitcount) = 0;

    // JTAG Scan DR
    virtual err_t doJTAGScanDR(uint8_t *data_in, uint8_t *data_out, uint32_t bitcount) = 0;

    // Send TAP to EXIT1_DR state after DR Scan
    virtual err_t doJTAGScanDRExit1(uint8_t *data_in, uint8_t *data_out, uint32_t bitcount) = 0;

    // Keep TAP at DR Scan after DR Scan
    virtual err_t doJTAGScanDRStay(uint8_t *data_in, uint8_t *data_out, uint32_t bitcount) = 0;

    virtual err_t doJTAGIdle(uint32_t cycles) = 0;
    virtual err_t doPauseDR(uint32_t cycles) = 0;
    virtual err_t doSDSCycles(uint32_t cycles) = 0;
    
protected:
    TAP();
};

class ASTRIS_EXPORT DAP: public ObjectBase
{
public:
    using ptr_t = RetainablePtr<DAP>;

    virtual ~DAP();

    virtual Maybe<uint32_t> getIdcode() = 0;

    // DP Functions - To do DAP (DP) register read and writes
    virtual Maybe<uint32_t> dpReadReg(uint32_t regaddr) = 0;
    virtual err_t dpWriteReg(uint32_t regaddr, uint32_t regval) = 0;

    // AP Functions - These are functions to read/write AP registers. NOT to use
    // this AP to do the read/write
    virtual Maybe<uint32_t> apGetType(uint32_t ap_select) = 0;
    virtual Maybe<uint32_t> apReadReg(uint32_t ap_select, uint32_t regaddr) = 0;
    virtual err_t apWriteReg(uint32_t ap_select, uint32_t regaddr, uint32_t regval) = 0;

protected:
    DAP();
};

class ASTRIS_EXPORT SoC: public ObjectBase
{
public:
    using ptr_t = RetainablePtr<SoC>;
    using cpu_dict_t = DictRange<std::string, CPU::ptr_t>;
    using tap_list_t = ListRange<TAP::ptr_t>;
    
    virtual ~SoC();
    
    virtual const char* getName() = 0;
    virtual const char* getRevision() = 0;
    
    virtual Maybe<size_t> readMemoryWithAP(uint32_t ap_select, AXmemaddr_t address, uint32_t width, uint8_t *buffer, size_t bytes) = 0;
    virtual Maybe<size_t> readValuesWithAP(uint32_t ap_select, AXmemaddr_t address, uint32_t width, uint8_t *buffer, size_t count, bool fifo=false) = 0;
    virtual Maybe<size_t> writeValuesWithAP(uint32_t ap_select, AXmemaddr_t address, uint32_t width, const uint8_t *buffer, size_t count, bool fifo=false) = 0;

    virtual Maybe<uint32_t> getSysAPSelect() = 0;
    virtual Maybe<uint32_t> getDbgAPSelect() = 0;

    virtual cpu_dict_t getCpus() = 0;
    virtual err_t haltAllCPUs() = 0;

    // TODO: what to do with complexes?

    
//    Thinking outloud:
//    - 2-Wire SWD: There are JTAG-APs, and each AP can technically have multiple TAPs.
//    Then there are can also be multiple JTAG-APs as well. We collect all these under AXchip_t
//    without any of these flags set: AXCHIP_HAS_JTAG_DP | AXCHIP_HAS_SWD_DP | AXCHIP_HAS_KIS .
//    These flags get set in astris_checkidcode via our hardcoded list of DAPs.
//
//    So each system can have lot of "TAPs" aka things we use JTAG-AP to talk via.
//    However, on basically all Apple SoCs we just have 1 TAP which is our main TAP, we do all the functions
//    via that. We could add in the back end in AppleSoC the notion of "default TAP" so that below plays here.
//
//    5-Wire:
//    We can be in scenarios where there are NO daps, and No SoCs and we just have TAP. What do we do here?
//
//    If we really think about how the old API is structured its AXchip -> SoC and AXchip is a DAP.
//    JTAG operations are done without the DAP and instead using the AXchip thats for a TAP.
//
//    This leads to question what is a system vs soc, if a system is multiple SoCs, are SoCs DAPs?
//    DAPs can contain TAPs?
//
//    I think question goes to does SoC object represent the DAP as a whole or just the AppleSoC object?
//    I propose the following, what if we break away how ARM Debug thinks and models and instead think of how HW does it:
//    SoC -> DAP -> TAP, so SoC is the larger all encompassing object, that object has a DAP, the DAP has APs and can have TAPs
//    TAP in the end will just talk to an AP, but this is an abstraction. Then we can have the notion of "default tap" for SoC, and
//    maybe have these functions here just be helpers that call into default TAP index
//    So we need a new DAP object that will encompass our lower leve DP, AP, TAP/JTAG commands I think, and there is only one DAP per SoC.

//      Or SoC -> DAP
//             -> TAP
//    Here the notion that TAPs can either be stand alone 5-write or part of the DAP and we hide that notion from the user. That way on
//    scenarios with no DAPs, we dont have this weird thing of "well technically we are in 5 write mode connected straight to TAP"

    virtual tap_list_t getTAPs() = 0;
    virtual Maybe<TAP::ptr_t> getDefaultTAP() = 0;

    // There can maybe be no DAP, if connected to 5 wire
    virtual Maybe<DAP::ptr_t> getDAP() = 0;

    virtual Maybe<uint64_t> getECID() = 0;

    virtual Maybe<uint64_t> spmi_read_bus(uint8_t bus_sel, astris_spmi_dev_addr_t dev_addr, astris_spmi_reg_addr_t reg_addr, uint8_t count) = 0;
    virtual Maybe<size_t> spmi_write_bus(uint8_t bus_sel, astris_spmi_dev_addr_t dev_addr, astris_spmi_reg_addr_t reg_addr, uint64_t value, uint8_t count) = 0;

protected:
    SoC();
};

enum class reset_type_e {
    JTAG_SRST,
    SWD,
    DCM,
};

enum class dfu_type_e {
    DEFAULT = 0,
    SPMI,
    EAM,
    DCM,
    RELAY,
};

struct BypassConfig
{
    BypassConfig():
        channel(0),
        target_id(0),
        instance(0)
    {}

    BypassConfig(const AXbypass_config_t &config):
        device_name(config.device_name),
        channel(config.channel),
        target_id(config.targetid),
        instance(config.instance)
    {}

    ::std::string device_name;
    uint32_t channel;
    uint32_t target_id;
    uint32_t instance;
};

class ASTRIS_EXPORT System: public ObjectBase
{
public:
    using ptr_t = RetainablePtr<System>;
    using soc_list_t = ListRange<SoC::ptr_t>;
    using bypass_list_t = ListRange<BypassConfig>;
    
    virtual ~System();
    
    virtual err_t reset(reset_type_e reset_type=reset_type_e::JTAG_SRST) = 0;
    virtual err_t enterDFU(dfu_type_e dfu_type=dfu_type_e::DEFAULT) = 0;
    virtual Maybe<bool> isDFU() const = 0;
    
    virtual soc_list_t getSoCs() = 0;

    virtual Maybe<uint32_t> getBoardID() const = 0;
    virtual Maybe<AXproduct_info_t> getProductInfo() const = 0;

    // TODO: should bypass done here or on SoC? Or both?

    // JTAG related methods
    enum jtag_mode_e {
        MODE_SWD = AXJTAG_MODE_SWD,
        MODE_JTAG = AXJTAG_MODE_JTAG,
    };
    virtual err_t setJTAGMode(jtag_mode_e mode) = 0;
    virtual jtag_mode_e getJTAGMode() const = 0;
    virtual Maybe<bypass_list_t> getBypassInfo() = 0;
    
    virtual err_t enableSWDBypass(uint32_t bypass_channel, bool force_pins, uint32_t target_select, uint32_t target_instance=0) = 0;
    virtual err_t disableSWDBypass() = 0;

    virtual Maybe<uint8_t> getSDOM() const = 0;

    virtual Maybe<SoC::ptr_t> getSoC(const char *name, size_t index=0) = 0;

    virtual Maybe<bool> isProdFused() const = 0;
protected:
    System();
};

class ASTRIS_EXPORT Probe: public ObjectBase
{
public:
    using ptr_t = RetainablePtr<Probe>;

    virtual ~Probe();
    
    virtual const char* getName() const = 0;
    virtual const char* getConnectionString() const = 0;
    virtual int getPort() const = 0;
    virtual AXProbeStatus_t getStatus() const = 0;
    virtual bool wasKickRequested() = 0;
    virtual const char* getKickInfo() = 0;
    
    virtual const char* getUsbCPortName() const = 0;
    virtual uint32_t getPrimateLoc() const = 0;
    virtual uint32_t getPrimateHubLoc() const = 0;
    virtual uint32_t getKisLoc() const = 0;
    virtual uint32_t getKisHubLoc() const = 0;

protected:
    Probe();
};

class ASTRIS_EXPORT Connection : public ObjectBase
{
public:
    using ptr_t = RetainablePtr<Connection>;

    virtual ~Connection();

    virtual err_t close() = 0;

    // TODO: need a more streamlined way to do explore flags
    virtual Maybe<System::ptr_t> explore(uint32_t explore_flags=0) = 0;
    // If the connection is already explored, then we can return the system
    virtual Maybe<System::ptr_t> getSystem() = 0;

    virtual Probe::ptr_t getProbe() const = 0;
    virtual const char* getConnectionString() const = 0;
    virtual bool isHosted() const = 0;
    virtual bool isConnected() const = 0;
    virtual bool isExplored() const = 0;
    virtual err_t switchGateways() = 0;
    virtual err_t chooseGateway(AXGatewayType_t gateway) = 0;
    virtual AXGatewayType_t currentGateway() = 0;
    virtual bool supportsKIS() = 0;
    virtual bool isKISEnabled() = 0;
    virtual bool isSTMConnection() = 0;

    virtual Maybe<Connection::ptr_t> createSTMBypass(uint32_t bypass_channel, uint32_t target_select, uint32_t target_instance=0) = 0;
    virtual Maybe<System::ptr_t> enableSWDBypass(uint32_t bypass_channel, bool force_pins, uint32_t target_select, uint32_t target_instance=0) = 0;
    virtual Maybe<System::ptr_t> disableSWDBypass() = 0;

    virtual uint32_t getBypassChannel() = 0;
    virtual uint32_t getTargetSel() = 0;
    virtual uint32_t getTargetInstance() = 0;

    virtual err_t Refresh() = 0;

    virtual bool wasKickRequested() = 0;
    virtual const char* getKickInfo() = 0;

#if DEBUG == 1
    virtual AXconn_t* getAxConn() const = 0;
    virtual AXchip_t* getAxDAP() const = 0;
    virtual err_t reExplore(bool progressive_phase2 = false) = 0;
#endif

protected:
    Connection();
};

enum class log_category_e: uint64_t {
    USER = AXL_USER,
    IN = AXL_IN,
    OUT = AXL_OUT,
    STATUS = AXL_STA,
    PROMPT = AXL_PRMPT,
    STDOUT = AXL_STD,
    STDERR = AXL_ERR,
    BEGIN = AXL_BEGIN,
    END = AXL_END,
};

enum class log_source_e {
    DEFAULT = ASTRIS_OS_LOG_SRC_DEFAULT,
    USER = ASTRIS_OS_LOG_SRC_USER,
    LLDB = ASTRIS_OS_LOG_SRC_GDB,
    EXPLORE = ASTRIS_OS_LOG_SRC_EXPLORE,
    STATUS = ASTRIS_OS_LOG_SRC_STATUS,
    CONNECT = ASTRIS_OS_LOG_SRC_CONNECT,
    BOOSTER = ASTRIS_OS_LOG_SRC_BOOSTER,
    RPC = ASTRIS_OS_LOG_SRC_RPC,
    PROBED = ASTRIS_OS_LOG_SRC_PROBED,
};

class ASTRIS_EXPORT Logger   // This class is a singleton inside Conductor
{
public:
    using ptr_t = Logger*;
    
    virtual ~Logger();
    
    virtual void log(uint64_t category, const char *msg) = 0;
    virtual void log(uint64_t category, const char *domain, const char *msg) = 0;
    
    virtual void setSource(log_source_e source) = 0;
    virtual void unsetSource() = 0;
    virtual log_source_e getSource() = 0;

    virtual err_t save(const char *filePath) = 0;
    virtual void clear() = 0;
    virtual bool getHistoryEnabled() = 0;
    virtual void setHistoryEnabled(bool enable) = 0;
    
    virtual void setDepth(int depth=AXLOG_HISTORY_NOLIMIT) = 0;
    virtual int getDepth() = 0;

    virtual void enableOutput() = 0;
    virtual void disableOutput() = 0;

protected:
    Logger();

private:
    // Logger is a singleton and should not be copied
    Logger(const Logger&) = delete;
    Logger& operator=(const Logger&) = delete;
};

enum connect_options_e: uint32_t {
    CONNECT_DEFAULT = 0,
    CONNECT_FORCE_KICK = AXCONN_FLG_CONN_FORCE_KICK,
    CONNECT_ONLY_HPM = AXCONN_FLG_CONN_ONLY_HPM,
    CONNECT_NO_FORCE_PINS = AXCONN_FLG_CONN_NO_FORCE_PINS,
};
    
/*!
 * @class ConnectionManager
 * @discussion Top level object in Astris C++ API. It represents the entire namespace of
 * Astris C++ API objects and serves as a top of object model hierarchy.
 * This class is asingleton.
 * @link GetConnectionManager @/link
 */
class ASTRIS_EXPORT ConnectionManager: public ObjectBase
{
public:
    using ptr_t = ConnectionManager*;
    using connection_list_t = ListRange<Connection::ptr_t>;
    using probe_list_t = ListRange<Probe::ptr_t>;
    
    virtual ~ConnectionManager();

    virtual const char *getVersion() const = 0;
    virtual Maybe<Logger::ptr_t> getLogger() = 0;
    
    virtual Maybe<Connection::ptr_t> createConnection(const char *connectionString, connect_options_e connect_options=CONNECT_DEFAULT) = 0;
    virtual connection_list_t getConnections() const = 0;
    
    virtual probe_list_t getProbes(const char *host=nullptr) const = 0;
    
    virtual const char* getBoosterPackRoot() const = 0;
    virtual void setBoosterPackRoot(const char *root) = 0;
    virtual const char* getAstrisRoot() const = 0;
    virtual void setAstrisRoot(const char *root) = 0;

    virtual bool isHosted() const = 0;

    // This creates automatic (JIT) bypass connection
    virtual Maybe<Connection::ptr_t> createSmartConnection(const char *connectionString, connect_options_e=CONNECT_DEFAULT) = 0;

protected:
    
    ConnectionManager();
    
private:
    // Connection manager is a singleton thus should not be copied
    ConnectionManager(const ConnectionManager&) = delete;
    ConnectionManager& operator=(const ConnectionManager&) = delete;
};

/*!
 * @function GetConnectionManager
 * @discussion This function is the main entry point to the Astris C++ API as it
    returns an instance of ConnectionManager, which can be used to create and
 *  access other Astris C++ API objects.
 * @return A pointer to the singleton instance of ConnectionManager class.
 * @link class ConnectionManager @/link
 */
ConnectionManager::ptr_t ASTRIS_EXPORT GetConnectionManager(void);

/*!
 * @function GetAPIVersion
 * @discussion This function returns API semantic version in the form of Major.Minor.Patch. The version
 * is returned as a structure and the structure has an optional suffix string. The suffix is used for pre-release version
 * designators as well as build metadata. Please see https://semver.org for more information.
 * @return A const pointer to the APIVersion_t structure.
 */
const AstrisAPI::APIVersion_t* ASTRIS_EXPORT GetAPIVersion(void);

}   // namespace AstrisAPI

#include "NewAPI_LogStream.hpp"

#endif /* NewApi_hpp */
