refactor v1

This commit is contained in:
2025-01-10 13:53:27 +01:00
parent 09c7107a07
commit 285ec4b38d
52 changed files with 79 additions and 21 deletions

View File

@@ -0,0 +1,35 @@
TARGET_EXEC ?= a.out
BUILD_DIR ?= ./build
SRC_DIRS ?= ./src
SRCS := $(shell find $(SRC_DIRS) -name *.cpp -or -name *.c -or -name *.s)
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)
DEPS := $(OBJS:.o=.d)
INC_DIRS := $(shell find $(SRC_DIRS) -type d)
INC_FLAGS := $(addprefix -I,$(INC_DIRS))
JSON_C_DIR=/path/to/json_c/install
CFLAGS += -I$(JSON_C_DIR)/include/json-c
# Or to use lines like: #include <json-c/json_object.h>
#CFLAGS += -I$(JSON_C_DIR)/include
LDFLAGS+= -L$(JSON_C_DIR)/lib -ljson-c
CPPFLAGS ?= $(INC_FLAGS) -MMD -MP
$(BUILD_DIR)/$(TARGET_EXEC): $(OBJS)
$(CC) $(OBJS) -o $@ $(LDFLAGS)
# c source
$(BUILD_DIR)/%.c.o: %.c
$(MKDIR_P) $(dir $@)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
.PHONY: clean
clean:
$(RM) -r $(BUILD_DIR)
-include $(DEPS)
MKDIR_P ?= mkdir -p

View File

