Mutila: Mouse's Utilities for Arduino
Oft-used utilities: debouncing buttons, averaging samples, and so on.
DFPReader.cpp
1 #include "MutilaDebug.h"
2 #include "DFPReader.h"
3 #include "Millis.h"
4 
5 // This is a hack to get DFPReader building on ESP8266. At time of writing
6 // there is a bug in the ESP libraries (v2.3.0 has a missing implementation
7 // of // __ieee754_remainder, causing linker to fail).
8 double dmod(double a, double b)
9 {
10  return (a - b * floor(a / b));
11 }
12 
13 const uint8_t DFPReader::SMALL_NUMBERS[] = {
14  Mp3TrackZero, Mp3TrackZero+1, Mp3TrackZero+2, Mp3TrackZero+3,
15  Mp3TrackZero+4, Mp3TrackZero+5, Mp3TrackZero+6, Mp3TrackZero+7,
16  Mp3TrackZero+8, Mp3TrackZero+9, Mp3TrackZero+10, Mp3TrackZero+11,
17  Mp3TrackZero+12, Mp3TrackZero+13, Mp3TrackZero+14, Mp3TrackZero+15,
18  Mp3TrackZero+16, Mp3TrackZero+17, Mp3TrackZero+18, Mp3TrackZero+19
19 };
20 
21 const uint8_t DFPReader::TENS[] = {
22  0, 0, Mp3TrackTwenty, Mp3TrackThirty, Mp3TrackFourty,
23  Mp3TrackFifty, Mp3TrackSixty, Mp3TrackSeventy,
24  Mp3TrackEighty, Mp3TrackNinety
25 };
26 
27 DFPReader::DFPReader(Stream& serial, DFPlayerMini::Cmd playCmd, uint8_t busyPin, uint8_t readerBufferSize) :
28  DFPlayerMini(serial, busyPin),
29  _playCmd(playCmd),
30  readerBufSize(readerBufferSize)
31 {
32  readerBuf = new uint8_t[readerBufSize];
33 }
34 
36 {
37  delete readerBuf;
38 }
39 
40 void DFPReader::begin(bool bootWait)
41 {
42  DFPlayerMini::begin(bootWait);
44  lastPlayStart = 0;
45  playbackState = Playing; // we will let it reset itself, in case there is a track already playing...
46 }
47 
49 {
50  if (playbackState == Pending) {
51  if (MillisSince(lastPlayStart) >= PlaybackStartMs) {
52  _DBLN(F("playbackState Pending -> Playing"));
53  playbackState = Playing;
54  }
55  } else if (playbackState == Playing) {
56  if (!busy()) {
57  _DBLN(F("playbackState Playing -> Idle"));
58  playbackState = Idle;
59  }
60  }
61 
62  if (unplayedElements > 0) {
63  if (playbackState == Idle) {
64  startPlayback(popElement());
65  }
66  }
67 }
68 
69 void DFPReader::startPlayback(uint16_t track)
70 {
71  _DB(F("DFPReader::startPlayback "));
72  _DBLN(track);
73  lastPlayStart = Millis();
74  playbackState = Pending;
75  sendCmd(_playCmd, track);
76 }
77 
78 void DFPReader::readNumber(double number, uint8_t dp)
79 {
80  _DB(F("DFPReader::readNumber n="));
81  _DB(number, 10);
82  _DB(F(" dp="));
83  _DB(dp);
84  double integerPart, fractionalPart;
85  double exp = pow(10, dp);
86  number = round(number*exp) / exp;
87  _DB(F(" rounded="));
88  _DB(number, 10);
89  fractionalPart = modf(number, &integerPart);
90  _DB(F(" ip="));
91  _DB(integerPart, 10);
92  _DB(F(" fp="));
93  _DBLN(fractionalPart, 10);
94 
95  if (integerPart < 0.0) {
96  appendElement(Mp3TrackMinus);
97  integerPart = fabs(integerPart);
98  }
99 
100  if (integerPart < 0.1) {
101  appendElement(Mp3TrackZero);
102  } else {
103  appendMagnitude(&integerPart, 1000000000000.0, Mp3TrackTrillion);
104  appendMagnitude(&integerPart, 1000000000.0, Mp3TrackBillion);
105  appendMagnitude(&integerPart, 1000000, Mp3TrackMillion);
106  appendMagnitude(&integerPart, 1000, Mp3TrackThousand);
107  appendSubThousand((long)integerPart);
108  }
109 
110  if (dp > 0) {
111  appendElement(Mp3TrackPoint);
112  for (uint8_t i=1; i<dp+1; i++) {
113  uint8_t digit = (uint32_t)(fractionalPart*pow(10, i))%10;
114  appendElement(Mp3TrackZero+digit);
115  }
116  }
117 }
118 
120 {
121  if (busy()) {
122  return true;
123  } else if (unplayedElements > 0) {
124  return true;
125  } else {
126  return false;
127  }
128 }
129 
131 {
132  tailPtr = 0;
133  unplayedElements = 0;
134  if (busy()) {
136  }
137 }
138 
139 uint8_t DFPReader::popElement()
140 {
141  if (unplayedElements==0) {
142  return 0;
143  } else {
144  uint8_t e = readerBuf[tailPtr];
145  tailPtr = (tailPtr+1) % readerBufSize;
146  unplayedElements--;
147  return e;
148  }
149 }
150 
151 bool DFPReader::appendElement(uint8_t value)
152 {
153  DB(F("DFPReader::appendElement "));
154  DBLN(value);
155  if (unplayedElements >= readerBufSize) {
156  DBLN(F("DFPReader::appendElement ERROR: buffer full"));
157  return false;
158  } else {
159  readerBuf[(tailPtr+unplayedElements)%readerBufSize] = value;
160  unplayedElements++;
161  return true;
162  }
163 }
164 
165 void DFPReader::appendSubThousand(int16_t num)
166 {
167  if (num >= 100) {
168  appendElement(SMALL_NUMBERS[num / 100]);
169  appendElement(Mp3TrackHundred);
170  num %= 100;
171  }
172  if (num >= 20) {
173  appendElement(TENS[num / 10]);
174  num %= 10;
175  }
176  if (num != 0) {
177  appendElement(SMALL_NUMBERS[num]);
178  }
179 }
180 
181 void DFPReader::appendMagnitude(double* number, double magnitude, uint8_t magnitudeElement)
182 {
183  if (*number < magnitude) {
184  return;
185  }
186 
187  appendSubThousand((int)(*number / magnitude));
188  appendElement(magnitudeElement);
189  *number = dmod(*number, magnitude);
190 }
191 
192 
Reader is not playing, but is waiting for an audio file to play.
Definition: DFPReader.h:57
void resetReaderBuf()
Definition: DFPReader.cpp:130
Reader is playing an audio file.
Definition: DFPReader.h:58
void readNumber(double number, uint8_t dp=0)
Definition: DFPReader.cpp:78
void update()
Definition: DFPReader.cpp:48
DFPReader(Stream &serial, DFPlayerMini::Cmd playCmd=DFPlayerMini::PlayTf, uint8_t busyPin=0, uint8_t readerBufferSize=30)
Definition: DFPReader.cpp:27
void sendCmd(Cmd cmd, uint16_t arg=0)
bool appendElement(uint8_t value)
Definition: DFPReader.cpp:151
void begin(bool bootWait=true)
Definition: DFPReader.cpp:40
Stop playback.
Definition: DFPlayerMini.h:57
Reader is idle.
Definition: DFPReader.h:56
void begin(bool bootWait=true)
bool reading()
Definition: DFPReader.cpp:119