added webserver
This commit is contained in:
251
software/pc_client/doc/api-doc.md
Normal file
251
software/pc_client/doc/api-doc.md
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
# Websockets Interface documentation
|
||||||
|
All requests and responses are sent as json objects.
|
||||||
|
|
||||||
|
## Request
|
||||||
|
Every request must conatin at least one value: `command`
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"command": "<command>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
### Device manager commands
|
||||||
|
|
||||||
|
#### Save config `dm_save`
|
||||||
|
Saves config to ./flapconfig.json.
|
||||||
|
|
||||||
|
Request:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"command": "dm_load"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Response:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"ack": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
#### Load config `dm_load`
|
||||||
|
Loads config from ./flapconfig.json.
|
||||||
|
|
||||||
|
Request:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"command": "dm_load"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Response:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"ack": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
#### Dump config `dm_dump`
|
||||||
|
Dumps current config to socket.
|
||||||
|
|
||||||
|
Request:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"command": "dm_dump"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Response:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"devices_all": <registered device count>
|
||||||
|
"devices_online": <online device count>,
|
||||||
|
"devices": <array of all devices>,
|
||||||
|
"map": <2D array of device locations>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Describe single device `dm_describe`
|
||||||
|
Gets all information for specified device id.
|
||||||
|
|
||||||
|
Request:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"command": "dm_describe",
|
||||||
|
"id": <device id>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Response:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
#### Register new device `dm_register`
|
||||||
|
Register device, assign new id and assign a location.
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"command": "dm_describe",
|
||||||
|
"address": <device nus address>,
|
||||||
|
"x": <x position on screen>,
|
||||||
|
"y": <y position on screen>,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Response:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"id": <assigned device id>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Remove device from config `dm_remove`
|
||||||
|
Removes device from config and frees location in screen
|
||||||
|
|
||||||
|
Request:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"command": "dm_remove",
|
||||||
|
"id": <device id>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Response:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"ack": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Remove device from config `dm_refresh`
|
||||||
|
Refresh device config
|
||||||
|
|
||||||
|
Request:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"command": "dm_refresh"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Response:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"devices_online": <online device count>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Device raw commands
|
||||||
|
|
||||||
|
#### Ping module `dr_ping`
|
||||||
|
Checks if a module reponds on the given address.
|
||||||
|
|
||||||
|
Request:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"command": "dr_ping",
|
||||||
|
"address": <address>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Response:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"success": <boolean: if device reponded 'true', else 'false'>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Set module address `dr_setaddress`
|
||||||
|
Changes the hardware address of an module.
|
||||||
|
|
||||||
|
Request:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"command": "dr_setaddress",
|
||||||
|
"address": <address>,
|
||||||
|
"newaddress": <new address>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Response:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"success": <boolean: if success 'true', else 'false'>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Set module offset calibration `dr_setcalibration`
|
||||||
|
Sets the offset calibration for an module.
|
||||||
|
|
||||||
|
Request:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"command": "dr_setcalibration",
|
||||||
|
"address": <address>,
|
||||||
|
"calibration": <calibration value (default: 1800)>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Response:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"success": <boolean: if success 'true', else 'false'>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Reset module `dr_reset`
|
||||||
|
Resets the controller of an module
|
||||||
|
|
||||||
|
Request:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"command": "dr_reset",
|
||||||
|
"address": <address>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Response:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"ack": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Display flap `dr_display`
|
||||||
|
Sets the module to the specified flap directly or with recalibration.
|
||||||
|
|
||||||
|
Request:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"command": "dr_display",
|
||||||
|
"address": <address>,
|
||||||
|
"flap": <flap-number>,
|
||||||
|
("full": <boolean: full rotation of drum/recalibration>)
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Response:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"ack": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Power module on/off `dr_power`
|
||||||
|
Sets the power-state for the motor of the given module.
|
||||||
|
|
||||||
|
Request:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"command": "dr_power",
|
||||||
|
"address": <address>,
|
||||||
|
"power": <boolean: power on>
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Response:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"ack": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Responses
|
||||||
|
### Error:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"error": "<error name>",
|
||||||
|
"detail": "<more detailed error message>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
The following responses are valid:
|
||||||
|
- `parsing error`: the json request is malformated and cannot be parsed
|
||||||
|
- `format error`: the json object is missing required fields. Check details for more information.
|
||||||
|
- `internal error`: an internal error occured. This should not happen. Chaeck server logs.
|
||||||
|
|
||||||
416
software/pc_client/src/console.c
Normal file
416
software/pc_client/src/console.c
Normal file
@@ -0,0 +1,416 @@
|
|||||||
|
#include "console.h"
|
||||||
|
|
||||||
|
const char *device_config_file = "./flapconfig.json";
|
||||||
|
int fd;
|
||||||
|
// command handlers
|
||||||
|
|
||||||
|
// dump config/ all devices
|
||||||
|
void cmd_dm_dump(json_object *req, json_object *res)
|
||||||
|
{
|
||||||
|
devicemgr_printDetailsAll(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
// describe single device
|
||||||
|
void cmd_dm_describe(json_object *req, json_object *res)
|
||||||
|
{
|
||||||
|
json_object *id;
|
||||||
|
if (json_object_object_get_ex(req, "id", &id))
|
||||||
|
{
|
||||||
|
devicemgr_printDetails(json_object_get_int(id), res);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "error", json_object_new_string("format error"));
|
||||||
|
json_object_object_add(res, "detail", json_object_new_string("missing key: id"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// register new device
|
||||||
|
void cmd_dm_register(json_object *req, json_object *res)
|
||||||
|
{
|
||||||
|
json_object *jaddress, *jx, *jy;
|
||||||
|
int address, x, y;
|
||||||
|
if (!json_object_object_get_ex(req, "address", &jaddress))
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "error", json_object_new_string("format error"));
|
||||||
|
json_object_object_add(res, "detail", json_object_new_string("missing key: address"));
|
||||||
|
}
|
||||||
|
else if (!json_object_object_get_ex(req, "x", &jx))
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "error", json_object_new_string("format error"));
|
||||||
|
json_object_object_add(res, "detail", json_object_new_string("missing key: x"));
|
||||||
|
}
|
||||||
|
else if (!json_object_object_get_ex(req, "y", &jy))
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "error", json_object_new_string("format error"));
|
||||||
|
json_object_object_add(res, "detail", json_object_new_string("missing key: y"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
address = json_object_get_int(jaddress);
|
||||||
|
x = json_object_get_int(jx);
|
||||||
|
y = json_object_get_int(jy);
|
||||||
|
|
||||||
|
printf("[INFO][console] register new device wit addr %i at (%i,%i)", address, x, y);
|
||||||
|
|
||||||
|
int newId = devicemgr_register(fd, address, x, y, -1);
|
||||||
|
json_object_object_add(res, "id", json_object_new_int(newId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// refresh all devices
|
||||||
|
void cmd_dm_refresh(json_object *req, json_object *res)
|
||||||
|
{
|
||||||
|
int devices_online = devicemgr_refresh();
|
||||||
|
json_object_object_add(res, "devices_online", json_object_new_int(devices_online));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// remove device
|
||||||
|
void cmd_dm_remove(json_object *req, json_object *res)
|
||||||
|
{
|
||||||
|
json_object *jid;
|
||||||
|
int id;
|
||||||
|
if (!json_object_object_get_ex(req, "id", &jid))
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "error", json_object_new_string("format error"));
|
||||||
|
json_object_object_add(res, "detail", json_object_new_string("missing key: id"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
id = json_object_get_int(jid);
|
||||||
|
devicemgr_remove(id);
|
||||||
|
json_object_object_add(res, "ack", json_object_new_boolean(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// save all devices
|
||||||
|
void cmd_dm_save(json_object *req, json_object *res)
|
||||||
|
{
|
||||||
|
devicemgr_save(device_config_file);
|
||||||
|
json_object_object_add(res, "ack", json_object_new_boolean(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
// load all devices
|
||||||
|
void cmd_dm_load(json_object *req, json_object *res)
|
||||||
|
{
|
||||||
|
devicemgr_load(device_config_file);
|
||||||
|
json_object_object_add(res, "ack", json_object_new_boolean(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// print string on display
|
||||||
|
void cmd_dm_print(json_object *req, json_object *res)
|
||||||
|
{
|
||||||
|
json_object *jx = json_object_object_get(req, "x");
|
||||||
|
json_object *jy = json_object_object_get(req, "y");
|
||||||
|
json_object *jstr = json_object_object_get(req, "string");
|
||||||
|
if (jx == NULL)
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "error", json_object_new_string("format error"));
|
||||||
|
json_object_object_add(res, "detail", json_object_new_string("missing key: x"));
|
||||||
|
}
|
||||||
|
else if (jy == NULL)
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "error", json_object_new_string("format error"));
|
||||||
|
json_object_object_add(res, "detail", json_object_new_string("missing key: y"));
|
||||||
|
}
|
||||||
|
else if (jstr == NULL)
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "error", json_object_new_string("format error"));
|
||||||
|
json_object_object_add(res, "detail", json_object_new_string("missing key: string"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int x = json_object_get_int(jx);
|
||||||
|
int y = json_object_get_int(jy);
|
||||||
|
char *str = json_object_get_string(jstr);
|
||||||
|
devicemgr_printText(str, x, y);
|
||||||
|
json_object_object_add(res, "ack", json_object_new_boolean(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set flap on display
|
||||||
|
void cmd_dm_print_single(json_object *req, json_object *res)
|
||||||
|
{
|
||||||
|
json_object *jx = json_object_object_get(req, "x");
|
||||||
|
json_object *jy = json_object_object_get(req, "y");
|
||||||
|
json_object *jflap = json_object_object_get(req, "flap");
|
||||||
|
if (jx == NULL)
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "error", json_object_new_string("format error"));
|
||||||
|
json_object_object_add(res, "detail", json_object_new_string("missing key: x"));
|
||||||
|
}
|
||||||
|
else if (jy == NULL)
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "error", json_object_new_string("format error"));
|
||||||
|
json_object_object_add(res, "detail", json_object_new_string("missing key: y"));
|
||||||
|
}
|
||||||
|
else if (jflap == NULL)
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "error", json_object_new_string("format error"));
|
||||||
|
json_object_object_add(res, "detail", json_object_new_string("missing key: string"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int x = json_object_get_int(jx);
|
||||||
|
int y = json_object_get_int(jy);
|
||||||
|
int flap = json_object_get_int(jflap);
|
||||||
|
|
||||||
|
devicemgr_printFlap(flap, x, y);
|
||||||
|
json_object_object_add(res, "ack", json_object_new_boolean(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ping device
|
||||||
|
void cmd_dr_ping(json_object *req, json_object *res)
|
||||||
|
{
|
||||||
|
json_object *jaddr = json_object_object_get(req, "address");
|
||||||
|
if (jaddr == NULL)
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "error", json_object_new_string("format error"));
|
||||||
|
json_object_object_add(res, "detail", json_object_new_string("missing key: address"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (sfbus_ping(fd, json_object_get_int(jaddr)) == 0)
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "success", json_object_new_boolean(true));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "success", json_object_new_boolean(false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set device address
|
||||||
|
void cmd_dr_setaddress(json_object *req, json_object *res)
|
||||||
|
{
|
||||||
|
json_object *jaddr = json_object_object_get(req, "address");
|
||||||
|
json_object *jaddrn = json_object_object_get(req, "newaddress");
|
||||||
|
if (jaddr == NULL)
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "error", json_object_new_string("format error"));
|
||||||
|
json_object_object_add(res, "detail", json_object_new_string("missing key: address"));
|
||||||
|
}
|
||||||
|
else if (jaddrn == NULL)
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "error", json_object_new_string("format error"));
|
||||||
|
json_object_object_add(res, "detail", json_object_new_string("missing key: newaddress"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (sfbusu_write_address(fd, json_object_get_int(jaddr), json_object_get_int(jaddrn)) == 0)
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "success", json_object_new_boolean(true));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "success", json_object_new_boolean(false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmd_dr_setcalibration(json_object *req, json_object *res)
|
||||||
|
{
|
||||||
|
json_object *jaddr = json_object_object_get(req, "address");
|
||||||
|
json_object *jcal = json_object_object_get(req, "calibration");
|
||||||
|
if (jaddr == NULL)
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "error", json_object_new_string("format error"));
|
||||||
|
json_object_object_add(res, "detail", json_object_new_string("missing key: address"));
|
||||||
|
}
|
||||||
|
else if (jcal == NULL)
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "error", json_object_new_string("format error"));
|
||||||
|
json_object_object_add(res, "detail", json_object_new_string("missing key: calibration"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (sfbusu_write_calibration(fd, json_object_get_int(jaddr), json_object_get_int(jcal)) == 0)
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "success", json_object_new_boolean(true));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "success", json_object_new_boolean(false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmd_dr_reset(json_object *req, json_object *res)
|
||||||
|
{
|
||||||
|
json_object *jaddr = json_object_object_get(req, "address");
|
||||||
|
if (jaddr == NULL)
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "error", json_object_new_string("format error"));
|
||||||
|
json_object_object_add(res, "detail", json_object_new_string("missing key: address"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sfbus_reset_device(fd, json_object_get_int(jaddr));
|
||||||
|
json_object_object_add(res, "ack", json_object_new_boolean(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmd_dr_display(json_object *req, json_object *res)
|
||||||
|
{
|
||||||
|
json_object *jaddr = json_object_object_get(req, "address");
|
||||||
|
json_object *jflap = json_object_object_get(req, "flap");
|
||||||
|
json_object *jfullrot = json_object_object_get(req, "full");
|
||||||
|
if (jaddr == NULL)
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "error", json_object_new_string("format error"));
|
||||||
|
json_object_object_add(res, "detail", json_object_new_string("missing key: address"));
|
||||||
|
}
|
||||||
|
else if (jflap == NULL)
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "error", json_object_new_string("format error"));
|
||||||
|
json_object_object_add(res, "detail", json_object_new_string("missing key: flap"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (jfullrot == NULL)
|
||||||
|
{
|
||||||
|
sfbus_display(fd, json_object_get_int(jaddr), json_object_get_int(jflap));
|
||||||
|
}
|
||||||
|
else if (json_object_get_boolean(jfullrot) == false)
|
||||||
|
{
|
||||||
|
sfbus_display(fd, json_object_get_int(jaddr), json_object_get_int(jflap));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sfbus_display_full(fd, json_object_get_int(jaddr), json_object_get_int(jflap));
|
||||||
|
}
|
||||||
|
json_object_object_add(res, "ack", json_object_new_boolean(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmd_dr_power(json_object *req, json_object *res)
|
||||||
|
{
|
||||||
|
json_object *jaddr = json_object_object_get(req, "address");
|
||||||
|
json_object *jpower = json_object_object_get(req, "power");
|
||||||
|
if (jaddr == NULL)
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "error", json_object_new_string("format error"));
|
||||||
|
json_object_object_add(res, "detail", json_object_new_string("missing key: address"));
|
||||||
|
}
|
||||||
|
else if (jpower == NULL)
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "error", json_object_new_string("format error"));
|
||||||
|
json_object_object_add(res, "detail", json_object_new_string("missing key: power"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (json_object_get_boolean(jpower) == false)
|
||||||
|
{
|
||||||
|
sfbus_motor_power(fd, json_object_get_int(jaddr), 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sfbus_motor_power(fd, json_object_get_int(jaddr), 1);
|
||||||
|
}
|
||||||
|
json_object_object_add(res, "ack", json_object_new_boolean(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// command parser
|
||||||
|
json_object *parse_command(json_object *req)
|
||||||
|
{
|
||||||
|
json_object *commandObj;
|
||||||
|
json_object *res = json_object_new_object();
|
||||||
|
json_object_object_get_ex(req, "command", &commandObj);
|
||||||
|
char *command = json_object_get_string(commandObj);
|
||||||
|
free(commandObj);
|
||||||
|
// command 'table'
|
||||||
|
if (strcmp(command, "dm_dump") == 0)
|
||||||
|
{
|
||||||
|
cmd_dm_dump(req, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
else if (strcmp(command, "dm_describe") == 0)
|
||||||
|
{
|
||||||
|
cmd_dm_describe(req, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
else if (strcmp(command, "dm_register") == 0)
|
||||||
|
{
|
||||||
|
cmd_dm_register(req, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
else if (strcmp(command, "dm_remove") == 0)
|
||||||
|
{
|
||||||
|
cmd_dm_remove(req, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
else if (strcmp(command, "dm_refresh") == 0)
|
||||||
|
{
|
||||||
|
cmd_dm_refresh(req, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
else if (strcmp(command, "dm_save") == 0)
|
||||||
|
{
|
||||||
|
cmd_dm_save(req, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
else if (strcmp(command, "dm_load") == 0)
|
||||||
|
{
|
||||||
|
cmd_dm_load(req, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
else if (strcmp(command, "dm_print") == 0)
|
||||||
|
{
|
||||||
|
cmd_dm_print(req, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
else if (strcmp(command, "dr_ping") == 0)
|
||||||
|
{
|
||||||
|
cmd_dr_ping(req, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
else if (strcmp(command, "dr_setaddress") == 0)
|
||||||
|
{
|
||||||
|
cmd_dr_setaddress(req, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
else if (strcmp(command, "dr_setcalibration") == 0)
|
||||||
|
{
|
||||||
|
cmd_dr_setcalibration(req, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
else if (strcmp(command, "dr_reset") == 0)
|
||||||
|
{
|
||||||
|
cmd_dr_reset(req, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
else if (strcmp(command, "dr_display") == 0)
|
||||||
|
{
|
||||||
|
cmd_dr_display(req, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
else if (strcmp(command, "dr_power") == 0)
|
||||||
|
{
|
||||||
|
cmd_dr_power(req, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
json_object_object_add(res, "error", json_object_new_string("invalid command"));
|
||||||
|
json_object_object_add(res, "detail", json_object_new_string(""));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void start_console(int _fd)
|
||||||
|
{
|
||||||
|
fd = _fd;
|
||||||
|
// init device manager
|
||||||
|
devicemgr_init(fd);
|
||||||
|
// start server
|
||||||
|
start_webserver(&parse_command);
|
||||||
|
}
|
||||||
6
software/pc_client/src/console.h
Normal file
6
software/pc_client/src/console.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#include "devicemgr.h"
|
||||||
|
#include "sfbus-util.h"
|
||||||
|
#include "wsserver.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void start_console();
|
||||||
@@ -3,15 +3,19 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file provides an abstraction layer to access many devices
|
* This section provides an abstraction layer to access many devices
|
||||||
* simultaneously. by Dennis Gunia - 2025 - wwwm.dennisgunia.de
|
* simultaneously.
|
||||||
|
*
|
||||||
|
* by Dennis Gunia - 2025 - www.dennisgunia.de
|
||||||
*/
|
*/
|
||||||
enum SFDEVICE_STATE
|
enum SFDEVICE_STATE
|
||||||
{
|
{
|
||||||
|
UNALLOCATED,
|
||||||
NEW,
|
NEW,
|
||||||
OFFLINE,
|
OFFLINE,
|
||||||
ONLINE,
|
ONLINE,
|
||||||
FAILED
|
FAILED,
|
||||||
|
REMOVED
|
||||||
};
|
};
|
||||||
enum SFDEVICE_POWER
|
enum SFDEVICE_POWER
|
||||||
{
|
{
|
||||||
@@ -25,6 +29,7 @@ struct SFDEVICE
|
|||||||
int pos_x;
|
int pos_x;
|
||||||
int pos_y;
|
int pos_y;
|
||||||
u_int16_t address;
|
u_int16_t address;
|
||||||
|
u_int16_t calibration;
|
||||||
int rs485_descriptor;
|
int rs485_descriptor;
|
||||||
double reg_voltage;
|
double reg_voltage;
|
||||||
u_int32_t reg_counter;
|
u_int32_t reg_counter;
|
||||||
@@ -38,21 +43,23 @@ enum
|
|||||||
{
|
{
|
||||||
SFDEVICE_MAXDEV = 128,
|
SFDEVICE_MAXDEV = 128,
|
||||||
SFDEVICE_MAX_X = 20,
|
SFDEVICE_MAX_X = 20,
|
||||||
SFDEVICE_MAX_Y = 4
|
SFDEVICE_MAX_Y = 4,
|
||||||
|
JSON_MAX_LINE_LEN = 256
|
||||||
};
|
};
|
||||||
|
|
||||||
// next free slot to register device
|
// next free slot to register device
|
||||||
int nextFreeSlot = -1;
|
int nextFreeSlot = -1;
|
||||||
int deviceMap[SFDEVICE_MAX_X][SFDEVICE_MAX_Y];
|
int deviceMap[SFDEVICE_MAX_X][SFDEVICE_MAX_Y];
|
||||||
|
int deviceFd;
|
||||||
struct SFDEVICE devices[SFDEVICE_MAXDEV];
|
struct SFDEVICE devices[SFDEVICE_MAXDEV];
|
||||||
|
|
||||||
const char *symbols[45] = {" ", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
|
const char *symbols[45] = {" ", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
|
||||||
"O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "Ä", "Ö", "Ü",
|
"O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "Ä", "Ö", "Ü",
|
||||||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ".", "-", "?", "!"};
|
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ".", "-", "?", "!"};
|
||||||
|
|
||||||
void devicemgr_init()
|
void devicemgr_init(int fd)
|
||||||
{
|
{
|
||||||
|
deviceFd = fd;
|
||||||
// reserve memory buffer
|
// reserve memory buffer
|
||||||
for (int y = 0; y < SFDEVICE_MAX_Y; y++)
|
for (int y = 0; y < SFDEVICE_MAX_Y; y++)
|
||||||
{
|
{
|
||||||
@@ -61,10 +68,17 @@ void devicemgr_init()
|
|||||||
deviceMap[x][y] = -1; //all empty slots are -1
|
deviceMap[x][y] = -1; //all empty slots are -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (int ix = 0; ix < SFDEVICE_MAXDEV; ix++)
|
||||||
|
{
|
||||||
|
devices[ix].address = 0; // Adress 0 is only used for new units. should never be used for active unit
|
||||||
|
devices[ix].deviceState = UNALLOCATED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int devicemgr_readStatus(int device_id)
|
int devicemgr_readStatus(int device_id)
|
||||||
{
|
{
|
||||||
|
if (devices[device_id].address > 0)
|
||||||
|
{ // only if defined
|
||||||
double _voltage = 0;
|
double _voltage = 0;
|
||||||
u_int32_t _counter = 0;
|
u_int32_t _counter = 0;
|
||||||
u_int8_t _status =
|
u_int8_t _status =
|
||||||
@@ -86,6 +100,35 @@ int devicemgr_readStatus(int device_id)
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int devicemgr_readCalib(int device_id)
|
||||||
|
{
|
||||||
|
if (devices[device_id].deviceState == ONLINE)
|
||||||
|
{
|
||||||
|
char *buffer_r = malloc(256);
|
||||||
|
if (sfbus_read_eeprom(devices[device_id].rs485_descriptor, devices[device_id].address, buffer_r) > 0)
|
||||||
|
{
|
||||||
|
uint16_t calib_data = (*(buffer_r + 2) & 0xFF | ((*(buffer_r + 3) << 8) & 0xFF00));
|
||||||
|
devices[device_id].calibration = calib_data;
|
||||||
|
free(buffer_r);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Error reading eeprom from %i\n", device_id);
|
||||||
|
free(buffer_r);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
json_object *devicemgr_printMap()
|
json_object *devicemgr_printMap()
|
||||||
{
|
{
|
||||||
@@ -102,12 +145,12 @@ json_object *devicemgr_printMap()
|
|||||||
return rows_array;
|
return rows_array;
|
||||||
}
|
}
|
||||||
|
|
||||||
json_object *devicemgr_printDetails(int device_id)
|
void devicemgr_printDetails(int device_id, json_object *root)
|
||||||
{
|
{
|
||||||
// generate json object with status
|
// generate json object with status
|
||||||
json_object *root = json_object_new_object();
|
|
||||||
json_object_object_add(root, "id", json_object_new_int(device_id));
|
json_object_object_add(root, "id", json_object_new_int(device_id));
|
||||||
json_object_object_add(root, "address", json_object_new_int(devices[device_id].address));
|
json_object_object_add(root, "address", json_object_new_int(devices[device_id].address));
|
||||||
|
json_object_object_add(root, "calibration", json_object_new_int(devices[device_id].calibration));
|
||||||
json_object_object_add(root, "flapID", json_object_new_int(devices[device_id].current_flap));
|
json_object_object_add(root, "flapID", json_object_new_int(devices[device_id].current_flap));
|
||||||
json_object_object_add(root, "flapChar", json_object_new_string(symbols[devices[device_id].current_flap]));
|
json_object_object_add(root, "flapChar", json_object_new_string(symbols[devices[device_id].current_flap]));
|
||||||
json_object *position = json_object_new_object();
|
json_object *position = json_object_new_object();
|
||||||
@@ -134,6 +177,12 @@ json_object *devicemgr_printDetails(int device_id)
|
|||||||
case NEW:
|
case NEW:
|
||||||
json_object_object_add(status, "device", json_object_new_string("NEW"));
|
json_object_object_add(status, "device", json_object_new_string("NEW"));
|
||||||
break;
|
break;
|
||||||
|
case REMOVED:
|
||||||
|
json_object_object_add(status, "device", json_object_new_string("REMOVED"));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
json_object_object_add(status, "device", json_object_new_string("UNALLOCATED"));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
json_object *status_flags = json_object_new_object();
|
json_object *status_flags = json_object_new_object();
|
||||||
json_object_object_add(status_flags,
|
json_object_object_add(status_flags,
|
||||||
@@ -159,31 +208,30 @@ json_object *devicemgr_printDetails(int device_id)
|
|||||||
json_object_new_boolean(((devices[device_id].reg_status) >> 6) & 0x01));
|
json_object_new_boolean(((devices[device_id].reg_status) >> 6) & 0x01));
|
||||||
json_object_object_add(status, "flags", status_flags);
|
json_object_object_add(status, "flags", status_flags);
|
||||||
json_object_object_add(root, "status", status);
|
json_object_object_add(root, "status", status);
|
||||||
|
|
||||||
return root;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
json_object *devicemgr_printDetailsAll()
|
void devicemgr_printDetailsAll(json_object *root)
|
||||||
{
|
{
|
||||||
json_object *root = json_object_new_object();
|
|
||||||
json_object_object_add(root, "devices_all", json_object_new_int(nextFreeSlot + 1));
|
json_object_object_add(root, "devices_all", json_object_new_int(nextFreeSlot + 1));
|
||||||
json_object *devices_arr = json_object_new_array();
|
json_object *devices_arr = json_object_new_array();
|
||||||
int devices_online = 0;
|
int devices_online = 0;
|
||||||
for (int i = 0; i < (nextFreeSlot + 1); i++)
|
for (int i = 0; i < (nextFreeSlot + 1); i++)
|
||||||
|
{
|
||||||
|
if (devices[i].address > 0)
|
||||||
{
|
{
|
||||||
devicemgr_readStatus(i);
|
devicemgr_readStatus(i);
|
||||||
if (devices[i].deviceState == ONLINE)
|
if (devices[i].deviceState == ONLINE)
|
||||||
{
|
{
|
||||||
devices_online++;
|
devices_online++;
|
||||||
}
|
}
|
||||||
json_object_array_add(devices_arr, devicemgr_printDetails(i));
|
json_object *device = json_object_new_object();
|
||||||
|
devicemgr_printDetails(i, device);
|
||||||
|
json_object_array_add(devices_arr, device);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
json_object_object_add(root, "map", devicemgr_printMap());
|
json_object_object_add(root, "map", devicemgr_printMap());
|
||||||
json_object_object_add(root, "devices", devices_arr);
|
json_object_object_add(root, "devices", devices_arr);
|
||||||
json_object_object_add(root, "devices_online", json_object_new_int(devices_online));
|
json_object_object_add(root, "devices_online", json_object_new_int(devices_online));
|
||||||
|
|
||||||
printf("The json representation:\n\n%s\n\n", json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY));
|
|
||||||
return root;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSingle(int id, char flap)
|
void setSingle(int id, char flap)
|
||||||
@@ -191,8 +239,10 @@ void setSingle(int id, char flap)
|
|||||||
// first convert char to flap id
|
// first convert char to flap id
|
||||||
char test_char = toupper(flap);
|
char test_char = toupper(flap);
|
||||||
printf("find char %c\n", test_char);
|
printf("find char %c\n", test_char);
|
||||||
for (int ix = 0; ix < 45; ix++){
|
for (int ix = 0; ix < 45; ix++)
|
||||||
if (*symbols[ix] == test_char){
|
{
|
||||||
|
if (*symbols[ix] == test_char)
|
||||||
|
{
|
||||||
printf("match char %i %i %i\n", test_char, *symbols[ix], ix);
|
printf("match char %i %i %i\n", test_char, *symbols[ix], ix);
|
||||||
sfbus_display_full(devices[id].rs485_descriptor, devices[id].address, ix);
|
sfbus_display_full(devices[id].rs485_descriptor, devices[id].address, ix);
|
||||||
break;
|
break;
|
||||||
@@ -201,7 +251,13 @@ void setSingle(int id, char flap)
|
|||||||
devices[nextFreeSlot].current_flap = flap;
|
devices[nextFreeSlot].current_flap = flap;
|
||||||
}
|
}
|
||||||
|
|
||||||
void printText(char *text, int x, int y)
|
void setSingleRaw(int id, int flap)
|
||||||
|
{
|
||||||
|
sfbus_display_full(devices[id].rs485_descriptor, devices[id].address, flap);
|
||||||
|
devices[nextFreeSlot].current_flap = flap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void devicemgr_printText(char *text, int x, int y)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < strlen(text); i++)
|
for (int i = 0; i < strlen(text); i++)
|
||||||
{
|
{
|
||||||
@@ -211,32 +267,209 @@ void printText(char *text, int x, int y)
|
|||||||
printf("print char %c to %i\n", *(text + i), devices[this_id].address);
|
printf("print char %c to %i\n", *(text + i), devices[this_id].address);
|
||||||
|
|
||||||
setSingle(this_id, *(text + i));
|
setSingle(this_id, *(text + i));
|
||||||
usleep(5000);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int devicemgr_register(int rs485_descriptor, u_int16_t address, int x, int y)
|
void devicemgr_printFlap(int flap, int x, int y)
|
||||||
|
{
|
||||||
|
int this_id = deviceMap[x][y];
|
||||||
|
if (this_id >= 0)
|
||||||
|
{
|
||||||
|
setSingleRaw(this_id, flap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int devicemgr_register(int rs485_descriptor, u_int16_t address, int x, int y, int nid)
|
||||||
|
{
|
||||||
|
if (nid < 0)
|
||||||
{
|
{
|
||||||
nextFreeSlot++;
|
nextFreeSlot++;
|
||||||
devices[nextFreeSlot].pos_x = x;
|
nid = nextFreeSlot;
|
||||||
devices[nextFreeSlot].pos_y = y;
|
}
|
||||||
devices[nextFreeSlot].address = address;
|
|
||||||
devices[nextFreeSlot].rs485_descriptor = rs485_descriptor;
|
devices[nid].pos_x = x;
|
||||||
devices[nextFreeSlot].reg_voltage = 0;
|
devices[nid].pos_y = y;
|
||||||
devices[nextFreeSlot].reg_counter = 0;
|
devices[nid].address = address;
|
||||||
devices[nextFreeSlot].reg_status = 0;
|
devices[nid].calibration = 0;
|
||||||
devices[nextFreeSlot].current_flap = 0;
|
devices[nid].rs485_descriptor = rs485_descriptor;
|
||||||
devices[nextFreeSlot].deviceState = NEW;
|
devices[nid].reg_voltage = 0;
|
||||||
devices[nextFreeSlot].powerState = DISABLED;
|
devices[nid].reg_counter = 0;
|
||||||
|
devices[nid].reg_status = 0;
|
||||||
|
devices[nid].current_flap = 0;
|
||||||
|
devices[nid].deviceState = NEW;
|
||||||
|
devices[nid].powerState = DISABLED;
|
||||||
// try to reach device
|
// try to reach device
|
||||||
devicemgr_readStatus(nextFreeSlot);
|
devicemgr_readStatus(nid);
|
||||||
|
devicemgr_readCalib(nid);
|
||||||
if (deviceMap[x][y] >= 0)
|
if (deviceMap[x][y] >= 0)
|
||||||
{ // rest old ones
|
{ // rest old ones
|
||||||
int old_id = deviceMap[x][y];
|
int old_id = deviceMap[x][y];
|
||||||
devices[old_id].pos_x = -1;
|
devices[old_id].pos_x = -1;
|
||||||
devices[old_id].pos_y = -1;
|
devices[old_id].pos_y = -1;
|
||||||
}
|
}
|
||||||
deviceMap[x][y] = nextFreeSlot;
|
deviceMap[x][y] = nid;
|
||||||
return nextFreeSlot;
|
return nid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// refreshes status of all devices
|
||||||
|
int devicemgr_refresh()
|
||||||
|
{
|
||||||
|
int devices_online = 0;
|
||||||
|
for (int ix = 0; ix < SFDEVICE_MAXDEV; ix++)
|
||||||
|
{
|
||||||
|
if (devices[ix].address > 0)
|
||||||
|
{
|
||||||
|
devicemgr_readStatus(ix);
|
||||||
|
if (devices[ix].deviceState == ONLINE)
|
||||||
|
{
|
||||||
|
devices_online++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return devices_online;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove devices from system
|
||||||
|
int devicemgr_remove(int id)
|
||||||
|
{
|
||||||
|
devices[nextFreeSlot].deviceState = REMOVED;
|
||||||
|
devices[nextFreeSlot].address = 0;
|
||||||
|
devices[nextFreeSlot].rs485_descriptor = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int devicemgr_save(char *file)
|
||||||
|
{
|
||||||
|
json_object *root = json_object_new_object();
|
||||||
|
json_object_object_add(root, "nextFreeSlot", json_object_new_int(nextFreeSlot));
|
||||||
|
json_object *device_array = json_object_new_array();
|
||||||
|
for (int ix = 0; ix < SFDEVICE_MAXDEV; ix++)
|
||||||
|
{
|
||||||
|
if (devices[ix].address > 0)
|
||||||
|
{
|
||||||
|
json_object *device = json_object_new_object();
|
||||||
|
devicemgr_printDetails(ix, device);
|
||||||
|
json_object_array_add(device_array, device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
json_object_object_add(root, "devices", device_array);
|
||||||
|
|
||||||
|
char *data = json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY);
|
||||||
|
printf("[INFO][console] store data to %s\n", file);
|
||||||
|
|
||||||
|
FILE *fptr;
|
||||||
|
fptr = fopen(file, "w");
|
||||||
|
fwrite(data, sizeof(char), strlen(data), fptr);
|
||||||
|
fclose(fptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int devicemgr_load(char *file)
|
||||||
|
{
|
||||||
|
FILE *fptr;
|
||||||
|
const char *line_in_file = malloc(JSON_MAX_LINE_LEN); // maximum of 256 bytes per line;
|
||||||
|
fptr = fopen(file, "r");
|
||||||
|
json_tokener *tok = json_tokener_new();
|
||||||
|
json_object *jobj = NULL;
|
||||||
|
int stringlen = 0;
|
||||||
|
enum json_tokener_error jerr;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
int read_ret = fgets(line_in_file, JSON_MAX_LINE_LEN, fptr); // read line from file
|
||||||
|
stringlen = strlen(line_in_file);
|
||||||
|
// printf("Read line with chars: %i : %s", stringlen, line_in_file); // only for testing
|
||||||
|
jobj = json_tokener_parse_ex(tok, line_in_file, stringlen);
|
||||||
|
if (read_ret == NULL)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while ((jerr = json_tokener_get_error(tok)) == json_tokener_continue);
|
||||||
|
if (jerr != json_tokener_success)
|
||||||
|
{
|
||||||
|
free(fptr); //free file pointer
|
||||||
|
fprintf(stderr, "Error: %s\n", json_tokener_error_desc(jerr));
|
||||||
|
// Handle errors, as appropriate for your application.
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
free(fptr); //free file pointer
|
||||||
|
free(tok); //free tokenizer
|
||||||
|
|
||||||
|
// dump loadad data to terminal ( for tetsting)
|
||||||
|
// char *data = json_object_to_json_string_ext(jobj, JSON_C_TO_STRING_PRETTY);
|
||||||
|
// printf("%s",data);
|
||||||
|
|
||||||
|
// load data
|
||||||
|
json_object *next_free;
|
||||||
|
if (!json_object_object_get_ex(jobj, "nextFreeSlot", &next_free))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error: %s\n", "Key 'nextFreeSlot' not found.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nextFreeSlot = json_object_get_int(next_free);
|
||||||
|
free(next_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear config
|
||||||
|
devicemgr_init(deviceFd);
|
||||||
|
|
||||||
|
// load devices
|
||||||
|
json_object *devices;
|
||||||
|
if (!json_object_object_get_ex(jobj, "devices", &devices))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error: %s\n", "Key 'devices' not found.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int arraylen = json_object_array_length(devices);
|
||||||
|
for (int i = 0; i < arraylen; i++)
|
||||||
|
{
|
||||||
|
devicemgr_load_single(json_object_array_get_idx(devices, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
free(devices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int devicemgr_load_single(json_object *device_obj)
|
||||||
|
{
|
||||||
|
json_object *jid = json_object_object_get(device_obj, "id");
|
||||||
|
json_object *jaddr = json_object_object_get(device_obj, "address");
|
||||||
|
json_object *jpos = json_object_object_get(device_obj, "position");
|
||||||
|
json_object *jposx = json_object_object_get(jpos, "x");
|
||||||
|
json_object *jposy = json_object_object_get(jpos, "y");
|
||||||
|
// verify values are present
|
||||||
|
if (jid == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error: Key 'device.%s' not found\n", "id");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (jaddr == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error: Key 'address.%s' not found\n", "id");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (jposx == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error: Key 'device.%s' not found\n", "position.x");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (jposy == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error: Key 'device.%s' not found\n", "position.y");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create device
|
||||||
|
devicemgr_register(deviceFd,
|
||||||
|
json_object_get_int(jaddr),
|
||||||
|
json_object_get_int(jposx),
|
||||||
|
json_object_get_int(jposy),
|
||||||
|
json_object_get_int(jid));
|
||||||
}
|
}
|
||||||
@@ -1,21 +1,26 @@
|
|||||||
|
#include "sfbus.h"
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <errno.h> // Error integer and strerror() function
|
||||||
|
#include <fcntl.h> // Contains file controls like O_RDWR
|
||||||
|
#include <json-c/json.h>
|
||||||
|
#include <json-c/json_object.h>
|
||||||
|
#include <json-c/json_tokener.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <fcntl.h> // Contains file controls like O_RDWR
|
|
||||||
#include <errno.h> // Error integer and strerror() function
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <termios.h> // Contains POSIX terminal control definitions
|
#include <termios.h> // Contains POSIX terminal control definitions
|
||||||
#include <unistd.h> // write(), read(), close()
|
#include <unistd.h> // write(), read(), close()
|
||||||
#include <sys/types.h>
|
|
||||||
#include "sfbus.h"
|
|
||||||
#include <json-c/json_object.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <json-c/json.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
int devicemgr_readStatus(int device_id);
|
int devicemgr_readStatus(int device_id);
|
||||||
json_object * devicemgr_printDetails(int device_id);
|
int devicemgr_readCalib(int device_id);
|
||||||
json_object * devicemgr_printDetailsAll();
|
void devicemgr_printDetails(int device_id, json_object *root);
|
||||||
int devicemgr_register(int rs485_descriptor, u_int16_t address, int x,int y);
|
void devicemgr_printDetailsAll(json_object *root);
|
||||||
|
int devicemgr_register(int rs485_descriptor, u_int16_t address, int x, int y, int nid);
|
||||||
void devicemgr_init();
|
void devicemgr_init();
|
||||||
int devicemgr_print(char *text);
|
int devicemgr_print(char *text);
|
||||||
|
int devicemgr_refresh();
|
||||||
|
int devicemgr_save(char *file);
|
||||||
|
void devicemgr_printText(char *text, int x, int y);
|
||||||
|
void devicemgr_printFlap(int flap, int x, int y);
|
||||||
@@ -12,6 +12,8 @@
|
|||||||
#include "ftdi485.h"
|
#include "ftdi485.h"
|
||||||
#include "sfbus.h"
|
#include "sfbus.h"
|
||||||
#include "devicemgr.h"
|
#include "devicemgr.h"
|
||||||
|
#include "console.h"
|
||||||
|
|
||||||
|
|
||||||
void printUsage(char *argv[]) {
|
void printUsage(char *argv[]) {
|
||||||
fprintf(stderr, "Usage: %s -p <tty> -c <command> [value]\n", argv[0]);
|
fprintf(stderr, "Usage: %s -p <tty> -c <command> [value]\n", argv[0]);
|
||||||
@@ -65,20 +67,10 @@ int main(int argc, char *argv[]) {
|
|||||||
printf("Open device at %s\n", port);
|
printf("Open device at %s\n", port);
|
||||||
int fd = rs485_init(port, B19200); // setup rs485
|
int fd = rs485_init(port, B19200); // setup rs485
|
||||||
|
|
||||||
// test
|
|
||||||
devicemgr_init();
|
|
||||||
devicemgr_register(fd,1,0,0);
|
|
||||||
devicemgr_register(fd,2,1,0);
|
|
||||||
devicemgr_register(fd,3,2,0);
|
|
||||||
devicemgr_register(fd,4,3,0);
|
|
||||||
devicemgr_printDetailsAll();
|
|
||||||
//exit(1);
|
|
||||||
|
|
||||||
if (strcmp(command, "ping") == 0) {
|
if (strcmp(command, "ping") == 0) {
|
||||||
sfbus_ping(fd, addr_int);
|
|
||||||
exit(0);
|
|
||||||
} else if (strcmp(command, "printf") == 0) {
|
} else if (strcmp(command, "printf") == 0) {
|
||||||
printText(data,0,0);
|
devicemgr_printText(data,0,0);
|
||||||
} else if (strcmp(command, "r_eeprom") == 0) {
|
} else if (strcmp(command, "r_eeprom") == 0) {
|
||||||
char *buffer = malloc(64);
|
char *buffer = malloc(64);
|
||||||
sfbus_read_eeprom(fd, addr_int, buffer);
|
sfbus_read_eeprom(fd, addr_int, buffer);
|
||||||
@@ -89,44 +81,12 @@ int main(int argc, char *argv[]) {
|
|||||||
exit(0);
|
exit(0);
|
||||||
} else if (strcmp(command, "w_addr") == 0) {
|
} else if (strcmp(command, "w_addr") == 0) {
|
||||||
int n_addr = strtol(data, NULL, 10);
|
int n_addr = strtol(data, NULL, 10);
|
||||||
if (n_addr < 1) {
|
int ret = sfbusu_write_address(fd,addr_int,n_addr);
|
||||||
printf("Please specify new address > 0 with -d\n");
|
exit(ret);
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
// read current eeprom status
|
|
||||||
char *buffer_w = malloc(64);
|
|
||||||
char *buffer_r = malloc(64);
|
|
||||||
if (sfbus_read_eeprom(fd, addr_int, buffer_w) < 0) {
|
|
||||||
fprintf(stderr, "Error reading eeprom\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
// modify current addr
|
|
||||||
u_int16_t n_addr_16 = n_addr;
|
|
||||||
memcpy(buffer_w, &n_addr_16, 2);
|
|
||||||
if (sfbus_write_eeprom(fd, addr_int, buffer_w, buffer_r) < 0) {
|
|
||||||
fprintf(stderr, "Error writing eeprom\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
exit(0);
|
|
||||||
} else if (strcmp(command, "w_cal") == 0) {
|
} else if (strcmp(command, "w_cal") == 0) {
|
||||||
int n_addr = strtol(data, NULL, 10);
|
int n_addr = strtol(data, NULL, 10);
|
||||||
// read current eeprom status
|
int ret = sfbusu_write_calibration(fd,addr_int,n_addr);
|
||||||
char *buffer_w = malloc(64);
|
exit(ret);
|
||||||
char *buffer_r = malloc(64);
|
|
||||||
if (sfbus_read_eeprom(fd, addr_int, buffer_w) < 0) {
|
|
||||||
fprintf(stderr, "Error reading eeprom\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
// modify current addr
|
|
||||||
u_int16_t n_addr_16 = n_addr;
|
|
||||||
memcpy(buffer_w+2, &n_addr_16, 2);
|
|
||||||
if (sfbus_write_eeprom(fd, addr_int, buffer_w, buffer_r) < 0) {
|
|
||||||
fprintf(stderr, "Error writing eeprom\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
exit(0);
|
|
||||||
} else if (strcmp(command, "status") == 0) {
|
} else if (strcmp(command, "status") == 0) {
|
||||||
double voltage = 0;
|
double voltage = 0;
|
||||||
u_int32_t counter = 0;
|
u_int32_t counter = 0;
|
||||||
@@ -165,20 +125,11 @@ int main(int argc, char *argv[]) {
|
|||||||
} else if (strcmp(command, "power_off") == 0) {
|
} else if (strcmp(command, "power_off") == 0) {
|
||||||
sfbus_motor_power(fd, addr_int,0);
|
sfbus_motor_power(fd, addr_int,0);
|
||||||
exit(0);
|
exit(0);
|
||||||
|
} else if (strcmp(command, "server") == 0){
|
||||||
|
start_console(fd);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Invalid command specified!\n");
|
fprintf(stderr, "Invalid command specified!\n");
|
||||||
printUsage(argv);
|
printUsage(argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *buffer = malloc(256);
|
|
||||||
char *cmd = "\xF0";
|
|
||||||
|
|
||||||
sfbus_send_frame(fd, 0, strlen(cmd), cmd);
|
|
||||||
|
|
||||||
int len = sfbus_recv_frame_wait(fd, 0xFFFF, buffer);
|
|
||||||
// printf("TEST:%i %s\n", len, buffer);
|
|
||||||
|
|
||||||
free(buffer);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
48
software/pc_client/src/sfbus-util.c
Normal file
48
software/pc_client/src/sfbus-util.c
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#include "sfbus-util.h"
|
||||||
|
int sfbusu_write_address(int fd, u_int16_t current, u_int16_t new)
|
||||||
|
{
|
||||||
|
if (new < 1)
|
||||||
|
{
|
||||||
|
printf("Please specify new address > 0 with -d\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// read current eeprom status
|
||||||
|
char *buffer_w = malloc(64);
|
||||||
|
char *buffer_r = malloc(64);
|
||||||
|
if (sfbus_read_eeprom(fd, current, buffer_w) < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error reading eeprom\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// modify current addr
|
||||||
|
u_int16_t n_addr_16 = new;
|
||||||
|
memcpy(buffer_w, &n_addr_16, 2);
|
||||||
|
if (sfbus_write_eeprom(fd, current, buffer_w, buffer_r) < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error writing eeprom\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sfbusu_write_calibration(int fd, u_int16_t address, u_int16_t data)
|
||||||
|
{
|
||||||
|
// read current eeprom status
|
||||||
|
char *buffer_w = malloc(64);
|
||||||
|
char *buffer_r = malloc(64);
|
||||||
|
if (sfbus_read_eeprom(fd, address, buffer_w) < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error reading eeprom\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// modify current calibration
|
||||||
|
memcpy(buffer_w + 2, &data, 2);
|
||||||
|
if (sfbus_write_eeprom(fd, address, buffer_w, buffer_r) < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error writing eeprom\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
7
software/pc_client/src/sfbus-util.h
Normal file
7
software/pc_client/src/sfbus-util.h
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#include "sfbus.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int sfbusu_write_address(int fd, u_int16_t current, u_int16_t new);
|
||||||
|
int sfbusu_write_calibration(int fd, u_int16_t address, u_int16_t data);
|
||||||
@@ -107,14 +107,10 @@ void sfbus_send_frame(int fd, u_int16_t address, u_int8_t length,
|
|||||||
}
|
}
|
||||||
*frame = '$'; // startbyte
|
*frame = '$'; // startbyte
|
||||||
|
|
||||||
//rs485_trdir(fd, 0);
|
|
||||||
|
|
||||||
int result = write(fd, frame_ptr, frame_size_complete);
|
int result = write(fd, frame_ptr, frame_size_complete);
|
||||||
print_bufferHexTx(frame_ptr + 5, frame_size_complete - 6, address);
|
print_bufferHexTx(frame_ptr + 5, frame_size_complete - 6, address);
|
||||||
free(frame_ptr);
|
free(frame_ptr);
|
||||||
// tcdrain(fd);
|
|
||||||
//usleep(470 * (frame_size_complete + 1));
|
|
||||||
//rs485_trdir(fd, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int sfbus_ping(int fd, u_int16_t address) {
|
int sfbus_ping(int fd, u_int16_t address) {
|
||||||
|
|||||||
106
software/pc_client/src/wsserver.c
Normal file
106
software/pc_client/src/wsserver.c
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
#include "wsserver.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This section provides a web server to controll the
|
||||||
|
* device manager through web sockets
|
||||||
|
*
|
||||||
|
* by Dennis Gunia - 2025 - www.dennisgunia.de
|
||||||
|
*/
|
||||||
|
|
||||||
|
json_object *(*commandparser_func)(json_object *);
|
||||||
|
|
||||||
|
// this sections handles ws connections and communications
|
||||||
|
// called on opening websocket client
|
||||||
|
void onopen(ws_cli_conn_t client)
|
||||||
|
{
|
||||||
|
char *cli;
|
||||||
|
cli = ws_getaddress(client);
|
||||||
|
printf("Connection opened, addr: %s\n", cli);
|
||||||
|
}
|
||||||
|
|
||||||
|
// called on closing websocket client
|
||||||
|
void onclose(ws_cli_conn_t client)
|
||||||
|
{
|
||||||
|
char *cli;
|
||||||
|
cli = ws_getaddress(client);
|
||||||
|
printf("Connection closed, addr: %s\n", cli);
|
||||||
|
}
|
||||||
|
|
||||||
|
// called on receiving websocket message
|
||||||
|
void onmessage(ws_cli_conn_t client, const unsigned char *msg, uint64_t size, int type)
|
||||||
|
{
|
||||||
|
char *cli = ws_getaddress(client);
|
||||||
|
printf("received message: %s (%zu), from: %s\n", msg, size, cli);
|
||||||
|
|
||||||
|
json_tokener *tok = json_tokener_new();
|
||||||
|
json_object *req = json_tokener_parse_ex(tok, msg, size);
|
||||||
|
enum json_tokener_error jerr;
|
||||||
|
jerr = json_tokener_get_error(tok);
|
||||||
|
if (jerr != json_tokener_success)
|
||||||
|
{
|
||||||
|
// check if request can be parsed, if not retrun error
|
||||||
|
send_json_error(client, "parsing error", json_tokener_error_desc(jerr));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if it can be parsed, get command.
|
||||||
|
json_object *commandObj = json_object_object_get(req, "command");
|
||||||
|
printf("test");
|
||||||
|
if (commandObj != NULL)
|
||||||
|
{
|
||||||
|
char *command = json_object_to_json_string(commandObj);
|
||||||
|
// get key
|
||||||
|
json_object *res = commandparser_func(req);
|
||||||
|
if (res == NULL)
|
||||||
|
{
|
||||||
|
send_json_error(client, "internal error", "");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
send_json_response(client, res);
|
||||||
|
}
|
||||||
|
free(res);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if key is missing, send error
|
||||||
|
send_json_error(client, "format error", "missing key: command");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(tok); // always free tokenizer, to prevent memory leak
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_json_response(ws_cli_conn_t client, json_object *res)
|
||||||
|
{
|
||||||
|
char *message = json_object_to_json_string_ext(res, JSON_C_TO_STRING_PRETTY);
|
||||||
|
ws_sendframe_txt(client, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_json_error(ws_cli_conn_t client, char *error, char *detail)
|
||||||
|
{
|
||||||
|
json_object *root = json_object_new_object();
|
||||||
|
json_object_object_add(root, "error", json_object_new_string(error));
|
||||||
|
json_object_object_add(root, "detail", json_object_new_string(detail));
|
||||||
|
send_json_response(client, root);
|
||||||
|
}
|
||||||
|
|
||||||
|
// starting webserver
|
||||||
|
int start_webserver(json_object *(*commandparser_func_ptr)(json_object *))
|
||||||
|
{
|
||||||
|
commandparser_func = commandparser_func_ptr;
|
||||||
|
ws_socket(&(struct ws_server){/*
|
||||||
|
* Bind host, such as:
|
||||||
|
* localhost -> localhost/127.0.0.1
|
||||||
|
* 0.0.0.0 -> global IPv4
|
||||||
|
* :: -> global IPv4+IPv6 (Dual stack)
|
||||||
|
*/
|
||||||
|
.host = WS_SERVER_ADDR,
|
||||||
|
.port = WS_SERVER_PORT,
|
||||||
|
.thread_loop = 0,
|
||||||
|
.timeout_ms = 1000,
|
||||||
|
.evs.onopen = &onopen,
|
||||||
|
.evs.onclose = &onclose,
|
||||||
|
.evs.onmessage = &onmessage});
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
11
software/pc_client/src/wsserver.h
Normal file
11
software/pc_client/src/wsserver.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#include <json-c/json_object.h>
|
||||||
|
#include <json-c/json_tokener.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <wsserver/ws.h>
|
||||||
|
|
||||||
|
#define WS_SERVER_PORT 8080
|
||||||
|
#define WS_SERVER_ADDR "localhost"
|
||||||
|
|
||||||
|
int start_webserver();
|
||||||
Reference in New Issue
Block a user