Skip to content

Commit 3f38470

Browse files
[TASK] preliminary support for aao
1 parent 13bbc9a commit 3f38470

File tree

2 files changed

+191
-0
lines changed

2 files changed

+191
-0
lines changed

src/pydev_aao.cpp

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/*************************************************************************\
2+
* PyDevice is distributed subject to a Software License Agreement found
3+
* in file LICENSE that is included with this distribution.
4+
\*************************************************************************/
5+
6+
#include <aaoRecord.h>
7+
8+
#include <alarm.h>
9+
#include <callback.h>
10+
#include <cantProceed.h>
11+
#include <dbScan.h>
12+
#include <devSup.h>
13+
#include <epicsExport.h>
14+
#include <recGbl.h>
15+
16+
#include <map>
17+
#include <string.h>
18+
19+
#include "asyncexec.h"
20+
#include "pywrapper.h"
21+
#include "util.h"
22+
#include "util_array.h"
23+
#include <iostream>
24+
25+
struct PyDevContext {
26+
CALLBACK callback;
27+
IOSCANPVT scan;
28+
int processCbStatus;
29+
};
30+
31+
static std::map<std::string, IOSCANPVT> ioScanPvts;
32+
33+
static void scanCallback(IOSCANPVT scan)
34+
{
35+
#ifdef VERSION_INT
36+
# if EPICS_VERSION_INT < VERSION_INT(3,16,0,0)
37+
scanIoRequest(scan);
38+
# else
39+
scanIoImmediate(scan, priorityHigh);
40+
scanIoImmediate(scan, priorityMedium);
41+
scanIoImmediate(scan, priorityLow);
42+
# endif
43+
#else
44+
scanIoRequest(scan);
45+
#endif
46+
}
47+
48+
static long initRecord(aaoRecord* rec)
49+
{
50+
51+
std::string addr = rec->out.value.instio.string;
52+
void *buffer = callocMustSucceed(1, sizeof(PyDevContext), "PyDev::initRecord");
53+
PyDevContext* ctx = new (buffer) PyDevContext;
54+
rec->dpvt = ctx;
55+
56+
// This could be better checked with regex
57+
if (addr.find("pydev.iointr('") == 0 && addr.substr(addr.size()-2) == "')") {
58+
std::string param = addr.substr(14, addr.size()-16);
59+
auto it = ioScanPvts.find(param);
60+
if (it == ioScanPvts.end()) {
61+
scanIoInit( &ioScanPvts[param] );
62+
PyWrapper::Callback cb = std::bind(scanCallback, ioScanPvts[param]);
63+
PyWrapper::registerIoIntr(param, cb);
64+
it = ioScanPvts.find(param);
65+
}
66+
ctx->scan = it->second;
67+
} else {
68+
ctx->scan = nullptr;
69+
}
70+
71+
return 0;
72+
}
73+
74+
static long getIointInfo(int /*direction*/, aaoRecord *rec, IOSCANPVT* io)
75+
{
76+
auto ctx = reinterpret_cast<PyDevContext*>(rec->dpvt);
77+
if (ctx != nullptr && ctx->scan != nullptr) {
78+
*io = ctx->scan;
79+
}
80+
return 0;
81+
}
82+
83+
84+
85+
static void processRecordCb(aaoRecord* rec)
86+
{
87+
auto ctx = reinterpret_cast<PyDevContext*>(rec->dpvt);
88+
89+
std::cerr << "processRecordCb: nelm" << rec->nelm << " nord " << rec->nord << std::endl;
90+
91+
auto fields = Util::getFields(rec->out.value.instio.string);
92+
for (auto& keyval: fields) {
93+
if (keyval.first == "VAL"){ keyval.second = rec_bptr_to_strings(rec);
94+
std::cerr << "processRecordCb" << keyval.second << std::endl;
95+
}else if (keyval.first == "NAME") keyval.second = rec->name;
96+
else if (keyval.first == "EGU") keyval.second = rec->egu;
97+
else if (keyval.first == "HOPR") keyval.second = Util::to_string(rec->hopr);
98+
else if (keyval.first == "LOPR") keyval.second = Util::to_string(rec->lopr);
99+
else if (keyval.first == "PREC") keyval.second = Util::to_string(rec->prec);
100+
else if (keyval.first == "TPRO") keyval.second = Util::to_string(rec->tpro);
101+
}
102+
std::string code = Util::replaceFields(rec->out.value.instio.string, fields);
103+
104+
try {
105+
epicsFloat64 val;
106+
auto r = PyWrapper::exec(code, (rec->tpro == 1));
107+
if (r.type == PyWrapper::MultiTypeValue::Type::NONE) {
108+
rec->udf = 0;
109+
}
110+
ctx->processCbStatus = 0;
111+
} catch (...) {
112+
recGblSetSevr(rec, epicsAlarmCalc, epicsSevInvalid);
113+
ctx->processCbStatus = -1;
114+
}
115+
callbackRequestProcessCallback(&ctx->callback, rec->prio, rec);
116+
117+
}
118+
119+
static long processRecord(aaoRecord* rec)
120+
{
121+
std::cerr << __FILE__ << " processing record " << std::endl;
122+
auto ctx = reinterpret_cast<PyDevContext*>(rec->dpvt);
123+
if (ctx == nullptr) {
124+
// Keep PACT=1 to prevent further processing
125+
rec->pact = 1;
126+
recGblSetSevr(rec, epicsAlarmUDF, epicsSevInvalid);
127+
return -1;
128+
}
129+
130+
if (rec->pact == 1) {
131+
rec->pact = 0;
132+
return ctx->processCbStatus;
133+
}
134+
rec->pact = 1;
135+
136+
auto scheduled = AsyncExec::schedule([rec]() {
137+
processRecordCb(rec);
138+
});
139+
std::cerr << __FILE__ << " processed record " << std::endl;
140+
return (scheduled ? 0 : -1);
141+
}
142+
143+
extern "C"
144+
{
145+
struct
146+
{
147+
long number{6};
148+
DEVSUPFUN report{nullptr};
149+
DEVSUPFUN init{nullptr};
150+
DEVSUPFUN init_record{(DEVSUPFUN)initRecord};
151+
DEVSUPFUN get_ioint_info{(DEVSUPFUN)getIointInfo};
152+
DEVSUPFUN write{(DEVSUPFUN)processRecord};
153+
DEVSUPFUN special_linconv{nullptr};
154+
} devPyDevAao;
155+
epicsExportAddress(dset, devPyDevAao);
156+
157+
}; // extern "C"

