Skip to content

Commit

Permalink
Resolves stepjam#59. Added signaling.
Browse files Browse the repository at this point in the history
  • Loading branch information
stepjam committed Dec 15, 2019
1 parent d73febc commit 8464e5a
Show file tree
Hide file tree
Showing 4 changed files with 234 additions and 0 deletions.
100 changes: 100 additions & 0 deletions pyrep/backend/sim.py
Original file line number Diff line number Diff line change
Expand Up @@ -1051,3 +1051,103 @@ def simGetSimulationTime():
time = lib.simGetSimulationTime()
_check_return(time)
return time


def simSetIntegerSignal(signalName, signalValue):
ret = lib.simSetIntegerSignal(signalName.encode('ascii'), signalValue)
_check_return(ret)


def simGetIntegerSignal(signalName):
val = ffi.new('int*')
ret = lib.simGetIntegerSignal(signalName.encode('ascii'), val)
_check_return(ret)
return ret, val[0]


def simClearIntegerSignal(signalName):
ret = lib.simClearIntegerSignal(signalName.encode('ascii'))
_check_return(ret)
return ret


def simSetFloatSignal(signalName, signalValue):
ret = lib.simSetFloatSignal(signalName.encode('ascii'), signalValue)
_check_return(ret)


def simGetFloatSignal(signalName):
val = ffi.new('float*')
ret = lib.simGetFloatSignal(signalName.encode('ascii'), val)
_check_return(ret)
return ret, val[0]


def simClearFloatSignal(signalName):
ret = lib.simClearFloatSignal(signalName.encode('ascii'))
_check_return(ret)
return ret


def simSetDoubleSignal(signalName, signalValue):
ret = lib.simSetDoubleSignal(signalName.encode('ascii'), signalValue)
_check_return(ret)


def simGetDoubleSignal(signalName):
val = ffi.new('double*')
ret = lib.simGetDoubleSignal(signalName.encode('ascii'), val)
_check_return(ret)
return ret, val[0]


def simClearDoubleSignal(signalName):
ret = lib.simClearDoubleSignal(signalName.encode('ascii'))
_check_return(ret)
return ret


def simSetStringSignal(signalName, signalValue):
ret = lib.simSetStringSignal(
signalName.encode('ascii'), signalValue.encode('ascii'),
len(signalValue))
_check_return(ret)


def simGetStringSignal(signalName):
valLen = ffi.new('int*')
str_ret = lib.simGetStringSignal(signalName.encode('ascii'), valLen)
if str_ret == ffi.NULL:
# No value.
return 0, None
val = ffi.string(str_ret[0:valLen[0]]).decode('utf-8')
simReleaseBuffer(ffi.cast('char *', str_ret))
return 1, val


def simClearStringSignal(signalName):
ret = lib.simClearStringSignal(signalName.encode('ascii'))
_check_return(ret)
return ret


def simSetUserParameter(objectHandle, parameterName, parameterValue):
# TODO: currently not used by PyRep.
# User params functionality missing in CoppeliaSim.
parameterLength = len(parameterValue)
ret = lib.simSetUserParameter(
objectHandle, parameterName.encode('ascii'),
parameterValue.encode('ascii'), parameterLength)
_check_return(ret)


def simGetUserParameter(objectHandle, parameterName):
# TODO: currently not used by PyRep.
# User params functionality missing in CoppeliaSim.
parameterLength = ffi.new('int*')
parameterValue = lib.simGetUserParameter(
objectHandle, parameterName.encode('ascii'), parameterLength)
_check_null_return(parameterValue)
val = ffi.string((parameterValue[0][:parameterLength[0]])).decode('utf-8')
simReleaseBuffer(ffi.cast('char *', parameterValue))
return val
102 changes: 102 additions & 0 deletions pyrep/misc/signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
from pyrep.errors import PyRepError
from pyrep.backend import sim
from typing import Any


class Signal(object):
"""Signals can be seen as global variables.
Four types of signals are currently supported:
integer-, floating-, double-, and string-type signals.
Signals can be defined, redefined, read and cleared.
"""

def __init__(self, name):
self._name = name

def set(self, value) -> None:
"""Sets the value of this signal.
:param value: The value of the signal.
"""
pass

def get(self) -> Any:
"""Gets the value of this signal.
:raises PyRepError if signal does not exist.
:return: The value of the signal.
"""
pass

def clear(self) -> int:
"""Clears the value of this signal.
:return: The number of signals cleared. Either 0 or 1.
"""
pass

def _check_signal(self, value: int, type_name: str) -> None:
if value == 0:
raise PyRepError('Signal %s of type %s does not exist.' % (
self._name, type_name))


class IntegerSignal(Signal):
"""An integer-type signal."""

def set(self, value) -> None:
sim.simSetIntegerSignal(self._name, value)

def get(self) -> int:
ret, value = sim.simGetIntegerSignal(self._name)
self._check_signal(ret, 'int')
return value

def clear(self) -> int:
return sim.simClearIntegerSignal(self._name)


class FloatSignal(Signal):
"""An float-type signal."""

def set(self, value) -> None:
sim.simSetFloatSignal(self._name, value)

def get(self) -> float:
ret, value = sim.simGetFloatSignal(self._name)
self._check_signal(ret, 'float')
return value

def clear(self) -> int:
return sim.simClearFloatSignal(self._name)


class DoubleSignal(Signal):
"""An double-type signal."""

def set(self, value) -> None:
sim.simSetDoubleSignal(self._name, value)

def get(self) -> float:
ret, value = sim.simGetDoubleSignal(self._name)
self._check_signal(ret, 'double')
return value

def clear(self) -> int:
return sim.simClearDoubleSignal(self._name)


class StringSignal(Signal):
"""An string-type signal."""

def set(self, value) -> None:
sim.simSetStringSignal(self._name, value)

def get(self) -> str:
ret, value = sim.simGetStringSignal(self._name)
self._check_signal(ret, 'string')
return value

def clear(self) -> int:
return sim.simClearStringSignal(self._name)
Binary file modified tests/assets/test_scene.ttt
Binary file not shown.
32 changes: 32 additions & 0 deletions tests/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
from pyrep.errors import PyRepError
from tests.core import TestCore
from pyrep.misc.distance import Distance
from pyrep.misc.signals import IntegerSignal, FloatSignal
from pyrep.misc.signals import DoubleSignal, StringSignal


# TODO: These tests will be re-enabled once bug has been fixed in CoppeliaSim.
Expand All @@ -22,5 +24,35 @@ class TestMisc(TestCore):
# d.read()


class TestSignal(TestCore):

SIGNALS = [
(IntegerSignal, 99),
(FloatSignal, 55.3),
(DoubleSignal, 22.2),
(StringSignal, 'hello')
]

def test_set_get_clear_signals(self):
for signal_class, test_value in TestSignal.SIGNALS:
with self.subTest(signal=str(signal_class)):
sig = signal_class('my_signal')
sig.set(test_value)
ret_value = sig.get()
if isinstance(test_value, float):
self.assertAlmostEqual(ret_value, test_value, places=3)
else:
self.assertEqual(ret_value, test_value)
clears = sig.clear()
self.assertEqual(clears, 1)

def test_get_signal_fails_when_empty(self):
for signal_class, test_value in TestSignal.SIGNALS:
with self.subTest(signal=str(signal_class)):
sig = signal_class('my_signal')
with self.assertRaises(PyRepError):
sig.get()


if __name__ == '__main__':
unittest.main()

0 comments on commit 8464e5a

Please sign in to comment.