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 
89 
90 int USART::read_timeout(uint8_t* buffer, uint16_t offset, uint8_t len, uint32_t timeout)
91 {
92  uint32_t elapsed = 0;
93  int n_read = -1;
94  auto start = std::chrono::steady_clock::now();
95  auto end = start;
96  while(elapsed < timeout)
97  {
98  n_read = read(file_desc, buffer + offset, len);
99  if (n_read == len)
100  return n_read;
101 
102  end = std::chrono::steady_clock::now();
103  elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
104  }
105 
106  return 0;
107 }
108 
109 int USART::write_timeout(uint8_t* buffer, uint16_t offset, uint8_t len, uint32_t timeout)
110 {
111  uint32_t elapsed = 0;
112  int n_sent = -1;
113  auto start = std::chrono::steady_clock::now();
114  auto end = start;
115  while(elapsed < timeout)
116  {
117  n_sent = write(file_desc, buffer + offset, len);
119  if (n_sent == len)
120  return n_sent;
121 
122  end = std::chrono::steady_clock::now();
123  elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
124  }
125 
126  return n_sent;
127 }
128 
129 void USART::writeBlock(uint8_t* buffer, uint16_t offset, uint8_t len)
130 {
131  uint8_t crc;
132  uint8_t aw;
133  const uint16_t us_per_bit = (1000000 / baudrate) * 16;
134  const uint16_t n_total = len + 3;
135 
136  n_blocks_total++;
137  bool failed = false;
138 
139  do
140  {
141  // calc crc
142  crc = 0;
143  for(uint8_t i = 0; i < len; i++)
144  {
145  crc ^= buffer[i];
146  for (uint8_t k = 0; k < 8; k++)
147  {
148  if (crc & 1)
149  crc ^= CRC7_POLY;
150  crc >>= 1;
151  }
152  }
153 
154  // construct block
155  block_buffer[0] = len;
156  std::memcpy(&block_buffer[1], buffer + offset, len);
157  block_buffer[len + 1] = crc;
158  block_buffer[len + 2] = BLOCK_END;
159 
160  // send block
163  int n_sent = write_timeout(&block_buffer[0], 0, len + 3, us_per_bit * n_total);
164  if(n_sent != n_total)
165  throw std::runtime_error("fatal (send): " + std::to_string(n_sent));
166 
167  /*for(uint8_t i = 0; i < len + 3; i++)
168  {
169  write_timeout(&block_buffer[i], 0, 1, us_per_bit * n_total);
170  //tcdrain(file_desc);
171  //usleep(1000);
172  }*/
173 
174  // flush output data
175  tcdrain(file_desc);
176 
177  //usleep(us_per_bit * n_total * 10);
178 
179  // check response
180  int n_read = read_timeout(&aw, 0, 1, us_per_bit * n_blocks_total * 10);
181  for(uint16_t i = 0; i < 255 && n_read != 1; i++)
182  {
183  writeByte(0x80); // Stoppzeichen für Block
184  if(tcdrain(file_desc))
185  {
186  std::cout << "drain failed" << std::endl;
187  }
188  std::cout << "WARNING: read error (" << n_read << "), retry #" << (int) i << std::endl;
189  usleep(us_per_bit*100);
190  n_read = read_timeout(&aw, 0, 1, us_per_bit);
191  }
192 
193  if(n_read != 1)
194  throw std::runtime_error("fatal: " + std::to_string(n_read));
195 
196  //clearInputBuffer();
197 
198  if(aw != 0xFF)
199  {
200  if(!failed)
201  n_blocks_failed++;
202  failed = true;
203  std::cout << "block failed, retry" << std::endl;
204  }
205  }
206  while(aw != 0xFF);
207 
208  //std::cout << "OK" << std::endl;
209 }
210 
211 uint8_t USART::readByte(void)
212 {
213  char b;
214  auto start = std::chrono::steady_clock::now();
215  auto end = start;
216  uint16_t elapsed = 0;
217  while(elapsed < timeout * 100)
218  {
219  int code = read(file_desc, &b, 1);
220  if (code > 0)
221  return static_cast<uint8_t>(b);
222 
223  end = std::chrono::steady_clock::now();
224  elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
225  }
226 
227  throw TimeoutException("Verbindung unterbrochen.", timeout);
228 }
229 
230 uint16_t USART::readInt(void)
231 {
232  return readByte() | readByte() << 8;
233 }
234 
235 bool USART::readBlock(uint8_t* buffer, uint16_t offset)
236 {
237  uint8_t len = readByte();
238  uint8_t crc = 0;
239  buffer += offset;
240 
241  uint32_t block_timeout = timeout / 10;
242 
243  // wait for block
244  int n_ready;
245  uint16_t elapsed = 0;
246  auto start = std::chrono::steady_clock::now();
247  auto end = start;
248  while(elapsed < block_timeout)
249  {
250  int code = ioctl(file_desc, FIONREAD, &n_ready);
251  if(code != 0)
252  {
253  std::cout << "n_ready code: " << code << std::endl;
254  return false;
255  }
256 
257  if(n_ready >= len + 1)
258  break;
259 
260  end = std::chrono::steady_clock::now();
261  elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
262  }
263  if(elapsed >= timeout)
264  {
265  std::cout << "block timeout: " << std::endl;
266  return false;
267  }
268 
269  while(len--)
270  {
271  *buffer = readByte();
272 
273  crc ^= *buffer++;
274  for (uint8_t i = 0; i < 8; i++)
275  {
276  if (crc & 1)
277  crc ^= CRC7_POLY;
278  crc >>= 1;
279  }
280  }
281 
282  crc ^= readByte();
283  for (uint8_t i = 0; i < 8; i++)
284  {
285  if (crc & 1)
286  crc ^= CRC7_POLY;
287  crc >>= 1;
288  }
289 
290  if(TEST == 1)
291  crc = 1;
292  if(TEST > 100)
293  TEST = 0;
294 
295  if (crc == 0)
296  {
297  writeByte(0xFF);
298  return true;
299  }
300  else
301  {
302  writeByte(0xFE);
303  return false;
304  }
305 }
306 
308 {
309  return baudrate;
310 }
311 
313 {
314  return timeout;
315 }
316 
317 void USART::setBaudrate(uint32_t baudrate)
318 {
319  this->baudrate = baudrate;
320 }
321 
322 void USART::setTimeout(uint8_t timeout)
323 {
324  this->timeout = timeout;
325 }
USART::getBaudrate
uint32_t getBaudrate(void)
Definition: usart.cpp:307
USART::readByte
uint8_t readByte(void)
Definition: usart.cpp:211
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:312
USART::clearOutputBuffer
void clearOutputBuffer(void)
Definition: usart.cpp:46
USART::setBaudrate
void setBaudrate(uint32_t baudrate)
Definition: usart.cpp:317
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:230
USART::setTimeout
void setTimeout(uint8_t timeout)
Definition: usart.cpp:322
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