@@ -0,0 +1,181 @@
#include "devicemgr.h"
#include <json-c/json_object.h>
#include <string.h>
/*
* This file provides an abstraction layer to access many devices
* simultaneously. by Dennis Gunia - 2025 - wwwm.dennisgunia.de
*/
enum SFDEVICE_STATE { NEW, OFFLINE, ONLINE, FAILED };
enum SFDEVICE_POWER { DISABLED, ENABLED, UNKNOWN };
struct SFDEVICE {
int pos_x;
int pos_y;
u_int16_t address;
int rs485_descriptor;
double reg_voltage;
u_int32_t reg_counter;
u_int8_t reg_status;
u_int8_t current_flap;
enum SFDEVICE_STATE deviceState;
enum SFDEVICE_POWER powerState;
};
#define SFDEVICE_MAXDEV 128
#define SFDEVICE_MAX_X 20
#define SFDEVICE_MAX_Y 4
// next free slot to register device
int nextFreeSlot = -1;
int deviceMap[SFDEVICE_MAX_X][SFDEVICE_MAX_Y];
struct SFDEVICE devices[SFDEVICE_MAXDEV];
const char* symbols[] = {" ", "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", "Ä", "Ö", "Ü", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ".", "-", "?", "!"};
void devicemgr_init() {
// reserve memory buffer
for (int y = 0; y<SFDEVICE_MAX_Y; y++){
for (int x = 0; x<SFDEVICE_MAX_X; x++){
deviceMap[x][y] = -1; //all empty slots are -1
}
}
}
int devicemgr_readStatus(int device_id) {
double _voltage = 0;
u_int32_t _counter = 0;
u_int8_t _status =
sfbus_read_status(devices[device_id].rs485_descriptor,
devices[device_id].address, &_voltage, &_counter);
if (_status == 0xFF) {
devices[device_id].powerState = UNKNOWN;
devices[device_id].deviceState = OFFLINE;
return -1;
} else {
devices[device_id].reg_voltage = _voltage;
devices[device_id].reg_counter = _counter;
devices[device_id].reg_status = _status;
devices[device_id].powerState = ~((devices[device_id].reg_status >> 4)) & 0x01;
devices[device_id].deviceState = ONLINE;
if ((((devices[device_id].reg_status) >> 5) & 0x01) > 0){
devices[device_id].deviceState = FAILED;
}
return 0;
}
}
json_object * devicemgr_printMap(){
json_object *rows_array = json_object_new_array();
for (int y = 0; y<SFDEVICE_MAX_Y; y++){
json_object *columns_array = json_object_new_array();
for (int x = 0; x<SFDEVICE_MAX_X; x++){
json_object_array_add(columns_array, json_object_new_int(deviceMap[x][y]));
}
json_object_array_add(rows_array,columns_array);
}
return rows_array;
}
json_object * devicemgr_printDetails(int device_id){
// 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, "address", json_object_new_int(devices[device_id].address));
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 *position = json_object_new_object();
json_object_object_add(position, "x", json_object_new_int(devices[device_id].pos_x));
json_object_object_add(position, "y", json_object_new_int(devices[device_id].pos_y));
json_object_object_add(root, "position", position);
json_object *status = json_object_new_object();
json_object_object_add(status, "voltage", json_object_new_double(devices[device_id].reg_voltage));
json_object_object_add(status, "rotations", json_object_new_int(devices[device_id].reg_counter));
json_object_object_add(status, "power", json_object_new_boolean(devices[device_id].powerState));
json_object_object_add(status, "raw", json_object_new_uint64(devices[device_id].reg_status));
switch(devices[device_id].deviceState){
case ONLINE:
json_object_object_add(status, "device", json_object_new_string("ONLINE"));
break;
case OFFLINE:
json_object_object_add(status, "device", json_object_new_string("OFFLINE"));
break;
case FAILED:
json_object_object_add(status, "device", json_object_new_string("FAILED"));
break;
case NEW:
json_object_object_add(status, "device", json_object_new_string("NEW"));
break;
}
json_object *status_flags = json_object_new_object();
json_object_object_add(status_flags, "errorTooBig", json_object_new_boolean(((devices[device_id].reg_status) >> 0) & 0x01));
json_object_object_add(status_flags, "noHome", json_object_new_boolean(((devices[device_id].reg_status) >> 1) & 0x01));
json_object_object_add(status_flags, "fuseBlown", json_object_new_boolean(((devices[device_id].reg_status) >> 2) & 0x01));
json_object_object_add(status_flags, "homeSense", json_object_new_boolean(((devices[device_id].reg_status) >> 3) & 0x01));
json_object_object_add(status_flags, "powerDown", json_object_new_boolean(((devices[device_id].reg_status) >> 4) & 0x01));
json_object_object_add(status_flags, "failSafe", json_object_new_boolean(((devices[device_id].reg_status) >> 5) & 0x01));
json_object_object_add(status_flags, "busy", json_object_new_boolean(((devices[device_id].reg_status) >> 6) & 0x01));
json_object_object_add(status, "flags", status_flags);
json_object_object_add(root, "status", status);
return root;
}
json_object * devicemgr_printDetailsAll(){
json_object *root = json_object_new_object();
json_object_object_add(root, "devices_all", json_object_new_int(nextFreeSlot + 1));
json_object *devices_arr = json_object_new_array();
int devices_online = 0;
for (int i = 0; i< (nextFreeSlot + 1); i++){
devicemgr_readStatus(i);
if ( devices[i].deviceState == ONLINE ){devices_online++;}
json_object_array_add(devices_arr, devicemgr_printDetails(i));
}
json_object_object_add(root, "map", devicemgr_printMap());
json_object_object_add(root, "devices", devices_arr);
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, u_int8_t flap){
sfbus_display_full(devices[id].rs485_descriptor , devices[id].address,flap);
devices[nextFreeSlot].current_flap = flap;
}
void printText(char* text,int x,int y){
for (int i = 0; i<strlen(text);i++){
int this_id = deviceMap[x+i][y];
if (this_id >= 0){
setSingle(devices[this_id].address,*(text+i));
}
}
}
int devicemgr_register(int rs485_descriptor, u_int16_t address, int x,int y) {
nextFreeSlot++;
devices[nextFreeSlot].pos_x = x;
devices[nextFreeSlot].pos_y = y;
devices[nextFreeSlot].address = address;
devices[nextFreeSlot].rs485_descriptor = rs485_descriptor;
devices[nextFreeSlot].reg_voltage = 0;
devices[nextFreeSlot].reg_counter = 0;
devices[nextFreeSlot].reg_status = 0;
devices[nextFreeSlot].current_flap = 0;
devices[nextFreeSlot].deviceState = NEW;
devices[nextFreeSlot].powerState = DISABLED;
// try to reach device
devicemgr_readStatus(nextFreeSlot);
if (deviceMap[x][y] >= 0){ // rest old ones
int old_id = deviceMap[x][y];
devices[old_id].pos_x = -1;
devices[old_id].pos_y = -1;
}
deviceMap[x][y] = nextFreeSlot;
return nextFreeSlot;
}

