/*************************************************************************\ * 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 #include #include #include #include #include #include #include #include #include #include #define epicsExportSharedSymbols #include "jlinkz.h" #include 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);