Compare commits

...

29 Commits
master ... me

Author SHA1 Message Date
Dongly 775ca9f499 fix 内存越界 2024-06-18 15:16:29 +08:00
Dongly 0af2878317 sn 固定前缀 2024-06-18 09:43:54 +08:00
Dongly ea8c32594c Merge remote-tracking branch 'official/master' into me 2024-06-18 09:40:40 +08:00
chinky aa64af85fd 手动输入sn 2024-06-17 16:31:58 +08:00
Hans-Erik Floryd 83c6264f99 Fix potential buffer overflow in exc_FOEread/write
An excessively long filename could overflow the mailbox buffer. Fix by
limiting the filename size to EC_MAXFOEDATA.

Problem found and fix proposed by m1etz.
2024-04-04 09:55:57 +02:00
Windsgo d478bce787
Fix `add_timespec` in other codes besides `red_test` (#794) 2024-03-21 07:51:29 +01:00
Chinky 1bdff2341d tj30_test check id 2024-03-15 17:22:27 +08:00
Chinky 750fc89ebb TJ30-1616DN bin 2024-03-15 17:22:02 +08:00
chinky 9ced549488 eeprom bin 改为 AX58100 EVB 2024-03-14 20:05:44 +08:00
Chinky 4ef663c66d change bin to ax58100 evd 2024-01-26 15:35:02 +08:00
Chinky 22420644c2 g 2024-01-23 18:07:06 +08:00
Chinky d29d9d4dac g 2024-01-22 16:04:40 +08:00
Chinky 1ab222fbd1 d 2024-01-22 10:25:46 +08:00
Chinky 8ec3391cbd test 2024-01-22 09:31:17 +08:00
Chinky 9c8dd8c2a1 fix bug 2024-01-19 22:20:30 +08:00
Chinky 35bfaf70c3 写sn并记录到数据库 2024-01-18 23:48:11 +08:00
Chinky a279640e26 优化代码 2024-01-17 17:55:45 +08:00
Chinky 5d2b04e7b3 get slave count 2024-01-14 23:08:53 +08:00
Chinky 5fbafd07ec 优化参数判断 2024-01-14 18:52:16 +08:00
Chinky 25fd9f81fb 加入 写 SN 2024-01-14 18:31:52 +08:00
Chinky be172749b2 format code 2024-01-14 16:48:30 +08:00
Chinky aa2c438d21 step time 可变 2024-01-14 15:59:51 +08:00
Chinky 2fabd78466 加入test error count ,fix set_bit / clr_bit 2024-01-14 15:43:04 +08:00
Chinky 1970f178fd cycletime可选,优化显示 2024-01-14 14:47:33 +08:00
Chinky 8479266ba2 [tj30_test]1.io_check 2. 修正diff 显示错误 2024-01-14 13:49:08 +08:00
Chinky d18d90cce5 [tj30 test]优化显示 2024-01-13 11:13:11 +08:00
Chinky 0a4cdc48ce 显示测试结果 2024-01-12 23:50:05 +08:00
Chinky 636c2b63bc io_test 输出流水灯 2024-01-12 17:14:29 +08:00
Chinky deeb945dae tj30_test 2024-01-11 22:00:10 +08:00
36 changed files with 2760 additions and 503 deletions

2
.gitignore vendored
View File

@ -4,3 +4,5 @@ install
/doc/latex
/doc/html
tags
*.pyc
test/linux/eceeprom/sn.csv

19
.vscode/c_cpp_properties.json vendored Normal file
View File

@ -0,0 +1,19 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/soem/**",
"${workspaceFolder}/oshw/linux/**",
"${workspaceFolder}/oshw/linux/**"
],
"defines": [],
"compilerPath": "/usr/bin/gcc-12",
"cStandard": "c17",
"cppStandard": "c++14",
"intelliSenseMode": "linux-gcc-x64",
"configurationProvider": "ms-vscode.cmake-tools"
}
],
"version": 4
}

12
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,12 @@
{
"files.associations": {
"time.h": "c",
"time_t.h": "c",
"struct_timeval.h": "c",
"features.h": "c",
"random": "c",
"logn.h": "c",
"timesize.h": "c"
},
"cmake.configureOnOpen": true
}

28
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,28 @@
{
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: gcc-13 生成活动文件",
"command": "/usr/bin/gcc-13",
"args": [
"-fdiagnostics-color=always",
"-g",
"${file}",
"-o",
"${fileDirname}/${fileBasenameNoExtension}"
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "调试器生成的任务。"
}
],
"version": "2.0.0"
}

View File

@ -1,5 +1,7 @@
cmake_minimum_required(VERSION 3.9)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/cmake/Modules")
# SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
project(SOEM
DESCRIPTION "Simple Open EtherCAT Master"
VERSION 1.4.0
@ -33,7 +35,7 @@ if(WIN32)
set(OS_LIBS wpcap.lib Packet.lib Ws2_32.lib Winmm.lib)
elseif(UNIX AND NOT APPLE)
set(OS "linux")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror -fPIC")
set(OS_LIBS pthread rt)
elseif(APPLE)
# This must come *before* linux or MacOSX will identify as Unix.
@ -106,8 +108,10 @@ install(FILES
DESTINATION ${SOEM_INCLUDE_INSTALL_DIR})
if(BUILD_TESTS)
add_subdirectory(test/simple_ng)
add_subdirectory(test/linux/slaveinfo)
add_subdirectory(test/linux/eepromtool)
add_subdirectory(test/linux/simple_test)
# add_subdirectory(test/simple_ng)
add_subdirectory(test/linux/ecslaveinfo)
add_subdirectory(test/linux/eceeprom)
# add_subdirectory(test/linux/simple_test)
add_subdirectory(test/linux/tj30_test)
# add_subdirectory(test/linux/red_test)
endif()

View File

@ -54,7 +54,7 @@ boolean osal_timer_is_expired (osal_timert * self)
stop_time.tv_usec = self->stop_time.usec;
is_not_yet_expired = timercmp (&current_time, &stop_time, <);
return is_not_yet_expired == FALSE;
return is_not_yet_expired == FALSE; // !is_not_yet_expired
}
int osal_usleep(uint32 usec)

View File

@ -87,6 +87,10 @@ int ecx_FOEread(ecx_contextt *context, uint16 slave, char *filename, uint32 pass
aFOEp = (ec_FOEt *)&MbxIn;
FOEp = (ec_FOEt *)&MbxOut;
fnsize = (uint16)strlen(filename);
if (fnsize > EC_MAXFOEDATA)
{
fnsize = EC_MAXFOEDATA;
}
maxdata = context->slavelist[slave].mbx_l - 12;
if (fnsize > maxdata)
{
@ -216,6 +220,10 @@ int ecx_FOEwrite(ecx_contextt *context, uint16 slave, char *filename, uint32 pas
FOEp = (ec_FOEt *)&MbxOut;
dofinalzero = TRUE;
fnsize = (uint16)strlen(filename);
if (fnsize > EC_MAXFOEDATA)
{
fnsize = EC_MAXFOEDATA;
}
maxdata = context->slavelist[slave].mbx_l - 12;
if (fnsize > maxdata)
{

38
test/linux/.clang-format Normal file
View File

@ -0,0 +1,38 @@
---
Language: Cpp
BasedOnStyle: LLVM
ColumnLimit: 100
AccessModifierOffset: -4
# 连续赋值时,对齐所有等号
AlignConsecutiveAssignments: false
# 连续宏时,对齐所有宏
AlignConsecutiveMacros: true
# 连续声明时,对齐所有声明的变量名
AlignConsecutiveDeclarations: true
# 水平对齐二元和三元表达式的操作数
AlignOperands: true
# 对齐连续的尾随的注释
AlignTrailingComments:true
# 允许函数声明的所有参数在放在下一行
AllowAllParametersOfDeclarationOnNextLine: false
# 允许短的块放在同一行
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: false
BreakBeforeBraces: Allman
BraceWrapping:
AfterFunction: true
BreakBeforeBinaryOperators: true
IndentCaseLabels: false
IndentWidth: 4
NamespaceIndentation: All
TabWidth: 4
UseTab: Never
# 代码块的开始处不能有空行
KeepEmptyLinesAtTheStartOfBlocks: false
# 连续的空行只保留至多两个这样的话1个和2个会有区别感
MaxEmptyLinesToKeep: 2
...

View File

@ -250,7 +250,7 @@ void add_timespec(struct timespec *ts, int64 addtime)
sec = (addtime - nsec) / NSEC_PER_SEC;
ts->tv_sec += sec;
ts->tv_nsec += nsec;
if ( ts->tv_nsec > NSEC_PER_SEC )
if ( ts->tv_nsec >= NSEC_PER_SEC )
{
nsec = ts->tv_nsec % NSEC_PER_SEC;
ts->tv_sec += (ts->tv_nsec - nsec) / NSEC_PER_SEC;

1
test/linux/eceeprom/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.csv

View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<!-- AX58100 EVB ESI Sample File - "AX58100 EVB (Digital 16-Input/16-Output)" -->
<EtherCATInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="EtherCATInfo.xsd" Version="1.2">
<Vendor>
<Id>#x00000b95</Id>
<Name>ASIX Electronics Corporation</Name>
<ImageData16x14>424DE6000000000000007600000028000000100000000E000000010004000000000070000000120B0000120B0000100000001000000000000000000080000080000000808000800000008000800080800000C0C0C000808080000000FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00FFF4444444444FFFFF448888888844FFF484448FF844484F4888444FF44488844F8F44444444F8F448884444444488844F8F84444448F8F448888444444888844F8F8F4444F8F8F4F48888444488884FFF4F8F4444F8F4FFFF448884488844FFFFFF4F8448F4FFFFFFFFF444444FFFFF</ImageData16x14>
</Vendor>
<Descriptions>
<Groups>
<Group>
<Type>AX58100_EVB</Type>
<Name LcId="1031">AX58100_EVB</Name>
<ImageData16x14>424DD6020000000000003600000028000000100000000E0000000100180000000000A0020000120B0000120B00000000000000000000FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF0000FFFF00FFFF00FFFF00FF0000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF0000FFFF00FFFF00FF0000FF0000FF0000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF0000FF0000FF0000FFFF00FFFF00FF0000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF0000FFFF00FFFF00FFFF00FF0000FFFF00FF008000008000008000008000008000008000008000008000404040404040404040404040404040404040404040404040008000007FFF007FFF00800000800000800000800000800040404000800000800000800000800000800000800040404000800000800000800000800000800000800000800000800040404000800000800000800000800000800000800040404000800000800000800000800000800000800000800000800040404000800000800000800000800000800000800040404000800000800000800000800000800000800000800000800040404040404040404040404040404040404040404040404000800000800000800000800000800000800000800000800000800000800000800000800000800000800000800000800000800000FFFF00800000FFFF00800000800000FFFF00800000FFFF00800000800000800000FFFF00800000FFFF00800000800000800000800000800000800000800000800000800000800000800000800000800000800000800000800000800000800000FFFF00800000FFFF00800000800000FFFF00800000FFFF00800000800000800000FFFF00800000FFFF008000008000008000008000008000008000008000008000008000008000008000008000008000008000008000008000008000</ImageData16x14>
</Group>
</Groups>
<Devices>
<!-- DIO, GPIO, FMMU=2, SM=3, DI=16, DO=16, ProductCode="#x00010200" RevisionNo="#x00000001" -->
<Device Physics="YY">
<Type ProductCode="#x00010200" RevisionNo="#x00000001">AX58100_EVB_DIO_16</Type>
<Name LcId="1031">AX58100 EVB (Digital 16-Input/16-Output)</Name>
<GroupType>AX58100_EVB</GroupType>
<Fmmu>Outputs</Fmmu>
<Fmmu>Inputs</Fmmu>
<Sm StartAddress="#x0f02" ControlByte="#x44" Enable="1" OpOnly="1">Outputs</Sm>
<Sm StartAddress="#x0f03" ControlByte="#x44" Enable="1" OpOnly="1">Outputs</Sm>
<Sm StartAddress="#x1000" ControlByte="0" Enable="1">Inputs</Sm>
<RxPdo Fixed="1" Sm="0">
<Index>#x1a00</Index>
<Name>Byte 0</Name>
<Entry>
<Index>#x3101</Index>
<SubIndex>1</SubIndex>
<BitLen>8</BitLen>
<Name>Output</Name>
<DataType>BITARR8</DataType>
</Entry>
</RxPdo>
<RxPdo Fixed="1" Sm="1">
<Index>#x1a01</Index>
<Name>Byte 1</Name>
<Entry>
<Index>#x3101</Index>
<SubIndex>2</SubIndex>
<BitLen>8</BitLen>
<Name>Output</Name>
<DataType>BITARR8</DataType>
</Entry>
</RxPdo>
<TxPdo Fixed="1" Sm="2">
<Index>#x1600</Index>
<Name>Byte 0</Name>
<Entry>
<Index>#x3001</Index>
<SubIndex>1</SubIndex>
<BitLen>8</BitLen>
<Name>Input</Name>
<DataType>BITARR8</DataType>
</Entry>
</TxPdo>
<TxPdo Fixed="1" Sm="2">
<Index>#x1601</Index>
<Name>Byte 1</Name>
<Entry>
<Index>#x3001</Index>
<SubIndex>2</SubIndex>
<BitLen>8</BitLen>
<Name>Input</Name>
<DataType>BITARR8</DataType>
</Entry>
</TxPdo>
<Dc>
<OpMode>
<Name>DcOff</Name>
<Desc>DC unused</Desc>
<AssignActivate>#x0000</AssignActivate>
</OpMode>
<OpMode>
<Name>DcSync</Name>
<Desc>DC for synchronization</Desc>
<AssignActivate>#x0100</AssignActivate>
<CycleTimeSync0 Factor="1">0</CycleTimeSync0>
<ShiftTimeSync0>0</ShiftTimeSync0>
</OpMode>
</Dc>
<Eeprom>
<ByteSize>2048</ByteSize>
<ConfigData>040d0044102700ff000000000000</ConfigData>
</Eeprom>
</Device>
</Devices>
</Descriptions>
</EtherCATInfo>

View File

@ -0,0 +1,23 @@
file(GLOB SOURCES *.c)
add_executable(eceeprom ${SOURCES})
target_link_libraries(eceeprom soem)
install(TARGETS eceeprom DESTINATION bin)
set(LIB_SRC eceeprom.c)
add_library(eceeprom_lib SHARED ${LIB_SRC})
set_target_properties(eceeprom_lib PROPERTIES OUTPUT_NAME "eceeprom")
target_link_libraries(eceeprom_lib soem)
add_library(eceeprom_static STATIC ${LIB_SRC})
set_target_properties(eceeprom_static PROPERTIES OUTPUT_NAME "eceeprom")
target_link_libraries(eceeprom_static soem)
target_include_directories(eceeprom_static
PUBLIC .)
install(TARGETS eceeprom_lib LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
install(FILES eceeprom.h DESTINATION include)
install(FILES ec_eeprom.py ec_eeprom301616.py ch_eeprom.py sn.py test.sh ch.sh DESTINATION bin PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
install(FILES database.py Verhoeff.py config.toml TJ30-1616DN-EEPROM.bin TongJi_TJ03-1616DN.xml DESTINATION bin)

Binary file not shown.

View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<!-- TJ30-1616DN ESI File - "TJ30-1616DN (Digital 16-Input/16-Output)" -->
<EtherCATInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="EtherCATInfo.xsd" Version="1.2">
<Vendor>
<Id>#x00000b95</Id>
<Name>ASIX Electronics Corporation</Name>
<ImageData16x14>424DE6000000000000007600000028000000100000000E000000010004000000000070000000120B0000120B0000100000001000000000000000000080000080000000808000800000008000800080800000C0C0C000808080000000FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00FFF4444444444FFFFF448888888844FFF484448FF844484F4888444FF44488844F8F44444444F8F448884444444488844F8F84444448F8F448888444444888844F8F8F4444F8F8F4F48888444488884FFF4F8F4444F8F4FFFF448884488844FFFFFF4F8448F4FFFFFFFFF444444FFFFF</ImageData16x14>
</Vendor>
<Descriptions>
<Groups>
<Group>
<Type>TJ30-1616DN</Type>
<Name LcId="1031">TJ30-1616DN</Name>
<ImageData16x14>424DD6020000000000003600000028000000100000000E0000000100180000000000A0020000120B0000120B00000000000000000000FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF0000FFFF00FFFF00FFFF00FF0000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF0000FFFF00FFFF00FF0000FF0000FF0000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF0000FF0000FF0000FFFF00FFFF00FF0000FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF0000FFFF00FFFF00FFFF00FF0000FFFF00FF008000008000008000008000008000008000008000008000404040404040404040404040404040404040404040404040008000007FFF007FFF00800000800000800000800000800040404000800000800000800000800000800000800040404000800000800000800000800000800000800000800000800040404000800000800000800000800000800000800040404000800000800000800000800000800000800000800000800040404000800000800000800000800000800000800040404000800000800000800000800000800000800000800000800040404040404040404040404040404040404040404040404000800000800000800000800000800000800000800000800000800000800000800000800000800000800000800000800000800000FFFF00800000FFFF00800000800000FFFF00800000FFFF00800000800000800000FFFF00800000FFFF00800000800000800000800000800000800000800000800000800000800000800000800000800000800000800000800000800000800000FFFF00800000FFFF00800000800000FFFF00800000FFFF00800000800000800000FFFF00800000FFFF008000008000008000008000008000008000008000008000008000008000008000008000008000008000008000008000008000</ImageData16x14>
</Group>
</Groups>
<Devices>
<!-- DIO, GPIO, FMMU=2, SM=3, DI=16, DO=16, ProductCode="#x00010200" RevisionNo="#x00000001" -->
<Device Physics="YY">
<Type ProductCode="#x00010200" RevisionNo="#x00000001">TJ30-1616DN</Type>
<Name LcId="1031">TJ30-1616DN (Digital 16-Input/16-Output)</Name>
<GroupType>TJ30-1616DN</GroupType>
<Fmmu>Outputs</Fmmu>
<Fmmu>Inputs</Fmmu>
<Sm StartAddress="#x0f02" ControlByte="#x44" Enable="1" OpOnly="1">Outputs</Sm>
<Sm StartAddress="#x0f03" ControlByte="#x44" Enable="1" OpOnly="1">Outputs</Sm>
<Sm StartAddress="#x1000" ControlByte="0" Enable="1">Inputs</Sm>
<RxPdo Fixed="1" Sm="0">
<Index>#x1a00</Index>
<Name>Byte 0</Name>
<Entry>
<Index>#x3101</Index>
<SubIndex>1</SubIndex>
<BitLen>8</BitLen>
<Name>Output</Name>
<DataType>BITARR8</DataType>
</Entry>
</RxPdo>
<RxPdo Fixed="1" Sm="1">
<Index>#x1a01</Index>
<Name>Byte 1</Name>
<Entry>
<Index>#x3101</Index>
<SubIndex>2</SubIndex>
<BitLen>8</BitLen>
<Name>Output</Name>
<DataType>BITARR8</DataType>
</Entry>
</RxPdo>
<TxPdo Fixed="1" Sm="2">
<Index>#x1600</Index>
<Name>Byte 0</Name>
<Entry>
<Index>#x3001</Index>
<SubIndex>1</SubIndex>
<BitLen>8</BitLen>
<Name>Input</Name>
<DataType>BITARR8</DataType>
</Entry>
</TxPdo>
<TxPdo Fixed="1" Sm="2">
<Index>#x1601</Index>
<Name>Byte 1</Name>
<Entry>
<Index>#x3001</Index>
<SubIndex>2</SubIndex>
<BitLen>8</BitLen>
<Name>Input</Name>
<DataType>BITARR8</DataType>
</Entry>
</TxPdo>
<Dc>
<OpMode>
<Name>DcOff</Name>
<Desc>DC unused</Desc>
<AssignActivate>#x0000</AssignActivate>
</OpMode>
<OpMode>
<Name>DcSync</Name>
<Desc>DC for synchronization</Desc>
<AssignActivate>#x0100</AssignActivate>
<CycleTimeSync0 Factor="1">0</CycleTimeSync0>
<ShiftTimeSync0>0</ShiftTimeSync0>
</OpMode>
</Dc>
<Eeprom>
<ByteSize>2048</ByteSize>
<ConfigData>040d0044102700ff000000000000</ConfigData>
</Eeprom>
</Device>
</Devices>
</Descriptions>
</EtherCATInfo>

53
test/linux/eceeprom/Verhoeff.py Executable file
View File

@ -0,0 +1,53 @@
#!`which python`
# Copyright (c) 2012, Simon David Pratt <me@simondavidpratt.com>
# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the
# above copyright notice and this permission notice appear in all
# copies.
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
# PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
d_table = [[0,1,2,3,4,5,6,7,8,9],
[1,2,3,4,0,6,7,8,9,5],
[2,3,4,0,1,7,8,9,5,6],
[3,4,0,1,2,8,9,5,6,7],
[4,0,1,2,3,9,5,6,7,8],
[5,9,8,7,6,0,4,3,2,1],
[6,5,9,8,7,1,0,4,3,2],
[7,6,5,9,8,2,1,0,4,3],
[8,7,6,5,9,3,2,1,0,4],
[9,8,7,6,5,4,3,2,1,0]]
def d(j,k):
return d_table[j][k]
p_table = [[0,1,2,3,4,5,6,7,8,9],
[1,5,7,6,2,8,3,0,9,4],
[5,8,0,3,7,9,6,1,4,2],
[8,9,1,6,0,4,3,5,2,7],
[9,4,5,3,1,2,6,8,7,0],
[4,2,8,6,5,7,3,9,0,1],
[2,7,9,3,8,0,6,4,1,5],
[7,0,4,6,9,1,3,2,5,8]]
def p(pos,num):
return p_table[pos%8][num]
def checksum(digits_str):
c=0
l = len(digits_str)-1
for i in range(0,l):
c=d(c,p(i,int(digits_str[l-i])))
return c
def verify(digits_str):
return checksum(digits_str[:-1]) == int(digits_str[-1])

10
test/linux/eceeprom/ch.sh Normal file
View File

@ -0,0 +1,10 @@
#!/bin/env bash
dir=$(cd "$(dirname $0)";pwd)
${dir}/ch_eeprom.py
echo 请先断电,再通电
read -n 1 -s -r -p "按任意键继续..."
sleep 2
# ${dir}/ecslaveinfo enp3s0f1
${dir}/tj30_test enp3s0f0

View File

@ -0,0 +1,65 @@
#!/root/venv/bin/python
import sys
from ctypes import *
from database import *
from sn import *
ll = cdll.LoadLibrary
# ece = ll("../../../build/test/linux/eceeprom/libeceeprom.so")
ece = ll("../lib/libeceeprom.so")
def change_multi_eeprom(count: int, eeprome_file: str):
# 当从机数量大于1时,不写最后一个
if count == 1:
count = 2
for i in range(1, count):
sn = ece.ecEepromGetSN(i)
print(f"Get origin SN: {sn}")
if sn==0:
print("SN is ERROR!!")
while True:
pass
print(f"Write file '{eeprome_file}' to slave EEPROM #{i}, SN = {sn} \n")
rc = ece.ecFileToEeprom(
c_int(i), c_char_p(eeprome_file), c_bool(False), c_uint(sn)
)
if rc > 0:
print("update eeprom sussus\n")
else:
print("Update EEPROM FAIL!\n")
def main():
is_force = False
if len(sys.argv) == 2 and sys.argv[1] == "-force":
is_force = True
ifname = b"enp3s0f0"
if ece.ec_init(c_char_p(ifname)) <= 0:
print("No socket connection on %s\nExcecute as root\n" % ifname)
return -1
print("ec_init on %s succeeded.\n" % ifname)
# Get the number of slaves
slaveCount = ece.ecGetSlaveCount()
if slaveCount < 1:
print("No slaves found!\n")
ece.ec_close()
return -1
print("Found %d slave(s)\n" % slaveCount)
# # # Write the SN
# session = db_init()
eeprom_file = b"./AX58100_EVD_16DI_16DO.bin"
change_multi_eeprom(slaveCount, eeprom_file)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,6 @@
[database]
user = "root"
password = "lldlcj123"
host = "192.168.222.5"
port = 6306
database = "product"

141
test/linux/eceeprom/database.py Executable file
View File

@ -0,0 +1,141 @@
#!/bin/env python
from sqlalchemy import (
create_engine,
Column,
Integer,
String,
DateTime,
ForeignKey,
func,
UniqueConstraint,
select,
)
from sqlalchemy.orm import sessionmaker, relationship, DeclarativeBase
import toml
# Declare models
class Base(DeclarativeBase):
pass
class Products(Base):
__tablename__ = "products"
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(128), nullable=False)
prefix = Column(String(16))
product_code = Column(String(32))
note = Column(String(512))
created_at = Column(DateTime, server_default=func.current_timestamp())
updated_at = Column(
DateTime,
server_default=func.current_timestamp(),
server_onupdate=func.current_timestamp(),
)
product_list = relationship("ProductList", back_populates="products")
__table_args__ = (UniqueConstraint("name", "prefix", "product_code"),)
class ProductList(Base):
__tablename__ = "product_list"
id = Column(Integer, primary_key=True, autoincrement=True)
product_id = Column(Integer, ForeignKey("products.id"), nullable=False)
sn = Column(Integer, nullable=False)
note = Column(String(128))
created_at = Column(DateTime, server_default=func.current_timestamp())
products = relationship("Products", back_populates="product_list")
__table_args__ = (UniqueConstraint("sn"),)
# Database initialization
def db_init():
config = toml.load("config.toml")
db_config = config["database"]
user = db_config["user"]
password = db_config["password"]
host = db_config["host"]
port = db_config["port"]
database = db_config["database"]
engine = create_engine(
f"mysql+pymysql://{user}:{password}@{host}:{port}/{database}?charset=utf8mb4",
# echo=True,
)
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
return session
# Get the last sn for a given product name
def get_last_sn(session, product_name: str) -> int:
stmt = (
select(ProductList.sn)
.join(ProductList.products)
.order_by(ProductList.created_at.desc())
.filter_by(name=product_name)
)
last_sn_record = session.execute(stmt).first()
if last_sn_record is not None:
last_sn = int(last_sn_record.sn)
else:
last_sn = 0
return last_sn
# check the new_sn valile for a given product name,if new_sn is exist, reture true
def sn_is_exist(session, product_name: str, sn: int) -> bool:
stmt = (
select(func.count())
.select_from(ProductList)
.join(ProductList.products)
.filter(Products.name == product_name, ProductList.sn == sn)
)
count = session.execute(stmt).scalar()
return count != 0
# Get the sn perfix for a given product name
def get_product_info(session, product_name: str):
stmt = select(Products.prefix, Products.product_code).filter_by(name=product_name)
product = session.execute(stmt).first()
prefix = ""
product_code = ""
if product is not None:
if product.prefix is not None:
prefix = product.prefix
if product.product_code is not None:
product_code = product.product_code
return product_code, prefix
# Set a new sn for a given product
def save_new_sn_to_db(session, product_name, sn):
product = session.query(Products).filter_by(name=product_name).first()
if sn_is_exist(session, product_name, sn):
print("Error: SN already exists.")
return
new_product_list = ProductList(product_id=product.id, sn=sn)
session.add(new_product_list)
session.commit()
if __name__ == "__main__":
session = db_init()
product_name = "TJ30-1616DN"
print("Get last sn ...")
last_sn = get_last_sn(session, product_name)
print("Last sn for product", product_name, "is:", last_sn)
product_code, prefix = get_product_info(session, product_name)
print(f"product_code = {product_code}, prefix = {prefix}")
new_sn = last_sn
print(f"new_sn = {new_sn}")
sn_ok = sn_is_exist(session, product_name, new_sn)
print(f"sn_ok = {sn_ok}")
print("save to database ...")
save_new_sn_to_db(session, product_name, new_sn)
print("save sn ok")
updated_last_sn = get_last_sn(session, product_name)
print("Updated sn for product", product_name, "is:", updated_last_sn)

View File

@ -0,0 +1,163 @@
/** \file
* \brief EEprom tool for Simple Open EtherCAT master
*
* Usage : eepromtool ifname slave OPTION fname|alias
* ifname is NIC interface, f.e. eth0
* slave = slave number in EtherCAT order 1..n
* -r read EEPROM, output binary format
* -ri read EEPROM, output Intel Hex format
* -w write EEPROM, input binary format
* -wi write EEPROM, input Intel Hex format
* -i display EEPROM information
* -walias write slave alias in EEPROM
*
* (c)Arthur Ketels 2010-2012
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "eceeprom.h"
#include "ethercat.h"
void show_help(void)
{
ec_adaptert *adapter = NULL;
printf("Usage: eceeprom ifname [slaveID [OPTION [fname|alias|serial_no]]]\n");
printf("ifname = name of the network interface, e.g., eth0\n");
printf("slaveID = slave number in EtherCAT order (1..n)\n");
printf("Options:\n");
printf("(no slaveID & option) Display slaves count\n");
printf(" -i Display EEPROM information\n");
printf(" -wa Write slave alias in decimal format\n");
printf(" -wah Write slave alias in hexadecimal format\n");
printf(" -wsn Write serial number in decimal format\n");
printf(" -wsnh Write serial number in hexadecimal format\n");
printf(" -r Read EEPROM and output in binary format\n");
printf(" -ri Read EEPROM and output in Intel Hex format\n");
printf(" -w Write EEPROM using binary input format\n");
printf(" -wi Write EEPROM using Intel Hex input format\n");
printf("Exaple:\n");
printf(" eceeprom eth0 -- Display slaves count\n");
printf(" eceeprom eth0 2 -wa 12345 -- Write slave 2 alias '12345'\n");
printf("\nAvailable adapters:\n");
adapter = ec_find_adapters();
while (adapter != NULL)
{
printf(" - %s (%s)\n", adapter->name, adapter->desc);
adapter = adapter->next;
}
ec_free_adapters(adapter);
}
int main(int argc, char *argv[])
{
int rc = 0;
char *option = NULL;
char *val = NULL;
int slave = 0;
int slaveCount = 0;
if (argc < 2)
{
goto __help;
}
char *ifname = argv[1];
printf("SOEM (Simple Open EtherCAT Master)\nEEPROM tool\n");
/* initialise SOEM, bind socket to ifname */
if (ec_init(ifname) <= 0)
{
printf("No socket connection on %s\nExcecute as root\n", ifname);
return -1;
}
printf("ec_init on %s succeeded.\n", ifname);
slaveCount = ecGetSlaveCount();
if (slaveCount < 1)
{
printf("No slaves found!\n");
rc = -1;
goto __exit;
}
printf("Found %d slave(s)\n", slaveCount);
if (argc >= 3)
{
slave = atoi(argv[2]);
}
else // argc == 2
{
goto __exit;
}
if ((slave > ec_slavecount) || (slave <= 0))
{
printf("Slave ID (%d) outside range.\n", slave);
rc = -1;
goto __exit;
}
switch (argc)
{
case 4:
if (strcmp(argv[3], "-i") != 0)
{
goto __help;
}
[[fallthrough]];
case 3:
ecShowInfo(slave, true);
break;
case 5:
val = argv[4];
option = argv[3];
if (strcmp(option, "-r") == 0)
rc = ecEepromToFile(slave, val, false);
else if (strcmp(option, "-ri") == 0)
rc = ecEepromToFile(slave, val, true);
else if (strcmp(option, "-w") == 0)
rc = ecFileToEeprom(slave, val, false, 0);
else if (strcmp(option, "-wi") == 0)
rc = ecFileToEeprom(slave, val, true, 0);
else if (strcmp(option, "-wa") == 0)
{
uint16_t alias = (uint16)strtoul(val, NULL, 10);
rc = ecWriteAlias(slave, alias);
}
else if (strcmp(option, "-wah") == 0)
{
uint16_t alias = (uint16)strtoul(val, NULL, 16);
rc = ecWriteAlias(slave, alias);
}
else if (strcmp(option, "-wsn") == 0)
{
int32_t sn = strtol(val, NULL, 10);
rc = ecWriteSN(slave, sn);
}
else if (strcmp(option, "-wsnh") == 0)
{
int32_t sn =(int32_t) strtoul(val, NULL, 16);
rc = ecWriteSN(slave, sn);
}
else
goto __help;
break;
default:
goto __help;
break;
}
goto __exit;
__help:
show_help();
__exit:
printf("End, close socket\n");
/* stop SOEM, close socket */
ec_close();
return rc;
}

