rusEFI
The most advanced open source ECU
efilib.cpp
Go to the documentation of this file.
1 /**
2  * @file efilib.cpp
3  *
4  * We cannot use stdlib because we do not have malloc - so, we have to implement these functions
5  *
6  * @date Feb 21, 2014
7  * @author Andrey Belomutskiy, (c) 2012-2020
8  */
9 
10 #include "pch.h"
11 
12 #include <string.h>
13 #include <math.h>
14 #include "datalogging.h"
15 #include "histogram.h"
16 
17 // also known as bool2string and boolean2string
18 const char * boolToString(bool value) {
19  return value ? "Yes" : "No";
20 }
21 
22 /*
23 float efiFloor(float value, float precision) {
24  int a = (int) (value / precision);
25  return a * precision;
26 }
27 */
28 
29 /**
30  *
31  * @param precision for example '0.1' for one digit fractional part
32  */
33 float efiRound(float value, float precision) {
34  efiAssert(ObdCode::CUSTOM_ERR_ASSERT, precision != 0, "zero precision", NAN);
35  float a = round(value / precision);
36  return fixNegativeZero(a * precision);
37 }
38 
39 char * efiTrim(char *param) {
40  while (param[0] == ' ') {
41  param++; // that would skip leading spaces
42  }
43  int len = efiStrlen(param);
44  while (len > 0 && param[len - 1] == ' ') {
45  param[len - 1] = 0;
46  len--;
47  }
48  return param;
49 }
50 
51 bool startsWith(const char *line, const char *prefix) {
52  uint32_t len = efiStrlen(prefix);
53  if (efiStrlen(line) < len) {
54  return false;
55  }
56  for (uint32_t i = 0; i < len; i++) {
57  if (line[i] != prefix[i]) {
58  return false;
59  }
60  }
61  return true;
62 }
63 
64 static char *ltoa_internal(char *p, uint32_t num, unsigned radix) {
65  constexpr int bufferLength = 10;
66 
67  char buffer[bufferLength];
68 
69  size_t idx = bufferLength - 1;
70 
71  // First, we write from right-to-left so that we don't have to compute
72  // log(num)/log(radix)
73  do
74  {
75  auto digit = num % radix;
76 
77  // Digits 0-9 -> '0'-'9'
78  // Digits 10-15 -> 'a'-'f'
79  char c = digit < 10
80  ? digit + '0'
81  : digit + 'a' - 10;
82 
83  // Write this digit in to the buffer
84  buffer[idx] = c;
85  idx--;
86  } while ((num /= radix) != 0);
87 
88  idx++;
89 
90  // Now, we copy characters in to place in the final buffer
91  while (idx < bufferLength)
92  {
93  *p++ = buffer[idx++];
94  }
95 
96  return p;
97 }
98 
99 /**
100  * @return pointer at the end zero symbol after the digits
101  */
102 static char* itoa_signed(char *p, int num, unsigned radix) {
103  if (num < 0) {
104  *p++ = '-';
105  char *end = ltoa_internal(p, -num, radix);
106  *end = 0;
107  return end;
108  }
109  char *end = ltoa_internal(p, num, radix);
110  *end = 0;
111  return end;
112 }
113 
114 /**
115  * Integer to string
116  *
117  * @return pointer at the end zero symbol after the digits
118  */
119 char* itoa10(char *p, int num) {
120  return itoa_signed(p, num, 10);
121 }
122 
123 int efiPow10(int param) {
124  switch (param) {
125  case 0:
126  return 1;
127  case 1:
128  return 10;
129  case 2:
130  return 100;
131  case 3:
132  return 1000;
133  case 4:
134  return 10000;
135  case 5:
136  return 100000;
137  case 6:
138  return 1000000;
139  case 7:
140  return 10000000;
141  case 8:
142  return 100000000;
143  }
144  return 10 * efiPow10(10 - 1);
145 }
146 
147 /*
148 ** return lower-case of c if upper-case, else c
149 */
150 int mytolower(const char c) {
151  return TO_LOWER(c);
152 }
153 
154 int djb2lowerCase(const char *str) {
155  unsigned long hash = 5381;
156  int c;
157 
158  while ( (c = *str++) ) {
159  c = TO_LOWER(c);
160  hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
161  }
162 
163  return hash;
164 }
165 
166 /**
167  * @brief This function knows how to print a histogram_s summary
168  */
169 void printHistogram(Logging *logging, histogram_s *histogram) {
170 #if EFI_HISTOGRAMS && ! EFI_UNIT_TEST
171  int report[5];
172  int len = hsReport(histogram, report);
173 
174  logging->reset();
175  logging.append(PROTOCOL_MSG LOG_DELIMITER);
176  logging.appendPrintf("histogram %s *", histogram->name);
177  for (int i = 0; i < len; i++)
178  logging.appendPrintf("%d ", report[i]);
179  logging.appendPrintf("*");
180  logging.append(LOG_DELIMITER);
181  scheduleLogging(logging);
182 #else
183  UNUSED(logging);
184  UNUSED(histogram);
185 
186 #endif /* EFI_HISTOGRAMS */
187 }
188 
189 float limitRateOfChange(float newValue, float oldValue, float incrLimitPerSec, float decrLimitPerSec, float secsPassed) {
190  if (newValue >= oldValue)
191  return (incrLimitPerSec <= 0.0f) ? newValue : oldValue + minF(newValue - oldValue, incrLimitPerSec * secsPassed);
192  return (decrLimitPerSec <= 0.0f) ? newValue : oldValue - minF(oldValue - newValue, decrLimitPerSec * secsPassed);
193 }
194 
195 bool isPhaseInRange(float test, float current, float next) {
196  bool afterCurrent = test >= current;
197  bool beforeNext = test < next;
198 
199  if (next > current) {
200  // we're not near the end of the cycle, comparison is simple
201  // 0 |------------------------| 720
202  // next current
203  return afterCurrent && beforeNext;
204  } else {
205  // we're near the end of the cycle so we have to check the wraparound
206  // 0 -----------| |------ 720
207  // next current
208  // Check whether test is after current (ie, between current tooth and end of cycle)
209  // or if test if before next (ie, between start of cycle and next tooth)
210  return afterCurrent || beforeNext;
211  }
212 }
213 
214 static int getBitRangeCommon(const uint8_t data[], int bitIndex, int bitWidth, int secondByteOffset) {
215  int byteIndex = bitIndex >> 3;
216  int shift = bitIndex - byteIndex * 8;
217  int value = data[byteIndex];
218  if (shift + bitWidth > 8) {
219  value = value + data[secondByteOffset + byteIndex] * 256;
220  }
221  int mask = (1 << bitWidth) - 1;
222  return (value >> shift) & mask;
223 }
224 
225 // see also getBitRange in lua_lib.h
226 int getBitRangeLsb(const uint8_t data[], int bitIndex, int bitWidth) {
227  return getBitRangeCommon(data, bitIndex, bitWidth, 1);
228 }
229 
230 // see also getBitRangeMsb in lua_lib.h
231 int getBitRangeMsb(const uint8_t data[], int bitIndex, int bitWidth) {
232  return getBitRangeCommon(data, bitIndex, bitWidth, -1);
233 }
void appendPrintf(const char *fmt,...)
Definition: datalogging.cpp:80
void reset()
Buffered console output stream header.
char * itoa10(char *p, int num)
Definition: efilib.cpp:119
float limitRateOfChange(float newValue, float oldValue, float incrLimitPerSec, float decrLimitPerSec, float secsPassed)
Definition: efilib.cpp:189
int djb2lowerCase(const char *str)
Definition: efilib.cpp:154
bool startsWith(const char *line, const char *prefix)
Definition: efilib.cpp:51
char * efiTrim(char *param)
Definition: efilib.cpp:39
static int getBitRangeCommon(const uint8_t data[], int bitIndex, int bitWidth, int secondByteOffset)
Definition: efilib.cpp:214
static char * itoa_signed(char *p, int num, unsigned radix)
Definition: efilib.cpp:102
bool isPhaseInRange(float test, float current, float next)
Definition: efilib.cpp:195
float efiRound(float value, float precision)
Definition: efilib.cpp:33
void printHistogram(Logging *logging, histogram_s *histogram)
This function knows how to print a histogram_s summary.
Definition: efilib.cpp:169
const char * boolToString(bool value)
Definition: efilib.cpp:18
static char * ltoa_internal(char *p, uint32_t num, unsigned radix)
Definition: efilib.cpp:64
int mytolower(const char c)
Definition: efilib.cpp:150
int getBitRangeLsb(const uint8_t data[], int bitIndex, int bitWidth)
Definition: efilib.cpp:226
int efiPow10(int param)
Definition: efilib.cpp:123
int getBitRangeMsb(const uint8_t data[], int bitIndex, int bitWidth)
Definition: efilib.cpp:231
union test_buffers test
Definition: test.c:50
int hsReport(histogram_s *h, int *report)
Prepare histogram report.
Definition: histogram.cpp:116
This data structure is used to analyze CPU performance.
UNUSED(samplingTimeSeconds)
void scheduleLogging(Logging *logging)
@ CUSTOM_ERR_ASSERT
char name[16]
Definition: histogram.h:28
static BigBufferHandle buffer
static tstrWifiInitParam param