/**
 * \file
 * \brief RPC Bindings for AOS
 */

/*
 * Copyright (c) 2013-2016, ETH Zurich.
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached LICENSE file.
 * If you do not find this file, copies can be found by writing to:
 * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
 */

#ifndef _LIB_BARRELFISH_AOS_MESSAGES_H
#define _LIB_BARRELFISH_AOS_MESSAGES_H

#include <aos/aos.h>

#define RPC_SHARED_SIZE PAGE_SIZE

// define some message types
enum rpc_mtype {
    RPC_MTYPE_CHILD_ENDPOINT,
    RPC_MTYPE_SEND_NUMBER,
    RPC_MTYPE_SEND_STRING,
    RPC_MTYPE_GET_RAM_CAP,
    RPC_MTYPE_SERIAL_GETCHAR,
    RPC_MTYPE_SERIAL_PUTCHAR,
    RPC_MTYPE_SERIAL_WRITE,
    RPC_MTYPE_SERIAL_READ,
    RPC_MTYPE_PROCESS_SPAWN,
    RPC_MTYPE_PROCESS_GET_NAME,
    RPC_MTYPE_PROCESS_GET_ALL_PIDS,
    RPC_MTYPE_COUNT // How many message types exist
};


/* An RPC binding, which may be transported over LMP or UMP. */
struct aos_rpc {
    struct lmp_chan *chan;
    struct waitset ws;
    void *shared_mem;

    // mutually exclusive access for threads accessing rpc
    struct thread_mutex lock;
    // take this lock if you use shared_mem, to ensure no-one else writes to it
    struct thread_mutex shared_mem_lock;
};

/**
 * \brief Initialize an aos_rpc struct.
 */
errval_t aos_rpc_init(struct aos_rpc *rpc, struct lmp_chan *chan, void *shared_mem);


/**
 * \brief Send a number.
 */
errval_t aos_rpc_send_number(struct aos_rpc *chan, uintptr_t val);

/**
 * \brief Send a string.
 */
errval_t aos_rpc_send_string(struct aos_rpc *chan, const char *string);


/**
 * \brief Request a RAM capability with >= request_bits of size over the given
 * channel.
 */
errval_t aos_rpc_get_ram_cap(struct aos_rpc *chan, size_t bytes,
                             size_t alignment, struct capref *retcap,
                             size_t *ret_bytes);


/**
 * \brief Get one character from the serial port
 */
errval_t aos_rpc_serial_getchar(struct aos_rpc *chan, char *retc);


/**
 * \brief Send one character to the serial port
 */
errval_t aos_rpc_serial_putchar(struct aos_rpc *chan, char c);

/**
 * \brief Send a list of characters to the serial port
 */
size_t aos_rpc_serial_write(struct aos_rpc *chan, const char *buf,
                            size_t buf_len);

/**
 * \brief Read a list of characters from the serial port
 */
size_t aos_rpc_serial_read(struct aos_rpc *rpc, char *buf,
                           size_t buf_len);


/**
 * \brief Request that the process manager start a new process
 * \arg cmdline the name of the process that needs to be spawned (without a
 *           path prefix) and optionally any arguments to pass to it
 * \arg newpid the process id of the newly-spawned process
 */
errval_t aos_rpc_process_spawn(struct aos_rpc *chan, char *cmdline,
                               coreid_t core, domainid_t *newpid);


/**
 * \brief Get name of process with the given PID.
 * \arg pid the process id to lookup
 * \arg name A null-terminated character array with the name of the process
 * that is allocated by the rpc implementation. Freeing is the caller's
 * responsibility.
 */
errval_t aos_rpc_process_get_name(struct aos_rpc *chan, domainid_t pid,
                                  char **name);


/**
 * \brief Get PIDs of all running processes.
 * \arg pids An array containing the process ids of all currently active
 * processes. Will be allocated by the rpc implementation. Freeing is the
 * caller's  responsibility.
 * \arg pid_count The number of entries in `pids' if the call was successful
 */
errval_t aos_rpc_process_get_all_pids(struct aos_rpc *chan,
                                      domainid_t **pids, size_t *pid_count);


/**
 * \brief Returns the RPC channel to init.
 */
struct aos_rpc *aos_rpc_get_init_channel(void);

/**
 * \brief Returns the channel to the memory server
 */
struct aos_rpc *aos_rpc_get_memory_channel(void);

/**
 * \brief Returns the channel to the process manager
 */
struct aos_rpc *aos_rpc_get_process_channel(void);

/**
 * \brief Returns the channel to the serial console
 */
struct aos_rpc *aos_rpc_get_serial_channel(void);

// MARKER SHELL: remove these temprorary functions
static inline size_t dummy_terminal_write(const char *buf, size_t len)
{
    errval_t err;

    if (len > 0) {
        err = sys_print(buf, len);
        if (err_is_fail(err)) {
            return 0;
        }
    }

    return len;
}
static inline size_t dummy_terminal_read(char *buf, size_t len)
{
    errval_t err;

    // we need this for now cause sys_getchar is blocking and not even allowing other processes to run
    if(len > 1) len = 1;

    for(size_t i = 0; i < len; ++i) {
        err = sys_getchar(&buf[i]);
        if (err_is_fail(err)) {
            return i;
        }
    }
    return len;
}

#endif // _LIB_BARRELFISH_AOS_MESSAGES_H
