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  if(!failed)
200  n_blocks_failed++;
201  failed = true;
202  std::cout << "block failed, retry" << std::endl;
203  }
204  }
205  while(aw != 0xFF);
206 
207  //std::cout << "OK" << std::endl;
208 }
209 
210 uint8_t USART::readByte(void)
211 {
212  char b;
213  auto start = std::chrono::steady_clock::now();
214  auto end = start;
215  uint16_t elapsed = 0;
216  while(elapsed < timeout * 100)
217  {
218  int code = read(file_desc, &b, 1);
219  if (code > 0)
220  return static_cast<uint8_t>(b);
221 
222  end = std::chrono::steady_clock::now();
223  elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
224  }
225 
226  throw TimeoutException("Verbindung unterbrochen.", timeout);
227 }
228 
229 uint16_t USART::readInt(void)
230 {
231  return readByte() | readByte() << 8;
232 }
233 
234 bool USART::readBlock(uint8_t* buffer, uint16_t offset)
235 {
236  uint8_t len = readByte();
237  uint8_t crc = 0;
238  buffer += offset;
239 
240  uint32_t block_timeout = timeout / 10;
241 
242  // wait for block
243  int n_ready;
244  uint16_t elapsed = 0;
245  auto start = std::chrono::steady_clock::now();
246  auto end = start;
247  while(elapsed < block_timeout)
248  {
249  int code = ioctl(file_desc, FIONREAD, &n_ready);
250  if(code != 0)
251  {
252  std::cout << "n_ready code: " << code << std::endl;
253  return false;
254  }
255 
256  if(n_ready >= len + 1)
257  break;
258 
259  end = std::chrono::steady_clock::now();
260  elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
261  }
262  if(elapsed >= timeout)
263  {
264  std::cout << "block timeout: " << std::endl;
265  return false;
266  }
267 
268  while(len--)
269  {
270  *buffer = readByte();
271 
272  crc ^= *buffer++;
273  for (uint8_t i = 0; i < 8; i++)
274  {
275  if (crc & 1)
276  crc ^= CRC7_POLY;
277  crc >>= 1;
278  }
279  }
280 
281  crc ^= readByte();
282  for (uint8_t i = 0; i < 8; i++)
283  {
284  if (crc & 1)
285  crc ^= CRC7_POLY;
286  crc >>= 1;
287  }
288 
289  if(TEST == 1)
290  crc = 1;
291  if(TEST > 100)
292  TEST = 0;
293 
294  if (crc == 0)
295  {
296  writeByte(0xFF);
297  return true;
298  }
299  else
300  {
301  writeByte(0xFE);
302  return false;
303  }
304 }
305 
307 {
308  return baudrate;
309 }
310 
312 {
313  return timeout;
314 }
315 
316 void USART::setBaudrate(uint32_t baudrate)
317 {
318  this->baudrate = baudrate;
319 }
320 
321 void USART::setTimeout(uint8_t timeout)
322 {
323  this->timeout = timeout;
324 }
USART::getBaudrate
uint32_t getBaudrate(void)
Definition: usart.cpp:306
USART::readByte
uint8_t readByte(void)
Definition: usart.cpp:210
USARTException
Definition: usartexception.h:9
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:311
USART::clearOutputBuffer
void clearOutputBuffer(void)
Definition: usart.cpp:46
USART::setBaudrate
void setBaudrate(uint32_t baudrate)
Definition: usart.cpp:316
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:229
USART::setTimeout
void setTimeout(uint8_t timeout)
Definition: usart.cpp:321
USART::flushOutputBuffer
void flushOutputBuffer(void)
Definition: usart.cpp:53
TimeoutException
Definition: timeoutexception.h:8
USART::writeInt
void writeInt(uint16_t d)
Definition: usart.cpp:81