View File

@@ -0,0 +1,19 @@
#include <stdio.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 <termios.h> // Contains POSIX terminal control definitions
#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>
int devicemgr_readStatus(int device_id) ;
json_object * devicemgr_printDetails(int device_id);
json_object * devicemgr_printDetailsAll();
int devicemgr_register(int rs485_descriptor, u_int16_t address, int x,int y);
void devicemgr_init();

View File

@@ -0,0 +1,163 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
// Linux headers
#include <fcntl.h> // Contains file controls like O_RDWR
#include <sys/types.h>
#include <termios.h> // Contains POSIX terminal control definitions
#include <unistd.h> // write(), read(), close()
#include "rs485.h"
#include "sfbus.h"
#include <unistd.h>
#include "devicemgr.h"
void printUsage(char *argv[]) {
fprintf(stderr, "Usage: %s -p <tty> -c <command> [value]\n", argv[0]);
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[]) {
int opt;
u_int16_t addr_int = 0;
char *port = malloc(256);
char *command = malloc(16);
char *addr = malloc(16);
char *data = malloc(256);
command = "";
addr = "";
data = "";
while ((opt = getopt(argc, argv, "p:c:a:d:")) != -1) {
switch (opt) {
case 'p':
port = optarg;
break;
case 'c':
command = optarg;
break;
case 'a':
addr = optarg;
break;
case 'd':
data = optarg;
break;
default:
printUsage(argv);
}
}
if (access(port, F_OK) != 0) {
fprintf(stderr, "Filedescriptor: %s does not exist or cannot be opened\n",
port);
printUsage(argv);
}
// parse address
if (strlen(addr) == 0) {
fprintf(stderr, "Please specify address\n");
printUsage(argv);
} else {
addr_int = strtol(addr, NULL, 10);
}
// start program
setvbuf(stdout, NULL, _IONBF, 0); // do not buffer stdout!!!!
printf("Open device at %s\n", port);
int fd = rs485_init(port, B19200); // setup rs485
// test
devicemgr_init();
devicemgr_register(fd,0,0,0);
devicemgr_register(fd,1,1,0);
devicemgr_printDetailsAll();
//exit(1);
if (strcmp(command, "ping") == 0) {
sfbus_ping(fd, addr_int);
exit(0);
} else if (strcmp(command, "r_eeprom") == 0) {
char *buffer = malloc(64);
sfbus_read_eeprom(fd, addr_int, buffer);
printf("Read data: 0x");
print_charHex(buffer, 5);
printf("\n");
free(buffer);
exit(0);
} else if (strcmp(command, "w_addr") == 0) {
int n_addr = strtol(data, NULL, 10);
if (n_addr < 1) {
printf("Please specify new address > 0 with -d\n");
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, "status") == 0) {
double voltage = 0;
u_int32_t counter = 0;
u_int8_t status = sfbus_read_status(fd, addr_int, &voltage, &counter);
printf("=======================\n");
printf("Status register flags :\n");
printf(" 00 -> errorTooBig : %i\n", (status >> 0) & 0x01);
printf(" 01 -> noHome : %i\n", (status >> 1) & 0x01);
printf(" 02 -> fuseBlown : %i\n", (status >> 2) & 0x01);
printf(" 03 -> homeSense : %i\n", (status >> 3) & 0x01);
printf(" 04 -> powerDown : %i\n", (status >> 4) & 0x01);
printf(" 05 -> failSafe : %i\n", (status >> 5) & 0x01);
printf(" 06 -> busy : %i\n", (status >> 6) & 0x01);
printf("Driver-Voltage : %.2fV\n", voltage);
printf("Rotations : %i\n", counter);
exit(0);
} else if (strcmp(command, "display") == 0) {
int flap = strtol(data, NULL, 10);
// read current eeprom status
char *buffer_w = malloc(4);
sfbus_display(fd, addr_int, flap);
exit(0);
} else if (strcmp(command, "display_fr") == 0) {
int flap = strtol(data, NULL, 10);
// read current eeprom status
char *buffer_w = malloc(4);
sfbus_display_full(fd, addr_int, flap);
exit(0);
}else if (strcmp(command, "reset") == 0) {
sfbus_reset_device(fd, addr_int);
exit(0);
} else if (strcmp(command, "power_on") == 0) {
sfbus_motor_power(fd, addr_int,1);
exit(0);
} else if (strcmp(command, "power_off") == 0) {
sfbus_motor_power(fd, addr_int,0);
exit(0);
} else {
fprintf(stderr, "Invalid command specified!\n");
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;
}

View File

@@ -0,0 +1,69 @@
#include "rs485.h"
/*
* Open RS485 Interface (FT232RL)
*/
int rs485_init(char *device, int baud) {
int rs485_fd = open(device, O_RDWR);
if (rs485_fd < 0) {
printf("Error %i from open: %s\n", errno, strerror(errno));
return -1;
}
// Flush all data
int result = tcflush(rs485_fd, TCIOFLUSH);
if (result) {
perror("tcflush failed"); // just a warning, not a fatal error
return -1;
}
// Set port config and baud
struct termios options;
result = tcgetattr(rs485_fd, &options);
if (result) {
perror("tcgetattr failed");
close(rs485_fd);
return -1;
}
// Turn off any options that might interfere with our ability to send and
// receive raw binary bytes.
options.c_iflag &= ~(INLCR | IGNCR | ICRNL | IXON | IXOFF);
options.c_oflag &= ~(ONLCR | OCRNL);
options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
// Set up timeouts: Calls to read() will return as soon as there is
// at least one byte available or when 100 ms has passed.
options.c_cc[VTIME] = 1;
options.c_cc[VMIN] = 0;
cfsetospeed(&options, baud);
cfsetispeed(&options, baud);
result = tcsetattr(rs485_fd, TCSANOW, &options);
if (result) {
perror("tcsetattr failed");
close(rs485_fd);
return -1;
}
rs485_trdir(rs485_fd, 1);
return rs485_fd;
}
/*
* Set RS485 Direction (FT232RL - RTS PIN)
*/
int rs485_trdir(int rs485_fd, int level) {
int status;
if (ioctl(rs485_fd, TIOCMGET, &status) == -1) {
perror("setRTS(): TIOCMGET");
return 0;
}
if (level)
status |= TIOCM_DTR;
else
status &= ~TIOCM_DTR;
if (ioctl(rs485_fd, TIOCMSET, &status) == -1) {
perror("setRTS(): TIOCMSET");
return 0;
}
return 1;
}

View File

@@ -0,0 +1,15 @@
#include <stdio.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 <termios.h> // Contains POSIX terminal control definitions
#include <unistd.h> // write(), read(), close()
#include <sys/types.h>
#define RS485TX 0
#define RS485RX 1
int rs485_init(char *device, int baud);
int rs485_trdir(int rs485_fd, int level);

View File

@@ -0,0 +1,229 @@
#include "sfbus.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
void print_charHex(char *buffer, int length) {
int _tlength = length;
while (_tlength > 0) {
printf("%02X", (*buffer & 0xFF));
buffer++;
_tlength--;
}
}
void print_bufferHexRx(char *buffer, int length, u_int16_t address) {
printf("Rx (0x%04X): 0x", address);
print_charHex(buffer, length);
printf(" | %i bytes received\n", length);
}
void print_bufferHexTx(char *buffer, int length, u_int16_t address) {
printf("Tx (0x%04X): 0x", address);
print_charHex(buffer, length);
printf(" | %i bytes sent\n", length);
}
ssize_t sfbus_recv_frame_wait(int fd, u_int16_t address, char *buffer) {
ssize_t len = 0;
int retryCount = 2;
do {
len = sfbus_recv_frame(fd, address, buffer);
retryCount--;
if (retryCount == 0) {
fprintf(stderr, "Rx timeout\n");
return -1;
}
} while (len <= 0);
print_bufferHexRx(buffer, len - 3, address);
return len;
}
ssize_t sfbus_recv_frame(int fd, u_int16_t address, char *buffer) {
// wait for start byte
char byte = 0x00;
int retryCount = 3;
while (byte != '+') {
byte = 0x00;
read(fd, &byte, 1);
retryCount--;
if (retryCount == 0) {
return -1;
}
}
u_int8_t frm_version;
u_int8_t frm_addr_l;
u_int8_t frm_addr_h;
u_int8_t frm_length;
u_int8_t frm_eof;
read(fd, &frm_version, 1);
read(fd, &frm_length, 1);
read(fd, &frm_addr_l, 1);
read(fd, &frm_addr_h, 1);
u_int16_t dst_addr = frm_addr_l | (frm_addr_h << 8);
if (dst_addr != address) {
return 0;
}
u_int8_t frm_length_counter = frm_length - 3;
// read all bytes:
while (frm_length_counter > 0) {
read(fd, buffer, 1);
buffer++;
frm_length_counter--;
}
read(fd, &frm_eof, 1);
if (frm_eof == '$') {
return frm_length;
} else {
return -1;
}
}
void sfbus_send_frame(int fd, u_int16_t address, u_int8_t length,
char *buffer) {
int frame_size_complete = length + 6;
char *frame = malloc(frame_size_complete);
char *frame_ptr = frame;
*frame = '+'; // startbyte
frame++;
*frame = 0; // protocol version
frame++;
*frame = length + 3; // length
frame++;
*frame = (address);
frame++;
*frame = ((address >> 8));
frame++;
while (length > 0) {
*frame = *buffer;
length--;
buffer++;
frame++;
}
*frame = '$'; // startbyte
rs485_trdir(fd, 0);
int result = write(fd, frame_ptr, frame_size_complete);
print_bufferHexTx(frame_ptr + 5, frame_size_complete - 6, address);
free(frame_ptr);
// tcdrain(fd);
usleep(470 * (frame_size_complete + 1));
rs485_trdir(fd, 1);
}
int sfbus_ping(int fd, u_int16_t address) {
char *cmd = "\xFE";
char *buffer = malloc(64);
sfbus_send_frame(fd, address, strlen(cmd), cmd);
int len = sfbus_recv_frame_wait(fd, 0xFFFF, buffer);
if (len == 4 && *buffer == (char)0xFF) {
printf("Ping okay!\n");
free(buffer);
return 0;
} else {
printf("Ping invalid response!\n");
free(buffer);
return 1;
}
}
int sfbus_read_eeprom(int fd, u_int16_t address, char *buffer) {
char *cmd = "\xF0";
char *_buffer = malloc(256);
sfbus_send_frame(fd, address, strlen(cmd), cmd);
int len = sfbus_recv_frame_wait(fd, 0xFFFF, _buffer);
if (len != 9) {
printf("Invalid data!\n");
return -1;
}
if (*(_buffer + 5) != (char)0xAA || *(_buffer) != (char)0xAA) {
printf("Invalid data!\n");
return -1;
}
memcpy(buffer, _buffer + 1, len - 4);
free(_buffer);
// printf("Read valid data!\n");
return len;
}
int sfbus_write_eeprom(int fd, u_int16_t address, char *wbuffer,
char *rbuffer) {
char *cmd = malloc(5);
*cmd = (char)0xF1; // write eeprom command
memcpy(cmd + 1, wbuffer, 4);
sfbus_send_frame(fd, address, 5, cmd);
free(cmd);
// wait for readback
char *_buffer = malloc(256);
int len = sfbus_recv_frame_wait(fd, 0xFFFF, _buffer);
if (len != 9) {
printf("Invalid data!\n");
return -1;
}
if (*(_buffer + 5) != (char)0xAA || *(_buffer) != (char)0xAA) {
printf("Invalid data!\n");
return -1;
}
memcpy(rbuffer, _buffer + 1, len - 4);
free(_buffer);
// printf("Read valid data!\n");
return len;
}
int sfbus_display(int fd, u_int16_t address, u_int8_t flap) {
char *cmd = malloc(5);
*cmd = (char)0x10; // write eeprom command
*(cmd + 1) = flap;
sfbus_send_frame(fd, address, 2, cmd);
free(cmd);
return 0;
}
int sfbus_display_full(int fd, u_int16_t address, u_int8_t flap) {
char *cmd = malloc(5);
*cmd = (char)0x11; // write eeprom command
*(cmd + 1) = flap;
sfbus_send_frame(fd, address, 2, cmd);
free(cmd);
return 0;
}
u_int8_t sfbus_read_status(int fd, u_int16_t address, double *voltage,
u_int32_t *counter) {
char *cmd = "\xF8";
char *_buffer = malloc(256);
sfbus_send_frame(fd, address, strlen(cmd), cmd);
int res = sfbus_recv_frame_wait(fd, 0xFFFF, _buffer);
if (res < 0){
return 0xFF;
}
u_int16_t _voltage = *(_buffer + 2) & 0xFF | ((*(_buffer + 1) << 8) & 0xFF00);
u_int32_t _counter =
*(_buffer + 6) & 0xFF | (((*(_buffer + 3) & 0xFF) << 24)) |
(((*(_buffer + 4) & 0xFF) << 16)) | (((*(_buffer + 5) & 0xFF) << 8));
double __voltage = ((double)_voltage / 1024) * 55;
*voltage = __voltage;
*counter = (u_int32_t)_counter;
return *_buffer;
}
void sfbus_reset_device(int fd, u_int16_t address) {
char *cmd = "\x30";
sfbus_send_frame(fd, address, strlen(cmd), cmd);
}
void sfbus_motor_power(int fd, u_int16_t address, u_int8_t state) {
char *cmd = "\x20";
if (state > 0) {
cmd = "\x21";
}
sfbus_send_frame(fd, address, 1, cmd);
}

View File

@@ -0,0 +1,14 @@
#include "rs485.h"
ssize_t sfbus_recv_frame(int fd, u_int16_t address, char *buffer);
ssize_t sfbus_recv_frame_wait(int fd, u_int16_t address, char *buffer);
void sfbus_send_frame(int fd, u_int16_t address, u_int8_t length, char *buffer);
void print_charHex(char *buffer, int length);
int sfbus_ping(int fd, u_int16_t address);
int sfbus_read_eeprom(int fd, u_int16_t address, char* buffer);
int sfbus_write_eeprom(int fd, u_int16_t address, char* wbuffer, char *rbuffer);
int sfbus_display(int fd, u_int16_t address, u_int8_t flap);
int sfbus_display_full(int fd, u_int16_t address, u_int8_t flap);
u_int8_t sfbus_read_status(int fd, u_int16_t address, double *voltage, u_int32_t *counter);
void sfbus_reset_device(int fd, u_int16_t address);
void sfbus_motor_power(int fd, u_int16_t address, u_int8_t state);