IPCFHAL开发说明
===============

IPC典型使用场景
--------------------

.. image:: ./media/imageipcscen.png
   :align: center
   :alt: 

IPC典型应用场景有OTA模块、诊断模块、规控、CANHAL等。

IPC实例分配方案
--------------------

IPC目前实例编号范围为0~34，分别用于Acore与MCU通信的实例0~14、Acore与VDSP通信的实例22~28、Acore与BPU通信的实例32~34，其余实例做其它私有用途。
客户Acore与MCU通信可使用实例3~10，若用户不需要CANHAL、规控等业务，可以自行使用CANHAL(实例0)和规控(实例1和2)的实例，其余实例为地平线内部使用。

Acore侧配置实例方法
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Acore侧配置实例可通过设备树文件配置，配置路径为：

.. code:: bash

	hobot-drivers/kernel-dts/hobot-j6e-ipc.dtsi
	hobot-drivers/kernel-dts/include/hobot_j6e_ipc.h

设备树配置信息如下：

.. code:: bash

	ipcfhal_cfg: ipcfhal_cfg {
		status = "okay"; #节点状态，不需要改动
		compatible = "hobot,hobot-ipcfhal"; #节点属性，不可改动

		/*******************instance-------num_chans--num_bufs--buf_size*******************/
		ipc-ins =	<&ipc_instance0		8	8	0x2000>, #(Acore&MCU)用于CANHAL
				<&ipc_instance1		8	8	0x1000>, #(Acore&MCU)用于规控
				<&ipc_instance2		2	8	0x800>, #(Acore&MCU)用于规控
				<&ipc_instance3		8	8	0x1000>, #(Acore&MCU)空闲，用户可自行配置
				<&ipc_instance4		8	8	0x1000>, #(Acore&MCU)空闲，用户可自行配置
				<&ipc_instance5		8	8	0x1000>, #(Acore&MCU)空闲，用户可自行配置
				<&ipc_instance6		8	8	0x1000>, #(Acore&MCU)空闲，用户可自行配置
				<&ipc_instance7		8	8	0x1000>, #(Acore&MCU)空闲，用户可自行配置
				<&ipc_instance8		8	8	0x1000>, #(Acore&MCU)空闲，用户可自行配置
				<&ipc_instance9		2	5	0x400>, #(Acore&MCU)空闲，用户可自行配置
				<&ipc_instance10	1	5	0x200>, #(Acore&MCU)空闲，用户可自行配置
				<&ipc_instance22	8	8	0x1000>, #(Acore&VDSP)VDSP预留，暂未对客户开放
				<&ipc_instance23	8	8	0x1000>, #(Acore&VDSP)VDSP预留，暂未对客户开放
				<&ipc_instance24	8	8	0x1000>; #(Acore&VDSP)VDSP预留，暂未对客户开放
	};

设备树配置说明
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

发布的版本设备树实例7和实例8并未配置，用户若需要使用，可参照上面设备树节点添加实例7和8的属性，属性中第一列表示实例编号，必须唯一且在有效范围，属性的第二列表示该实例分配的通道数量，用户可以自行配置，最大值为32个。
属性的第三列表示每个通道的缓冲buf的个数，用户可以自行配置，最大值为1024个，但受控制空间大小的限制。属性第四列表示缓冲buf的大小，单位是Bytes，用户可以自行配置，通道个数*缓冲buf个数*buf大小需要小于等于0.5MB（目前每个实例预分配了1MB的数据空间，暂不扩增）。

单个实例的设备树节点如下：

.. code:: bash

	#Not used, User can apply for it
	ipc_instance3: ipc_instance3 {
		status = "okay"; #节点状态，不需要改动
		compatible = "hobot,hobot-ipc"; #节点属性，不可改动
		mbox-names = "mbox-chan"; #mailbox名字属性，不可改动
		mboxes = <&mailbox0 3 19 3>; #mailbox通信方向，实例5和实例6需要改动，其它实例不需要改动
		instance = <3>; #实例id，不需要改动
		data_local_addr = /bits/ 64 <IPC_INS3_DATA_LOCAL>; #Acore数据段，实例5和实例6需要改动，其它实例不需要改动
		data_remote_addr = /bits/ 64 <IPC_INS3_DATA_REMOTE>; #MCU数据段，实例5和实例6需要改动，其它实例不需要改动
		data_size = <IPC_SINGLE_DATA_SIZE>; #数据段大小，不可改动，单位Bytes
		ctrl_local_addr = /bits/ 64 <IPC_INS3_CTRL_LOCAL>; #Acore控制段，实例5和实例6需要改动，其它实例不需要改动
		ctrl_remote_addr = /bits/ 64 <IPC_INS3_CTRL_REMOTE>; #MCU控制段，实例5和实例6需要改动，其它实例不需要改动
		ctrl_size = <IPC_SINGLE_CTRL_SIZE>; #数据段大小，不可改动，单位Bytes
	};

