1 /***************************************************************************** |
|
2 * |
|
3 * $Id$ |
|
4 * |
|
5 * Copyright (C) 2006-2009 Florian Pose, Ingenieurgemeinschaft IgH |
|
6 * |
|
7 * This file is part of the IgH EtherCAT Master. |
|
8 * |
|
9 * The IgH EtherCAT Master is free software; you can redistribute it and/or |
|
10 * modify it under the terms of the GNU General Public License version 2, as |
|
11 * published by the Free Software Foundation. |
|
12 * |
|
13 * The IgH EtherCAT Master is distributed in the hope that it will be useful, |
|
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
|
16 * Public License for more details. |
|
17 * |
|
18 * You should have received a copy of the GNU General Public License along |
|
19 * with the IgH EtherCAT Master; if not, write to the Free Software |
|
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
|
21 * |
|
22 * --- |
|
23 * |
|
24 * The license mentioned above concerns the source code only. Using the |
|
25 * EtherCAT technology and brand is only permitted in compliance with the |
|
26 * industrial property and similar rights of Beckhoff Automation GmbH. |
|
27 * |
|
28 ****************************************************************************/ |
|
29 |
|
30 #include <iostream> |
|
31 #include <iomanip> |
|
32 using namespace std; |
|
33 |
|
34 #include "CommandPhyRead.h" |
|
35 |
|
36 /*****************************************************************************/ |
|
37 |
|
38 CommandPhyRead::CommandPhyRead(): |
|
39 Command("phy_read", "Output a slave's physical memory contents.") |
|
40 { |
|
41 } |
|
42 |
|
43 /*****************************************************************************/ |
|
44 |
|
45 string CommandPhyRead::helpString() const |
|
46 { |
|
47 stringstream str; |
|
48 |
|
49 str << getName() << " [OPTIONS] <OFFSET> [LENGTH]" << endl |
|
50 << endl |
|
51 << getBriefDescription() << endl |
|
52 << endl |
|
53 << "This command requires a single slave to be selected." << endl |
|
54 << endl |
|
55 << "Arguments:" << endl |
|
56 << " OFFSET is the physical memory address. Must" << endl |
|
57 << " be an unsigned 16 bit number." << endl |
|
58 << " LENGTH is the number of bytes to read and must also be" << endl |
|
59 << " an unsigned 16 bit number. OFFSET plus LENGTH" << endl |
|
60 << " may not exceed 64k. The length is ignored (and" << endl |
|
61 << " can be omitted), if a selected data type" << endl |
|
62 << " implies a length." << endl |
|
63 << endl |
|
64 << "These are the valid data types:" << endl |
|
65 << " int8, int16, int32, int64, uint8, uint16, uint32," << endl |
|
66 << " uint64, string, octet_string, raw." << endl |
|
67 << endl |
|
68 << "Command-specific options:" << endl |
|
69 << " --alias -a <alias>" << endl |
|
70 << " --position -p <pos> Slave selection. See the help of" << endl |
|
71 << " the 'slaves' command." << endl |
|
72 << " --type -t <type> Data type (see above)." << endl |
|
73 << endl |
|
74 << numericInfo(); |
|
75 |
|
76 return str.str(); |
|
77 } |
|
78 |
|
79 /****************************************************************************/ |
|
80 |
|
81 void CommandPhyRead::execute(MasterDevice &m, const StringVector &args) |
|
82 { |
|
83 SlaveList slaves; |
|
84 ec_ioctl_slave_phy_t data; |
|
85 stringstream strOffset, err; |
|
86 const DataType *dataType = NULL; |
|
87 |
|
88 if (args.size() < 1 || args.size() > 2) { |
|
89 err << "'" << getName() << "' takes one or two arguments!"; |
|
90 throwInvalidUsageException(err); |
|
91 } |
|
92 |
|
93 strOffset << args[0]; |
|
94 strOffset |
|
95 >> resetiosflags(ios::basefield) // guess base from prefix |
|
96 >> data.offset; |
|
97 if (strOffset.fail()) { |
|
98 err << "Invalid offset '" << args[0] << "'!"; |
|
99 throwInvalidUsageException(err); |
|
100 } |
|
101 |
|
102 if (args.size() > 1) { |
|
103 stringstream strLength; |
|
104 strLength << args[1]; |
|
105 strLength |
|
106 >> resetiosflags(ios::basefield) // guess base from prefix |
|
107 >> data.length; |
|
108 if (strLength.fail()) { |
|
109 err << "Invalid length '" << args[1] << "'!"; |
|
110 throwInvalidUsageException(err); |
|
111 } |
|
112 |
|
113 if (!data.length) { |
|
114 err << "Length may not be zero!"; |
|
115 throwInvalidUsageException(err); |
|
116 } |
|
117 } else { // no length argument given |
|
118 data.length = 0; |
|
119 } |
|
120 |
|
121 if (!getDataType().empty()) { |
|
122 if (!(dataType = findDataType(getDataType()))) { |
|
123 err << "Invalid data type '" << getDataType() << "'!"; |
|
124 throwInvalidUsageException(err); |
|
125 } |
|
126 |
|
127 if (dataType->byteSize) { |
|
128 // override length argument |
|
129 data.length = dataType->byteSize; |
|
130 } |
|
131 } |
|
132 |
|
133 if (!data.length) { |
|
134 err << "The length argument is mandatory, if no datatype is " << endl |
|
135 << "specified, or the datatype does not imply a length!"; |
|
136 throwInvalidUsageException(err); |
|
137 } |
|
138 |
|
139 if ((uint32_t) data.offset + data.length > 0xffff) { |
|
140 err << "Offset and length exceeding 64k!"; |
|
141 throwInvalidUsageException(err); |
|
142 } |
|
143 |
|
144 m.open(MasterDevice::Read); |
|
145 slaves = selectedSlaves(m); |
|
146 |
|
147 if (slaves.size() != 1) { |
|
148 throwSingleSlaveRequired(slaves.size()); |
|
149 } |
|
150 data.slave_position = slaves.front().position; |
|
151 |
|
152 data.data = new uint8_t[data.length]; |
|
153 |
|
154 try { |
|
155 m.readPhy(&data); |
|
156 } catch (MasterDeviceException &e) { |
|
157 delete [] data.data; |
|
158 throw e; |
|
159 } |
|
160 |
|
161 cout << setfill('0'); |
|
162 if (!dataType || |
|
163 dataType->name == "string" || |
|
164 dataType->name == "octet_string") { |
|
165 uint16_t i; |
|
166 for (i = 0; i < data.length; i++) { |
|
167 cout << data.data[i]; |
|
168 } |
|
169 } else if (dataType->name == "int8") { |
|
170 int sval = *(int8_t *) data.data; |
|
171 cout << sval << " 0x" << hex << setw(2) << sval << endl; |
|
172 } else if (dataType->name == "int16") { |
|
173 int sval = le16_to_cpup(data.data); |
|
174 cout << sval << " 0x" << hex << setw(4) << sval << endl; |
|
175 } else if (dataType->name == "int32") { |
|
176 int sval = le32_to_cpup(data.data); |
|
177 cout << sval << " 0x" << hex << setw(8) << sval << endl; |
|
178 } else if (dataType->name == "int64") { |
|
179 long long int sval = le64_to_cpup(data.data); |
|
180 cout << sval << " 0x" << hex << setw(16) << sval << endl; |
|
181 } else if (dataType->name == "uint8") { |
|
182 unsigned int uval = (unsigned int) *(uint8_t *) data.data; |
|
183 cout << uval << " 0x" << hex << setw(2) << uval << endl; |
|
184 } else if (dataType->name == "uint16") { |
|
185 unsigned int uval = le16_to_cpup(data.data); |
|
186 cout << uval << " 0x" << hex << setw(4) << uval << endl; |
|
187 } else if (dataType->name == "uint32") { |
|
188 unsigned int uval = le32_to_cpup(data.data); |
|
189 cout << uval << " 0x" << hex << setw(8) << uval << endl; |
|
190 } else if (dataType->name == "uint64") { |
|
191 long long unsigned int uval = le32_to_cpup(data.data); |
|
192 cout << uval << " 0x" << hex << setw(8) << uval << endl; |
|
193 } else { |
|
194 uint8_t *d = data.data; |
|
195 unsigned int size = data.length; |
|
196 |
|
197 cout << hex << setfill('0'); |
|
198 while (size--) { |
|
199 cout << "0x" << setw(2) << (unsigned int) *d++; |
|
200 if (size) |
|
201 cout << " "; |
|
202 } |
|
203 cout << endl; |
|
204 } |
|
205 |
|
206 delete [] data.data; |
|
207 } |
|
208 |
|
209 /****************************************************************************/ |
|
210 |
|
211 const CommandPhyRead::DataType *CommandPhyRead::findDataType( |
|
212 const string &str |
|
213 ) |
|
214 { |
|
215 const DataType *d; |
|
216 |
|
217 for (d = dataTypes; d->name; d++) |
|
218 if (str == d->name) |
|
219 return d; |
|
220 |
|
221 return NULL; |
|
222 } |
|
223 |
|
224 /****************************************************************************/ |
|
225 |
|
226 const CommandPhyRead::DataType CommandPhyRead::dataTypes[] = { |
|
227 {"int8", 1}, |
|
228 {"int16", 2}, |
|
229 {"int32", 4}, |
|
230 {"int64", 8}, |
|
231 {"uint8", 1}, |
|
232 {"uint16", 2}, |
|
233 {"uint32", 4}, |
|
234 {"uint64", 8}, |
|
235 {"string", 0}, |
|
236 {"octet_string", 0}, |
|
237 {"raw", 0}, |
|
238 {} |
|
239 }; |
|
240 |
|
241 /*****************************************************************************/ |
|