-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathGenericFuncs.c
456 lines (415 loc) · 21.5 KB
/
GenericFuncs.c
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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
/*********************************************************************************************
* GenericFuncs.c *
*===========================================================================================*
* Created on: Aug 28, 2016 *
* Author: eliaschr *
* (c) Elias Chrysocheris and Iraklis Rigakis *
*-------------------------------------------------------------------------------------------*
* In this file there are some generic functions used by other parts of the application. *
* They are not meant to belong to a specific task or functionality, so they lie in their *
* own file. *
* *
* DISCLAMER NOTICE: *
*------------------- *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY *
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
* THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
********************************************************************************************/
/*********************************************************************************************
* Includes *
********************************************************************************************/
#include "GenericFuncs.h"
/*********************************************************************************************
* Definitions to control the whole code behavior *
********************************************************************************************/
/*********************************************************************************************
* Constants definitions *
********************************************************************************************/
/*********************************************************************************************
* Variable definitions *
********************************************************************************************/
/*********************************************************************************************
* Function declarations *
********************************************************************************************/
/*********************************************************************************************
* Generic Helper Functions *
********************************************************************************************/
//********************************************************************************************
/*Parses a string as a hexadecimal, decimal or binary number. The default is a decimal number.
There are two functions, one for 16 bits target value and one for 32 bits target value. The
full implementation is made in 32 bits (ParseNumber32). The 16 bits variant (ParseNumber) uses
the 32 bits one and truncates the value before passing it to the target variable.
If there is a need for a hexadecimal number then there must be a prefix of '0x' to the hex
number, or a postfix of 'h'. If there are both no harm is made. In the same way a binary
number is specified by a prefix of '0b' or a postfix of 'b'. Using both does not harm the
parsing. The strings can be included in single or double quotes or even no quotes can be used.
The parsing is not case sensitive; it accepts both capital and small letters in prefix, main
number or postfix.
The input parameters are:
InStr points to the string containing the number to be parsed,
OutVal is a pointer to the target variable that receives the value parsed
The function returns the number of characters used, including the terminating ones. If there
was an error, that number is negative
*/
int8_t ParseNumber32(char* InStr, uint32_t* OutVal) {
#define NUM_BIN (1<<0) //Specifies if a possible binary number is used
#define NUM_DEC (1<<1) //Specifies if a possible decimal number is used
#define NUM_HEX (1<<2) //Specifies if a possible hex number is used
#define NUM_PREFIX (1<<3) //Found 0x prefix for hex number notation
#define NUM_POSTFIX (1<<4) //Found h postfix for hex number notation
#define NUM_MAYPRE (1<<5) //Found 0b prefix. It can be a binary number
// specifier or part of a hex number
#define NUM_MAYPOST (1<<6) //Found b postfix. It can be a binary number
// specifier or part of a hex number
int Skipped = 0; //Counts the number of characters used
uint32_t Bin = 0, //Will contain the value in dec if the input
Dec = 0, // value is in binary, decimal or hexadecimal
Hex = 0; // respectively
char Quote = *InStr; //Get the quote character
char NumFlag = NUM_DEC | NUM_HEX | NUM_BIN;
char TempChr = 0; //Current character manipulated
//Skip the first space characters (if they exist)
while(Quote == ' ') { //Need to skip space characters (if they exist)
Skipped++; //Another one character skipped
Quote = *(++InStr); //Fetch next character
}
//Find the quote character and its kind (single or double), if it is used
if((Quote != '"') && (Quote != '\'')) { //Is it a kind of quote? (single or double)
Quote = '\0'; //No => Quote is zeroed
} else { //Yes =>, Keep Quote kind
InStr++; //Skip this character, also
Skipped++; //Another one character skipped
}
//Find the prefix that defines the type of number used, if it is used, and if not, skip
// the leading 0s, if they exist
if(*InStr == '0') { //Is first 0?
InStr++; //Must check the following character to see if it
// is a prefix character
Skipped++; //Add another character in the skipped ones
TempChr = *InStr & 0xDF; //Get the character and convert it to capital
if(TempChr == 'X') { //Hex prefix?
NumFlag = NUM_HEX | NUM_PREFIX; //Then it is a hex number with prefix (no postfix
// allowed)
InStr++; //Go to next character
Skipped++; //Add another character in the list of used
} else if(TempChr == 'B') { //Bin possible prefix? (may be hex digit)
NumFlag = NUM_HEX | NUM_BIN | NUM_MAYPRE;//Perhaps hex, perhaps bin with prefix
InStr++; //Advance to next character
Skipped++; //Add another one to those used
Hex = 11; //If it is hex we must include it in accounting
} else { //else, we need to skip possible prepended 0s
while(*InStr == '0') { //Skip the first zero digits if they exist
InStr++; //Advance pointer
Skipped++; //Another skipped character
}
}
}
//Now lets parse the rest of the number (main one)
while((NumFlag & (NUM_BIN | NUM_DEC | NUM_HEX)) != 0) {
TempChr = *InStr; //Get current character
if((TempChr == 'h') || (TempChr == 'H')) {//Postfix H found
NumFlag = NUM_HEX | NUM_POSTFIX;//Flag that we found a postfix specifier for hex
TempChr = *(++InStr); //Get the new character
Skipped++; //Another character used
} else if(((TempChr == 'b') || (TempChr == 'B')) &&
((NumFlag & (NUM_PREFIX | NUM_BIN)) == NUM_BIN)) {
NumFlag |= NUM_MAYPOST; //Flag that it may be a postfix for binary
NumFlag &= ~NUM_DEC; //Cannot be a decimal number
Skipped++; //Add another character used
TempChr = *(++InStr); //Get the following character
Hex = Hex *16 + 11; //In case of a Hex number, count this in
}
if(((TempChr == Quote) && (Quote != '\0')) ||
(((TempChr <= ' ') || (TempChr == ',') || (TempChr == '.') || (TempChr == ':'))
&& (Quote == '\0'))) {
if((NumFlag & NUM_MAYPOST) != 0) {
NumFlag &= ~(NUM_HEX); //The final number is not hexadecimal
}
Skipped++; //Also count in this terminating character
break; //Normal exit, OK
} else if((NumFlag & NUM_POSTFIX) != 0){//Do we have a postfix? => Error
Skipped++; //Yes => Add this character also
NumFlag &= ~(NUM_HEX | NUM_DEC | NUM_BIN);//No type of number found
break; //Exit with error
}
NumFlag &= ~NUM_MAYPOST; //So, no postfix found
TempChr -= '0'; //Convert digit to value
if(TempChr > 1) { //Not valid binary character?
NumFlag &= ~NUM_BIN; //Exclude binary
}
if(TempChr > 9) { //Not a valid decimal character?
NumFlag &= ~NUM_DEC; //Exclude decimal
TempChr -= 7; //Convert Capital Hex digit to number
if(TempChr > 15) {
TempChr -= 32; //Convert lower case hex digit to number
}
if((TempChr < 10) || (TempChr > 15)) {//A symbol between 9 and A or above F is
// invalid
NumFlag &= ~NUM_HEX; //Also clear the hex flag
break; //Exit the loop. It is invalid digit
}
}
if((NumFlag & NUM_HEX) != 0) { //Possible hex number?
Hex = Hex *16 + TempChr; //Include current digit
}
if((NumFlag & NUM_DEC) != 0) { //Possible decimal number?
Dec = Dec *10 + TempChr; //Include current digit
}
if((NumFlag & NUM_BIN) != 0) { //Possible binary number?
Bin = Bin *2 + TempChr; //Include current digit
}
InStr++; //Go to next character to be parsed
Skipped++; //Count in another one character
}
//In case of error, no type is help, so exit
if((NumFlag & (NUM_HEX | NUM_DEC | NUM_BIN)) == 0) {
return -Skipped;
}
//Now we have to decide which numbering system to use
if((NumFlag & NUM_HEX) != 0) { //Used hexadecimal? Yes =>
if((NumFlag & (NUM_POSTFIX | NUM_PREFIX)) != 0) {//Valid if only there was a
// post/prefix
*OutVal = Hex; //Output value comes from hexadecimal number
return Skipped;
}
}
if((NumFlag & NUM_BIN) != 0) {
if((NumFlag & (NUM_MAYPRE | NUM_MAYPOST)) != 0) {
*OutVal = Bin; //Output value comes from a binary number
return Skipped;
}
}
if((NumFlag & NUM_DEC) != 0) {
if((NumFlag & (NUM_MAYPRE | NUM_PREFIX | NUM_MAYPOST | NUM_POSTFIX)) == 0) {
*OutVal = Dec; //Output value comes from a decimal number
return Skipped;
}
}
return -Skipped; //In case of error the returned number is
// negative
}
/*The 16 bits variant of this function follows.*/
int8_t ParseNumber(char* InStr, uint16_t* OutVal) {
int8_t Skipped; //Counts the number of characters used
uint32_t Result; //Will get the resulting number
Skipped = ParseNumber32(InStr, &Result);//Parse the number
*OutVal = Result & 0xFFFF; //Truncate the lower 16 bits and store them to the
// target variable
return Skipped; //Return the number of characters used
}
//********************************************************************************************
/* SkipCRLF
Counts the number of CR or LF characters needed to be skipped in order to reach the
beginning of a new line in the input buffer.
Input parameters:
InBuffer is a pointer to the buffer that will be scanned
InSize is the size of the InBuffer
Returns:
- In normal operation it returns the number of CR and LF characters found in a raw
- If there was an invalid character (not literal and not CR or LF) returns -1
- If all the characters in InBuffer are CR or LF then it returns 0 as it could never find
a normal character = a new line starting
*/
int16_t SkipCRLF(char* InBuffer, int16_t InSize) {
#define FOUNDFLG (1<<1) //Flags that one character of CRLF characters were
// found
#define FAILFLG (1<<0) //Flags that there was an invalid character in the
// input string
int16_t count; //Counter of the found characters
uint8_t flags; //Helper flags
count = 0; //Reset characters counting
flags = 0; //Reset flags
while(InSize > 0) { //Repeat until all the input string was parsed
//Does the current input character belong to a newline (CRLF) combination?
if((*InBuffer == '\r') || (*InBuffer == '\n')) { //Yes =>
flags = FOUNDFLG; //Flag the founding o a CRLF character
count++; //One more character in the CRLF sequence
InBuffer++; //Point to next character in input buffer
InSize--; //One character less till the end of input buffer
continue; //Next loop iteration
}
//Is the current input character an invalid one?
if((*InBuffer < ' ') || (*InBuffer > 0x7F)) { //Yes =>
flags = FAILFLG; //Flag the founding of a non-acceptable character
count = -1; //Going to return a negative number in order to
// notify the caller for the failure.
break; //Break the loop, going to exit
}
//If a normal character is found then the loop should break and the caller should know
// the searching is over.
flags = FOUNDFLG; //So, raise the FOUNDFLAG to notify the outer
// check that everything went fine and the loop
// was terminated due to a normal character
// finding an not because the input buffer was
// exhausted.
break; //Break the loop
}
if(flags == 0) { //Was the input line exhausted?
count = 0; //Yes => Clear the number of CRLF characters found
}
return count; //Return the number of CRLF characters found at
// the beginning of the input string
}
//********************************************************************************************
/* FindCRLF
Counts the number of characters needed to be skipped in order to find the first CR or LF
character
Input parameters:
InBuffer is a pointer to the buffer that will be scanned
InSize is the size of the InBuffer
Returns:
- In normal operation it returns the number of characters found in a raw
- If there was an invalid character (not literal and not CR or LF) returns -1
- If all the characters in InBuffer are CR or LF then it returns 0 as it could never find
a normal character = a new line starting
*/
int16_t FindCRLF(char* InBuffer, int16_t InSize) {
int16_t count; //Counter of the found characters
uint8_t flags; //Helper flags
count = 0; //Reset characters counting
flags = 0; //Reset flags
while(InSize > 0) { //Repeat until all the input string was parsed
//Does the current input character belong to a newline (CRLF) combination?
if((*InBuffer == '\r') || (*InBuffer == '\n')) { //Yes =>
flags = FOUNDFLG; //Flag the founding and ...
break; //... terminate the loop
}
//Is the current input character an invalid one?
if((*InBuffer < ' ') || (*InBuffer > 0x7F)) { //Yes =>
flags = FAILFLG; //Flag the founding of a non-acceptable character
count = -1; //Going to return a negative number in order to
// notify the caller for the failure.
break; //Break the loop, going to exit
}
//Is the current input character an normal one? then...
count++; //Count it in
InBuffer++; //Advance the pointer to the next input character
InSize--; //One character less to end
}
if(flags == 0) { //Was the input line exhausted?
count = 0; //Yes => Clear the number of characters found
}
return count; //Return the number of characters found until CRLF
// was met
}
//********************************************************************************************
/*Gets a two digit ASCII value that represents a hex byte and converts it to integer. If there
is an invalid characted, then it returns -1. The input of the function is a pointer to the two
digit hex ASCII (InVal) and the length of the hex to be interpreted, in digits (Len)*/
int16_t Hex2Int(char *InVal, uint8_t Len) {
int16_t OutVal, DigVal;
uint8_t i;
OutVal = 0; //Clear the resulting value
for(i = 0; i < Len; i++) { //Repeat for as many digits as Len defines
DigVal = InVal[i] - '0'; //Get current digit value
if(DigVal >= 10) { //Greater than 10? => Need to
DigVal -= 7; //subtract other 7 becase of '9' to 'A' ASCII gap
}
if((DigVal >= 16) || (DigVal <0)) { //Value out of bounds?
OutVal = -1; //Well... Flag the value as -1
break; //and stop interpretting more digits
}
OutVal = OutVal *16 + DigVal; //Digit OK => Include it in final calculation
}
return OutVal; //Return the converted value
}
//********************************************************************************************
/*Converts an integer number to ASCII string in a target buffer. The size of the buffer is
specified by BufLen in order not to have buffer overflow situations. The return value is the
number of digits converted. No terminating character ('\0') is inserted in the target buffer.
The converted string appears at the last cells of the target buffer.
Tip on usage: Since we have an integer (16 bits), a buffer of 6 characters (indexed 0 to 5) is
enough. By calling this function with BufLen equal to real_buffer_length -1, in our example 5,
and placing the terminating character in the last position of the buffer (in our example
Buffer[5] = '\0'), then upon return of this function the string that can be used starts at
position (real_buffer_length* -1 -return_value) = (BufLen -return_value). Lets see a coding
example:
int TempInt = 1352; //Value to be converted
char* Buffer[6]; //Storage buffer of target string
Buffer[5] = '\0'; //Last Buffer cell is the terminating character
int i = Int2Ascii(TempInt, Buffer, 5); //Convert TempInt to string in Buffer. Returns 4
print(&Buffer[5 -i]); //prints the string of 4 characters + 1 the
// terminating one, from position 1 of Buffer and
// not position 0!
*/
int16_t Int2Ascii(int16_t InVal, char* Buffer, int16_t BufLen) {
int16_t j = BufLen; //Starting position in target buffer is its final
// cell
do {
j--; //One more digit in buffer
Buffer[j] = (InVal %10) + '0'; //Store the last digit (Less Significant one)
InVal /= 10; //Divide the value by 10 to discard the last digit
} while((InVal > 0) && (j >= 0)); //Repeat as long as the value contains more digits
// and the buffer contains more empty cells
return (BufLen -j); //Return the number of characters used in target
// buffer
}
//********************************************************************************************
/*Finds the string size, in characters. The string is composed of normal ASCII characters from
space character to 0x7F. All other characters are considered as string termination. The return
value is the pure number of characters in the string, without the terminating one.
*/
uint16_t StrSize(char* InStr) {
uint16_t counter;
counter = 0;
while((InStr[counter] >= ' ') && (InStr[counter] <= 0x7F)) {
counter++;
}
return counter;
}
//********************************************************************************************
/*Calculates CRC16 of data. The polynomial used is (x^16 +x^15 +x^2 +1). If another polynomial
is needed, it can be changed through the CRC16_POLY definition. When the checksum calculation
is started, the input parameter OldCRC should be DEF_CRC16 which is defined as all bits set
(0xFFFF).
Input:
InByte: is the byte to be included in the CRC16 checksum
OldCRC: is the old CRC16 value calculated for the previous bytes. If InByte is the first
one in the series of bytes that needed to be included in CRC16, then OlCRC should be
equal to DEF_CRC16
Returns: the new CRC16 value
Example of usage:
uint16_t CRC16Value;
uint8_t i;
CRC16Value = DEF_CRC16;
for(i = 0; i < sizeof(ArrayOfBytesForCRC); i++) {
CRC16Value = CalcCRC16( ArrayOfBytesForCRC[i], CRC16Value);
}
//Now CRC16Value contains the CRC16 checksum of all bytes in array ArrayOfBytesForCRC
*/
uint16_t CalcCRC16(uint8_t InByte, uint16_t OldCRC) {
uint8_t i; //Counter for bits of InByte
for(i = 0; i < 8; i++) {
if(((OldCRC & 0x8000) >> 8) ^ (OldCRC & 0x80)) {
OldCRC = (OldCRC << 1) ^ CRC16_POLY;
} else {
OldCRC = OldCRC << 1;
}
OldCRC <<= 1;
}
return OldCRC;
}
//********************************************************************************************
/*Converts the byte value of the input to a string of two hex characters that represent the
input value in Hex format. The input of the function is the byte value to be converted (InVal)
and a pointer to the two digit hex ASCII buffer that will hold the resulting string. No
termination '\0' is appended, thus the resulting string is always two characters long.*/
void Byte2Hex(uint8_t InVal, char *OutStr) {
uint8_t tempVal;
tempVal = (InVal >> 4);
if(tempVal > 9) {
tempVal += 7;
}
OutStr[0] = tempVal +0x30;
tempVal = InVal & 0x0F;
if(tempVal > 9) {
tempVal += 7;
}
OutStr[1] = tempVal +0x30;
}