121
test/linux/eceeprom/ec_eeprom.py Executable file
View File

@ -0,0 +1,121 @@
#!/root/venv/bin/python
import sys
from ctypes import *
from database import *
from sn import *
ll = cdll.LoadLibrary
# ece = ll("../../../build/test/linux/eceeprom/libeceeprom.so")
ece = ll("../lib/libeceeprom.so")
def get_new_sn(
ece, session, slave_id: int, product_name: str, prefix: int, is_force: bool
):
if not is_force:
# check origin sn
origin_sn = ece.ecEepromGetSN(slave_id)
# origin_sn = 0 # 强制写 SN
print(f"Slave {slave_id}: Origin SN = {origin_sn}")
if (
origin_sn != 0
# and origin_sn != 0xFFFFFFFF
and sn_is_exist(session, product_name, origin_sn)
):
print(f"SN ({origin_sn}) is exist. Do NOT update SN")
return False, origin_sn
# new sn
last_sn_ = last_sn = get_last_sn(session, product_name)
sn_ok = False
new_sn = 0
while not sn_ok:
new_sn = generate_sn(last_sn_, prefix)
sn_ok = not sn_is_exist(session, product_name, new_sn)
print(
"last sn = %d,new SN %d is %s"
% (last_sn_, new_sn, "OK" if sn_ok else "exist")
)
last_sn_ = new_sn
print(f"id: {slave_id}, last sn: {last_sn}, new sn : {new_sn}, prefix: {prefix}")
return True, new_sn
def write_multi_eeprom(
count: int, session, product_name: str, eeprome_file: str, is_force: bool
):
product_code_str, prefix_str = get_product_info(session, product_name)
prefix = None
if prefix_str is not None and prefix_str != "":
prefix = int(prefix_str)
product_code = None
if product_code_str is not None and product_code_str != "":
product_code = int(product_code_str)
# 当从机数量大于1时,不写最后一个
if count == 1:
count = 2
for i in range(1, count):
print(f"Write slave EEPROM #{i} :\n")
is_new_sn, new_sn = get_new_sn(session, i, product_name, prefix, is_force)
is_eeprom_initialized = False
if not is_force:
e_product_code = ece.ecEepromGetProductCode(i)
# EEPROM 未初始化
if e_product_code == product_code:
is_eeprom_initialized = True
print(
f"Origin product code is {e_product_code}. Is initialized. Do NOT need update EEPROM"
)
else:
print(
"Origin product code is %d.Do not matched(%d). Is NOT initialized"
% (e_product_code, product_code)
)
rc = 0
if is_eeprom_initialized:
if is_new_sn and new_sn != 0 and new_sn != -1:
rc = ece.ecWriteSN(c_int(i), c_uint32(new_sn))
else:
print(f"i ={i}, eeprom_file:{eeprome_file},new_sn: {new_sn}")
rc = ece.ecFileToEeprom(
c_int(i), c_char_p(eeprome_file), c_bool(False), c_uint(new_sn)
)
if rc > 0:
save_new_sn_to_db(session, product_name, new_sn) # update database
print("\n")
def main():
is_force = False
if len(sys.argv) == 2 and sys.argv[1] == "-force":
is_force = True
ifname = b"enp3s0f1"
if ece.ec_init(c_char_p(ifname)) <= 0:
print("No socket connection on %s\nExcecute as root\n" % ifname)
return -1
print("ec_init on %s succeeded.\n" % ifname)
# Get the number of slaves
slaveCount = ece.ecGetSlaveCount()
if slaveCount < 1:
print("No slaves found!\n")
ece.ec_close()
return -1
print("Found %d slave(s)\n" % slaveCount)
# # Write the SN
session = db_init()
eeprom_file = b"./TJ30-1616DN-EEPROM.bin"
product_name = "TJ30-1616DN"
write_multi_eeprom(slaveCount, session, product_name, eeprom_file, is_force)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,103 @@
#!/root/venv/bin/python
import sys
from ctypes import *
from database import *
from sn import *
ll = cdll.LoadLibrary
# ece = ll("../../../build/test/linux/eceeprom/libeceeprom.so")
ece = ll("../lib/libeceeprom.so")
# 输入一个SN(当输入为空时该sn为0非字数时重新输入), 返回SN(int)
def input_one_sn():
sn = input("请输入SN值则不修改 SN: ")
if sn == "":
return 0
else:
try:
return int("142404"+sn)
except ValueError:
print("输入的不是数字,请重新输入。")
return input_one_sn()
# 输入SN(当输入为空时该sn为0), 返回SN列表, count = 1 时读取一个SNcount > 1 时,读取 count -1 个SN
def input_sn(count: int):
sn = []
if count == 1:
sn.append(input_one_sn())
elif count > 1:
for i in range(1, count):
print(f"#{i} -> ",end='')
sn.append(input_one_sn())
return sn
def write_multi_eeprom(
count: int, sn, eeprome_file: str, is_force: bool
):
product_code = 66048 # for TJ30-1616DN
# 当从机数量大于1时,不写最后一个
if count == 1:
count = 2
for i in range(1, count):# 1 ~ count-1
print(f"Write slave EEPROM #{i} :\n")
is_eeprom_initialized = False
if not is_force:# 检测是否已经初始化
e_product_code = ece.ecEepromGetProductCode(i)
# EEPROM 未初始化
if e_product_code == product_code:
is_eeprom_initialized = True
print(
f"Origin product code is {e_product_code}. Is initialized. Do NOT need update EEPROM"
)
else:
print(
"Origin product code is %d.Do not matched(%d). Is NOT initialized"
% (e_product_code, product_code)
)
rc = 0
if sn[i-1] == 0 or sn[i-1] == -1:
print("SN is 0 or -1. Do NOT need update EEPROM")
continue
if is_eeprom_initialized:
if is_force:
rc = ece.ecWriteSN(c_int(i), c_uint32(sn[i-1]))
else:
print(f"i ={i}, eeprom_file:{eeprome_file},sn: {sn[i-1]}")
rc = ece.ecFileToEeprom(
c_int(i), c_char_p(eeprome_file), c_bool(False), c_uint(sn[i-1])
)
print("\n")
def main():
is_force = False
if len(sys.argv) == 2 and sys.argv[1] == "-force":
is_force = True
ifname = b"enp3s0f1"
if ece.ec_init(c_char_p(ifname)) <= 0:
print("No socket connection on %s\nExcecute as root\n" % ifname)
return -1
print("ec_init on %s succeeded.\n" % ifname)
# Get the number of slaves
slaveCount = ece.ecGetSlaveCount()
if slaveCount < 1:
print("No slaves found!\n")
ece.ec_close()
return -1
print("Found %d slave(s)\n" % slaveCount)
# # Write the SN
eeprom_file = b"./TJ30-1616DN-EEPROM.bin"
sn = input_sn(slaveCount)
write_multi_eeprom(slaveCount, sn, eeprom_file, is_force)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,569 @@
/** \file
* \brief EEprom tool for Simple Open EtherCAT master
*
* Usage : eepromtool ifname slave OPTION fname|alias
* ifname is NIC interface, f.e. eth0
* slave = slave number in EtherCAT order 1..n
* -r read EEPROM, output binary format
* -ri read EEPROM, output Intel Hex format
* -w write EEPROM, input binary format
* -wi write EEPROM, input Intel Hex format
* -i display EEPROM information
* -walias write slave alias in EEPROM
*
* (c)Arthur Ketels 2010-2012
*/
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "eceeprom.h"
#include "ethercat.h"
#define MAXSLENGTH 256
#define IHEXLENGTH 0x20
#define CRCBUF 14
uint8 ebuf[MAXBUF];
static void calc_crc(uint8_t *crc, uint8_t b)
{
int j;
*crc ^= b;
for (j = 0; j <= 7; j++)
{
if (*crc & 0x80)
*crc = (*crc << 1) ^ 0x07;
else
*crc = (*crc << 1);
}
}
static uint16_t SIIcrc(uint8_t *buf)
{
int i;
uint8_t crc;
crc = 0xff;
for (i = 0; i <= 13; i++)
{
calc_crc(&crc, *(buf++));
}
return (uint16_t)crc;
}
int ecBufferFromBin(const char *fname, int *length)
{
FILE *fp;
int cc = 0, c;
fp = fopen(fname, "rb");
if (fp == NULL)
return 0;
while (((c = fgetc(fp)) != EOF) && (cc < MAXBUF))
ebuf[cc++] = (uint8_t)c;
*length = cc;
fclose(fp);
return 1;
}
int ecBufferFromIntelHex(const char *fname, int *start, int *length)
{
FILE *fp;
int c, sc, retval = 1;
int ll, ladr, lt, sn, i, lval;
int hstart, hlength, sum;
char sline[MAXSLENGTH];
fp = fopen(fname, "r");
if (fp == NULL)
return 0;
hstart = MAXBUF;
hlength = 0;
sum = 0;
do
{
memset(sline, 0x00, MAXSLENGTH);
sc = 0;
while (((c = fgetc(fp)) != EOF) && (c != 0x0A) && (sc < (MAXSLENGTH - 1)))
sline[sc++] = (uint8_t)c;
if ((c != EOF) && ((sc < 11) || (sline[0] != ':')))
{
c = EOF;
retval = 0;
printf("Invalid Intel Hex format.\n");
}
if (c != EOF)
{
sn = sscanf(sline, ":%2x%4x%2x", &ll, &ladr, &lt);
if ((sn == 3) && ((ladr + ll) <= MAXBUF) && (lt == 0))
{
sum = ll + (ladr >> 8) + (ladr & 0xff) + lt;
if (ladr < hstart)
hstart = ladr;
for (i = 0; i < ll; i++)
{
sn = sscanf(&sline[9 + (i << 1)], "%2x", &lval);
ebuf[ladr + i] = (uint8_t)lval;
sum += (uint8_t)lval;
}
if (((ladr + ll) - hstart) > hlength)
hlength = (ladr + ll) - hstart;
sum = (0x100 - sum) & 0xff;
sn = sscanf(&sline[9 + (i << 1)], "%2x", &lval);
if (!sn || ((sum - lval) != 0))
{
c = EOF;
retval = 0;
printf("Invalid checksum.\n");
}
}
}
} while (c != EOF);
if (retval)
{
*length = hlength;
*start = hstart;
}
fclose(fp);
return retval;
}
int ecBufferToBin(const char *fname, int length)
{
FILE *fp;
int cc;
fp = fopen(fname, "wb");
if (fp == NULL)
{
printf("Can not write to file %s\n", fname);
return 0;
}
for (cc = 0; cc < length; cc++)
fputc(ebuf[cc], fp);
fclose(fp);
return length;
}
int ecBufferToIntelHex(const char *fname, int length)
{
FILE *fp;
int cc = 0, ll, sum, i;
fp = fopen(fname, "w");
if (fp == NULL)
{
printf("Can not write to file %s\n", fname);
return 0;
}
while (cc < length)
{
ll = length - cc;
if (ll > IHEXLENGTH)
ll = IHEXLENGTH;
sum = ll + (cc >> 8) + (cc & 0xff);
fprintf(fp, ":%2.2X%4.4X00", ll, cc);
for (i = 0; i < ll; i++)
{
fprintf(fp, "%2.2X", ebuf[cc + i]);
sum += ebuf[cc + i];
}
fprintf(fp, "%2.2X\n", (0x100 - sum) & 0xff);
cc += ll;
}
fprintf(fp, ":00000001FF\n");
fclose(fp);
return length;
}
int ecEepromRead(int slave, int start, int length)
{
int i, ainc = 4;
uint16_t estat, aiadr;
uint32_t b4;
uint64_t b8;
uint8_t eepctl;
if ((ec_slavecount >= slave) && (slave > 0) && ((start + length) <= MAXBUF))
{
aiadr = 1 - slave;
eepctl = 2;
ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl,
EC_TIMEOUTRET); /* force Eeprom from PDI */
eepctl = 0;
ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl,
EC_TIMEOUTRET); /* set Eeprom to master */
estat = 0x0000;
aiadr = 1 - slave;
ec_APRD(aiadr, ECT_REG_EEPSTAT, sizeof(estat), &estat,
EC_TIMEOUTRET); /* read eeprom status */
estat = etohs(estat);
if (estat & EC_ESTAT_R64)
{
ainc = 8;
for (i = start; i < (start + length); i += ainc)
{
b8 = ec_readeepromAP(aiadr, i >> 1, EC_TIMEOUTEEP);
ebuf[i] = b8 & 0xFF;
ebuf[i + 1] = (b8 >> 8) & 0xFF;
ebuf[i + 2] = (b8 >> 16) & 0xFF;
ebuf[i + 3] = (b8 >> 24) & 0xFF;
ebuf[i + 4] = (b8 >> 32) & 0xFF;
ebuf[i + 5] = (b8 >> 40) & 0xFF;
ebuf[i + 6] = (b8 >> 48) & 0xFF;
ebuf[i + 7] = (b8 >> 56) & 0xFF;
}
}
else
{
for (i = start; i < (start + length); i += ainc)
{
b4 = ec_readeepromAP(aiadr, i >> 1, EC_TIMEOUTEEP) & 0xFFFFFFFF;
ebuf[i] = b4 & 0xFF;
ebuf[i + 1] = (b4 >> 8) & 0xFF;
ebuf[i + 2] = (b4 >> 16) & 0xFF;
ebuf[i + 3] = (b4 >> 24) & 0xFF;
}
}
return 1;
}
return 0;
}
int ecEepromWrite(int slave, int start, int wlength)
{
int i, dc = 0;
uint16_t aiadr, *wbuf;
uint8_t eepctl;
if ((ec_slavecount >= slave) && (slave > 0) && ((start + wlength) * 2 <= MAXBUF))
{
aiadr = 1 - slave;
eepctl = 2;
ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl,
EC_TIMEOUTRET); /* force Eeprom from PDI */
eepctl = 0;
ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl,
EC_TIMEOUTRET); /* set Eeprom to master */
aiadr = 1 - slave;
wbuf = (uint16_t *)&ebuf[0];
for (i = start; i < (start + wlength); i++)
{
ec_writeeepromAP(aiadr, i, *(wbuf + i), EC_TIMEOUTEEP);
if (++dc >= 100)
{
dc = 0;
printf(".");
fflush(stdout);
}
}
return 1;
}
return 0;
}
int ecGetESize(void)
{
uint16_t *wbuf = (uint16_t *)&ebuf[0];
int esize = (*(wbuf + 0x3E) + 1) * 128;
if (esize > MAXBUF)
{
esize = MAXBUF;
}
return esize;
}
int ecEepromToBuffer(int slave, bool isFull)
{
int rc;
rc = ecEepromRead(slave, 0x0000, MINBUF); // read first 128 bytes
if (isFull && rc > 0)
{
uint16_t esize = ecGetESize();
if (esize > MINBUF)
rc += ecEepromRead(slave, MINBUF, esize - MINBUF); // read reminder}
}
return rc;
}
#if 0
void show_hex(uint8_t *buff, int len)
{
int i = 0;
uint16_t a = 0;
printf("addr 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15\n");
for (; i < len - 16; i += 16, a += 16)
{
printf("%04X %02X %02X %02X %02X %02X %02X %02X %02X "
"%02X %02X %02X %02X %02X %02X %02X %02X\n",
a, buff[i], buff[i + 1], buff[i + 2], buff[i + 3], buff[i + 4], buff[i + 5],
buff[i + 6], buff[i + 7], buff[i + 8], buff[i + 9], buff[i + 10], buff[i + 11],
buff[i + 12], buff[i + 13], buff[i + 14], buff[i + 15]);
}
if (i == len)
{
return;
}
printf("%04X", a);
for (int j = 0; i < len; i++, j++)
{
if (j == 8)
{
printf(" ");
}
printf(" %02X", buff[i]);
}
printf("\n");
}
#endif
int ecEepromWriteAlias(int slave, uint16_t alias, uint16_t *crc)
{
int ret;
ret = ecEepromToBuffer(slave, false);
if (ret <= 0)
{
return ret;
}
uint16 *wbuf = (uint16 *)&ebuf[0];
*(wbuf + 0x04) = alias;
*crc = *(wbuf + 0x07) = SIIcrc(&ebuf[0]);
ret = ecEepromWrite(slave, 0x00, 8);
return ret;
}
uint32_t ecEepromGetProductCode(int slave)
{
int ret;
ret = ecEepromToBuffer(slave, true);
if (ret <= 0)
{
return 0;
}
uint16 *wbuf = (uint16 *)&ebuf[0];
return ((uint32_t) * (wbuf + 0x0B)) << 16 | *(wbuf + 0x0A);
}
int32_t ecEepromGetSN(int slave)
{
int ret;
ret = ecEepromToBuffer(slave, true);
if (ret <= 0)
{
return 0;
}
uint16 *wbuf = (uint16 *)&ebuf[0];
return ((int32_t) * (wbuf + 0x0F)) << 16 | *(wbuf + 0x0E);
}
void ecUpdateSNBuff(int32_t sn)
{
uint16 *wbuf = (uint16 *)&ebuf[0];
*(wbuf + 0x0E) = (uint16_t)((uint32_t)sn & 0xffff);
*(wbuf + 0x0F) = (uint16_t)((uint32_t)sn >> 16);
}
int ecEepromWriteSN(int slave, int32_t sn)
{
int ret;
ret = ecEepromToBuffer(slave, true);
if (ret <= 0)
{
return ret;
}
ecUpdateSNBuff(sn);
return ecEepromWrite(slave, 0x0E, 2);
}
int ecGetSlaveCount(void)
{
int w = 0x0000;
/* detect number of slaves */
int wkc = ec_BRD(0x0000, ECT_REG_TYPE, sizeof(w), &w, EC_TIMEOUTSAFE);
if (wkc > 0)
{
ec_slavecount = wkc;
return wkc;
}
return 0;
}
void ecBufferShowInfo(int slave, bool isDetails)
{
uint16_t crc = SIIcrc(&ebuf[0]);
uint16 *wbuf = (uint16 *)&ebuf[0];
int esize = ecGetESize();
printf("Slave %d data\n", slave);
printf(" Vendor ID : 0x%8.8X(%u)\n", *(uint32_t *)(wbuf + 0x08),
*(uint32_t *)(wbuf + 0x08));
printf(" Product Code : 0x%8.8X(%u)\n", *(uint32_t *)(wbuf + 0x0A),
*(uint32_t *)(wbuf + 0x0A));
printf(" Revision Number : 0x%8.8X(%u)\n", *(uint32_t *)(wbuf + 0x0C),
*(uint32_t *)(wbuf + 0x0C));
printf(" Serial Number : 0x%8.8X(%u)\n", *(uint32_t *)(wbuf + 0x0E),
*(uint32_t *)(wbuf + 0x0E));
printf(" Config Alias : 0x%4.4X(%u)\n", *(wbuf + 0x04), *(wbuf + 0x04));
printf(" Checksum : 0x%2.2X (%s)\n", *(wbuf + 0x07),
(*(wbuf + 0x07) == crc) ? "Match" : "NOT Match");
printf(" calculated : 0x%2.2X\n", crc);
if (isDetails)
{
printf(" PDI Control : 0x%4.4X(%u)\n", *(wbuf + 0x00), *(wbuf + 0x00));
printf(" PDI Config : 0x%4.4X(%u)\n", *(wbuf + 0x01), *(wbuf + 0x01));
printf(" Mailbox Protocol : 0x%4.4X\n", *(wbuf + 0x1C));
printf(" EEPROM Size : 0x%4.4X = %d bytes\n", *(wbuf + 0x3E), esize);
}
printf(" Version : 0x%4.4X(%u)\n", *(wbuf + 0x3F), *(wbuf + 0x3F));
// show_hex(ebuf, 32);
}
void ecShowInfo(int slave, bool isDetails)
{
osal_usleep(1000);
int ret = ecEepromToBuffer(slave, false); // read first 128 bytes
if (ret <= 0)
{
return;
}
ecBufferShowInfo(slave, isDetails);
}
int ecEepromToFile(int slave, const char *fname, bool isHex)
{
ec_timet tstart, tend, tdif;
char *format;
int esize;
int rc;
printf("Slave %d:\n", slave);
printf("Read data from EEPROM ...\n");
tstart = osal_current_time();
rc = ecEepromToBuffer(slave, true);
if (rc <= 0)
{
printf("Read Slave %d EEPROM FALL\n", slave);
return rc;
}
tend = osal_current_time();
osal_time_diff(&tstart, &tend, &tdif);
printf("\nTotal EEPROM read time: %ldms\n", (tdif.usec + (tdif.sec * 1000000L)) / 1000);
esize = ecGetESize();
if (isHex)
{
rc = ecBufferToIntelHex(fname, esize);
format = "Intel Hex";
}
else
{
rc = ecBufferToBin(fname, esize);
format = "Binary";
}
if (rc > 0)
{
printf("EEPROM data save to file %s in %s format, size %d bytes\n", fname, format, rc);
}
return rc;
}
int ecFileToEeprom(int slave, const char *fname, bool isHex, int32_t sn)
{
printf("Load file '%s'. Is Hex? %s\n", fname, isHex ? "True" : "False");
int rc;
int estart = 0;
int esize = 0;
if (isHex)
rc = ecBufferFromIntelHex(fname, &estart, &esize);
else
rc = ecBufferFromBin(fname, &esize);
if (rc <= 0)
{
printf("Load file '%s' FAIL\n", fname);
return rc;
}
if (sn)
{
printf("Update SN -> %u\n", sn);
ecUpdateSNBuff(sn);
}
// ecBufferShowInfo(slave, true);
printf("Busy");
fflush(stdout);
ec_timet tstart = osal_current_time();
estart = 0;
rc = ecEepromWrite(slave, estart, esize / 2);
if (rc > 0)
{
ec_timet tend = osal_current_time();
ec_timet tdif = {0};
osal_time_diff(&tstart, &tend, &tdif);
printf("\nTotal EEPROM write time :%ldms\n", (tdif.usec + (tdif.sec * 1000000L)) / 1000);
ecShowInfo(slave, true);
}
else
{
printf("Error reading file, abort.\n");
}
return rc;
}
int ecWriteAlias(int slave, uint16_t alias)
{
uint16_t crc;
int rc = ecEepromWriteAlias(slave, alias, &crc);
if (rc > 0)
{
printf("Alias %d (HEX: %4.4X) , CRC = %02X written successfully to slave %d\n", alias,
alias, crc, slave);
ecShowInfo(slave, false);
}
else if (rc < 0)
{
printf("Could not read slave EEPROM");
}
else
{
printf("Alias not written\n");
}
return rc;
}
int ecWriteSN(int slave, int32_t sn)
{
printf("Write slave %d SN %u ...\n", slave, sn);
int rc = ecEepromWriteSN(slave, sn);
if (rc > 0)
{
printf("SN %d (HEX: %8.8X) written successfully to slave %d\n", sn, sn, slave);
ecShowInfo(slave, false);
}
else if (rc < 0)
{
printf("Could not read slave EEPROM\n");
}
else
{
printf("SN not written\n");
}
return rc;
}

