From 2656ac3d43452de22ed572f3e2f67b1df7e567b3 Mon Sep 17 00:00:00 2001 From: eddyem Date: Tue, 13 Oct 2020 00:01:41 +0300 Subject: [PATCH] add USBrelay --- Binary_search/errors.c | 102 ++++++++++++++ Binary_search/errors.h | 28 ++++ README | 8 +- USBrelay/1.c | 196 ++++++++++++++++++++++++++ USBrelay/99-hidrelay.rules | 1 + USBrelay/Makefile | 56 ++++++++ calcAP/slalib_sofa_nova.c | 4 +- cmakelists_/CMakeLists_regular_03.txt | 69 +++++++++ cmakelists_/Makefiledbg | 56 ++++++++ count_bits.c | 1 + netdaemon/Readme.md | 2 + powerof2.c | 3 + sockmsgs.c | 22 +-- 13 files changed, 536 insertions(+), 12 deletions(-) create mode 100644 Binary_search/errors.c create mode 100644 Binary_search/errors.h create mode 100644 USBrelay/1.c create mode 100644 USBrelay/99-hidrelay.rules create mode 100644 USBrelay/Makefile create mode 100644 cmakelists_/CMakeLists_regular_03.txt create mode 100644 cmakelists_/Makefiledbg create mode 100644 count_bits.c create mode 100644 powerof2.c diff --git a/Binary_search/errors.c b/Binary_search/errors.c new file mode 100644 index 0000000..0e4500f --- /dev/null +++ b/Binary_search/errors.c @@ -0,0 +1,102 @@ +/* + * Copyright 2020 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "errors.h" +#include +#include + +static const abortcodes AC[] = { + //while read l; do N=$(echo $l|awk '{print $1 $2}'); R=$(echo $l|awk '{$1=$2=""; print substr($0,3)}'|sed 's/\.//'); echo -e "{0x$N, \"$R\"},"; done < codes.b + {0x05030000, "Toggle bit not alternated"}, + {0x05040000, "SDO protocol timed out"}, + {0x05040001, "Client/server command specifier not valid or unknown"}, + {0x05040002, "Invalid block size (block mode only)"}, + {0x05040003, "Invalid sequence number (block mode only)"}, + {0x05040004, "CRC error (block mode only)"}, + {0x05040005, "Out of memory"}, + {0x06010000, "Unsupported access to an object"}, + {0x06010001, "Attempt to read a write only object"}, + {0x06010002, "Attempt to write a read only object"}, + {0x06020000, "Object does not exist in the object dictionary"}, + {0x06040041, "Object cannot be mapped to the PDO"}, + {0x06040042, "The number and length of the objects to be mapped would exceed PDO length"}, + {0x06040043, "General parameter incompatibility reason"}, + {0x06040047, "General internal incompatibility in the device"}, + {0x06060000, "Access failed due to a hardware error"}, + {0x06070010, "Data type does not match; length of service parameter does not match"}, + {0x06070012, "Data type does not match; length of service parameter too high"}, + {0x06070013, "Data type does not match; length of service parameter too low"}, + {0x06090011, "Sub-index does not exist"}, + {0x06090030, "Value range of parameter exceeded (only for write access)"}, + {0x06090031, "Value of parameter written too high"}, + {0x06090032, "Value of parameter written too low"}, + {0x06090036, "Maximum value is less than minimum value"}, + {0x08000000, "General error"}, + {0x08000020, "Data cannot be transferred or stored to the application"}, + {0x08000021, "Data cannot be transferred or stored to the application because of local control"}, + {0x08000022, "Data cannot be transferred or stored to the application because of the present device state"}, + {0x08000023, "Object dictionary dynamic generation fails or no object dictionary is present"}, +}; + +const int ACmax = sizeof(AC)/sizeof(abortcodes) - 1; + +const char *ACtext(uint32_t abortcode, int *n){ + int idx = ACmax/2, min_ = 0, max_ = ACmax, newidx = 0, iter=0; + do{ + ++iter; + uint32_t c = AC[idx].code; + printf("idx=%d, min=%d, max=%d\n", idx, min_, max_); + if(c == abortcode){ + if(n) *n = iter; + return AC[idx].errmsg; + }else if(c > abortcode){ + newidx = (idx + min_)/2; + max_ = idx; + + }else{ + newidx = (idx + max_ + 1)/2; + min_ = idx; + } + if(newidx == idx || min_ < 0 || max_ > ACmax){ + if(n) *n = 0; + return NULL; + } + idx = newidx; + }while(1); +} + +void check_all(){ + int iter = 0, N; + for(int i = 0; i <= ACmax; ++i){ + printf("code 0x%X: %s\n\n", AC[i].code, ACtext(AC[i].code, &N)); + iter += N; + } + printf("\n\ntotal: %d iterations, mean: %d, (%d for direct lookup)\n", iter, iter/(ACmax+1), (ACmax+1)/2); +} + +int main(int argc, char **argv){ + if(argc != 2){ + check_all(); + return 0; + } + uint32_t x = (uint32_t)strtol(argv[1], NULL, 0); + printf("x=0x%X\n", x); + const char *text = ACtext(x, NULL); + if(text) printf("%s\n", text); + else printf("Unknown error code\n"); + return 0; +} diff --git a/Binary_search/errors.h b/Binary_search/errors.h new file mode 100644 index 0000000..ea23ccc --- /dev/null +++ b/Binary_search/errors.h @@ -0,0 +1,28 @@ +/* + * Copyright 2020 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#ifndef ERRORS_H__ +#define ERRORS_H__ + +#include + +typedef struct{ + uint32_t code; + char *errmsg; +} abortcodes; + +#endif // ERRORS_H__ diff --git a/README b/README index e44f81b..6b39c30 100644 --- a/README +++ b/README @@ -7,8 +7,12 @@ B-trees - simple but slowly binary search trees with all main operations fifo_lifo - simple stack-like queues +netdaemon - snippet for network management of serial devices + simple_list - 1-directional list with functions: add element; delete list +stellarium_emul - snippet for stellarium telescope remote control + tmout - theads-based timeout to check something usefull_macros - a lot of different macros & functions @@ -18,6 +22,4 @@ usefull_macros - a lot of different macros & functions * error/warning/debug macros * MMAP files into memory -stellarium_emul - snippet for stellarium telescope remote control - -netdaemon - snippet for network management of serial devices +USBrelay - simplest tool to manage USB-HID chinese relays diff --git a/USBrelay/1.c b/USBrelay/1.c new file mode 100644 index 0000000..77de6bb --- /dev/null +++ b/USBrelay/1.c @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hidraw Userspace Example + * + * Copyright (c) 2010 Alan Ott + * Copyright (c) 2010 Signal 11 Software + * + * The code may be used by anyone for any purpose, + * and can serve as a starting point for developing + * applications using hidraw. + */ + +/* + * Copyright 2020 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// chinese USB-HID relay management +// works only with one relay (the first found or pointed) + +#define RELAY_VENDOR_ID 0x16c0 +#define RELAY_PRODUCT_ID 0x05df + +char *device = NULL; // device name +int help = 0; // call help +int quiet = 0; // no info messages +int **set = NULL; // turn ON given relays +int **reset = NULL; // turn OFF given relays +int fd = 0; // device file descriptor + +static myoption cmdlnopts[] = { +// common options + {"help", NO_ARGS, NULL, 'h', arg_int, APTR(&help), _("show this help")}, + {"device", NEED_ARG, NULL, 'd', arg_string, APTR(&device), _("serial device name")}, + {"set", MULT_PAR, NULL, 's', arg_int, APTR(&set), _("turn ON relays with given number[s]")}, + {"reset", MULT_PAR, NULL, 'r', arg_int, APTR(&reset), _("turn OFF relays with given number[s]")}, + {"quiet", NO_ARGS, NULL, 'q', arg_int, APTR(&quiet), _("don't show info messages")}, + end_option +}; + +static void parse_args(int argc, char **argv){ + int i; + char helpstring[1024]; + snprintf(helpstring, 1024, "Usage: %%s [args]\n\n\tWhere args are:\n"); + change_helpstring(helpstring); + parseargs(&argc, &argv, cmdlnopts); + if(help) showhelp(-1, cmdlnopts); + if(argc > 0){ + WARNX("Wrong parameters:"); + for (i = 0; i < argc; i++) + fprintf(stderr, "\t%s\n", argv[i]); + showhelp(-1, cmdlnopts); + } +} + +#define CMD_ON 0xff +#define CMD_OFF 0xfd +#define CMD_SETSER 0xfa + +/** + * @brief relay_cmd - turn on/off given relay + * @param cmd: CMD_ON/CMD_OFF + * @param relaynmbr - 1..8 + */ +static void relay_cmd(int cmd, int relaynmbr){ + char buf[9] = {0}; + // buf[0] = 0x00; /* Report Number */ + buf[1] = cmd; // ON - ff, OFF - fd; SET_SERIAL - 0xfa + buf[2] = relaynmbr; // relay number or [2]..[6] - new serial + int res = ioctl(fd, HIDIOCSFEATURE(9), buf); + if(res < 0) + ERR("HIDIOCSFEATURE"); + else if(res != 9) ERRX("Wrong return value: %d instead of 9", res); +} + +#define INFO(...) do{if(!quiet){green(__VA_ARGS__); printf("\n");}}while(0) + +int main(int argc, char **argv){ + int res; + char buf[256]; + struct hidraw_report_descriptor rpt_desc; + struct hidraw_devinfo info; + + initial_setup(); + parse_args(argc, argv); + if(!device) ERRX("No device given"); + + fd = open(device, O_RDWR|O_NONBLOCK); + if(fd < 0){ + WARN("Unable to open device"); + return 1; + } + + memset(&rpt_desc, 0x0, sizeof(rpt_desc)); + memset(&info, 0x0, sizeof(info)); + memset(buf, 0x0, sizeof(buf)); + /* Get Raw Name */ + res = ioctl(fd, HIDIOCGRAWNAME(256), buf); + if(res < 0) + ERR("HIDIOCGRAWNAME"); + else + INFO("Raw Name: %s\n", buf); + int L = strlen(buf), wrong = 0; + char nr = '0'; + if(L < 9) wrong = 1; + else{ + if(strncmp(buf+L-9, "USBRelay", 8)) wrong = 1; + nr = buf[L-1]; + if(nr < '0' || nr > '8') wrong = 1; + } + /* Get Raw Info */ + res = ioctl(fd, HIDIOCGRAWINFO, &info); + if(res < 0){ + ERR("HIDIOCGRAWINFO"); + }else{ + if(info.vendor != RELAY_VENDOR_ID || info.product != RELAY_PRODUCT_ID) wrong = 1; + } + if(wrong){ + ERRX("Wrong relay raw name: %s (VID=0x%04X, PID=0x%04X)", buf, info.vendor, info.product); + } + int Nrelays = nr - '0'; + INFO("N relays = %d", Nrelays); + + if(set || reset){ + if(set) do{ + int On = **set; + if(On < 0 || On > Nrelays) WARNX("Wrong relay number: %d", On); + else{ + INFO("SET: %d\n", On); + relay_cmd(CMD_ON, On); + } + ++set; + }while(*set); + if(reset) do{ + int Off = **reset; + if(Off < 0 || Off > Nrelays) WARNX("Wrong relay number: %d", Off); + else{ + INFO("RESET: %d\n", Off); + relay_cmd(CMD_OFF, Off); + } + ++reset; + }while(*reset); + } + + /* Get Feature */ + buf[0] = 0x01; /* Report Number */ + memset(buf+1, 0, 8); + res = ioctl(fd, HIDIOCGFEATURE(9), buf); + if(res < 0){ + ERR("HIDIOCGFEATURE"); + }else{ + if(res != 9) ERRX("Bad answer"); + // report: + // bytes 0..4 - serial (e.g. HURTM) + // byte 7 - state (each bit of state ==1 - ON, ==0 - off) + buf[5] = 0; + INFO("Relay serial: %s", buf); + for(int i = 0; i < Nrelays; ++i){ + INFO("Relay%d=%d", i, buf[7]&(1< $(OBJDIR)/$(TARGET) + @echo -e "\t\tLD $(PROGRAM)" + $(CC) $(LDFLAGS) $(OBJS) -o $(PROGRAM) + +$(OBJDIR): + @mkdir $(OBJDIR) + +ifneq ($(MAKECMDGOALS),clean) +-include $(DEPS) +endif + +$(OBJDIR)/%.o: %.c + @echo -e "\t\tCC $<" + $(CC) -MD -c $(LDFLAGS) $(CFLAGS) $(DEFINES) -o $@ $< + +clean: + @echo -e "\t\tCLEAN" + @rm -rf $(OBJDIR) 2>/dev/null || true + +xclean: clean + @rm -f $(PROGRAM) + +gentags: + CFLAGS="$(CFLAGS) $(DEFINES)" geany -g $(PROGRAM).c.tags *[hc] 2>/dev/null + +.PHONY: gentags clean xclean diff --git a/calcAP/slalib_sofa_nova.c b/calcAP/slalib_sofa_nova.c index c00ed72..607b54d 100644 --- a/calcAP/slalib_sofa_nova.c +++ b/calcAP/slalib_sofa_nova.c @@ -118,7 +118,7 @@ void radtodeg(double r){ double getta(char *str){ int a,b,s = 1; double c; if(3 != sscanf(str, "%d:%d:%lf", &a,&b,&c)) return -1; - if(a < 0){ s = -1; a = -a;} + if(a < 0 || *str == '-'){ s = -1; a = -a;} c /= 3600.; c += a + b/60.; c *= s; @@ -217,6 +217,8 @@ int main (int argc, char **argv){ dut1 = 0.13026 ; // DUT1 /* ICRS to observed. */ double aob, zob, hob, dob, rob; + printf("iauAtco13(%g, %g, %g, %g, %g, %g, %g, %g, %g, %g, %g, %g, %g, %g, %g, %g, %g, %g)\n", + rc, dc, pr, pd, px, rv, utc1, utc2, dut1, elong, phi, hm, xp, yp, phpa, tc, rh, wl); if ( iauAtco13 ( rc, dc, pr, pd, px, rv, utc1, utc2, dut1, elong, phi, hm, xp, yp, phpa, tc, rh, wl, &aob, &zob, diff --git a/cmakelists_/CMakeLists_regular_03.txt b/cmakelists_/CMakeLists_regular_03.txt new file mode 100644 index 0000000..c356a80 --- /dev/null +++ b/cmakelists_/CMakeLists_regular_03.txt @@ -0,0 +1,69 @@ +cmake_minimum_required(VERSION 3.0) +set(PROJ steppermove) +set(MINOR_VERSION "1") +set(MID_VERSION "0") +set(MAJOR_VERSION "0") +set(VERSION "${MAJOR_VERSION}.${MID_VERSION}.${MINOR_VERSION}") + +project(${PROJ} VERSION ${PROJ_VERSION} LANGUAGES C) +#enable_language(C) + +message("VER: ${VERSION}") + +# default flags +set(CMAKE_C_FLAGS_RELEASE "") +set(CMAKE_C_FLAGS_DEBUG "") +set(CMAKE_C_FLAGS "-O2 -std=gnu99") + +set(CMAKE_COLOR_MAKEFILE ON) + +# here is one of two variants: all .c in directory or .c files in list +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} SOURCES) + +# cmake -DDEBUG=1 -> debugging +if(DEFINED EBUG) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra -Wall -Werror -W") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra -Wall -Werror -W") + set(CMAKE_BUILD_TYPE DEBUG) + set(CMAKE_VERBOSE_MAKEFILE "ON") + add_definitions(-DEBUG) +else() + set(CMAKE_BUILD_TYPE RELEASE) +endif() + +###### pkgconfig ###### +# pkg-config modules (for pkg-check-modules) +set(MODULES usefull_macros) + +# find packages: +find_package(PkgConfig REQUIRED) +pkg_check_modules(${PROJ} REQUIRED ${MODULES}) + +###### additional flags ###### +#list(APPEND ${PROJ}_LIBRARIES "-lfftw3_threads") + +# change wrong behaviour with install prefix +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT AND CMAKE_INSTALL_PREFIX MATCHES "/usr/local") +else() + message("Change default install path to /usr/local") + set(CMAKE_INSTALL_PREFIX "/usr/local") +endif() +message("Install dir prefix: ${CMAKE_INSTALL_PREFIX}") + +# exe file +add_executable(${PROJ} ${SOURCES}) +# -I +include_directories(${${PROJ}_INCLUDE_DIRS}) +# -L +link_directories(${${PROJ}_LIBRARY_DIRS}) +# -D +add_definitions(${CFLAGS} -DLOCALEDIR=\"${LOCALEDIR}\" + -DPACKAGE_VERSION=\"${VERSION}\" -DGETTEXT_PACKAGE=\"${PROJ}\" + -DMINOR_VERSION=\"${MINOR_VERSION}\" -DMID_VERSION=\"${MID_VERSION}\" + -DMAJOR_VERSION=\"${MAJOR_VESION}\") + +# -l +target_link_libraries(${PROJ} ${${PROJ}_LIBRARIES} -lm) + +# Installation of the program +INSTALL(TARGETS ${PROJ} DESTINATION "bin") diff --git a/cmakelists_/Makefiledbg b/cmakelists_/Makefiledbg new file mode 100644 index 0000000..8b41010 --- /dev/null +++ b/cmakelists_/Makefiledbg @@ -0,0 +1,56 @@ +# run `make DEF=...` to add extra defines +PROGRAM := +<<<<<<< HEAD +LDFLAGS := -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,--discard-all +SRCS := $(wildcard *.c) +DEFINES := $(DEF) -D_GNU_SOURCE -D_XOPEN_SOURCE=1111 +OBJDIR := mk +CFLAGS += -O2 -Wall -Wextra -Wno-trampolines -std=gnu99 +======= +LDFLAGS := -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,--discard-all -Xlinker --warn-common +SRCS := $(wildcard *.c) +DEFINES := $(DEF) -D_XOPEN_SOURCE=1111 +OBJDIR := mk +CFLAGS += -O2 -Wall -Werror -Wextra -Wno-trampolines -std=gnu99 +>>>>>>> 8c51b1c4c29737d7d3c062d88cbb0f3ca2f97652 +OBJS := $(addprefix $(OBJDIR)/, $(SRCS:%.c=%.o)) +DEPS := $(OBJS:.o=.d) +CC = gcc +#CXX = g++ + + +all : $(OBJDIR) $(PROGRAM) + +<<<<<<< HEAD +debug: CFLAGS += -DEBUG -Werror +debug: all + +======= +>>>>>>> 8c51b1c4c29737d7d3c062d88cbb0f3ca2f97652 +$(PROGRAM) : $(OBJS) + @echo -e "\t\tLD $(PROGRAM)" + $(CC) $(LDFLAGS) $(OBJS) -o $(PROGRAM) + +$(OBJDIR): + mkdir $(OBJDIR) + +ifneq ($(MAKECMDGOALS),clean) +-include $(DEPS) +endif + +$(OBJDIR)/%.o: %.c + @echo -e "\t\tCC $<" + $(CC) -MD -c $(LDFLAGS) $(CFLAGS) $(DEFINES) -o $@ $< + +clean: + @echo -e "\t\tCLEAN" + @rm -f $(OBJS) $(DEPS) + @rmdir $(OBJDIR) 2>/dev/null || true + +xclean: clean + @rm -f $(PROGRAM) + +gentags: + CFLAGS="$(CFLAGS) $(DEFINES)" geany -g $(PROGRAM).c.tags *[hc] 2>/dev/null + +.PHONY: gentags clean xclean diff --git a/count_bits.c b/count_bits.c new file mode 100644 index 0000000..bba43d9 --- /dev/null +++ b/count_bits.c @@ -0,0 +1 @@ +__builtin_popcount(x) - counts all non-zero bits in number diff --git a/netdaemon/Readme.md b/netdaemon/Readme.md index 6d73c44..24d6bef 100644 --- a/netdaemon/Readme.md +++ b/netdaemon/Readme.md @@ -1,6 +1,8 @@ Network daemon snippet ================== +This isn't an end-product, but just a template for different net-daemons. + Open a socket at given port (default: 4444), works with http & direct requests. Can read and send commands over serial interface. diff --git a/powerof2.c b/powerof2.c new file mode 100644 index 0000000..26d83b1 --- /dev/null +++ b/powerof2.c @@ -0,0 +1,3 @@ +int IsPowerOfTwo(uint64_t x){ + return (x != 0) && ((x & (x - 1)) == 0); +} diff --git a/sockmsgs.c b/sockmsgs.c index 7d12576..8a4a45d 100644 --- a/sockmsgs.c +++ b/sockmsgs.c @@ -86,14 +86,20 @@ void *handle_socket(void *asock){ buff[readed] = 0; // DBG("get %zd bytes: %s", readed, buff); // now we should check what do user want - char *got, *found = buff; + char *found = buff; DBG("Buff: %s", buff); - if((got = stringscan(buff, "GET")) || (got = stringscan(buff, "POST"))){ // web query + //if((got = stringscan(buff, "GET"))){ // web query + if(strncmp(buff, "GET", 3) == 0){ webquery = 1; - char *slash = strchr(got, '/'); + char *slash = strchr(buff, '/'); if(slash) found = slash + 1; // web query have format GET /some.resource + }else if(strncmp(buff, "POST", 4) == 0){ + webquery = 1; + char *hdrend = strstr(buff, "\r\n\r\n"); + if(hdrend) found = hdrend + 4; } + DBG("Found=%s", found); size_t L; char *X; if((X = strstr(found, "sum="))){ // check working for GET from browser @@ -103,18 +109,18 @@ void *handle_socket(void *asock){ newx = x; DBG("User give sum=%d", x); } - L = snprintf(obuff, BUFLEN, "sum=%d\n", newx); + int l = snprintf(obuff, BUFLEN, "sum=%d\n", newx); if(webquery){ // save file with current value L = snprintf(obuff, BUFLEN, "HTTP/2.0 200 OK\r\n" "Access-Control-Allow-Origin: *\r\n" "Access-Control-Allow-Methods: GET, POST\r\n" "Access-Control-Allow-Credentials: true\r\n" - "Content-type: multipart/form-data\r\nContent-Length: %zd\r\n\r\n" - "sum=%d\n", L, newx); - } + "Content-type: text/html\r\nContent-Length: %d\r\n\r\n" + "sum=%d\n", l, newx); + }else L = l; if(L != (size_t)write(sock, obuff, L)) WARN("write"); - DBG("%s", obuff); + DBG("\nWRITE TO client: %s\n", obuff); }else{ // simply copy back all data size_t blen = strlen(buff); if(webquery){