由于实例5和实例6内部用于测试，外部客户若需要使用，需要自行配置，配置信息如下，不需要改动。

.. code:: bash

	ipc_instance5: ipc_instance5 {
		status = "okay";
		compatible = "hobot,hobot-ipc";
		mbox-names = "mbox-chan";
		mboxes = <&mailbox0 5 21 5>;
		instance = <5>;
		data_local_addr = /bits/ 64 <IPC_INS5_DATA_LOCAL>;
		data_remote_addr = /bits/ 64 <IPC_INS5_DATA_REMOTE>;
		data_size = <IPC_SINGLE_DATA_SIZE>;
		ctrl_local_addr = /bits/ 64 <IPC_INS5_CTRL_LOCAL>;
		ctrl_remote_addr = /bits/ 64 <IPC_INS5_CTRL_REMOTE>;
		ctrl_size = <IPC_SINGLE_CTRL_SIZE>;
	};

	ipc_instance6: ipc_instance6 {
		status = "okay";
		compatible = "hobot,hobot-ipc";
		mbox-names = "mbox-chan";
		mboxes = <&mailbox0 6 22 6>;
		instance = <6>;
		data_local_addr = /bits/ 64 <IPC_INS6_DATA_LOCAL>;
		data_remote_addr = /bits/ 64 <IPC_INS6_DATA_REMOTE>;
		data_size = <IPC_SINGLE_DATA_SIZE>;
		ctrl_local_addr = /bits/ 64 <IPC_INS6_CTRL_LOCAL>;
		ctrl_remote_addr = /bits/ 64 <IPC_INS6_CTRL_REMOTE>;
		ctrl_size = <IPC_SINGLE_CTRL_SIZE>;
	};

设备树配置注意事项
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

-  实例3~10数据段默认预分配了1MB空间，Acore侧使用0.5MB，MCU侧使用0.5MB，所以通道个数*缓冲buf个数*buf大小需要小于等于0.5MB。
-  实例3~10控制段默认预分配了5KB空间，Acore侧使用2.5KB，MCU侧使用2.5KB，存放环形buf的控制信息和状态信息，所以(缓冲buf个数+2)*16*通道个数+8需要小于等于2.5KB。
-  实例5~6用于地平线内部测试，用户可按照上面配置，修改设备树节点即可。
-  每个实例的通道数量需要小于等于32，缓冲buf个数需要小于等于1024，同时需要满足前两点的不等式。
-  多个业务使用同一个实例的不同通道或者使用不同实例对传输影响不大，主要是参考buf_size/buf_num是否合适以及业务的开发和维护是否方便。
-  底层Mailbox中断分配不支持修改。
-  Acore与MCU的通道个数、缓冲buf个数和大小需要保持一致，数据段和控制段的local和remote需要相反。
-  实例的控制段首地址存储实例是否初始化的状态，可用于判断实例是否初始化，其中Acore默认启动kernel时完成初始化。
-  若用户需要自行分配数据段和地址段，则需要修改Acore设备树文件、Uboot设备树文件以及MCU配置文件（包括MCU EB配置）。

用户态Json配置文件使用方法
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

请参考: :doc:`ipc sample <../../sample_doc/platform_samples/sample_doc_platform_samples_ipc_sample>`。

MCU侧配置实例方法
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

请参考: :doc:`配置文档 <../../mcu_mcalcdd/cdd_ipc/mcu_mcallcdd_ipc_2_configuration>`。

Acore与MCU传输流程
--------------------

Acore与MCU IPC通信使用MCU MDMA将数据在DDR与MCU SRAM之间搬运，MCU发送数据到Acore的流程中，MCU先使用MDMA将数据从SRAM搬运到DDR，再发送中断通知，
Acore发送数据到MCU的流程中，MCU收到中断通知后，使用MDMA将数据从DDR搬运到SRAM。

MCU发送数据到Acore
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. image:: ./media/imager52a78.png
   :align: center
   :alt: 

Acore发送数据到MCU
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. image:: ./media/imagea78r52.png
   :align: center
   :alt: 

IPCFHAL接口使用序列
--------------------

.. image:: ./media/imageipcfhalapi.png
   :align: center
   :alt: 