View File

@ -0,0 +1,29 @@
#ifndef __EC_EEPROM_H__
#define __EC_EEPROM_H__
#include <stdbool.h>
#include <stdint.h>
#define MAXBUF 524288
#define MINBUF 128
int ecBufferFromBin(const char *fname, int *length);
int ecBufferFromIntelHex(const char *fname, int *start, int *length);
int ecBufferToBin(const char *fname, int length);
int ecBufferToIntelHex(const char *fname, int length);
int ecEepromRead(int slave, int start, int length);
int ecEepromWrite(int slave, int start, int length);
int ecEepromWriteAlias(int slave, uint16_t alias, uint16_t *crc);
void ecUpdateSNBuff(int32_t sn);
int ecEepromWriteSN(int slave, int32_t sn);
int32_t ecEepromGetSN(int slave);
int ecGetSlaveCount(void);
int ecGetESize(void);
void ecShowInfo(int slave, bool isDetails);
void ecBufferShowInfo(int slave, bool isDetails);
int ecEepromToBuffer(int slave, bool isFull);
int ecEepromToFile(int slave, const char *fname, bool isHex);
int ecFileToEeprom(int slave, const char *fname, bool isHex, int32_t sn);
int ecWriteAlias(int slave, uint16_t alias);
int ecWriteSN(int slave, int32_t sn);
uint32_t ecEepromGetProductCode(int slave);
#endif /* __EC_EEPROM_H__ */