src/util_array.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*************************************************************************\
2+
* PyDevice is distributed subject to a Software License Agreement found
3+
* in file LICENSE that is included with this distribution.
4+
\*************************************************************************/
5+
6+
#ifndef UTIL_ARRAY_H
7+
#define UTIL_ARRAY_H
8+
9+
10+
#include <string>
11+
#include <menuFtype.h>
12+
13+
#include "util.h"
14+
template <typename T>
15+
static std::string rec_bptr_to_strings(T* rec)
16+
{
17+
18+
switch(rec->ftvl){
19+
case menuFtypeCHAR: return Util::to_pylist_string ( reinterpret_cast< epicsInt8* >(rec->bptr) , rec->nelm ); break;
20+
case menuFtypeUCHAR: return Util::to_pylist_string ( reinterpret_cast< epicsUInt8* >(rec->bptr) , rec->nelm ); break;
21+
case menuFtypeSHORT: return Util::to_pylist_string ( reinterpret_cast< epicsInt16* >(rec->bptr) , rec->nelm ); break;
22+
case menuFtypeUSHORT: return Util::to_pylist_string ( reinterpret_cast< epicsUInt16* >(rec->bptr) , rec->nelm ); break;
23+
case menuFtypeLONG: return Util::to_pylist_string ( reinterpret_cast< epicsInt32* >(rec->bptr) , rec->nelm ); break;
24+
case menuFtypeULONG: return Util::to_pylist_string ( reinterpret_cast< epicsUInt32* >(rec->bptr) , rec->nelm ); break;
25+
case menuFtypeFLOAT: return Util::to_pylist_string ( reinterpret_cast< epicsFloat32* >(rec->bptr) , rec->nelm ); break;
26+
case menuFtypeDOUBLE: return Util::to_pylist_string ( reinterpret_cast< epicsFloat64* >(rec->bptr) , rec->nelm ); break;
27+
default:
28+
break;
29+
}
30+
throw std::runtime_error("could not convert vertor to string") ;
31+
}
32+
33+
34+
#endif // UTIL_ARRAY_H

0 commit comments

Comments
 (0)