IPCFHAL在Acore与MCU通信时，MCU侧用户使用IPCF接口。

IPCFHAL使用注意事项
--------------------

-  ipcfhal同一个通道不支持多进程；若使用多线程收发，收发时序和逻辑需要用户保障。
-  MCU侧SRAM fifo 太小仅用于地平线内部使用。出于节省SRAM的角度，客户使用DDR方案。
-  Acore侧每个实例的中断对应的优先级不可配置，MCU可配置。
-  若应用对系统调度延时的波动比较敏感，可调整应用程序的调度策略为SCHED_FIFO。

IPCFHAL调试方法
--------------------

调试日志
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

IPCFHAL及底层的IPCF、Mailbox驱动都提供了较完整的log信息，若有调试问题，可查看log输出，帮助定位问题。

error code (api 返回值)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

IPCFHAL定义了一些error code，覆盖了常见的错误类型，可使用接口：hb_ipcfhal_trans_err将error code转换为错误描述。

sysfs调试节点(Acore侧)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

statistic调试节点
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

打印统计的通信信息，包括pkg，pkg_len，err_acq，err_shm_tx，err_cb。

【节点路径】

.. code:: c

	//ins-X表示insid，若insid是5，则为ins-5
	/sys/kernel/debug/ipcdrv-ins-5/statistic

【节点作用】

.. code:: c

	//以instance为单位，统计所有channel接收&发送的count
	struct ipc_statistic_t {
		uint32_t acq_cnt;/**< tx: acquire buf count*/
		uint32_t shm_tx_cnt;/**< tx: send count*/
		uint32_t cb_cnt;/**< rx: callback count*/
		uint32_t err_acq;/**< tx: error acquire buf count*/
		uint32_t err_shm_tx;/**< tx: error send count*/
		uint32_t err_cb;/**< rx: error callback count*/

		uint32_t packages;/**< tx/rx: packages count*/
		uint64_t datalen;/**< tx/rx: datalen*/
	};

【节点使用】

.. code:: c

	//方法一：直接操作sys节点
	//通道完成初始化，未收发数据时, enable
	echo 0 > /sys/kernel/debug/ipcdrv-ins-5/statistic
	//收发数据结束，且通道未去初始化时，get
	cat /sys/kernel/debug/ipcdrv-ins-5/statistic


	//方法二：使用open/write/read/close操作
	fd= open(/sys/kernel/debug/ipcdrv-ins-5/statistic, O_RDWR);
	write(fd, buf, 1024);
	//tx/rx，收发数据
	read(fd, buf, 1024);
	close(fd);


【log】

.. code:: c

	DataLink:
					pkg              pkg_len    err_acq err_shm_tx     err_cb
		INS5CH0 TX:              1                   32          0          0          0
		INS5CH0 RX:              1                   32          0          0          0
		INS5CH1 TX:              0                    0          0          0          0
		INS5CH1 RX:              0                    0          0          0          0
		INS5CH2 TX:              0                    0          0          0          0
		INS5CH2 RX:              0                    0          0          0          0
		INS5CH3 TX:              0                    0          0          0          0
		INS5CH3 RX:              0                    0          0          0          0
		INS5CH4 TX:              0                    0          0          0          0
		INS5CH4 RX:              0                    0          0          0          0
		INS5CH5 TX:              0                    0          0          0          0
		INS5CH5 RX:              0                    0          0          0          0
		INS5CH6 TX:              0                    0          0          0          0
		INS5CH6 RX:              0                    0          0          0          0
		INS5CH7 TX:              0                    0          0          0          0
		INS5CH7 RX:              0                    0          0          0          0


tsdump调试节点
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

以channel为单位，收发数据时打印时间戳。

【节点路径】

.. code:: c

	//ins-X表示insid，若insid是5，则为ins-5
	/sys/kernel/debug/ipcdrv-ins-5/tsdump

【节点作用】

.. code:: c

	//以channel为单位，使能收发数据时，打印时间戳log
	int32_t tsdump;/**< >=0, 使能指定channel的时间戳打印log， <0, 关闭时间戳log*/

【节点使用】

.. code:: c

	//方法一：直接操作sys节点
	//通道完成初始化，未收发数据时, enable
	echo 0 > /sys/kernel/debug/ipcdrv-ins-5/tsdump
	//收发数据过程中，会打印时间戳log
	//收发数据结束，且通道未去初始化时，get
	cat /sys/kernel/debug/ipcdrv-ins-5/tsdump


	//方法二：使用open/write/read/close操作
	fd= open(/sys/kernel/debug/ipcdrv-ins-5/tsdump, O_RDWR);
	write(fd, buf, 1024);
	//tx/rx，打印时间戳log
	read(fd, buf, 1024);
	close(fd);