64
test/linux/eceeprom/sn.py Normal file
View File

@ -0,0 +1,64 @@
#!/bin/env python3
import datetime, sys
import Verhoeff
from database import *
import csv
# sn 的组成:
# [0 1] [2 3] [4 5] [6 7 8] [9]
# [设备ID] [ 年 ] [ 月 ] [顺序号] [校验码]
# sn 10位十进制数据
# 顺序号每月开始重置为 001
# 校验码算法 Verhoeff
def generate_sn(last_sn: int, prefix: int = None) -> int:
device_id = last_sn // 100000000
curr_device_id = device_id if prefix is None else prefix
today = datetime.datetime.today()
# today = datetime.datetime(2023,12,1,0,0,0)
curr_year = today.year % 100
curr_month = today.month
year = last_sn // 1000000 % 100
month = last_sn // 10000 % 100
sequence_num = last_sn // 10 % 1000
if year != curr_year or month != curr_month or device_id != curr_device_id:
sequence_num = 1
year = curr_year
month = curr_month
else:
sequence_num += 1
new_sn_without_check = (
curr_device_id * 10000000 + year * 100000 + month * 1000 + sequence_num
)
new_check = Verhoeff.checksum(str(new_sn_without_check))
return new_sn_without_check * 10 + new_check
if __name__ == "__main__":
if len(sys.argv) != 4:
print("python sn.py last_sn num csv_file")
else:
csv_file = sys.argv[3]
last_sn = int(sys.argv[1])
num = int(sys.argv[2])
print(f"last SN: {last_sn}, num: {num}")
sn_list = []
for i in range(1, num + 1):
sn = generate_sn(last_sn)
row = [i, sn]
sn_list.append(row)
last_sn = sn
print(sn_list)
with open(csv_file, "w", encoding="utf-8", newline="") as f:
csv_writer = csv.writer(f)
name = ["ID", "SN"]
csv_writer.writerow(name)
csv_writer.writerows(sn_list)
print(f"写入{csv_file}成功")
f.close()

