refactor v1
This commit is contained in:
35
software/pc_client/makefile
Normal file
35
software/pc_client/makefile
Normal 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
|
||||
181
software/pc_client/src/devicemgr.c
Normal file
181
software/pc_client/src/devicemgr.c
Normal 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;
|
||||
}
|
||||
|
||||
19
software/pc_client/src/devicemgr.h
Normal file
19
software/pc_client/src/devicemgr.h
Normal 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();
|
||||
163
software/pc_client/src/main.c
Normal file
163
software/pc_client/src/main.c
Normal 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;
|
||||
}
|
||||
69
software/pc_client/src/rs485.c
Normal file
69
software/pc_client/src/rs485.c
Normal 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;
|
||||
}
|
||||
15
software/pc_client/src/rs485.h
Normal file
15
software/pc_client/src/rs485.h
Normal 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);
|
||||
229
software/pc_client/src/sfbus.c
Normal file
229
software/pc_client/src/sfbus.c
Normal 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);
|
||||
}
|
||||
14
software/pc_client/src/sfbus.h
Normal file
14
software/pc_client/src/sfbus.h
Normal 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);
|
||||
Reference in New Issue
Block a user