AceSegmentWriter  0.5
Write decimal numbers, hex numbers, temperature, clock digits, characters, and strings to seven segment LED modules
NumberWriter.h
1 /*
2 MIT License
3 
4 Copyright (c) 2021 Brian T. Park
5 
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12 
13 The above copyright notice and this permission notice shall be included in all
14 copies or substantial portions of the Software.
15 
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 SOFTWARE.
23 */
24 
25 #ifndef ACE_SEGMENT_WRITER_NUMBER_WRITER_H
26 #define ACE_SEGMENT_WRITER_NUMBER_WRITER_H
27 
28 #include <stdint.h>
29 #include <AceCommon.h> // PrintStr<N>
30 #include "PatternWriter.h"
31 
32 namespace ace_segment {
33 
35 const uint8_t kNumDigitPatterns = 18;
36 
38 extern const uint8_t kDigitPatterns[kNumDigitPatterns];
39 
54 typedef uint8_t digit_t;
55 
57 const digit_t kDigitSpace = 16;
58 
60 const digit_t kDigitMinus = 17;
61 
71 template <typename T_LED_MODULE>
72 class NumberWriter {
73  public:
76  mPatternWriter(patternWriter)
77  {}
78 
80  T_LED_MODULE& ledModule() { return mPatternWriter.ledModule(); }
81 
83  PatternWriter<T_LED_MODULE>& patternWriter() { return mPatternWriter; }
84 
86  void home() { mPatternWriter.home(); }
87 
93  void writeDigit(digit_t c) {
94  write(((uint8_t) c < kNumDigitPatterns) ? c : kDigitSpace);
95  }
96 
98  void writeDigits(const digit_t s[], uint8_t len) {
99  for (uint8_t i = 0; i < len; ++i) {
100  writeDigit(s[i]);
101  }
102  }
103 
113  void writeDec2(uint8_t d, uint8_t padPattern = kPattern0) {
114  if (d >= 100) {
115  mPatternWriter.writePattern(kPatternSpace);
116  mPatternWriter.writePattern(kPatternSpace);
117  } else {
118  uint8_t tens = d / 10;
119  uint8_t ones = d - 10 * tens;
120  if (tens == 0) {
121  mPatternWriter.writePattern(padPattern);
122  } else {
123  writeDigit(tens);
124  }
125  writeDigit(ones);
126  }
127  }
128 
134  void writeDec4(uint16_t dd, uint8_t padPattern = kPattern0) {
135  if (dd >= 10000) {
136  mPatternWriter.writePattern(kPatternSpace);
137  mPatternWriter.writePattern(kPatternSpace);
138  mPatternWriter.writePattern(kPatternSpace);
139  mPatternWriter.writePattern(kPatternSpace);
140  } else {
141  uint8_t high = dd / 100;
142  uint8_t low = dd - high * 100;
143  if (high == 0) {
144  mPatternWriter.writePattern(padPattern);
145  mPatternWriter.writePattern(padPattern);
146  writeDec2(low, padPattern);
147  } else {
148  writeDec2(high, padPattern);
149  writeDec2(low, kPattern0);
150  }
151  }
152  }
153 
159  void writeBcd(uint8_t bcd) {
160  uint8_t high = (bcd & 0xF0) >> 4;
161  uint8_t low = (bcd & 0x0F);
162  if (high > 9) high = kDigitSpace;
163  if (low > 9) low = kDigitSpace;
164  writeDigit(high);
165  writeDigit(low);
166  }
167 
169  void writeHexByte(uint8_t b) {
170  uint8_t low = (b & 0x0F);
171  uint8_t high = ((b >> 4) & 0x0F);
172  write(high);
173  write(low);
174  }
175 
177  void writeHexWord(uint16_t w) {
178  uint8_t low = (w & 0xFF);
179  uint8_t high = (w >> 8) & 0xFF;
180  writeHexByte(high);
181  writeHexByte(low);
182  }
183 
199  uint8_t writeUnsignedDecimal(uint16_t num, int8_t boxSize = 0) {
200  const uint8_t bufSize = 5;
201  digit_t buf[bufSize];
202  uint8_t start = toDecimal(num, buf, bufSize);
203 
204  return writeDigitsInsideBox(&buf[start], bufSize - start, boxSize);
205  }
206 
208  uint8_t writeSignedDecimal(int16_t num, int8_t boxSize = 0) {
209  // Even -32768 turns into +32768, which is exactly what we want
210  bool negative = num < 0;
211  uint16_t absNum = negative ? -num : num;
212 
213  const uint8_t bufSize = 6;
214  digit_t buf[bufSize];
215  uint8_t start = toDecimal(absNum, buf, bufSize);
216  if (negative) {
217  buf[--start] = kDigitMinus;
218  }
219 
220  return writeDigitsInsideBox(&buf[start], bufSize - start, boxSize);
221  }
222 
231  void writeFloat(float x, uint8_t prec = 2) {
232  ace_common::PrintStr<16> buf;
233  buf.print(x, prec);
234  for (const char *s = buf.cstr(); *s != '\0'; s++) {
235  writeChar(*s);
236  }
237  }
238 
246  void writeChar(char c) {
247  if (c == '.') {
249  } else {
250  uint8_t d;
251  if (c >= '0' && c <= '9') {
252  d = c - '0';
253  } else if (c == '-') {
254  d = kDigitMinus;
255  } else {
256  d = kDigitSpace;
257  }
258  writeDigit(d);
259  }
260  }
261 
267  void writeDecimalPoint(bool state = true) {
268  mPatternWriter.writeDecimalPoint(state);
269  }
270 
272  void clear() { mPatternWriter.clear(); }
273 
279  void clearToEnd() { mPatternWriter.clearToEnd(); }
280 
281  private:
282  // disable copy-constructor and assignment operator
283  NumberWriter(const NumberWriter&) = delete;
284  NumberWriter& operator=(const NumberWriter&) = delete;
285 
287  void write(digit_t c) {
288  uint8_t pattern = pgm_read_byte(&kDigitPatterns[(uint8_t) c]);
289  mPatternWriter.writePattern(pattern);
290  }
291 
293  void writeInternalDigits(const digit_t s[], uint8_t len) {
294  for (uint8_t i = 0; i < len; ++i) {
295  write(s[i]);
296  }
297  }
298 
306  uint8_t writeDigitsInsideBox(
307  const digit_t s[], uint8_t len, int8_t boxSize) {
308 
309  uint8_t absBoxSize = (boxSize < 0) ? -boxSize : boxSize;
310 
311  // if the box is too small, print normally
312  if (len >= absBoxSize) {
313  writeInternalDigits(s, len);
314  return len;
315  }
316 
317  // Print either left justified or right justified inside box
318  uint8_t padSize = absBoxSize - len;
319  if (boxSize < 0) {
320  // left justified
321  writeInternalDigits(s, len);
322  while (padSize--) write(kDigitSpace);
323  } else {
324  // right justified
325  while (padSize--) write(kDigitSpace);
326  writeInternalDigits(s, len);
327  }
328 
329  return absBoxSize;
330  }
331 
345  static uint8_t toDecimal(uint16_t num, digit_t buf[], uint8_t bufSize) {
346  uint8_t pos = bufSize;
347  while (true) {
348  if (num < 10) {
349  buf[--pos] = num;
350  break;
351  }
352  uint16_t quot = num / 10;
353  buf[--pos] = num - quot * 10;
354  num = quot;
355  }
356  return pos;
357  }
358 
359  private:
360  PatternWriter<T_LED_MODULE> &mPatternWriter;
361 };
362 
363 }
364 
365 #endif
The NumberWriter supports converting decimal and hexadecimal numbers to segment patterns expected by ...
Definition: NumberWriter.h:72
void writeFloat(float x, uint8_t prec=2)
Write a float using the same format as the Print class.
Definition: NumberWriter.h:231
void writeDec2(uint8_t d, uint8_t padPattern=kPattern0)
Write a 2-digit decimal number at position digit, right justified with the given padPattern (default ...
Definition: NumberWriter.h:113
void writeDigits(const digit_t s[], uint8_t len)
Write the len hex characters given by s at LED pos.
Definition: NumberWriter.h:98
PatternWriter< T_LED_MODULE > & patternWriter()
Get the underlying PatternWriter.
Definition: NumberWriter.h:83
void clearToEnd()
Clear the display from the current position to the end.
Definition: NumberWriter.h:279
uint8_t writeSignedDecimal(int16_t num, int8_t boxSize=0)
Same as writeUnsignedDecimal() but prepends a '-' sign if negative.
Definition: NumberWriter.h:208
uint8_t writeUnsignedDecimal(uint16_t num, int8_t boxSize=0)
Write the 16-bit unsigned number num as a decimal number at pos.
Definition: NumberWriter.h:199
void clear()
Clear the entire display.
Definition: NumberWriter.h:272
NumberWriter(PatternWriter< T_LED_MODULE > &patternWriter)
Constructor.
Definition: NumberWriter.h:75
T_LED_MODULE & ledModule()
Get the underlying LedModule.
Definition: NumberWriter.h:80
void writeHexWord(uint16_t w)
Write the 4 digit (16-bit) hexadecimal word at pos.
Definition: NumberWriter.h:177
void writeDigit(digit_t c)
Write the digit c at position pos.
Definition: NumberWriter.h:93
void writeHexByte(uint8_t b)
Write the 2-digit (8-bit) hexadecimal byte 'b' at pos.
Definition: NumberWriter.h:169
void writeDec4(uint16_t dd, uint8_t padPattern=kPattern0)
Write the 4 digit decimal number dd at pos, right justified, padded with a the padPattern (default kP...
Definition: NumberWriter.h:134
void writeDecimalPoint(bool state=true)
Write the decimal point at the digit before the current position.
Definition: NumberWriter.h:267
void writeChar(char c)
Write a limited set of ASCII characters, enough to support floating point numbers without scientific ...
Definition: NumberWriter.h:246
void home()
Reset cursor to home.
Definition: NumberWriter.h:86
void writeBcd(uint8_t bcd)
Write a 2-digit BCD number at position, which involves just printing the number as a hexadecimal numb...
Definition: NumberWriter.h:159
Write LED segment patterns to the underlying LedModule.