mirror of
https://github.com/eddyem/BTA_utils.git
synced 2026-01-31 20:35:05 +03:00
pre-pre alpha of Network_CAN_clientserver
This commit is contained in:
parent
882c782c52
commit
c16e343961
73
Network_CAN_clientserver/CMakeLists.txt
Normal file
73
Network_CAN_clientserver/CMakeLists.txt
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
set(PROJ canserv)
|
||||||
|
set(MINOR_VERSION "1")
|
||||||
|
set(MID_VERSION "0")
|
||||||
|
set(MAJOR_VERSION "0")
|
||||||
|
set(VERSION "${MAJOR_VERSION}.${MID_VERSION}.${MINOR_VERSION}")
|
||||||
|
|
||||||
|
project(${PROJ} VERSION ${VERSION} LANGUAGES C)
|
||||||
|
|
||||||
|
message("VERSION: ${VERSION}")
|
||||||
|
|
||||||
|
# list of options
|
||||||
|
option(DEBUG "Compile in debug mode" OFF)
|
||||||
|
option(EXAMPLES "Compile also all examples" ON)
|
||||||
|
|
||||||
|
# default flags
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -W -Wextra -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=yes -> debugging
|
||||||
|
if(DEBUG)
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Og -g3 -ggdb -fno-builtin-strlen -Werror")
|
||||||
|
add_definitions(-DEBUG)
|
||||||
|
set(CMAKE_BUILD_TYPE DEBUG)
|
||||||
|
set(CMAKE_VERBOSE_MAKEFILE "ON")
|
||||||
|
else()
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -march=native -fdata-sections -ffunction-sections")
|
||||||
|
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
|
||||||
|
set(CMAKE_BUILD_TYPE RELEASE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
message("Build type: ${CMAKE_BUILD_TYPE}")
|
||||||
|
|
||||||
|
###### pkgconfig ######
|
||||||
|
# pkg-config modules (for pkg-check-modules)
|
||||||
|
set(MODULES usefull_macros>=0.3.2)
|
||||||
|
# find packages:
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
pkg_check_modules(${PROJ} REQUIRED ${MODULES})
|
||||||
|
|
||||||
|
# external modules like OpenMP:
|
||||||
|
include(FindOpenMP)
|
||||||
|
if(OPENMP_FOUND)
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
|
||||||
|
add_definitions(-DOMP_FOUND)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
###### additional flags ######
|
||||||
|
#list(APPEND ${PROJ}_LIBRARIES "-lfftw3_threads")
|
||||||
|
add_executable(${PROJ} ${SOURCES} ${PO_FILE})
|
||||||
|
# -I
|
||||||
|
target_include_directories(${PROJ} PUBLIC ${${PROJ}_INCLUDE_DIRS} .)
|
||||||
|
# -L
|
||||||
|
target_link_directories(${PROJ} PUBLIC ${${PROJ}_LIBRARY_DIRS} )
|
||||||
|
# -D
|
||||||
|
add_definitions(-D_XOPEN_SOURCE=1234 -D_DEFAULT_SOURCE -D_GNU_SOURCE -DPACKAGE_VERSION=\"${VERSION}\"
|
||||||
|
-DMINOR_VERSION=\"${MINOR_VERSION}\" -DMID_VERSION=\"${MID_VERSION}\"
|
||||||
|
-DMAJOR_VERSION=\"${MAJOR_VESION}\")
|
||||||
|
# -l
|
||||||
|
target_link_libraries(${PROJ} ${${PROJ}_LIBRARIES} -lm)
|
||||||
|
|
||||||
|
# Installation of the program
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
install(TARGETS ${PROJ} DESTINATION "bin")
|
||||||
|
|
||||||
|
# EXAMPLES
|
||||||
|
if(EXAMPLES)
|
||||||
|
add_subdirectory(examples)
|
||||||
|
endif()
|
||||||
1
Network_CAN_clientserver/Readme
Normal file
1
Network_CAN_clientserver/Readme
Normal file
@ -0,0 +1 @@
|
|||||||
|
simple server for operate with FX3U-clone over TCP sockets
|
||||||
92
Network_CAN_clientserver/canproto.h
Normal file
92
Network_CAN_clientserver/canproto.h
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the fx3u project.
|
||||||
|
* Copyright 2024 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// command parameter flag means this is a setter
|
||||||
|
#define SETTER_FLAG (0x80)
|
||||||
|
#define ISSETTER(data) ((data[2] & SETTER_FLAG))
|
||||||
|
// parameter number 127 means there no parameter number at all (don't need paremeter or get all)
|
||||||
|
#define NO_PARNO (0x7f)
|
||||||
|
// base value of parameter (even if it is a setter)
|
||||||
|
#define PARBASE(x) (x & 0x7f)
|
||||||
|
// get parameter value of msg->data
|
||||||
|
#define PARVAL(data) (data[2] & 0x7f)
|
||||||
|
|
||||||
|
// make error for CAN answer
|
||||||
|
#define FORMERR(m, err) do{m->data[3] = err; if(m->length < 4) m->length = 4;}while(0)
|
||||||
|
|
||||||
|
// error codes for answer message
|
||||||
|
typedef enum{
|
||||||
|
ERR_OK, // 0 - all OK
|
||||||
|
ERR_BADPAR, // 1 - parameter is wrong
|
||||||
|
ERR_BADVAL, // 2 - wrong value
|
||||||
|
ERR_WRONGLEN, // 3 - wrong message length
|
||||||
|
ERR_BADCMD, // 4 - unknown command
|
||||||
|
ERR_CANTRUN, // 5 - can't run given command due to bad parameters or other
|
||||||
|
ERR_AMOUNT // amount of error codes
|
||||||
|
} errcodes;
|
||||||
|
|
||||||
|
// set command bytes in CAN message
|
||||||
|
#define MSG_SET_CMD(msg, cmd) do{*((uint16_t*)msg.data) = (cmd);}while(0)
|
||||||
|
#define MSGP_SET_CMD(msg, cmd) do{*((uint16_t*)msg->data) = (cmd);}while(0)
|
||||||
|
#define MSG_GET_CMD(msg) (*(uint16_t*)msg.data)
|
||||||
|
#define MSGP_GET_CMD(msg) (*(uint16_t*)msg->data)
|
||||||
|
// set command parameter number
|
||||||
|
#define MSG_SET_PARNO(msg, n) do{msg.data[2] = (n);}while(0)
|
||||||
|
#define MSGP_SET_PARNO(msg, n) do{msg->data[2] = (n);}while(0)
|
||||||
|
// set error
|
||||||
|
#define MSG_SET_ERR(msg, err) do{msg.data[3] = (err);}while(0)
|
||||||
|
#define MSGP_SET_ERR(msg, err) do{msg->data[3] = (err);}while(0)
|
||||||
|
// set uint32_t data
|
||||||
|
#define MSG_SET_U32(msg, d) do{*((uint32_t*)(&msg.data[4])) = (d);}while(0)
|
||||||
|
#define MSGP_SET_U32(msg, d) do{*((uint32_t*)(&msg->data[4])) = (d);}while(0)
|
||||||
|
// get uint32_t data
|
||||||
|
#define MSG_GET_U32(msg) (*(uint32_t*)&msg.data[4])
|
||||||
|
#define MSGP_GET_U32(msg) (*(uint32_t*)&msg->data[4])
|
||||||
|
|
||||||
|
// CAN commands indexes
|
||||||
|
enum{
|
||||||
|
CMD_PING, // just ping
|
||||||
|
CMD_RESET, // reset MCU
|
||||||
|
CMD_TIME, // get/set Tms
|
||||||
|
CMD_MCUTEMP, // get MCU temperature (*10)
|
||||||
|
CMD_ADCRAW, // get ADC raw values
|
||||||
|
CMD_CANSPEED, // get/set CAN speed (kbps)
|
||||||
|
CMD_CANID, // get/set common CAN ID (both in and out)
|
||||||
|
CMD_CANIDin, // input CAN ID
|
||||||
|
CMD_CANIDout, // output CAN ID
|
||||||
|
CMD_SAVECONF, // save configuration
|
||||||
|
CMD_ERASESTOR, // erase all flash storage
|
||||||
|
CMD_RELAY, // switch relay ON/OFF
|
||||||
|
CMD_GETESW, // current ESW state, bounce-free
|
||||||
|
CMD_GETESWNOW, // current ESW state, absolute
|
||||||
|
CMD_BOUNCE, // get/set bounce constant (ms)
|
||||||
|
CMD_USARTSPEED, // get/set USART1 speed
|
||||||
|
CMD_LED, // onboard LED
|
||||||
|
CMD_FLAGS, // flags setter/getter
|
||||||
|
CMD_INCHNLS, // all bits set are active supported IN channels
|
||||||
|
CMD_OUTCHNLS, // all bits set are active supported OUT channels
|
||||||
|
CMD_MODBUSID, // set/get modbus slave ID (or 0 if master)
|
||||||
|
CMD_MODBUSIDOUT,// slave ID to send modbus relay command if IN changes
|
||||||
|
CMD_MODBUSSPEED,// speed of modbus interface
|
||||||
|
// should be the last:
|
||||||
|
CMD_AMOUNT // amount of CAN commands
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
1
Network_CAN_clientserver/canserver.cflags
Normal file
1
Network_CAN_clientserver/canserver.cflags
Normal file
@ -0,0 +1 @@
|
|||||||
|
-std=c17
|
||||||
5
Network_CAN_clientserver/canserver.config
Normal file
5
Network_CAN_clientserver/canserver.config
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
// Add predefined macros for your project here. For example:
|
||||||
|
// #define THE_ANSWER 42
|
||||||
|
#define XOPEN_SOURCE 1234
|
||||||
|
#define DEFAULT_SOURCE
|
||||||
|
#define GNU_SOURCE
|
||||||
1
Network_CAN_clientserver/canserver.creator
Normal file
1
Network_CAN_clientserver/canserver.creator
Normal file
@ -0,0 +1 @@
|
|||||||
|
[General]
|
||||||
184
Network_CAN_clientserver/canserver.creator.user
Normal file
184
Network_CAN_clientserver/canserver.creator.user
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE QtCreatorProject>
|
||||||
|
<!-- Written by QtCreator 16.0.0, 2025-04-28T11:38:19. -->
|
||||||
|
<qtcreator>
|
||||||
|
<data>
|
||||||
|
<variable>EnvironmentId</variable>
|
||||||
|
<value type="QByteArray">{cf63021e-ef53-49b0-b03b-2f2570cdf3b6}</value>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
||||||
|
<value type="qlonglong">0</value>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
||||||
|
<valuemap type="QVariantMap">
|
||||||
|
<value type="bool" key="EditorConfiguration.AutoDetect">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
|
||||||
|
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
||||||
|
<value type="QString" key="language">Cpp</value>
|
||||||
|
<valuemap type="QVariantMap" key="value">
|
||||||
|
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
|
||||||
|
</valuemap>
|
||||||
|
</valuemap>
|
||||||
|
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
|
||||||
|
<value type="QString" key="language">QmlJS</value>
|
||||||
|
<valuemap type="QVariantMap" key="value">
|
||||||
|
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
|
||||||
|
</valuemap>
|
||||||
|
</valuemap>
|
||||||
|
<value type="qlonglong" key="EditorConfiguration.CodeStyle.Count">2</value>
|
||||||
|
<value type="QByteArray" key="EditorConfiguration.Codec">KOI8-R</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
||||||
|
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
|
||||||
|
<value type="int" key="EditorConfiguration.LineEndingBehavior">0</value>
|
||||||
|
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
||||||
|
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
||||||
|
<value type="int" key="EditorConfiguration.PreferAfterWhitespaceComments">0</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">false</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
|
||||||
|
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">1</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
||||||
|
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
||||||
|
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.UseIndenter">false</value>
|
||||||
|
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
||||||
|
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.inEntireDocument">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
|
||||||
|
<value type="bool" key="EditorConfiguration.tintMarginArea">true</value>
|
||||||
|
</valuemap>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
||||||
|
<valuemap type="QVariantMap">
|
||||||
|
<valuemap type="QVariantMap" key="AutoTest.ActiveFrameworks">
|
||||||
|
<value type="bool" key="AutoTest.Framework.Boost">true</value>
|
||||||
|
<value type="bool" key="AutoTest.Framework.CTest">false</value>
|
||||||
|
<value type="bool" key="AutoTest.Framework.Catch">true</value>
|
||||||
|
<value type="bool" key="AutoTest.Framework.GTest">true</value>
|
||||||
|
<value type="bool" key="AutoTest.Framework.QtQuickTest">true</value>
|
||||||
|
<value type="bool" key="AutoTest.Framework.QtTest">true</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="bool" key="AutoTest.ApplyFilter">false</value>
|
||||||
|
<valuemap type="QVariantMap" key="AutoTest.CheckStates"/>
|
||||||
|
<valuelist type="QVariantList" key="AutoTest.PathFilters"/>
|
||||||
|
<value type="int" key="AutoTest.RunAfterBuild">0</value>
|
||||||
|
<value type="bool" key="AutoTest.UseGlobal">true</value>
|
||||||
|
<valuemap type="QVariantMap" key="ClangTools">
|
||||||
|
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
|
||||||
|
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
|
||||||
|
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
|
||||||
|
<value type="int" key="ClangTools.ParallelJobs">4</value>
|
||||||
|
<value type="bool" key="ClangTools.PreferConfigFile">true</value>
|
||||||
|
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
|
||||||
|
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
|
||||||
|
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
|
||||||
|
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
|
||||||
|
</valuemap>
|
||||||
|
</valuemap>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.Target.0</variable>
|
||||||
|
<valuemap type="QVariantMap">
|
||||||
|
<value type="QString" key="DeviceType">Desktop</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{91347f2c-5221-46a7-80b1-0a054ca02f79}</value>
|
||||||
|
<value type="qlonglong" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||||
|
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||||
|
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||||
|
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/eddy/Docs/SAO/BTA/ACS-АСУ/Network_CAN_clientserver</value>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||||
|
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
||||||
|
<value type="QString">all</value>
|
||||||
|
</valuelist>
|
||||||
|
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Сборка</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||||
|
</valuemap>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||||
|
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
|
||||||
|
<value type="QString">clean</value>
|
||||||
|
</valuelist>
|
||||||
|
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Очистка</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Очистка</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||||
|
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||||
|
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
|
||||||
|
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
|
||||||
|
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">По умолчанию</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="qlonglong" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||||
|
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Развёртывание</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Развёртывание</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||||
|
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
||||||
|
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||||
|
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||||
|
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||||
|
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
|
||||||
|
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||||
|
<value type="QList<int>" key="Analyzer.Valgrind.VisibleErrorKinds"></value>
|
||||||
|
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||||
|
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||||
|
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||||
|
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||||
|
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||||
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
|
||||||
|
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
||||||
|
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||||
|
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||||
|
</valuemap>
|
||||||
|
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||||
|
</valuemap>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.TargetCount</variable>
|
||||||
|
<value type="qlonglong">1</value>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
|
||||||
|
<value type="int">22</value>
|
||||||
|
</data>
|
||||||
|
<data>
|
||||||
|
<variable>Version</variable>
|
||||||
|
<value type="int">22</value>
|
||||||
|
</data>
|
||||||
|
</qtcreator>
|
||||||
1
Network_CAN_clientserver/canserver.cxxflags
Normal file
1
Network_CAN_clientserver/canserver.cxxflags
Normal file
@ -0,0 +1 @@
|
|||||||
|
-std=c++17
|
||||||
8
Network_CAN_clientserver/canserver.files
Normal file
8
Network_CAN_clientserver/canserver.files
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
canproto.h
|
||||||
|
clientserver.c
|
||||||
|
clientserver.h
|
||||||
|
globopts.c
|
||||||
|
globopts.h
|
||||||
|
main.c
|
||||||
|
parsecanmsgs.c
|
||||||
|
parsecanmsgs.h
|
||||||
0
Network_CAN_clientserver/canserver.includes
Normal file
0
Network_CAN_clientserver/canserver.includes
Normal file
245
Network_CAN_clientserver/clientserver.c
Normal file
245
Network_CAN_clientserver/clientserver.c
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the canserver project.
|
||||||
|
* Copyright 2025 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "clientserver.h"
|
||||||
|
#include "parsecanmsgs.h"
|
||||||
|
|
||||||
|
static pthread_t clientthread;
|
||||||
|
sl_sock_t *serialsock = NULL;
|
||||||
|
|
||||||
|
#define CMDIN "in"
|
||||||
|
#define CMDOUT "out"
|
||||||
|
#define CMDMCUT "mcut"
|
||||||
|
#define CMDLED "led"
|
||||||
|
#define CMDINCH "inchnls"
|
||||||
|
#define CMDOUTCH "outchnls"
|
||||||
|
#define CMDTIME "time"
|
||||||
|
#define CMDPING "ping"
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
const char *textcmd;
|
||||||
|
int cancmd;
|
||||||
|
int havesetter;
|
||||||
|
} commands;
|
||||||
|
|
||||||
|
// list of all supported commands
|
||||||
|
static commands allcommands[] = {
|
||||||
|
{CMDIN, CMD_GETESW, 0},
|
||||||
|
{CMDOUT, CMD_RELAY, 1},
|
||||||
|
{CMDMCUT, CMD_MCUTEMP, 0},
|
||||||
|
{CMDLED, CMD_LED, 1},
|
||||||
|
{CMDINCH, CMD_INCHNLS, 0},
|
||||||
|
{CMDOUTCH, CMD_OUTCHNLS, 0},
|
||||||
|
{CMDTIME, CMD_TIME, 1},
|
||||||
|
{CMDPING, CMD_PING, 1},
|
||||||
|
{NULL, 0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int Relay1cmds(CAN_message *msg, char buf[BUFSIZ]){
|
||||||
|
int L = 0;
|
||||||
|
uint16_t cmd = MSGP_GET_CMD(msg);
|
||||||
|
uint8_t par = PARVAL(msg->data);
|
||||||
|
uint32_t data = MSGP_GET_U32(msg);
|
||||||
|
commands *c = allcommands;
|
||||||
|
while(c->textcmd){
|
||||||
|
if(cmd == c->cancmd) break;
|
||||||
|
++c;
|
||||||
|
}
|
||||||
|
if(!c->textcmd) return 0;
|
||||||
|
DBG("found text cmd is %s (%u)", c->textcmd, data);
|
||||||
|
if(par == NO_PARNO) L = snprintf(buf, BUFSIZ-1, "%s=%u\n", c->textcmd, data);
|
||||||
|
else L = snprintf(buf, BUFSIZ-1, "%s[%d]=%u\n", c->textcmd, par, data);
|
||||||
|
return L;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check CAN_message and if recognize send ans to all clients
|
||||||
|
static void gotCANans(CAN_message *msg){
|
||||||
|
if(!msg) return;
|
||||||
|
char buf[BUFSIZ];
|
||||||
|
int L = 0;
|
||||||
|
switch(msg->ID){
|
||||||
|
case CANIDOUT:
|
||||||
|
L = Relay1cmds(msg, buf);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(L < 1) return;
|
||||||
|
DBG("BUF: %s", buf);
|
||||||
|
int N = sl_sock_sendall((uint8_t*) buf, L);
|
||||||
|
green("Send to %d clients\n", N);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief clientproc - process data received from serial terminal
|
||||||
|
* @param par - socket
|
||||||
|
* @return NULL
|
||||||
|
*/
|
||||||
|
void *clientproc(void _U_ *par){
|
||||||
|
FNAME();
|
||||||
|
char rbuf[BUFSIZ];
|
||||||
|
if(!serialsock) return NULL;
|
||||||
|
do{
|
||||||
|
ssize_t got = sl_sock_readline(serialsock, rbuf, BUFSIZ);
|
||||||
|
if(got < 0){ // disconnected
|
||||||
|
WARNX("Serial server disconnected");
|
||||||
|
if(serialsock) sl_sock_delete(&serialsock);
|
||||||
|
return NULL;
|
||||||
|
}else if(got == 0){ // nothing to read from serial port
|
||||||
|
usleep(1000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// process data
|
||||||
|
DBG("GOT: %s", rbuf);
|
||||||
|
CAN_message msg;
|
||||||
|
if(parseCANstr(rbuf, &msg)){
|
||||||
|
DBG("Got CAN message");
|
||||||
|
gotCANans(&msg);
|
||||||
|
}
|
||||||
|
} while(serialsock && serialsock->connected);
|
||||||
|
WARNX("disconnected");
|
||||||
|
if(serialsock) sl_sock_delete(&serialsock);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static sl_sock_hresult_e dtimeh(sl_sock_t *client, _U_ sl_sock_hitem_t *item, _U_ const char *req){
|
||||||
|
char buf[32];
|
||||||
|
snprintf(buf, 31, "UNIXT=%.2f\n", sl_dtime());
|
||||||
|
sl_sock_sendstrmessage(client, buf);
|
||||||
|
return RESULT_SILENCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static sl_sock_hresult_e procUserCmd(sl_sock_t _U_ *client, sl_sock_hitem_t *item, const char *req){
|
||||||
|
#define CBUFLEN (128)
|
||||||
|
char buf[CBUFLEN];
|
||||||
|
int buflen = 0;
|
||||||
|
CAN_message msg;
|
||||||
|
msg.ID = CANIDIN;
|
||||||
|
int issetter = 0;
|
||||||
|
uint8_t parno = NO_PARNO;
|
||||||
|
uint32_t setterval = 0;
|
||||||
|
if(req){
|
||||||
|
int N;
|
||||||
|
if(!sl_str2i(&N, req) || N < 0){
|
||||||
|
DBG("BAD value %d", N);
|
||||||
|
return RESULT_BADVAL;
|
||||||
|
}
|
||||||
|
setterval = (uint32_t) N;
|
||||||
|
issetter = 1;
|
||||||
|
}
|
||||||
|
commands *c = allcommands;
|
||||||
|
while(c->textcmd){
|
||||||
|
if(0 == strcmp(c->textcmd, item->key)) break;
|
||||||
|
++c;
|
||||||
|
}
|
||||||
|
if(!c->textcmd) return RESULT_BADKEY;
|
||||||
|
if(issetter){
|
||||||
|
DBG("setter");
|
||||||
|
if(!c->havesetter) return RESULT_BADVAL;
|
||||||
|
if(CANu32setter(c->cancmd, parno, setterval, &msg) && (buflen = formCANmsg(&msg, buf, CBUFLEN-1)) > 0){
|
||||||
|
}else{
|
||||||
|
WARNX("Can't form message");
|
||||||
|
return RESULT_FAIL;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
DBG("getter");
|
||||||
|
if(CANu32getter(c->cancmd, parno, &msg) && (buflen = formCANmsg(&msg, buf, CBUFLEN-1)) > 0){
|
||||||
|
}else{
|
||||||
|
WARNX("Can't form message");
|
||||||
|
return RESULT_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(buflen) sl_sock_sendstrmessage(serialsock, buf);
|
||||||
|
return RESULT_SILENCE;
|
||||||
|
#undef CBUFLEN
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
static sl_sock_hresult_e show(sl_sock_t *client, _U_ sl_sock_hitem_t *item, _U_ const char *req){
|
||||||
|
if(!client) return RESULT_FAIL;
|
||||||
|
if(client->type != SOCKT_UNIX){
|
||||||
|
if(*client->IP){
|
||||||
|
printf("Client \"%s\" (fd=%d) ask for flags:\n", client->IP, client->fd);
|
||||||
|
}else printf("Can't get client's IP, flags:\n");
|
||||||
|
}else printf("Socket fd=%d asks for flags:\n", client->fd);
|
||||||
|
return RESULT_OK;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// Too much clients handler
|
||||||
|
static void toomuch(int fd){
|
||||||
|
const char m[] = "Try later: too much clients connected\n";
|
||||||
|
send(fd, m, sizeof(m)-1, MSG_NOSIGNAL);
|
||||||
|
shutdown(fd, SHUT_WR);
|
||||||
|
DBG("shutdown, wait");
|
||||||
|
double t0 = sl_dtime();
|
||||||
|
uint8_t buf[8];
|
||||||
|
while(sl_dtime() - t0 < 11.){
|
||||||
|
if(sl_canread(fd)){
|
||||||
|
ssize_t got = read(fd, buf, 8);
|
||||||
|
DBG("Got=%zd", got);
|
||||||
|
if(got < 1) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DBG("Disc after %gs", sl_dtime() - t0);
|
||||||
|
LOGWARN("Client fd=%d tried to connect after MAX reached", fd);
|
||||||
|
}
|
||||||
|
// new connections handler
|
||||||
|
static void connected(sl_sock_t *c){
|
||||||
|
if(c->type == SOCKT_UNIX) LOGMSG("New client fd=%d connected", c->fd);
|
||||||
|
else LOGMSG("New client fd=%d, IP=%s connected", c->fd, c->IP);
|
||||||
|
}
|
||||||
|
// disconnected handler
|
||||||
|
static void disconnected(sl_sock_t *c){
|
||||||
|
if(c->type == SOCKT_UNIX) LOGMSG("Disconnected client fd=%d", c->fd);
|
||||||
|
else LOGMSG("Disconnected client fd=%d, IP=%s", c->fd, c->IP);
|
||||||
|
}
|
||||||
|
|
||||||
|
static sl_sock_hitem_t handlers[] = {
|
||||||
|
{dtimeh, "dtime", "get server's UNIX time for all clients connected", NULL},
|
||||||
|
{procUserCmd, CMDOUT, "outputs setter/getter", NULL},
|
||||||
|
{procUserCmd, CMDIN, "inputs getter", NULL},
|
||||||
|
{procUserCmd, CMDMCUT, "get MCU temperature (/10degC)", NULL},
|
||||||
|
{procUserCmd, CMDLED, "onboard LED set/get", NULL},
|
||||||
|
{procUserCmd, CMDINCH, "get available input channels mask", NULL},
|
||||||
|
{procUserCmd, CMDOUTCH, "get available output channels mask", NULL},
|
||||||
|
{procUserCmd, CMDTIME, "get MCU milliseconds counter value", NULL},
|
||||||
|
{procUserCmd, CMDPING, "ping controller", NULL},
|
||||||
|
{NULL, NULL, NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
sl_sock_t *RunSrv(sl_socktype_e type, const char *node){
|
||||||
|
sl_sock_maxclhandler(toomuch);
|
||||||
|
sl_sock_connhandler(connected);
|
||||||
|
sl_sock_dischandler(disconnected);
|
||||||
|
return sl_sock_run_server(type, node, 4096, handlers);
|
||||||
|
}
|
||||||
|
|
||||||
|
sl_sock_t *RunClt(sl_socktype_e type, const char *node){
|
||||||
|
serialsock = sl_sock_run_client(type, node, 4096);
|
||||||
|
if(!serialsock){
|
||||||
|
DBG("Can't run client");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(pthread_create(&clientthread, NULL, clientproc, NULL)) return NULL;
|
||||||
|
return serialsock;
|
||||||
|
}
|
||||||
24
Network_CAN_clientserver/clientserver.h
Normal file
24
Network_CAN_clientserver/clientserver.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the canserver project.
|
||||||
|
* Copyright 2025 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
sl_sock_t *RunSrv(sl_socktype_e type, const char *node);
|
||||||
|
sl_sock_t *RunClt(sl_socktype_e type, const char *node);
|
||||||
41
Network_CAN_clientserver/globopts.c
Normal file
41
Network_CAN_clientserver/globopts.c
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the canserver project.
|
||||||
|
* Copyright 2025 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "globopts.h"
|
||||||
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
globopts UserOpts = {
|
||||||
|
.maxclients = 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
static sl_option_t cmdlnopts[] = {
|
||||||
|
{"help", NO_ARGS, NULL, 'h', arg_int, APTR(&UserOpts.help), "show this help"},
|
||||||
|
{"verbose", NO_ARGS, NULL, 'v', arg_none, APTR(&UserOpts.verbose), "verbose level (each -v adds 1)"},
|
||||||
|
{"logfile", NEED_ARG, NULL, 'l', arg_string, APTR(&UserOpts.logfile), "log file name"},
|
||||||
|
{"srvnode", NEED_ARG, NULL, 'N', arg_string, APTR(&UserOpts.srvnode), "server node \"port\", \"name:port\" or path (could be \"\\0path\" for anonymous UNIX-socket)"},
|
||||||
|
{"srvunix", NO_ARGS, NULL, 'U', arg_int, APTR(&UserOpts.srvunix), "server use UNIX socket instead of INET"},
|
||||||
|
{"maxclients", NEED_ARG, NULL, 'm', arg_int, APTR(&UserOpts.maxclients), "max amount of clients connected to server (default: 2)"},
|
||||||
|
{"cltnode", NEED_ARG, NULL, 'n', arg_string, APTR(&UserOpts.cltnode), "serial client node \"IP\", \"name:IP\" or path (could be \"\\0path\" for anonymous UNIX-socket)"},
|
||||||
|
{"cltunix", NO_ARGS, NULL, 'u', arg_int, APTR(&UserOpts.cltunix), "serial client use UNIX socket instead of INET"},
|
||||||
|
end_option
|
||||||
|
};
|
||||||
|
|
||||||
|
void parseargs(int argc, char **argv){
|
||||||
|
sl_parseargs(&argc, &argv, cmdlnopts);
|
||||||
|
if(UserOpts.help) sl_showhelp(-1, cmdlnopts);
|
||||||
|
}
|
||||||
34
Network_CAN_clientserver/globopts.h
Normal file
34
Network_CAN_clientserver/globopts.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the canserver project.
|
||||||
|
* Copyright 2025 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
int help;
|
||||||
|
int verbose;
|
||||||
|
int srvunix;
|
||||||
|
int cltunix;
|
||||||
|
int maxclients;
|
||||||
|
char *logfile;
|
||||||
|
char *srvnode;
|
||||||
|
char *cltnode;
|
||||||
|
} globopts;
|
||||||
|
|
||||||
|
extern globopts UserOpts;
|
||||||
|
|
||||||
|
void parseargs(int argc, char **argv);
|
||||||
81
Network_CAN_clientserver/main.c
Normal file
81
Network_CAN_clientserver/main.c
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the canserver project.
|
||||||
|
* Copyright 2025 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
#include "clientserver.h"
|
||||||
|
#include "globopts.h"
|
||||||
|
|
||||||
|
static sl_sock_t *srv = NULL, *clt = NULL;
|
||||||
|
|
||||||
|
void signals(int sig){
|
||||||
|
if(sig){
|
||||||
|
signal(sig, SIG_IGN);
|
||||||
|
DBG("Get signal %d, quit.\n", sig);
|
||||||
|
LOGERR("Exit with status %d", sig);
|
||||||
|
}else LOGERR("Exit");
|
||||||
|
if(srv){
|
||||||
|
DBG("Del server");
|
||||||
|
sl_sock_delete(&srv);
|
||||||
|
}
|
||||||
|
if(clt){
|
||||||
|
DBG("Del client");
|
||||||
|
sl_sock_delete(&clt);
|
||||||
|
}
|
||||||
|
exit(sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char **argv){
|
||||||
|
sl_init();
|
||||||
|
parseargs(argc, argv);
|
||||||
|
if(!UserOpts.srvnode) ERRX("Point server node");
|
||||||
|
if(!UserOpts.cltnode) ERRX("Point serial client node");
|
||||||
|
sl_socktype_e type = (UserOpts.srvunix) ? SOCKT_UNIX : SOCKT_NET;
|
||||||
|
sl_sock_changemaxclients(UserOpts.maxclients);
|
||||||
|
srv = RunSrv(type, UserOpts.srvnode);
|
||||||
|
if(!srv) ERRX("Server: can't create socket and/or run threads");
|
||||||
|
DBG("Server done");
|
||||||
|
type = (UserOpts.cltunix) ? SOCKT_UNIX : SOCKT_NET;
|
||||||
|
clt = RunClt(type, UserOpts.cltnode);
|
||||||
|
if(!clt) ERRX("Serial client: can't connect to socket and/or run threads");
|
||||||
|
DBG("Client done");
|
||||||
|
sl_loglevel_e lvl = UserOpts.verbose + LOGLEVEL_ERR;
|
||||||
|
if(lvl >= LOGLEVEL_AMOUNT) lvl = LOGLEVEL_AMOUNT - 1;
|
||||||
|
if(UserOpts.logfile) OPENLOG(UserOpts.logfile, lvl, 1);
|
||||||
|
LOGMSG("Started");
|
||||||
|
signal(SIGTERM, signals);
|
||||||
|
signal(SIGINT, signals);
|
||||||
|
signal(SIGQUIT, signals);
|
||||||
|
signal(SIGTSTP, SIG_IGN);
|
||||||
|
signal(SIGHUP, signals);
|
||||||
|
while(srv && srv->connected && clt && clt->connected){
|
||||||
|
if(!srv->rthread){
|
||||||
|
WARNX("Server handlers thread is dead");
|
||||||
|
LOGERR("Server handlers thread is dead");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOGMSG("End");
|
||||||
|
DBG("Close");
|
||||||
|
if(srv) sl_sock_delete(&srv);
|
||||||
|
if(clt) sl_sock_delete(&clt);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
91
Network_CAN_clientserver/parsecanmsgs.c
Normal file
91
Network_CAN_clientserver/parsecanmsgs.c
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the canserver project.
|
||||||
|
* Copyright 2025 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
#include "parsecanmsgs.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief parseCANstr - parser of string like "timestamp #ID [data0 data1 ...]"
|
||||||
|
* @param str - input string
|
||||||
|
* @param msg - message to fill
|
||||||
|
* @return FALSE if given string isn't CAN message
|
||||||
|
*/
|
||||||
|
int parseCANstr(const char *str, CAN_message *msg){
|
||||||
|
if(!str || !msg) return FALSE;
|
||||||
|
const char *IDstart = strchr(str, '#');
|
||||||
|
if(!IDstart) return FALSE;
|
||||||
|
++IDstart;
|
||||||
|
msg->timestamp = atoi(str);
|
||||||
|
DBG("Timestamp: %u", msg->timestamp);
|
||||||
|
unsigned bytes[9];
|
||||||
|
int N = sscanf(IDstart, "%x %x %x %x %x %x %x %x %x",
|
||||||
|
&bytes[0], &bytes[1], &bytes[2], &bytes[3], &bytes[4], &bytes[5], &bytes[6], &bytes[7], &bytes[8]);
|
||||||
|
if(N < 1) return FALSE; // where's ID?
|
||||||
|
DBG("ID=%u", bytes[0]);
|
||||||
|
msg->length = N - 1;
|
||||||
|
msg->ID = bytes[0];
|
||||||
|
for(int i = 0; i < msg->length; ++i) msg->data[i] = bytes[i + 1];
|
||||||
|
DBG("length: %u", msg->length);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return result of snprintf
|
||||||
|
int formCANmsg(CAN_message *msg, char *buf, int buflen){
|
||||||
|
if(!msg || !buf || buflen < 8) return 0;
|
||||||
|
DBG("msg ID=%u, len=%u", msg->ID, msg->length);
|
||||||
|
int L = snprintf(buf, buflen, "s %u ", msg->ID);
|
||||||
|
for(int i = 0; i < msg->length && L < buflen; ++i)
|
||||||
|
L += snprintf(buf + L, buflen - L, "%u ", msg->data[i]);
|
||||||
|
if(L >= buflen){
|
||||||
|
WARNX("buffer overflow");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
L += snprintf(buf + L, buflen - L, "\n");
|
||||||
|
DBG("convert CAN message to %d symbols: _%s_", L, buf);
|
||||||
|
return L;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fill command and parameter into message
|
||||||
|
// !!!!! msg->ID should be set by user !!!!!
|
||||||
|
static int fillcmd(int cancmd, uint8_t par, CAN_message *msg){
|
||||||
|
if(!msg || cancmd > 0xffff) return FALSE;
|
||||||
|
MSGP_SET_CMD(msg, cancmd);
|
||||||
|
MSGP_SET_PARNO(msg, par);
|
||||||
|
MSGP_SET_ERR(msg, 0);
|
||||||
|
msg->length = 4;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CANu32setter(int cancmd, uint8_t par, uint32_t data, CAN_message *msg){
|
||||||
|
if(!msg) return FALSE;
|
||||||
|
par |= SETTER_FLAG;
|
||||||
|
if(!fillcmd(cancmd, par, msg)) return FALSE;
|
||||||
|
MSGP_SET_U32(msg, data);
|
||||||
|
msg->length = 8;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CANu32getter(int cancmd, uint8_t par, CAN_message *msg){
|
||||||
|
if(!msg) return FALSE;
|
||||||
|
if(!fillcmd(cancmd, par, msg)) return FALSE;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
39
Network_CAN_clientserver/parsecanmsgs.h
Normal file
39
Network_CAN_clientserver/parsecanmsgs.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the canserver project.
|
||||||
|
* Copyright 2025 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "canproto.h"
|
||||||
|
|
||||||
|
#define CANIDIN 1
|
||||||
|
#define CANIDOUT 2
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
uint16_t ID; // message ID
|
||||||
|
uint32_t timestamp; // milliseconds timestamp
|
||||||
|
uint8_t length; // data length
|
||||||
|
uint8_t data[8]; // up to 8 bytes of data
|
||||||
|
} CAN_message;
|
||||||
|
|
||||||
|
int parseCANstr(const char *str, CAN_message *msg);
|
||||||
|
int formCANmsg(CAN_message *msg, char *buf, int buflen);
|
||||||
|
|
||||||
|
int CANu32setter(int cancmd, uint8_t par, uint32_t data, CAN_message *msg);
|
||||||
|
int CANu32getter(int cancmd, uint8_t par, CAN_message *msg);
|
||||||
1
Network_CAN_clientserver/run
Normal file
1
Network_CAN_clientserver/run
Normal file
@ -0,0 +1 @@
|
|||||||
|
socat tcp-l:22222,reuseaddr,fork file:/dev/multistepper0,rawer
|
||||||
Loading…
x
Reference in New Issue
Block a user