EV3RT CXX API Reference [English]
An RTOS-based development platform for LEGO Mindstorms EV3.
ev3cxx_format.h
Go to the documentation of this file.
1 
7 #pragma once
8 
9 #include <type_traits>
10 
11 #include "ev3api.h"
12 
13 #include <string>
14 
15 namespace ev3cxx {
16 
17 template <typename Stream>
18 void send(Stream & s, char const * str)
19 {
20  for (; *str != 0; ++str)
21  s.write(*str);
22 }
23 
24 template <typename Stream>
25 void send(Stream & s, const std::string& str)
26 {
27  for (auto c: str)
28  s.write(c);
29 }
30 
31 template <typename Stream>
32 void send_bool(Stream & s, bool value)
33 {
34  send(s, value? "true": "false");
35 }
36 
37 template <typename Stream, typename Unsigned>
38 void send_bin_text(Stream & s, Unsigned v, uint8_t width = 0, char fill = '0')
39 {
40  char buf[32];
41  uint8_t i = 0;
42 
43  if (v == 0)
44  {
45  buf[i++] = '0';
46  }
47  else if (v < 0)
48  {
49  buf[i++] = '*';
50  }
51  else
52  {
53  for (; v != 0; v >>= 1)
54  {
55  buf[i++] = '0' + (v & 0x1);
56  }
57  }
58 
59  while (i < width)
60  buf[i++] = fill;
61 
62  for (; i > 0; --i)
63  s.write(buf[i - 1]);
64 }
65 
66 template <typename Stream, typename Unsigned>
67 void send_hex(Stream & s, Unsigned v, uint8_t width = 0, char fill = '0')
68 {
69  static char const digits[] = "0123456789ABCDEF";
70 
71  char buf[32];
72  uint8_t i = 0;
73 
74  if (v == 0)
75  {
76  buf[i++] = '0';
77  }
78  else if (v < 0)
79  {
80  buf[i++] = '*';
81  }
82  else
83  {
84  for (; v != 0; v >>= 4)
85  {
86  buf[i++] = digits[v & 0xF];
87  }
88  }
89 
90  while (i < width)
91  buf[i++] = fill;
92 
93  for (; i > 0; --i)
94  s.write(buf[i - 1]);
95 }
96 
97 template <typename Stream, typename Signed>
98 void send_shex(Stream & s, Signed v, uint8_t width = 0, char fill = ' ')
99 {
100  static char const digits[] = "0123456789ABCDEF";
101 
102  char buf[32];
103  uint8_t i = 0;
104 
105  bool negative = (v < 0);
106  if (negative)
107  v = -v;
108 
109  if (v == 0)
110  {
111  buf[i++] = '0';
112  }
113  else
114  {
115  for (; v != 0; v >>= 4)
116  {
117  buf[i++] = digits[v & 0xF];
118  }
119  }
120 
121  if (negative)
122  buf[i++] = '-';
123 
124  while (i < width)
125  buf[i++] = fill;
126 
127  for (; i > 0; --i)
128  s.write(buf[i - 1]);
129 }
130 
131 template <typename Stream, typename Integer>
132 void send_int(Stream & s, Integer v, uint8_t width = 0, char fill = ' ')
133 {
134  char buf[32];
135  uint8_t i = 0;
136  bool negative = false;
137 
138  if (v == 0)
139  {
140  buf[i++] = '0';
141  }
142  else
143  {
144  if (v < 0)
145  {
146  negative = true;
147  v = -v;
148  }
149 
150  for (; v != 0; v /= 10)
151  {
152  buf[i++] = (v % 10) + '0';
153  }
154  }
155 
156  if (negative)
157  buf[i++] = '-';
158 
159  while (i < width)
160  buf[i++] = fill;
161 
162  for (; i > 0; --i)
163  s.write(buf[i - 1]);
164 }
165 
166 template <typename Stream, typename T>
167 void send_bin(Stream & s, T const & t)
168 {
169  char const * ptr = reinterpret_cast<char const *>(&t);
170  for (uint8_t i = 0; i < sizeof t; ++i)
171  s.write(ptr[i]);
172 }
173 
174 template <typename Stream>
175 uint8_t readline(Stream & s, uint8_t * buffer, uint8_t len)
176 {
177  uint8_t i = 0;
178 
179  while (i < len)
180  {
181  while (s.empty())
182  {
183  s.process_rx();
184  s.process_tx();
185  }
186 
187  uint8_t ch = s.read();
188  buffer[i++] = ch;
189 
190  if (ch == '\n')
191  break;
192  }
193 
194  return i;
195 }
196 
197 namespace detail {
198 
199 template <int N>
200 bool bufcmp(uint8_t const * buf, uint8_t len, char const (&pattern)[N])
201 {
202  for (int i = 0; i < N - 1; ++i)
203  if (buf[i] != pattern[i])
204  return false;
205  return true;
206 }
207 
208 template <typename Stream, typename Pattern>
210 {
211 public:
212  format_impl(Stream & out, Pattern const & pattern)
213  : m_out(out), m_pattern(pattern)
214  {
215  this->write_literal();
216  }
217 
218  format_impl & operator%(const char& ch)
219  {
220  if(m_pattern.empty())
221  return *this;
222  m_out.write(ch);
223  m_pattern.pop();
224  this->write_literal();
225  return *this;
226  }
227 
228  format_impl & operator%(const char * str)
229  {
230  if(m_pattern.empty())
231  return *this;
232  while (*str)
233  m_out.write(*str++);
234  m_pattern.pop();
235  this->write_literal();
236  return *this;
237  }
238 
239  format_impl & operator%(const std::string& str)
240  {
241  if(m_pattern.empty())
242  return *this;
243  for (auto c: str)
244  m_out.write(c);
245  m_pattern.pop();
246  this->write_literal();
247  return *this;
248  }
249 
250  format_impl & operator%(const bool& v)
251  {
252  if(m_pattern.empty())
253  return *this;
254  m_out.write(v ? '1' : '0');
255  m_pattern.pop();
256  this->write_literal();
257  return *this;
258  }
259 
260  format_impl & operator%(const float& v)
261  {
262  if(m_pattern.empty())
263  return *this;
264 
265  static const int ft_size = 12;
266  char float_text[ft_size];
267  char * float_text_ptr = float_text;
268  snprintf(float_text, ft_size,"%g", v);
269  while (*float_text_ptr)
270  m_out.write(*float_text_ptr++);
271 
272  m_pattern.pop();
273  this->write_literal();
274  return *this;
275  }
276 
277  format_impl & operator%(const double& v)
278  {
279  if(m_pattern.empty())
280  return *this;
281 
282  static const int dt_size = 20;
283  char double_text[dt_size];
284  char * double_text_ptr = double_text;
285  snprintf(double_text, dt_size,"%f", v);
286  while (*double_text_ptr)
287  m_out.write(*double_text_ptr++);
288 
289  m_pattern.pop();
290  this->write_literal();
291  return *this;
292  }
293 
294  template <typename T >
295  typename std::enable_if<std::is_integral<T>::value, format_impl&>::type operator%(T const& t)
296  {
297  if (m_pattern.empty()) return *this;
298  char f = m_pattern.top();
299  bool hex = false;
300  bool bin = false;
301  uint8_t width = 0;
302  if (f == 'x') {
303  hex = true;
304  m_pattern.pop();
305  f = m_pattern.top();
306  } else if (f == 'b') {
307  bin = true;
308  m_pattern.pop();
309  f = m_pattern.top();
310  }
311  if (f >= '0' && f <= '9') width = f - '0';
312  if (hex)
313  send_hex(m_out, t, width);
314  else if (bin)
315  send_bin_text(m_out, t, width);
316  else
317  send_int(m_out, t, width);
318  if (!m_pattern.empty()) m_pattern.pop();
319  this->write_literal();
320  return *this;
321  }
322 
323 private:
324  void write_literal()
325  {
326  bool escape = false;
327  for (; !m_pattern.empty(); m_pattern.pop())
328  {
329  char ch = m_pattern.top();
330 
331  if (ch == '%')
332  {
333  if (escape)
334  {
335  m_out.write('%');
336  m_out.write('%');
337  escape = false;
338  }
339  else
340  {
341  escape = true;
342  }
343  }
344  else
345  {
346  if (escape)
347  break;
348  m_out.write(ch);
349  }
350  }
351  }
352 
353  Stream & m_out;
354  Pattern m_pattern;
355 };
356 
358 {
359 public:
360  string_literal_range(char const * pattern)
361  : m_pattern(pattern)
362  {
363  }
364 
365  bool empty() const
366  {
367  return *m_pattern == 0;
368  }
369 
370  char top() const
371  {
372  return *m_pattern;
373  }
374 
375  void pop()
376  {
377  ++m_pattern;
378  }
379 
380 private:
381  char const * m_pattern;
382 };
383 
384 } // end of namespace detail
385 
386 template <typename Stream>
387 detail::format_impl<Stream, detail::string_literal_range> format(Stream & out, char const * pattern)
388 {
390 }
391 
392 } // end of namespace ev3cxx
Definition: ev3cxx.h:35