B15F
Board 15 Famulus Edition
usart.cpp
1 #include "usart.h"
2 
3 void USART::openDevice(std::string device)
4 {
5  file_desc = open(device.c_str(), O_RDWR | O_NOCTTY | O_NDELAY /* | O_NONBLOCK*/);
6  if(file_desc <= 0)
7  throw USARTException("Fehler beim Öffnen des Gerätes");
8 
9  struct termios options;
10  int code = tcgetattr(file_desc, &options);
11  if(code)
12  throw USARTException("Fehler beim Lesen der Geräteparameter");
13 
14  options.c_cflag = CS8 | CLOCAL | CREAD;
15  options.c_iflag = IGNPAR;
16  options.c_oflag = 0;
17  options.c_lflag = 0;
18  options.c_cc[VMIN] = 0; // #bytes read returns at least
19  options.c_cc[VTIME] = timeout;
20  code = cfsetspeed(&options, baudrate);
21  if(code)
22  throw USARTException("Fehler beim Setzen der Baudrate");
23 
24  code = tcsetattr(file_desc, TCSANOW, &options);
25  if(code)
26  throw USARTException("Fehler beim Setzen der Geräteparameter");
27 
30 }
31 
33 {
34  int code = close(file_desc);
35  if(code)
36  throw USARTException("Fehler beim Schließen des Gerätes");
37 }
38 
40 {
41  int code = tcflush(file_desc, TCIFLUSH);
42  if(code)
43  throw USARTException("Fehler beim Leeren des Eingangspuffers");
44 }
45 
47 {
48  int code = tcflush(file_desc, TCOFLUSH);
49  if(code)
50  throw USARTException("Fehler beim Leeren des Ausgangspuffers");
51 }
52 
54 {
55  int code = tcdrain(file_desc);
56  if(code)
57  throw USARTException("Fehler beim Versenden des Ausgangspuffers");
58 }
59 
61 {
62  double pz = 1e2 * n_blocks_failed / n_blocks_total;
63  pz = std::round(pz * 1e2) / 1e2;
64  std::cout << "blocks total: " << n_blocks_total << " ok: " << (n_blocks_total - n_blocks_failed) << " failed: " << n_blocks_failed << " (" << pz << "%)" << std::endl;
65 }
66 
67 void USART::writeByte(uint8_t b)
68 {
69  int sent = write(file_desc, &b, 1);
70  if(sent != 1)
71  {
72  std::cout << "WARNUNG: Fehler beim Senden (" << sent << "): writeByte(), wiederhole..." << std::endl;
73  usleep(100000);
74  sent = write(file_desc, &b, 1);
75  if(sent != 1)
76  throw USARTException("Fehler beim Senden: writeByte()");
77  }
78 
79 }
80 
81 void USART::writeInt(uint16_t d)
82 {
83  int sent = write(file_desc, reinterpret_cast<char*>(&d), 2);
84  if(sent != 2)
85  throw USARTException("Fehler beim Senden: writeInt()");
86 }
87 
88 void USART::writeU32(uint32_t w)
89 {
90  int sent = write(file_desc, reinterpret_cast<char*>(&w), 4);
91  if(sent != 4)
92  throw USARTException("Fehler beim Senden: writeU32()");
93 }
94 
95 int USART::read_timeout(uint8_t* buffer, uint16_t offset, uint8_t len, uint32_t timeout)
96 {
97  uint32_t elapsed = 0;
98  int n_read = -1;
99  auto start = std::chrono::steady_clock::now();
100  auto end = start;
101  while(elapsed < timeout)
102  {
103  n_read = read(file_desc, buffer + offset, len);
104  if (n_read == len)
105  return n_read;
106 
107  end = std::chrono::steady_clock::now();
108  elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
109  }
110 
111  return 0;
112 }
113 
114 int USART::write_timeout(uint8_t* buffer, uint16_t offset, uint8_t len, uint32_t timeout)
115 {
116  uint32_t elapsed = 0;
117  int n_sent = -1;
118  auto start = std::chrono::steady_clock::now();
119  auto end = start;
120  while(elapsed < timeout)
121  {
122  n_sent = write(file_desc, buffer + offset, len);
124  if (n_sent == len)
125  return n_sent;
126 
127  end = std::chrono::steady_clock::now();
128  elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
129  }
130 
131  return n_sent;
132 }
133 
134 void USART::writeBlock(uint8_t* buffer, uint16_t offset, uint8_t len)
135 {
136  uint8_t crc;
137  uint8_t aw;
138  const uint16_t us_per_bit = (1000000 / baudrate) * 16;
139  const uint16_t n_total = len + 3;
140 
141  n_blocks_total++;
142  bool failed = false;
143 
144  do
145  {
146  // calc crc
147  crc = 0;
148  for(uint8_t i = 0; i < len; i++)
149  {
150  crc ^= buffer[i];
151  for (uint8_t k = 0; k < 8; k++)
152  {
153  if (crc & 1)
154  crc ^= CRC7_POLY;
155  crc >>= 1;
156  }
157  }
158 
159  // construct block
160  block_buffer[0] = len;
161  std::memcpy(&block_buffer[1], buffer + offset, len);
162  block_buffer[len + 1] = crc;
163  block_buffer[len + 2] = BLOCK_END;
164 
165  // send block
168  int n_sent = write_timeout(&block_buffer[0], 0, len + 3, us_per_bit * n_total);
169  if(n_sent != n_total)
170  throw std::runtime_error("fatal (send): " + std::to_string(n_sent));
171 
172  /*for(uint8_t i = 0; i < len + 3; i++)
173  {
174  write_timeout(&block_buffer[i], 0, 1, us_per_bit * n_total);
175  //tcdrain(file_desc);
176  //usleep(1000);
177  }*/
178 
179  // flush output data
180  tcdrain(file_desc);
181 
182  //usleep(us_per_bit * n_total * 10);
183 
184  // check response
185  int n_read = read_timeout(&aw, 0, 1, us_per_bit * n_blocks_total * 10);
186  for(uint16_t i = 0; i < 255 && n_read != 1; i++)
187  {
188  writeByte(0x80); // Stoppzeichen für Block
189  if(tcdrain(file_desc))
190  {
191  std::cout << "drain failed" << std::endl;
192  }
193  std::cout << "WARNING: read error (" << n_read << "), retry #" << (int) i << std::endl;
194  usleep(us_per_bit*100);
195  n_read = read_timeout(&aw, 0, 1, us_per_bit);
196  }
197 
198  if(n_read != 1)
199  throw std::runtime_error("fatal: " + std::to_string(n_read));
200 
201  //clearInputBuffer();
202 
203  if(aw != 0xFF)
204  {
205  if(!failed)
206  n_blocks_failed++;
207  failed = true;
208  std::cout << "block failed, retry" << std::endl;
209  }
210  }
211  while(aw != 0xFF);
212 
213  //std::cout << "OK" << std::endl;
214 }
215 
216 uint8_t USART::readByte(void)
217 {
218  char b;
219  auto start = std::chrono::steady_clock::now();
220  auto end = start;
221  uint16_t elapsed = 0;
222  while(elapsed < timeout * 100)
223  {
224  int code = read(file_desc, &b, 1);
225  if (code > 0)
226  return static_cast<uint8_t>(b);
227 
228  end = std::chrono::steady_clock::now();
229  elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
230  }
231 
232  throw TimeoutException("Verbindung unterbrochen.", timeout);
233 }
234 
235 uint16_t USART::readInt(void)
236 {
237  return readByte() | readByte() << 8;
238 }
239 
240 bool USART::readBlock(uint8_t* buffer, uint16_t offset)
241 {
242  uint8_t len = readByte();
243  uint8_t crc = 0;
244  buffer += offset;
245 
246  uint32_t block_timeout = timeout / 10;
247 
248  // wait for block
249  int n_ready;
250  uint16_t elapsed = 0;
251  auto start = std::chrono::steady_clock::now();
252  auto end = start;
253  while(elapsed < block_timeout)
254  {
255  int code = ioctl(file_desc, FIONREAD, &n_ready);
256  if(code != 0)
257  {
258  std::cout << "n_ready code: " << code << std::endl;
259  return false;
260  }
261 
262  if(n_ready >= len + 1)
263  break;
264 
265  end = std::chrono::steady_clock::now();
266  elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
267  }
268  if(elapsed >= timeout)
269  {
270  std::cout << "block timeout: " << std::endl;
271  return false;
272  }
273 
274  while(len--)
275  {
276  *buffer = readByte();
277 
278  crc ^= *buffer++;
279  for (uint8_t i = 0; i < 8; i++)
280  {
281  if (crc & 1)
282  crc ^= CRC7_POLY;
283  crc >>= 1;
284  }
285  }
286 
287  crc ^= readByte();
288  for (uint8_t i = 0; i < 8; i++)
289  {
290  if (crc & 1)
291  crc ^= CRC7_POLY;
292  crc >>= 1;
293  }
294 
295  if(TEST == 1)
296  crc = 1;
297  if(TEST > 100)
298  TEST = 0;
299 
300  if (crc == 0)
301  {
302  writeByte(0xFF);
303  return true;
304  }
305  else
306  {
307  writeByte(0xFE);
308  return false;
309  }
310 }
311 
313 {
314  return baudrate;
315 }
316 
318 {
319  return timeout;
320 }
321 
322 void USART::setBaudrate(uint32_t baudrate)
323 {
324  this->baudrate = baudrate;
325 }
326 
327 void USART::setTimeout(uint8_t timeout)
328 {
329  this->timeout = timeout;
330 }
USART::writeU32
void writeU32(uint32_t d)
Definition: usart.cpp:88
USART::getBaudrate
uint32_t getBaudrate(void)
Definition: usart.cpp:312
USART::readByte
uint8_t readByte(void)
Definition: usart.cpp:216
USARTException
Definition: usartexception.h:11
USART::printStatistics
void printStatistics(void)
Definition: usart.cpp:60
USART::closeDevice
void closeDevice(void)
Definition: usart.cpp:32
USART::clearInputBuffer
void clearInputBuffer(void)
Definition: usart.cpp:39
USART::getTimeout
uint8_t getTimeout(void)
Definition: usart.cpp:317
USART::clearOutputBuffer
void clearOutputBuffer(void)
Definition: usart.cpp:46
USART::setBaudrate
void setBaudrate(uint32_t baudrate)
Definition: usart.cpp:322
USART::writeByte
void writeByte(uint8_t b)
Definition: usart.cpp:67
USART::openDevice
void openDevice(std::string device)
Definition: usart.cpp:3
USART::readInt
uint16_t readInt(void)
Definition: usart.cpp:235
USART::setTimeout
void setTimeout(uint8_t timeout)
Definition: usart.cpp:327
USART::flushOutputBuffer
void flushOutputBuffer(void)
Definition: usart.cpp:53
TimeoutException
Definition: timeoutexception.h:10
USART::writeInt
void writeInt(uint16_t d)
Definition: usart.cpp:81