260 lines
5.3 KiB
C
260 lines
5.3 KiB
C
/*************************************************************************\
|
|
* Copyright (c) 2016 Michael Davidsaver
|
|
* SPDX-License-Identifier: EPICS
|
|
* EPICS BASE is distributed subject to a Software License Agreement found
|
|
* in file LICENSE that is included with this distribution.
|
|
\*************************************************************************/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <dbAccess.h>
|
|
#include <link.h>
|
|
#include <alarm.h>
|
|
#include <dbJLink.h>
|
|
#include <dbDefs.h>
|
|
#include <dbConvertFast.h>
|
|
#include <epicsMutex.h>
|
|
#include <epicsAtomic.h>
|
|
#include <epicsUnitTest.h>
|
|
|
|
#define epicsExportSharedSymbols
|
|
|
|
#include "jlinkz.h"
|
|
|
|
#include <epicsExport.h>
|
|
|
|
int numzalloc;
|
|
|
|
|
|
static
|
|
void z_open(struct link *plink)
|
|
{
|
|
zpriv *priv = CONTAINER(plink->value.json.jlink, zpriv, base);
|
|
|
|
if(priv->isopen)
|
|
testDiag("lsetZ re-open");
|
|
priv->isopen = 1;
|
|
testDiag("Open jlinkz %p", priv);
|
|
}
|
|
|
|
static
|
|
void z_remove(struct dbLocker *locker, struct link *plink)
|
|
{
|
|
zpriv *priv = CONTAINER(plink->value.json.jlink, zpriv, base);
|
|
|
|
epicsMutexLock(priv->lock);
|
|
|
|
if(!priv->isopen)
|
|
testDiag("lsetZ remove without open");
|
|
|
|
epicsMutexUnlock(priv->lock);
|
|
|
|
testDiag("Remove/free jlinkz %p", priv);
|
|
|
|
epicsAtomicDecrIntT(&numzalloc);
|
|
|
|
epicsMutexDestroy(priv->lock);
|
|
free(priv);
|
|
plink->value.json.jlink = NULL; /* paranoia */
|
|
}
|
|
|
|
static
|
|
int z_connected(const struct link *plink)
|
|
{
|
|
return 1; /* TODO: not provided should be connected */
|
|
}
|
|
|
|
static
|
|
int z_dbftype(const struct link *plink)
|
|
{
|
|
return DBF_LONG;
|
|
}
|
|
|
|
static
|
|
long z_elements(const struct link *plink, long *nelements)
|
|
{
|
|
*nelements = 1;
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
long z_getval(struct link *plink, short dbrType, void *pbuffer,
|
|
long *pnRequest)
|
|
{
|
|
long ret;
|
|
long (*pconv)(const epicsInt32 *, void *, const dbAddr *) = dbFastGetConvertRoutine[DBF_LONG][dbrType];
|
|
zpriv *priv = CONTAINER(plink->value.json.jlink, zpriv, base);
|
|
|
|
if(pnRequest && *pnRequest==0) return 0;
|
|
|
|
epicsMutexLock(priv->lock);
|
|
ret = (*pconv)(&priv->value, pbuffer, NULL);
|
|
epicsMutexUnlock(priv->lock);
|
|
if(ret==0 && pnRequest) *pnRequest = 1;
|
|
return ret;
|
|
}
|
|
|
|
/* TODO: atomically get value and alarm */
|
|
static
|
|
long z_getalarm(const struct link *plink, epicsEnum16 *status,
|
|
epicsEnum16 *severity)
|
|
{
|
|
zpriv *priv = CONTAINER(plink->value.json.jlink, zpriv, base);
|
|
epicsEnum16 sevr, stat;
|
|
|
|
epicsMutexLock(priv->lock);
|
|
sevr = priv->isset ? 0 : INVALID_ALARM;
|
|
stat = priv->isset ? 0 : LINK_ALARM;
|
|
epicsMutexUnlock(priv->lock);
|
|
|
|
if(status) *status = stat;
|
|
if(severity) *severity = sevr;
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
long z_putval(struct link *plink, short dbrType,
|
|
const void *pbuffer, long nRequest)
|
|
{
|
|
long ret;
|
|
long (*pconv)(epicsInt32 *, const void *, const dbAddr *);
|
|
zpriv *priv = CONTAINER(plink->value.json.jlink, zpriv, base);
|
|
|
|
if(INVALID_DB_REQ(dbrType))
|
|
return S_db_badDbrtype;
|
|
|
|
pconv = dbFastPutConvertRoutine[DBF_LONG][dbrType];
|
|
|
|
if(nRequest==0) return 0;
|
|
|
|
epicsMutexLock(priv->lock);
|
|
ret = (*pconv)(&priv->value, pbuffer, NULL);
|
|
epicsMutexUnlock(priv->lock);
|
|
return ret;
|
|
}
|
|
|
|
static lset lsetZ = {
|
|
0, 0, /* non-const, non-volatile */
|
|
&z_open,
|
|
&z_remove,
|
|
NULL, NULL, NULL, /* load */
|
|
&z_connected,
|
|
&z_dbftype,
|
|
&z_elements,
|
|
&z_getval,
|
|
NULL, /* control limits */
|
|
NULL, /* display limits */
|
|
NULL, /* alarm limits */
|
|
NULL, /* prec */
|
|
NULL, /* units */
|
|
&z_getalarm,
|
|
NULL, /* time */
|
|
&z_putval,
|
|
NULL, /* putasync */
|
|
NULL, /* forward */
|
|
NULL, /* doLocked */
|
|
};
|
|
|
|
static
|
|
jlink* z_alloc(short dbfType)
|
|
{
|
|
zpriv *priv;
|
|
priv = calloc(1, sizeof(*priv));
|
|
if(!priv) goto fail;
|
|
|
|
priv->lock = epicsMutexCreate();
|
|
if(!priv->lock) goto fail;
|
|
|
|
epicsAtomicIncrIntT(&numzalloc);
|
|
|
|
testDiag("Alloc jlinkz %p", priv);
|
|
|
|
return &priv->base;
|
|
fail:
|
|
if(priv && priv->lock) epicsMutexDestroy(priv->lock);
|
|
free(priv);
|
|
return NULL;
|
|
}
|
|
|
|
static
|
|
void z_free(jlink *pj)
|
|
{
|
|
zpriv *priv = CONTAINER(pj, zpriv, base);
|
|
|
|
if(priv->isopen)
|
|
testDiag("lsetZ jlink free after open()");
|
|
|
|
testDiag("Free jlinkz %p", priv);
|
|
|
|
epicsAtomicDecrIntT(&numzalloc);
|
|
|
|
epicsMutexDestroy(priv->lock);
|
|
free(priv);
|
|
}
|
|
|
|
static
|
|
jlif_result z_int(jlink *pj, long long num)
|
|
{
|
|
zpriv *priv = CONTAINER(pj, zpriv, base);
|
|
|
|
priv->value = num;
|
|
priv->isset = 1;
|
|
|
|
return jlif_continue;
|
|
}
|
|
|
|
static
|
|
jlif_key_result z_start(jlink *pj)
|
|
{
|
|
return jlif_key_continue;
|
|
}
|
|
|
|
static
|
|
jlif_result z_key(jlink *pj, const char *key, size_t len)
|
|
{
|
|
zpriv *priv = CONTAINER(pj, zpriv, base);
|
|
|
|
if(len==4 && strncmp(key,"fail", len)==0) {
|
|
testDiag("Found fail key jlinkz %p", priv);
|
|
return jlif_stop;
|
|
} else {
|
|
return jlif_continue;
|
|
}
|
|
}
|
|
|
|
static
|
|
jlif_result z_end(jlink *pj)
|
|
{
|
|
return jlif_continue;
|
|
}
|
|
|
|
static
|
|
struct lset* z_lset(const jlink *pj)
|
|
{
|
|
return &lsetZ;
|
|
}
|
|
|
|
static jlif jlifZ = {
|
|
"z",
|
|
&z_alloc,
|
|
&z_free,
|
|
NULL, /* null */
|
|
NULL, /* bool */
|
|
&z_int,
|
|
NULL, /* double */
|
|
NULL, /* string */
|
|
&z_start,
|
|
&z_key,
|
|
&z_end,
|
|
NULL, /* start array */
|
|
NULL, /* end array */
|
|
NULL, /* end child */
|
|
&z_lset,
|
|
NULL, /* report */
|
|
NULL, /* map child */
|
|
NULL /* start child */
|
|
};
|
|
|
|
epicsExportAddress(jlif, jlifZ);
|