【log】

.. code:: c

	[ 1173.246630] ipc-shm-hal: dev_print_timestamp()[515]: [5][0] tx wt sta: 1717558158.887241446
	[ 1173.246642] ipc-shm-hal: dev_print_timestamp()[515]: [5][0] tx wt end: 1717558158.887253646
	[ 1173.246717] ipc-shm-hal: dev_print_timestamp()[515]: [5][0] rx cb sta: 1717558158.887327971
	[ 1173.246723] ipc-shm-hal: dev_print_timestamp()[515]: [5][0] rx cb end: 1717558158.887334796
	[ 1173.246725] ipc-shm-hal: dev_print_timestamp()[515]: [5][0] rx rd sta: 1717558158.887336446
	[ 1173.246727] ipc-shm-hal: dev_print_timestamp()[515]: [5][0] rx sm sta: 1717558158.887338496
	[ 1173.246729] ipc-shm-hal: dev_print_timestamp()[515]: [5][0] rx sm end: 1717558158.887340121
	[ 1173.246730] ipc-shm-hal: dev_print_timestamp()[515]: [5][0] rx rd end: 1717558158.887341646
	libipcfhal-test: TestBody() [2328] info :
	tsdump: 0

	libipcfhal-test: TestBody() [2329] info :
	tsdump: 0


wdump调试节点
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

以channel为单位，打印发送的数据。

【节点路径】

.. code:: c

	//ins-X表示insid，若insid是5，则为ins-5
	/sys/kernel/debug/ipcdrv-ins-5/wdump

【节点作用】

.. code:: c

	//以channel为单位，使能发送数据dump，打印发送的数据
	//打印的长度取决于dumplen，若未配置dumplen，则默认打印全部
	int32_t wdump;/**< =chan_id, 使能发送dump， 否则, 关闭发送dump*/

【节点使用】

.. code:: c

	//方法一：直接操作sys节点
	//通道完成初始化，未发送数据时, enable
	echo 0 > /sys/kernel/debug/ipcdrv-ins-5/wdump
	//发送数据过程中，会打印发送的数据
	//收发数据结束，且通道未去初始化时，get
	cat /sys/kernel/debug/ipcdrv-ins-5/wdump


	//方法二：使用open/write/read/close操作
	fd= open(/sys/kernel/debug/ipcdrv-ins-5/wdump, O_RDWR);
	write(fd, buf, 1024);
	//tx/rx，打印发送的数据
	read(fd, buf, 1024);
	close(fd);


【log】

.. code:: c

	[ 1022.271650] ipc-shm-hal: hal_ipc_shm_write()[926]: [5][0] tx size 32
	[ 1022.271666] ipc-shm-hal: ipcf_dump_data()[519]: dump info: tx data len[32] mul[1] remain[0]
	[ 1022.271700] ipc-shm-hal: ipcf_dump_data()[522]: 0x0000: 00 01 02 03 04 05 06 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
	[ 1022.273489] ipc-shm-hal: hal_ipc_shm_write()[926]: [6][0] tx size 32
	[ 1022.273505] ipc-shm-hal: ipcf_dump_data()[519]: dump info: tx data len[32] mul[1] remain[0]
	[ 1022.273733] ipc-shm-hal: ipcf_dump_data()[522]: 0x0000: 00 01 02 03 04 05 06 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
	libipcfhal-test: TestBody() [2403] info :
	wdump: 0

	libipcfhal-test: TestBody() [2404] info :
	wdump: 0


rdump调试节点
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

以channel为单位，打印接收的数据。

【节点路径】

.. code:: c

	//ins-X表示insid，若insid是5，则为ins-5
	/sys/kernel/debug/ipcdrv-ins-5/rdump

【节点作用】

.. code:: c

	//以channel为单位，使能接收数据dump，打印接收的数据
	//打印的长度取决于dumplen，若未配置dumplen，则默认打印全部
	uint32_t rdump;/**< =chan_id, 使能接收dump，否则，关闭接收dump*/

【节点使用】

.. code:: c

	//方法一：直接操作sys节点
	//通道完成初始化，未收发数据时, enable
	echo 0 > /sys/kernel/debug/ipcdrv-ins-5/rdump
	//发送数据过程中，会打印接收的数据
	//收发数据结束，且通道未去初始化时，get
	cat /sys/kernel/debug/ipcdrv-ins-5/rdump


	//方法二：使用open/write/read/close操作
	fd= open(/sys/kernel/debug/ipcdrv-ins-5/rdump, O_RDWR);
	write(fd, buf, DEV_README_BUFSIZE);
	//tx/rx，打印接收的数据
	read(fd, buf, DEV_README_BUFSIZE);
	close(fd);


