AceSegment  0.3.0
An adjustable, configurable, and extensible framework for rendering seven segment LED displays.
Renderer.cpp
1 /*
2 MIT License
3 
4 Copyright (c) 2018 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 #include <Arduino.h>
26 #include "Util.h"
27 #include "StyledPattern.h"
28 #include "Hardware.h"
29 #include "Styler.h"
30 #include "Renderer.h"
31 
32 namespace ace_segment {
33 
35  uint16_t nowMicros = mHardware->micros();
36 
37  // Extract driver specific info.
38  mIsBrightnessEnabled = mDriver->isBrightnessSupported();
39  mFieldsPerFrame = mDriver->getFieldsPerFrame();
40 
41  // Counters for frames and fields.
42  mCurrentField = 0;
43 
44  // Set up durations for polling.
45  mMicrosPerField = 1000000UL / getFieldsPerSecond();
46  mLastRenderFieldMicros = nowMicros;
47 
48  // Reset statistics
49  mStats.reset();
50 
51  // Reset the active styles.
52  memset(mActiveStyles, 0, kNumStyles * sizeof(uint8_t));
53  mActiveStyles[0] = mNumDigits;
54 }
55 
56 void Renderer::writePatternAt(uint8_t digit, uint8_t pattern, uint8_t style) {
57  if (digit >= mNumDigits) return;
58  if (style >= kNumStyles) return;
59  // style 0 is always allowed
60  if (style > 0 && mStylers[style] == nullptr) return;
61 
62  StyledPattern& styledPattern = mStyledPatterns[digit];
63  styledPattern.pattern = pattern;
64 
65  mActiveStyles[styledPattern.style]--;
66  mActiveStyles[style]++;
67  styledPattern.style = style;
68 }
69 
70 void Renderer::writePatternAt(uint8_t digit, uint8_t pattern) {
71  if (digit >= mNumDigits) return;
72  StyledPattern& styledPattern = mStyledPatterns[digit];
73  styledPattern.pattern = pattern;
74 }
75 
76 void Renderer::writeStyleAt(uint8_t digit, uint8_t style) {
77  if (digit >= mNumDigits) return;
78  if (style >= kNumStyles) return;
79  // style 0 is always allowed
80  if (style > 0 && mStylers[style] == nullptr) return;
81 
82  StyledPattern& styledPattern = mStyledPatterns[digit];
83 
84  mActiveStyles[styledPattern.style]--;
85  mActiveStyles[style]++;
86  styledPattern.style = style;
87 }
88 
89 void Renderer::writeDecimalPointAt(uint8_t digit, bool state) {
90  if (digit >= mNumDigits) return;
91  StyledPattern& styledPattern = mStyledPatterns[digit];
92  if (state) {
93  styledPattern.setDecimalPoint();
94  } else {
95  styledPattern.clearDecimalPoint();
96  }
97 }
99  for (uint8_t i = 0; i < mNumDigits; i++) {
100  mStyledPatterns[i].pattern = 0;
101  }
102 }
103 
105  uint16_t now = mHardware->micros();
106  uint16_t elapsedMicros = now - mLastRenderFieldMicros;
107  if (elapsedMicros >= mMicrosPerField) {
108  renderField();
109  mLastRenderFieldMicros = now;
110  return true;
111  } else {
112  return false;
113  }
114 }
115 
117  uint16_t now = mHardware->micros();
118  if (mCurrentField == 0) {
119  updateFrame();
120  }
121  mDriver->displayCurrentField();
122  Util::incrementMod(mCurrentField, mFieldsPerFrame);
123 
124  uint16_t duration = mHardware->micros() - now;
125  mStats.update(duration);
126 }
127 
128 void Renderer::updateFrame() {
129  updateStylers();
130  renderStyledPatterns();
131  if (mStatsResetInterval > 0 &&
132  mStats.getCount() >= mStatsResetInterval) {
133  mStats.reset();
134  }
135 }
136 
137 void Renderer::updateStylers() {
138  // Update the active Stylers.
139  // Style 0 is the no-op style that does nothing.
140  for (uint8_t style = 1; style < kNumStyles; style++) {
141  if (mActiveStyles[style] > 0) {
142  Styler* styler = mStylers[style];
143  if (isStylerSupported(styler)) {
144  styler->calcForFrame();
145  }
146  }
147  }
148 }
149 
151  if (styler == nullptr) return false;
152  if (!styler->requiresBrightness()) return true;
153  return mIsBrightnessEnabled;
154 }
155 
157  noInterrupts();
158  TimingStats stats = mStats;
159  interrupts();
160  return stats;
161 }
162 
163 void Renderer::renderStyledPatterns() {
164  for (uint8_t digit = 0; digit < mNumDigits; digit++) {
165  StyledPattern& styledPattern = mStyledPatterns[digit];
166 
167  uint8_t pattern = styledPattern.pattern;
168  uint8_t brightness = mBrightness;
169 
170  uint8_t style = styledPattern.style;
171  if (0 < style && style < kNumStyles) {
172  Styler* styler = mStylers[style];
173  if (isStylerSupported(styler)) {
174  styler->apply(&pattern, &brightness);
175  }
176  }
177  mDriver->setPattern(digit, pattern, brightness);
178  }
179 }
180 
181 }
bool renderFieldWhenReady()
Display one field of a frame when the time is right.
Definition: Renderer.cpp:104
TimingStats getTimingStats()
Return stats.
Definition: Renderer.cpp:156
virtual void displayCurrentField()=0
Display the current field of the frame.
static const uint8_t kNumStyles
Maximum number of styles.
Definition: Renderer.h:55
bool isStylerSupported(Styler *styler)
Return true if the given Styler is supported by the current Driver.
Definition: Renderer.cpp:150
void writePatternAt(uint8_t digit, uint8_t pattern, uint8_t style)
Write the pattern and style for a given digit.
Definition: Renderer.cpp:56
void renderField()
Render the current field immediately.
Definition: Renderer.cpp:116
void writeStyleAt(uint8_t digit, uint8_t style)
Write the style for a given digit, leaving pattern unchanged.
Definition: Renderer.cpp:76
virtual unsigned long micros()
Get the current micros.
Definition: Hardware.h:59
virtual void calcForFrame()=0
Called once per frame to update the internal variables of the object.
virtual void configure()
Configure the driver with the parameters given by in the constructor.
Definition: Renderer.cpp:34
virtual bool isBrightnessSupported()=0
Returns true if the driver supports brightness.
uint16_t getCount() const
Number of times update() was called since last reset.
Definition: TimingStats.h:58
void clear()
Clear all digits, preserving the styles at each digit.
Definition: Renderer.cpp:98
uint16_t getFieldsPerSecond()
Return the fields per second.
Definition: Renderer.h:92
void writeDecimalPointAt(uint8_t digit, bool state=true)
Write the decimal point for the digit.
Definition: Renderer.cpp:89
void setPattern(uint8_t digit, SegmentPatternType pattern, uint8_t brightness=DimmablePattern::kOn)
Set the pattern for a given digit.
Definition: Driver.cpp:49
virtual bool requiresBrightness()=0
Requires driver support for brightness control if true.
virtual void apply(uint8_t *pattern, uint8_t *brightness)=0
Changes updates the brightness for current frame.
Data structure that keeps track of the state of each digit (its segment bit pattern and its style)...
Definition: StyledPattern.h:36
Interface for classes which apply a style to the given bit pattern and brightness.
Definition: Styler.h:34
static void incrementMod(T &i, T m)
Increment i modulo m, avoiding expensive % operator on some 8-bit processors like AVR...
Definition: Util.h:39
virtual uint16_t getFieldsPerFrame()=0
Return number of fields per frame.