Commit 80b47ffe authored by Alessandro Rubini's avatar Alessandro Rubini

use libminipc/ instead of libwripc/

parent 8de7f894
......@@ -33,14 +33,14 @@ CFLAGS += $(shell ./check-endian $(CC))
# Flags for standalone compilation
TOPDIR=$(shell /bin/pwd)
CFLAGS += -Wall -ggdb -I$(TOPDIR)/wrsw_hal -I$(TOPDIR)/libwripc \
CFLAGS += -Wall -ggdb -I$(TOPDIR)/wrsw_hal -I$(TOPDIR)/libminipc \
-I$(TOPDIR)/libptpnetif -I$(TOPDIR)/PTPWRd -I$(LINUX)/include \
-include compat.h -include libposix/ptpd-wrappers.h
# These are lifted in the ptp.o temporary object file, for me to see the size
CORELIBS = libwripc.a libptpnetif.a
CORELIBS = libptpnetif.a libminipc.a
LDFLAGS = #-L. -lwripc -lptpnetif
LDFLAGS = #-L. -lminipc -lptpnetif
# Flags from the original Makefiles
......@@ -94,7 +94,8 @@ check:
libs: check $(CORELIBS)
libwripc.a: libwripc/wr_ipc.o libwripc/helper_arm.o
libminipc.a: libminipc/minipc-core.o \
libminipc/minipc-server.o libminipc/minipc-client.o
$(AR) r $@ $^
libptpnetif.a: libptpnetif/hal_client.o libptpnetif/ptpd_netif.o
......
#ifdef __STDC_HOSTED__
#include <string.h>
#include <wr_ipc.h>
#include <minipc.h>
#include "ptpd.h"
#define PTP_EXPORT_STRUCTURES
#include "ptpd_exports.h"
extern int servo_state_valid;
extern ptpdexp_sync_state_t cur_servo_state;
void ptpdexp_get_sync_state(ptpdexp_sync_state_t *state)
int ptpdexp_get_sync_state(ptpdexp_sync_state_t *state)
{
if(servo_state_valid)
{
......@@ -17,9 +19,10 @@ void ptpdexp_get_sync_state(ptpdexp_sync_state_t *state)
state->valid = 1;
} else
state->valid = 0;
return 0;
}
void ptpdexp_cmd(int cmd, int value)
int ptpdexp_cmd(int cmd, int value)
{
if(cmd == PTPDEXP_COMMAND_TRACKING)
......@@ -27,23 +30,49 @@ void ptpdexp_cmd(int cmd, int value)
if(cmd == PTPDEXP_COMMAND_MAN_ADJUST_PHASE)
wr_servo_man_adjust_phase(value);
return 0;
}
static wripc_handle_t wripc_srv;
/* Two functions to manage packet/args conversions */
static int export_get_sync_state(const struct minipc_pd *pd,
uint32_t *args, void *ret)
{
ptpdexp_sync_state_t state;
ptpdexp_get_sync_state(&state);
*(ptpdexp_sync_state_t *)ret = state;
return 0;
void ptpd_init_exports()
}
static int export_cmd(const struct minipc_pd *pd,
uint32_t *args, void *ret)
{
wripc_srv = wripc_create_server("ptpd");
int i;
i = ptpdexp_cmd(args[0], args[1]);
*(int *)ret = i;
return 0;
}
static struct minipc_ch *ptp_ch;
void ptpd_init_exports(void)
{
ptp_ch = minipc_server_create("ptpd", 0);
__rpcdef_get_sync_state.f = export_get_sync_state;
__rpcdef_cmd.f = export_cmd;
wripc_export(wripc_srv, T_STRUCT(ptpdexp_sync_state_t), "ptpdexp_get_sync_state", ptpdexp_get_sync_state, 0);
wripc_export(wripc_srv, T_VOID, "ptpdexp_cmd", ptpdexp_cmd, 2, T_INT32, T_INT32);
minipc_export(ptp_ch, &__rpcdef_get_sync_state);
minipc_export(ptp_ch, &__rpcdef_cmd);
}
void ptpd_handle_wripc()
{
// fprintf(stderr, ".");
wripc_process(wripc_srv);
minipc_server_action(ptp_ch, 200 /* ms */);
}
#endif
......@@ -27,7 +27,32 @@ typedef struct{
#define PTPDEXP_COMMAND_TRACKING 1
#define PTPDEXP_COMMAND_MAN_ADJUST_PHASE 2
void ptpdexp_get_sync_state(ptpdexp_sync_state_t *state);
void ptpdexp_cmd(int cmd, int value);
extern int ptpdexp_get_sync_state(ptpdexp_sync_state_t *state);
extern int ptpdexp_cmd(int cmd, int value);
/* Export structures, shared by server and client for argument matching */
#ifdef PTP_EXPORT_STRUCTURES
//int ptpdexp_get_sync_state(ptpdexp_sync_state_t *state);
struct minipc_pd __rpcdef_get_sync_state = {
.name = "get_sync_state",
.retval = MINIPC_ARG_ENCODE(MINIPC_ATYPE_STRUCT, ptpdexp_sync_state_t),
.args = {
MINIPC_ARG_END,
},
};
//int ptpdexp_cmd(int cmd, int value);
struct minipc_pd __rpcdef_cmd = {
.name = "cmd",
.retval = MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
.args = {
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
MINIPC_ARG_END,
},
};
#endif /* PTP_EXPORT_STRUCTURES */
#endif
/*
* Mini-ipc: Exported functions for client operation
*
* Copyright (C) 2011 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
* Based on ideas by Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <poll.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "minipc-int.h"
struct minipc_ch *minipc_client_create(const char *name, int f)
{
return __minipc_link_create(name, MPC_USER_FLAGS(f) | MPC_FLAG_CLIENT);
}
int minipc_call(struct minipc_ch *ch, int millisec_timeout,
const struct minipc_pd *pd, void *ret, ...)
{
struct mpc_link *link = mpc_get_link(ch);
struct mpc_shmem *shm = link->memaddr;
struct pollfd pfd;
int i, narg, size, retsize, pollnr;
int atype, asize;
va_list ap;
struct mpc_req_packet *p_out, _pkt_out = {"",};
struct mpc_rep_packet *p_in, _pkt_in;
CHECK_LINK(link);
if (shm) {
p_out = &shm->request;
p_in = &shm->reply;
} else {
p_out = & _pkt_out;
p_in = & _pkt_in;
}
/* Build the packet to send out -- marshall args */
if (link->logf) {
fprintf(link->logf, "%s: calling \"%s\"\n",
__func__, pd->name);
}
memcpy(p_out->name, pd->name, MINIPC_MAX_NAME);
va_start(ap, ret);
for (i = narg = 0; ; i++) {
int next_narg = narg;
atype = MINIPC_GET_ATYPE(pd->args[i]);
asize = MINIPC_GET_ASIZE(pd->args[i]);
next_narg += MINIPC_GET_ANUM(asize);
if (next_narg >= MINIPC_MAX_ARGUMENTS) /* unlikely */
goto doesnt_fit;
switch (atype) {
case MINIPC_ATYPE_NONE:
goto out; /* end of list */
case MINIPC_ATYPE_INT:
p_out->args[narg++] = va_arg(ap, int);
break;
case MINIPC_ATYPE_INT64:
*(uint64_t *)(p_out->args + narg)
= va_arg(ap, uint64_t);
narg = next_narg;
break;
case MINIPC_ATYPE_DOUBLE:
*(double *)(p_out->args + narg) = va_arg(ap, double);
narg = next_narg;
break;
case MINIPC_ATYPE_STRING:
{
char *sin = va_arg(ap, void *);
char *sout = (void *)(p_out->args + narg);
int slen = strlen(sin);
int alen;
/*
* argument len is arbitrary, terminate and 4-align
* we can't use next_narg here, as len changes
*/
alen = MINIPC_GET_ANUM(slen + 1);
if (narg + alen >= MINIPC_MAX_ARGUMENTS)
goto doesnt_fit;
strcpy(sout, sin);
narg += alen;
break;
}
case MINIPC_ATYPE_STRUCT:
memcpy(p_out->args + narg, va_arg(ap, void *), asize);
narg = next_narg;
break;
default:
if (link->logf) {
fprintf(link->logf, "%s: unkown type 0x%x\n",
__func__, atype);
}
errno = EPROTO;
return -1;
}
}
out:
va_end(ap);
if (shm) {
shm->nrequest++;
} else {
size = sizeof(p_out->name) + sizeof(p_out->args[0]) * narg;
if (send(ch->fd, p_out, size, 0) < 0) {
/* errno already set */
return -1;
}
}
/* Wait for the reply packet */
pfd.fd = ch->fd;
pfd.events = POLLIN | POLLHUP;
pfd.revents = 0;
pollnr = poll(&pfd, 1, millisec_timeout);
if (pollnr < 0) {
/* errno already set */
return -1;
}
if (pollnr == 0) {
errno = ETIMEDOUT;
return -1;
}
if (shm) {
read(ch->fd, &i, 1);
size = retsize = sizeof(shm->reply);
} else {
/* this "size" is wrong for strings, so recv the max size */
size = MINIPC_GET_ASIZE(pd->retval) + sizeof(uint32_t);
retsize = recv(ch->fd, p_in, sizeof(*p_in), 0);
}
/* if very short, we have a problem */
if (retsize < (sizeof(p_in->type)) + sizeof(int))
goto too_short;
/* remote error reported */
if (MINIPC_GET_ATYPE(p_in->type) == MINIPC_ATYPE_ERROR) {
int remoteerr = *(int *)&p_in->val;
if (link->logf) {
fprintf(link->logf, "%s: remote error \"%s\"\n",
__func__, strerror(remoteerr));
}
*(int *)ret = remoteerr;
errno = EREMOTEIO;
return -1;
}
/* another check: the return type must match */
if (MINIPC_GET_ATYPE(p_in->type) != MINIPC_GET_ATYPE(pd->retval)) {
if (link->logf) {
fprintf(link->logf, "%s: wrong code %08x (not %08x)\n",
__func__, p_in->type, pd->retval);
}
errno = EPROTO;
return -1;
}
/* check size */
if (retsize < size)
goto too_short;
/* all good */
memcpy(ret, &p_in->val, MINIPC_GET_ASIZE(p_in->type));
return 0;
too_short:
if (link->logf) {
fprintf(link->logf, "%s: short reply (%i bytes)\n",
__func__, retsize);
}
errno = EPROTO;
return -1;
doesnt_fit:
if (link->logf) {
fprintf(link->logf, "%s: rpc call \"%s\" won't fit %i slots\n",
__func__, pd->name, MINIPC_MAX_ARGUMENTS);
}
errno = EPROTO;
return -1;
}
/*
* Mini-ipc: Core library functions and data
*
* Copyright (C) 2011 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
* Based on ideas by Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/shm.h>
#include "minipc-int.h"
struct mpc_link *__mpc_base;
static int __mpc_poll_usec = MINIPC_DEFAULT_POLL;
void mpc_free_flist(struct mpc_link *link, struct mpc_flist *flist)
{
struct mpc_flist **nextp;
/* Look for flist and release it*/
for (nextp = &link->flist; (*nextp); nextp = &(*nextp)->next)
if (*nextp == flist)
break;
if (!*nextp) {
if (link->logf)
fprintf(link->logf, "%s: function not found %p (%s)\n",
__func__, flist, flist->pd->name);
return;
}
*nextp = flist->next;
fprintf(link->logf, "%s: unexported function %p (%s)\n",
__func__, flist->pd->f, flist->pd->name);
free(flist);
}
int minipc_close(struct minipc_ch *ch)
{
struct mpc_link *link = mpc_get_link(ch);
struct mpc_link **nextp;
CHECK_LINK(link);
/* Look for link in our list */
for (nextp = &__mpc_base; (*nextp); nextp = &(*nextp)->nextl)
if (*nextp == link)
break;
if (!*nextp) {
errno = ENOENT;
return -1;
}
(*nextp)->nextl = link->nextl;
if (link->logf) {
fprintf(link->logf, "%s: found link %p (fd %i)\n",
__func__, link, link->ch.fd);
}
close(ch->fd);
if (link->pid)
kill(link->pid, SIGINT);
if (link->flags & MPC_FLAG_SHMEM)
shmdt(link->memaddr);
if (link->flags & MPC_FLAG_DEVMEM)
munmap(link->memaddr, link->memsize);
/* Release allocated functions */
while (link->flist)
mpc_free_flist(link, link->flist);
free(link);
return 0;
}
int minipc_set_poll(int usec)
{
int ret = __mpc_poll_usec;
if (usec <= 0) {
errno = EINVAL;
return -1;
}
__mpc_poll_usec = usec;
return ret;
}
int minipc_set_logfile(struct minipc_ch *ch, FILE *logf)
{
struct mpc_link *link = mpc_get_link(ch);
CHECK_LINK(link);
link->logf = logf;
return 0;
}
/* the child for memory-based channels just polls */
void __minipc_child(void *addr, int fd, int flags)
{
int i;
uint32_t prev, *vptr;
struct mpc_shmem *shm = addr;
for (i = 0; i < 256; i++)
if (i != fd) close(i);
/* check the parent: if it changes, then we exit */
i = getppid();
/* the process must only send one byte when the value changes */
if (flags & MPC_FLAG_SERVER)
vptr = &shm->nrequest;
else
vptr = &shm->nreply;
prev = *vptr;
/* Ok, unlock the parent: we are ready */
write(fd, "-", 1);
while (1) {
if (*vptr != prev) {
write(fd, "", 1);
prev++;
}
if (getppid() != i)
exit(0);
usleep(__mpc_poll_usec);
}
}
/* helper function for memory-based channels */
static struct mpc_link *__minipc_memlink_create(struct mpc_link *link)
{
void *addr;
long offset;
int memsize, pid, ret;
int pagesize = getpagesize();
int pfd[2];
char msg;
memsize = (sizeof(struct mpc_shmem) + pagesize - 1) & ~pagesize;
/* Warning: no check for trailing garbage in name */
if (sscanf(link->name, "shm:%li", &offset)) {
ret = shmget(offset, memsize, IPC_CREAT | 0666);
if (ret < 0)
return NULL;
addr = shmat(ret, NULL, SHM_RND);
if (addr == (void *)-1)
return NULL;
link->flags |= MPC_FLAG_SHMEM;
}
/* Warning: no check for trailing garbage in name -- hex mandatory */
if (sscanf(link->name, "mem:%lx", &offset)) {
int fd = open("/dev/mem", O_RDWR | O_SYNC);
if (fd < 0)
return NULL;
addr = mmap(0, memsize, PROT_READ | PROT_WRITE, MAP_SHARED,
fd, offset);
close(fd);
if (addr == (MAP_FAILED))
return NULL;
link->flags |= MPC_FLAG_DEVMEM;
}
link->memaddr = addr;
link->memsize = memsize;
if (link->flags & MPC_FLAG_SERVER)
memset(addr, 0, sizeof(struct mpc_shmem));
/* fork a polling process */
if (pipe(pfd) < 0)
goto err_unmap;
switch ( (pid = fork()) ) {
case 0: /* child */
close(pfd[0]);
__minipc_child(addr, pfd[1], link->flags);
exit(1);
default: /* father */
close(pfd[1]);
link->ch.fd = pfd[0];
link->pid = pid;
/* Before operating, wait for the child to ping us */
read (pfd[0], &msg, 1); /* must be '-' ... check? */
return link;
case -1:
break; /* error... */
}
close(pfd[0]);
close(pfd[1]);
err_unmap:
if (link->flags & MPC_FLAG_SHMEM)
shmdt(link->memaddr);
if (link->flags & MPC_FLAG_DEVMEM)
munmap(link->memaddr, link->memsize);
return NULL;
}
/* create a link, either server or client */
struct minipc_ch *__minipc_link_create(const char *name, int flags)
{
struct mpc_link *link, *next;
struct sockaddr_un sun;
int fd, i;
link = calloc(1, sizeof(*link));
if (!link) return NULL;
link->magic = MPC_MAGIC;
link->flags = flags;
strncpy(link->name, name, sizeof(link->name) -1);
/* special-case the memory-based channels */
if (!strncmp(name, "shm:", 4) || !strncmp(name, "mem:", 4)) {
if (!__minipc_memlink_create(link))
goto out_free;
goto out_success;
}
/* now create the socket and prepare the service */
fd = socket(SOCK_STREAM, AF_UNIX, 0);
if(fd < 0)
goto out_free;
link->ch.fd = fd;
sun.sun_family = AF_UNIX;
strcpy(sun.sun_path, MINIPC_BASE_PATH);
strcat(sun.sun_path, "/");
strcat(sun.sun_path, link->name);
mkdir(MINIPC_BASE_PATH, 0777); /* may exist, ignore errors */
if (flags & MPC_FLAG_SERVER) {
unlink(sun.sun_path);
if (bind (fd, (struct sockaddr *)&sun, sizeof(sun)) < 0)
goto out_close;
if (listen(fd, 5) < 0)
goto out_close;
} else { /* client */
if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) < 0)
goto out_close;
}
/* success: fix your fd values, link to the list and return */
out_success:
if (flags & MPC_FLAG_SERVER) {
for (i = 0; i < MINIPC_MAX_CLIENTS; i++)
link->fd[i] = -1;
FD_ZERO(&link->fdset);
FD_SET(link->ch.fd, &link->fdset);
}
link->addr = sun;
next = __mpc_base;
link->nextl = __mpc_base;
__mpc_base = link;
return &link->ch;
out_close:
close(fd);
out_free:
free(link);
return NULL;
}
/*
* Private definition for mini-ipc
*
* Copyright (C) 2011 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
* Based on ideas by Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef __MINIPC_INT_H__
#define __MINIPC_INT_H__
#include <sys/types.h>
#if __STDC_HOSTED__ /* freestanding servers have less material */
#include <sys/un.h>
#include <sys/select.h>
#endif
#include "minipc.h"
/* be safe, in case some other header had them slightly differntly */
#undef container_of
#undef offsetof
#undef ARRAY_SIZE
/* We are strongly based on container_of internally */
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
/*
* While public symbols are minipc_* internal ones are mpc_* to be shorter.
* The connection includes an fd, which is the only thing returned back
*/
/* The list of functions attached to a service */
struct mpc_flist {
const struct minipc_pd *pd;
struct mpc_flist *next;
};
/*
* The main server or client structure. Server links have client sockets
* hooking on it.
*/
struct mpc_link {
struct minipc_ch ch;
int magic;
int pid;
int flags;
struct mpc_link *nextl;
struct mpc_flist *flist;
void *memaddr;
int memsize;
#if __STDC_HOSTED__ /* these fields are not used in freestanding uC */
FILE *logf;
struct sockaddr_un addr;
int fd[MINIPC_MAX_CLIENTS];
fd_set fdset;
#endif
char name[MINIPC_MAX_NAME];
};
#define MPC_MAGIC 0xc0ffee99
#define MPC_FLAG_SERVER 0x00010000
#define MPC_FLAG_CLIENT 0x00020000
#define MPC_FLAG_SHMEM 0x00040000
#define MPC_FLAG_DEVMEM 0x00080000
#define MPC_USER_FLAGS(x) ((x) & 0xffff)
/* The request packet being transferred */
struct mpc_req_packet {
char name[MINIPC_MAX_NAME];
uint32_t args[MINIPC_MAX_ARGUMENTS];
};
/* The reply packet being transferred */
struct mpc_rep_packet {
uint32_t type;
uint8_t val[MINIPC_MAX_REPLY];
};
/* A structure for shared memory (takes more than 2kB) */
struct mpc_shmem {
uint32_t nrequest; /* incremented at each request */
uint32_t nreply; /* incremented at each reply */
struct mpc_req_packet request;
struct mpc_rep_packet reply;
};
#define MPC_TIMEOUT 1000 /* msec, hardwired */
static inline struct mpc_link *mpc_get_link(struct minipc_ch *ch)
{
return container_of(ch, struct mpc_link, ch);
}
#define CHECK_LINK(link) /* Horrible shortcut, don't tell around... */ \
if ((link)->magic != MPC_MAGIC) { \
errno = EINVAL; \
return -1; \
}
extern struct mpc_link *__mpc_base;
extern void mpc_free_flist(struct mpc_link *link, struct mpc_flist *flist);
extern struct minipc_ch *__minipc_link_create(const char *name, int flags);
/* Used for lists and structures -- sizeof(uint32_t) is 4, is it? */
#define MINIPC_GET_ANUM(len) (((len) + 3) >> 2)
#endif /* __MINIPC_INT_H__ */
/*
* Mini-ipc: Exported functions for server operation
*
* Copyright (C) 2011 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
* Based on ideas and code by Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/select.h>
#include "minipc-int.h"
/*
* This function creates a server structure and links it to the
* process-wide list of links
*/
struct minipc_ch *minipc_server_create(const char *name, int f)
{
return __minipc_link_create(name, MPC_USER_FLAGS(f) | MPC_FLAG_SERVER);
}
/*
* The following ones add to the export list and remove from it
*/
int minipc_export(struct minipc_ch *ch, const struct minipc_pd *pd)
{
struct mpc_link *link = mpc_get_link(ch);
struct mpc_flist *flist;
CHECK_LINK(link);
flist = calloc(1, sizeof(*flist));
if (!flist)
return -1;
flist->pd = pd;
flist->next = link->flist;
link->flist = flist;
if (link->logf)
fprintf(link->logf, "%s: exported %p (%s) with pd %p --"
" retval %08x, args %08x...\n", __func__,
flist, pd->name, pd, pd->retval, pd->args[0]);
return 0;
}
int minipc_unexport(struct minipc_ch *ch, const struct minipc_pd *pd)
{
struct mpc_link *link = mpc_get_link(ch);
struct mpc_flist *flist;
CHECK_LINK(link);
/* We must find the flist that points to pd */
for (flist = link->flist; flist; flist = flist->next)
if (flist->pd == pd)
break;
if (!flist) {
if (link->logf)
fprintf(link->logf, "%s: not found pd %p\n",
__func__, pd);
errno = EINVAL;
return -1;
}
flist = container_of(&pd, struct mpc_flist, pd);
mpc_free_flist(link, flist);
return 0;
}
/* Return the current fdset associated to the service */
int minipc_server_get_fdset(struct minipc_ch *ch, fd_set *setptr)
{
struct mpc_link *link = mpc_get_link(ch);
CHECK_LINK(link);
*setptr = link->fdset;
return 0;
}
/* Get a pointer to the next argument in the array */
uint32_t *minipc_get_next_arg(uint32_t arg[], uint32_t atype)
{
int asize;
char *s = (void *)arg;
if (MINIPC_GET_ATYPE(atype) != MINIPC_ATYPE_STRING)
asize = MINIPC_GET_ANUM(MINIPC_GET_ASIZE(atype));
else
asize = MINIPC_GET_ANUM(strlen(s) + 1);
return arg + asize;
}
/*
* Internal functions used by server action below: handle a request
* or the arrival of a new client
*/
static void mpc_handle_client(struct mpc_link *link, int pos, int fd)
{
struct mpc_req_packet *p_in, _pkt_in;
struct mpc_rep_packet *p_out, _pkt_out;
struct mpc_shmem *shm = link->memaddr;
const struct minipc_pd *pd;
struct mpc_flist *flist;
int i;
if (shm) {
p_in = &shm->request;
p_out = &shm->reply;
/* read one byte, it's just a signal */
read(fd, &i, 1);
} else {
p_in = & _pkt_in;
p_out = & _pkt_out;
/* receive the packet and manage errors */
i = recv(fd, p_in, sizeof(*p_in), 0);
if (i < 0 && errno == EINTR)
return;
if (i <= 0)
goto close_client;
}
/* use p_in->name to look for the function */
for (flist = link->flist; flist; flist = flist->next)
if (!(strcmp(p_in->name, flist->pd->name)))
break;
if (!flist) {
if (link->logf)
fprintf(link->logf, "%s: function %s not found\n",
__func__, p_in->name);
p_out->type = MINIPC_ARG_ENCODE(MINIPC_ATYPE_ERROR, int);
*(int *)(&p_out->val) = EOPNOTSUPP;
goto send_reply;
}
pd = flist->pd;
if (link->logf)
fprintf(link->logf, "%s: request for %s\n",
__func__, pd->name);
/* call the function and send back stuff */
i = pd->f(pd, p_in->args, p_out->val);
if (i < 0) {
p_out->type = MINIPC_ARG_ENCODE(MINIPC_ATYPE_ERROR, int);
*(int *)(&p_out->val) = errno;
} else {
/* Use retval, but fix the length for strings */
if (MINIPC_GET_ATYPE(pd->retval) == MINIPC_ATYPE_STRING) {
int size = strlen((char *)p_out->val) + 1;
size = (size + 3) & ~3; /* align */
p_out->type =
__MINIPC_ARG_ENCODE(MINIPC_ATYPE_STRING, size);
} else {
p_out->type = pd->retval;
}
}
send_reply:
if (shm) {
shm->nreply++; /* message already in place */
return;
}
/* send a 32-bit value plus the declared return length */
if (send(fd, p_out, sizeof(p_out->type)
+ MINIPC_GET_ASIZE(p_out->type), MSG_NOSIGNAL) < 0)
goto close_client;
return;
close_client:
if (link->logf)
fprintf(link->logf, "%s: error %i in fd %i, closing\n",
__func__, i < 0 ? errno : 0, fd);
close(fd);
FD_CLR(fd, &link->fdset);
link->fd[pos] = -1;
return;
}
static void mpc_handle_connection(struct mpc_link *link, int fd)
{
int i, newfd;
struct sockaddr_un sun;
socklen_t slen = sizeof(sun);
newfd = accept(fd, (struct sockaddr *)&sun, &slen);
if (link->logf)
fprintf(link->logf, "%s: accept returned fd %i (error %i)\n",
__func__, newfd, newfd < 0 ? errno : 0);
if (newfd < 0)
return;
/* Lookf for a place for this */
for (i = 0; i < MINIPC_MAX_CLIENTS; i++)
if (link->fd[i] < 0)
break;
if (i == MINIPC_MAX_CLIENTS) {
if (link->logf)
fprintf(link->logf, "%s: refused: too many clients\n",
__func__);
close(newfd);
return;
}
link->fd[i] = newfd;
FD_SET(newfd, &link->fdset);
}
/*
* The server action returns an error or zero. If the user wants
* the list of active descriptors, it must ask for the filemask
* (at this point there is no support for poll, only select)
*/
int minipc_server_action(struct minipc_ch *ch, int timeoutms)
{
struct mpc_link *link = mpc_get_link(ch);
struct timeval to;
fd_set set;
int i;
CHECK_LINK(link);
to.tv_sec = timeoutms/1000;
to.tv_usec = (timeoutms % 1000) * 1000;
set = link->fdset;
i = select(64 /* FIXME: hard constant */, &set, NULL, NULL, &to);
if (!i)
return 0;
if (i < 0 && errno == EINTR)
return 0;
if (i < 0)
return -1;
if (i == 0) {
errno = EAGAIN;
return -1;
}
/* A shmem server has only one descriptor, for one client */
if (link->memaddr) {
mpc_handle_client(link, -1, ch->fd);
return 0;
}
/* First, look for all clients */
for (i = 0; i < MINIPC_MAX_CLIENTS; i++) {
if (link->fd[i] < 0)
continue;
if (!FD_ISSET(link->fd[i], &set))
continue;
mpc_handle_client(link, i, link->fd[i]);
}
/* Finally, look for a new client */
if (FD_ISSET(ch->fd, &set))
mpc_handle_connection(link, ch->fd);
return 0;
}
/*
* Public definition for mini-ipc
*
* Copyright (C) 2011 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
* Based on ideas by Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef __MINIPC_H__
#define __MINIPC_H__
#include <stdint.h>
#if __STDC_HOSTED__ /* freestanding servers have less material */
#include <stdio.h>
#include <sys/select.h>
#endif
/* Hard limits */
#define MINIPC_MAX_NAME 20 /* includes trailing 0 */
#define MINIPC_MAX_CLIENTS 64
#define MINIPC_MAX_ARGUMENTS 256 /* Also, max size of packet words -- 1k */
#define MINIPC_MAX_REPLY 1024 /* bytes */
#if !__STDC_HOSTED__
#define MINIPC_MAX_EXPORT 12 /* freestanding: static allocation */
#endif
/* The base pathname, mkdir is performed as needed */
#define MINIPC_BASE_PATH "/tmp/.minipc"
/* Default polling interval for memory-based channels */
#define MINIPC_DEFAULT_POLL (10*1000)
/* Argument type (and retval type). The size is encoded in the same word */
enum minipc_at {
MINIPC_ATYPE_ERROR = 0xffff,
MINIPC_ATYPE_NONE = 0, /* used as terminator */
MINIPC_ATYPE_INT = 1,
MINIPC_ATYPE_INT64,
MINIPC_ATYPE_DOUBLE, /* float is promoted to double */
MINIPC_ATYPE_STRING, /* size of strings is strlen() each time */
MINIPC_ATYPE_STRUCT
};
/* Encoding of argument type and size in one word */
#define __MINIPC_ARG_ENCODE(atype, asize) (((atype) << 16) | (asize))
#define MINIPC_ARG_ENCODE(atype, type) __MINIPC_ARG_ENCODE(atype, sizeof(type))
#define MINIPC_GET_ATYPE(word) ((word) >> 16)
#define MINIPC_GET_ASIZE(word) ((word) & 0xffff)
#define MINIPC_ARG_END __MINIPC_ARG_ENCODE(MINIPC_ATYPE_NONE, 0) /* zero */
/* The exported procedure looks like this */
struct minipc_pd;
typedef int (minipc_f)(const struct minipc_pd *, uint32_t *args, void *retval);
/* This is the "procedure definition" */
struct minipc_pd {
minipc_f *f; /* pointer to the function */
char name[MINIPC_MAX_NAME]; /* name of the function */
uint32_t flags;
uint32_t retval; /* type of return value */
uint32_t args[]; /* zero-terminated */
};
/* Flags: verbosity is about argument and retval marshall/unmarshall */
#define MINIPC_FLAG_VERBOSE 1
/* This is the channel definition */
struct minipc_ch {
int fd;
};
static inline int minipc_fileno(struct minipc_ch *ch) {return ch->fd;}
/* These return NULL with errno on error, name is the socket pathname */
struct minipc_ch *minipc_server_create(const char *name, int flags);
struct minipc_ch *minipc_client_create(const char *name, int flags);
int minipc_close(struct minipc_ch *ch);
/* Generic: set the default polling interval for mem-based channels */
int minipc_set_poll(int usec);
/* Server: register exported functions */
int minipc_export(struct minipc_ch *ch, const struct minipc_pd *pd);
int minipc_unexport(struct minipc_ch *ch, const struct minipc_pd *pd);
/* Server: helpers to unmarshall a string or struct from a request */
uint32_t *minipc_get_next_arg(uint32_t arg[], uint32_t atype);
/* Handle a request if pending, otherwise -1 and EAGAIN */
int minipc_server_action(struct minipc_ch *ch, int timeoutms);
#if __STDC_HOSTED__
/* Generic: attach diagnostics to a log file */
int minipc_set_logfile(struct minipc_ch *ch, FILE *logf);
/* Return an fdset for the user to select() on the service */
int minipc_server_get_fdset(struct minipc_ch *ch, fd_set *setptr);
/* Client: make requests */
int minipc_call(struct minipc_ch *ch, int millisec_timeout,
const struct minipc_pd *pd, void *ret, ...);
#endif /* __STDC_HOSTED__ */
#endif /* __MINIPC_H__ */
#include <stdio.h>
#include <stdlib.h>
#include <minipc.h>
#define HAL_EXPORT_STRUCTURES
#include "hal_exports.h"
#include <wr_ipc.h>
#define DEFAULT_TO 200 /* ms */
static wripc_handle_t hal_cli;
static struct minipc_ch *hal_ch;
int halexp_check_running()
{
......@@ -22,34 +25,47 @@ int halexp_reset_port(const char *port_name)
int halexp_calibration_cmd(const char *port_name, int command, int on_off)
{
int rval;
wripc_call(hal_cli, "halexp_calibration_cmd", &rval,3, A_STRING(port_name), A_INT32(command), A_INT32(on_off));
int ret, rval;
ret = minipc_call(hal_ch, DEFAULT_TO, &__rpcdef_calibration_cmd,
&rval, port_name, command, on_off);
if (ret < 0)
return ret;
return rval;
}
int halexp_lock_cmd(const char *port_name, int command, int priority)
{
int rval;
wripc_call(hal_cli, "halexp_lock_cmd", &rval, 3, A_STRING(port_name), A_INT32(command), A_INT32(priority));
int ret, rval;
ret = minipc_call(hal_ch, DEFAULT_TO, &__rpcdef_lock_cmd,
&rval, port_name, command, priority);
if (ret < 0)
return ret;
return rval;
}
int halexp_query_ports(hexp_port_list_t *list)
{
wripc_call(hal_cli, "halexp_query_ports", list, 0);
return 0;
int ret;
ret = minipc_call(hal_ch, DEFAULT_TO, &__rpcdef_query_ports,
list /* return val */);
return ret;
}
int halexp_get_port_state(hexp_port_state_t *state, const char *port_name)
{
wripc_call(hal_cli, "halexp_get_port_state", state, 1, A_STRING(port_name));
return 0;
int ret;
ret = minipc_call(hal_ch, DEFAULT_TO, &__rpcdef_query_ports,
state /* retval */, port_name);
return ret;
}
int halexp_pps_cmd(int cmd, hexp_pps_params_t *params)
{
int rval;
wripc_call(hal_cli, "halexp_pps_cmd", &rval, 2, A_INT32(cmd), A_STRUCT(*params));
int ret, rval;
ret = minipc_call(hal_ch, DEFAULT_TO, &__rpcdef_pps_cmd,
&rval, cmd, params);
if (ret < 0)
return ret;
return rval;
}
......@@ -57,7 +73,7 @@ int halexp_pps_cmd(int cmd, hexp_pps_params_t *params)
int halexp_pll_cmd(int cmd, hexp_pll_cmd_t *params)
{
int rval;
wripc_call(hal_cli, "halexp_pll_cmd", &rval, 2, A_INT32(cmd), A_STRUCT(*params));
wripc_call(hal_ch, "halexp_pll_cmd", &rval, 2, A_INT32(cmd), A_STRUCT(*params));
return rval;
}
......@@ -65,8 +81,8 @@ int halexp_pll_cmd(int cmd, hexp_pll_cmd_t *params)
int halexp_client_init()
{
hal_cli = wripc_connect(WRSW_HAL_SERVER_ADDR);
if(hal_cli < 0)
hal_ch = minipc_client_create(WRSW_HAL_SERVER_ADDR, 0);
if (!hal_ch)
return -1;
else
return 0;
......@@ -75,7 +91,8 @@ int halexp_client_init()
int halexp_extsrc_cmd(int command)
{
int rval;
wripc_call(hal_cli, "halexp_extsrc_cmd", &rval, 1, A_INT32(command));
int ret, rval;
ret = minipc_call(hal_ch, DEFAULT_TO, &__rpcdef_extsrc_cmd,
&rval, command);
return rval;
}
// architecture-specific _do_call() functions
#ifdef __i386__
static int _do_call(void *func_ptr, void *args, int args_size)
{
int rval;
asm volatile (
"movl %%esp, %%edi\n"
"movl %%ebx, %%ecx\n"
"subl %%ebx, %%edi\n"
"shrl $2, %%ecx\n"
"cld\n"
"rep\n"
"movsl\n"
"subl %3, %%esp\n"
"call *%%eax\n"
"addl %3, %%esp\n"
: "=a"(rval)
: "a"(func_ptr), "S"(args), "b"(args_size)
:
);
/* "si", "di", "ax", "bx", "cx", "memory" */
return rval;
}
#endif
#ifdef __arm__
extern int _do_call(void *func_ptr, void *args, int args_size);
#endif
.global _do_call
_do_call:
stmfd sp!, {r4, r5, r6, r7, fp, lr}
mov r4, r1 // r4 = args_buffer
mov lr, r0 // lr = func_ptr
mov r5, r2 // r5 = args_size
ldr r0, [r4, #0]
ldr r1, [r4, #4]
ldr r2, [r4, #8]
ldr r3, [r4, #12]
mov fp, sp
sub r5, #16
cmp r5, #0
blt do_call
add r4, #16
mov r7, sp
sub r7, r5
sub sp, r5
copy_args:
ldr r6, [r4]
str r6, [r7]
add r7, #4
add r4, #4
sub r5, #4
cmp r5, #0
bne copy_args
do_call:
mov r6, lr
mov lr, pc
bx r6
mov sp, fp
ldmfd sp!, {r4, r5, r6, r7, fp, lr}
bx lr
struct test_struct {
int apples;
int peas;
char name[80];
float value;
};
struct state_struct {
char state_name[80];
float t;
int x;
};
void test_void(double *ptr, double a, double b)
{
*ptr = a+b;
}
main()
{
test_void(1000, 1.123, 2.245);
}
\ No newline at end of file
#include <stdio.h>
#include "wr_ipc.h"
#include "structs.h"
main()
{
wripc_handle_t cli;
int res_int;
float result, a,b;
struct state_struct s;
cli = wripc_connect("test");
wripc_call(cli, "bigfunc", &res_int, 8, A_INT32(1), A_INT32(2), A_INT32(3), A_INT32(4), A_INT32(5), A_INT32(6), A_INT32(7), A_INT32(8));
printf("1+...+8 = %d\n", res_int);
a=2.2; b= 4.4;
wripc_call(cli, "add", &result, 2, A_FLOAT(a), A_FLOAT(b));
printf("%.1f + %.1f = %.1f\n", a,b,result);
wripc_call(cli, "get_state", &s, 1, A_INT32(12345));
printf("state->name %s\n", s.state_name);
printf("state->t %.3f\n", s.t);
printf("state->x %d\n", s.x);
struct test_struct s2;
s2.apples = 10;
s2.peas = 15;
strcpy(s2.name, "Javier");
s2.value = 17.50;
// wripc_call(cli, "structure_test", &result, 1, A_STRUCT(s2));
wripc_call(cli, "string_test", &res_int, 3, A_STRING("Hello, world"), A_INT32(1), A_INT32(100));
printf("rval = %d\n", res_int);
usleep(1000);
wripc_close(cli);
}
float ret_float() { return 1.0; }
double ret_double() { return 1.0; }
void test_float(double a)
{
*(volatile double *) 0xdeadbee0 = a;
}
main()
{
float x = 123.345;
test_float(x);
}
\ No newline at end of file
#include <stdio.h>
#include <string.h>
#include "wr_ipc.h"
#include "structs.h"
int bigfunc(int a, int b, int c, int d, int e, int f, int g, int h)
{
printf("Call bigfunc: %d %d %d %d %d %d %d %d\n" ,a,b,c,d,e,f,g,h);
return a+b+c+d+e+f+g+h;
}
void add(float *rval, float a, float b)
{
printf("Call add: %.3f + %.3f\n", a,b);
*rval = a + b;
}
int string_test(char *string, int a, int b)
{
printf("Call string_test: a = %d, b= %d, string = '%s'\n", a,b,string);
return 12345;
}
void structure_test(struct test_struct *s)
{
printf("Call structure_test: %s got %d apples and %d peas of total value %.3f\n",s->name, s->apples, s->peas, s->value);
}
void get_state(struct state_struct *rval, int request)
{
printf("Call get_state: request = %d\n", request);
rval->t = 123.0;
strcpy(rval->state_name, "SomeState");
rval->x = request;
}
int main()
{
wripc_handle_t srv;
srv = wripc_create_server("test");
// add(10000, 1.0, 2.0);
wripc_export(srv, T_INT32, "bigfunc", bigfunc, 8, T_INT32, T_INT32, T_INT32, T_INT32, T_INT32, T_INT32, T_INT32, T_INT32 );
wripc_export(srv, T_FLOAT, "add", add, 2, T_FLOAT, T_FLOAT);
wripc_export(srv, T_INT32, "sub", add, 2, T_INT32, T_INT32);
wripc_export(srv, T_INT32, "string_test", string_test, 3, T_STRING, T_INT32, T_INT32);
wripc_export(srv, T_VOID, "structure_test", structure_test, 1, T_STRUCT(struct test_struct));
wripc_export(srv, T_STRUCT(struct state_struct), "get_state", get_state, 1, T_INT32);
for(;;) wripc_process(srv);
return 0;
}
This diff is collapsed.
#ifndef __WR_IPC_H
#define __WR_IPC_H
//#include <inttypes.h> -- now in ptpd-wrappers.h
#define T_INT32 1
#define T_INT16 2
#define T_INT8 3
#define T_STRING 4
#define T_FLOAT 5
#define T_DOUBLE 6
#define T_STRUCT_TYPE 7
#define T_STRUCT(type) (T_STRUCT_TYPE | (sizeof(type) << 8))
#define T_VOID 8
#define A_INT8(x) T_INT8,(x)
#define A_INT16(x) T_INT16,(x)
#define A_INT32(x) T_INT32,(x)
#define A_STRING(x) T_STRING,(x)
#define A_FLOAT(x) T_FLOAT,(x)
#define A_DOUBLE(x) T_DOUBLE,(x)
#define A_STRUCT(x) T_STRUCT(x),&x
#define WRIPC_ERROR_INVALID_REQUEST -1
#define WRIPC_ERROR_UNKNOWN_FUNCTION -2
#define WRIPC_ERROR_MALFORMED_PACKET -3
#define WRIPC_ERROR_INVALID_ARG -4
#define WRIPC_ERROR_NO_MEMORY -5
#define WRIPC_ERROR_TIMEOUT -6
#define WRIPC_ERROR_NETWORK_FAIL -7
typedef int wripc_handle_t;
wripc_handle_t wripc_create_server(const char *name);
wripc_handle_t wripc_connect(const char *name);
void wripc_close(wripc_handle_t h);
int wripc_export (wripc_handle_t handle, int rval_type, const char *name, void *func_ptr, int num_args, ...);
int wripc_call (wripc_handle_t handle, const char *name, void *rval, int num_args, ...);
int wripc_process(wripc_handle_t handle);
int wripc_publish_event(wripc_handle_t handle, int event_id, void *buf, int buf_len);
int wripc_subscribe_event(wripc_handle_t handle, int event_id);
int wripc_receive_event(wripc_handle_t handle, int *event_id, void *buf, int buf_len);
#endif
......@@ -139,16 +139,120 @@ typedef struct {
} hexp_pll_cmd_t;
int halexp_check_running();
int halexp_reset_port(const char *port_name);
int halexp_calibration_cmd(const char *port_name, int command, int on_off);
int halexp_lock_cmd(const char *port_name, int command, int priority);
int halexp_query_ports(hexp_port_list_t *list);
int halexp_get_port_state(hexp_port_state_t *state, const char *port_name);
int halexp_pps_cmd(int cmd, hexp_pps_params_t *params);
int halexp_pll_set_gain(int pll, int branch, int kp, int ki);
int halexp_extsrc_cmd(int command); //added by ML
/* Prototypes of functions that call on rpc */
extern int halexp_check_running(void);
extern int halexp_reset_port(const char *port_name);
extern int halexp_calibration_cmd(const char *port_name, int command, int on_off);
extern int halexp_lock_cmd(const char *port_name, int command, int priority);
extern int halexp_query_ports(hexp_port_list_t *list);
extern int halexp_get_port_state(hexp_port_state_t *state, const char *port_name);
extern int halexp_pps_cmd(int cmd, hexp_pps_params_t *params);
extern int halexp_pll_set_gain(int pll, int branch, int kp, int ki);
extern int halexp_extsrc_cmd(int command); //added by ML
/* Export structures, shared by server and client for argument matching */
#ifdef HAL_EXPORT_STRUCTURES
//int halexp_check_running();
struct minipc_pd __rpcdef_check_running = {
.name = "check_running",
.retval = MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
.args = {
MINIPC_ARG_END,
},
};
//int halexp_reset_port(const char *port_name);
struct minipc_pd __rpcdef_reset_port = {
.name = "reset_port",
.retval = MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
.args = {
MINIPC_ARG_ENCODE(MINIPC_ATYPE_STRING, char *),
MINIPC_ARG_END,
},
};
//int halexp_calibration_cmd(const char *port_name, int command, int on_off);
struct minipc_pd __rpcdef_calibration_cmd = {
.name = "calibration_cmd",
.retval = MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
.args = {
MINIPC_ARG_ENCODE(MINIPC_ATYPE_STRING, char *),
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
MINIPC_ARG_END,
},
};
//int halexp_lock_cmd(const char *port_name, int command, int priority);
struct minipc_pd __rpcdef_lock_cmd = {
.name = "lock_cmd",
.retval = MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
.args = {
MINIPC_ARG_ENCODE(MINIPC_ATYPE_STRING, char *),
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
MINIPC_ARG_END,
},
};
//int halexp_query_ports(hexp_port_list_t *list);
struct minipc_pd __rpcdef_query_ports = {
.name = "query_ports",
.retval = MINIPC_ARG_ENCODE(MINIPC_ATYPE_STRUCT, hexp_port_list_t),
.args = {
MINIPC_ARG_END,
},
};
//int halexp_get_port_state(hexp_port_state_t *state, const char *port_name);
struct minipc_pd __rpcdef_get_port_state = {
.name = "get_port_state",
.retval = MINIPC_ARG_ENCODE(MINIPC_ATYPE_STRUCT, hexp_port_state_t),
.args = {
MINIPC_ARG_ENCODE(MINIPC_ATYPE_STRING, char *),
MINIPC_ARG_END,
},
};
//int halexp_pps_cmd(int cmd, hexp_pps_params_t *params);
struct minipc_pd __rpcdef_pps_cmd = {
.name = "pps_cmd",
.retval = MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
.args = {
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
MINIPC_ARG_ENCODE(MINIPC_ATYPE_STRUCT, hexp_pps_params_t),
MINIPC_ARG_END,
},
};
//int halexp_pll_set_gain(int pll, int branch, int kp, int ki);
struct minipc_pd __rpcdef_pll_set_gain = {
.name = "pll_set_gain",
.retval = MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
.args = {
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
MINIPC_ARG_END,
},
};
//int halexp_extsrc_cmd(int command); //added by ML
struct minipc_pd __rpcdef_extsrc_cmd = {
.name = "extsrc_cmd",
.retval = MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
.args = {
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
MINIPC_ARG_END,
},
};
#endif /* HAL_EXPORT_STRUCTURES */
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment