#ifndef _CHANNEL_RPC_COMM_H_
#define _CHANNEL_RPC_COMM_H_

/*  提示词：
请帮我用C语言来实现，编程环境为嵌入式debian linux环境。 
需求背景：
1、 在protod进程中，已经创建了一个网络通信的channel（比如可以进行报文收发, 注：socket已经创建成功），在protod进程中，会使用该channelA进行周期性的南向数据采集的任务；
2、 在north进程中，主要有OTA升级、和debug调测也需要使用到channel通道，进行报文通信，分别在不同的任务中执行相应的操作。 
3、 其中 OTA升级由于占用时间比较长，OTA升级流程会把protod上的channel通道关闭掉，OTA升级流程会自己打开通道，进行报文的收发。
4、 其中debug调测功能，会直接复用protod的channel进行报文收发
5、 主要涉及3个时序图的交互流程，参考后面内容
注1：原流程中部署在同一个进程上，debug调测、OTA升级、南向数据采集功能都已经完整实现。
注2：channel仅作为示例，实际系统中支持多个channel通道并发的。
需求描述：
1、 进程拆分后，需要实现关于channel的RPC的同步接口，支持RPC同步接口，对channel的上锁、读、写、解锁、关通道、打开通道的功能，读和写的字节长度不确定。 
2、 嵌入式环境已经引入nng的lib库，如库函数nng_listen等。
注1： RPC的读、写服务是基于RAW socket接口（read、write），不需要针对不同的协议类型，在RPC接口中进行应用层报文的封装。
注2：流程图中的锁A，主要目的是为了让northd进程上，最多只有1个任务可以访问该通道
注3：流程图中的锁B、主要目的是为了让protod进程上，最多只有1个任务可以访问该通道。
注4：流程图中的通道文件锁、主要目的是为了所有进程，只有1个通道可以打开通道。
*/


#include <stdint.h>

#ifndef CHANNEL_NAME_SIZE
#define CHANNEL_NAME_SIZE 32
#endif

#define INVALID_CLIENT_HANDLER	0xffffffff


// RPC 命令
enum channel_rpc_cmd {
    CHANNEL_RPC_SESSION_OPEN = 1,   	// 打开RPC远端通道(锁定通道只允许给RPC使用)（调测任务使用）  data为 channel的字符串
    CHANNEL_RPC_SESSION_CLOSE,        	// 关闭RPC远端通道(解锁通道允许protod本地使用)	data为0
    CHANNEL_RPC_SESSION_READ,           // 读通道	data为超时时间
    CHANNEL_RPC_SESSION_WRITE,          // 写通道	data为报文长度
    CHANNEL_RPC_REMOTE_CLOSE,           // 关闭南向protod通道（OTA升级使用）   data为channel的字符串
    CHANNEL_RPC_REMOTE_OPEN,            // 重新打开南向protod通道	
};

#define CHANNEL_RPC_PROCESS_NAME_MAX_LEN 32		/* 固定定义的比内核的长度要长，内核最大15，应用层为了区分，增大长度做兼容 */
typedef struct{
	char channel[CHANNEL_NAME_SIZE];
	char pid_name[CHANNEL_RPC_PROCESS_NAME_MAX_LEN];	/* 主要用于server端进行资源核查 */
	int pid;									/* 主要用于server端进行资源核查 */
	uint32_t resource_req_id;					/* 资源请求类的id，client端会递增，如果服务端在没有释放时，就收到资源请求，说明client有异常 */
} channel_rpc_data_alloc_resource_req;					/* 资源类请求消息的数据内容 */

typedef struct{
	uint32_t resource_req_id;					/* 资源请求类的id，client端会递增，如果服务端在没有释放时，就收到资源请求，说明client有异常 */
} channel_rpc_data_free_resource_req;					/* 资源类请求消息的数据内容 */

#define channel_rpc_data_open_session_req   channel_rpc_data_alloc_resource_req

typedef struct {
	uint32_t session_id;
} channel_rpc_data_open_session_resp;

typedef struct{
	uint32_t timeout;
	int read_size;
} channel_rpc_data_read_req;

typedef struct {
	char data[0];
} channel_rpc_data_read_resp;

typedef struct{
	char data[0];
} channel_rpc_data_write_req;

typedef struct {
	int sys_errno;		/* 南向写操作返回的系统信息 */
	int write_len;
} channel_rpc_data_write_resp;


#define channel_rpc_data_close_session_req  channel_rpc_data_free_resource_req

typedef struct {
	char data[0];
} channel_rpc_data_close_session_resp;


#define channel_rpc_data_close_req channel_rpc_data_alloc_resource_req

typedef struct{
	char data[0];		/* 当前没有数据 */
} channel_rpc_data_close_resp;


#define channel_rpc_data_open_req  channel_rpc_data_free_resource_req

typedef struct{
	char data[0];		/* 当前没有数据 */
} channel_rpc_data_open_resp;


// RPC 请求头部（后面紧跟变长数据）
typedef struct {
    uint32_t cmd;
    uint32_t trans_id;		// 传输序列号, 针对本通道，每次发起RPC请求，都会递增
    uint32_t session_id;	// 针对session由server端分配的，client针对本session发起的读、写、close
    uint32_t data_len;      // 数据长度
    // 变长数据紧随其后
} channel_rpc_request_t;

// RPC 响应头部（后面紧跟变长数据）
typedef struct {
    uint32_t transid;
    int32_t result;         // 0成功，负值错误码
    uint32_t data_len;      // 返回数据长度
    // 变长数据紧随其后
} channel_rpc_response_t;

// NNG 监听地址（IPC）
#define CHANNEL_RPC_SERVER_URL "ipc:///tmp/channel_rpc_%s.ipc"


#endif
