-
Notifications
You must be signed in to change notification settings - Fork 0
/
Util.cpp
193 lines (169 loc) · 6.96 KB
/
Util.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
/**The MIT License (MIT)
Copyright (c) 2017 by Jared Gaillard
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
extern unsigned int __bss_end;
extern unsigned int __heap_start;
extern void *__brkval;
#include "Util.h"
#include <Wire.h>
#include <time.h>
// Anything worse than or equal to this will show 0 bars.
#define MIN_RSSI -100
// Anything better than or equal to this will show the max bars.
#define MAX_RSSI -55
/**
Calculates the level of the signal. This should be used any time a signal
is being shown.
@param rssi The power of the signal measured in RSSI.
@param numLevels The number of levels to consider in the calculated
level.
@return A level of the signal, given in the range of 0 to numLevels-1
(both inclusive).
*/
int Util::calculateSignalLevel(int rssi, int numLevels) {
if (rssi <= MIN_RSSI) {
return 0;
} else if (rssi >= MAX_RSSI) {
return numLevels - 1;
} else {
float inputRange = (MAX_RSSI - MIN_RSSI);
float outputRange = (numLevels - 1);
return (int)((float)(rssi - MIN_RSSI) * outputRange / inputRange);
}
}
String Util::getTime(time_t *timestamp) {
struct tm *timeInfo = gmtime(timestamp);
char buf[6];
sprintf(buf, "%02d:%02d", timeInfo->tm_hour, timeInfo->tm_min);
return String(buf);
}
long Util::time2long(uint16_t days, uint8_t h, uint8_t m, uint8_t s) {
return ((days * 24L + h) * 60 + m) * 60 + s;
}
String Util::formatTime(DateTime dateTime, bool hour24, bool ampm) {
return formatTime(dateTime.hour(), dateTime.minute(), hour24, ampm);
}
String Util::formatTime(int hour, int minute, bool hour24, bool ampm) {
char timeText[20];
bool isPM = false;
if (!hour24) {
if (hour == 0)
hour = 12;
else if ( hour > 12) {
isPM = true;
hour -= 12;
}
if (ampm) {
sprintf_P(timeText, PSTR("%d:%02d%s"), hour, minute, isPM ? "pm" : "am");
}
else {
sprintf_P(timeText, PSTR("%d:%02d"), hour, minute);
}
}
else {
sprintf_P(timeText, (char *) F("%d:%02d"), hour, minute);
}
return String(timeText);
}
String Util::formatTime(int hour, int minute, int second) {
char timeText[20];
sprintf_P(timeText, "%d:%02d:%02d", hour, minute, second);
return String(timeText);
}
void Util::clearBusI2C() {
int rtn = I2C_ClearBus(); // clear the I2C bus first before calling Wire.begin()
if (rtn != 0) {
Sprintln(F("I2C bus error. Could not clear"));
if (rtn == 1) {
Sprintln(F("SCL clock line held low"));
} else if (rtn == 2) {
Sprintln(F("SCL clock line held low by slave clock stretch"));
} else if (rtn == 3) {
Sprintln(F("SDA data line held low"));
}
} else { // bus clear
// re-enable Wire
// now can start Wire Arduino master
Wire.begin();
}
}
/**
This routine turns off the I2C bus and clears it
on return SCA and SCL pins are tri-state inputs.
You need to call Wire.begin() after this to re-enable I2C
This routine does NOT use the Wire library at all.
returns 0 if bus cleared
1 if SCL held low.
2 if SDA held low by slave clock stretch for > 2sec
*/
int Util::I2C_ClearBus() {
#if defined(TWCR) && defined(TWEN)
TWCR &= ~(_BV(TWEN)); //Disable the Atmel 2-Wire interface so we can control the SDA and SCL pins directly
#endif
pinMode(SDA, INPUT_PULLUP); // Make SDA (data) and SCL (clock) pins Inputs with pullup.
pinMode(SCL, INPUT_PULLUP);
delay(2500); // Wait 2.5 secs. This is strictly only necessary on the first power
// up of the DS3231 module to allow it to initialize properly,
// but is also assists in reliable programming of FioV3 boards as it gives the
// IDE a chance to start uploaded the program
// before existing sketch confuses the IDE by sending Serial data.
boolean SCL_LOW = (digitalRead(SCL) == LOW); // Check is SCL is Low.
if (SCL_LOW) { //If it is held low Arduno cannot become the I2C master.
return 1; //I2C bus error. Could not clear SCL clock line held low
}
boolean SDA_LOW = (digitalRead(SDA) == LOW); // vi. Check SDA input.
int clockCount = 20; // > 2x9 clock
while (SDA_LOW && (clockCount > 0)) { // vii. If SDA is Low,
clockCount--;
// Note: I2C bus is open collector so do NOT drive SCL or SDA high.
pinMode(SCL, INPUT); // release SCL pullup so that when made output it will be LOW
pinMode(SCL, OUTPUT); // then clock SCL Low
delayMicroseconds(10); // for >5uS
pinMode(SCL, INPUT); // release SCL LOW
pinMode(SCL, INPUT_PULLUP); // turn on pullup resistors again
// do not force high as slave may be holding it low for clock stretching.
delayMicroseconds(10); // for >5uS
// The >5uS is so that even the slowest I2C devices are handled.
SCL_LOW = (digitalRead(SCL) == LOW); // Check if SCL is Low.
int counter = 20;
while (SCL_LOW && (counter > 0)) { // loop waiting for SCL to become High only wait 2sec.
counter--;
delay(100);
SCL_LOW = (digitalRead(SCL) == LOW);
}
if (SCL_LOW) { // still low after 2 sec error
return 2; // I2C bus error. Could not clear. SCL clock line held low by slave clock stretch for >2sec
}
SDA_LOW = (digitalRead(SDA) == LOW); // and check SDA input again and loop
}
if (SDA_LOW) { // still low
return 3; // I2C bus error. Could not clear. SDA data line held low
}
// else pull SDA line low for Start or Repeated Start
pinMode(SDA, INPUT); // remove pullup.
pinMode(SDA, OUTPUT); // and then make it LOW i.e. send an I2C Start or Repeated start control.
// When there is only one I2C master a Start or Repeat Start has the same function as a Stop and clears the bus.
/// A Repeat Start is a Start occurring after a Start with no intervening Stop.
delayMicroseconds(10); // wait >5uS
pinMode(SDA, INPUT); // remove output low
pinMode(SDA, INPUT_PULLUP); // and make SDA high i.e. send I2C STOP control.
delayMicroseconds(10); // x. wait >5uS
pinMode(SDA, INPUT); // and reset pins as tri-state inputs which is the default state on reset
pinMode(SCL, INPUT);
return 0; // all ok
}