207 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			207 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								/* This is a sample demonstration application that showcases usage of rpmsg 
							 | 
						||
| 
								 | 
							
								This application is meant to run on the remote CPU running baremetal code. 
							 | 
						||
| 
								 | 
							
								This application echoes back data that was sent to it by the master core. */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <stdio.h>
							 | 
						||
| 
								 | 
							
								#include <stdlib.h>
							 | 
						||
| 
								 | 
							
								#include <string.h>
							 | 
						||
| 
								 | 
							
								#include <unistd.h>
							 | 
						||
| 
								 | 
							
								#include <openamp/open_amp.h>
							 | 
						||
| 
								 | 
							
								#include <metal/alloc.h>
							 | 
						||
| 
								 | 
							
								#include "platform_info.h"
							 | 
						||
| 
								 | 
							
								#include "rpmsg-ping.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define APP_EPT_ADDR    0
							 | 
						||
| 
								 | 
							
								#define LPRINTF(format, ...) printf(format, ##__VA_ARGS__)
							 | 
						||
| 
								 | 
							
								#define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								struct _payload {
							 | 
						||
| 
								 | 
							
									unsigned long num;
							 | 
						||
| 
								 | 
							
									unsigned long size;
							 | 
						||
| 
								 | 
							
									unsigned char data[];
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int err_cnt;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define PAYLOAD_MIN_SIZE	1
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* Globals */
							 | 
						||
| 
								 | 
							
								static struct rpmsg_endpoint lept;
							 | 
						||
| 
								 | 
							
								static struct _payload *i_payload;
							 | 
						||
| 
								 | 
							
								static int rnum = 0;
							 | 
						||
| 
								 | 
							
								static int err_cnt = 0;
							 | 
						||
| 
								 | 
							
								static int ept_deleted = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* External functions */
							 | 
						||
| 
								 | 
							
								extern int init_system();
							 | 
						||
| 
								 | 
							
								extern void cleanup_system();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*-----------------------------------------------------------------------------*
							 | 
						||
| 
								 | 
							
								 *  RPMSG endpoint callbacks
							 | 
						||
| 
								 | 
							
								 *-----------------------------------------------------------------------------*/
							 | 
						||
| 
								 | 
							
								static int rpmsg_endpoint_cb(struct rpmsg_endpoint *ept, void *data, size_t len,
							 | 
						||
| 
								 | 
							
											     uint32_t src, void *priv)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									int i;
							 | 
						||
| 
								 | 
							
									struct _payload *r_payload = (struct _payload *)data;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									(void)ept;
							 | 
						||
| 
								 | 
							
									(void)src;
							 | 
						||
| 
								 | 
							
									(void)priv;
							 | 
						||
