#ifndef _SYS_LPC_H /* local procedure call */
#define _SYS_LPC_H

#ifdef __cplusplus
extern "C" {
#endif

#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <xbook/portcomm.h>

#define FIRST_CALL_CODE  (0x00000001)
#define LAST_CALL_CODE   (0x000FFFFF)

/* 使用malloc来分配消息 */
#define LPC_MSG_USE_MALLOC  1   

/* the args we support now */
#define LPC_PARCEL_ARG_NR 8

// TODO: add FLOAT & DOUBLE arg support

enum lpc_parcel_arg_type {
    LPC_PARCEL_ARG_NONE = 0,
    LPC_PARCEL_ARG_CHAR,
    LPC_PARCEL_ARG_SHORT,
    LPC_PARCEL_ARG_INT,
    LPC_PARCEL_ARG_LONG,
    LPC_PARCEL_ARG_FLOAT,   // not support
    LPC_PARCEL_ARG_DOUBLE,  // not support
    LPC_PARCEL_ARG_STRING,
    LPC_PARCEL_ARG_SEQUENCE
};

typedef struct {
    uint32_t args[LPC_PARCEL_ARG_NR];   // 参数值
    uint16_t arglen[LPC_PARCEL_ARG_NR]; // 表明参数的长度
    uint16_t argtype[LPC_PARCEL_ARG_NR];// 表明参数的类型
    uint32_t argused;       // 如果某位是1，则表示这个参数已经被使用
    uint32_t size;          // 数据区的大小
} lpc_parcel_header_t;

#define LPC_PARCEL_HEADER_SIZE sizeof(lpc_parcel_header_t)
#define LPC_PARCEL_BUF_SIZE (PORT_MSG_SIZE - LPC_PARCEL_HEADER_SIZE)

typedef struct {
    lpc_parcel_header_t header;
    uint32_t code;      // call code
    uint8_t data[1];    // 柔性数组数据
} _lpc_parcel_t, *lpc_parcel_t;

typedef bool (*lpc_handler_t)(uint32_t, lpc_parcel_t, lpc_parcel_t);
typedef bool (*lpc_remote_handler_t) (lpc_parcel_t, lpc_parcel_t);

#define LPC_ID_TEST     PORT_COMM_TEST
#define LPC_ID_NET      PORT_COMM_NET
#define LPC_ID_GRAPH    PORT_COMM_GRAPH


lpc_parcel_t lpc_parcel_get();
int lpc_parcel_put(lpc_parcel_t parcel);
void lpc_parcel_dump_args(lpc_parcel_t parcel);
int lpc_parcel_write_string(lpc_parcel_t parcel, char *str);
int lpc_parcel_write_sequence(lpc_parcel_t parcel, void *buf, size_t len);
int lpc_parcel_write_int(lpc_parcel_t parcel, uint32_t num);
int lpc_parcel_write_long(lpc_parcel_t parcel, uint64_t num);
int lpc_parcel_write_short(lpc_parcel_t parcel, uint16_t num);
int lpc_parcel_write_char(lpc_parcel_t parcel, uint8_t num);
int lpc_parcel_read_int(lpc_parcel_t parcel, uint32_t *num);
int lpc_parcel_read_long(lpc_parcel_t parcel, uint64_t *num);
int lpc_parcel_read_short(lpc_parcel_t parcel, uint16_t *num);
int lpc_parcel_read_char(lpc_parcel_t parcel, uint8_t *num);
int lpc_parcel_read_string(lpc_parcel_t parcel, char **str);
int lpc_parcel_read_sequence(lpc_parcel_t parcel, void *buf, size_t *len);
int lpc_parcel_read_sequence_buf(lpc_parcel_t parcel, void **buf, size_t *len);
int lpc_echo(uint32_t port, lpc_handler_t func);
int lpc_echo_group(uint32_t port, lpc_handler_t func);
int lpc_call(uint32_t port, uint32_t code, lpc_parcel_t data, lpc_parcel_t reply);

#ifdef __cplusplus
}
#endif

#endif   /* _SYS_LPC_H */