From c3f595442ba92b5070db3ab899b6b3b2b3c86702 Mon Sep 17 00:00:00 2001
From: Florian Pose <fp@igh-essen.com>
Date: Thu, 11 Mar 2010 14:29:43 +0100
Subject: [PATCH] Implemented SoE IDN parser for strings like 'P-0-0150'; moved
 data type information string to DataTypeHandler.

---
 TODO                     |   2 -
 tool/CommandDownload.cpp |   4 +-
 tool/CommandRegRead.cpp  |   4 +-
 tool/CommandRegWrite.cpp |   4 +-
 tool/CommandSoeRead.cpp  |  27 ++++++----
 tool/CommandSoeRead.h    |   6 +--
 tool/CommandSoeWrite.cpp |  24 +++++----
 tool/CommandSoeWrite.h   |   6 +--
 tool/CommandUpload.cpp   |   4 +-
 tool/DataTypeHandler.cpp |  14 +++++
 tool/DataTypeHandler.h   |   2 +
 tool/Makefile.am         |   2 +
 tool/SoeCommand.cpp      | 108 +++++++++++++++++++++++++++++++++++++++
 tool/SoeCommand.h        |  51 ++++++++++++++++++
 14 files changed, 215 insertions(+), 43 deletions(-)
 create mode 100644 tool/SoeCommand.cpp
 create mode 100644 tool/SoeCommand.h

diff --git a/TODO b/TODO
index e7b21e0d..8c61b06d 100644
--- a/TODO
+++ b/TODO
@@ -40,8 +40,6 @@ Version 1.5.0:
     - Implement indent in 'ethercat ma'
     - Implement 0xXXXX:YY format for specifying SDOs.
     - Lookup codes for 64bit data types.
-    - Move data type usage string into DataTypeHandler.
-    - Implement interpretation of SoE '[SP]-x-yyy' strings.
     - Implement reading from stream for soe_write.
 
 Future issues:
diff --git a/tool/CommandDownload.cpp b/tool/CommandDownload.cpp
index 47ec9c15..ee008f13 100644
--- a/tool/CommandDownload.cpp
+++ b/tool/CommandDownload.cpp
@@ -59,9 +59,7 @@ string CommandDownload::helpString() const
         << "information service or the SDO is not in the dictionary," << endl
         << "the --type option is mandatory." << endl
         << endl
-        << "These are the valid SDO entry data types:" << endl
-        << "  int8, int16, int32, uint8, uint16, uint32, string," << endl
-        << "  octet_string." << endl
+        << typeInfo()
         << endl
         << "Arguments:" << endl
         << "  INDEX    is the SDO index and must be an unsigned" << endl
diff --git a/tool/CommandRegRead.cpp b/tool/CommandRegRead.cpp
index 5689d523..8847ba7b 100644
--- a/tool/CommandRegRead.cpp
+++ b/tool/CommandRegRead.cpp
@@ -62,9 +62,7 @@ string CommandRegRead::helpString() const
         << "         can be omitted), if a selected data type" << endl
         << "         implies a length." << endl
         << endl
-        << "These are the valid data types:" << endl
-        << "  int8, int16, int32, int64, uint8, uint16, uint32," << endl
-        << "  uint64, string, raw." << endl
+        << typeInfo()
         << endl
         << "Command-specific options:" << endl
         << "  --alias    -a <alias>" << endl
diff --git a/tool/CommandRegWrite.cpp b/tool/CommandRegWrite.cpp
index 9927f3d4..0c6ed512 100644
--- a/tool/CommandRegWrite.cpp
+++ b/tool/CommandRegWrite.cpp
@@ -64,9 +64,7 @@ string CommandRegWrite::helpString() const
         << "          stdin. If a datatype was specified, VALUE is" << endl
         << "          interpreted respective to the given type." << endl
         << endl
-        << "These are the valid data types:" << endl
-        << "  int8, int16, int32, int64, uint8, uint16, uint32," << endl
-        << "  uint64, string." << endl
+        << typeInfo()
         << endl
         << "Command-specific options:" << endl
         << "  --alias    -a <alias>" << endl
diff --git a/tool/CommandSoeRead.cpp b/tool/CommandSoeRead.cpp
index 7623d8a8..6edb894d 100644
--- a/tool/CommandSoeRead.cpp
+++ b/tool/CommandSoeRead.cpp
@@ -37,7 +37,7 @@ using namespace std;
 /*****************************************************************************/
 
 CommandSoeRead::CommandSoeRead():
