AbstractInterface.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5 *
6 * ArmarX is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ArmarX is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * @package
19 * @author
20 * @date
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
24#include "AbstractInterface.h"
25
26#include <stdio.h>
27#include <string.h>
28
29#include <iostream>
30#include <stdexcept>
31
32#include "Checksum.h"
33#include "Response.h"
35#include "Types.h"
36
40
44
45int
46AbstractInterface::read(unsigned char* buf, unsigned int len)
47{
48 int res = readInternal(buf, len);
49
50 if (log != NULL)
51 {
52 log->logRead(buf, res);
53 }
54
55 return res;
56}
57
58int
59AbstractInterface::write(unsigned char* buf, unsigned int len)
60{
61 if (log != NULL)
62 {
63 log->logWrite(buf, len);
64 }
65
66 return writeInternal(buf, len);
67}
68
71 unsigned char* payload,
72 unsigned int len,
73 bool pending)
74{
75 fireAndForgetCmd(id, payload, len, pending);
76 return receive(pending, id);
77}
78
79void
81 unsigned char* payload,
82 unsigned int len,
83 bool pending)
84{
85
86 int res;
88 // Check if we're connected
89 if (!connected)
90 {
91 throw TransmissionException("Interface not connected");
92 }
93
94 // Send command
95 res = send(id, len, payload);
96
97 if (res < 0)
98 {
99 throw TransmissionException("Message send failed");
100 }
101}
102
103void
105{
106 log.reset(new BinaryLogger(file));
107}
108
109void
110AbstractInterface::logText(std::string message)
111{
112 if (log != NULL)
113 {
114 log->logText(message);
115 }
116}
117
120{
121 int res;
122 status_t status;
123 msg_t msg;
124
125 // Receive response data
126 res = receive(&msg);
127
128 if (res < 0)
129 {
130 throw TransmissionException("Message receive failed");
131 }
132
133 status = (status_t)make_short(msg.data[0], msg.data[1]);
134
135 return Response(res, msg.id, status, msg.data, msg.len);
136}
137
139AbstractInterface::receive(bool pending, unsigned char expectedId)
140{
141 int res;
142 status_t status;
143 msg_t msg;
144
145 // Receive response. Repeat if pending.
146 do
147 {
148 // Receive response data
149 res = receive(&msg);
150
151 if (res < 0)
152 {
153 throw TransmissionException("Message receive failed");
154 }
155
156 // Check response ID
157 if (msg.id != expectedId)
158 {
159 //std::strstream strStream;
160 //strStream << "Response ID ()" << msg.id << ") does not match submitted command ID (" << id << ")";
161 //throw std::runtime_error(strStream.str());
163 str(boost::format("Response ID (%02X) does not match submitted command ID (%02X)") %
164 (int)msg.id % (int)expectedId));
165 }
166
167 if (pending)
168 {
169 if (msg.len < 2)
170 {
171 throw TransmissionException("No status code received");
172 }
173
174 status = (status_t)make_short(msg.data[0], msg.data[1]);
175 }
176 } while (pending && status == E_CMD_PENDING);
177
178 status = (status_t)make_short(msg.data[0], msg.data[1]);
179
180 return Response(res, msg.id, status, msg.data, msg.len);
181}
182
183int
185{
186 int res;
187 unsigned char header[3]; // 1 byte command, 2 bytes payload length
188 unsigned short checksum = 0x50f5; // Checksum over preamble (0xaa 0xaa 0xaa)
189 unsigned int sync;
190
191 logText("read preamble");
192 // Syncing - necessary for compatibility with serial interface
193 sync = 0;
194
195 while (sync != MSG_PREAMBLE_LEN)
196 {
197 res = read(header, 1);
198
199 if (res > 0 && header[0] == MSG_PREAMBLE_BYTE)
200 {
201 sync++;
202 }
203 else
204 {
205 sync = 0;
206 }
207 }
208
209 // Read header
210 res = read(header, 3);
211
212 if (res < 3)
213 {
215 str(boost::format("Failed to receive header data (%d bytes read)") % res));
216 }
217
218 // Calculate checksum over header
219 checksum = Checksum::Update_crc16(header, 3, checksum);
220
221 // Get message id of received
222 msg->id = header[0];
223
224 // Get payload size of received message
225 msg->len = make_short(header[1], header[2]);
226
227 // Allocate space for payload and checksum
228 //msg->data.resize( msg->len + 2u );
229 //if ( !msg->data ) return -1;
230 //std::shared_ptr<unsigned char[]> data(new unsigned char[ msg->len + 2u ]);
231
232 unsigned char* data = new unsigned char[msg->len + 2u];
233
234
235 // Read payload and checksum
236 /*int maxReads = 10;
237 int remaining = msg->len + 2;
238 int dataOffset = 0;
239 while ( maxReads > 0 && remaining > 0)
240 {
241 int read = this->read( data + dataOffset, remaining );
242 dataOffset += read;
243 remaining -= read;
244 maxReads--;
245 if (remaining > 0) {
246 //fprintf( stderr, "Partial message received, waiting 100µs\n" );
247 usleep(100);
248 }
249 }
250 if (remaining > 0)
251 {
252 throw TransmissionException(str(boost::format("Not enough data (%d, expected %d), Command = %02X") % res % (msg->len + 2) % msg->id));
253 }*/
254
255 // Read payload and checksum:
256 // payload: msg->len
257 // checksum: 2 byte
258 int read = this->read(data, msg->len + 2);
259
260 if (read != (int)msg->len + 2)
261 {
262 delete[] data;
264 str(boost::format("Not enough data (%d, expected %d), Command = %02X") % res %
265 (msg->len + 2) % msg->id));
266 }
267
268 /*
269 res = interface->read( msg->data, msg->len + 2 );
270 if ( res < (int) (msg->len + 2) )
271 {
272 fprintf( stderr, "Not enough data (%d, expected %d)\n", res, msg->len + 2 );
273 fprintf( stderr, "Command = %X\n", msg->id );
274 return -1;
275 }*/
276
277 // Check checksum
278 checksum = Checksum::Update_crc16(data, msg->len + 2, checksum);
279
280 if (checksum != 0)
281 {
282 delete[] data;
283 logText("CHECKSUM ERROR");
284 throw ChecksumErrorException("Checksum error");
285 }
286
287 msg->data = std::vector<unsigned char>(data, data + msg->len + 2);
288 delete[] data;
289 logText("receive done.");
290 return msg->len + 8;
291}
292
293int
294AbstractInterface::send(unsigned char id, unsigned int len, unsigned char* data)
295{
296 unsigned char header[MSG_PREAMBLE_LEN + 3];
297 unsigned short crc;
298 int i, res;
299
300 logText("write preamble");
301
302 // Preamble
303 for (i = 0; i < MSG_PREAMBLE_LEN; i++)
304 {
305 header[i] = MSG_PREAMBLE_BYTE;
306 }
307
308 // Command ID
309 header[MSG_PREAMBLE_LEN] = id;
310
311 // Length
312 header[MSG_PREAMBLE_LEN + 1] = lo(len);
313 header[MSG_PREAMBLE_LEN + 2] = hi(len);
314
315 // Checksum
316 crc = Checksum::Crc16(header, 6);
317 crc = Checksum::Update_crc16(data, len, crc);
318
319
320 unsigned char* buf = new unsigned char[6 + len + 2];
321 memcpy(buf, header, 6);
322 memcpy(buf + 6, data, len);
323 memcpy(buf + 6 + len, (unsigned char*)&crc, 2);
324
325 res = write(buf, 6 + len + 2);
326
327 if (res < 6 + (int)len + 2)
328 {
329 delete[] buf;
330 close();
331 throw TransmissionException("Failed to submit message checksum");
332 //cerr << "Failed to submit message checksum" << endl;
333 }
334
335 delete[] buf;
336
337 logText("send done.");
338
339 return len + 8;
340}
341
342std::ostream&
343operator<<(std::ostream& strm, const AbstractInterface& a)
344{
345 return strm << a.toString();
346}
std::ostream & operator<<(std::ostream &strm, const AbstractInterface &a)
#define make_short(lowbyte, highbyte)
#define MSG_PREAMBLE_BYTE
#define MSG_PREAMBLE_LEN
#define lo(x)
#define hi(x)
uint8_t data[1]
status_t
Definition Types.h:36
@ E_CMD_PENDING
Definition Types.h:63
std::string str(const T &t)
void startLogging(std::string file)
int receive(msg_t *msg)
int write(unsigned char *buf, unsigned int len)
virtual int readInternal(unsigned char *buf, unsigned int len)=0
Response submitCmd(unsigned char id, unsigned char *payload, unsigned int len, bool pending)
int read(unsigned char *buf, unsigned int len)
int send(unsigned char id, unsigned int len, unsigned char *data)
void logText(std::string message)
void fireAndForgetCmd(unsigned char id, unsigned char *payload, unsigned int len, bool pending)
virtual int writeInternal(unsigned char *buf, unsigned int len)=0
virtual void close()=0
static unsigned short Update_crc16(unsigned char *data, unsigned int size, unsigned short crc)
Calculates the CRC16 checksum of an array by using a table.
Definition Checksum.cpp:75
static unsigned short Crc16(unsigned char *data, unsigned int size)
Calculates the CRC16 checksum of an array by using a table.
Definition Checksum.cpp:104
Definition Types.h:29
unsigned char id
Definition Types.h:30
unsigned int len
Definition Types.h:31
std::vector< unsigned char > data
Definition Types.h:32