diff --git a/adaptors/java/src/se/lth/control/realtime/moberg/Moberg.java b/adaptors/java/src/se/lth/control/realtime/moberg/Moberg.java index 2a79c03ccf8cade5e6be27dcec2c9008621195c4..ec3643d53dbb3ba57090d7472990bf606708cb91 100644 --- a/adaptors/java/src/se/lth/control/realtime/moberg/Moberg.java +++ b/adaptors/java/src/se/lth/control/realtime/moberg/Moberg.java @@ -28,7 +28,7 @@ public class Moberg { public static native void analogOutOpen(int index) throws MobergException; public static native void analogOutClose(int index) throws MobergException; - public static native void analogOut(int index, double value) throws MobergException; + public static native double analogOut(int index, double value) throws MobergException; public static native void digitalInOpen(int index) throws MobergException; public static native void digitalInClose(int index) throws MobergException; @@ -36,7 +36,7 @@ public class Moberg { public static native void digitalOutOpen(int index) throws MobergException; public static native void digitalOutClose(int index) throws MobergException; - public static native void digitalOut(int index, boolean value) throws MobergException; + public static native boolean digitalOut(int index, boolean value) throws MobergException; public static native void encoderInOpen(int index) throws MobergException; public static native void encoderInClose(int index) throws MobergException; diff --git a/adaptors/java/src/se_lth_control_realtime_moberg_Moberg.c b/adaptors/java/src/se_lth_control_realtime_moberg_Moberg.c index 8cd8e4aaff9e42706773b2305e918ad497fa2a2d..769f4235e2341d42b43a56ef35b71ba40b287e57 100644 --- a/adaptors/java/src/se_lth_control_realtime_moberg_Moberg.c +++ b/adaptors/java/src/se_lth_control_realtime_moberg_Moberg.c @@ -261,16 +261,19 @@ Java_se_lth_control_realtime_moberg_Moberg_analogOutClose( } -JNIEXPORT void JNICALL +JNIEXPORT double JNICALL Java_se_lth_control_realtime_moberg_Moberg_analogOut( - JNIEnv *env, jobject obj, jint index, jdouble value + JNIEnv *env, jobject obj, jint index, jdouble desired ) { struct channel *channel = channel_get(&analog_out, index); if (! channel) { throwMobergNotOpenException(env, index); + return 0.0; } else { - channel->analog_out.write(channel->analog_out.context, value); + double actual; + channel->analog_out.write(channel->analog_out.context, desired, &actual); + return actual; } } @@ -354,16 +357,19 @@ Java_se_lth_control_realtime_moberg_Moberg_digitalOutClose( } } -JNIEXPORT void JNICALL +JNIEXPORT jboolean JNICALL Java_se_lth_control_realtime_moberg_Moberg_digitalOut( - JNIEnv *env, jobject obj, jint index, jboolean value + JNIEnv *env, jobject obj, jint index, jboolean desired ) { struct channel *channel = channel_get(&digital_out, index); if (! channel) { throwMobergNotOpenException(env, index); + return 0; } else { - channel->digital_out.write(channel->digital_out.context, value); + int actual; + channel->digital_out.write(channel->digital_out.context, desired, &actual); + return actual; } } diff --git a/adaptors/julia/AnalogOut.jl b/adaptors/julia/AnalogOut.jl index a911d103c57c7521c8476953e64e08414052cc39..47ae229ae6661d2386c72d1e86ee110af2b1a1c7 100644 --- a/adaptors/julia/AnalogOut.jl +++ b/adaptors/julia/AnalogOut.jl @@ -29,8 +29,10 @@ function close(aout::AnalogOut) end function write(aout::AnalogOut, value::Cdouble) + result = Ref{Cdouble}(0.0) checkOK(ccall(aout.channel.write, Status, - (Ptr{Nothing}, Cdouble), - aout.channel.context, value)) + (Ptr{Nothing}, Cdouble, Ptr{Cdouble}), + aout.channel.context, value, result)) + return result[]; end diff --git a/adaptors/julia/DigitalOut.jl b/adaptors/julia/DigitalOut.jl index 3c978fbbcb4d9650daf35e503370618ff7cce76a..b65cc1af963bdb243741012178294cf4b00f4801 100644 --- a/adaptors/julia/DigitalOut.jl +++ b/adaptors/julia/DigitalOut.jl @@ -29,8 +29,10 @@ function close(dout::DigitalOut) end function write(dout::DigitalOut, value::Bool) + result = Ref{Cint}(0) checkOK(ccall(dout.channel.write, Status, - (Ptr{Nothing}, Cint), - dout.channel.context, value ? 1 : 0)) + (Ptr{Nothing}, Cint, Ptr{Cint}), + dout.channel.context, value ? 1 : 0, result)) + return result[] != 0 end diff --git a/adaptors/matlab/analogout.c b/adaptors/matlab/analogout.c index a1d5909669a7af86b7cf6d25fdfdb400ea448672..e545ab93cd860c48a222857451a2f43e588c972f 100644 --- a/adaptors/matlab/analogout.c +++ b/adaptors/matlab/analogout.c @@ -136,7 +136,7 @@ static void mdlOutputs(SimStruct *S, int_T tid) for (i = 0 ; i < ssGetNumPWork(S) ; i++) { struct moberg_analog_out *aout = (struct moberg_analog_out*)pwork[i]; - if (! moberg_OK(aout->write(aout->context, *up[i]))) { + if (! moberg_OK(aout->write(aout->context, *up[i], NULL))) { static char error[256]; double *channel = mxGetPr(ssGetSFcnParam(S,1)); sprintf(error, "Failed to write analogout #%d", (int)channel[i]); diff --git a/adaptors/matlab/digitalout.c b/adaptors/matlab/digitalout.c index 97d9a8bac7be2be3e1368449161ebdecf9d9df35..be8d48e9e85e3e9d786797d4b73f7a705519cd81 100644 --- a/adaptors/matlab/digitalout.c +++ b/adaptors/matlab/digitalout.c @@ -136,7 +136,7 @@ static void mdlOutputs(SimStruct *S, int_T tid) for (i = 0 ; i < ssGetNumPWork(S) ; i++) { struct moberg_digital_out *dout = (struct moberg_digital_out*)pwork[i]; - if (! moberg_OK(dout->write(dout->context, *up[i]))) { + if (! moberg_OK(dout->write(dout->context, *up[i], NULL))) { static char error[256]; double *channel = mxGetPr(ssGetSFcnParam(S,1)); sprintf(error, "Failed to write digitalout #%d", (int)channel[i]); diff --git a/adaptors/python/python-moberg.c b/adaptors/python/python-moberg.c index 33dced2f621cbcb786529647b8faee4f2a92ce2e..c00392e16191776529bfeffa16dacf640c4e16f0 100644 --- a/adaptors/python/python-moberg.c +++ b/adaptors/python/python-moberg.c @@ -276,7 +276,7 @@ MobergAnalogIn_read(MobergAnalogInObject *self, PyObject *Py_UNUSED(ignored)) PyErr_Format(PyExc_OSError, "moberg._AnalogIn(%d).read() failed with %d", self->index, status.result); } - return Py_BuildValue("f", value); + return Py_BuildValue("d", value); } static PyMethodDef MobergAnalogIn_methods[] = { @@ -373,19 +373,20 @@ MobergAnalogOut_init(MobergAnalogOutObject *self, PyObject *args, PyObject *kwds static PyObject * MobergAnalogOut_write(MobergAnalogOutObject *self, PyObject *args) { - double value = 1.23; - if (! PyArg_ParseTuple(args, "d", &value)) { + double desired_value, actual_value; + if (! PyArg_ParseTuple(args, "d", &desired_value)) { goto err; } struct moberg_status status = self->channel.write(self->channel.context, - value); + desired_value, + &actual_value); if (!moberg_OK(status)) { PyErr_Format(PyExc_OSError, "moberg._AnalogOut(%d).write() failed with %d", self->index, status.result); goto err; } - Py_INCREF(Py_None); - return Py_None; + + return Py_BuildValue("d", actual_value); err: return NULL; } @@ -588,19 +589,20 @@ MobergDigitalOut_init(MobergDigitalOutObject *self, PyObject *args, PyObject *kw static PyObject * MobergDigitalOut_write(MobergDigitalOutObject *self, PyObject *args) { - double value = 1.23; - if (! PyArg_ParseTuple(args, "d", &value)) { + PyObject *desired; + int actual; + if (! PyArg_ParseTuple(args, "O", &desired)) { goto err; } struct moberg_status status = self->channel.write(self->channel.context, - value); + PyObject_IsTrue(desired), + &actual); if (!moberg_OK(status)) { PyErr_Format(PyExc_OSError, "moberg._DigitalOut(%d).write() failed with %d", self->index, status.result); goto err; } - Py_INCREF(Py_None); - return Py_None; + return Py_BuildValue("O", actual ? Py_True: Py_False); err: return NULL; } diff --git a/moberg.h b/moberg.h index 3023e06717a0a5b6bf9c27d64721c7b9cd7123fd..69c432248a6b51891e96a76d40653790668f9ea1 100644 --- a/moberg.h +++ b/moberg.h @@ -53,7 +53,8 @@ struct moberg_analog_in { struct moberg_analog_out { struct moberg_channel_analog_out *context; struct moberg_status (*write)(struct moberg_channel_analog_out *, - double value); + double desired_value, + double *actual_value); }; struct moberg_digital_in { @@ -65,7 +66,8 @@ struct moberg_digital_in { struct moberg_digital_out { struct moberg_channel_digital_out *context; struct moberg_status (*write)(struct moberg_channel_digital_out *, - int value); + int desired_value, + int *actual_value); }; struct moberg_encoder_in { diff --git a/plugins/comedi/comedi.c b/plugins/comedi/comedi.c index 00a1912950c85d8711197c3f1fe91bb7406e33cc..8755b23f3daac399baed83e9b90bf46dd78533dd 100644 --- a/plugins/comedi/comedi.c +++ b/plugins/comedi/comedi.c @@ -112,16 +112,17 @@ err_errno: static struct moberg_status analog_out_write( struct moberg_channel_analog_out *analog_out, - double value) + double desired_value, + double *actual_value) { struct channel_descriptor descriptor = analog_out->channel_context.descriptor; lsampl_t data; - if (value < descriptor.min) { + if (desired_value < descriptor.min) { data = 0; - } else if (value > descriptor.max) { + } else if (desired_value > descriptor.max) { data = descriptor.maxdata; } else { - data = (value - descriptor.min) / descriptor.delta; + data = (desired_value - descriptor.min) / descriptor.delta; } if (data < 0) { data = 0; @@ -134,6 +135,10 @@ static struct moberg_status analog_out_write( 0, 0, data)) { goto err_errno; } + if (actual_value) { + *actual_value = data * descriptor.delta + descriptor.min; + } + return MOBERG_OK; err_errno: return MOBERG_ERRNO(comedi_errno()); @@ -162,16 +167,20 @@ err_errno: static struct moberg_status digital_out_write( struct moberg_channel_digital_out *digital_out, - int value) + int desired_value, + int *actual_value) { struct channel_descriptor descriptor = digital_out->channel_context.descriptor; - lsampl_t data = value==0?0:1; + lsampl_t data = desired_value==0?0:1; if (0 > comedi_data_write(digital_out->channel_context.device->comedi.handle, descriptor.subdevice, descriptor.subchannel, 0, 0, data)) { goto err_errno; } + if (actual_value) { + *actual_value = data; + } return MOBERG_OK; err_errno: return MOBERG_ERRNO(comedi_errno()); diff --git a/plugins/libtest/libtest.c b/plugins/libtest/libtest.c index c0b6f2c55159826e82ecd55f7e2cd1079c0e5523..8ea3a2167711e38c58927415fc473b229e81fb30 100644 --- a/plugins/libtest/libtest.c +++ b/plugins/libtest/libtest.c @@ -96,11 +96,15 @@ err_einval: static struct moberg_status analog_out_write( struct moberg_channel_analog_out *analog_out, - double value) + double desired_value, + double *actual_value) { struct moberg_channel_context *channel = &analog_out->channel_context; struct moberg_device_context *device = channel->device; - device->analog = value * (channel->index + 1); + device->analog = desired_value * (channel->index + 1); + if (actual_value) { + *actual_value = desired_value; + } return MOBERG_OK; } @@ -120,16 +124,20 @@ err_einval: static struct moberg_status digital_out_write( struct moberg_channel_digital_out *digital_out, - int value) + int desired_value, + int *actual_value) { struct moberg_channel_context *channel = &digital_out->channel_context; struct moberg_device_context *device = channel->device; int mask = (1<<channel->index); - if (value) { + if (desired_value) { device->digital |= mask; } else { device->digital &= ~mask; } + if (actual_value) { + *actual_value = desired_value; + } return MOBERG_OK; } diff --git a/plugins/serial2002/serial2002.c b/plugins/serial2002/serial2002.c index 4017406a4b6604f307a456c3f030286be5db2285..3b6f93268e28950f62aa798f61720e8de592f376 100644 --- a/plugins/serial2002/serial2002.c +++ b/plugins/serial2002/serial2002.c @@ -128,12 +128,13 @@ err_einval: static struct moberg_status analog_out_write( struct moberg_channel_analog_out *analog_out, - double value) + double desired_value, + double *actual_value) { struct moberg_channel_context *channel = &analog_out->channel_context; struct moberg_device_context *device = channel->device; struct analog_map map = device->analog_out.map[channel->index]; - long as_long = (value - map.min) / map.delta; + long as_long = (desired_value - map.min) / map.delta; if (as_long < 0) { as_long = 0; } else if (as_long > map.maxdata) { @@ -141,7 +142,11 @@ static struct moberg_status analog_out_write( } struct serial2002_data data = { is_channel, map.index, as_long }; - return serial2002_write(device->port.fd, data); + struct moberg_status result = serial2002_write(device->port.fd, data); + if (OK(result) && actual_value) { + *actual_value = data.value * map.delta + map.min; + } + return result; } static struct moberg_status digital_in_read( @@ -173,13 +178,18 @@ err_einval: static struct moberg_status digital_out_write( struct moberg_channel_digital_out *digital_out, - int value) + int desired_value, + int *actual_value) { struct moberg_channel_context *channel = &digital_out->channel_context; struct moberg_device_context *device = channel->device; struct digital_map map = device->digital_out.map[channel->index]; - struct serial2002_data data = { is_digital, map.index, value != 0 }; - return serial2002_write(device->port.fd, data); + struct serial2002_data data = { is_digital, map.index, desired_value != 0 }; + struct moberg_status result = serial2002_write(device->port.fd, data); + if (OK(result) && actual_value) { + *actual_value = data.value; + } + return result; } static struct moberg_status encoder_in_read( diff --git a/test/Makefile b/test/Makefile index ec3b973cbfb61e19eb8fd25b3384f41b8eab1f12..50ee3e2374622eb6f38c9760941a259f35d7d9fa 100644 --- a/test/Makefile +++ b/test/Makefile @@ -14,12 +14,13 @@ PYTHON3PATH=$(shell realpath ../adaptors/python/install/usr/lib*/python3*/site-p all: .PHONY: test -test: $(PYTEST:%=run_py_%) $(JULIATEST:%=run_jl_%) $(CTEST:%=run_c_%) +test: $(CTEST:%=run_c_%) $(PYTEST:%=run_py_%) $(JULIATEST:%=run_jl_%) echo Tests run .PHONY: run_c_% run_c_%:build/% $(ENV_TEST) valgrind --leak-check=full ./build/$* + env -i LD_LIBRARY_PATH=../build valgrind --leak-check=full ./build/$* .PHONY: run_py_% run_py_%: %.py diff --git a/test/test_io.c b/test/test_io.c index 72a644b8897901aeeb4c2eef71e1b3adfd94a790..a730a2f48c6971b01864006f4ef3d5496658aaf4 100644 --- a/test/test_io.c +++ b/test/test_io.c @@ -10,7 +10,7 @@ int main(int argc, char *argv[]) } struct moberg_analog_in ai0; struct moberg_analog_out ao0; - double ai0_value; + double ai0_value, ao0_actual; if (! moberg_OK(moberg_analog_in_open(moberg, 0, &ai0))) { fprintf(stderr, "OPEN failed\n"); goto free; @@ -24,11 +24,11 @@ int main(int argc, char *argv[]) fprintf(stderr, "OPEN failed\n"); goto free; } - if (! moberg_OK(ao0.write(ao0.context, ai0_value * 2))) { + if (! moberg_OK(ao0.write(ao0.context, ai0_value * 2, &ao0_actual))) { fprintf(stderr, "READ failed\n"); goto close_ao0; } - fprintf(stderr, "WROTE ao0: %f\n", ai0_value * 2); + fprintf(stderr, "WROTE ao0: %f %f\n", ai0_value * 2, ao0_actual); close_ao0: moberg_analog_out_close(moberg, 0, ao0); close_ai0: diff --git a/test/test_jl.jl b/test/test_jl.jl index 89a7f00e7c07004886d3c885a1f5849ebdae742d..270b88829d9a4ddbb72db85bf2f5ff311edf7f8c 100644 --- a/test/test_jl.jl +++ b/test/test_jl.jl @@ -7,33 +7,32 @@ import MobergIO: read, write function test() m = MobergIO.Moberg() - println(stderr,m) + println(m) for v in -10.0:2.0:10 for i in 0:1 try aout = MobergIO.AnalogOut(m, Unsigned(i)) value = v + i; - write(aout, value) - print("$value ") + actual = write(aout, value) + print("($value, $actual)") catch ex println(stderr,"analog_out $i does not exist $(ex)") end end - println(stderr) - flush(stderr) + println() sleep(0.01) for j in 0:3 try ain = MobergIO.AnalogIn(m, Unsigned(j)) println(stderr,read(ain)) catch ex - println(stderr,"analog_in $j does not exist $(ex)") + println("analog_in $j does not exist $(ex)") end - flush(stderr) + flush(stdout) end - println(stderr) - flush(stderr) + println() + flush(stdout) end for v in false:true for i in 0:6 @@ -43,34 +42,34 @@ function test() write(dout, value) print("$value ") catch ex - println(stderr,"digital_out $i does not exist $(ex)") + println("digital_out $i does not exist $(ex)") end - flush(stderr) + flush(stdout) end - println(stderr) - flush(stderr) + println() + flush(stdout) for i in 0:6 try din = MobergIO.DigitalIn(m, Unsigned(i)) print("$(read(din)) ") catch ex - println(stderr,"digital_in $i does not exist $(ex)") + println("digital_in $i does not exist $(ex)") end - flush(stderr) + flush(stdout) end - println(stderr) - println(stderr) + println() + println() sleep(0.01) end end test() -println(stderr,"DONE") -flush(stderr) +println("DONE") +flush(stdout) GC.gc() -println(stderr,"....") -flush(stderr) +println("....") +flush(stdout) GC.gc() # See https://github.com/JuliaCI/BenchmarkTools.jl/blob/af35d0513fe1e336ad0d8b9a35f924e8461aefa2/src/execution.jl#L1 -println(stderr,"Really DONE") -flush(stderr) +println("Really DONE") +flush(stdout) diff --git a/test/test_start_stop.c b/test/test_start_stop.c index 393d9328350d50aef54094c852b7fddfbb4b9e49..ee0a49a51262b7af609519eb7be2527d0ab0427d 100644 --- a/test/test_start_stop.c +++ b/test/test_start_stop.c @@ -3,11 +3,13 @@ int main(int argc, char *argv[]) { + fprintf(stderr, "NEW\n"); struct moberg *moberg = moberg_new(NULL); - printf("START:\n"); + fprintf(stderr, "START:\n"); moberg_start(moberg, stdout); - printf("STOP:\n"); + fprintf(stderr, "STOP:\n"); moberg_stop(moberg, stdout); - printf("DONE\n"); + fprintf(stderr, "FREE\n"); moberg_free(moberg); + fprintf(stderr, "DONE\n"); }