View File

@ -0,0 +1,10 @@
#!/bin/env bash
dir=$(cd "$(dirname $0)";pwd)
${dir}/ec_eeprom.py
echo 请先断电,再通电
read -n 1 -s -r -p "按任意键继续..."
sleep 2
# ${dir}/ecslaveinfo enp3s0f1
${dir}/tj30_test enp3s0f1

View File

@ -0,0 +1,5 @@
set(SOURCES ecslaveinfo.c)
add_executable(ecslaveinfo ${SOURCES})
target_link_libraries(ecslaveinfo soem)
install(TARGETS ecslaveinfo DESTINATION bin)

View File

@ -711,7 +711,7 @@ int main(int argc, char *argv[])
}
else
{
printf("Usage: slaveinfo ifname [options]\nifname = eth0 for example\nOptions :\n -sdo : print SDO info\n -map : print mapping\n");
printf("Usage: ecslaveinfo ifname [options]\nifname = eth0 for example\nOptions :\n -sdo : print SDO info\n -map : print mapping\n");
printf ("Available adapters\n");
adapter = ec_find_adapters ();

View File

@ -1,5 +0,0 @@
set(SOURCES eepromtool.c)
add_executable(eepromtool ${SOURCES})
target_link_libraries(eepromtool soem)
install(TARGETS eepromtool DESTINATION bin)

View File

@ -1,484 +0,0 @@
/** \file
* \brief EEprom tool for Simple Open EtherCAT master
*
* Usage : eepromtool ifname slave OPTION fname|alias
* ifname is NIC interface, f.e. eth0
* slave = slave number in EtherCAT order 1..n
* -r read EEPROM, output binary format
* -ri read EEPROM, output Intel Hex format
* -w write EEPROM, input binary format
* -wi write EEPROM, input Intel Hex format
* -i display EEPROM information
* -walias write slave alias in EEPROM
*
* (c)Arthur Ketels 2010-2012
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ethercat.h"
#define MAXBUF 524288
#define STDBUF 2048
#define MINBUF 128
#define CRCBUF 14
#define MODE_NONE 0
#define MODE_READBIN 1
#define MODE_READINTEL 2
#define MODE_WRITEBIN 3
#define MODE_WRITEINTEL 4
#define MODE_WRITEALIAS 5
#define MODE_INFO 6
#define MAXSLENGTH 256
uint8 ebuf[MAXBUF];
uint8 ob;
uint16 ow;
int os;
int slave;
int alias;
ec_timet tstart,tend, tdif;
int wkc;
int mode;
char sline[MAXSLENGTH];
#define IHEXLENGTH 0x20
void calc_crc(uint8 *crc, uint8 b)
{
int j;
*crc ^= b;
for(j = 0; j <= 7 ; j++ )
{
if(*crc & 0x80)
*crc = (*crc << 1) ^ 0x07;
else
*crc = (*crc << 1);
}
}
uint16 SIIcrc(uint8 *buf)
{
int i;
uint8 crc;
crc = 0xff;
for( i = 0 ; i <= 13 ; i++ )
{
calc_crc(&crc , *(buf++));
}
return (uint16)crc;
}
int input_bin(char *fname, int *length)
{
FILE *fp;
int cc = 0, c;
fp = fopen(fname, "rb");
if(fp == NULL)
return 0;
while (((c = fgetc(fp)) != EOF) && (cc < MAXBUF))
ebuf[cc++] = (uint8)c;
*length = cc;
fclose(fp);
return 1;
}
int input_intelhex(char *fname, int *start, int *length)
{
FILE *fp;
int c, sc, retval = 1;
int ll, ladr, lt, sn, i, lval;
int hstart, hlength, sum;
fp = fopen(fname, "r");
if(fp == NULL)
return 0;
hstart = MAXBUF;
hlength = 0;
sum = 0;
do
{
memset(sline, 0x00, MAXSLENGTH);
sc = 0;
while (((c = fgetc(fp)) != EOF) && (c != 0x0A) && (sc < (MAXSLENGTH -1)))
sline[sc++] = (uint8)c;
if ((c != EOF) && ((sc < 11) || (sline[0] != ':')))
{
c = EOF;
retval = 0;
printf("Invalid Intel Hex format.\n");
}
if (c != EOF)
{
sn = sscanf(sline , ":%2x%4x%2x", &ll, &ladr, &lt);
if ((sn == 3) && ((ladr + ll) <= MAXBUF) && (lt == 0))
{
sum = ll + (ladr >> 8) + (ladr & 0xff) + lt;
if(ladr < hstart) hstart = ladr;
for(i = 0; i < ll ; i++)
{
sn = sscanf(&sline[9 + (i << 1)], "%2x", &lval);
ebuf[ladr + i] = (uint8)lval;
sum += (uint8)lval;
}
if(((ladr + ll) - hstart) > hlength)
hlength = (ladr + ll) - hstart;
sum = (0x100 - sum) & 0xff;
sn = sscanf(&sline[9 + (i << 1)], "%2x", &lval);
if (!sn || ((sum - lval) != 0))
{
c = EOF;
retval = 0;
printf("Invalid checksum.\n");
}
}
}
}
while (c != EOF);
if (retval)
{
*length = hlength;
*start = hstart;
}
fclose(fp);
return retval;
}
int output_bin(char *fname, int length)
{
FILE *fp;
int cc;
fp = fopen(fname, "wb");
if(fp == NULL)
return 0;
for (cc = 0 ; cc < length ; cc++)
fputc( ebuf[cc], fp);
fclose(fp);
return 1;
}
int output_intelhex(char *fname, int length)
{
FILE *fp;
int cc = 0, ll, sum, i;
fp = fopen(fname, "w");
if(fp == NULL)
return 0;
while (cc < length)
{
ll = length - cc;
if (ll > IHEXLENGTH) ll = IHEXLENGTH;
sum = ll + (cc >> 8) + (cc & 0xff);
fprintf(fp, ":%2.2X%4.4X00", ll, cc);
for (i = 0; i < ll; i++)
{
fprintf(fp, "%2.2X", ebuf[cc + i]);
sum += ebuf[cc + i];
}
fprintf(fp, "%2.2X\n", (0x100 - sum) & 0xff);
cc += ll;
}
fprintf(fp, ":00000001FF\n");
fclose(fp);
return 1;
}
int eeprom_read(int slave, int start, int length)
{
int i, ainc = 4;
uint16 estat, aiadr;
uint32 b4;
uint64 b8;
uint8 eepctl;
if((ec_slavecount >= slave) && (slave > 0) && ((start + length) <= MAXBUF))
{
aiadr = 1 - slave;
eepctl = 2;
ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* force Eeprom from PDI */
eepctl = 0;
ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* set Eeprom to master */
estat = 0x0000;
aiadr = 1 - slave;
ec_APRD(aiadr, ECT_REG_EEPSTAT, sizeof(estat), &estat, EC_TIMEOUTRET); /* read eeprom status */
estat = etohs(estat);
if (estat & EC_ESTAT_R64)
{
ainc = 8;
for (i = start ; i < (start + length) ; i+=ainc)
{
b8 = ec_readeepromAP(aiadr, i >> 1 , EC_TIMEOUTEEP);
ebuf[i] = b8 & 0xFF;
ebuf[i+1] = (b8 >> 8) & 0xFF;
ebuf[i+2] = (b8 >> 16) & 0xFF;
ebuf[i+3] = (b8 >> 24) & 0xFF;
ebuf[i+4] = (b8 >> 32) & 0xFF;
ebuf[i+5] = (b8 >> 40) & 0xFF;
ebuf[i+6] = (b8 >> 48) & 0xFF;
ebuf[i+7] = (b8 >> 56) & 0xFF;
}
}
else
{
for (i = start ; i < (start + length) ; i+=ainc)
{
b4 = ec_readeepromAP(aiadr, i >> 1 , EC_TIMEOUTEEP) & 0xFFFFFFFF;
ebuf[i] = b4 & 0xFF;
ebuf[i+1] = (b4 >> 8) & 0xFF;
ebuf[i+2] = (b4 >> 16) & 0xFF;
ebuf[i+3] = (b4 >> 24) & 0xFF;
}
}
return 1;
}
return 0;
}
int eeprom_write(int slave, int start, int length)
{
int i, dc = 0;
uint16 aiadr, *wbuf;
uint8 eepctl;
if((ec_slavecount >= slave) && (slave > 0) && ((start + length) <= MAXBUF))
{
aiadr = 1 - slave;
eepctl = 2;
ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* force Eeprom from PDI */
eepctl = 0;
ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* set Eeprom to master */
aiadr = 1 - slave;
wbuf = (uint16 *)&ebuf[0];
for (i = start ; i < (start + length) ; i+=2)
{
ec_writeeepromAP(aiadr, i >> 1 , *(wbuf + (i >> 1)), EC_TIMEOUTEEP);
if (++dc >= 100)
{
dc = 0;
printf(".");
fflush(stdout);
}
}
return 1;
}
return 0;
}
int eeprom_writealias(int slave, int alias, uint16 crc)
{
uint16 aiadr;
uint8 eepctl;
int ret;
if((ec_slavecount >= slave) && (slave > 0) && (alias <= 0xffff))
{
aiadr = 1 - slave;
eepctl = 2;
ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* force Eeprom from PDI */
eepctl = 0;
ec_APWR(aiadr, ECT_REG_EEPCFG, sizeof(eepctl), &eepctl , EC_TIMEOUTRET); /* set Eeprom to master */
ret = ec_writeeepromAP(aiadr, 0x04 , alias, EC_TIMEOUTEEP);
if (ret)
ret = ec_writeeepromAP(aiadr, 0x07 , crc, EC_TIMEOUTEEP);
return ret;
}
return 0;
}
void eepromtool(char *ifname, int slave, int mode, char *fname)
{
int w, rc = 0, estart, esize;
uint16 *wbuf;
/* initialise SOEM, bind socket to ifname */
if (ec_init(ifname))
{
printf("ec_init on %s succeeded.\n",ifname);
w = 0x0000;
wkc = ec_BRD(0x0000, ECT_REG_TYPE, sizeof(w), &w, EC_TIMEOUTSAFE); /* detect number of slaves */
if (wkc > 0)
{
ec_slavecount = wkc;
printf("%d slaves found.\n",ec_slavecount);
if((ec_slavecount >= slave) && (slave > 0))
{
if ((mode == MODE_INFO) || (mode == MODE_READBIN) || (mode == MODE_READINTEL))
{
tstart = osal_current_time();
eeprom_read(slave, 0x0000, MINBUF); // read first 128 bytes
wbuf = (uint16 *)&ebuf[0];
printf("Slave %d data\n", slave);
printf(" PDI Control : %4.4X\n",*(wbuf + 0x00));
printf(" PDI Config : %4.4X\n",*(wbuf + 0x01));
printf(" Config Alias : %4.4X\n",*(wbuf + 0x04));
printf(" Checksum : %4.4X\n",*(wbuf + 0x07));
printf(" calculated : %4.4X\n",SIIcrc(&ebuf[0]));
printf(" Vendor ID : %8.8X\n",*(uint32 *)(wbuf + 0x08));
printf(" Product Code : %8.8X\n",*(uint32 *)(wbuf + 0x0A));
printf(" Revision Number : %8.8X\n",*(uint32 *)(wbuf + 0x0C));
printf(" Serial Number : %8.8X\n",*(uint32 *)(wbuf + 0x0E));
printf(" Mailbox Protocol : %4.4X\n",*(wbuf + 0x1C));
esize = (*(wbuf + 0x3E) + 1) * 128;
if (esize > MAXBUF) esize = MAXBUF;
printf(" Size : %4.4X = %d bytes\n",*(wbuf + 0x3E), esize);
printf(" Version : %4.4X\n",*(wbuf + 0x3F));
}
if ((mode == MODE_READBIN) || (mode == MODE_READINTEL))
{
if (esize > MINBUF)
eeprom_read(slave, MINBUF, esize - MINBUF); // read reminder
tend = osal_current_time();
osal_time_diff(&tstart, &tend, &tdif);
if (mode == MODE_READINTEL) output_intelhex(fname, esize);
if (mode == MODE_READBIN) output_bin(fname, esize);
printf("\nTotal EEPROM read time :%ldms\n", (tdif.usec+(tdif.sec*1000000L)) / 1000);
}
if ((mode == MODE_WRITEBIN) || (mode == MODE_WRITEINTEL))
{
estart = 0;
if (mode == MODE_WRITEINTEL) rc = input_intelhex(fname, &estart, &esize);
if (mode == MODE_WRITEBIN) rc = input_bin(fname, &esize);
if (rc > 0)
{
wbuf = (uint16 *)&ebuf[0];
printf("Slave %d\n", slave);
printf(" Vendor ID : %8.8X\n",*(uint32 *)(wbuf + 0x08));
printf(" Product Code : %8.8X\n",*(uint32 *)(wbuf + 0x0A));
printf(" Revision Number : %8.8X\n",*(uint32 *)(wbuf + 0x0C));
printf(" Serial Number : %8.8X\n",*(uint32 *)(wbuf + 0x0E));
printf("Busy");
fflush(stdout);
tstart = osal_current_time();
eeprom_write(slave, estart, esize);
tend = osal_current_time();
osal_time_diff(&tstart, &tend, &tdif);
printf("\nTotal EEPROM write time :%ldms\n", (tdif.usec+(tdif.sec*1000000L)) / 1000);
}
else
printf("Error reading file, abort.\n");
}
if (mode == MODE_WRITEALIAS)
{
if( eeprom_read(slave, 0x0000, CRCBUF) ) // read first 14 bytes
{
wbuf = (uint16 *)&ebuf[0];
*(wbuf + 0x04) = alias;
if(eeprom_writealias(slave, alias, SIIcrc(&ebuf[0])))
{
printf("Alias %4.4X written successfully to slave %d\n", alias, slave);
}
else
{
printf("Alias not written\n");
}
}
else
{
printf("Could not read slave EEPROM");
}
}
}
else
{
printf("Slave number outside range.\n");
}
}
else
{
printf("No slaves found!\n");
}
printf("End, close socket\n");
/* stop SOEM, close socket */
ec_close();
}
else
{
printf("No socket connection on %s\nExcecute as root\n",ifname);
}
}
int main(int argc, char *argv[])
{
printf("SOEM (Simple Open EtherCAT Master)\nEEPROM tool\n");
mode = MODE_NONE;
if (argc > 3)
{
slave = atoi(argv[2]);
if ((strncmp(argv[3], "-i", sizeof("-i")) == 0)) mode = MODE_INFO;
if (argc > 4)
{
if ((strncmp(argv[3], "-r", sizeof("-r")) == 0)) mode = MODE_READBIN;
if ((strncmp(argv[3], "-ri", sizeof("-ri")) == 0)) mode = MODE_READINTEL;
if ((strncmp(argv[3], "-w", sizeof("-w")) == 0)) mode = MODE_WRITEBIN;
if ((strncmp(argv[3], "-wi", sizeof("-wi")) == 0)) mode = MODE_WRITEINTEL;
if ((strncmp(argv[3], "-walias", sizeof("-walias")) == 0))
{
mode = MODE_WRITEALIAS;
alias = atoi(argv[4]);
}
}
/* start tool */
eepromtool(argv[1],slave,mode,argv[4]);
}
else
{
ec_adaptert * adapter = NULL;
printf("Usage: eepromtool ifname slave OPTION fname|alias\n");
printf("ifname = eth0 for example\n");
printf("slave = slave number in EtherCAT order 1..n\n");
printf(" -i display EEPROM information\n");
printf(" -walias write slave alias\n");
printf(" -r read EEPROM, output binary format\n");
printf(" -ri read EEPROM, output Intel Hex format\n");
printf(" -w write EEPROM, input binary format\n");
printf(" -wi write EEPROM, input Intel Hex format\n");
printf ("\nAvailable adapters:\n");
adapter = ec_find_adapters ();
while (adapter != NULL)
{
printf (" - %s (%s)\n", adapter->name, adapter->desc);
adapter = adapter->next;
}
ec_free_adapters(adapter);
}
printf("End program\n");
return (0);
}

