Phase 2/4 done, working on phase 3/5
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
#ifndef CA_WRAPPER_H
|
||||
#define CA_WRAPPER_H
|
||||
|
||||
#include <cadef.h>
|
||||
#include <db_access.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* Go-exported callback declarations.
|
||||
* These are implemented in ca_callback.go (via //export directives).
|
||||
*
|
||||
* goCAMonitorCallback is called for each value update received from CA.
|
||||
* goCAConnectionCallback is called when a channel connects or disconnects.
|
||||
*/
|
||||
extern void goCAMonitorCallback(uintptr_t handle, int dbrType, long count,
|
||||
const void *dbr, int severity,
|
||||
double epicsTimeSecs);
|
||||
extern void goCAConnectionCallback(uintptr_t handle, int connected);
|
||||
|
||||
/*
|
||||
* CA monitor callback shim.
|
||||
*
|
||||
* CA calls this function with the fixed evargs signature. We extract the
|
||||
* relevant fields and forward them to the Go callback.
|
||||
*/
|
||||
static void caMonitorCallbackShim(struct event_handler_args args) {
|
||||
if (args.status != ECA_NORMAL) {
|
||||
return;
|
||||
}
|
||||
|
||||
double timeSecs = 0.0;
|
||||
int severity = 0;
|
||||
|
||||
/*
|
||||
* Determine the timestamp and alarm severity from the DBR type.
|
||||
* We request DBR_TIME_* types so the timestamp is embedded in the value
|
||||
* buffer right after the alarm fields (struct dbr_time_double et al.).
|
||||
*/
|
||||
switch (args.type) {
|
||||
case DBR_TIME_DOUBLE: {
|
||||
const struct dbr_time_double *p = (const struct dbr_time_double *)args.dbr;
|
||||
timeSecs = (double)p->stamp.secPastEpoch + (double)p->stamp.nsec / 1e9;
|
||||
severity = (int)p->severity;
|
||||
break;
|
||||
}
|
||||
case DBR_TIME_FLOAT: {
|
||||
const struct dbr_time_float *p = (const struct dbr_time_float *)args.dbr;
|
||||
timeSecs = (double)p->stamp.secPastEpoch + (double)p->stamp.nsec / 1e9;
|
||||
severity = (int)p->severity;
|
||||
break;
|
||||
}
|
||||
case DBR_TIME_LONG: {
|
||||
const struct dbr_time_long *p = (const struct dbr_time_long *)args.dbr;
|
||||
timeSecs = (double)p->stamp.secPastEpoch + (double)p->stamp.nsec / 1e9;
|
||||
severity = (int)p->severity;
|
||||
break;
|
||||
}
|
||||
case DBR_TIME_SHORT: {
|
||||
const struct dbr_time_short *p = (const struct dbr_time_short *)args.dbr;
|
||||
timeSecs = (double)p->stamp.secPastEpoch + (double)p->stamp.nsec / 1e9;
|
||||
severity = (int)p->severity;
|
||||
break;
|
||||
}
|
||||
case DBR_TIME_STRING: {
|
||||
const struct dbr_time_string *p = (const struct dbr_time_string *)args.dbr;
|
||||
timeSecs = (double)p->stamp.secPastEpoch + (double)p->stamp.nsec / 1e9;
|
||||
severity = (int)p->severity;
|
||||
break;
|
||||
}
|
||||
case DBR_TIME_ENUM: {
|
||||
const struct dbr_time_enum *p = (const struct dbr_time_enum *)args.dbr;
|
||||
timeSecs = (double)p->stamp.secPastEpoch + (double)p->stamp.nsec / 1e9;
|
||||
severity = (int)p->severity;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
goCAMonitorCallback((uintptr_t)args.usr, (int)args.type, (long)args.count,
|
||||
args.dbr, severity, timeSecs);
|
||||
}
|
||||
|
||||
/*
|
||||
* CA connection callback shim.
|
||||
*
|
||||
* CA calls this with a connection_handler_args struct. We map the op field
|
||||
* to a simple boolean (1 = connected, 0 = disconnected) and forward.
|
||||
*/
|
||||
static void caConnectionCallbackShim(struct connection_handler_args args) {
|
||||
int connected = (args.op == CA_OP_CONN_UP) ? 1 : 0;
|
||||
goCAConnectionCallback((uintptr_t)ca_puser(args.chid), connected);
|
||||
}
|
||||
|
||||
/*
|
||||
* Thin helpers so CGo callers do not need to deal with C function-pointer
|
||||
* syntax directly. All CA API calls stay in C to avoid issues with CGo
|
||||
* passing Go pointers across the CA callback boundary.
|
||||
*/
|
||||
|
||||
/* Create a channel with the connection shim as the connection callback.
|
||||
* user_handle is the Go uintptr_t that identifies this channel in the handle
|
||||
* table. Returns the ECA_* status code. */
|
||||
static int caCreateChannel(const char *pvName, uintptr_t userHandle,
|
||||
chid *pChid) {
|
||||
return ca_create_channel(pvName, caConnectionCallbackShim,
|
||||
(void *)userHandle, CA_PRIORITY_DEFAULT, pChid);
|
||||
}
|
||||
|
||||
/* Add a value-monitor event on chid. Returns the ECA_* status code and stores
|
||||
* the evid in *pEvid. */
|
||||
static int caAddMonitor(chid ch, short dbrType, uintptr_t userHandle,
|
||||
evid *pEvid) {
|
||||
return ca_add_event(dbrType, ch, caMonitorCallbackShim,
|
||||
(void *)userHandle, pEvid);
|
||||
}
|
||||
|
||||
#endif /* CA_WRAPPER_H */
|
||||
Reference in New Issue
Block a user