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"
34 #include "TransmissionException.h"
35 #include "Types.h"
36 
38 {
39 }
40 
42 {
43 }
44 
45 int
46 AbstractInterface::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 
58 int
59 AbstractInterface::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 
79 void
81  unsigned char* payload,
82  unsigned int len,
83  bool pending)
84 {
85 
86  int res;
87 
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 
103 void
105 {
106  log.reset(new BinaryLogger(file));
107 }
108 
109 void
111 {
112  if (log != NULL)
113  {
114  log->logText(message);
115  }
116 }
117 
118 Response
120 {
121  int res;
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 
138 Response
139 AbstractInterface::receive(bool pending, unsigned char expectedId)
140 {
141  int res;
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());
162  throw TransmissionException(
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 
183 int
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  {
214  throw TransmissionException(
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;
263  throw TransmissionException(
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 
293 int
294 AbstractInterface::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 
342 std::ostream&
343 operator<<(std::ostream& strm, const AbstractInterface& a)
344 {
345  return strm << a.toString();
346 }
AbstractInterface::read
int read(unsigned char *buf, unsigned int len)
Definition: AbstractInterface.cpp:46
str
std::string str(const T &t)
Definition: UserAssistedSegmenterGuiWidgetController.cpp:43
MSG_PREAMBLE_LEN
#define MSG_PREAMBLE_LEN
Definition: AbstractInterface.h:34
msg_t::len
unsigned int len
Definition: Types.h:31
AbstractInterface::~AbstractInterface
virtual ~AbstractInterface()
Definition: AbstractInterface.cpp:41
string.h
Response.h
TransmissionException.h
AbstractInterface::write
int write(unsigned char *buf, unsigned int len)
Definition: AbstractInterface.cpp:59
status_t
status_t
Definition: Types.h:35
ChecksumErrorException
Definition: TransmissionException.h:36
message
message(STATUS "Boost-Library-Dir: " "${Boost_LIBRARY_DIRS}") message(STATUS "Boost-LIBRARIES
Definition: CMakeLists.txt:8
lo
#define lo(x)
Definition: AbstractInterface.h:47
AbstractInterface::receiveWithoutChecks
Response receiveWithoutChecks()
Definition: AbstractInterface.cpp:119
AbstractInterface::AbstractInterface
AbstractInterface()
Definition: AbstractInterface.cpp:37
AbstractInterface::submitCmd
Response submitCmd(unsigned char id, unsigned char *payload, unsigned int len, bool pending)
Definition: AbstractInterface.cpp:70
AbstractInterface::send
int send(unsigned char id, unsigned int len, unsigned char *data)
Definition: AbstractInterface.cpp:294
Checksum::Crc16
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
Checksum::Update_crc16
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
armarx::status
status
Definition: FiniteStateMachine.h:244
AbstractInterface::fireAndForgetCmd
void fireAndForgetCmd(unsigned char id, unsigned char *payload, unsigned int len, bool pending)
Definition: AbstractInterface.cpp:80
armarx::ctrlutil::a
double a(double t, double a0, double j)
Definition: CtrlUtil.h:45
AbstractInterface.h
AbstractInterface
Definition: AbstractInterface.h:52
data
uint8_t data[1]
Definition: EtherCATFrame.h:68
AbstractInterface::logText
void logText(std::string message)
Definition: AbstractInterface.cpp:110
make_short
#define make_short(lowbyte, highbyte)
Definition: AbstractInterface.h:37
AbstractInterface::startLogging
void startLogging(std::string file)
Definition: AbstractInterface.cpp:104
MSG_PREAMBLE_BYTE
#define MSG_PREAMBLE_BYTE
Definition: AbstractInterface.h:33
msg_t::id
unsigned char id
Definition: Types.h:30
Checksum.h
AbstractInterface::writeInternal
virtual int writeInternal(unsigned char *buf, unsigned int len)=0
AbstractInterface::readInternal
virtual int readInternal(unsigned char *buf, unsigned int len)=0
Response
Definition: Response.h:36
AbstractInterface::connected
bool connected
Definition: AbstractInterface.h:81
hi
#define hi(x)
Definition: AbstractInterface.h:46
msg_t
Definition: Types.h:28
TransmissionException
Definition: TransmissionException.h:28
operator<<
std::ostream & operator<<(std::ostream &strm, const AbstractInterface &a)
Definition: AbstractInterface.cpp:343
BinaryLogger
Definition: BinaryLogger.h:28
AbstractInterface::receive
int receive(msg_t *msg)
Definition: AbstractInterface.cpp:184
AbstractInterface::close
virtual void close()=0
msg_t::data
std::vector< unsigned char > data
Definition: Types.h:32
E_CMD_PENDING
@ E_CMD_PENDING
Definition: Types.h:63
Types.h