-    Command("soe_read", "Read an SoE IDN from a slave.")
+    SoeCommand("soe_read", "Read an SoE IDN from a slave.")
 {
 }
 
@@ -47,20 +47,27 @@ string CommandSoeRead::helpString() const
 {
     stringstream str;
 
-    str << getName() << " [OPTIONS] <INDEX> <SUBINDEX>" << endl
+    str << getName() << " [OPTIONS] <IDN>" << endl
         << endl
         << getBriefDescription() << endl
         << endl
         << "This command requires a single slave to be selected." << endl
         << endl
         << "Arguments:" << endl
-        << "  IDN      is the IDN and must be an unsigned" << endl
-        << "           16 bit number." << endl
+        << "  IDN      is the IDN and must be either an unsigned" << endl
+        << "           16 bit number acc. to IEC 61800-7-204:" << endl
+        << "             Bit 15: (0) Standard data, (1) Product data" << endl
+        << "             Bit 14 - 12: Parameter set (0 - 7)" << endl
+        << "             Bit 11 - 0: Data block number" << endl
+        << "           or a string like 'P-0-150'." << endl
+        << endl
+        << typeInfo()
         << endl
         << "Command-specific options:" << endl
         << "  --alias    -a <alias>" << endl
         << "  --position -p <pos>    Slave selection. See the help of" << endl
         << "                         the 'slaves' command." << endl
+        << "  --type     -t <type>   Data type (see above)." << endl
         << endl
         << numericInfo();
 
@@ -72,7 +79,7 @@ string CommandSoeRead::helpString() const
 void CommandSoeRead::execute(const StringVector &args)
 {
     SlaveList slaves;
-    stringstream err, strIdn;
+    stringstream err;
     const DataType *dataType = NULL;
     ec_ioctl_slave_soe_read_t ioctl;
 
@@ -81,12 +88,10 @@ void CommandSoeRead::execute(const StringVector &args)
         throwInvalidUsageException(err);
     }
 
-    strIdn << args[0];
-    strIdn
-        >> resetiosflags(ios::basefield) // guess base from prefix
-        >> ioctl.idn;
-    if (strIdn.fail()) {
-        err << "Invalid IDN '" << args[0] << "'!";
+    try {
+        ioctl.idn = parseIdn(args[0]);
+    } catch (runtime_error &e) {
+        err << "Invalid IDN '" << args[0] << "': " << e.what();
         throwInvalidUsageException(err);
     }
 
diff --git a/tool/CommandSoeRead.h b/tool/CommandSoeRead.h
index c7cff524..31ac9fe6 100644
--- a/tool/CommandSoeRead.h
+++ b/tool/CommandSoeRead.h
@@ -30,14 +30,12 @@
 #ifndef __COMMANDSOEREAD_H__
 #define __COMMANDSOEREAD_H__
 
-#include "Command.h"
-#include "DataTypeHandler.h"
+#include "SoeCommand.h"
 
 /****************************************************************************/
 
 class CommandSoeRead:
-    public Command,
-    public DataTypeHandler
+    public SoeCommand
 {
     public:
         CommandSoeRead();
diff --git a/tool/CommandSoeWrite.cpp b/tool/CommandSoeWrite.cpp
index 1d93f48d..a67345b4 100644
--- a/tool/CommandSoeWrite.cpp
+++ b/tool/CommandSoeWrite.cpp
@@ -37,7 +37,7 @@ using namespace std;
 /*****************************************************************************/
 
 CommandSoeWrite::CommandSoeWrite():
-    Command("soe_write", "Write an SoE IDN to a slave.")
+    SoeCommand("soe_write", "Write an SoE IDN to a slave.")
 {
 }
 
@@ -47,17 +47,23 @@ string CommandSoeWrite::helpString() const
 {
     stringstream str;
 
-    str << getName() << " [OPTIONS] <INDEX> <SUBINDEX> <VALUE>" << endl
+    str << getName() << " [OPTIONS] <IDN> <VALUE>" << endl
         << endl
         << getBriefDescription() << endl
         << endl
         << "This command requires a single slave to be selected." << endl
         << endl
         << "Arguments:" << endl
-        << "  IDN      is the IDN and must be an unsigned" << endl
-        << "           16 bit number." << endl
+        << "  IDN      is the IDN and must be either an unsigned" << endl
+        << "           16 bit number acc. to IEC 61800-7-204:" << endl
+        << "             Bit 15: (0) Standard data, (1) Product data" << endl
+        << "             Bit 14 - 12: Parameter set (0 - 7)" << endl
+        << "             Bit 11 - 0: Data block number" << endl
+        << "           or a string like 'P-0-150'." << endl
         << "  VALUE    is the value to write and is interpreted" << endl
         << "           as the given datatype (see above)." << endl
+		<< endl
+		<< typeInfo()
         << endl
         << "Command-specific options:" << endl
         << "  --alias    -a <alias>" << endl
@@ -85,12 +91,10 @@ void CommandSoeWrite::execute(const StringVector &args)
         throwInvalidUsageException(err);
     }
 
-    strIdn << args[0];
-    strIdn
-        >> resetiosflags(ios::basefield) // guess base from prefix
-        >> ioctl.idn;
-    if (strIdn.fail()) {
-        err << "Invalid IDN '" << args[0] << "'!";
+    try {
+        ioctl.idn = parseIdn(args[0]);
+    } catch (runtime_error &e) {
+        err << "Invalid IDN '" << args[0] << "': " << e.what();
         throwInvalidUsageException(err);
     }
 
diff --git a/tool/CommandSoeWrite.h b/tool/CommandSoeWrite.h
index 3c507b4a..c5cc14f5 100644
--- a/tool/CommandSoeWrite.h
+++ b/tool/CommandSoeWrite.h
@@ -30,14 +30,12 @@
 #ifndef __COMMANDSOEWRITE_H__
 #define __COMMANDSOEWRITE_H__
 
-#include "Command.h"
-#include "DataTypeHandler.h"
+#include "SoeCommand.h"
 
 /****************************************************************************/
 
 class CommandSoeWrite:
-    public Command,
-    public DataTypeHandler
+    public SoeCommand
 {
     public:
         CommandSoeWrite();
diff --git a/tool/CommandUpload.cpp b/tool/CommandUpload.cpp
index 0f960585..7a186f54 100644
--- a/tool/CommandUpload.cpp
+++ b/tool/CommandUpload.cpp
@@ -59,9 +59,7 @@ string CommandUpload::helpString() const
         << "information service or the SDO is not in the dictionary," << endl
         << "the --type option is mandatory."  << endl
         << endl
-        << "These are the valid SDO entry data types:" << endl
-        << "  int8, int16, int32, uint8, uint16, uint32, string," << endl
-        << "  octet_string." << endl
+        << typeInfo()
         << endl
         << "Arguments:" << endl
         << "  INDEX    is the SDO index and must be an unsigned" << endl
diff --git a/tool/DataTypeHandler.cpp b/tool/DataTypeHandler.cpp
index 028c451c..2dfaf838 100644
--- a/tool/DataTypeHandler.cpp
+++ b/tool/DataTypeHandler.cpp
@@ -64,6 +64,20 @@ const DataTypeHandler::DataType *DataTypeHandler::findDataType(
 
 /****************************************************************************/
 
+string DataTypeHandler::typeInfo()
+{
+	stringstream s;
+
+	s
+		<< "These are valid data types to use with" << endl
+		<< "the --type option:" << endl
+		<< "  int8, int16, int32, uint8, uint16, uint32, string," << endl
+		<< "  octet_string." << endl;
+	return s.str();
+}
+
+/****************************************************************************/
+
 const DataTypeHandler::DataType *DataTypeHandler::findDataType(uint16_t code)
 {
     const DataType *d;
diff --git a/tool/DataTypeHandler.h b/tool/DataTypeHandler.h
index 2a0e08a0..90648957 100644
--- a/tool/DataTypeHandler.h
+++ b/tool/DataTypeHandler.h
@@ -51,6 +51,8 @@ class DataTypeHandler
             size_t byteSize;
         };
 
+		static std::string typeInfo();
+
         static const DataType *findDataType(const std::string &);
         static const DataType *findDataType(uint16_t);
         static size_t interpretAsType(const DataType *, const std::string &,
diff --git a/tool/Makefile.am b/tool/Makefile.am
index ba4d7fcd..b1de2434 100644
--- a/tool/Makefile.am
+++ b/tool/Makefile.am
@@ -66,6 +66,7 @@ ethercat_SOURCES = \
 	MasterDevice.cpp \
 	NumberListParser.cpp \
 	SdoCommand.cpp \
+	SoeCommand.cpp \
 	main.cpp \
 	sii_crc.cpp
 
@@ -106,6 +107,7 @@ noinst_HEADERS = \
 	MasterDevice.h \
 	NumberListParser.h \
 	SdoCommand.h \
+	SoeCommand.h \
 	sii_crc.h
 
 if ENABLE_EOE
diff --git a/tool/SoeCommand.cpp b/tool/SoeCommand.cpp
new file mode 100644
index 00000000..70030e20
--- /dev/null
+++ b/tool/SoeCommand.cpp
@@ -0,0 +1,108 @@
+/*****************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006-2009  Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ *  This file is part of the IgH EtherCAT Master.
+ *
+ *  The IgH EtherCAT Master is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License version 2, as
+ *  published by the Free Software Foundation.
+ *
+ *  The IgH EtherCAT Master 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 the IgH EtherCAT Master; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  ---
+ *
+ *  The license mentioned above concerns the source code only. Using the
+ *  EtherCAT technology and brand is only permitted in compliance with the
+ *  industrial property and similar rights of Beckhoff Automation GmbH.
+ *
+ ****************************************************************************/
+
+#include <iomanip>
+using namespace std;
+
+#include "SoeCommand.h"
+
+/*****************************************************************************/
+
+SoeCommand::SoeCommand(const string &name, const string &briefDesc):
+    Command(name, briefDesc)
+{
+}
+
+/*****************************************************************************/
+
+uint16_t SoeCommand::parseIdn(const string &str)
+{
+    uint16_t idn = 0x0000;
+    stringstream s, err;
+
+    if (!str.length()) {
+        err << "Zero-size string not allowed!";
+        throw runtime_error(err.str());
+    }
+
+    if (str[0] == 'S' || str[0] == 'P') {
+        unsigned int num;
+        unsigned char c;
+
+        s << str;
+
+        s >> c;
+        if (c == 'P') {
+            idn |= 0x8000;
+        }
+
+        s >> c;
+        if (s.fail() || c != '-') {
+             err << "'-' expected!";
+             throw runtime_error(err.str());
+        }
+
+        s >> num;
+        if (s.fail() || num > 7) {
+            err << "Invalid parameter set number!";
+            throw runtime_error(err.str());
+        }
+        idn |= num << 12;
+
+        s >> c;
+        if (s.fail() || c != '-') {
+             err << "'-' expected!";
+             throw runtime_error(err.str());
+        }
+
+        s >> num;
+        if (s.fail() || num > 4095) {
+            err << "Invalid data block number!";
+            throw runtime_error(err.str());
+        }
+        idn |= num;
+
+        s.peek();
+        if (!s.eof()) {
+            err << "Additional input!";
+            throw runtime_error(err.str());
+        }
+    } else {
+        s << str;
+        s >> resetiosflags(ios::basefield) >> idn;
+        if (s.fail()) {
+            err << "Invalid number!";
+            throw runtime_error(err.str());
+        }
+    }
+
+    return idn;
+}
+
+/****************************************************************************/
diff --git a/tool/SoeCommand.h b/tool/SoeCommand.h
new file mode 100644
index 00000000..478bec90
--- /dev/null
+++ b/tool/SoeCommand.h
@@ -0,0 +1,51 @@
+/*****************************************************************************
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2006-2009  Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ *  This file is part of the IgH EtherCAT Master.
+ *
+ *  The IgH EtherCAT Master is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License version 2, as
+ *  published by the Free Software Foundation.
+ *
+ *  The IgH EtherCAT Master 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 the IgH EtherCAT Master; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  ---
+ *
+ *  The license mentioned above concerns the source code only. Using the
+ *  EtherCAT technology and brand is only permitted in compliance with the
+ *  industrial property and similar rights of Beckhoff Automation GmbH.
+ *
+ ****************************************************************************/
+
+#ifndef __SOECOMMAND_H__
+#define __SOECOMMAND_H__
+
+#include "Command.h"
+#include "DataTypeHandler.h"
+
+/****************************************************************************/
+
+class SoeCommand:
+    public Command,
+    public DataTypeHandler
+{
+    public:
+        SoeCommand(const string &, const string &);
+
+    protected:
+        static uint16_t parseIdn(const string &);
+};
+
+/****************************************************************************/
+
+#endif
-- 
GitLab