Skip to content

Commit

Permalink
Merge pull request #2 from tim-schoenmackers/add-swdevice-notifications
Browse files Browse the repository at this point in the history
Enable software devices to send and receive notifications
  • Loading branch information
sreyero authored Sep 17, 2021
2 parents ce38155 + 7294d8b commit 5b44183
Show file tree
Hide file tree
Showing 4 changed files with 485 additions and 2 deletions.
82 changes: 82 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,88 @@ functions follow this approach when possible.
value for the `projector.keystone` function, but we expose these functions
for consistency with the rest of the API.

### Software Devices

Recent versions of `SoHal` allow specifically written pieces of software to
register themselves on SoHal as a Software Device. These devices inform
`SoHal` as to which functions they implement, and allow a `SoHal` client
to connect to the software device and call those functions. Because the
data is passed between SoHal and the software device via JSONRPC, the data
must be serializable. An example of a software device (adder) that
implements a few sample functions can be found in the swdevices subfolder.
The functions that the sample device implements is defined in the
`adder.json` file within that subfolder. Function parameters that can be
modeled as c-style structs can also be passed between a software device
client and server by defining the data type as a json schema.
Examples of these schemas can be found in the `swdevices\schemas` subfolder.

A complete example `adder` software device is located in the `swdevices`
subfolder. To compile the adder software device, first compile the hippo
library by opening & compiling the `win\hippo.sln` project. Then open a
console window and cd to the `swdevices` subfolder and type:


```
python gen_cpp.py --json adder.json --schemas schemas
```

This will run a python script that creates two files:

1. `swdevices\src\adder.cc`
2. `swdevices\include\adder.h`

After these two files are created, open the `swdevces\hippo_swdevices.sln"
solution and compile both the client and server projects. This will create
a software device server that can connect to and register itelf with SoHal,
and a client that will call into the server to perform various tasks.

To use the software device the user should perform the following steps in order:

1. Launch `SoHal`
2. Launch the compiled `swdevices_server.exe`
3. Launch the compiled `swdevices_client.exe`

A more complete client/server `adder` software device can be found in the
`test\test_swdevice.cc` file. In this case a `Blackadder` server class registers
on `SoHal` and an `adder` client connects to the `Blackadder` server to call even
more functions than the example shown in the `swdevices` subfolder.

### Notifications

`hiPPo` now allows Software Device servers to send notifications to clients.
In order to do so, the software device server can call the `SendNotification`
function. Currently the notification sends a notification name, and an
optional parameter as part of the notification. The data types that the
parameter can contain is limited to the following types:

1. `int`
2. `float`
3. `bool`
4. `c-style strings` passed in via null terminated char*
5. `wcharptr` type
6. `b64bytes` type
7. no parameter

Internally, the server will add an `<SoftwareDeviceName>.on_` to the notification
name, i.e. calling

`SendNotification("slow_call","tick")`

from an `adder` software device server will result in the client receiving a
notification

`adder.on_slow_call` with a `SWDeviceNotificationParam` parameter that contains
`tick` in the charData field.

In order for the software device client to receive notifications it must be
subscribed to the notifications. This can be achieved via a call to `subscribe`.
The client must know the type of parameter for each notification, as a
`SWDeviceNotificationParam` will load as many of its fields with the parameter
data as is possible.

An example of the `Blackadder` software device server sending notifications
every 1 second to the client can be found in the `test\test_swdevice.cc` file.


### No exceptions thrown

Expand Down
68 changes: 68 additions & 0 deletions include/hippo_swdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,36 @@ class DLLEXPORT b64bytes {
uint64_t resize(size_t len);
};

class DLLEXPORT SWDeviceNotificationParam {
public:
SWDeviceNotificationParam();
~SWDeviceNotificationParam();

// the name of the notification (up to 128 chars)
char *methodName;

// The various types of data that the parameter could be
// Note: if the JSON library indicates that the
// parameter is not valid then that particular field is not filled

// the data as a uint32 type
uint32_t uint32Data;

// the data as a float type
float floatData;

// the data as boolean type
bool boolData;

// the data as a char type
char* charData;

// the data as a wcharptr type
wcharptr wcharData;

// the data as a b64bytes type
b64bytes b64bytesData;
};

class DLLEXPORT HippoSwDevice : public HippoDevice {
public:
Expand All @@ -58,13 +88,39 @@ class DLLEXPORT HippoSwDevice : public HippoDevice {

uint64_t disconnect_device(void);

// subscribe to notifications
uint64_t subscribe(void(*callback)(const SWDeviceNotificationParam &param,
void *data),
void *data);
uint64_t subscribe(void(*callback)(const SWDeviceNotificationParam &param,
void *data),
void *data, uint32_t *get);

// unsubscribe from notifications
uint64_t unsubscribe();
uint64_t unsubscribe(uint32_t *get);

protected:
uint64_t connect_device(const char *json);

void WaitForCommand(void);
virtual uint64_t ProcessCommand(const char *method, void *params,
void *result);

uint64_t SendNotification(const char *notificationName);
uint64_t SendNotification(const char *notificationName,
int32_t param);
uint64_t SendNotification(const char *notificationName,
float param);
uint64_t SendNotification(const char *notificationName,
bool param);
uint64_t SendNotification(const char *notificationName,
char* param);
uint64_t SendNotification(const char *notificationName,
wcharptr* param);
uint64_t SendNotification(const char *notificationName,
b64bytes* param);

uint64_t int32_t_c2json(const int32_t &set, void *obj);
uint64_t int32_t_json2c(const void *obj, int32_t *get);
uint64_t float_c2json(const float &set, void *obj);
Expand All @@ -77,6 +133,18 @@ class DLLEXPORT HippoSwDevice : public HippoDevice {
uint64_t b64bytes_c2json(const b64bytes &set, void *obj);
uint64_t b64bytes_json2c(const void *obj, b64bytes *get);

// Callback items
void ProcessSignal(char *method, void *obj) override;
bool HasRegisteredCallback();

void(*callback_)(const SWDeviceNotificationParam &param, void *data);


private:
// private function that actually sends notifications
// this is called by the protected functions that take specific types in
uint64_t SendNotification(const char *method, const void *param);

private:
HippoWS *wsCmd_;
std::thread *cmd_th_;
Expand Down
Loading

0 comments on commit 5b44183

Please sign in to comment.