incubator-nuttx/drivers/rpmsg/rpmsg_ping.c

265 lines
6.8 KiB
C

/****************************************************************************
* drivers/rpmsg/rpmsg_ping.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/arch.h>
#include <nuttx/signal.h>
#include <inttypes.h>
#include <string.h>
#include <sys/param.h>
#include <time.h>
#include <syslog.h>
#include "rpmsg_ping.h"
/****************************************************************************
* Pre-processor definitions
****************************************************************************/
#define RPMSG_PING_EPT_NAME "rpmsg-ping"
#define RPMSG_PING_SEND 1
#define RPMSG_PING_SEND_CHECK 2
#define RPMSG_PING_SEND_NOACK 3
#define RPMSG_PING_SEND_ACK 4
#define RPMSG_PING_ACK 5
#define RPMSG_PING_CHECK_DATA 0xee
/****************************************************************************
* Private Types
****************************************************************************/
begin_packed_struct struct rpmsg_ping_msg_s
{
uint32_t cmd;
uint32_t len;
uint64_t cookie;
uint8_t data[1];
} end_packed_struct;
/****************************************************************************
* Private Functions
****************************************************************************/
static int rpmsg_ping_ept_cb(FAR struct rpmsg_endpoint *ept,
FAR void *data, size_t len, uint32_t src,
FAR void *priv)
{
FAR struct rpmsg_ping_msg_s *msg = data;
FAR sem_t *sem = (FAR sem_t *)(uintptr_t)msg->cookie;
if (msg->cmd == RPMSG_PING_SEND)
{
msg->cmd = RPMSG_PING_ACK;
rpmsg_send(ept, msg, len);
}
else if (msg->cmd == RPMSG_PING_SEND_CHECK)
{
size_t data_len;
size_t i;
data_len = msg->len - sizeof(struct rpmsg_ping_msg_s) + 1;
for (i = 0; i < data_len; i++)
{
if (msg->data[i] != RPMSG_PING_CHECK_DATA)
{
syslog(LOG_ERR, "receive data error at %zu of %zu\n",
i, data_len);
break;
}
msg->data[i] = 0;
}
msg->cmd = RPMSG_PING_ACK;
rpmsg_send(ept, msg, len);
}
else if (msg->cmd == RPMSG_PING_SEND_ACK)
{
msg->cmd = RPMSG_PING_ACK;
rpmsg_send(ept, msg, sizeof(*msg));
}
else if (msg->cmd == RPMSG_PING_ACK)
{
nxsem_post(sem);
}
return 0;
}
static int rpmsg_ping_once(FAR struct rpmsg_endpoint *ept,
int len, int ack, uint32_t *buf_len)
{
FAR struct rpmsg_ping_msg_s *msg;
int ret;
msg = rpmsg_get_tx_payload_buffer(ept, buf_len, true);
if (!msg)
{
return -ENOMEM;
}
len = MAX(len, sizeof(struct rpmsg_ping_msg_s));
len = MIN(len, *buf_len);
memset(msg, 0, len);
if (ack)
{
sem_t sem;
if (ack == 1)
{
msg->cmd = RPMSG_PING_SEND;
}
else if (ack == 2)
{
msg->cmd = RPMSG_PING_SEND_CHECK;
}
else
{
msg->cmd = RPMSG_PING_SEND_ACK;
}
msg->len = len;
msg->cookie = (uintptr_t)&sem;
if (msg->cmd == RPMSG_PING_SEND_CHECK)
{
memset(msg->data, RPMSG_PING_CHECK_DATA,
len - sizeof(struct rpmsg_ping_msg_s) + 1);
}
nxsem_init(&sem, 0, 0);
ret = rpmsg_send_nocopy(ept, msg, len);
if (ret >= 0)
{
nxsem_wait_uninterruptible(&sem);
}
nxsem_destroy(&sem);
}
else
{
msg->cmd = RPMSG_PING_SEND_NOACK;
msg->len = len;
ret = rpmsg_send_nocopy(ept, msg, len);
}
return ret;
}
static void rpmsg_ping_logout(FAR const char *s, clock_t value)
{
struct timespec ts;
perf_convert(value, &ts);
#ifdef CONFIG_SYSTEM_TIME64
syslog(LOG_INFO, "%s: %" PRIu64 " s, %ld ns\n", s, ts.tv_sec, ts.tv_nsec);
#else
syslog(LOG_INFO, "%s: %" PRIu32 " s, %ld ns\n", s, ts.tv_sec, ts.tv_nsec);
#endif
}
static void rpmsg_ping_logout_rate(uint64_t len, clock_t avg)
{
struct timespec ts;
size_t ratebits;
size_t rateint;
size_t ratedec;
perf_convert(avg, &ts);
ratebits = len * 8 * 1000000000 / (ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec);
rateint = ratebits / 1000000;
ratedec = ratebits - rateint * 1000000;
syslog(LOG_INFO, "rate: %zu.%06zu Mbits/sec\n", rateint, ratedec);
}
/****************************************************************************
* Public Functions
****************************************************************************/
int rpmsg_ping(FAR struct rpmsg_endpoint *ept,
FAR const struct rpmsg_ping_s *ping)
{
clock_t min = CLOCK_MAX;
clock_t max = 0;
uint64_t total = 0;
uint32_t buf_len = 0;
int send_len = 0;
int i;
if (!ept || !ping || ping->times <= 0)
{
return -EINVAL;
}
for (i = 0; i < ping->times; i++)
{
clock_t tm = perf_gettime();
send_len = rpmsg_ping_once(ept, ping->len, ping->ack, &buf_len);
if (send_len < 0)
{
return send_len;
}
tm = perf_gettime() - tm;
min = MIN(min, tm);
max = MAX(max, tm);
total += tm;
if (ping->sleep > 0)
{
nxsig_usleep(ping->sleep * USEC_PER_MSEC);
}
}
syslog(LOG_INFO, "ping times: %d\n", ping->times);
rpmsg_ping_logout("avg", total / ping->times);
rpmsg_ping_logout("min", min);
rpmsg_ping_logout("max", max);
rpmsg_ping_logout_rate(send_len, total / ping->times);
return 0;
}
int rpmsg_ping_init(FAR struct rpmsg_device *rdev,
FAR struct rpmsg_endpoint *ept)
{
return rpmsg_create_ept(ept, rdev, RPMSG_PING_EPT_NAME,
RPMSG_ADDR_ANY, RPMSG_ADDR_ANY,
rpmsg_ping_ept_cb, NULL);
}
void rpmsg_ping_deinit(FAR struct rpmsg_endpoint *ept)
{
rpmsg_destroy_ept(ept);
}