View File

@ -0,0 +1,5 @@
set(SOURCES red_test.c)
add_executable(red_test ${SOURCES})
target_link_libraries(red_test soem)
install(TARGETS red_test DESTINATION bin)

View File

@ -1,5 +0,0 @@
set(SOURCES slaveinfo.c)
add_executable(slaveinfo ${SOURCES})
target_link_libraries(slaveinfo soem)
install(TARGETS slaveinfo DESTINATION bin)

View File

@ -0,0 +1,5 @@
set(SOURCES tj30_test.c)
add_executable(tj30_test ${SOURCES})
target_link_libraries(tj30_test soem eceeprom_static)
install(TARGETS tj30_test DESTINATION bin)

224
test/linux/tj30_test/logn.h Normal file
View File

@ -0,0 +1,224 @@
#ifndef __LOGN_H___
#define __LOGN_H___
#ifdef __cplusplus
extern "C"
{
#endif
#ifdef RT_VERSION_MAJOR
#define LOGN_PRINTF(...) rt_kprintf(__VA_ARGS__)
#else
#define LOGN_PRINTF(...) printf(__VA_ARGS__)
#endif // RT_VERSION_MAJOR
#if defined(RT_USING_ULOG)
#include <ulog.h>
#else
#define LOG_LVL_ERROR 0
#define LOG_LVL_WARNING 1
#define LOG_LVL_INFO 2
#define LOG_LVL_DBG 3
#ifdef LOG_TAG
#undef DBG_TAG
#define DBG_TAG LOG_TAG
#else
#define LOG_TAG DGB_TAG
#endif // LOG_TAG
#ifdef RT_DEBUG
#ifdef LOG_LVL
#undef DBG_LVL
#define DBG_LVL LOG_LVL
#else
#define LOG_LVL DBG_LVL
#endif // LOG_LVL
#include <rtdbg.h>
#else
#define LOGN_ENABLE
#endif // RT_DEBUG
#endif // !RT_USING_ULOG
#if (LOG_LVL < LOG_LVL_DBG)
#define LOG0(fmt, ...)
#define LOG1(fmt, ...)
#define LOG2(fmt, ...)
#define LOG3(fmt, ...)
#define LOG4(fmt, ...)
#define LOG5(fmt, ...)
#define LOG6(fmt, ...)
#define LOG7(fmt, ...)
#define LOG10(fmt, ...)
#define LOG11(fmt, ...)
#define LOG12(fmt, ...)
#define LOG13(fmt, ...)
#define LOG14(fmt, ...)
#define LOG15(fmt, ...)
#define LOG16(fmt, ...)
#define LOG17(fmt, ...)
#else
/**
* CSI(Control Sequence Introducer/Initiator) sign
* more information on https://en.wikipedia.org/wiki/ANSI_escape_code
*/
#define CSI_START "\033["
#define CSI_END "\033[0m"
/* output log front color */
#define F_BLACK "30m"
#define F_RED "31m"
#define F_GREEN "32m"
#define F_YELLOW "33m"
#define F_BLUE "34m"
#define F_MAGENTA "35m"
#define F_CYAN "36m"
#define F_WHITE "37m"
/* output log backgroup color */
#define B_BLACK "40m"
#define B_RED "41m"
#define B_GREEN "42m"
#define B_YELLOW "43m"
#define B_BLUE "44m"
#define B_MAGENTA "45m"
#define B_CYAN "46m"
#define B_WHITE "47m"
// 亮前景色
#define F_GRAY "90m"
#define F_B_BLACK "90m"
#define F_B_RED "91m"
#define F_B_GREEN "92m"
#define F_B_YELLOW "93m"
#define F_B_BLUE "94m"
#define F_B_MAGENTA "95m"
#define F_B_CYAN "96m"
#define F_B_WHITE "97m"
// 亮背景色
#define B_GRAY "100m"
#define B_B_BLACK "100m"
#define B_B_RED "101m"
#define B_B_GREEN "102m"
#define B_B_YELLOW "103m"
#define B_B_BLUE "104m"
#define B_B_MAGENTA "105m"
#define B_B_CYAN "106m"
#define B_B_WHITE "107m"
#define SET_COLOR(c, s) CSI_START c s CSI_END
#ifdef RT_USING_ULOG
#define logn_line(color_n, fmt, ...) ulog_d(LOG_TAG, SET_COLOR(color_n, fmt), ##__VA_ARGS__)
#else // !RT_USING_ULOG
#if (DBG_LEVEL >= DBG_LOG || defined(LOGN_ENABLE))
#ifndef RT_DEBUG
#define dbg_log_line(lvl, color_n, fmt, ...) LOGN_PRINTF(LOG_TAG ":" SET_COLOR(color_n, fmt) "\n", ##__VA_ARGS__)
#endif // !RT_DEBUG
#define logn(color_n, fmt, ...) LOGN_PRINTF(SET_COLOR(color_n, fmt), ##__VA_ARGS__)
#define logn_line(color_n, fmt, ...) LOGN_PRINTF(SET_COLOR(color_n, fmt) "\n", ##__VA_ARGS__)
#define logn_lvl(color_n, fmt, ...) dbg_log_line(LOG_LVL, color_n, fmt, ##__VA_ARGS__)
#else // !(DBG_LEVEL >= DBG_LOG)
#define logn_line(...)
#endif // (DBG_LEVEL >= DBG_LOG)
#endif // RT_USING_ULOG
#ifdef USE_LOG0
#define LOG0(fmt, ...) logn_lvl("30;100m", fmt, ##__VA_ARGS__)
#else
#define LOG0(fmt, ...)
#endif // USE_LOG0
#ifdef USE_LOG1
#define LOG1(fmt, ...) logn_lvl(F_RED, fmt, ##__VA_ARGS__)
#else
#define LOG1(fmt, ...)
#endif // USE_LOG1
#ifdef USE_LOG2
#define LOG2(fmt, ...) logn_lvl(F_GREEN, fmt, ##__VA_ARGS__)
#else
#define LOG2(fmt, ...)
#endif // USE_LOG2
#ifdef USE_LOG3
#define LOG3(fmt, ...) logn_lvl(F_YELLOW, fmt, ##__VA_ARGS__)
#else
#define LOG3(fmt, ...)
#endif // USE_LOG3
#ifdef USE_LOG4
#define LOG4(fmt, ...) logn_lvl(F_BLUE, fmt, ##__VA_ARGS__)
#else
#define LOG4(fmt, ...)
#endif // USE_LOG4
#ifdef USE_LOG5
#define LOG5(fmt, ...) logn_lvl(F_MAGENTA, fmt, ##__VA_ARGS__)
#else
#define LOG5(fmt, ...)
#endif // USE_LOG5
#ifdef USE_LOG6
#define LOG6(fmt, ...) logn_lvl(F_CYAN, fmt, ##__VA_ARGS__)
#else
#define LOG6(fmt, ...)
#endif // USE_LOG6
#ifdef USE_LOG7
#define LOG7(fmt, ...) logn_lvl(F_WHITE, fmt, ##__VA_ARGS__)
#else
#define LOG7(fmt, ...)
#endif // USE_LOG7
#ifdef USE_LOG10
#define LOG10(fmt, ...) logn_lvl(F_GRAY, fmt, ##__VA_ARGS__)
#else
#define LOG10(fmt, ...)
#endif // USE_LOG10
#ifdef USE_LOG11
#define LOG11(fmt, ...) logn_lvl(F_B_RED, fmt, ##__VA_ARGS__)
#else
#define LOG11(fmt, ...)
#endif // USE_LOG11
#ifdef USE_LOG12
#define LOG12(fmt, ...) logn_lvl(F_B_GREEN, fmt, ##__VA_ARGS__)
#else
#define LOG12(fmt, ...)
#endif // USE_LOG12
#ifdef USE_LOG13
#define LOG13(fmt, ...) logn_lvl(F_B_YELLOW, fmt, ##__VA_ARGS__)
#else
#define LOG13(fmt, ...)
#endif // USE_LOG13
#ifdef USE_LOG14
#define LOG14(fmt, ...) logn_lvl(F_B_BLUE, fmt, ##__VA_ARGS__)
#else
#define LOG14(fmt, ...)
#endif // USE_LOG14
#ifdef USE_LOG15
#define LOG15(fmt, ...) logn_lvl(F_B_MAGENTA, fmt, ##__VA_ARGS__)
#else
#define LOG15(fmt, ...)
#endif // USE_LOG15
#ifdef USE_LOG16
#define LOG16(fmt, ...) logn_lvl(F_B_CYAN, fmt, ##__VA_ARGS__)
#else
#define LOG16(fmt, ...)
#endif // USE_LOG16
#ifdef USE_LOG17
#define LOG17(fmt, ...) logn_lvl(F_B_WHITE, fmt, ##__VA_ARGS__)
#else
#define LOG17(fmt, ...)
#endif // USE_LOG17
#ifndef USE_LOG_D
#undef LOG_D
#define LOG_D(...)
#endif // USE_LOG_D
#endif
#define IS_USE_LOGN(n) ((defined(USE_LOG##n)) && (LOG_LVL >= LOG_LVL_DBG))
#ifdef __cplusplus
}
#endif
#endif // !__LOGN_H___