【log】

.. code:: c

	[  983.730497] ipc-shm-hal: data_callback()[803]: [6][0] callback size 32
	[  983.730524] ipc-shm-hal: ipcf_dump_data()[519]: dump info: callback rx len[32] mul[1] remain[0]
	[  983.730540] ipc-shm-hal: ipcf_dump_data()[522]: 0x0000: 00 01 02 03 04 05 06 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
	[  983.731415] ipc-shm-hal: data_callback()[803]: [5][0] callback size 32
	[  983.731431] ipc-shm-hal: ipcf_dump_data()[519]: dump info: callback rx len[32] mul[1] remain[0]
	[  983.731443] ipc-shm-hal: ipcf_dump_data()[522]: 0x0000: 00 01 02 03 04 05 06 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
	libipcfhal-test: TestBody() [2478] info :
	rdump: 0

	libipcfhal-test: TestBody() [2479] info :
	rdump: 0


dumplen调试节点
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

以channel为单位，配置dump数据长度。

【节点路径】

.. code:: c

	//ins-X表示insid，若insid是5，则为ins-5
	/sys/kernel/debug/ipcdrv-ins-5/dumplen

【节点作用】

.. code:: c

	//以channel为单位，配置dump数据的长度
	//dumplen>0且dumplen<data_len时有效
	//前提条件是使能wdump或rdump
	uint32_t dumplen;/**< dump数据时，打印数据的字节数*/

【节点使用】

.. code:: c

	//方法一：直接操作sys节点
	//通道完成初始化，未发送数据时, enable
	echo 0 > /sys/kernel/debug/ipcdrv-ins-5/dumplen
	//发送数据过程中，会打印发送的数据
	//收发数据结束，且通道未去初始化时，get
	cat /sys/kernel/debug/ipcdrv-ins-5/dumplen


	//方法二：使用open/write/read/close操作
	fd= open(/sys/kernel/debug/ipcdrv-ins-5/dumplen, O_RDWR);
	write(fd, buf, DEV_README_BUFSIZE);
	//tx/rx，打印发送的数据
	read(fd, buf, DEV_README_BUFSIZE);
	close(fd);


【log】

.. code:: c

	[  852.898250] ipc-shm-hal: hal_ipc_shm_write()[926]: [5][0] tx size 32
	[  852.898283] ipc-shm-hal: ipcf_dump_data()[519]: dump info: tx data len[16] mul[0] remain[16]
	[  852.898315] ipc-shm-hal: ipcf_dump_data()[539]: 0x0000: 00 01 02 03 04 05 06 07 00 00 00 00 00 00 00 00
	[  852.898519] ipc-shm-hal: data_callback()[803]: [6][0] callback size 32
	[  852.898542] ipc-shm-hal: ipcf_dump_data()[519]: dump info: callback rx len[16] mul[0] remain[16]
	[  852.898571] ipc-shm-hal: ipcf_dump_data()[539]: 0x0000: 00 01 02 03 04 05 06 07 00 00 00 00 00 00 00 00
	[  853.900076] ipc-shm-hal: hal_ipc_shm_write()[926]: [6][0] tx size 32
	[  853.900112] ipc-shm-hal: ipcf_dump_data()[519]: dump info: tx data len[16] mul[0] remain[16]
	[  853.900143] ipc-shm-hal: ipcf_dump_data()[539]: 0x0000: 00 01 02 03 04 05 06 07 00 00 00 00 00 00 00 00
	[  853.900359] ipc-shm-hal: data_callback()[803]: [5][0] callback size 32
	[  853.900373] ipc-shm-hal: ipcf_dump_data()[519]: dump info: callback rx len[16] mul[0] remain[16]
	[  853.900401] ipc-shm-hal: ipcf_dump_data()[539]: 0x0000: 00 01 02 03 04 05 06 07 00 00 00 00 00 00 00 00
	libipcfhal-test: TestBody() [2576] info :
	dumplen: 16

	libipcfhal-test: TestBody() [2577] info :
	dumplen: 16

	libipcfhal-test: TestBody() [2584] info :
	rdump: 0

	libipcfhal-test: TestBody() [2585] info :
	rdump: 0

	libipcfhal-test: TestBody() [2592] info :
	wdump: 0

	libipcfhal-test: TestBody() [2593] info :
	wdump: 0
