概述
/***************************************************************************** * CANopenSocket CANopenCommand.c hacking * 说明: * 分析一下CANopenSocket中的CANopenCommand部分是怎么工作的。 * * 2017-3-23 深圳 南山平山村 曾剑锋 ****************************************************************************/ /* * Client socket command interface for CANopenSocket. * * @file CANopenCommand.c * @author Janez Paternoster * @copyright 2015 Janez Paternoster * * This file is part of CANopenNode, an opensource CANopen Stack. * Project home page is <https://github.com/CANopenNode/CANopenNode>. * For more information on CANopen see <http://www.can-cia.org/>. * * CANopenNode is free and open source 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 2 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 <stdlib.h> #include <unistd.h> #include <sys/un.h> #include <sys/socket.h> #ifndef BUF_SIZE #define BUF_SIZE 100000 #endif /** * 错误退出函数 */ /* Helper functions */ void errExit(char* msg) { perror(msg); exit(EXIT_FAILURE); } /** * 是否打印错误描述相关信息标志 */ static int printErrorDescription = 0; /** * 发送命令函数,fd是socket描述符 */ static void sendCommand(int fd, char* command, size_t commandLength); /** * 参数使用方法说明 */ static void printUsage(char *progName) { fprintf(stderr, "Usage: %s [options] <command string>n", progName); fprintf(stderr, "n" "Program reads arguments or standard input or file. It sends commands ton" "canopend via socket, line after line. Result is printed to standard output.n" "For more information see http://www.can-cia.org/, CiA 309 standard.n" "n" "Options:n" " -f <input file path> Path to the input file.n" " -s <socket path> Path to the socket (default '/tmp/CO_command_socket').n" " -h Display description of error codes in case of error.n" " (Default, if command is passed by program arguments.)n" " --help Display this help.n" " --helpall Display this help, internal and SDO error codes.n" "n" "Command strings must start with "["<sequence>"]" (except if from arguments):n" " - SDO upload: [[<net>] <node>] r[ead] <index> <subindex> [<datatype>]n" " - SDO download: [[<net>] <node>] w[rite] <index> <subindex> <datatype> <value>n" " - Configure SDO time-out: [<net>] set sdo_timeout <value>n" " - Enable SDO block transfer: [<net>] set sdo_block <value>n" " - Set default node: [<net>] set node <value>n" "n" " - Start node: [[<net>] <node>] startn" " - Stop node: [[<net>] <node>] stopn" " - Set node to pre-operational: [[<net>] <node>] preop[erational]n" " - Reset node: [[<net>] <node>] reset noden" " - Reset communication: [[<net>] <node>] reset comm[unication]n" "n" "Comments started with '#' are ignored. They may be on the beginning of the linen" "or after the command string. 'sdo_timeout' is in milliseconds, 500 by default.n" "If <node> is not specified within commands, then value defined by 'set node'n" "command is used.n" "n" "n" "Datatypes:n" " - b - Boolean.n" " - u8, u16, u32, u64 - Unsigned integers.n" " - i8, i16, i32, i64 - Signed integers.n" " - r32, r64 - Real numbers.n" " - t, td - Time of day, time difference.n" " - vs - Visible string (between double quotes).n" " - os, us, d - Octet string, unicode string, domainn" " (mime-base64 (RFC2045) should be used).n" "n" "n" "Response: "["<sequence>"]" \n" " OK | <value> | ERROR: <SDO-abort-code> | ERROR: <internal-error-code>n" "n" "n" "LICENSEn" " This program is part of CANopenSocket and can be downloaded from:n" " https://github.com/CANopenNode/CANopenSocketn" " Permission is granted to copy, distribute and/or modify this documentn" " under the terms of the GNU General Public License, Version 2.n" "n" ); } /** * 错误描述对应的结构体 */ /* Extract error description */ typedef struct { int code; char* desc; } errorDescs_t; /** * 这里列出所有的canopend返回的错误编号对应的显示的英文 */ static const errorDescs_t errorDescs[] = { {100, "Request not supported."}, {101, "Syntax error."}, {102, "Request not processed due to internal state."}, {103, "Time-out (where applicable)."}, {104, "No default net set."}, {105, "No default node set."}, {106, "Unsupported net."}, {107, "Unsupported node."}, {200, "Lost guarding message."}, {201, "Lost connection."}, {202, "Heartbeat started."}, {203, "Heartbeat lost."}, {204, "Wrong NMT state."}, {205, "Boot-up."}, {300, "Error passive."}, {301, "Bus off."}, {303, "CAN buffer overflow."}, {304, "CAN init."}, {305, "CAN active (at init or start-up)."}, {400, "PDO already used."}, {401, "PDO length exceeded."}, {501, "LSS implementation- / manufacturer-specific error."}, {502, "LSS node-ID not supported."}, {503, "LSS bit-rate not supported."}, {504, "LSS parameter storing failed."}, {505, "LSS command failed because of media error."}, {600, "Running out of memory."}, {0x00000000, "No abort."}, {0x05030000, "Toggle bit not altered."}, {0x05040000, "SDO protocol timed out."}, {0x05040001, "Command specifier not valid or unknown."}, {0x05040002, "Invalid block size in block mode."}, {0x05040003, "Invalid sequence number in block mode."}, {0x05040004, "CRC error (block mode only)."}, {0x05040005, "Out of memory."}, {0x06010000, "Unsupported access to an object."}, {0x06010001, "Attempt to read a write only object."}, {0x06010002, "Attempt to write a read only object."}, {0x06020000, "Object does not exist."}, {0x06040041, "Object cannot be mapped to the PDO."}, {0x06040042, "Number and length of object to be mapped exceeds PDO length."}, {0x06040043, "General parameter incompatibility reasons."}, {0x06040047, "General internal incompatibility in device."}, {0x06060000, "Access failed due to hardware error."}, {0x06070010, "Data type does not match, length of service parameter does not match."}, {0x06070012, "Data type does not match, length of service parameter too high."}, {0x06070013, "Data type does not match, length of service parameter too short."}, {0x06090011, "Sub index does not exist."}, {0x06090030, "Invalid value for parameter (download only)."}, {0x06090031, "Value range of parameter written too high."}, {0x06090032, "Value range of parameter written too low."}, {0x06090036, "Maximum value is less than minimum value."}, {0x060A0023, "Resource not available: SDO connection."}, {0x08000000, "General error."}, {0x08000020, "Data cannot be transferred or stored to application."}, {0x08000021, "Data cannot be transferred or stored to application because of local control."}, {0x08000022, "Data cannot be transferred or stored to application because of present device state."}, {0x08000023, "Object dictionary not present or dynamic generation fails."}, {0x08000024, "No data available."} }; /** * 打印所有的错误描述文档内容,有一部分是十进制的,有一部分是十六进制的,注意for循环中的if判断和上面结构体数组中的数值就能体现出来了 */ static void printErrorDescs(void) { int i, len; len = sizeof(errorDescs) / sizeof(errorDescs_t); fprintf(stderr, "Internal error codes:n"); for(i=0; i<len; i++) { const errorDescs_t *ed = &errorDescs[i]; if(ed->code == 0) break; fprintf(stderr, " - %d - %sn", ed->code, ed->desc); } fprintf(stderr, "n"); fprintf(stderr, "SDO abort codes:n"); for(; i<len; i++) { const errorDescs_t *ed = &errorDescs[i]; fprintf(stderr, " - 0x%08X - %sn", ed->code, ed->desc); } fprintf(stderr, "n"); } /******************************************************************************/ int main (int argc, char *argv[]) { char *socketPath = "/tmp/CO_command_socket"; /* Name of the local domain socket, configurable by arguments. */ char *inputFilePath = NULL; char buf[BUF_SIZE]; int fd; struct sockaddr_un addr; int opt; int i; /** * 输出基本帮助信息 */ if(argc >= 2 && strcmp(argv[1], "--help") == 0) { printUsage(argv[0]); exit(EXIT_SUCCESS); } /** * 输出基本帮助信息和返回的错误码信息 */ if(argc >= 2 && strcmp(argv[1], "--helpall") == 0) { printUsage(argv[0]); printErrorDescs(); exit(EXIT_SUCCESS); } /* Get program options */ /** * 获取程序运行时命令行传递过来的参数,并解析 */ while((opt = getopt(argc, argv, "s:f:h")) != -1) { switch (opt) { case 'f': // 将命令放置于文件中,通过读取文件并发送给canopend处理 inputFilePath = optarg; break; case 's': // 指定canopend的socket的path在哪里 socketPath = optarg; break; case 'h': // 输出错误描述 printErrorDescription = 1; break; default: printUsage(argv[0]); exit(EXIT_FAILURE); } } /* Create and connect client socket */ /** * 创建本地客户端socket */ fd = socket(AF_UNIX, SOCK_STREAM, 0); if(fd == -1) { errExit("Socket creation failed"); } /** * 设置本地socket */ memset(&addr, 0, sizeof(struct sockaddr_un)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, socketPath, sizeof(addr.sun_path) - 1); /** * 链接本地socket */ if(connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) == -1) { errExit("Socket connection failed"); } /* get commands from input file, line after line */ /** * 从文件中获取命令,这里不进行任何处理,直接全部传送,仅仅是将文件中的内容完整转给canopend处理 */ if(inputFilePath != NULL) { FILE *fp = fopen(inputFilePath, "r"); if(fp == NULL) { errExit("Can't open input file"); } while(fgets(buf, BUF_SIZE, fp) != NULL) { sendCommand(fd, buf, strlen(buf)); } fclose(fp); } /* get command from arguments */ /** * 从命令行的参数中获取命令 */ else if(optind < argc) { buf[0] = 0; size_t buflen = 0; /* Add sequence number if not present on command line arguments */ /** * 如果CAN设备的序号没有提供,那么就是用默认的1号设备(can1)设备 */ if(argv[optind][0] != '[') { strcat(buf, "[1] "); } /** * 将命令行参数合成命令 */ for(i=optind; i<argc; i++) { strncat(buf, argv[i], (BUF_SIZE - 2) - buflen); strcat(buf, " "); buflen = strlen(buf); if(buflen >= (BUF_SIZE - 1)) { fprintf(stderr, "String too long!n"); exit(EXIT_FAILURE); } } /** * 每一条命令都是使用'n'结束,表示一行 */ buf[buflen - 1] = 'n'; /* replace last space with newline */ /** * 将合成的命令发送给canopend */ printErrorDescription = 1; sendCommand(fd, buf, buflen); } /* get commands from stdin, line after line */ /** * 从终端的标准输入中一行一行的获取命令 */ else { while(fgets(buf, BUF_SIZE, stdin) != NULL) { sendCommand(fd, buf, strlen(buf)); } } close(fd); exit(EXIT_SUCCESS); } static void sendCommand(int fd, char* command, size_t commandLength) { size_t n; char buf[BUF_SIZE]; /** * 发送命令 */ if (write(fd, command, commandLength) != commandLength) { errExit("Socket write failed"); } /** * 接收命令返回信息 */ n = read(fd, buf, sizeof(buf)); if(n == -1) { errExit("Socket read failed"); } /** * 是否处理返回的信息 */ if(printErrorDescription == 1) { char *errLoc = strstr(buf, "ERROR:"); char *endLoc = strstr(buf, "rn"); if(errLoc != NULL && endLoc != NULL) { int num; char *sRet = NULL; errLoc += 6; num = strtol(errLoc, &sRet, 0); if(strlen(errLoc) != 0 && sRet == strchr(errLoc, 'r')) { int i, len; len = sizeof(errorDescs) / sizeof(errorDescs_t); /** * 查找并输出信息 */ for(i=0; i<len; i++) { const errorDescs_t *ed = &errorDescs[i]; if(ed->code == num) { sprintf(endLoc, " - %srn", ed->desc); break; } } } } } /** * 输出返回原始信息 */ printf("%s", buf); }
转载于:https://www.cnblogs.com/zengjfgit/p/6603830.html
最后
以上就是细心往事为你收集整理的CANopenSocket CANopenCommand.c hacking的全部内容,希望文章能够帮你解决CANopenSocket CANopenCommand.c hacking所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复