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 #include "Response.h"
26 #include "Checksum.h"
27 #include "Types.h"
28 #include "TransmissionException.h"
29 #include <string.h>
30 #include <iostream>
31 #include <stdio.h>
32 #include <stdexcept>
33 
34 
36  : connected(false)
37 {
38 
39 }
40 
42 {
43 }
44 
45 int AbstractInterface::read(unsigned char* buf, unsigned int len)
46 {
47  int res = readInternal(buf, len);
48 
49  if (log != NULL)
50  {
51  log->logRead(buf, res);
52  }
53 
54  return res;
55 }
56 
57 int AbstractInterface::write(unsigned char* buf, unsigned int len)
58 {
59  if (log != NULL)
60  {
61  log->logWrite(buf, len);
62  }
63 
64  return writeInternal(buf, len);
65 }
66 
67 
68 Response AbstractInterface::submitCmd(unsigned char id, unsigned char* payload, unsigned int len, bool pending)
69 {
70  fireAndForgetCmd(id, payload, len, pending);
71  return receive(pending, id);
72 }
73 
74 void AbstractInterface::fireAndForgetCmd(unsigned char id, unsigned char* payload, unsigned int len, bool pending)
75 {
76 
77  int res;
78 
79  // Check if we're connected
80  if (!connected)
81  {
82  throw TransmissionException("Interface not connected");
83  }
84 
85  // Send command
86  res = send(id, len, payload);
87 
88  if (res < 0)
89  {
90  throw TransmissionException("Message send failed");
91  }
92 }
93 
94 void AbstractInterface::startLogging(std::string file)
95 {
96  log.reset(new BinaryLogger(file));
97 }
98 
100 {
101  if (log != NULL)
102  {
103  log->logText(message);
104  }
105 }
106 
108 {
109  int res;
111  msg_t msg;
112 
113  // Receive response data
114  res = receive(&msg);
115 
116  if (res < 0)
117  {
118  throw TransmissionException("Message receive failed");
119  }
120 
121  status = (status_t) make_short(msg.data[0], msg.data[1]);
122 
123  return Response(res, msg.id, status, msg.data, msg.len);
124 }
125 
126 Response AbstractInterface::receive(bool pending, unsigned char expectedId)
127 {
128  int res;
130  msg_t msg;
131 
132  // Receive response. Repeat if pending.
133  do
134  {
135  // Receive response data
136  res = receive(&msg);
137 
138  if (res < 0)
139  {
140  throw TransmissionException("Message receive failed");
141  }
142 
143  // Check response ID
144  if (msg.id != expectedId)
145  {
146  //std::strstream strStream;
147  //strStream << "Response ID ()" << msg.id << ") does not match submitted command ID (" << id << ")";
148  //throw std::runtime_error(strStream.str());
149  throw TransmissionException(str(boost::format("Response ID (%02X) does not match submitted command ID (%02X)") % (int)msg.id % (int)expectedId));
150  }
151 
152  if (pending)
153  {
154  if (msg.len < 2)
155  {
156  throw TransmissionException("No status code received");
157  }
158 
159  status = (status_t) make_short(msg.data[0], msg.data[1]);
160  }
161  }
162  while (pending && status == E_CMD_PENDING);
163 
164  status = (status_t) make_short(msg.data[0], msg.data[1]);
165 
166  return Response(res, msg.id, status, msg.data, msg.len);
167 }
168 
170 {
171  int res;
172  unsigned char header[3]; // 1 byte command, 2 bytes payload length
173  unsigned short checksum = 0x50f5; // Checksum over preamble (0xaa 0xaa 0xaa)
174  unsigned int sync;
175 
176  logText("read preamble");
177  // Syncing - necessary for compatibility with serial interface
178  sync = 0;
179 
180  while (sync != MSG_PREAMBLE_LEN)
181  {
182  res = read(header, 1);
183 
184  if (res > 0 && header[0] == MSG_PREAMBLE_BYTE)
185  {
186  sync++;
187  }
188  else
189  {
190  sync = 0;
191  }
192  }
193 
194  // Read header
195  res = read(header, 3);
196 
197  if (res < 3)
198  {
199  throw TransmissionException(str(boost::format("Failed to receive header data (%d bytes read)") % res));
200  }
201 
202  // Calculate checksum over header
203  checksum = Checksum::Update_crc16(header, 3, checksum);
204 
205  // Get message id of received
206  msg->id = header[0];
207 
208  // Get payload size of received message
209  msg->len = make_short(header[1], header[2]);
210 
211  // Allocate space for payload and checksum
212  //msg->data.resize( msg->len + 2u );
213  //if ( !msg->data ) return -1;
214  //std::shared_ptr<unsigned char[]> data(new unsigned char[ msg->len + 2u ]);
215 
216  unsigned char* data = new unsigned char[ msg->len + 2u ];
217 
218 
219  // Read payload and checksum
220  /*int maxReads = 10;
221  int remaining = msg->len + 2;
222  int dataOffset = 0;
223  while ( maxReads > 0 && remaining > 0)
224  {
225  int read = this->read( data + dataOffset, remaining );
226  dataOffset += read;
227  remaining -= read;
228  maxReads--;
229  if (remaining > 0) {
230  //fprintf( stderr, "Partial message received, waiting 100µs\n" );
231  usleep(100);
232  }
233  }
234  if (remaining > 0)
235  {
236  throw TransmissionException(str(boost::format("Not enough data (%d, expected %d), Command = %02X") % res % (msg->len + 2) % msg->id));
237  }*/
238 
239  // Read payload and checksum:
240  // payload: msg->len
241  // checksum: 2 byte
242  int read = this->read(data, msg->len + 2);
243 
244  if (read != (int)msg->len + 2)
245  {
246  delete[] data;
247  throw TransmissionException(str(boost::format("Not enough data (%d, expected %d), Command = %02X") % res % (msg->len + 2) % msg->id));
248  }
249 
250  /*
251  res = interface->read( msg->data, msg->len + 2 );
252  if ( res < (int) (msg->len + 2) )
253  {
254  fprintf( stderr, "Not enough data (%d, expected %d)\n", res, msg->len + 2 );
255  fprintf( stderr, "Command = %X\n", msg->id );
256  return -1;
257  }*/
258 
259  // Check checksum
260  checksum = Checksum::Update_crc16(data, msg->len + 2, checksum);
261 
262  if (checksum != 0)
263  {
264  delete[] data;
265  logText("CHECKSUM ERROR");
266  throw ChecksumErrorException("Checksum error");
267  }
268 
269  msg->data = std::vector<unsigned char>(data, data + msg->len + 2);
270  delete[] data;
271  logText("receive done.");
272  return msg->len + 8;
273 }
274 
275 int AbstractInterface::send(unsigned char id, unsigned int len, unsigned char* data)
276 {
277  unsigned char header[MSG_PREAMBLE_LEN + 3];
278  unsigned short crc;
279  int i, res;
280 
281  logText("write preamble");
282 
283  // Preamble
284  for (i = 0; i < MSG_PREAMBLE_LEN; i++)
285  {
286  header[i] = MSG_PREAMBLE_BYTE;
287  }
288 
289  // Command ID
290  header[MSG_PREAMBLE_LEN] = id;
291 
292  // Length
293  header[MSG_PREAMBLE_LEN + 1] = lo(len);
294  header[MSG_PREAMBLE_LEN + 2] = hi(len);
295 
296  // Checksum
297  crc = Checksum::Crc16(header, 6);
298  crc = Checksum::Update_crc16(data, len, crc);
299 
300 
301  unsigned char* buf = new unsigned char[ 6 + len + 2 ];
302  memcpy(buf, header, 6);
303  memcpy(buf + 6, data, len);
304  memcpy(buf + 6 + len, (unsigned char*) &crc, 2);
305 
306  res = write(buf, 6 + len + 2);
307 
308  if (res < 6 + (int)len + 2)
309  {
310  delete[] buf;
311  close();
312  throw TransmissionException("Failed to submit message checksum");
313  //cerr << "Failed to submit message checksum" << endl;
314  }
315 
316  delete[] buf;
317 
318  logText("send done.");
319 
320  return len + 8;
321 }
322 
323 
324 
325 
326 std::ostream& operator<<(std::ostream& strm, const AbstractInterface& a)
327 {
328  return strm << a.toString();
329 }
AbstractInterface::read
int read(unsigned char *buf, unsigned int len)
Definition: AbstractInterface.cpp:45
str
std::string str(const T &t)
Definition: UserAssistedSegmenterGuiWidgetController.cpp:42
MSG_PREAMBLE_LEN
#define MSG_PREAMBLE_LEN
Definition: AbstractInterface.h:33
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:57
status_t
status_t
Definition: Types.h:36
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:43
AbstractInterface::receiveWithoutChecks
Response receiveWithoutChecks()
Definition: AbstractInterface.cpp:107
AbstractInterface::AbstractInterface
AbstractInterface()
Definition: AbstractInterface.cpp:35
AbstractInterface::submitCmd
Response submitCmd(unsigned char id, unsigned char *payload, unsigned int len, bool pending)
Definition: AbstractInterface.cpp:68
AbstractInterface::send
int send(unsigned char id, unsigned int len, unsigned char *data)
Definition: AbstractInterface.cpp:275
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:115
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:86
armarx::status
status
Definition: FiniteStateMachine.h:259
AbstractInterface::fireAndForgetCmd
void fireAndForgetCmd(unsigned char id, unsigned char *payload, unsigned int len, bool pending)
Definition: AbstractInterface.cpp:74
armarx::ctrlutil::a
double a(double t, double a0, double j)
Definition: CtrlUtil.h:45
AbstractInterface.h
AbstractInterface
Definition: AbstractInterface.h:49
data
uint8_t data[1]
Definition: EtherCATFrame.h:68
AbstractInterface::logText
void logText(std::string message)
Definition: AbstractInterface.cpp:99
make_short
#define make_short(lowbyte, highbyte)
Definition: AbstractInterface.h:36
AbstractInterface::startLogging
void startLogging(std::string file)
Definition: AbstractInterface.cpp:94
MSG_PREAMBLE_BYTE
#define MSG_PREAMBLE_BYTE
Definition: AbstractInterface.h:32
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:34
AbstractInterface::connected
bool connected
Definition: AbstractInterface.h:77
hi
#define hi(x)
Definition: AbstractInterface.h:42
msg_t
Definition: Types.h:28
TransmissionException
Definition: TransmissionException.h:28
operator<<
std::ostream & operator<<(std::ostream &strm, const AbstractInterface &a)
Definition: AbstractInterface.cpp:326
BinaryLogger
Definition: BinaryLogger.h:28
AbstractInterface::receive
int receive(msg_t *msg)
Definition: AbstractInterface.cpp:169
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:64
Types.h