View File

@ -0,0 +1,853 @@
/** \file
* \brief Example code for Simple Open EtherCAT master
*
* Usage : red_test [ifname1] [ifname2] [cycletime]
* ifname is NIC interface, f.e. eth0
* cycletime in us, f.e. 500
*
* This is a redundancy test.
*
* (c)Arthur Ketels 2008
*/
#include <fcntl.h>
#include <inttypes.h>
#include <math.h>
#include <pthread.h>
#include <sched.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>
#include "eceeprom.h"
#include "ethercat.h"
#include "osal.h"
#define LOG_TAG "io_test"
#define LOG_LVL LOG_LVL_DBG
// #define LOG_LVL LOG_LVL_INFO
// #define USE_LOG1
// #define USE_LOG2
// #define USE_LOG3
// #define USE_LOG4
// #define USE_LOG5
// #define USE_LOG6
// #define USE_LOG_D
#include "logn.h"
#define NSEC_PER_SEC 1000000000
#define EC_TIMEOUTMON 500
#define TEST_STEP_CYCLETIME (75 * 1000) // us
#define INPUT_CHECK_TIMEOUT (5 * 1000) // us
#define MAX_SLAVE 8
#define ROL_U16(a, n) ((uint16_t)((a) << (n) | (a) >> (16 - n)))
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#define GET_BIT(value, bit) (((value) >> (bit)) & 1) // 读取指定位
#define CPL_BIT(value, bit) ((value) ^= (1 << (bit))) // 取反指定位
#define CLR_BIT(value, bit) ((value) &= ~(1 << (bit))) // 把某个位置0
#define SET_BIT(value, bit) ((value) |= (1 << (bit))) // 把某个位置1
#define show_err(fmt, ...) \
do \
{ \
/* 擦除行, 输出 */ \
sprintf(ec_error.str + strlen(ec_error.str), CSI_START "2K" fmt, ##__VA_ARGS__); \
ec_error.cnt++; \
ec_error.is_showed = false; \
} while (0)
#define time_cmp(a, b, CMP) \
(((a)->sec == (b)->sec) ? ((a)->usec CMP(b)->usec) : ((a)->sec CMP(b)->sec))
#define set_check_stop_time(current_time, us, stop_time) \
do \
{ \
(stop_time)->sec = (current_time)->sec + (us) / 1000000; \
(stop_time)->usec = (current_time)->usec + (us) % 1000000; \
if ((stop_time)->usec >= 1000000) \
{ \
++(stop_time)->sec; \
(stop_time)->usec -= 1000000; \
} \
} while (0)
struct sched_param schedp;
char IOmap[4096];
pthread_t thread1, thread2;
struct timeval tv, t1, t2;
int32_t dorun = 0;
int32_t test_step = 0;
int32_t test_cycle = 0;
int deltat, tmax = 0;
int64 toff, gl_delta;
int DCdiff;
int os;
uint8 ob;
uint16 ob2;
uint8 *digout = 0;
int expectedWKC;
volatile int wkc;
boolean inOP;
uint8 currentgroup = 0;
static int cycletime;
static int step_time;
static struct
{
char str[1024];
size_t cnt;
bool is_showed;
} ec_error;
typedef struct
{
ssize_t input_bytes;
ssize_t output_bytes;
uint8_t outputs[4];
uint8_t inputs[4];
uint8_t is_out_changed[4];
uint8_t is_in_changed[4];
ec_timet check_stop_time[32];
ec_timet output_change_time[32];
ec_timet in_out_time_diff[32];
ec_timet max_in_out_time_diff[32];
bool error[32];
size_t err_cnt[32];
} io_test_t;
io_test_t io_test[MAX_SLAVE + 1] = {0};
static uint16_t test_list[] = {
ROL_U16(0x4241u, 0),
ROL_U16(0x4241u, 1),
ROL_U16(0x4241u, 2),
ROL_U16(0x4241u, 3),
ROL_U16(0x4241u, 4),
ROL_U16(0x4241u, 5),
ROL_U16(0x4241u, 6),
ROL_U16(0x4241u, 7),
ROL_U16(0x4241u, 8),
ROL_U16(0x4241u, 9),
ROL_U16(0x4241u, 10),
ROL_U16(0x4241u, 11),
ROL_U16(0x4241u, 12),
ROL_U16(0x4241u, 13),
ROL_U16(0x4241u, 14),
ROL_U16(0x4241u, 15),
ROL_U16(0x4241u, 0),
ROL_U16(0x4241u, 1),
ROL_U16(0x4241u, 2),
ROL_U16(0x4241u, 3),
ROL_U16(0x4241u, 4),
ROL_U16(0x4241u, 5),
ROL_U16(0x4241u, 6),
ROL_U16(0x4241u, 7),
ROL_U16(0x4241u, 8),
ROL_U16(0x4241u, 9),
ROL_U16(0x4241u, 10),
ROL_U16(0x4241u, 11),
ROL_U16(0x4241u, 12),
ROL_U16(0x4241u, 13),
ROL_U16(0x4241u, 14),
ROL_U16(0x4241u, 15),
ROL_U16(0x4241u, 0),
ROL_U16(0x4241u, 1),
ROL_U16(0x4241u, 2),
ROL_U16(0x4241u, 3),
ROL_U16(0x4241u, 4),
ROL_U16(0x4241u, 5),
ROL_U16(0x4241u, 6),
ROL_U16(0x4241u, 7),
ROL_U16(0x4241u, 8),
ROL_U16(0x4241u, 9),
ROL_U16(0x4241u, 10),
ROL_U16(0x4241u, 11),
ROL_U16(0x4241u, 12),
ROL_U16(0x4241u, 13),
ROL_U16(0x4241u, 14),
ROL_U16(0x4241u, 15),
0xFFFFu,
0xFFFFu,
0xFFFFu,
0xFFFFu,
0xFFFFu,
0xFFFFu,
0xFFFFu,
0xFFFFu,
0xFFFFu,
0xFFFFu,
0xFFFFu,
0xFFFFu,
0xFFFFu,
0xFFFFu,
0xFFFFu,
0xFFFFu,
0xFFFFu,
0xFFFFu,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
};
static int sprint_ms(char *buff, ec_timet *t)
{
int n;
if ((t)->sec) // >= 1000ms
{
n = sprintf(buff, "%u%03u", (t)->sec, (t)->usec / 1000);
}
else if ((t)->usec < 10 * 1000) // 0.00 ~ 9.99ms
{
n = sprintf(buff, "%u.%02u", (t)->usec / 1000, (t)->usec / 10 % 100);
}
else if ((t)->usec < 100 * 1000) // 10.0 ~ 99.9ms
{
n = sprintf(buff, "%u.%u", (t)->usec / 1000, (t)->usec / 100 % 10);
}
else // 100 ~ 999ms
{
n = sprintf(buff, " %u", (t)->usec / 1000);
}
return n;
}
static void show_check(void)
{
struct termios orig_termios;
tcgetattr(STDIN_FILENO, &orig_termios);
struct termios new_termios = orig_termios;
new_termios.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &new_termios);
int flags = fcntl(STDIN_FILENO, F_GETFL, 0);
fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
char ch;
bool is_first = true;
ec_error.is_showed = true;
printf(CSI_START "?25l"); // 隐藏光标
for (;;)
{
// 按空格q, x 键退出
int result = read(STDIN_FILENO, &ch, 1);
if (result == 1 && (ch == ' ' || ch == 'q' || ch == 'x'))
{
break;
}
if (is_first)
{
is_first = false;
}
else
{
printf(CSI_START "4F"); // 光标上移4行,到行首
for (int i = 1; i <= ec_slavecount; i++)
{
printf(CSI_START "5F"); // 光标上移5行,到行首
}
}
if (!ec_error.is_showed)
{
printf("%s", ec_error.str); // 输出
ec_error.str[0] = '\0';
ec_error.is_showed = true;
}
printf("ID | Type | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | "
"15 | 16 |\n"
"---+-------+----+----+----+----+----+----+----+----+----+----+----+----+----+----+-"
"---+----+\n");
for (int i = 1; i <= ec_slavecount; i++)
{
char buff[64 * 1024];
char *p = buff;
// show output / input
p += sprintf(p, "%2d | Out/In|", i);
int j = 0;
for (; j < io_test[i].output_bytes; j++)
{
for (int k = 0; k < 8; k++)
{
bool b = GET_BIT(io_test[i].outputs[j], k);
if (b)
{
p += sprintf(p, SET_COLOR(B_RED, " 1"));
}
else
{
p += sprintf(p, " 0");
}
b = GET_BIT(io_test[i].inputs[j], k);
if (b)
{
p += sprintf(p, SET_COLOR(B_BLUE, "/1"));
}
else
{
p += sprintf(p, "/0");
}
p += sprintf(p, "|");
}
}
for (; j < 2; j++)
{
p += sprintf(p, " | | | | | | | |");
}
// show diff
p += sprintf(p, "\n |Diff/ms|");
j = 0;
for (; j < io_test[i].input_bytes; j++)
{
for (int k = 0; k < 8; k++)
{
int idx = j * 8 + k;
if (io_test[i].max_in_out_time_diff[idx].sec > 0)
{
p += sprintf(p, SET_COLOR(B_RED, " !! "));
}
else
{
p += sprint_ms(p, &io_test[i].in_out_time_diff[idx]);
}
p += sprintf(p, "|");
}
}
for (; j < 2; j++)
{
p += sprintf(p, " | | | | | | | |");
}
// show max
p += sprintf(p, "\n | Max/ms|");
j = 0;
for (; j < io_test[i].input_bytes; j++)
{
for (int k = 0; k < 8; k++)
{
int idx = j * 8 + k;
if (io_test[i].error[j * 8 + k]) // 出错
{
if (io_test[i].max_in_out_time_diff[idx].sec > 9)
{
p += sprintf(p, SET_COLOR(B_RED, " !! "));
}
else
{
char ms[16];
sprint_ms(ms, &io_test[i].max_in_out_time_diff[idx]);
p += sprintf(p, SET_COLOR(B_RED, "%s"), ms);
}
}
else // 正常
{
if (io_test[i].max_in_out_time_diff[idx].sec > 0)
{
p += sprintf(p, SET_COLOR(B_GREEN, " !! "));
}
else
{
char ms[16];
sprint_ms(ms, &io_test[i].max_in_out_time_diff[idx]);
p += sprintf(p, SET_COLOR(B_GREEN, "%s"), ms);
}
}
p += sprintf(p, "|");
}
}
for (; j < 2; j++)
{
p += sprintf(p, " | | | | | | | |");
}
// err_cnt
p += sprintf(p, "\n |ErrCnt |");
j = 0;
for (; j < io_test[i].input_bytes; j++)
{
for (int k = 0; k < 8; k++)
{
int idx = j * 8 + k;
if (io_test[i].err_cnt[idx] == 0)
{
p += sprintf(p, " 0");
}
else if (io_test[i].err_cnt[idx] > 999)
{
p += sprintf(p, SET_COLOR(B_B_RED, "999+"));
}
else
{
p += sprintf(p, SET_COLOR(B_B_RED, " %3lu"), io_test[i].err_cnt[idx]);
}
p += sprintf(p, "|");
}
}
for (; j < 2; j++)
{
p += sprintf(p, " | | | | | | | |");
}
p += sprintf(p, "\n---+-------+----+----+----+----+----+----+----+----+----+----+----+-"
"---+----+----+----+----+\n");
printf("%s", buff);
}
printf("Processdata cycle %5d, cycletime %dus, Wck %3d, DCtime %12" PRId64
"ns, dt " CSI_START "K" /*擦除到行尾*/ "%6" PRId64 "ns\n",
dorun, cycletime, wkc, ec_DCtime, gl_delta);
printf("Test cycle %d, Step time %dms, Test step %3d, EC Error count %lu."
" Press key SPACE or 'q' or 'x' to EXIT.\n",
test_cycle, step_time / 1000, test_step, ec_error.cnt);
fflush(stdout);
osal_usleep(50000);
}
printf(CSI_START "?25h"); // 显示光标
}
void tj30_test(char *ifname)
{
int cnt, i;
printf("Starting TJ30-XXXX test\n");
/* initialise SOEM, bind socket to ifname */
if (!ec_init(ifname))
{
printf("No socket connection on %s\nExcecute as root\n", ifname);
return;
}
printf("ec_init on %s succeeded.\n", ifname);
/* find and auto-config slaves */
if (ec_config(FALSE, &IOmap) <= 0)
{
printf("No slaves found!\n");
goto __exit;
}
printf("%d slaves found and configured.\n", ec_slavecount);
/* check for TJ30-1616DN */
for (cnt = 1; cnt <= ec_slavecount; cnt++)
{
if (ec_slave[cnt].eep_id != 0x00010200)
{
printf("Slave %i: ID (%u) 不匹配!\n", cnt, ec_slave[cnt].eep_id);
goto __exit;
}
}
/* wait for all slaves to reach SAFE_OP state */
ec_statecheck(0, EC_STATE_SAFE_OP, EC_TIMEOUTSTATE);
/* configure DC options for every DC capable slave found in the list */
ec_configdc();
/* read indevidual slave state and store in ec_slave[] */
ec_readstate();
for (cnt = 1; cnt <= ec_slavecount; cnt++)
{
int32_t sn = ecEepromGetSN(cnt);
logn(F_B_BLUE,
"Slave:%d Name:%s ID: " CSI_START B_B_WHITE "%u/0x%08x" CSI_END CSI_START F_B_BLUE
" SN:" CSI_START B_B_WHITE "%d" CSI_END CSI_START F_B_BLUE
" Output size:%3dbits Input size:%3dbits\n",
cnt, ec_slave[cnt].name, ec_slave[cnt].eep_id, ec_slave[cnt].eep_id, sn,
ec_slave[cnt].Obits, ec_slave[cnt].Ibits);
logn(F_B_BLUE, "State:%2d delay:%3d DC:%2d Out:%p,%4d In:%p,%4d\n", ec_slave[cnt].state,
(int)ec_slave[cnt].pdelay, ec_slave[cnt].hasdc, ec_slave[cnt].outputs,
ec_slave[cnt].Obytes, ec_slave[cnt].inputs, ec_slave[cnt].Ibytes);
io_test[cnt].input_bytes = ec_slave[cnt].Ibytes;
if (io_test[cnt].input_bytes == 0 && ec_slave[cnt].Ibits > 0)
{
io_test[cnt].input_bytes = 1;
}
io_test[cnt].output_bytes = ec_slave[cnt].Obytes;
if (io_test[cnt].output_bytes == 0 && ec_slave[cnt].Obits > 0)
{
io_test[cnt].output_bytes = 1;
}
}
expectedWKC = (ec_group[0].outputsWKC * 2) + ec_group[0].inputsWKC;
printf("Calculated workcounter %d\n", expectedWKC);
printf("Request operational state for all slaves\n");
ec_slave[0].state = EC_STATE_OPERATIONAL;
/* request OP state for all slaves */
ec_writestate(0);
/* wait for all slaves to reach OP state */
ec_statecheck(0, EC_STATE_OPERATIONAL, 5 * EC_TIMEOUTSTATE);
/* activate cyclic process data */
dorun = 1;
/* 运行模式 */
if (ec_slave[0].state == EC_STATE_OPERATIONAL)
{
printf("Operational state reached for all slaves.\n");
inOP = TRUE;
show_check();
printf("Test is END.\n");
dorun = 0;
inOP = FALSE;
}
else
{
printf("Not all slaves reached operational state.\n");
ec_readstate();
for (i = 1; i <= ec_slavecount; i++)
{
if (ec_slave[i].state != EC_STATE_OPERATIONAL)
{
printf("Slave %d State=0x%2.2x StatusCode=0x%4.4x : %s\n", i, ec_slave[i].state,
ec_slave[i].ALstatuscode, ec_ALstatuscode2string(ec_slave[i].ALstatuscode));
}
}
}
printf("Request safe operational state for all slaves\n");
ec_slave[0].state = EC_STATE_SAFE_OP;
/* request SAFE_OP state for all slaves */
ec_writestate(0);
__exit:
printf("End IO test, close socket\n");
/* stop SOEM, close socket */
ec_close();
}
/* add ns to timespec */
void add_timespec(struct timespec *ts, int64 addtime)
{
int64 sec, nsec;
nsec = addtime % NSEC_PER_SEC;
sec = (addtime - nsec) / NSEC_PER_SEC;
ts->tv_sec += sec;
ts->tv_nsec += nsec;
if (ts->tv_nsec >= NSEC_PER_SEC)
{
nsec = ts->tv_nsec % NSEC_PER_SEC;
ts->tv_sec += (ts->tv_nsec - nsec) / NSEC_PER_SEC;
ts->tv_nsec = nsec;
}
}
/* PI calculation to get linux time synced to DC time */
void ec_sync(int64 reftime, int64 cycletime, int64 *offsettime)
{
static int64 integral = 0;
int64 delta;
/* set linux sync point 50us later than DC sync, just as example */
delta = (reftime - 50000) % cycletime;
if (delta > (cycletime / 2))
{
delta = delta - cycletime;
}
if (delta > 0)
{
integral++;
}
if (delta < 0)
{
integral--;
}
*offsettime = -(delta / 100) - (integral / 20);
gl_delta = delta;
}
static void check_io()
{
ec_timet current_time = osal_current_time();
for (int i = 1; i <= ec_slavecount; i++)
{
for (int j = 0; j < io_test[i].input_bytes; j++)
{
uint8_t is_in_changed = io_test[i].inputs[j] ^ ec_slave[i].inputs[j];
io_test[i].is_in_changed[j] |= is_in_changed;
io_test[i].inputs[j] = ec_slave[i].inputs[j];
uint8_t is_not_same = io_test[i].inputs[j] ^ io_test[i].outputs[j];
for (int k = 0; k < 8; k++)
{
// if (!GET_BIT(io_test[i].is_out_changed[j], k)) //输出未变
// {
// continue;
// }
int idx = j * 8 + k;
if (GET_BIT(is_not_same, k)) // update result
{
if (GET_BIT(io_test[i].is_out_changed[j], k))
{
if (time_cmp(&io_test[i].check_stop_time[idx], &current_time, <)) // 到期
{
io_test[i].error[idx] = true;
io_test[i].err_cnt[idx]++;
CLR_BIT(io_test[i].is_out_changed[j], k);
CLR_BIT(io_test[i].is_in_changed[j], k);
if (time_cmp(&io_test[i].in_out_time_diff[idx],
&io_test[i].max_in_out_time_diff[idx], >))
{
io_test[i].max_in_out_time_diff[idx]
= io_test[i].in_out_time_diff[idx];
}
}
}
else // 输出未变,且不同,就出错
{
if (GET_BIT(io_test[i].is_in_changed[j], k))
{
io_test[i].max_in_out_time_diff[idx].sec = 0;
io_test[i].max_in_out_time_diff[idx].usec = 99900;
CLR_BIT(io_test[i].is_in_changed[j], k);
io_test[i].error[idx] = true;
io_test[i].err_cnt[idx]++;
}
}
}
else if (GET_BIT(io_test[i].is_out_changed[j], k)) // 相同, 且输出有变化
{
if (GET_BIT(io_test[i].is_in_changed[j], k)) // update time diff
{
CLR_BIT(io_test[i].is_in_changed[j], k);
CLR_BIT(io_test[i].is_out_changed[j], k);
osal_time_diff(&io_test[i].output_change_time[idx], &current_time,
&io_test[i].in_out_time_diff[idx]);
if (time_cmp(&io_test[i].in_out_time_diff[idx],
&io_test[i].max_in_out_time_diff[idx], >))
{
io_test[i].max_in_out_time_diff[idx] = io_test[i].in_out_time_diff[idx];
}
}
}
}
}
}
}
static void write_output(void)
{
static osal_timert tmr = {0};
static size_t list_idx = 0;
if (osal_timer_is_expired(&tmr))
{
test_step++;
osal_timer_start(&tmr, step_time);
uint16_t test_val = test_list[list_idx];
list_idx++;
if (list_idx >= ARRAY_SIZE(test_list))
{
list_idx = 0;
test_cycle++;
}
ec_timet current_time = osal_current_time();
for (int i = 1; i <= ec_slavecount; i++)
{
for (int j = 0; j < io_test[i].output_bytes; j++)
{
ec_slave[i].outputs[j] = (uint8_t)((test_val >> (j % 2)) & 0xff);
uint8_t is_out_changed = io_test[i].outputs[j] ^ ec_slave[i].outputs[j];
for (int k = 0; k < 8; k++)
{
size_t p_idx = j * 8 + k;
if (GET_BIT(is_out_changed, k))
{
io_test[i].output_change_time[p_idx] = current_time;
set_check_stop_time(&current_time, INPUT_CHECK_TIMEOUT,
&io_test[i].check_stop_time[p_idx]);
}
}
io_test[i].is_out_changed[j] |= is_out_changed;
io_test[i].outputs[j] = ec_slave[i].outputs[j];
}
}
}
}
/* RT EtherCAT thread */
OSAL_THREAD_FUNC_RT ecatthread(void *ptr)
{
struct timespec ts, tleft;
int ht;
int64 cycletime;
clock_gettime(CLOCK_MONOTONIC, &ts);
ht = (ts.tv_nsec / 1000000) + 1; /* round to nearest ms */
ts.tv_nsec = ht * 1000000;
if (ts.tv_nsec >= NSEC_PER_SEC)
{
ts.tv_sec++;
ts.tv_nsec -= NSEC_PER_SEC;
}
cycletime = *(int *)ptr * 1000; /* cycletime in ns */
toff = 0;
dorun = 0;
ec_send_processdata();
while (1)
{
/* calculate next cycle start */
add_timespec(&ts, cycletime + toff);
/* wait to cycle start */
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, &tleft);
if (dorun == 0)
{
continue;
}
else if (dorun < 0)
{
break;
}
dorun++;
wkc = ec_receive_processdata(EC_TIMEOUTRET);
check_io();
write_output();
if (ec_slave[0].hasdc)
{
/* calulate toff to get linux time and DC synced */
ec_sync(ec_DCtime, cycletime, &toff);
}
ec_send_processdata();
}
}
OSAL_THREAD_FUNC ecatcheck(void *ptr)
{
int slave;
(void)ptr;
while (1)
{
if (inOP && ((wkc < expectedWKC) || ec_group[currentgroup].docheckstate))
{
/* one ore more slaves are not responding */
ec_group[currentgroup].docheckstate = FALSE;
ec_readstate();
for (slave = 1; slave <= ec_slavecount; slave++)
{
if ((ec_slave[slave].group == currentgroup)
&& (ec_slave[slave].state != EC_STATE_OPERATIONAL))
{
ec_group[currentgroup].docheckstate = TRUE;
if (ec_slave[slave].state == (EC_STATE_SAFE_OP + EC_STATE_ERROR))
{
show_err("ERROR : slave %d is in SAFE_OP + ERROR, attempting ack.\n",
slave);
ec_slave[slave].state = (EC_STATE_SAFE_OP + EC_STATE_ACK);
ec_writestate(slave);
}
else if (ec_slave[slave].state == EC_STATE_SAFE_OP)
{
show_err("WARNING : slave %d is in SAFE_OP, change to OPERATIONAL.\n",
slave);
ec_slave[slave].state = EC_STATE_OPERATIONAL;
ec_writestate(slave);
}
else if (ec_slave[slave].state > EC_STATE_NONE)
{
if (ec_reconfig_slave(slave, EC_TIMEOUTMON))
{
ec_slave[slave].islost = FALSE;
show_err("MESSAGE : slave %d reconfigured\n", slave);
}
}
else if (!ec_slave[slave].islost)
{
/* re-check state */
ec_statecheck(slave, EC_STATE_OPERATIONAL, EC_TIMEOUTRET);
if (ec_slave[slave].state == EC_STATE_NONE)
{
ec_slave[slave].islost = TRUE;
show_err("ERROR : slave %d lost\n", slave);
}
}
}
if (ec_slave[slave].islost)
{
if (ec_slave[slave].state == EC_STATE_NONE)
{
if (ec_recover_slave(slave, EC_TIMEOUTMON))
{
ec_slave[slave].islost = FALSE;
show_err("MESSAGE : slave %d recovered\n", slave);
}
}
else
{
ec_slave[slave].islost = FALSE;
show_err("MESSAGE : slave %d found\n", slave);
}
}
}
if (!ec_group[currentgroup].docheckstate)
show_err("OK : all slaves resumed OPERATIONAL.\n");
}
osal_usleep(10);
}
}
#define stack64k (64 * 1024)
int main(int argc, char *argv[])
{
cycletime = 50;
step_time = TEST_STEP_CYCLETIME;
printf("SOEM (Simple Open EtherCAT Master)\nIO test for TJ30-XXXX\n");
switch (argc)
{
case 4:
step_time = atoi(argv[3]) * 1000;
[[fallthrough]];
case 3:
cycletime = atoi(argv[2]);
[[fallthrough]];
case 2:
dorun = 0;
/* create RT thread */
osal_thread_create_rt(&thread1, stack64k * 2, &ecatthread, (void *)&cycletime);
/* create thread to handle slave error handling in OP */
osal_thread_create(&thread2, stack64k * 4, &ecatcheck, NULL);
/* start acyclic part */
tj30_test(argv[1]);
break;
default:
printf("Usage: tj30_test ifname [cycletime [step_time]]\n"
"ifname = eth0 for example\n"
"cycletime in us (default is 50us)\n"
"step_time in ms (default is 75ms)");
ec_adaptert *adapter = NULL;
printf("\nAvailable adapters:\n");
adapter = ec_find_adapters();
while (adapter != NULL)
{
printf(" - %s (%s)\n", adapter->name, adapter->desc);
adapter = adapter->next;
}
ec_free_adapters(adapter);
}
return (0);
}

View File

@ -250,7 +250,7 @@ void add_timespec(struct timespec *ts, int64 addtime)
sec = (addtime - nsec) / NSEC_PER_SEC;
ts->tv_sec += sec;
ts->tv_nsec += nsec;
if ( ts->tv_nsec > NSEC_PER_SEC )
if ( ts->tv_nsec >= NSEC_PER_SEC )
{
nsec = ts->tv_nsec % NSEC_PER_SEC;
ts->tv_sec += (ts->tv_nsec - nsec) / NSEC_PER_SEC;