| 
								 | 
							
									LPRINTF(" received payload number %lu of size %lu \r\n",
							 | 
						||
| 
								 | 
							
										r_payload->num, (unsigned long)len);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (r_payload->size == 0) {
							 | 
						||
| 
								 | 
							
										LPERROR(" Invalid size of package is received.\n");
							 | 
						||
| 
								 | 
							
										err_cnt++;
							 | 
						||
| 
								 | 
							
										return RPMSG_SUCCESS;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									/* Validate data buffer integrity. */
							 | 
						||
| 
								 | 
							
									for (i = 0; i < (int)r_payload->size; i++) {
							 | 
						||
| 
								 | 
							
										if (r_payload->data[i] != 0xA5) {
							 | 
						||
| 
								 | 
							
											LPRINTF("Data corruption at index %d\n", i);
							 | 
						||
| 
								 | 
							
											err_cnt++;
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									rnum = r_payload->num + 1;
							 | 
						||
| 
								 | 
							
									return RPMSG_SUCCESS;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void rpmsg_service_unbind(struct rpmsg_endpoint *ept)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									(void)ept;
							 | 
						||
| 
								 | 
							
									rpmsg_destroy_ept(&lept);
							 | 
						||
| 
								 | 
							
									LPRINTF("echo test: service is destroyed\n");
							 | 
						||
| 
								 | 
							
									ept_deleted = 1;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void rpmsg_name_service_bind_cb(struct rpmsg_device *rdev,
							 | 
						||
| 
								 | 
							
												       const char *name, uint32_t dest)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									LPRINTF("new endpoint notification is received.\n");
							 | 
						||
| 
								 | 
							
									if (strcmp(name, RPMSG_SERVICE_NAME))
							 | 
						||
| 
								 | 
							
										LPERROR("Unexpected name service %s.\n", name);
							 | 
						||
| 
								 | 
							
									else
							 | 
						||
| 
								 | 
							
										(void)rpmsg_create_ept(&lept, rdev, RPMSG_SERVICE_NAME,
							 | 
						||
| 
								 | 
							
												       APP_EPT_ADDR, dest,
							 | 
						||
| 
								 | 
							
												       rpmsg_endpoint_cb,
							 | 
						||
| 
								 | 
							
												       rpmsg_service_unbind);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*-----------------------------------------------------------------------------*
							 | 
						||
| 
								 | 
							
								 *  Application
							 | 
						||
| 
								 | 
							
								 *-----------------------------------------------------------------------------*/
							 | 
						||
| 
								 | 
							
								int app (struct rpmsg_device *rdev, void *priv)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									int ret;
							 | 
						||
| 
								 | 
							
									int i;
							 | 
						||
| 
								 | 
							
									int size, max_size, num_payloads;
							 | 
						||
| 
								 | 
							
									int expect_rnum = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									LPRINTF(" 1 - Send data to remote core, retrieve the echo");
							 | 
						||
| 
								 | 
							
									LPRINTF(" and validate its integrity ..\n");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									max_size = rpmsg_virtio_get_buffer_size(rdev);
							 | 
						||
| 
								 | 
							
									if (max_size < 0) {
							 | 
						||
| 
								 | 
							
										LPERROR("No avaiable buffer size.\n");
							 | 
						||
| 
								 | 
							
										return -1;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									max_size -= sizeof(struct _payload);
							 | 
						||
| 
								 | 
							
									num_payloads = max_size - PAYLOAD_MIN_SIZE + 1;
							 | 
						||
| 
								 | 
							
									i_payload =
							 | 
						||
| 
								 | 
							
									    (struct _payload *)metal_allocate_memory(2 * sizeof(unsigned long) +
							 | 
						||
| 
								 | 
							
												      max_size);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (!i_payload) {
							 | 
						||
| 
								 | 
							
										LPERROR("memory allocation failed.\n");
							 | 
						||
| 
								 | 
							
										return -1;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* Create RPMsg endpoint */
							 | 
						||
| 
								 | 
							
									ret = rpmsg_create_ept(&lept, rdev, RPMSG_SERVICE_NAME, APP_EPT_ADDR,
							 | 
						||
| 
								 | 
							
											       RPMSG_ADDR_ANY,
							 | 
						||
| 
								 | 
							
											       rpmsg_endpoint_cb, rpmsg_service_unbind);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (ret) {
							 | 
						||
| 
								 | 
							
										LPERROR("Failed to create RPMsg endpoint.\n");
							 | 
						||
| 
								 | 
							
										return ret;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									while (!is_rpmsg_ept_ready(&lept))
							 | 
						||
| 
								 | 
							
										platform_poll(priv);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									LPRINTF("RPMSG endpoint is binded with remote.\n");
							 | 
						||
| 
								 | 
							
									for (i = 0, size = PAYLOAD_MIN_SIZE; i < num_payloads; i++, size++) {
							 | 
						||
| 
								 | 
							
										i_payload->num = i;
							 | 
						||
| 
								 | 
							
										i_payload->size = size;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/* Mark the data buffer. */
							 | 
						||
| 
								 | 
							
										memset(&(i_payload->data[0]), 0xA5, size);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										LPRINTF("sending payload number %lu of size %lu\n",
							 | 
						||
| 
								 | 
							
											i_payload->num,
							 | 
						||
| 
								 | 
							
											(unsigned long)(2 * sizeof(unsigned long)) + size);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										ret = rpmsg_send(&lept, i_payload,
							 | 
						||
| 
								 | 
							
												 (2 * sizeof(unsigned long)) + size);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (ret < 0) {
							 | 
						||
| 
								 | 
							
											LPERROR("Failed to send data...\n");
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										LPRINTF("echo test: sent : %lu\n",
							 | 
						||
| 
								 | 
							
											(unsigned long)(2 * sizeof(unsigned long)) + size);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										expect_rnum++;
							 | 
						||
| 
								 | 
							
										do {
							 | 
						||
| 
								 | 
							
											platform_poll(priv);
							 | 
						||
| 
								 | 
							
										} while ((rnum < expect_rnum) && !err_cnt && !ept_deleted);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									LPRINTF("**********************************\n");
							 | 
						||
| 
								 | 
							
									LPRINTF(" Test Results: Error count = %d \n", err_cnt);
							 | 
						||
| 
								 | 
							
									LPRINTF("**********************************\n");
							 | 
						||
| 
								 | 
							
									/* Destroy the RPMsg endpoint */
							 | 
						||
| 
								 | 
							
									rpmsg_destroy_ept(&lept);
							 | 
						||
| 
								 | 
							
									LPRINTF("Quitting application .. Echo test end\n");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									metal_free_memory(i_payload);
							 | 
						||
| 
								 | 
							
									return 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int main(int argc, char *argv[])
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									void *platform;
							 | 
						||
| 
								 | 
							
									struct rpmsg_device *rpdev;
							 | 
						||
| 
								 | 
							
									int ret;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* Initialize platform */
							 | 
						||
| 
								 | 
							
									ret = platform_init(argc, argv, &platform);
							 | 
						||
| 
								 | 
							
									if (ret) {
							 | 
						||
| 
								 | 
							
										LPERROR("Failed to initialize platform.\n");
							 | 
						||
| 
								 | 
							
										ret = -1;
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
										rpdev = platform_create_rpmsg_vdev(platform, 0,
							 | 
						||
| 
								 | 
							
														  VIRTIO_DEV_MASTER,
							 | 
						||
| 
								 | 
							
														  NULL,
							 | 
						||
| 
								 | 
							
														  rpmsg_name_service_bind_cb);
							 | 
						||
| 
								 | 
							
										if (!rpdev) {
							 | 
						||
| 
								 | 
							
											LPERROR("Failed to create rpmsg virtio device.\n");
							 | 
						||
| 
								 | 
							
											ret = -1;
							 | 
						||
| 
								 | 
							
										} else {
							 | 
						||
| 
								 | 
							
											app(rpdev, platform);
							 | 
						||
| 
								 | 
							
											platform_release_rpmsg_vdev(rpdev);
							 | 
						||
| 
								 | 
							
											ret = 0;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									LPRINTF("Stopping application...\n");
							 | 
						||
| 
								 | 
							
									platform_cleanup(platform);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return ret;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 |