diff --git a/Examples/StreamOverSocket/.gitignore b/Examples/StreamOverSocket/.gitignore new file mode 100644 index 0000000..2dff2f0 --- /dev/null +++ b/Examples/StreamOverSocket/.gitignore @@ -0,0 +1 @@ +cmake-build-debug diff --git a/Examples/StreamOverSocket/.idea/.gitignore b/Examples/StreamOverSocket/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/Examples/StreamOverSocket/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/Examples/StreamOverSocket/.idea/misc.xml b/Examples/StreamOverSocket/.idea/misc.xml new file mode 100644 index 0000000..4619d2b --- /dev/null +++ b/Examples/StreamOverSocket/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/Examples/StreamOverSocket/.idea/modules.xml b/Examples/StreamOverSocket/.idea/modules.xml new file mode 100644 index 0000000..95a2860 --- /dev/null +++ b/Examples/StreamOverSocket/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/Examples/StreamOverSocket/.idea/serialPort.iml b/Examples/StreamOverSocket/.idea/serialPort.iml new file mode 100644 index 0000000..f08604b --- /dev/null +++ b/Examples/StreamOverSocket/.idea/serialPort.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Examples/StreamOverSocket/.idea/vcs.xml b/Examples/StreamOverSocket/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/Examples/StreamOverSocket/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Examples/StreamOverSocket/CMakeLists.txt b/Examples/StreamOverSocket/CMakeLists.txt new file mode 100644 index 0000000..0b2a06a --- /dev/null +++ b/Examples/StreamOverSocket/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.25) +project(serialPort C) + +set(CMAKE_C_STANDARD 11) +#set(ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(SOURCES + main.c + uart_sock.c + userCodes.c + Str/Str.c + Stream/StreamBuffer.c + Stream/UARTStream.c + Stream/buffer.c + Stream/OutputStream.c + Stream/InputStream.c + arduino/arduino.c + ) + +#target_include_directories(${PROJECT_NAME} PRIVATE ${ROOT_DIR} ${ROOT_DIR}/Stream ${ROOT_DIR}/Str) +include_directories(parser Str Stream arduino ec200) +add_executable(serialPort ${SOURCES}) + +if (WIN32) + target_link_libraries(${PROJECT_NAME} PRIVATE ws2_32) +endif () \ No newline at end of file diff --git a/Examples/StreamOverSocket/README.md b/Examples/StreamOverSocket/README.md new file mode 100644 index 0000000..7a2a7ca --- /dev/null +++ b/Examples/StreamOverSocket/README.md @@ -0,0 +1 @@ +# StreamOverSocket diff --git a/Examples/StreamOverSocket/Str/Str.c b/Examples/StreamOverSocket/Str/Str.c new file mode 100644 index 0000000..ca291c1 --- /dev/null +++ b/Examples/StreamOverSocket/Str/Str.c @@ -0,0 +1,2270 @@ +#include "Str.h" + +#if STR_USE_STRING_LIBRARY + #include +#endif + +/** + * variables + **/ + +#if STR_USE_CONST_VARIABLES + const Str_Radix __Str_Decimal = Str_Decimal; + const char __Str_0 = '0'; + const char __Str_9 = '9'; + const char __Str_Zero = 0; + const char __Str_One = 1; + const char __Str_Null = '\0'; + const Str_LenType __Str_MaxLength = STR_MAX_LENGTH; +#else + #define __Str_Decimal Str_Decimal + #define __Str_MaxLength STR_MAX_LENGTH + #define __Str_0 '0' + #define __Str_9 '9' + #define __Str_Zero 0 + #define __Str_One 1 + #define __Str_Null '\0' +#endif // STR_USE_CONST_VARIABLES + +#ifndef NULL + #define NULL ((const void*) 0) +#endif + + +/** + * @brief this Function can use for copy array into another array with reverse order + * + * @param src address of source array that we want copy from + * @param dest address of destination array that we want copy into + * @param len number of bytes + * @return void* address of destination array + */ +void* Mem_copyReverse(void* dest, const void* src, Mem_LenType len) { + unsigned char* pD = (unsigned char*) dest; + unsigned char* pS = (unsigned char*) src + (len - 1); + while (len-- > 0){ + *pD++ = *pS--; + } + return dest; +} +/** + * @brief reverse order of bytes in array + * + * @param arr address of array that we want reverse order + * @param len number of byte + * @return void* address of array + */ +void* Mem_reverse(void* arr, Mem_LenType len) { + unsigned char* pStart = (unsigned char*) arr; + unsigned char* pEnd = &((unsigned char*)arr)[len - 1]; + unsigned char temp; + len >>= 1; + while (len-- > 0){ + temp = *pEnd; + *pEnd-- = *pStart; + *pStart++ = temp; + } + return arr; +} +/** + * @brief this function return address of last character + * + * @param str + * @return + */ +char* Str_indexOfEnd(const char* str) { + Str_LenType len = Str_len(str); + if (len) { + return (char*) &str[len - 1]; + } + else { + return NULL; + } +} +/** + * @brief this function return end of string (Null character) + * + * @param str address of string must include 'null' in end of it + * @return char* address of null character + */ +char* Str_indexOfNull(const char* str) { + Str_LenType len = Str_len(str); + if (len) { + return (char*) &str[len]; + } + else { + return NULL; + } +} +/** + * @brief compare two string and result is opposite of Str_compare + * + * @param str1 address of string 1 + * @param str2 address of string 2 + * @return char result of compare, + * str1 > str2 -> result < 0 + * str1 == str2 -> result == 0 + * str1 < str2 -> result > 0 + */ +char Str_compareInverse(const char* str1, const char* str2) { + return Str_compare(str2, str1); +} +/** + * @brief compare word in str, with priority of word and continue until word reach null + * + * @param str address of base string + * @param word address of word that we want compare with str + * @return char result of compare, + * str > word -> result > 0 + * str == word -> result == 0 + * str < word -> result < 0 + */ +char Str_compareWord(const char* str, const char* word) { + char res; + while (*word != __Str_Null){ + res = *str++ - *word++; + if (res != 0){ + break; + } + } + return res; +} +/** + * @brief find first digit in string and return address of digit + * + * @param str address of string + * @return char* address of digit in str, return null if nothing found + */ +char* Str_findDigit(const char* str) { + while ((*str < __Str_0 || *str > __Str_9) && + *str != __Str_Null){ + str++; + } + return *str == __Str_Null ? NULL : (char*) str; +} +/** + * @brief find first digit in string and return address of digit, keep search until reach null or reach end charachter + * + * @param str address of string + * @param endChar ending character + * @return char* address of digit in str, return null if nothing found + */ +char* Str_findDigitUntil(const char* str, char endChar) { + while ((*str < __Str_0 || *str > __Str_9) && + *str != __Str_Null && + *str != endChar){ + str++; + } + return *str == __Str_Null || *str == endChar ? NULL : (char*) str; +} +/** + * @brief find first digit in string and return address of digit, keep search until reach null or pass the length limit + * + * @param str address of string + * @param len length of string + * @return char* address of digit in str, return null if nothing found + */ +char* Str_findDigitFix(const char* str, Str_LenType len) { + while ((*str < __Str_0 || *str > __Str_9) && + *str != __Str_Null && + len-- > 0){ + str++; + } + return *str == __Str_Null || len == 0 ? NULL : (char*) str; +} +/** + * @brief find a number and return last digit of it + * + * @param str address of string + * @return char* address of digit in str, return null if nothing found + */ +char* Str_findLastDigit(const char* str) { + str = Str_findDigit(str); + if (str != NULL) { + while (*str >= __Str_0 && *str <= __Str_9){ + str++; + } + str--; + } + return (char*) str; +} +/** + * @brief find a number and return last digit of it with ending charachter condition + * + * @param str address of string + * @param endChar ending charachter + * @return char* address of digit in str, return null if nothing found + */ +char* Str_findLastDigitUntil(const char* str, char endChar) { + str = Str_findDigitUntil(str, endChar); + if (str != NULL) { + while (*str >= __Str_0 && *str <= __Str_9){ + str++; + } + str--; + } + return (char*) str; +} +/** + * @brief find a number and return last digit of it with length condition + * + * @param str address of string + * @param len length of string + * @return char* address of digit in str, return null if nothing found + */ +char* Str_findLastDigitFix(const char* str, Str_LenType len) { + str = Str_findDigitFix(str, len); + if (str != NULL) { + while (*str >= __Str_0 && *str <= __Str_9){ + str++; + } + str--; + } + return (char*) str; +} +/** + * @brief find digit from end of string in backward + * + * @param str address of string, must include null + * @return char* address of digit in str, return null if nothing found + */ +char* Str_findReverseDigit(const char* str) { + return Str_findReverseDigitFix(str, Str_len(str)); +} +/** + * @brief find digit from end of string in backward with fixed string length + * + * @param str address of string + * @param len lenght of string + * @return char* address of digit in str, return null if nothing found + */ +char* Str_findReverseDigitFix(const char* str, Str_LenType len) { + str = &str[len - 1]; + while ((*str < __Str_0 || *str > __Str_9) && + len-- > 0){ + str--; + } + return *str == __Str_Null || len == 0 ? NULL : (char*) str; +} +/** + * @brief find multiple indexes of 'c' in string + * + * @param str address of strings + * @param c charachter that we want search for indexes + * @param indexes a pointer array that will hold our indexes + * @return Str_LenType number of indexes that found + */ +Str_LenType Str_indexesOf(const char* str, char c, char const** indexes) { + Str_LenType count = 0; + while (*str != __Str_Null){ + if (c == *str){ + *indexes++ = str; + count++; + } + str++; + } + return count; +} +/** + * @brief find multiple indexes of 'c' in string until reach null or pass the limit + * + * @param str address of strings + * @param c charachter that we want search for indexes + * @param indexes a pointer array that will hold our indexes + * @param len lenght of string + * @return Str_LenType number of indexes that found + */ +Str_LenType Str_indexesOfFix(const char* str, char c, char const** indexes, Str_LenType len) { + Str_LenType count = 0; + while (*str != __Str_Null && len-- > 0){ + if (c == *str){ + *indexes++ = str; + count++; + } + str++; + } + return count; +} +/** + * @brief find multiple indexes of 'c' in string until reach null or ending charachter + * + * @param str address of strings + * @param c charachter that we want search for indexes + * @param indexes a pointer array that will hold our indexes + * @param endChar ending charachter + * @return Str_LenType number of indexes that found + */ +Str_LenType Str_indexesOfUntil(const char* str, char c, char const** indexes, char endChar) { + Str_LenType count = 0; + while (*str != __Str_Null && *str != endChar){ + if (c == *str){ + *indexes++ = str; + count++; + } + str++; + } + return count; +} +/** + * @brief This Fntion finds the address of a character in a given number and returns the last one + * + * @param str address of string + * @param c charachter that we want to search + * @param num The number of times the Fuction looks for a character, must greater than 0 + * @return char* address of charachter, return null if not found + */ +char* Str_indexOfAt(const char* str, char c, Str_LenType num) { + if (str != NULL) { + if (num > 0) { + while ((str = Str_indexOf(str, c)) != NULL && --num > 0) { + str = str + 1; + } + } + return (char*) str; + } + else { + return NULL; + } +} +/** + * @brief This Fntion finds the address of a character in a given number and returns the last one until reach null or ending charachter + * + * @param str address of string + * @param c charachter that we want to search + * @param num The number of times the Fntion looks for a character + * @param end ending charachter + * @return char* address of charachter, return null if not found + */ +char* Str_indexOfAtUntil(const char* str, char c, Str_LenType num, char end) { + return Str_indexOfAtFix(str, c, num, Str_posOf(str, end)); +} +/** + * @brief This Fntion finds the address of a character in a given number and returns the last one until reach null or pass the limit + * + * @param str address of string + * @param c charachter that we want to search + * @param num The number of times the Fntion looks for a character + * @param len length of string + * @return char* address of charachter, return null if not found + */ +char* Str_indexOfAtFix(const char* str, char c, Str_LenType num, Str_LenType len) { + char* temp = NULL; + while (num-- > 0) { + temp = Mem_indexOf(str, c, len); + if (!temp) { + break; + } + len -= temp - str; + str = temp; + } + return temp; +} + +char* Str_reverseIndexOf(const char* str, char c, const char* startOfStr) { + while (startOfStr <= str) { + if (*str == c) { + return (char*) str; + } + str--; + } + return NULL; +} + +char* Str_reverseIndexOfFix(const char* str, char c, int length) { + while (length-- > 0) { + if (*str == c) { + return (char*) str; + } + str--; + } + return NULL; +} + +/** + * @brief revesre order of charachter in string + * + * @param str address of string + * @return char* address of str + */ +char* Str_reverse(char* str) { + return Mem_reverse(str, Str_len(str)); +} +/** + * @brief copy source string in reverse order into destination string + * + * @param src address of source string + * @param dest address of destination string + * @return char* address of dest + */ +char* Str_copyReverse(char* dest, const char* src) { + Mem_LenType len = Str_len(src); + Mem_copyReverse(dest, src, len); + dest[len] = __Str_Null; + return dest; +} +/** + * @brief copy a string into dest from given start position + * + * @param str address of base string + * @param dest address of destination string + * @param start Copy start location + * @return char* address of dest + */ +char* Str_substr(char* dest, const char* str, Str_LenType start) { + return Str_copy(dest, &str[start]); +} +/** + * @brief copy a string into dest from given start position + * + * @param str address of base string + * @param dest address of destination string + * @param start Copy start location + * @param len length of characters to be copy + * @return char* address of dest + */ +char* Str_substrFix(char* dest, const char* str, Str_LenType start, Str_LenType len) { + Str_copyFix(dest, &str[start], len); + dest[len] = __Str_Null; + return dest; +} +/** + * @brief copy a string into dest from given start position until reach ending charachter + * + * @param str address of base string + * @param dest address of destination string + * @param start Copy start location + * @param endChar ending charachter + * @return char* address of dest + */ +char* Str_substrUntil(char* dest, const char* str, Str_LenType start, char endChar) { + Str_LenType len = Str_posOf(str, endChar); + Str_copyFix(dest, &str[start], len); + dest[len] = __Str_Null; + return dest; +} +/** + * @brief replace first word that find in string with a another word + * + * @param str address of string + * @param word addres of word + * @param replacement address of replacement + * @return char* return address of str if word found otherwise return null + */ +char* Str_replace(char* str, const char* word, const char* replacement) { + char* pWord = Str_indexOfStr(str, word); + if (pWord != NULL) { + Str_LenType wordLen = Str_len(word); + Str_LenType repLen = Str_len(replacement); + if (wordLen != repLen) { + char* pEndOfWord = pWord + wordLen; + int len = (Str_LenType) ((char*) Mem_indexOf(pEndOfWord, __Str_Null, __Str_MaxLength) - pEndOfWord) + 1; + Mem_move(pEndOfWord + (repLen - wordLen), pEndOfWord, len); + } + Str_copyFix(pWord, replacement, repLen); + return pWord; + } + return NULL; +} +/** + * @brief replace all words that find in string with a replacement word + * + * @param str address of string + * @param word addres of word + * @param replacement address of replacement + * @return char* return address of str if word found otherwise return null + */ +int Str_replaceAll(char* str, const char* word, const char* replacement) { + int count = 0; + int replacementLen = Str_len(replacement); + while ((str = Str_replace(str, word, replacement)) != NULL) { + str = str + replacementLen; + count++; + } + return count; +} +/** + * @brief copy sourc string into destination string until reach ending char + * + * @param src address of source string + * @param dest address of destination string + * @param endChar ending character + * @return char* return null if source not contain ending character otherwise return destination + */ +char* Str_copyUntil(char* dest, const char* src, char endChar) { + char* pStr = Str_indexOf(src, endChar); + if (pStr != NULL){ + Str_LenType len = (Str_LenType) (pStr - src); + Str_copyFix(dest, src, len); + dest[len] = __Str_Null; + return dest; + } + return pStr; +} +/** + * @brief read a line form source and copy it into destination + * + * @param src address of source string + * @param dest address of destination string + * @return char* return null if source not contain ending character otherwise return destination + */ +char* Str_copyLine(char* dest, const char* src) { + return Str_copyUntil(dest, src, '\n'); +} +/** + * @brief sort array of strings with selection sort algorithm + * + * @param strs array of strings + * @param len length of array + * @return char** return address of strs + */ +const char** Str_sort(const char** strs, Str_LenType len) { + return Str_selectionSortBlock(strs, (Mem_LenType) len, (Str_CompareFn) Str_compare); +} +/** + * @brief sort array of strings with quick sort algorithm + * + * @param strs array of strings + * @param len length of array + * @return const char** return address of strs + */ +const char** Str_quickSort(const char** strs, Str_LenType len) { + return Str_quickSortBlock(strs, 0, (Mem_LenType) len - 1, (Str_CompareFn) Str_compare); +} +/** + * @brief sort array of strings in reverse order, use selection sort algorithm + * + * @param strs array of strings + * @param len length of array + * @return char** return address of strs + */ +const char** Str_sortReverse(const char** strs, Str_LenType len) { + return Str_selectionSortBlock(strs, (Mem_LenType) len, (Str_CompareFn) Str_compareInverse); +} +/** + * @brief sort array of strings in reverse order, use quick sort algorithm + * + * @param strs array of strings + * @param len length of array + * @return char** return address of strs + */ +const char** Str_quickSortReverse(const char** strs, Str_LenType len) { + return Str_quickSortBlock(strs, 0, (Mem_LenType) len - 1, (Str_CompareFn) Str_compareInverse); +} +/** + * @brief Split string into 2D character array + * + * @param src address of string + * @param separator separator character + * @param strs address of 2D array + * @param rowLen length of each row + * @param len length of rows + * @return Str_LenType return number of strs found + */ +Str_LenType Str_split(const char* src, char separator, char* strs, Str_LenType rowLen, Str_LenType len) { + Str_LenType count = 0; + Str_LenType tmpLen; + char* end; + + // for null character + rowLen--; + + if (*src != __Str_Null) { + while ((end = Str_indexOf(src, separator)) != NULL && len-- > 0) { + tmpLen = (Str_UNum)(end - src); + // check it's enough space for string + if (rowLen < tmpLen) { + tmpLen = rowLen; + } + Str_copyFix(strs, src, tmpLen); + strs[tmpLen] = __Str_Null; + strs += rowLen + 1; + src = end + 1; + count++; + } + + if (len > 0) { + end = Str_indexOfNull(src); + tmpLen = (Str_UNum)(end - src); + if (rowLen < tmpLen) { + tmpLen = rowLen; + } + Str_copyFix(strs, src, tmpLen); + strs[tmpLen] = __Str_Null; + count++; + } + } + + return count; +} +/** + * @brief Split string into character pointer array + * + * @param src address of string + * @param separator separator character + * @param strs address of array + * @param len length of array + * @param setNull if it's 1 change base string and replace separator characters with null + * @return Str_LenType return number of strs found + */ +Str_LenType Str_splitPtr(char* src, char separator, char** strs, Str_LenType len, uint8_t setNull) { + Str_UNum count = 0; + char* end; + + if (*src != __Str_Null) { + while ((end = Str_indexOf(src, separator)) != NULL && len-- > 0) { + *strs = src; + if (setNull) { + *end = __Str_Null; + } + strs++; + src = end + 1; + count++; + } + + if (len > 0) { + *strs = src; + count++; + } + } + + return count; +} +/** + * @brief Split string in serialize mode, put in in loop until return NULL + * it's similar to strtok + * remember it will replace separator characters with null + * + * @param src address of base string + * @param separator separator character + * @param ptr temporay character pointer + * @return char* return next token or NULL if there is any + */ +char* Str_splitToken(char* src, char separator, char** ptr, uint8_t setNull) { + char* end; + + if (src == NULL || *src == __Str_Null) { + *ptr = NULL; + return NULL; + } + + if (*ptr < src) { + *ptr = src; + } + + src = *ptr; + if (**ptr != __Str_Null) { + end = Str_indexOf(*ptr, separator); + if (end) { + *ptr = end + 1; + if (setNull) { + *end = __Str_Null; + } + } + else { + *ptr = Str_indexOfNull(*ptr); + } + } + + return src; +} +/** + * @brief find position of a character in string + * + * @param str address of string + * @param c searching character + * @return Str_LenType position of character + */ +Str_LenType Str_posOf(const char* str, char c) { + return (Str_LenType) (Str_indexOf(str, c) - str); +} +/** + * @brief find position of a character in string with reverse search + * + * @param str address of string + * @param c searching character + * @return Str_LenType position of charachter + */ +Str_LenType Str_lastPosOf(const char* str, char c) { + return (Str_LenType) (Str_lastIndexOf(str, c) - str); +} +/** + * @brief find position of start of word in string + * + * @param str address of string + * @param word searching string + * @return Str_LenType + */ +Str_LenType Str_posOfStr(const char* str, const char* word) { + return (Str_LenType) (Str_indexOfStr(str, word) - str); +} +/** + * @brief find string in array of strings with linear search algorithm + * + * @param strs array of strings + * @param len length of strs + * @param str searching string + * @return Str_LenType position of str in strs + */ +Str_LenType Str_multiCompare(const char** strs, Str_LenType len, const char* str) { + return Str_linearSearch(strs, len, str, (Str_CompareFn) Str_compare); +} +/** + * @brief find string in array of strings with binary search algorithm + * + * @param strs array of strings + * @param len length of strs + * @param str searching string + * @return Str_LenType position of str in strs + */ +Str_LenType Str_multiCompareSorted(const char** strs, Str_LenType len, const char* str) { + return Str_binarySearch(strs, len, str, (Str_CompareFn) Str_compare); +} +/** + * @brief find first string that found in array of strings + * + * @param src addres of source string + * @param strs array of strings that we want find in source string + * @param len length of strs + * @param result index and position of finded string + * @return const char* address of finded string in source string + */ +const char* Str_findStrs(const char* src, const char** strs, Str_LenType len, Str_MultiResult* result) { + Str_LenType index; + + while (*src != __Str_Null) { + for (index = 0; index < len; index++) { + if (Str_compareWord(src, strs[index]) == 0) { + result->IndexOf = src; + result->Position = index; + return src; + } + } + src++; + } + return NULL; +} +/** + * @brief find first string that found in array of strings with binary search algorithm + * + * @param src addres of source string + * @param strs array of strings that we want find in source string + * @param len length of strs + * @param result index and position of finded string + * @return const char* address of finded string in source string + */ +const char* Str_findStrsSorted(const char* src, const char** strs, Str_LenType len, Str_MultiResult* result) { + Str_LenType index; + Str_LenType pos; + + while (*src != __Str_Null) { + for (index = 0; index < len; index++) { + if ((pos = Str_binarySearch(strs, len, src, (Str_CompareFn) Str_compareWord)) != -1) { + result->IndexOf = src; + result->Position = pos; + return src; + } + } + src++; + } + return NULL; +} +/** + * @brief find first string that found in array of strings + * + * @param src addres of source string + * @param strs array of strings that we want find in source string + * @param len length of strs + * @param result index and position of finded string + * @param srcLen len of source string + * @return const char* address of finded string in source string + */ +const char* Str_findStrsFix(const char* src, const char** strs, Str_LenType len, Str_MultiResult* result, Str_LenType srcLen) { + Str_LenType index; + + while (*src != __Str_Null && srcLen-- > 0) { + for (index = 0; index < len; index++) { + if (Str_compareWord(src, strs[index]) == 0) { + result->IndexOf = src; + result->Position = index; + return src; + } + } + src++; + } + return NULL; +} +/** + * @brief find first string that found in array of strings with binary search algorithm + * + * @param src addres of source string + * @param strs array of strings that we want find in source string + * @param len length of strs + * @param result index and position of finded string + * @param srcLen len of source string + * @return const char* address of finded string in source string + */ +const char* Str_findStrsSortedFix(const char* src, const char** strs, Str_LenType len, Str_MultiResult* result, Str_LenType srcLen) { + Str_LenType index; + Str_LenType pos; + + while (*src != __Str_Null && srcLen-- > 0) { + for (index = 0; index < len; index++) { + if ((pos = Str_binarySearch(strs, len, src, (Str_CompareFn) Str_compareWord)) >= 0) { + result->IndexOf = src; + result->Position = pos; + return src; + } + } + src++; + } + return NULL; +} +/** + * @brief parse string text into real values + * ex: "\"Test\"" -> "Test" + * ex: "\"Line1 \\nLine 2\"" -> "Line 1 \nLine 2" + * + * @param string + * @param str + * @return Str_LenType + */ +Str_LenType Str_parseString(const char* string, char* str) { + unsigned int unicodeChar; + char* pSrc = str; + // check start double quote + if (*string++ != '"') { + return -1; + } + // parse string + while (*string != '\0' && *string != '"') { + if (*string == '\\') { + string++; + switch (*string) { + case '"': // quotaion mark + *str = '"'; + break; + case '\\': // reverse solidus + *str = '\\'; + break; + case '/': // solidus + *str = '/'; + break; + case 'b': // backspace + *str = '\b'; + break; + case 'f': // formfeed + *str = '\f'; + break; + case 'n': // line feed + *str = '\n'; + break; + case 'r': // carriage return + *str = '\r'; + break; + case 't': // tab + *str = '\t'; + break; + case 'u': // 4x HEX Digit + if (Str_convertUNumFix(++string, &unicodeChar, Str_Hex, 4) == Str_Ok) { + char temp = (char) (unicodeChar >> 8); + string += 3; + if (temp != __Str_Null) { + *str++ = temp; + } + *str = (char) unicodeChar; + } + else { + return -1; + } + break; + default: // not support + return -1; + } + } + else { + *str = *string; + } + str++; + string++; + } + // check end double quote + if (*string != '"') { + return -1; + } + // return len of str + *str = __Str_Null; + return (Str_LenType)(str - pSrc); +} +/** + * @brief parse string text into real values + * ex: "\"Test\"" -> "Test" + * ex: "\"Line1 \\nLine 2\"" -> "Line 1 \nLine 2" + * + * @param str + * @return Str_LenType + */ +Str_LenType Str_fromString(char* str) { + return Str_parseString(str, str); +} +/** + * @brief convert str into valid string format for serialize + * ex: "Text\\n" -> "\"Text\\n\"" + * + * @param str + * @param string + * @return char* return last index of string + */ +char* Str_convertString(const char* str, char* string) { + // set first double quote + *string++ = '"'; + // convert str + while (*str != __Str_Null) { + if (*str < ' ' || *str == '\\' || *str == '/' || *str == '"') { + *string++ = '\\'; + switch (*str) { + case '"': + *string = '"'; + break; + case '\n': + *string = 'n'; + break; + case '\r': + *string = 'r'; + break; + case '\t': + *string = 't'; + break; + case '\\': + *string = '\\'; + break; + case '/': + *string = '/'; + break; + case '\b': + *string = 'b'; + break; + case '\f': + *string = 'f'; + break; + default: + // ignore character + string--; + break; + } + } + else { + *string = *str; + } + string++; + str++; + } + // set second double qoute + *string++ = '"'; + *string = __Str_Null; + return string; +} +/** + * @brief convert str into valid string format for serialize + * ex: "Text\n" -> "\"Text\\n\"" + * + * @param str + * @param string + * @param len number of characters for convert + * @return char* return last index of string + */ +char* Str_convertStringFix(const char* str, char* string, Str_LenType len) { + // set first double quote + *string++ = '"'; + // convert str + while (*str != __Str_Null && len-- > 0) { + if (*str < ' ' || *str == '\\' || *str == '/' || *str == '"') { + *string++ = '\\'; + switch (*str) { + case '"': + *string = '"'; + break; + case '\n': + *string = 'n'; + break; + case '\r': + *string = 'r'; + break; + case '\t': + *string = 't'; + break; + case '\\': + *string = '\\'; + break; + case '/': + *string = '/'; + break; + case '\b': + *string = 'b'; + break; + case '\f': + *string = 'f'; + break; + default: + // ignore character + string--; + break; + } + } + else { + *string = *str; + } + string++; + str++; + } + // set second double qoute + *string++ = '"'; + *string = __Str_Null; + return string; +} +/** + * @brief convert a number into string with specific base index and length + * + * @param num number that we want convert + * @param base base index + * @param minLen minimum length of result string + * @param str address destination string + * @return Str_LenType return length of str + */ +Str_LenType Str_parseNum(Str_Num num, Str_Radix base, Str_LenType minLen, char* str) { + if (num < 0){ + *str++ = '-'; + num *= -1; + return Str_parseUNum((Str_UNum) num, base, minLen, str) + 1; + } + else { + return Str_parseUNum((Str_UNum) num, base, minLen, str); + } +} +/** + * @brief convert a unsigned number into string with specific base index and length + * + * @param num number that we want convert + * @param base base index + * @param minLen minimum length of result string + * @param str address destination string + * @return Str_LenType return length of str + */ +Str_LenType Str_parseUNum(Str_UNum num, Str_Radix base, Str_LenType minLen, char* str) { + Str_LenType count = 0; + char* pStr = str; + char temp; + do { + temp = num % (Str_LenType) base; + *pStr++ = temp < __Str_Decimal ? (temp + __Str_0) : (temp + 0x37); + count++; + num /= base; + } while (num != 0 || count < minLen); + Mem_reverse(str, (Mem_LenType) count); + *pStr = __Str_Null; + return count; +} +/** + * @brief convert a string into number + * + * @param str address of source string + * @param num address of output number + * @param base base index + * @return Str_Result result of convert + */ +Str_Result Str_convertNum(const char* str, Str_Num* num, Str_Radix base) { + return Str_convertNumFix(str, num, base, __Str_MaxLength); +} +/** + * @brief convert a string into unsigned number + * + * @param str address of source string + * @param num address of output number + * @param base base index + * @return Str_Result result of convert + */ +Str_Result Str_convertUNum(const char* str, Str_UNum* num, Str_Radix base) { + return Str_convertUNumFix(str, num, base, __Str_MaxLength); +} +/** + * @brief convert a string into number with fixed length + * + * @param str address of source string + * @param num address of output number + * @param base base index + * @return Str_Result result of convert + */ +Str_Result Str_convertNumFix(const char* str, Str_Num* num, Str_Radix base, Str_LenType len) { + if (*str == '-'){ + Str_Result res; + res = Str_convertUNumFix(++str, (Str_UNum*) num, base, --len); + *num *= -1; + return res; + } + else { + return Str_convertUNumFix(str, (Str_UNum*) num, base, len); + } +} +/** + * @brief convert a string into unsigned number with fixed length + * + * @param str address of source string + * @param num address of output number + * @param base base index + * @return Str_Result result of convert + */ +Str_Result Str_convertUNumFix(const char* str, Str_UNum* num, Str_Radix base, Str_LenType len) { + Str_UNum temp; + *num = 0; + while (*str != __Str_Null && len-- > 0){ + if (*str >= __Str_0 && *str <= __Str_9){ + temp = *str - __Str_0; + } + else if (*str >= 'A' && *str <= 'Z'){ + temp = *str - 0x37; + } + else if (*str >= 'a' && *str <= 'z'){ + temp = *str - 0x57; + } + else { + return Str_Error; + } + if (temp >= base){ + return Str_Error; + } + *num = *num * base + temp; + str++; + } + return Str_Ok; +} +#if STR_ENABLE_LONG_NUMBER +/** + * @brief convert a long number into string with specific base index and length + * + * @param num number that we want convert + * @param base base index + * @param minLen minimum length of result string + * @param str address destination string + * @return Str_LenType return length of str + */ +Str_LenType Str_parseLong(Str_Long num, Str_Radix base, Str_LenType minLen, char* str) { + if (num < 0){ + *str++ = '-'; + num *= -1; + return Str_parseULong((Str_ULong) num, base, minLen, str) + 1; + } + else { + return Str_parseULong((Str_ULong) num, base, minLen, str); + } +} +/** + * @brief convert a unsigned long number into string with specific base index and length + * + * @param num number that we want convert + * @param base base index + * @param minLen minimum length of result string + * @param str address destination string + * @return Str_LenType return length of str + */ +Str_LenType Str_parseULong(Str_ULong num, Str_Radix base, Str_LenType minLen, char* str) { + Str_LenType count = 0; + char* pStr = str; + char temp; + do { + temp = num % (Str_LenType) base; + *pStr++ = temp < __Str_Decimal ? (temp + __Str_0) : (temp + 0x37); + count++; + num /= base; + } while (num != 0 || count < minLen); + Mem_reverse(str, (Mem_LenType) count); + *pStr = __Str_Null; + return count; +} +/** + * @brief convert a string into long number + * + * @param str address of source string + * @param num address of output number + * @param base base index + * @return Str_Result result of convert + */ +Str_Result Str_convertLong(const char* str, Str_Long* num, Str_Radix base) { + return Str_convertLongFix(str, num, base, __Str_MaxLength); +} +/** + * @brief convert a string into unsigned long number + * + * @param str address of source string + * @param num address of output number + * @param base base index + * @return Str_Result result of convert + */ +Str_Result Str_convertULong(const char* str, Str_ULong* num, Str_Radix base) { + return Str_convertULongFix(str, num, base, __Str_MaxLength); +} +/** + * @brief convert a string into long number with fixed length + * + * @param str address of source string + * @param num address of output number + * @param base base index + * @param len + * @return Str_Result result of convert + */ +Str_Result Str_convertLongFix(const char* str, Str_Long* num, Str_Radix base, Str_LenType len) { + if (*str == '-'){ + Str_Result res; + res = Str_convertULongFix(++str, (Str_ULong*) num, base, --len); + *num *= -1; + return res; + } + else { + return Str_convertULongFix(str, (Str_ULong*) num, base, len); + } +} +/** + * @brief convert a string into unsigned long number with fixed length + * + * @param str address of source string + * @param num address of output number + * @param base base index + * @return Str_Result result of convert + */ +Str_Result Str_convertULongFix(const char* str, Str_ULong* num, Str_Radix base, Str_LenType len) { + Str_UNum temp; + *num = 0; + while (*str != __Str_Null && len-- > 0){ + if (*str >= __Str_0 && *str <= __Str_9){ + temp = *str - __Str_0; + } + else if (*str >= 'A' && *str <= 'Z'){ + temp = *str - 0x37; + } + else if (*str >= 'a' && *str <= 'z'){ + temp = *str - 0x57; + } + else { + return Str_Error; + } + if (temp >= base){ + return Str_Error; + } + *num = *num * base + temp; + str++; + } + return Str_Ok; +} +#endif // STR_ENABLE_LONG_NUMBER +/** + * @brief convert float number into string + * + * @param num float number + * @param str address of output string + * @return Str_LenType + */ +Str_LenType Str_parseFloat(float num, char* str) { + int numInt = (int) num; + Str_LenType len; + len = Str_parseNum(numInt, __Str_Decimal, STR_NORMAL_LEN, str); + str = str + len; + num = num - numInt; + if (num != 0) { + *str++ = '.'; + len++; + if (num < 0){ + num *= -1; + } + numInt = (int) num; + while (num != 0) { + num *= __Str_Decimal; + numInt = (int) num; + *str++ = numInt + __Str_0; + len++; + num -= numInt; + } + } + *str = __Str_Null; + return len; +} +/** + * @brief convert float number into string + * + * @param num float number + * @param str address of output string + * @param decimalLen resolution of floating part + * @return Str_LenType + */ +Str_LenType Str_parseFloatFix(float num, char* str, Str_LenType decimalLen) { + int pow = decimalLen; + int numInt = (int) num; + Str_LenType len; + len = Str_parseNum(numInt, __Str_Decimal, STR_NORMAL_LEN, str); + if (decimalLen != 0) { + str = str + len; + *str++ = '.'; + num = num - numInt; + if (num < 0){ + num *= -1; + } + while (pow-- != 0){ + num *= __Str_Decimal; + } + len += Str_parseNum((int) num, __Str_Decimal, STR_NORMAL_LEN, str) + 1; + } + return len; +} +/** + * @brief convert a string into float number + * + * @param str address of source string + * @param num address of output number + * @return Str_Result result of convert + */ +Str_Result Str_convertFloat(const char* str, float* num) { + return Str_convertFloatFix(str, num, Str_len(str)); +} +/** + * @brief convert a string into float number with fixed length + * + * @param str address of source string + * @param num address of output number + * @param len number of charactres for convert + * @return Str_Result result of convert + */ +Str_Result Str_convertFloatFix(const char* str, float* num, Str_LenType len) { + const char* pDot = Str_indexOf(str, '.'); + float temp; + int numInt; + Str_LenType strLen; + if (pDot == NULL){ + pDot = Mem_indexOf(str, __Str_Null, __Str_MaxLength); + } + strLen = (Str_LenType)(pDot - str); + if (strLen > len){ + strLen = len; + } + if (Str_convertNumFix(str, &numInt, __Str_Decimal, strLen) == Str_Ok){ + *num = numInt; + if (*pDot != __Str_Null){ + len -= strLen + 1; + if (Str_convertNumFix(++pDot, &numInt, Str_Decimal, len) != Str_Ok){ + return Str_Error; + } + temp = numInt; + while (len-- > 0) { + temp /= __Str_Decimal; + } + *num = *num < 0 ? *num - temp : *num + temp; + } + return Str_Ok; + } + return Str_Error; +} +/** + * @brief ignore all characters below than space character (' ' = 0x20) + * + * @param str + * @return char* return address of first character + */ +char* Str_ignoreWhitespace(const char* str) { + while (*str <= ' ' && *str != __Str_Null) { + str++; + } + return (char*) str; +} +/** + * @brief ignore all characters above and equal than space character (' ' = 0x20) + * + * @param str + * @return char* return address of first whitespace + */ +char* Str_ignoreCharacters(const char* str) { + while (*str >= ' ' && *str != __Str_Null) { + str++; + } + return (char*) str; +} +/** + * @brief ignore all a-z,A-Z,0-9 characters + * + * @param str + * @return char* + */ +char* Str_ignoreAlphaNumeric(const char* str) { + while (*str != __Str_Null && + ((*str >= '0' && *str <= '9') || + (*str >= 'A' && *str <= 'Z') || + (*str >= 'a' && *str <= 'z'))) { + str++; + } + return (char*) str; +} +/** + * @brief ignore all alphabet characters, A-Z,a-z + * + * @param str + * @return char* + */ +char* Str_ignoreAlphabet(const char* str) { + while (*str != __Str_Null && + ((*str >= 'A' && *str <= 'Z') || + (*str >= 'a' && *str <= 'z'))) { + str++; + } + return (char*) str; +} +/** + * @brief ignore all numeric characters, 0-9 + * + * @param str + * @return char* + */ +char* Str_ignoreNumeric(const char* str) { + while (*str != __Str_Null && (*str >= '0' && *str <= '9')) { + str++; + } + return (char*) str; +} +/** + * @brief ignore all special characters + * + * @param str + * @return char* + */ +char* Str_ignoreSpecialCharacters(const char* str) { + while (*str != __Str_Null && + ((*str >= '!' && *str <= '/') || + (*str >= ':' && *str <= '@') || + (*str >= '[' && *str <= '`') || + (*str >= '{' && *str <= '~'))) { + str++; + } + return (char*) str; +} +/** + * @brief ignore all following characters: 0-9,A-Z,a-z, '-', '_' + * + * @param str + * @return char* + */ +char* Str_ignoreNameCharacters(const char* str) { + while (*str != __Str_Null && + ((*str >= '0' && *str <= '9') || + (*str >= 'A' && *str <= 'Z') || + (*str >= 'a' && *str <= 'z') || + *str == '-' || *str == '_')) { + str++; + } + return (char*) str; +} +/** + * @brief ingore following characters: ':'-'@','#'-'&','!' + * + * @param str + * @return char* + */ +char* Str_ignoreCommandCharacters(const char* str) { + while (*str != __Str_Null && + ((*str >= ':' && *str <= '@') || + (*str >= '#' && *str <= '&') || + *str == '!')) { + str++; + } + return (char*) str; +} +/** + * @brief ignore characters in given str with custom role + * + * @param str + * @param cmp + * @return char* + */ +char* Str_ignore(const char* str, Str_IgnoreRoleFn cmp) { + while (*str != __Str_Null && (char) cmp(*str)) { + str++; + } + return (char*) str; +} +/** + * @brief ignore whitespaces from last of string + * + * @param str + * @return char* + */ +char* Str_ignoreWhitespaceReverse(const char* str) { + str = Str_indexOfEnd(str); + while (*str <= ' ' && *str != __Str_Null) { + str--; + } + return (char*) str; +} +/** + * @brief ignore characters from last of string + * + * @param str + * @return char* + */ +char* Str_ignoreCharactersReverse(const char* str) { + str = Str_indexOfEnd(str); + while (*str > ' ' && *str != __Str_Null) { + str--; + } + return (char*) str; +} +/** + * @brief change all characters into upper case + * + * @param str + * @return char* + */ +void Str_upperCase(char* str) { + while (*str != __Str_Null) { + if (*str >= 'a' && *str <= 'z') { + *str = *str - 32; + } + str++; + } +} +/** + * @brief change all characters into upper case, with fixed Length + * + * @param str + * @param len + * @return char* + */ +void Str_upperCaseFix(char* str, Str_LenType len) { + while (*str != __Str_Null && len-- > 0) { + if (*str >= 'a' && *str <= 'z') { + *str = *str - 32; + } + str++; + } +} +/** + * @brief change all characters into lower case + * + * @param str + */ +void Str_lowerCase(char* str) { + while (*str != __Str_Null) { + if (*str >= 'A' && *str <= 'Z') { + *str = *str + 32; + } + str++; + } +} +/** + * @brief change all characters into lower case with fix Length + * + * @param str + */ +void Str_lowerCaseFix(char* str, Str_LenType len) { + while (*str != __Str_Null && len-- > 0) { + if (*str >= 'A' && *str <= 'Z') { + *str = *str + 32; + } + str++; + } +} +/** + * @brief remove all whitespace in left of string + * + * @param str + * @return char* + */ +char* Str_trimLeft(char* str) { + char* pEnd = Str_ignoreWhitespace(str); + if (pEnd != str) { + Mem_move(str, pEnd, Str_len(str) - (Mem_LenType)(pEnd - str) + 1); + } + return str; +} +/** + * @brief remove all whitespaces in right of string + * + * @param str + * @return char* + */ +char* Str_trimRight(char* str) { + char* pEnd = Str_ignoreWhitespaceReverse(str) + 1; + *pEnd = __Str_Null; + return str; +} +/** + * @brief trim left and right of string + * + * @param str + * @return char* + */ +char* Str_trim(char* str) { + Str_trimRight(str); + Str_trimLeft(str); + return str; +} +/** + * @brief remove all backspace ('\b') characters and left character + * ex: "ABCD\bER" -> "ABCER" + * + * @param str + * @return Str_LenType return new length + */ +Str_LenType Str_removeBackspace(char* str) { + Str_LenType len = Str_len(str); + if (len > 0) { + char* pStr = str + len - 1; + while (str < pStr) { + if (*pStr-- == '\b') { + Mem_move(pStr, pStr + 2, len - (Mem_LenType)(pStr - str)); + len -= 2; + } + } + if (*pStr == '\b') { + Mem_move(pStr, pStr + 1, len - (Mem_LenType)(pStr - str)); + len -= 1; + } + } + return len; +} +/** + * @brief remove all backspace ('\b') characters and left character with fix len + * ex: "ABCD\bER" -> "ABCER" + * + * @param str + * @param len + * @return Str_LenType return new length + */ +Str_LenType Str_removeBackspaceFix(char* str, Str_LenType len) { + if (len > 0) { + char* pStr = str + len - 1; + while (str < pStr) { + if (*pStr-- == '\b') { + Mem_move(pStr, pStr + 2, len - (Mem_LenType)(pStr - str)); + len -= 2; + } + } + if (*pStr == '\b') { + Mem_move(pStr, pStr + 1, len - (Mem_LenType)(pStr - str)); + len -= 1; + } + } + return len; +} +#if STR_ENABLE_DOUBLE +/** + * @brief convert double number into string + * + * @param num float number + * @param str address of output string + * @return Str_LenType + */ +Str_LenType Str_parseDouble(double num, char* str) { + int numInt = (int) num; + Str_LenType len; + len = Str_parseNum(numInt, __Str_Decimal, STR_NORMAL_LEN, str); + str = str + len; + num = num - numInt; + if (num != 0) { + *str++ = '.'; + len++; + if (num < 0){ + num *= -1; + } + numInt = (int) num; + while (num != 0) { + num *= __Str_Decimal; + numInt = (int) num; + *str++ = numInt + __Str_0; + len++; + num -= numInt; + } + } + *str = __Str_Null; + return len; +} +/** + * @brief convert double number into string + * + * @param num float number + * @param str address of output string + * @param decimalLen resolution of floating part + * @return Str_LenType + */ +Str_LenType Str_parseDoubleFix(double num, char* str, Str_LenType decimalLen) { + int pow = decimalLen; + int numInt = (int) num; + Str_LenType len; + len = Str_parseNum(numInt, __Str_Decimal, STR_NORMAL_LEN, str); + if (decimalLen != 0) { + str = str + len; + *str++ = '.'; + num = num - numInt; + if (num < 0){ + num *= -1; + } + while (pow-- != 0){ + num *= __Str_Decimal; + } + len += Str_parseNum((int) num, __Str_Decimal, STR_NORMAL_LEN, str) + 1; + } + return len; +} + +/** + * @brief convert a string into double number + * + * @param str address of source string + * @param num address of output number + * @return Str_Result result of convert + */ +Str_Result Str_convertDouble(const char* str, double* num) { + return Str_convertDoubleFix(str, num, Str_len(str)); +} +/** + * @brief convert a string into double number with fixed length + * + * @param str address of source string + * @param num address of output number + * @return Str_Result result of convert + */ +Str_Result Str_convertDoubleFix(const char* str, double* num, Str_LenType len) { + const char* pDot = Str_indexOf(str, '.'); + double temp; + int numInt; + Str_LenType strLen; + if (pDot == NULL){ + pDot = Mem_indexOf(str, __Str_Null, __Str_MaxLength); + } + strLen = (Str_LenType)(pDot - str); + if (strLen > len){ + strLen = len; + } + if (Str_convertNumFix(str, &numInt, __Str_Decimal, strLen) == Str_Ok){ + *num = numInt; + if (*pDot != __Str_Null){ + len -= strLen + 1; + if (Str_convertNumFix(++pDot, &numInt, __Str_Decimal, len) != Str_Ok){ + return Str_Error; + } + temp = numInt; + while (len-- > 0) { + temp /= __Str_Decimal; + } + *num = *num < 0 ? *num - temp : *num + temp; + } + return Str_Ok; + } + return Str_Error; +} + +#endif // STR_ENABLE_DOUBLE +/** + * @brief get first number that found in string + * + * @param str address of source string + * @param num number that found + * @param numPos index of number that found + * @return Str_Result result of searching for number + */ +Str_Result Str_getNum(const char* str, int* num, const char** numPos) { + const char* baseStr = str; + str = Str_findDigit(str); + if (str != NULL){ + if (baseStr < str && *(str - 1) == '-'){ + str--; + } + *numPos = str; + if (Str_convertNumFix(str, num, __Str_Decimal, (Str_LenType) (Str_findLastDigit(str) - str + 1)) == Str_Ok){ + return Str_Ok; + } + } + return Str_Error; +} +/** + * @brief get first unsigned number that found in string + * + * @param str address of source string + * @param num number that found + * @param numPos index of number that found + * @return Str_Result result of searching for number + */ +Str_Result Str_getUNum(const char* str, unsigned int* num, const char** numPos) { + str = Str_findDigit(str); + if (str != 0){ + *numPos = str; + if (Str_convertUNumFix(str, num, __Str_Decimal, (Str_LenType) (Str_findLastDigit(str) - str + 1)) == Str_Ok){ + return Str_Ok; + } + } + return Str_Error; +} +/** + * @brief get first float number that found in string + * + * @param str address of source string + * @param num number that found + * @param numPos index of number that found + * @return Str_Result result of searching for number + */ +Str_Result Str_getFloat(const char* str, float* num, const char** numPos) { + const char* pDot = str; + str = Str_findDigit(str); + if (str != NULL){ + if (pDot < str && *(str - 1) == '-'){ + str--; + } + pDot = Str_findLastDigit(str) + 1; + if (*(pDot) == '.'){ + pDot = Str_findLastDigit(pDot); + pDot = pDot == NULL ? Str_indexOfEnd(str) : pDot + 1; + } + *numPos = str; + if (Str_convertFloatFix(str, num, pDot - str) == Str_Ok){ + return Str_Ok; + } + } + return Str_Error; +} +/** + * @brief get token from an string + * ex: getToken("123,ABCD,48", ',', 1, token); + * assert(token, "ABCD"); + * + * @param str + * @param separator + * @param index + * @param token + * @return Str_Result + */ +Str_Result Str_getToken(const char* str, char separator, Str_LenType index, char* token) { + return Str_getTokenFix(str, separator, index, token, STR_NORMAL_LEN); +} +/** + * @brief get token from an string + * ex: getTokenFix("123,ABCD,48", ',', 1, token, sizeof(token) - 1); + * assert(token, "ABCD"); + * + * @param str + * @param separator + * @param index + * @param token + * @param len + * @return Str_Result + */ +Str_Result Str_getTokenFix(const char* str, char separator, Str_LenType index, char* token, Str_LenType len) { + if ((str = Str_indexOfAt(str, separator, index)) != NULL) { + char* end; + Mem_LenType tokenLen; + if (*str == separator) { + str++; + } + if ((end = Str_indexOf(str, separator)) == NULL) { + end = Str_indexOfNull(str); + } + tokenLen = (Mem_LenType)(end - str); + if (STR_NORMAL_LEN != len && tokenLen >= len) { + tokenLen = len; + } + Mem_copy(token, str, tokenLen); + token[tokenLen] = __Str_Null; + return Str_Ok; + } + + return Str_Error; +} +/** + * @brief swap address of two string + * + * @param itemA string 1 + * @param itemB string 2 + */ +void Str_swap(const char** itemA, const char** itemB) { + const char* temp = *itemA; + *itemA = *itemB; + *itemB = temp; +} + +Str_LenType Str_partition(const char** items, Str_LenType low, Str_LenType high, Str_CompareFn cmp) { + const char* pivot = items[high]; // pivot + Str_LenType i = (low - 1); // Index of smaller element + Str_LenType j; + for (j = low; j <= high - 1; j++) + { + // If current element is smaller than the pivot + if (cmp(items[j], pivot) < 0) + { + i++; // increment index of smaller element + Str_swap(&items[i], &items[j]); + } + } + Str_swap(&items[i + 1], &items[high]); + return (i + 1); +} +/** + * @brief run quick sort algorithm for items with given compare Fntion + * + * @param items array of strings + * @param low position of start + * @param high position of end + * @param cmp address of compare Fntion + * @return char** return items + */ +const char** Str_quickSortBlock(const char** items, Mem_LenType low, Mem_LenType high, Str_CompareFn cmp) { + if (low < high) { + /* pi is partitioning index, arr[p] is now + at right place */ + Str_LenType pi = Str_partition(items, low, high, cmp); + + // Separately sort elements before + // partition and after partition + Str_quickSortBlock(items, low, pi - 1, cmp); + Str_quickSortBlock(items, pi + 1, high, cmp); + } + return items; +} +/** + * @brief run selection sort algorithm for item with given compare Fntion + * + * @param items array of strings + * @param len length of array + * @param cmp address of compare Fntion + * @return char** + */ +const char** Str_selectionSortBlock(const char** items, Mem_LenType len, Str_CompareFn cmp) { + Mem_LenType i; + Mem_LenType j; + Mem_LenType min_idx; + + // One by one move boundary of unsorted sub-array + for (i = 0; i < len-1; i++) + { + // Find the minimum element in unsorted array + min_idx = i; + for (j = i+1; j < len; j++) { + if (cmp(items[j], items[min_idx]) < 0) { + min_idx = j; + } + } + // Swap the found minimum element with the first element + Str_swap(&items[min_idx], &items[i]); + } + return items; +} +/** + * @brief find string in array of strings + * + * @param strs array of strings + * @param len len of array + * @param str + * @param cmp address of comperator function + * @return Str_LenType index of string in array + */ +Str_LenType Str_linearSearch(const char** strs, Str_LenType len, const char* str, Str_CompareFn cmp) { + Str_LenType tempLen = len; + while (len--) { + if (cmp(str, *strs++) == 0) { + return tempLen - len - 1; + } + } + return -1; +} +/** + * @brief search a string in array of strings with binary search algorithm + * + * @param strs + * @param len + * @param str + * @param cmp + * @return Str_LenType + */ +Str_LenType Str_binarySearch(const char** strs, Str_LenType len, const char* str, Str_CompareFn cmp) { + Str_LenType left = 0; + Str_LenType mid; + char result; + + len--; + + while (left <= len) { + mid = (len + left) >> 1; + result = cmp(str, strs[mid]); + // Check if str is present at mid + if (result == 0) { + return mid; + } + // If str greater, ignore left half + else if (result > 0) { + left = mid + 1; + } + // If x is smaller, ignore right half + else { + len = mid - 1; + } + } + // if we reach here, then element was + // not present + return -1; +} +/** + * @brief run selection sort algorithm for item with given compare Fntion, and swap function + * + * @param items array of items such as struct + * @param len length of array + * @param itemLen size of single item + * @param cmp address of compare Fntion + * @param swap address of swap function + * @return char** + */ +void* Mem_sort(void* items, Mem_LenType len, Mem_LenType itemLen, Mem_CompareFn cmp, Mem_SwapFn swap) { + Mem_LenType i; + Mem_LenType j; + Mem_LenType min_idx; + unsigned char* pItems = (unsigned char*) items; + + // One by one move boundary of unsorted sub-array + len *= itemLen; + for (i = 0; i < len - itemLen; i += itemLen) + { + // Find the minimum element in unsorted array + min_idx = i; + for (j = i + itemLen; j < len; j += itemLen) { + if (cmp(&pItems[j], &pItems[min_idx], itemLen) < 0) { + min_idx = j; + } + } + // Swap the found minimum element with the first element + swap(&pItems[min_idx], &pItems[i], itemLen); + } + return items; +} +/** + * @brief sort array of items with quick sort algorithm + * + * @param items array of items such as struct + * @param len length of array + * @param itemLen sizeof single item + * @param cmp address of compare function + * @param swap address of swap function + * @return const char** return address of strs + */ +void* Mem_quickSort(void* items, Mem_LenType len, Mem_LenType itemLen, Mem_CompareFn cmp, Mem_SwapFn swap) { + return Mem_quickSortBlock(items, 0, (Mem_LenType) (len - 1) * itemLen, itemLen, cmp, swap); +} +Mem_LenType Mem_partition(void* items, Mem_LenType low, Mem_LenType high, Mem_LenType itemLen, Mem_CompareFn cmp, Mem_SwapFn swap) { + unsigned char* pItems = (unsigned char*) items; + const unsigned char* pivot = &pItems[high]; // pivot + Mem_LenType i = (low - itemLen); // Index of smaller element + Mem_LenType j; + for (j = low; j <= high - itemLen; j += itemLen) + { + // If current element is smaller than the pivot + if (cmp(&pItems[j], pivot, itemLen) < 0) + { + i += itemLen; // increment index of smaller element + swap(&pItems[i], &pItems[j], itemLen); + } + } + swap(&pItems[i + itemLen], &pItems[high], itemLen); + return (i + itemLen); +} +void* Mem_quickSortBlock(void* items, Mem_LenType low, Mem_LenType high, Mem_LenType itemLen, Mem_CompareFn cmp, Mem_SwapFn swap) { + if (low < high) { + /* pi is partitioning index, arr[p] is now + at right place */ + Mem_LenType pi = Mem_partition(items, low, high, itemLen, cmp, swap); + + // Separately sort elements before + // partition and after partition + Mem_quickSortBlock(items, low, pi - itemLen, itemLen, cmp, swap); + Mem_quickSortBlock(items, pi + itemLen, high, itemLen, cmp, swap); + } + return items; +} +/** + * @brief find item in array + * + * @param items + * @param len + * @param itemLen + * @param item + * @param cmp + * @return Mem_LenType + */ +Mem_LenType Mem_linearSearch(const void* items, Mem_LenType len, Mem_LenType itemLen, const void* item, Mem_CompareFn cmp) { + unsigned char* pItems = (unsigned char*) items; + Mem_LenType pIndex; + len *= itemLen; + + + for (pIndex = 0; pIndex < len; pIndex += itemLen, pItems += itemLen) { + if (cmp(item, pItems, itemLen) == 0) { + return pIndex / itemLen; + } + + } + return -1; +} +/** + * @brief find item in array with binary search algorithm + * + * @param items + * @param len + * @param itemLen + * @param item + * @param cmp + * @return Mem_LenType + */ +Mem_LenType Mem_binarySearch(const void* items, Mem_LenType len, Mem_LenType itemLen, const void* item, Mem_CompareFn cmp) { + unsigned char* pItems = (unsigned char*) items; + Mem_LenType left = 0; + Mem_LenType mid; + char result; + + len--; + + while (left <= len) { + mid = (len + left) >> 1; + result = cmp(item, &pItems[mid * itemLen], itemLen); + // Check if str is present at mid + if (result == 0) { + return mid; + } + // If str greater, ignore left half + else if (result > 0) { + left = mid + 1; + } + // If x is smaller, ignore right half + else { + len = mid - 1; + } + } + // if we reach here, then element was + // not present + return -1; +} + +#if !STR_USE_STRING_LIBRARY + +void* Mem_copy(void* dest, const void* src, Mem_LenType len) { + unsigned char* pDest = (unsigned char*) dest; + const unsigned char* pSrc = (const unsigned char*) src; + while (len-- > 0) { + *pDest++ = *pSrc++; + } + return dest; +} +char Mem_compare(const void* arr1, const void* arr2, Mem_LenType len) { + const unsigned char* pArr1 = (const unsigned char*) arr1; + const unsigned char* pArr2 = (const unsigned char*) arr2; + char result; + while (len-- > 0) { + if((result = *pArr1++ - *pArr2++)) { + break; + } + } + return result; +} +void* Mem_move(void* dest, const void* src, Mem_LenType len) { + unsigned char* pDest = (unsigned char*) dest; + const unsigned char* pSrc = (const unsigned char*) src; + if (len <= 0 || src == dest) { + return NULL; + } + if (pDest < pSrc) { + while (len-- > 0) { + *pDest++ = *pSrc++; + } + } + else { + const unsigned char* lastSrc = (const unsigned char*) (pSrc + (len - 1)); + unsigned char* lastDest = (unsigned char*) (pDest + (len - 1)); + while (len-- > 0) { + *lastDest-- = *lastSrc--; + } + } + return dest; +} +void* Mem_indexOf(const void* arr, unsigned char value, Mem_LenType len) { + const unsigned char* pArr = (const unsigned char*) arr; + + while (len-- > 0) { + if (*pArr == value) { + return (void*) pArr;; + } + pArr++; + } + return NULL; +} +void* Mem_set(void* arr, unsigned char value, Mem_LenType len) { + unsigned char* pArr = (unsigned char*) arr; + + while (len-- > 0) { + *pArr++ = value; + } + return arr; +} + + + +char* Str_copy(char* dest, const char* src) { + char* pDest = dest; + while (*src != __Str_Null) { + *pDest++ = *src++; + } + *pDest = __Str_Null; + return dest; +} +char* Str_copyFix(char* dest, const char* src, Str_LenType len) { + return Mem_copy(dest, src, len); +} +char Str_compare(const char* str1, const char* str2) { + char result; + while (*str1 != __Str_Null) { + if ((result = *str1++ - *str2++)) { + break; + } + } + return result; +} +char Str_compareFix(const char* str1, const char* str2, Str_LenType len) { + return Mem_compare(str1, str2, len); +} +Str_LenType Str_len(const char* str) { + char* pStr = str; + while (*pStr != __Str_Null) { + pStr++; + } + return (Str_LenType) (pStr - str); +} +char* Str_indexOf(char* str, char c) { + while (*str != __Str_Null) { + if (*str == c) { + return str; + } + str++; + } + return NULL; +} +char* Str_lastIndexOf(char* str, char c) { + char* pStr = (char*) Mem_indexOf(str, '\'0', __Str_MaxLength) - 1; + while (pStr >= str) { + if (*pStr == c) { + return pStr; + } + pStr--; + } + return NULL; +} +char* Str_indexOfStr(char* str, char* sub) { + while (*str != __Str_Null && str != NULL) { + str = Str_indexOf(str, *sub); + if (Str_compareWord(str, sub) == 0) { + return str; + } + } + return NULL; +} +char* Str_append(char* str, char* sub) { + char* pStr = (char*) Mem_indexOf(str, '\'0', __Str_MaxLength); + Str_copy(pStr, sub); + return str; +} + +#endif // STR_USE_STRING_LIBRARY diff --git a/Examples/StreamOverSocket/Str/Str.h b/Examples/StreamOverSocket/Str/Str.h new file mode 100644 index 0000000..6f24839 --- /dev/null +++ b/Examples/StreamOverSocket/Str/Str.h @@ -0,0 +1,329 @@ +/** + * @file Str.h + * @author Ali Mirghasemi (ali.mirghasemi1376@gmail.com) + * @brief this library can use to handle with ASCII strings in c + * @version 0.2 + * @date 2021-08-08 + * + * @copyright Copyright (c) 2021 + * + */ +#ifndef _STR_UTILS_H_ +#define _STR_UTILS_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define STR_VER_MAJOR 0 +#define STR_VER_MINOR 5 +#define STR_VER_FIX 0 + +#include + +/********************************************************************************************/ +/* Configuration */ +/********************************************************************************************/ +#define STR_ENABLE_PARSE 1 + +#define STR_ENABLE_CONVERT_STR 1 + +#define MEM_MAX_LENGTH 1024 + +#define STR_MAX_LENGTH 1024 + +#define STR_ENABLE_LONG_NUMBER 1 + +#define STR_ENABLE_DOUBLE 1 + +#define STR_USE_CONST_VARIABLES 0 + +#define STR_USE_STRING_LIBRARY 1 + +typedef int Mem_CmpResult; +typedef short Str_CmpResult; + +typedef int32_t Str_Num; +typedef uint32_t Str_UNum; + +#if STR_ENABLE_LONG_NUMBER + typedef int64_t Str_Long; + typedef uint64_t Str_ULong; +#endif + +typedef int16_t Str_LenType; +typedef int16_t Mem_LenType; +/********************************************************************************************/ + +#if STR_USE_STRING_LIBRARY +#include + +#define Mem_copy memcpy +#define Mem_compare memcmp +#define Mem_move memmove +#define Mem_indexOf memchr +#define Mem_set memset + +#define Str_copy strcpy +#define Str_copyFix strncpy +#define Str_compare strcmp +#define Str_compareFix strncmp +#define Str_len strlen +#define Str_indexOf strchr +#define Str_lastIndexOf strrchr +#define Str_indexOfStr strstr +#define Str_append strcat + +#else + +void* Mem_copy(void* dest, const void* src, Mem_LenType len); +char Mem_compare(const void* arr1, const void* arr2, Mem_LenType len); +void* Mem_move(void* dest, const void* src, Mem_LenType len); +void* Mem_indexOf(const void* arr, unsigned char value, Mem_LenType len); +void* Mem_set(void* arr, unsigned char value, Mem_LenType len); + + + +char* Str_copy(char* dest, const char* str); +char* Str_copyFix(char* dest, const char* str, Str_LenType len); +char Str_compare(const char* str1, const char* str2); +char Str_compareFix(const char* str1, const char* str2, Str_LenType len); +Str_LenType Str_len(const char* str); +char* Str_indexOf(char* str, char c); +char* Str_lastIndexOf(char* str, char c); +char* Str_indexOfStr(char* str, char* sub); +char* Str_append(char* str, char* sub); + +#endif // STR_USE_STRING_LIBRARY + +#define STR_NORMAL_LEN 0 +/** + * @brief result type for str functions + */ +typedef enum { + Str_Ok = 0, + Str_Error = 1, +} Str_Result; +/** + * @brief hold result of multi str find + */ +typedef struct { + const char* IndexOf; + Str_LenType Position; +} Str_MultiResult; +/** + * @brief custom radix for parse and convert functions + * other values is valid too + */ +typedef enum { + Str_Binary = 2, + Str_Nibble = 4, + Str_Octal = 8, + Str_Decimal = 10, + Str_Hex = 16, +} Str_Radix; +/** + * @brief return type for ignore role function + */ +typedef enum { + Str_NotIgnore = 0, + Str_Ignore = 1, +} Str_Ignore_Result; +/** + * @brief custom role for ignore characters + */ +typedef Str_Ignore_Result (*Str_IgnoreRoleFn) (char character); +/** + * @brief string holder + */ +typedef struct { + char* Text; + Str_LenType Len; +} Str; +/** + * @brief const string holder + */ +typedef struct { + const char* Text; + Str_LenType Len; +} StrConst; + + +void* Mem_copyReverse(void* dest, const void* src, Mem_LenType len); +void* Mem_reverse(void* arr, Mem_LenType len); + +char* Str_copyUntil(char* dest, const char* src, char endChar); +char* Str_copyLine(char* dest, const char* src); + +char* Str_reverseIndexOf(const char* str, char c, const char* startOfStr); +char* Str_reverseIndexOfFix(const char* str, char c, int length); + +char* Str_indexOfEnd(const char* str); +char* Str_indexOfNull(const char* str); + +char Str_compareInverse(const char* str1, const char* str2); +char Str_compareWord(const char* str, const char* word); + +char* Str_findDigit(const char* str); +char* Str_findDigitUntil(const char* str, char endChar); +char* Str_findDigitFix(const char* str, Str_LenType len); + +char* Str_findLastDigit(const char* str); +char* Str_findLastDigitUntil(const char* str, char endChar); +char* Str_findLastDigitFix(const char* str, Str_LenType len); + +char* Str_ignoreWhitespace(const char* str); +char* Str_ignoreCharacters(const char* str); +char* Str_ignoreAlphaNumeric(const char* str); +char* Str_ignoreAlphabet(const char* str); +char* Str_ignoreNumeric(const char* str); +char* Str_ignoreSpecialCharacters(const char* str); +char* Str_ignoreNameCharacters(const char* str); +char* Str_ignoreCommandCharacters(const char* str); +char* Str_ignore(const char* str, Str_IgnoreRoleFn cmp); + +char* Str_ignoreWhitespaceReverse(const char* str); +char* Str_ignoreCharactersReverse(const char* str); + +void Str_upperCase(char* str); +void Str_upperCaseFix(char* str, Str_LenType len); +void Str_lowerCase(char* str); +void Str_lowerCaseFix(char* str, Str_LenType len); + +char* Str_trimLeft(char* str); +char* Str_trimRight(char* str); +char* Str_trim(char* str); + +Str_LenType Str_removeBackspace(char* str); +Str_LenType Str_removeBackspaceFix(char* str, Str_LenType len); + +char* Str_findReverseDigit(const char* str); +char* Str_findReverseDigitFix(const char* str, Str_LenType len); + +Str_LenType Str_indexesOf(const char* str, char c, char const** indexes); +Str_LenType Str_indexesOfFix(const char* str, char c, char const** indexes, Str_LenType len); +Str_LenType Str_indexesOfUntil(const char* str, char c, char const** indexes, char endChar); + +char* Str_indexOfAt(const char* str, char c, Str_LenType num); +char* Str_indexOfAtUntil(const char* str, char c, Str_LenType num, char end); +char* Str_indexOfAtFix(const char* str, char c, Str_LenType num, Str_LenType len); + +char* Str_reverse(char* str); + +char* Str_copyReverse(char* dest, const char* src); + +char* Str_substr(char* dest, const char* str, Str_LenType start); +char* Str_substrFix(char* dest, const char* str, Str_LenType start, Str_LenType len); +char* Str_substrUntil(char* dest, const char* str, Str_LenType start, char endChar); + +char* Str_replace(char* str, const char* word, const char* replacement); +int Str_replaceAll(char* str, const char* word, const char* replacement); + +const char** Str_sort(const char** strs, Str_LenType len); +const char** Str_quickSort(const char** strs, Str_LenType len); +const char** Str_sortReverse(const char** strs, Str_LenType len); +const char** Str_quickSortReverse(const char** strs, Str_LenType len); + +Str_LenType Str_split(const char* src, char separator, char* strs, Str_LenType rowLen, Str_LenType len); +Str_LenType Str_splitPtr(char* src, char separator, char** strs, Str_LenType len, uint8_t setNull); +char* Str_splitToken(char* src, char separator, char** ptr, uint8_t setNull); + +Str_LenType Str_posOf(const char* str, char c); +Str_LenType Str_lastPosOf(const char* str, char c); + +Str_LenType Str_posOfStr(const char* str, const char* word); + +Str_LenType Str_multiCompare(const char** strs, Str_LenType len, const char* str); +Str_LenType Str_multiCompareSorted(const char** strs, Str_LenType len, const char* str); + +const char* Str_findStrs(const char* src, const char** strs, Str_LenType len, Str_MultiResult* result); +const char* Str_findStrsSorted(const char* src, const char** strs, Str_LenType len, Str_MultiResult* result); + +const char* Str_findStrsFix(const char* src, const char** strs, Str_LenType len, Str_MultiResult* result, Str_LenType srcLen); +const char* Str_findStrsSortedFix(const char* src, const char** strs, Str_LenType len, Str_MultiResult* result, Str_LenType srcLen); + +Str_LenType Str_parseNum(Str_Num num, Str_Radix base, Str_LenType minLen, char* str); +Str_LenType Str_parseUNum(Str_UNum num, Str_Radix base, Str_LenType minLen, char* str); + +Str_LenType Str_parseString(const char* string, char* str); +Str_LenType Str_fromString(char* str); + +Str_Result Str_convertNum(const char* str, Str_Num* num, Str_Radix base); +Str_Result Str_convertUNum(const char* str, Str_UNum* num, Str_Radix base); +Str_Result Str_convertNumFix(const char* str, Str_Num* num, Str_Radix base, Str_LenType len); +Str_Result Str_convertUNumFix(const char* str, Str_UNum* num, Str_Radix base, Str_LenType len); + +char* Str_convertString(const char* str, char* string); +char* Str_convertStringFix(const char* str, char* string, Str_LenType len); + +#if STR_ENABLE_LONG_NUMBER + +Str_LenType Str_parseLong(Str_Long num, Str_Radix base, Str_LenType minLen, char* str); +Str_LenType Str_parseULong(Str_ULong num, Str_Radix base, Str_LenType minLen, char* str); + +Str_Result Str_convertLong(const char* str, Str_Long* num, Str_Radix base); +Str_Result Str_convertULong(const char* str, Str_ULong* num, Str_Radix base); +Str_Result Str_convertLongFix(const char* str, Str_Long* num, Str_Radix base, Str_LenType len); +Str_Result Str_convertULongFix(const char* str, Str_ULong* num, Str_Radix base, Str_LenType len); + +#endif // STR_ENABLE_LONG_NUMBER + +Str_LenType Str_parseFloat(float num, char* str); +Str_LenType Str_parseFloatFix(float num, char* str, Str_LenType decimalLen); + +Str_Result Str_convertFloat(const char* str, float* num); +Str_Result Str_convertFloatFix(const char* str, float* num, Str_LenType len); + +#if STR_ENABLE_DOUBLE + +Str_LenType Str_parseDouble(double num, char* str); +Str_LenType Str_parseDoubleFix(double num, char* str, Str_LenType decimalLen); + +Str_Result Str_convertDouble(const char* str, double* num); +Str_Result Str_convertDoubleFix(const char* str, double* num, Str_LenType len); + +#endif // STR_ENABLE_DOUBLE + +Str_Result Str_getNum(const char* str, int* num, const char** numPos); +Str_Result Str_getUNum(const char* str, unsigned int* num, const char** numPos); +Str_Result Str_getFloat(const char* str, float* num, const char** numPos); + +Str_Result Str_getToken(const char* str, char separator, Str_LenType index, char* token); +Str_Result Str_getTokenFix(const char* str, char separator, Str_LenType index, char* token, Str_LenType len); + +/** + * Sorting Functions + **/ + +#define Mem_castItem(TYPE, ITEM) ((TYPE*) ITEM) + +typedef Mem_CmpResult (*Mem_CompareFn) (const void* itemA, const void* itemB, Mem_LenType itemLen); +typedef void (*Mem_SwapFn) (void* itemA, void* itemB, Mem_LenType itemLen); + +void* Mem_sort(void* items, Mem_LenType len, Mem_LenType itemLen, Mem_CompareFn cmp, Mem_SwapFn swap); +void* Mem_quickSort(void* items, Mem_LenType len, Mem_LenType itemLen, Mem_CompareFn cmp, Mem_SwapFn swap); + +Mem_LenType Mem_partition(void* items, Mem_LenType low, Mem_LenType high, Mem_LenType itemLen, Mem_CompareFn cmp, Mem_SwapFn swap); +void* Mem_quickSortBlock(void* items, Mem_LenType low, Mem_LenType high, Mem_LenType itemLen, Mem_CompareFn cmp, Mem_SwapFn swap); + +Mem_LenType Mem_linearSearch(const void* items, Mem_LenType len, Mem_LenType itemLen, const void* item, Mem_CompareFn cmp); +Mem_LenType Mem_binarySearch(const void* items, Mem_LenType len, Mem_LenType itemLen, const void* item, Mem_CompareFn cmp); + +typedef Str_CmpResult (*Str_CompareFn) (const char* itemA, const char* ItemB); + +void Str_swap(const char** itemA, const char** itemB); +Str_LenType Str_partition(const char** items, Str_LenType low, Str_LenType high, Str_CompareFn cmp); +const char** Str_quickSortBlock(const char** items, Mem_LenType low, Mem_LenType high, Str_CompareFn cmp); + +const char** Str_selectionSortBlock(const char** items, Mem_LenType len, Str_CompareFn cmp); + +Str_LenType Str_linearSearch(const char** strs, Str_LenType len, const char* str, Str_CompareFn cmp); +Str_LenType Str_binarySearch(const char** strs, Str_LenType len, const char* str, Str_CompareFn cmp); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif // _STR_UTILS_H_ + + diff --git a/Examples/StreamOverSocket/Stream/InputStream.c b/Examples/StreamOverSocket/Stream/InputStream.c new file mode 100644 index 0000000..7eb4f0c --- /dev/null +++ b/Examples/StreamOverSocket/Stream/InputStream.c @@ -0,0 +1,187 @@ +#include "InputStream.h" +#include + +/** + * @brief Initialize InputStream + * + * @param stream InputStream to initialize + * @param receiveFn Function to receive data + * @param buff Buffer to hold data + * @param size Size of buffer + */ +void IStream_init(IStream* stream, IStream_ReceiveFn receiveFn, uint8_t* buff, Stream_LenType size) { + Stream_init(&stream->Buffer, buff, size); + stream->receive = receiveFn; +#if ISTREAM_ARGS + stream->Args = (void*) 0; +#endif +#if ISTREAM_CHECK_RECEIVE + stream->checkReceive = (IStream_CheckReceiveFn) 0; +#endif + stream->IncomingBytes = 0; +} +/** + * @brief Deinitialize InputStream + * + * @param stream InputStream to deinitialize + */ +void IStream_deinit(IStream* stream) { + memset(stream, 0, sizeof(IStream)); +} + +/** + * @brief call in interrupt or RxCplt callback for Async Receive + * + * @param stream + * @param len + * @return Stream_Result + */ +Stream_Result IStream_handle(IStream* stream, Stream_LenType len) { + Stream_Result res; + + if (!stream->Buffer.InReceive) { + return Stream_NoReceive; + } + + if (stream->IncomingBytes < len) { + len = stream->IncomingBytes; + } + + stream->Buffer.InReceive = 0; + if ((res = Stream_moveWritePos(&stream->Buffer, len)) != Stream_Ok) { + return res; + } + + return IStream_receive(stream); +} +/** + * @brief call receive function for Async read + * + * @param stream + * @return Stream_Result + */ +Stream_Result IStream_receive(IStream* stream) { + if (!stream->Buffer.InReceive) { + Stream_LenType len = Stream_directSpace(&stream->Buffer); + stream->IncomingBytes = len; + if (len > 0) { + if (stream->receive) { + stream->Buffer.InReceive = 1; + return stream->receive(stream, IStream_getDataPtr(stream), len); + } + else { + return Stream_NoReceiveFn; + } + } + else { + return Stream_NoSpace; + } + } + else { + return Stream_InReceive; + } +} +/** + * @brief blocking receive for 1 byte + * + * @param stream + * @param val + * @return Stream_Result + */ +Stream_Result IStream_receiveByte(IStream* stream, uint8_t val) { + *IStream_getDataPtr(stream) = val; + return Stream_moveWritePos(&stream->Buffer, 1); + +} +/** + * @brief blocking receive for n bytes + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result IStream_receiveBytes(IStream* stream, uint8_t* val, Stream_LenType len) { + return Stream_writeBytes(&stream->Buffer, val, len); +} +#if ISTREAM_ARGS +/** + * @brief set args for IStream + * + * @param stream + * @param args + */ +void IStream_setArgs(IStream* stream, void* args) { + stream->Args = args; +} +/** + * @brief get args form IStream + * + * @param stream + * @return void* + */ +void* IStream_getArgs(IStream* stream) { + return stream->Args; +} +#endif // ISTREAM_ARGS +/** + * @brief return available bytes in buffer to read + * + * @param stream + * @return Stream_LenType + */ +Stream_LenType IStream_available(IStream* stream) { +#if ISTREAM_CHECK_RECEIVE + if (stream->checkReceive) { + Stream_LenType len = stream->checkReceive(stream); + if (len > 0) { + if (stream->IncomingBytes < len) { + len = stream->IncomingBytes; + } + Stream_moveWritePos(&stream->Buffer, len); + stream->IncomingBytes -= len; + if (stream->Buffer.WPos == 0) { + IStream_receive(stream); + } + } + } +#endif // ISTREAM_CHECK_RECEIVE + // now get available bytes len + return Stream_available(&stream->Buffer); +} +#if ISTREAM_CHECK_RECEIVE +/** + * @brief set check receive function + * + * @param stream + * @param fn + */ +void IStream_setCheckReceive(IStream* stream, IStream_CheckReceiveFn fn) { + stream->checkReceive = fn; +} +#endif // ISTREAM_CHECK_RECEIVE +/** + * @brief return number of bytes that in receive + * + * @param stream + * @return Stream_LenType + */ +Stream_LenType IStream_incomingBytes(IStream* stream) { + return stream->IncomingBytes; +} +#if ISTREAM_LOCK +/** + * @brief lock input stream for fixed write + * + * @param stream + * @param lock + * @return Stream_Result + */ +Stream_Result IStream_lock(IStream* stream, IStream* lock, Stream_LenType len) { + Stream_Result res; + if ((res = Stream_lockRead(&stream->Buffer, &lock->Buffer, len)) == Stream_Ok) { + memcpy(&lock->receive, &stream->receive, sizeof(IStream) - sizeof(Stream)); + } + return res; +} +#endif // ISTREAM_LOCK diff --git a/Examples/StreamOverSocket/Stream/InputStream.h b/Examples/StreamOverSocket/Stream/InputStream.h new file mode 100644 index 0000000..9d8274a --- /dev/null +++ b/Examples/StreamOverSocket/Stream/InputStream.h @@ -0,0 +1,308 @@ +/** + * @file InputStream.h + * @author Ali Mirghasemi (ali.mirghasemi1376@gamil.com) + * @brief this library implement input stream over stream buffer + * @version 0.4 + * @date 2021-09-01 + * + * @copyright Copyright (c) 2021 + * + */ +#ifndef _INPUT_STREAM_H_ +#define _INPUT_STREAM_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define ISTREAM_VER_MAJOR 0 +#define ISTREAM_VER_MINOR 5 +#define ISTREAM_VER_FIX 0 + +#include "StreamBuffer.h" + +/************************************************************************/ +/* Configuration */ +/************************************************************************/ + +/** + * @brief enable user argument in OStream + */ +#define ISTREAM_ARGS 1 +/** + * @brief enable checkTransmit function + */ +#define ISTREAM_CHECK_RECEIVE 1 +/** + * @brief enable lock read feature + */ +#define ISTREAM_LOCK STREAM_READ_LOCK + + +/************************************************************************/ + +/** + * @brief show stream version in string format + */ +#define ISTREAM_VER_STR _STREAM_VER_STR(ISTREAM_VER_MAJOR, ISTREAM_VER_MINOR, ISTREAM_VER_FIX) +/** + * @brief show stream version in integer format, ex: 0.2.0 -> 200 + */ +#define ISTREAM_VER ((ISTREAM_VER_MAJOR * 10000UL) + (ISTREAM_VER_MINOR * 100UL) + (ISTREAM_VER_FIX)) + +/* Pre-defined variables */ +struct __IStream; +typedef struct __IStream IStream; +/** + * @brief receive function, OStream_space + * @param stream IStream + * @param buff uint8_t* + * @param len Stream_LenType + * @return Stream_Result + */ +typedef Stream_Result (*IStream_ReceiveFn)(IStream* stream, uint8_t* buff, Stream_LenType len); +/** + * @brief check how many bytes received, this functions allows to check + * how many bytes received in available function, it's good to work with DMA + * @param stream IStream + * @return Stream_LenType + */ +typedef Stream_LenType (*IStream_CheckReceiveFn)(IStream* stream); + +/** + * @brief hold InputStream properties + */ +struct __IStream { + Stream Buffer; /**< hold stream buffer */ + IStream_ReceiveFn receive; /**< receive function */ +#if ISTREAM_ARGS + void* Args; /**< hold user defined arguments */ +#endif +#if ISTREAM_CHECK_RECEIVE + IStream_CheckReceiveFn checkReceive; /**< check receive function */ +#endif + Stream_LenType IncomingBytes; /**< hold how many bytes are coming */ +}; + + +void IStream_init(IStream* stream, IStream_ReceiveFn receiveFn, uint8_t* buff, Stream_LenType size); +void IStream_deinit(IStream* stream); + + +/* Input Bytes of IStream */ +Stream_Result IStream_handle(IStream* stream, Stream_LenType len); +Stream_Result IStream_receive(IStream* stream); +Stream_Result IStream_receiveByte(IStream* stream, uint8_t val); +Stream_Result IStream_receiveBytes(IStream* stream, uint8_t* val, Stream_LenType len); + +#define IStream_availableUncheck(STREAM) Stream_available(&(STREAM)->Buffer) +Stream_LenType IStream_available(IStream* stream); + +Stream_LenType IStream_incomingBytes(IStream* stream); + +#define IStream_inReceive(STREAM) Stream_inReceive(&(STREAM)->Buffer) + +#if ISTREAM_ARGS + void IStream_setArgs(IStream* stream, void* args); + void* IStream_getArgs(IStream* stream); +#endif // ISTREAM_ARGS + +#if ISTREAM_CHECK_RECEIVE + void IStream_setCheckReceive(IStream* stream, IStream_CheckReceiveFn fn); +#endif // ISTREAM_CHECK_RECEIVE + +#if ISTREAM_LOCK + Stream_Result IStream_lock(IStream* stream, IStream* lock, Stream_LenType len); + #define IStream_unlock(STREAM, LOCK) Stream_unlockRead(&(STREAM)->Buffer, &(LOCK)->Buffer); + #define IStream_unlockIgnore(STREAM) Stream_unlockReadIgnore(&(STREAM)->Buffer) + #define IStream_lockLen(STREAM, LOCK) Stream_lockReadLen(&(STREAM)->Buffer, &(LOCK)->Buffer) +#endif // ISTREAM_LOCK + +#define IStream_getDataPtr(STREAM) Stream_getWritePtr(&((STREAM)->Buffer)) + +#define IStream_clear(STREAM) Stream_clear(&((STREAM)->Buffer)) +#define IStream_reset(STREAM) Stream_reset(&((STREAM)->Buffer)) +#define IStream_resetIO(STREAM) Stream_resetIO(&((STREAM)->Buffer)) + +#if STREAM_BYTE_ORDER + #define IStream_getSystemByteOrder() Stream_getSystemByteOrder() + #define IStream_setByteOrder(STREAM, ORDER) Stream_setByteOrder(&((STREAM)->Buffer), ORDER) + #define IStream_getByteOrder(STREAM) Stream_getByteOrder(&((STREAM)->Buffer)) +#endif + +#if STREAM_READ_LIMIT + #define IStream_setLimit(STREAM, LEN) Stream_setReadLimit(&((STREAM)->Buffer), (LEN)) + #define IStream_getLimit(STREAM) Stream_getReadLimit(&((STREAM)->Buffer)) + #define IStream_isLimited(STREAM) Stream_isReadLimited(&((STREAM)->Buffer)) +#endif + +#if STREAM_CURSOR + #define IStream_getCursor(STREAM, CUR) Stream_getCursor(&((STREAM)->Buffer), (CUR)) + #define IStream_len(STREAM, CUR) Stream_getReadLen(&((STREAM)->Buffer), (CUR)) +#endif + +#define IStream_ignore(STREAM, LEN) Stream_moveReadPos(&((STREAM)->Buffer), (LEN)) + +/* Read function same as Stream read functions */ +#define IStream_read(STREAM) Stream_read(&((STREAM)->Buffer)) +#define IStream_readBytes(STREAM, VAL, LEN) Stream_readBytes(&((STREAM)->Buffer), (VAL), (LEN)) +#define IStream_readBytesReverse(STREAM, VAL, LEN) Stream_readBytesReverse(&((STREAM)->Buffer), (VAL), (LEN)) +#define IStream_readStream(IN, OUT, LEN) Stream_readStream(&((IN)->Buffer), &((OUT)->Buffer), (LEN)) +#define IStream_readChar(STREAM) Stream_readChar(&((STREAM)->Buffer)) +#define IStream_readUInt8(STREAM) Stream_readUInt8(&((STREAM)->Buffer)) +#define IStream_readInt8(STREAM) Stream_readInt8(&((STREAM)->Buffer)) +#define IStream_readUInt16(STREAM) Stream_readUInt16(&((STREAM)->Buffer)) +#define IStream_readInt16(STREAM) Stream_readInt16(&((STREAM)->Buffer)) +#define IStream_readUInt32(STREAM) Stream_readUInt32(&((STREAM)->Buffer)) +#define IStream_readInt32(STREAM) Stream_readInt32(&((STREAM)->Buffer)) +#define IStream_readFloat(STREAM) Stream_readFloat(&((STREAM)->Buffer)) + +#if STREAM_UINT64 + #define IStream_readUInt64(STREAM) Stream_readUInt64(&((STREAM)->Buffer)) + #define IStream_readInt64(STREAM) Stream_readInt64(&((STREAM)->Buffer)) +#endif // STREAM_UINT64 +#if STREAM_DOUBLE + #define IStream_readDouble(STREAM) Stream_readDouble(&((STREAM)->Buffer)) +#endif // STREAM_DOUBLE + +#define IStream_readCharArray(STREAM, VAL, LEN) Stream_readCharArray(&((STREAM)->Buffer), (VAL), (LEN)) +#define IStream_readUInt8Array(STREAM, VAL, LEN) Stream_readUInt8Array(&((STREAM)->Buffer), (VAL), (LEN)) +#define IStream_readInt8Array(STREAM, VAL, LEN) Stream_readInt8Array(&((STREAM)->Buffer), (VAL), (LEN)) +#define IStream_readUInt16Array(STREAM, VAL, LEN) Stream_readUInt16Array(&((STREAM)->Buffer), (VAL), (LEN)) +#define IStream_readInt16Array(STREAM, VAL, LEN) Stream_readInt16Array(&((STREAM)->Buffer), (VAL), (LEN)) +#define IStream_readUInt32Array(STREAM, VAL, LEN) Stream_readUInt32Array(&((STREAM)->Buffer), (VAL), (LEN)) +#define IStream_readInt32Array(STREAM, VAL, LEN) Stream_readInt32Array(&((STREAM)->Buffer), (VAL), (LEN)) +#define IStream_readFloatArray(STREAM, VAL, LEN) Stream_readFloatArray(&((STREAM)->Buffer), (VAL), (LEN)) + +#if STREAM_UINT64 + #define IStream_readUInt64Array(STREAM,VAL,LEN) Stream_readUInt64Array(&((STREAM)->Buffer), (VAL), (LEN)) + #define IStream_readInt64Array(STREAM,VAL,LEN) Stream_readInt64Array(&((STREAM)->Buffer), (VAL), (LEN)) +#endif // STREAM_UINT64 +#if STREAM_DOUBLE + #define IStream_readDoubleArray(STREAM,VAL,LEN) Stream_readDoubleArray(&((STREAM)->Buffer), (VAL), (LEN)) +#endif // STREAM_DOUBLE + +#define IStream_getBytes(STREAM, VAL, LEN) Stream_getBytes((STREAM), (VAL), (LEN)) +#define IStream_getBytesReverse(STREAM, VAL, LEN) Stream_getBytesReverse(&((STREAM)->Buffer), (VAL), (LEN)); +#define IStream_getChar(STREAM) Stream_getChar(&((STREAM)->Buffer)) +#define IStream_getUInt8(STREAM) Stream_getUInt8(&((STREAM)->Buffer)) +#define IStream_getInt8(STREAM) Stream_getInt8(&((STREAM)->Buffer)) +#define IStream_getUInt16(STREAM) Stream_getUInt16(&((STREAM)->Buffer)) +#define IStream_getInt16(STREAM) Stream_getInt16(&((STREAM)->Buffer)) +#define IStream_getUInt32(STREAM) Stream_getUInt32(&((STREAM)->Buffer)) +#define IStream_getInt32(STREAM) Stream_getInt32(&((STREAM)->Buffer)) +#define IStream_getFloat(STREAM) Stream_getFloat(&((STREAM)->Buffer)) + +#if STREAM_UINT64 + #define IStream_getUInt64(STREAM) Stream_getUInt64(&((STREAM)->Buffer)) + #define IStream_getInt64(STREAM) Stream_getInt64(&((STREAM)->Buffer)) +#endif // STREAM_UINT64 +#if STREAM_DOUBLE + #define IStream_getDouble(STREAM) Stream_getDouble(&((STREAM)->Buffer)) +#endif // STREAM_DOUBLE + +#define IStream_getCharArray(STREAM, VAL, LEN) Stream_getCharArray(&((STREAM)->Buffer), (VAL), (LEN)) +#define IStream_getUInt8Array(STREAM, VAL, LEN) Stream_getUInt8Array(&((STREAM)->Buffer), (VAL), (LEN)) +#define IStream_getInt8Array(STREAM, VAL, LEN) Stream_getInt8Array(&((STREAM)->Buffer), (VAL), (LEN)) +#define IStream_getUInt16Array(STREAM, VAL, LEN) Stream_getUInt16Array(&((STREAM)->Buffer), (VAL), (LEN)) +#define IStream_getInt16Array(STREAM, VAL, LEN) Stream_getInt16Array(&((STREAM)->Buffer), (VAL), (LEN)) +#define IStream_getUInt32Array(STREAM, VAL, LEN) Stream_getUInt32Array(&((STREAM)->Buffer), (VAL), (LEN)) +#define IStream_getInt32Array(STREAM, VAL, LEN) Stream_getInt32Array(&((STREAM)->Buffer), (VAL), (LEN)) +#define IStream_getFloatArray(STREAM, VAL, LEN) Stream_getFloatArray(&((STREAM)->Buffer), (VAL), (LEN)) + +#if STREAM_UINT64 + #define IStream_getUInt64Array(STREAM,VAL,LEN) Stream_getUInt64Array(&((STREAM)->Buffer), (VAL), (LEN)) + #define IStream_getInt64Array(STREAM,VAL,LEN) Stream_getInt64Array(&((STREAM)->Buffer), (VAL), (LEN)) +#endif // STREAM_UINT64 +#if STREAM_DOUBLE + #define IStream_getDoubleArray(STREAM,VAL,LEN) Stream_getDoubleArray(&((STREAM)->Buffer), (VAL), (LEN)) +#endif // STREAM_DOUBLE + +#define IStream_getBytesAt(STREAM, IXD, VAL, LEN) Stream_getBytesAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN)) +#define IStream_getBytesReverseAt(STREAM, IDX, VAL, LEN) Stream_getBytesReverseAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN)); +#define IStream_getCharAt(STREAM, IDX) Stream_getCharAt(&((STREAM)->Buffer), (IDX)) +#define IStream_getUInt8At(STREAM, IDX) Stream_getUInt8At(&((STREAM)->Buffer), (IDX)) +#define IStream_getInt8At(STREAM, IDX) Stream_getInt8At(&((STREAM)->Buffer), (IDX)) +#define IStream_getUInt16At(STREAM, IDX) Stream_getUInt16At(&((STREAM)->Buffer), (IDX)) +#define IStream_getInt16At(STREAM, IDX) Stream_getInt16At(&((STREAM)->Buffer), (IDX)) +#define IStream_getUInt32At(STREAM, IDX) Stream_getUInt32At(&((STREAM)->Buffer), (IDX)) +#define IStream_getInt32At(STREAM, IDX) Stream_getInt32At(&((STREAM)->Buffer), (IDX)) +#define IStream_getFloatAt(STREAM, IDX) Stream_getFloatAt(&((STREAM)->Buffer), (IDX)) + +#if STREAM_UINT64 + #define IStream_getUInt64At(STREAM) Stream_getUInt64At(&((STREAM)->Buffer), (IDX)) + #define IStream_getInt64At(STREAM) Stream_getInt64At(&((STREAM)->Buffer), (IDX)) +#endif // STREAM_UINT64 +#if STREAM_DOUBLE + #define IStream_getDoubleAt(STREAM) Stream_getDoubleAt(&((STREAM)->Buffer), (IDX)) +#endif // STREAM_DOUBLE + +#define IStream_getCharArrayAt(STREAM, IDX, VAL, LEN) Stream_getCharArrayAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN)) +#define IStream_getUInt8ArrayAt(STREAM, IDX, VAL, LEN) Stream_getUInt8ArrayAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN)) +#define IStream_getInt8ArrayAt(STREAM, IDX, VAL, LEN) Stream_getInt8ArrayAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN)) +#define IStream_getUInt16ArrayAt(STREAM, IDX, VAL, LEN) Stream_getUInt16ArrayAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN)) +#define IStream_getInt16ArrayAt(STREAM, IDX, VAL, LEN) Stream_getInt16ArrayAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN)) +#define IStream_getUInt32ArrayAt(STREAM, IDX, VAL, LEN) Stream_getUInt32ArrayAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN)) +#define IStream_getInt32ArrayAt(STREAM, IDX, VAL, LEN) Stream_getInt32ArrayAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN)) +#define IStream_getFloatArrayAt(STREAM, IDX, VAL, LEN) Stream_getFloatArrayAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN)) + +#if STREAM_UINT64 + #define IStream_getUInt64ArrayAt(STREAM,IDX,VAL,LEN) Stream_getUInt64ArrayAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN)) + #define IStream_getInt64ArrayAt(STREAM,IDX,VAL,LEN) Stream_getInt64ArrayAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN)) +#endif // STREAM_UINT64 +#if STREAM_DOUBLE + #define IStream_getDoubleArrayAt(STREAM,IDX,VAL,LEN) Stream_getDoubleArrayAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN)) +#endif // STREAM_DOUBLE + +#if STREAM_FIND_FUNCTIONS + #define IStream_findByte(STREAM, VAL) Stream_findByte(&((STREAM)->Buffer), (VAL)) + #define IStream_findByteAt(STREAM, IDX, VAL) Stream_findByteAt(&((STREAM)->Buffer)) + #define IStream_findPattern(STREAM, PAT, PAT_LEN) Stream_findPattern(&((STREAM)->Buffer), (PAT), (PAT_LEN)) + #define IStream_findPatternAt(STREAM, IDX, PAT, PAT_LEN) Stream_findPatternAt(&((STREAM)->Buffer), (IDX), (PAT), (PAT_LEN)) + #define IStream_readBytesUntil(STREAM, END, VAL, LEN) Stream_readBytesUntil(&((STREAM)->Buffer), (END), (VAL), (LEN)) + #define IStream_readBytesUntilAt(STREAM, IDX, END, VAL, LEN) Stream_readBytesUntil(&((STREAM)->Buffer), (IDX), (END), (VAL), (LEN)) + #define IStream_readBytesUntilPattern(STREAM, PAT, PAT_LEN, VAL, LEN) Stream_readBytesUntilPattern(&((STREAM)->Buffer), (PAT), (PAT_LEN), (VAL), (LEN)) + #define IStream_readBytesUntilPatternAt(STREAM, IDX, PAT, PAT_LEN, VAL, LEN) Stream_readBytesUntilPatternAt(&((STREAM)->Buffer), (IDX), (PAT), (PAT_LEN), (VAL), (LEN)) + + #define IStream_findUInt8(STREAM, VAL) Stream_findUInt8(&((STREAM)->Buffer), (VAL)) + #define IStream_findInt8(STREAM, VAL) Stream_findInt8(&((STREAM)->Buffer), (VAL)) + #define IStream_findUInt16(STREAM, VAL) Stream_findUInt16(&((STREAM)->Buffer), (VAL)) + #define IStream_findInt16(STREAM, VAL) Stream_findInt16(&((STREAM)->Buffer), (VAL)) + #define IStream_findUInt32(STREAM, VAL) Stream_findUInt32(&((STREAM)->Buffer), (VAL)) + #define IStream_findInt32(STREAM, VAL) Stream_findInt32(&((STREAM)->Buffer), (VAL)) +#if STREAM_UINT64 + #define IStream_findUInt64(STREAM, VAL) Stream_findUInt64(&((STREAM)->Buffer), (VAL)) + #define IStream_findInt64(STREAM, VAL) Stream_findInt64(&((STREAM)->Buffer), (VAL)) +#endif + #define IStream_findFloat(STREAM, VAL) Stream_findFloat(&((STREAM)->Buffer), (VAL)) +#if STREAM_DOUBLE + #define IStream_findDouble(STREAM, VAL) Stream_findDouble(&((STREAM)->Buffer), (VAL)) +#endif + +#if STREAM_FIND_AT_FUNCTIONS + #define IStream_findUInt8At(STREAM, IDX, VAL) Stream_findUInt8(&((STREAM)->Buffer), (IDX), (VAL)) + #define IStream_findInt8At(STREAM, IDX, VAL) Stream_findInt8(&((STREAM)->Buffer), (IDX), (VAL)) + #define IStream_findUInt16At(STREAM, IDX, VAL) Stream_findUInt16(&((STREAM)->Buffer), (IDX), (VAL)) + #define IStream_findInt16At(STREAM, IDX, VAL) Stream_findInt16(&((STREAM)->Buffer), (IDX), (VAL)) + #define IStream_findUInt32At(STREAM, IDX, VAL) Stream_findUInt32(&((STREAM)->Buffer), (IDX), (VAL)) + #define IStream_findInt32At(STREAM, IDX, VAL) Stream_findInt32(&((STREAM)->Buffer), (IDX), (VAL)) +#if STREAM_UINT64 + #define IStream_findUInt64At(STREAM, IDX, VAL) Stream_findUInt64(&((STREAM)->Buffer), (IDX), (VAL)) + #define IStream_findInt64At(STREAM, IDX, VAL) Stream_findInt64(&((STREAM)->Buffer), (IDX), (VAL)) +#endif + #define IStream_findFloatAt(STREAM, IDX, VAL) Stream_findFloat(&((STREAM)->Buffer), (IDX), (VAL)) +#if STREAM_DOUBLE + #define IStream_findDoubleAt(STREAM, IDX, VAL) Stream_findDouble(&((STREAM)->Buffer), (IDX), (VAL)) +#endif +#endif // STREAM_FIND_AT_FUNCTIONS + +#endif // STREAM_FIND_FUNCTIONS + +#define IStream_compare(STREAM, VAL, LEN) Stream_compareAt(&((STREAM)->Buffer), (VAL), (LEN)) +#define IStream_compareAt(STREAM, IDX, VAL, LEN) Stream_compareAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN)) + +#ifdef __cplusplus +}; +#endif + +#endif /* _INPUT_STREAM_H_ */ diff --git a/Examples/StreamOverSocket/Stream/OutputStream.c b/Examples/StreamOverSocket/Stream/OutputStream.c new file mode 100644 index 0000000..4b0e9bc --- /dev/null +++ b/Examples/StreamOverSocket/Stream/OutputStream.c @@ -0,0 +1,256 @@ +#include "OutputStream.h" +#include + +/** + * @brief Initialize OutputStream + * + * @param stream OutputStream to initialize + * @param transmitFn Function to transmit data + * @param buff Buffer to hold data + * @param size Size of buffer + */ +void OStream_init(OStream* stream, OStream_TransmitFn transmitFn, uint8_t* buff, Stream_LenType size) { + Stream_init(&stream->Buffer, buff, size); + stream->Buffer.FlushMode = OSTREAM_FLUSH_MODE; + stream->transmit = transmitFn; +#if OSTREAM_ARGS + stream->Args = (void*) 0; +#endif +#if OSTREAM_CHECK_TRANSMIT + stream->checkTransmit = (OStream_CheckTransmitFn) 0; +#endif + stream->OutgoingBytes = 0; +} +/** + * @brief Deinitialize OutputStream + * + * @param stream OutputStream to deinitialize + */ +void OStream_deinit(OStream* stream) { + memset(stream, 0, sizeof(OStream)); +} + + +/** + * @brief call it in interrupt or TxCplt for Async Transmit + * + * @param stream + * @param len + * @return Stream_Result + */ +Stream_Result OStream_handle(OStream* stream, Stream_LenType len) { + Stream_Result res; + if (!stream->Buffer.InTransmit) { + return Stream_NoTransmit; + } + + if (stream->OutgoingBytes < len) { + len = stream->OutgoingBytes; + } + + stream->Buffer.InTransmit = 0; + if ((res = Stream_moveReadPos(&stream->Buffer, len)) != Stream_Ok) { + return res; + } + +#if OSTREAM_FLUSH_CALLBACK + if (stream->flushCallback && OStream_pendingBytes(stream) == 0) { + stream->flushCallback(stream); + } +#endif + + return stream->Buffer.FlushMode != Stream_FlushMode_Single ? + OStream_flush(stream) : + Stream_Ok; +} +/** + * @brief start sending bytes and flush stream in Async Transmit + * + * @param stream + * @return Stream_Result + */ +Stream_Result OStream_flush(OStream* stream) { + if (!stream->Buffer.InTransmit) { + Stream_LenType len = Stream_directAvailable(&stream->Buffer); + stream->OutgoingBytes = len; + if (len > 0) { + if (stream->transmit) { + stream->Buffer.InTransmit = 1; + return stream->transmit(stream, OStream_getDataPtr(stream), len); + } + else { + return Stream_NoTransmitFn; + } + } + else { + return Stream_NoAvailable; + } + } + else { + return Stream_InTransmit; + } +} +/** + * @brief flush and wait for transmit all pending bytes + * + * @param stream + * @return Stream_Result + */ +Stream_Result OStream_flushBlocking(OStream* stream) { + Stream_Result res; + + while (OStream_pendingBytes(stream) == 0) { + if ((res = OStream_flush(stream)) != Stream_Ok) { + break; + } + } + + return res; +} +/** + * @brief blocking transmit 1 byte just call transmit function no need handle function + * + * @param stream + * @return Stream_Result + */ +Stream_Result OStream_transmitByte(OStream* stream) { + Stream_LenType len = Stream_directAvailable(&stream->Buffer); + if (len > 0) { + if (stream->transmit) { + stream->transmit(stream, OStream_getDataPtr(stream), 1); + return Stream_moveReadPos(&stream->Buffer, 1); + } + else { + return Stream_NoTransmitFn; + } + } + else { + return Stream_NoAvailable; + } +} +/** + * @brief blocking transmit n byte just call transmit function no need handle function + * + * @param stream + * @return Stream_Result + */ +Stream_Result OStream_transmitBytes(OStream* stream, Stream_LenType len) { + Stream_LenType dirLen = OStream_pendingBytes(stream); + Stream_Result res; + if (dirLen < len) { + len = dirLen; + } + while (len > 0) { + dirLen = Stream_directAvailable(&stream->Buffer); + if (dirLen > 0) { + if (stream->transmit) { + if (dirLen > len) { + dirLen = len; + } + stream->transmit(stream, OStream_getDataPtr(stream), dirLen); + if ((res = Stream_moveReadPos(&stream->Buffer, 1)) != Stream_Ok) { + return res; + } + len -= dirLen; + } + else { + return Stream_NoTransmitFn; + } + } + else { + return Stream_NoAvailable; + } + } + return Stream_Ok; +} +#if OSTREAM_ARGS +/** + * @brief set args for OStream + * + * @param stream + * @param args + */ +void OStream_setArgs(OStream* stream, void* args) { + stream->Args = args; +} +/** + * @brief get args for OStream + * + * @param stream + * @return void* + */ +void* OStream_getArgs(OStream* stream) { + return stream->Args; +} +#endif // OSTREAM_ARGS +#if OSTREAM_CHECK_TRANSMIT +/** + * @brief set check transmit function for OStream + * + * @param stream + * @param checkTransmit + */ +void OStream_setCheckTransmit(OStream* stream, OStream_CheckTransmitFn fn) { + stream->checkTransmit = fn; +} +#endif // OSTREAM_CHECK_TRANSMIT +#if OSTREAM_FLUSH_CALLBACK +/** + * @brief set flush callback function + * + * @param stream + * @param fn + */ +void OStream_setFlushCallback(OStream* stream, OStream_FlushCallbackFn fn) { + stream->flushCallback = fn; +} +#endif +/** + * @brief return available space for write in bytes + * + * @param stream + * @return OStream_CheckTransmitFn + */ +Stream_LenType OStream_space(OStream* stream) { +#if OSTREAM_CHECK_TRANSMIT + if (stream->checkTransmit) { + Stream_LenType len = stream->checkTransmit(stream); + if (len > 0) { + if (stream->OutgoingBytes < len) { + len = stream->OutgoingBytes; + } + Stream_moveReadPos(&stream->Buffer, len); + stream->OutgoingBytes -= len; + if (stream->Buffer.RPos == 0) { + OStream_flush(stream); + } + } + } +#endif // OSTREAM_CHECK_TRANSMIT + return Stream_space(&stream->Buffer); +} +/** + * @brief return number of bytes that are in transmit + * + * @param stream + * @return Stream_LenType + */ +Stream_LenType OStream_outgoingBytes(OStream* stream) { + return stream->OutgoingBytes; +} +#if OSTREAM_LOCK +/** + * @brief lock output stream for fixed write + * + * @param stream + * @param lock + * @return Stream_Result + */ +Stream_Result OStream_lock(OStream* stream, OStream* lock, Stream_LenType len) { + Stream_Result res; + if ((res = Stream_lockWrite(&stream->Buffer, &lock->Buffer, len)) == Stream_Ok) { + memcpy(&lock->transmit, &stream->transmit, sizeof(OStream) - sizeof(Stream)); + } + return res; +} +#endif // OSTREAM_LOCK diff --git a/Examples/StreamOverSocket/Stream/OutputStream.h b/Examples/StreamOverSocket/Stream/OutputStream.h new file mode 100644 index 0000000..30e0f71 --- /dev/null +++ b/Examples/StreamOverSocket/Stream/OutputStream.h @@ -0,0 +1,218 @@ +/** + * @file OutputStream.h + * @author Ali Mirghasemi (ali.mirghasemi1376@gmail.com) + * @brief this library implement output stream over stream buffer + * @version 0.4 + * @date 2021-09-01 + * + * @copyright Copyright (c) 2021 + * + */ +#ifndef _OUTPUT_STREAM_H_ +#define _OUTPUT_STREAM_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define OSTREAM_VER_MAJOR 0 +#define OSTREAM_VER_MINOR 5 +#define OSTREAM_VER_FIX 0 + +#include "StreamBuffer.h" + +/************************************************************************/ +/* Configuration */ +/************************************************************************/ + +/** + * @brief enable user argument in OStream + */ +#define OSTREAM_ARGS 1 +/** + * @brief enable checkTransmit function + */ +#define OSTREAM_CHECK_TRANSMIT 1 +/** + * @brief enable lock write feature + */ +#define OSTREAM_LOCK STREAM_WRITE_LOCK +/** + * @brief set default flush mode + * Stream_FlushMode_Single: flush only pending bytes before call flush function + * Stream_FlushMode_Continue: after flush complete if there is any pending bytes transmit pending bytes again + */ +#define OSTREAM_FLUSH_MODE Stream_FlushMode_Continue +/** + * @brief enable flush complete callback + */ +#define OSTREAM_FLUSH_CALLBACK 1 + +/************************************************************************/ + +/** + * @brief show stream version in string format + */ +#define OSTREAM_VER_STR _STREAM_VER_STR(OSTREAM_VER_MAJOR, OSTREAM_VER_MINOR, OSTREAM_VER_FIX) +/** + * @brief show stream version in integer format, ex: 0.2.0 -> 200 + */ +#define OSTREAM_VER ((OSTREAM_VER_MAJOR * 10000UL) + (OSTREAM_VER_MINOR * 100UL) + (OSTREAM_VER_FIX)) + +/* Pre-defined variables */ +struct __OStream; +typedef struct __OStream OStream; + +/** + * @brief transmit function, this function allow stream to work with hardware + * @param stream OStream + * @param buff uint8_t* + * @param len Stream_LenType + */ +typedef Stream_Result (*OStream_TransmitFn)(OStream* stream, uint8_t* buff, Stream_LenType len); +/** + * @brief check how many bytes transmitted, this functions allow stream to check + * how many bytes transmitted over hardware, it's good for work with DMA + * @param stream OStream + * @return Stream_LenType return how many bytes transmitted + */ +typedef Stream_LenType (*OStream_CheckTransmitFn)(OStream* stream); +/** + * @brief flush callback, call after flush completed + * + */ +typedef void (*OStream_FlushCallbackFn)(OStream* stream); + +/** + * @brief hold OutputStream properties + */ +struct __OStream { + Stream Buffer; /**< stream buffer */ + OStream_TransmitFn transmit; /**< transmit function */ +#if OSTREAM_ARGS + void* Args; /**< user argument */ +#endif +#if OSTREAM_CHECK_TRANSMIT + OStream_CheckTransmitFn checkTransmit; /**< check transmit function */ +#endif +#if OSTREAM_FLUSH_CALLBACK + OStream_FlushCallbackFn flushCallback; /**< flush callback */ +#endif + Stream_LenType OutgoingBytes; /**< outgoing bytes */ +}; + + +void OStream_init(OStream* stream, OStream_TransmitFn transmitFn, uint8_t* buff, Stream_LenType size); +void OStream_deinit(OStream* stream); + + +/* Output Bytes of OStream */ +Stream_Result OStream_handle(OStream* stream, Stream_LenType len); +Stream_Result OStream_flush(OStream* stream); +Stream_Result OStream_flushBlocking(OStream* stream); +Stream_Result OStream_transmitByte(OStream* stream); +Stream_Result OStream_transmitBytes(OStream* stream, Stream_LenType len); + +#define OStream_spaceUncheck(STREAM) Stream_space(&(STREAM)->Buffer) +Stream_LenType OStream_space(OStream* stream); + +Stream_LenType OStream_outgoingBytes(OStream* stream); + +#define OStream_setFlushMode(STREAM, MODE) Stream_setFlushMode(&(STREAM)->Buffer, (MODE)) + +#define OStream_inTransmit(STREAM) Stream_inTransmit(&(STREAM)->Buffer) + +#if OSTREAM_ARGS + void OStream_setArgs(OStream* stream, void* args); + void* OStream_getArgs(OStream* stream); +#endif // OSTREAM_ARGS + +#if OSTREAM_CHECK_TRANSMIT + void OStream_setCheckTransmit(OStream* stream, OStream_CheckTransmitFn fn); +#endif // OSTREAM_CHECK_TRANSMIT + +#if OSTREAM_FLUSH_CALLBACK + void OStream_setFlushCallback(OStream* stream, OStream_FlushCallbackFn fn); +#endif + +#if OSTREAM_LOCK + Stream_Result OStream_lock(OStream* stream, OStream* lock, Stream_LenType len); + #define OStream_unlock(STREAM, LOCK) Stream_unlockWrite(&(STREAM)->Buffer, &(LOCK)->Buffer); + #define OStream_unlockIgnore(STREAM) Stream_unlockWriteIgnore(&(STREAM)->Buffer) + #define OStream_lockLen(STREAM, LOCK) Stream_lockWriteLen(&(STREAM)->Buffer, &(LOCK)->Buffer) +#endif // OSTREAM_LOCK + +/** + * @brief return number of bytes waiting for transmit + */ +#define OStream_pendingBytes(STREAM) Stream_available(&((STREAM)->Buffer)) + +#define OStream_getDataPtr(STREAM) Stream_getReadPtr(&((STREAM)->Buffer)) + +#define OStream_clear(STREAM) Stream_clear(&((STREAM)->Buffer)) +#define OStream_reset(STREAM) Stream_reset(&((STREAM)->Buffer)) +#define OStream_resetIO(STREAM) Stream_resetIO(&((STREAM)->Buffer)) + +#if STREAM_BYTE_ORDER + #define OStream_getSystemByteOrder() Stream_getSystemByteOrder() + #define OStream_setByteOrder(STREAM, ORDER) Stream_setByteOrder(&((STREAM)->Buffer), ORDER) + #define OStream_getByteOrder(STREAM) Stream_getByteOrder(&((STREAM)->Buffer)) +#endif + +#if STREAM_WRITE_LIMIT + #define OStream_setLimit(STREAM, LEN) Stream_setWriteLimit(&((STREAM)->Buffer), (LEN)) + #define OStream_getLimit(STREAM) Stream_getWriteLimit(&((STREAM)->Buffer)) + #define OStream_isLimited(STREAM) Stream_isWriteLimited(&((STREAM)->Buffer)) +#endif + +#if STREAM_CURSOR + #define OStream_getCursor(STREAM, CUR) Stream_getCursor(&((STREAM)->Buffer), (CUR)) + #define OStream_len(STREAM, CUR) Stream_getWriteLen(&((STREAM)->Buffer), (CUR)) +#endif + +#define OStream_ignore(STREAM, LEN) Stream_moveWritePos(&((STREAM)->Buffer), (LEN)) + +#define OStream_writeBytes(STREAM, VAL, LEN) Stream_writeBytes(&((STREAM)->Buffer), (VAL), (LEN)) +#define OStream_writeBytesReverse(STREAM, VAL, LEN) Stream_writeBytesReverse(&((STREAM)->Buffer), (VAL), (LEN)) +#define OStream_writeStream(OUT, IN, LEN) Stream_writeStream(&((OUT)->Buffer), &((IN)->Buffer), (LEN)) +#define OStream_writePadding(STREAM, VAL, LEN) Stream_writePadding(&((STREAM)->Buffer), (VAL), (LEN)) +#define OStream_writeChar(STREAM, VAL) Stream_writeChar(&((STREAM)->Buffer), (VAL)) +#define OStream_writeStr(STREAM, VAL) Stream_writeStr(&((STREAM)->Buffer), (VAL)) +#define OStream_writeUInt8(STREAM, VAL) Stream_writeUInt8(&((STREAM)->Buffer), (VAL)) +#define OStream_writeInt8(STREAM, VAL) Stream_writeInt8(&((STREAM)->Buffer), (VAL)) +#define OStream_writeUInt16(STREAM, VAL) Stream_writeUInt16(&((STREAM)->Buffer), (VAL)) +#define OStream_writeInt16(STREAM, VAL) Stream_writeInt16(&((STREAM)->Buffer), (VAL)) +#define OStream_writeUInt32(STREAM, VAL) Stream_writeUInt32(&((STREAM)->Buffer), (VAL)) +#define OStream_writeInt32(STREAM, VAL) Stream_writeInt32(&((STREAM)->Buffer), (VAL)) +#define OStream_writeFloat(STREAM, VAL) Stream_writeFloat(&((STREAM)->Buffer), (VAL)) +#if STREAM_UINT64 +#define OStream_writeUInt64(STREAM, VAL) Stream_writeUInt64(&((STREAM)->Buffer), (VAL)) +#define OStream_writeInt64(STREAM, VAL) Stream_writeInt64(&((STREAM)->Buffer), (VAL)) +#endif // STREAM_UINT64 +#if STREAM_DOUBLE +#define OStream_writeDouble(STREAM, VAL) Stream_writeDouble(&((STREAM)->Buffer), (VAL)) +#endif // STREAM_DOUBLE + +#define OStream_writeCharArray(STREAM, VAL, LEN) Stream_writeCharArray(&((STREAM)->Buffer), (VAL), (LEN)) +#define OStream_writeUInt8Array(STREAM, VAL, LEN) Stream_writeUInt8Array(&((STREAM)->Buffer), (VAL), (LEN)) +#define OStream_writeInt8Array(STREAM, VAL, LEN) Stream_writeInt8Array(&((STREAM)->Buffer), (VAL), (LEN)) +#define OStream_writeUInt16Array(STREAM, VAL, LEN) Stream_writeUInt16Array(&((STREAM)->Buffer), (VAL), (LEN)) +#define OStream_writeInt16Array(STREAM, VAL, LEN) Stream_writeInt16Array(&((STREAM)->Buffer), (VAL), (LEN)) +#define OStream_writeUInt32Array(STREAM, VAL, LEN) Stream_writeUInt32Array(&((STREAM)->Buffer), (VAL), (LEN)) +#define OStream_writeInt32Array(STREAM, VAL, LEN) Stream_writeInt32Array(&((STREAM)->Buffer), (VAL), (LEN)) +#define OStream_writeFloatArray(STREAM, VAL, LEN) Stream_writeFloatArray(&((STREAM)->Buffer), (VAL), (LEN)) +#if STREAM_UINT64 +#define OStream_writeUInt64Array(STREAM, VAL, LEN) Stream_writeUInt64Array(&((STREAM)->Buffer), (VAL), (LEN)) +#define OStream_writeInt64Array(STREAM, VAL, LEN) Stream_writeInt64Array(&((STREAM)->Buffer), (VAL), (LEN)) +#endif // STREAM_UINT64 +#if STREAM_DOUBLE +#define OStream_writeDoubleArray(STREAM, VAL, LEN) Stream_writeDoubleArray(&((STREAM)->Buffer), (VAL), (LEN)) +#endif // STREAM_DOUBLE + + + +#ifdef __cplusplus +}; +#endif + +#endif // _OUTPUT_STREAM_H_ diff --git a/Examples/StreamOverSocket/Stream/StreamBuffer.c b/Examples/StreamOverSocket/Stream/StreamBuffer.c new file mode 100644 index 0000000..b9dfcfb --- /dev/null +++ b/Examples/StreamOverSocket/Stream/StreamBuffer.c @@ -0,0 +1,2437 @@ +#include "StreamBuffer.h" +#include + +/* Memory IO Macros */ +#if STREAM_MEM_IO == STREAM_MEM_IO_DEFAULT + #define __memCopy(S, DEST, SRC, LEN) STREAM_MEM_COPY((DEST), (SRC), (LEN)) + #define __memCopyReverse(S, DEST, SRC, LEN) STREAM_MEM_COPY_REVERSE((DEST), (SRC), (LEN)) + #define __memSet(S, SRC, VAL, LEN) STREAM_MEM_SET((SRC), (VAL), (LEN)) + #define __memReverse(S, SRC, LEN) STREAM_MEM_REVERSE((SRC), (LEN)) +#elif STREAM_MEM_IO == STREAM_MEM_IO_CUSTOM + #define __memCopy(S, DEST, SRC, LEN) (S)->Mem.copy((DEST), (SRC), (LEN)) + #define __memCopyReverse(S, DEST, SRC, LEN) (S)->Mem.copyReverse((DEST), (SRC), (LEN)) + #define __memSet(S, SRC, VAL, LEN) (S)->Mem.set((SRC), (VAL), (LEN)) + #define __memReverse(S, SRC, LEN) (S)->Mem.reverse((SRC), (LEN)) +#elif STREAM_MEM_IO == STREAM_MEM_IO_DRIVER + #define __memCopy(S, DEST, SRC, LEN) (S)->Mem->copy((DEST), (SRC), (LEN)) + #define __memCopyReverse(S, DEST, SRC, LEN) (S)->Mem->copyReverse((DEST), (SRC), (LEN)) + #define __memSet(S, SRC, VAL, LEN) (S)->Mem->set((SRC), (VAL), (LEN)) + #define __memReverse(S, SRC, LEN) (S)->Mem->reverse((SRC), (LEN)) +#else + #error "STREAM_MEM_IO is invalid!" +#endif + +#if STREAM_BYTE_ORDER +/* private typedef */ +typedef Stream_Result (*Stream_WriteBytesFn)(Stream* stream, uint8_t* val, Stream_LenType len); +typedef Stream_Result (*Stream_ReadBytesFn)(Stream* stream, uint8_t* val, Stream_LenType len); +typedef Stream_Result (*Stream_GetBytesFn)(Stream* stream, Stream_LenType index, uint8_t* val, Stream_LenType len); +/* private variables */ +static const Stream_WriteBytesFn writeBytes[2] = { + Stream_writeBytes, + Stream_writeBytesReverse, +}; +static const Stream_ReadBytesFn readBytes[2] = { + Stream_readBytes, + Stream_readBytesReverse, +}; +#if STREAM_GET_AT_FUNCTIONS +static const Stream_GetBytesFn getBytesAt[2] = { + Stream_getBytesAt, + Stream_getBytesReverseAt, +}; +#endif + + #define __writeBytes(STREAM, VAL, LEN) writeBytes[STREAM->OrderFn]((STREAM), (VAL), (LEN)) + #define __readBytes(STREAM, VAL, LEN) readBytes[STREAM->OrderFn]((STREAM), (VAL), (LEN)) + #define __getBytesAt(STREAM, INDEX, VAL, LEN) getBytesAt[STREAM->OrderFn]((STREAM), (INDEX), (VAL), (LEN)) + + #define __checkReverse(STREAM, VAL) if (STREAM->OrderFn) {__memReverse((STREAM), &VAL, sizeof(VAL));} + +#else + #define __writeBytes(STREAM, VAL, LEN) Stream_writeBytes((STREAM), (VAL), (LEN)) + #define __readBytes(STREAM, VAL, LEN) Stream_readBytes((STREAM), (VAL), (LEN)) + #define __getBytesAt(STREAM, INDEX, VAL, LEN) Stream_getBytesAt((STREAM), (INDEX), (VAL), (LEN)) + + #define __checkReverse(STREAM, VAL) +#endif // STREAM_BYTE_ORDER + +/* private function */ +static void memrcpy(void* dest, const void* src, int len); +static void memreverse(void* arr, int len); + +/* Stream MemIO default driver*/ +#if STREAM_MEM_IO == STREAM_MEM_IO_DRIVER +static const Stream_MemIO STREAM_DEFAULT_DRIVER = { + (Stream_MemCopyFn) STREAM_MEM_COPY, + (Stream_MemCopyReverseFn) STREAM_MEM_COPY_REVERSE, + (Stream_MemSetFn) STREAM_MEM_SET, + (Stream_MemReverseFn) STREAM_MEM_REVERSE, +}; +#endif + +/** + * @brief initialize stream + * + * @param stream address of stream struct + * @param buffer address of byte buffer + * @param size size of buffer + */ +void Stream_init(Stream* stream, uint8_t* buffer, Stream_LenType size) { + stream->Data = buffer; + stream->Size = size; + stream->Overflow = 0; + stream->InReceive = 0; + stream->InTransmit = 0; +#if STREAM_BYTE_ORDER + stream->Order = Stream_getSystemByteOrder(); + stream->OrderFn = 0; +#endif // STREAM_BYTE_ORDER + stream->RPos = 0; + stream->WPos = 0; +#if STREAM_WRITE_LIMIT + stream->WriteLimit = STREAM_NO_LIMIT; +#endif // STREAM_WRITE_LIMIT +#if STREAM_READ_LIMIT + stream->ReadLimit = STREAM_NO_LIMIT; +#endif // STREAM_READ_LIMIT +#if STREAM_WRITE_LOCK + stream->WriteLocked = 0; +#endif // STREAM_WRITE_LOCK +#if STREAM_READ_LOCK + stream->ReadLocked = 0; +#endif // STREAM_READ_LOCK +#if STREAM_MEM_IO == STREAM_MEM_IO_CUSTOM + Stream_setMemIO( + stream, + (Stream_MemCopyFn) STREAM_MEM_COPY, + (Stream_MemCopyReverseFn) STREAM_MEM_COPY_REVERSE, + (Stream_MemSetFn) STREAM_MEM_SET, + (Stream_MemReverseFn) STREAM_MEM_REVERSE + ); +#elif STREAM_MEM_IO == STREAM_MEM_IO_DRIVER + Stream_setMemIO(stream, &STREAM_DEFAULT_DRIVER); +#endif +} +/** + * @brief initialize stream with a buffer that already have data in it + * + * @param stream + * @param buffer + * @param size + */ +void Stream_fromBuff(Stream* stream, uint8_t* buffer, Stream_LenType size) { + Stream_init(stream, buffer, size); + stream->WPos = size; +} +/** + * @brief reset stream struct into default values + * + * @param stream address of stream + */ +void Stream_deinit(Stream* stream) { + __memSet(stream, stream, 0, sizeof(Stream)); +} +#if STREAM_MEM_IO == STREAM_MEM_IO_CUSTOM +/** + * @brief Set custom memory io functions + * if input is null use default functions + * + * @param stream + * @param copy + * @param copyReverse + * @param set + * @param reverse + */ +void Stream_setMemIO( + Stream* stream, + Stream_MemCopyFn copy, + Stream_MemCopyReverseFn copyReverse, + Stream_MemSetFn set, + Stream_MemReverseFn reverse +) { + stream->Mem.copy = copy ? copy : (Stream_MemCopyFn) STREAM_MEM_COPY; + stream->Mem.copyReverse = copyReverse ? copyReverse : (Stream_MemCopyReverseFn) STREAM_MEM_COPY_REVERSE; + stream->Mem.set = set ? set : (Stream_MemSetFn) STREAM_MEM_SET; + stream->Mem.reverse = reverse ? reverse : (Stream_MemReverseFn) STREAM_MEM_REVERSE; +} +#elif STREAM_MEM_IO == STREAM_MEM_IO_DRIVER +/** + * @brief Set memory io driver + * if input is null use default driver. all function must exists + * + * @param stream + * @param mem + */ +void Stream_setMemIO(Stream* stream, const Stream_MemIO* mem) { + stream->Mem = mem ? mem : &STREAM_DEFAULT_DRIVER; +} +#endif + +/** + * @brief return available bytes to read + * + * @param stream + * @return Stream_LenType available bytes + */ +Stream_LenType Stream_availableReal(Stream* stream) { + return stream->Size * stream->Overflow + stream->WPos - stream->RPos; +} +/** + * @brief return buffer space for write bytes + * + * @param stream + * @return Stream_LenType space for write + */ +Stream_LenType Stream_spaceReal(Stream* stream) { + return stream->Size * !stream->Overflow + stream->RPos - stream->WPos; +} +/** + * @brief check stream is empty + * no bytes available to read + * @param stream + * @return uint8_t 0 -> Not Empty, 1-> it's empty + */ +uint8_t Stream_isEmpty(Stream* stream) { + return stream->RPos == stream->WPos && !stream->Overflow; +} +/** + * @brief check stream it's full + * no bytes can write + * + * @param stream + * @return uint8_t 0 -> Not Full, 1-> it's Full + */ +uint8_t Stream_isFull(Stream* stream) { + return stream->RPos == stream->WPos && stream->Overflow; +} +/** + * @brief reset stream + * + * @param stream + */ +void Stream_reset(Stream* stream) { + stream->RPos = 0; + stream->WPos = 0; + stream->Overflow = 0; +} +/** + * @brief reset stream and ignore receive and transmit operations + * + * @param stream + */ +void Stream_resetIO(Stream* stream) { + stream->RPos = 0; + stream->WPos = 0; + stream->Overflow = 0; + stream->InReceive = 0; + stream->InTransmit = 0; +} +/** + * @brief clear buffer and reset stream + * + * @param stream + */ +void Stream_clear(Stream* stream) { + Stream_reset(stream); + __memSet(stream, stream->Data, 0, stream->Size); +} +/** + * @brief + * + * @param stream + * @param mode + */ +void Stream_setFlushMode(Stream* stream, Stream_FlushMode mode) { + stream->FlushMode = mode; +} +/** + * @brief return in receive flag + * + * @param stream + * @return uint8_t + */ +uint8_t Stream_inReceive(Stream* stream) { + return stream->InReceive; +} +/** + * @brief return in transmit flag + * + * @param stream + * @return uint8_t + */ +uint8_t Stream_inTransmit(Stream* stream) { + return stream->InTransmit; +} +/** + * @brief return Write Pos + * + * @param stream + * @return Stream_LenType it's between 0 ~ Size + */ +Stream_LenType Stream_getWritePos(Stream* stream) { + return stream->WPos; +} +/** + * @brief return Read Pos + * + * @param stream + * @return Stream_LenType it's between 0 ~ Size + */ +Stream_LenType Stream_getReadPos(Stream* stream) { + return stream->RPos; +} +/** + * @brief return number of bytes that it's in row in the ram + * use for transmit function in OStream + * + * @param stream + * @return Stream_LenType + */ +Stream_LenType Stream_directAvailable(Stream* stream) { + return stream->Overflow ? stream->Size - stream->RPos : + stream->WPos - stream->RPos; +} +/** + * @brief return number of bytes it's in row in the ram + * use for receive function in IStream + * + * @param stream + * @return Stream_LenType + */ +Stream_LenType Stream_directSpace(Stream* stream) { + return stream->Overflow ? stream->RPos - stream->WPos : + stream->Size - stream->WPos; +} +/** + * @brief return number of bytes that it's in row in the ram + * use for transmit function in OStream + * offset is RPos + * + * @param stream + * @return Stream_LenType + */ +Stream_LenType Stream_directAvailableAt(Stream* stream, Stream_LenType index) { + Stream_LenType len = Stream_availableReal(stream); + Stream_LenType dirLen = Stream_directAvailable(stream); + if (len == dirLen) { + return len - index; + } + else { + return dirLen > index ? dirLen - index : + stream->WPos - (index - dirLen); + } +} +/** + * @brief return number of bytes it's in row in the ram + * use for receive function in IStream + * offset is WPos + * + * @param stream + * @return Stream_LenType + */ +Stream_LenType Stream_directSpaceAt(Stream* stream, Stream_LenType index) { + Stream_LenType len = Stream_spaceReal(stream); + Stream_LenType dirLen = Stream_directSpace(stream); + if (len == dirLen) { + return len - index; + } + else { + return dirLen > index ? dirLen - index : + stream->RPos - (index - dirLen); + } +} +/** + * @brief get ptr to start of WPos in ram + * + * @param stream + * @return uint8_t* + */ +uint8_t* Stream_getWritePtr(Stream* stream) { + return &stream->Data[stream->WPos]; +} +/** + * @brief get ptr to start of RPos in ram + * + * @param stream + * @return uint8_t* + */ +uint8_t* Stream_getReadPtr(Stream* stream) { + return &stream->Data[stream->RPos]; +} +uint8_t* Stream_getWritePtrAt(Stream* stream, Stream_LenType index) { + index += stream->WPos; + + if (index >= stream->Size) { + index %= stream->Size; + } + + return &stream->Data[index]; +} +uint8_t* Stream_getReadPtrAt(Stream* stream, Stream_LenType index) { + index += stream->RPos; + + if (index >= stream->Size) { + index %= stream->Size; + } + + return &stream->Data[index]; +} +/** + * @brief set buffer for stream and reset stream + * + * @param stream + */ +void Stream_setBuffer(Stream* stream, uint8_t* data, Stream_LenType size) { + Stream_init(stream, data, size); +} +/** + * @brief return byte buffer + * + * @param stream + * @return uint8_t* + */ +uint8_t* Stream_getBuffer(Stream* stream) { + return stream->Data; +} +/** + * @brief return size of stream buffer + * + * @param stream + * @return Stream_LenType + */ +Stream_LenType Stream_getBufferSize(Stream* stream) { + return stream->Size; +} +/** + * @brief can use for ignore bytes, and move WPos index + * + * @param stream + * @param steps + * @return Stream_Result + */ +Stream_Result Stream_moveWritePos(Stream* stream, Stream_LenType steps) { + if (Stream_space(stream) < steps) { + return Stream_NoSpace; + } + + stream->WPos += steps; + if (stream->WPos >= stream->Size) { + stream->WPos %= stream->Size; + stream->Overflow = 1; + } + + return Stream_Ok; +} +/** + * @brief can use for ignore bytes, and move RPos index + * + * @param stream + * @param steps + * @return Stream_Result + */ +Stream_Result Stream_moveReadPos(Stream* stream, Stream_LenType steps) { + if (Stream_available(stream) < steps) { + return Stream_NoAvailable; + } + + stream->RPos += steps; + if (stream->RPos >= stream->Size) { + stream->RPos %= stream->Size; + stream->Overflow = 0; + } + + return Stream_Ok; +} +/** + * @brief flip space size for write + * + * @param stream + * @param len + */ +void Stream_flipWrite(Stream* stream, Stream_LenType len) { + stream->RPos = stream->WPos + len; + if (stream->RPos >= stream->Size) { + stream->RPos %= stream->Size; + stream->Overflow = 0; + } + else { + stream->Overflow = 1; + } +} +/** + * @brief flip available size for read + * + * @param stream + * @param len + */ +void Stream_flipRead(Stream* stream, Stream_LenType len) { + stream->WPos = stream->RPos + len; + if (stream->WPos >= stream->Size) { + stream->WPos %= stream->Size; + stream->Overflow = 1; + } + else { + stream->Overflow = 0; + } +} +#if STREAM_BYTE_ORDER + +/** + * @brief determine platform byte order + * + * @return ByteOrder + */ +ByteOrder Stream_getSystemByteOrder(void) { +#if STREAM_BYTE_ORDER_SYS_STATIC + static ByteOrder sysByteOrder = ByteOrder_Reserved; + if (sysByteOrder == ByteOrder_Reserved) { + const uint8_t arr[2] = {0xAA, 0xBB}; + const uint16_t val = 0xAABB; + sysByteOrder = (ByteOrder) (memcmp(arr, (uint8_t*) &val, sizeof(val)) == 0); + } + return sysByteOrder; +#else + const uint8_t arr[2] = {0xAA, 0xBB}; + const uint16_t val = 0xAABB; + return (ByteOrder) (memcmp(arr, (uint8_t*) &val, sizeof(val)) == 0); +#endif +} +/** + * @brief set stream r/w byte order + * + * @param stream + * @param order + */ +void Stream_setByteOrder(Stream* stream, ByteOrder order) { + ByteOrder osOrder = Stream_getSystemByteOrder(); + stream->Order = order; + stream->OrderFn = osOrder != order; +} +/** + * @brief return stream byte order + * + * @param stream + * @return ByteOrder + */ +ByteOrder Stream_getByteOrder(Stream* stream) { + return (ByteOrder) stream->Order; +} +#endif +#if STREAM_WRITE_LIMIT +/** + * @brief set limit for write operations, you can't set limit greater than space + * + * @param stream + * @param len + */ +void Stream_setWriteLimit(Stream* stream, Stream_LenType len) { + Stream_LenType space = Stream_spaceReal(stream); + if (space < len) { + len = space; + } + stream->WriteLimit = len; +} +/** + * @brief return write operation is limited or not + * + * @param stream + * @return uint8_t true means limited + */ +uint8_t Stream_isWriteLimited(Stream* stream) { + return stream->WriteLimit >= 0; +} +/** + * @brief return space available for write bytes respect to write limit + * + * @param stream + * @return Stream_LenType + */ +Stream_LenType Stream_spaceLimit(Stream* stream) { + return stream->WriteLimit >= 0 ? stream->WriteLimit : Stream_spaceReal(stream); +} +Stream_LenType Stream_getWriteLimit(Stream* stream) { + return stream->WriteLimit; +} +#endif // STREAM_WRITE_LIMIT +#if STREAM_READ_LIMIT +/** + * @brief set limit for read operations, you can't set limit greater than available + * + * @param stream + * @param len + */ +void Stream_setReadLimit(Stream* stream, Stream_LenType len) { + Stream_LenType available = Stream_availableReal(stream); + if (available < len) { + len = available; + } + stream->ReadLimit = len; +} +/** + * @brief return read operations is limited or not + * + * @param stream + * @return uint8_t true means it's limited + */ +uint8_t Stream_isReadLimited(Stream* stream) { + return stream->ReadLimit >= 0; +} +/** + * @brief retruna available bytes for read respect to read limit + * + * @param stream + * @return Stream_LenType + */ +Stream_LenType Stream_availableLimit(Stream* stream) { + return stream->ReadLimit >= 0 ? stream->ReadLimit : Stream_availableReal(stream); +} +/** + * @brief return read limit + * + * @param stream + * @return Stream_LenType + */ +Stream_LenType Stream_getReadLimit(Stream* stream) { + return stream->ReadLimit; +} +#endif // STREAM_READ_LIMIT +#if STREAM_CURSOR +/** + * @brief fill cursor object based on given stream + * + * @param stream + * @param cursor + */ +void Stream_getCursor(Stream* stream, Stream_Cursor* cursor) { + cursor->WPos = stream->WPos; + cursor->RPos = stream->RPos; +} +/** + * @brief return read len from cursor pos + * + * @param stream + * @param cursor + * @return Stream_LenType + */ +Stream_LenType Stream_getReadLen(Stream* stream, Stream_Cursor* cursor) { + return cursor->RPos >= stream->RPos ? cursor->RPos - stream->RPos : + (stream->Size - cursor->RPos) + stream->RPos; +} +/** + * @brief return write len from cursor pos + * + * @param stream + * @param cursor + * @return Stream_LenType + */ +Stream_LenType Stream_getWriteLen(Stream* stream, Stream_Cursor* cursor) { + return cursor->WPos >= stream->WPos ? cursor->WPos - stream->WPos : + (stream->Size - cursor->WPos) + stream->WPos; +} +#endif // STREAM_CURSOR +/** + * @brief write byte array into stream + * + * @param stream + * @param val byte array + * @param len len of array + * @return Stream_Result + */ +Stream_Result Stream_writeBytes(Stream* stream, uint8_t* val, Stream_LenType len) { +#if STREAM_CHECK_ZERO_LEN + if (len == 0) { + return Stream_ZeroLen; + } +#endif + if (Stream_space(stream) < len) { + return Stream_NoSpace; + } +#if STREAM_WRITE_LIMIT + if (Stream_isWriteLimited(stream)) { + stream->WriteLimit -= len; + } +#endif + + if (stream->WPos + len >= stream->Size) { + Stream_LenType tmpLen; + + tmpLen = stream->Size - stream->WPos; + len -= tmpLen; + __memCopy(stream, &stream->Data[stream->WPos], val, tmpLen); + val += tmpLen; + // move WPos + stream->WPos = 0; + stream->Overflow = 1; + } + if (len > 0) { + __memCopy(stream, &stream->Data[stream->WPos], val, len); + // move WPos + stream->WPos += len; + } + + return Stream_Ok; +} +/** + * @brief write array into stream in reverse order + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_writeBytesReverse(Stream* stream, uint8_t* val, Stream_LenType len) { +#if STREAM_CHECK_ZERO_LEN + if (len == 0) { + return Stream_ZeroLen; + } +#endif + if (Stream_space(stream) < len) { + return Stream_NoSpace; + } +#if STREAM_WRITE_LIMIT + if (Stream_isWriteLimited(stream)) { + stream->WriteLimit -= len; + } +#endif + + if (stream->WPos + len >= stream->Size) { + Stream_LenType tmpLen; + + tmpLen = stream->Size - stream->WPos; + len -= tmpLen; + __memCopyReverse(stream, &stream->Data[stream->WPos], val + len, tmpLen); + // move WPos + stream->WPos = 0; + stream->Overflow = 1; + } + if (len > 0) { + __memCopyReverse(stream, &stream->Data[stream->WPos], val, len); + // move WPos + stream->WPos += len; + } + + return Stream_Ok; +} +/** + * @brief directly read from a stream and write to another + * + * @param stream + * @param in + * @param len + * @return Stream_Result + */ +Stream_Result Stream_writeStream(Stream* out, Stream* in, Stream_LenType len) { + // check available space for write +#if STREAM_CHECK_ZERO_LEN + if (len == 0) { + return Stream_ZeroLen; + } +#endif + if (Stream_space(out) < len) { + return Stream_NoSpace; + } + // check available bytes for read + if (Stream_available(in) < len) { + return Stream_NoAvailable; + } +#if STREAM_WRITE_LIMIT + if (Stream_isWriteLimited(out)) { + out->WriteLimit -= len; + } +#endif + + if (out->WPos + len >= out->Size) { + Stream_LenType tmpLen; + tmpLen = out->Size - out->WPos; + len -= tmpLen; + Stream_readBytes(in, &out->Data[out->WPos], tmpLen); + // move WPos + out->WPos = 0; + out->Overflow = 1; + } + if (len > 0) { + Stream_readBytes(in, &out->Data[out->WPos], len); + // move WPos + out->WPos += len; + } + + return Stream_Ok; + +} +/** + * @brief this function can use for write value multiple time into stream, can use for padding + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_writePadding(Stream* stream, uint8_t val, Stream_LenType len) { +#if STREAM_CHECK_ZERO_LEN + if (len == 0) { + return Stream_ZeroLen; + } +#endif + if (Stream_space(stream) < len) { + return Stream_NoSpace; + } +#if STREAM_WRITE_LIMIT + if (Stream_isWriteLimited(stream)) { + stream->WriteLimit -= len; + } +#endif + + if (stream->WPos + len >= stream->Size) { + Stream_LenType tmpLen; + + tmpLen = stream->Size - stream->WPos; + len -= tmpLen; + __memSet(stream, &stream->Data[stream->WPos], val, tmpLen); + val += tmpLen; + // move WPos + stream->WPos = 0; + stream->Overflow = 1; + } + if (len > 0) { + __memSet(stream, &stream->Data[stream->WPos], val, len); + // move WPos + stream->WPos += len; + } + + return Stream_Ok; +} +Stream_Result Stream_writeChar(Stream* stream, char val) { + return Stream_writeBytes(stream, (uint8_t*) &val, sizeof(val)); +} +Stream_Result Stream_writeStr(Stream* stream, const char* val) { + return Stream_writeBytes(stream, (uint8_t*) val, strlen(val)); +} +Stream_Result Stream_writeUInt8(Stream* stream, uint8_t val) { + return Stream_writeBytes(stream, (uint8_t*) &val, sizeof(val)); +} +Stream_Result Stream_writeInt8(Stream* stream, int8_t val) { + return Stream_writeBytes(stream, (uint8_t*) &val, sizeof(val)); +} +Stream_Result Stream_writeUInt16(Stream* stream, uint16_t val) { + return __writeBytes(stream, (uint8_t*) &val, sizeof(val)); +} +Stream_Result Stream_writeInt16(Stream* stream, int16_t val) { + return __writeBytes(stream, (uint8_t*) &val, sizeof(val)); +} +Stream_Result Stream_writeUInt32(Stream* stream, uint32_t val) { + return __writeBytes(stream, (uint8_t*) &val, sizeof(val)); +} +Stream_Result Stream_writeInt32(Stream* stream, int32_t val) { + return __writeBytes(stream, (uint8_t*) &val, sizeof(val)); +} +Stream_Result Stream_writeFloat(Stream* stream, float val) { + return __writeBytes(stream, (uint8_t*) &val, sizeof(val)); +} +#if STREAM_UINT64 +Stream_Result Stream_writeUInt64(Stream* stream, uint64_t val) { + return __writeBytes(stream, (uint8_t*) &val, sizeof(val)); +} +Stream_Result Stream_writeInt64(Stream* stream, int64_t val) { + return __writeBytes(stream, (uint8_t*) &val, sizeof(val)); +} +#endif // STREAM_UINT64 +#if STREAM_DOUBLE +Stream_Result Stream_writeDouble(Stream* stream, double val) { + return __writeBytes(stream, (uint8_t*) &val, sizeof(val)); +} +#endif // STREAM_DOUBLE + +/** + * @brief read one byte from stream if available return value between 0~255, else return -1 + * + * @param stream + * @return int16_t + */ +int16_t Stream_read(Stream* stream) { + if (Stream_available(stream)) { + return (int16_t) Stream_readUInt8(stream); + } + else { + return -1; + } +} +/** + * @brief read bytes form stream, if possible + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_readBytes(Stream* stream, uint8_t* val, Stream_LenType len) { +#if STREAM_CHECK_ZERO_LEN + if (len == 0) { + return Stream_ZeroLen; + } +#endif + if (Stream_available(stream) < len) { + return Stream_NoAvailable; + } +#if STREAM_READ_LIMIT + if (Stream_isReadLimited(stream)) { + stream->ReadLimit -= len; + } +#endif + + if (stream->RPos + len >= stream->Size) { + Stream_LenType tmpLen; + + tmpLen = stream->Size - stream->RPos; + len -= tmpLen; + __memCopy(stream, val, &stream->Data[stream->RPos], tmpLen); + val += tmpLen; + // move RPos + stream->RPos = 0; + stream->Overflow = 0; + } + if (len > 0) { + __memCopy(stream, val, &stream->Data[stream->RPos], len); + // move RPos + stream->RPos += len; + } + + return Stream_Ok; +} +Stream_Result Stream_readBytesReverse(Stream* stream, uint8_t* val, Stream_LenType len) { +#if STREAM_CHECK_ZERO_LEN + if (len == 0) { + return Stream_ZeroLen; + } +#endif + if (Stream_available(stream) < len) { + return Stream_NoAvailable; + } +#if STREAM_READ_LIMIT + if (Stream_isReadLimited(stream)) { + stream->ReadLimit -= len; + } +#endif + + if (stream->RPos + len >= stream->Size) { + Stream_LenType tmpLen; + + tmpLen = stream->Size - stream->RPos; + len -= tmpLen; + __memCopyReverse(stream, val + len, &stream->Data[stream->RPos], tmpLen); + // move RPos + stream->RPos = 0; + stream->Overflow = 0; + } + if (len > 0) { + __memCopyReverse(stream, val, &stream->Data[stream->RPos], len); + // move RPos + stream->RPos += len; + } + + return Stream_Ok; +} +Stream_Result Stream_readStream(Stream* in, Stream* out, Stream_LenType len) { +#if STREAM_CHECK_ZERO_LEN + if (len == 0) { + return Stream_ZeroLen; + } +#endif + if (Stream_available(in) < len) { + return Stream_NoAvailable; + } + if (Stream_space(out) < len) { + return Stream_NoSpace; + } +#if STREAM_READ_LIMIT + if (Stream_isReadLimited(in)) { + in->ReadLimit -= len; + } +#endif + + if (in->RPos + len >= in->Size) { + Stream_LenType tmpLen; + + tmpLen = in->Size - in->RPos; + len -= tmpLen; + Stream_writeBytes(out, &in->Data[in->RPos], tmpLen); + // move RPos + in->RPos = 0; + in->Overflow = 0; + } + if (len > 0) { + Stream_writeBytes(out, &in->Data[in->RPos], len); + // move RPos + in->RPos += len; + } + + return Stream_Ok; +} +char Stream_readChar(Stream* stream) { + char val = STREAM_READ_DEFAULT_VALUE; + __readBytes(stream, (uint8_t*) &val, sizeof(val)); + return val; +} +uint8_t Stream_readUInt8(Stream* stream) { + uint8_t val = STREAM_READ_DEFAULT_VALUE; + __readBytes(stream, (uint8_t*) &val, sizeof(val)); + return val; +} +int8_t Stream_readInt8(Stream* stream) { + int8_t val = STREAM_READ_DEFAULT_VALUE; + __readBytes(stream, (uint8_t*) &val, sizeof(val)); + return val; +} +uint16_t Stream_readUInt16(Stream* stream) { + uint16_t val = STREAM_READ_DEFAULT_VALUE; + __readBytes(stream, (uint8_t*) &val, sizeof(val)); + return val; +} +int16_t Stream_readInt16(Stream* stream) { + int16_t val = STREAM_READ_DEFAULT_VALUE; + __readBytes(stream, (uint8_t*) &val, sizeof(val)); + return val; +} +uint32_t Stream_readUInt32(Stream* stream) { + uint32_t val = STREAM_READ_DEFAULT_VALUE; + __readBytes(stream, (uint8_t*) &val, sizeof(val)); + return val; +} +int32_t Stream_readInt32(Stream* stream) { + int32_t val = STREAM_READ_DEFAULT_VALUE; + __readBytes(stream, (uint8_t*) &val, sizeof(val)); + return val; +} +float Stream_readFloat(Stream* stream) { + float val = STREAM_READ_DEFAULT_VALUE; + __readBytes(stream, (uint8_t*) &val, sizeof(val)); + return val; +} +#if STREAM_UINT64 +uint64_t Stream_readUInt64(Stream* stream) { + uint64_t val = STREAM_READ_DEFAULT_VALUE; + __readBytes(stream, (uint8_t*) &val, sizeof(val)); + return val; +} +int64_t Stream_readInt64(Stream* stream) { + int64_t val = STREAM_READ_DEFAULT_VALUE; + __readBytes(stream, (uint8_t*) &val, sizeof(val)); + return val; +} +#endif // STREAM_UINT64 +#if STREAM_DOUBLE +double Stream_readDouble(Stream* stream) { + double val = STREAM_READ_DEFAULT_VALUE; + __readBytes(stream, (uint8_t*) &val, sizeof(val)); + return val; +} +#endif // STREAM_DOUBLE + +#if STREAM_GET_AT_FUNCTIONS && STREAM_GET_FUNCTIONS + +Stream_Result Stream_getBytes(Stream* stream, uint8_t* val, Stream_LenType len) { + return Stream_getBytesAt(stream, stream->RPos, val, len); +} +Stream_Result Stream_getBytesReverse(Stream* stream, uint8_t* val, Stream_LenType len) { + return Stream_getBytesAt(stream, stream->RPos, val, len); +} +char Stream_getChar(Stream* stream) { + return Stream_getCharAt(stream, stream->RPos); +} +uint8_t Stream_getUInt8(Stream* stream) { + return Stream_getUInt8At(stream, stream->RPos); +} +int8_t Stream_getInt8(Stream* stream) { + return Stream_getInt8At(stream, stream->RPos); +} +uint16_t Stream_getUInt16(Stream* stream) { + return Stream_getUInt16At(stream, stream->RPos); +} +int16_t Stream_getInt16(Stream* stream) { + return Stream_getInt16At(stream, stream->RPos); +} +uint32_t Stream_getUInt32(Stream* stream) { + return Stream_getUInt32At(stream, stream->RPos); +} +int32_t Stream_getInt32(Stream* stream) { + return Stream_getInt32At(stream, stream->RPos); +} +float Stream_getFloat(Stream* stream) { + return Stream_getFloatAt(stream, stream->RPos); +} +#if STREAM_UINT64 +uint64_t Stream_getUInt64(Stream* stream) { + return Stream_getUInt64At(stream, stream->RPos); +} +int64_t Stream_getInt64(Stream* stream) { + return Stream_getInt64At(stream, stream->RPos); +} +#endif // STREAM_UINT64 +#if STREAM_DOUBLE +double Stream_getDouble(Stream* stream) { + return Stream_getDoubleAt(stream, stream->RPos); +} +#endif // STREAM_DOUBLE +/** + * @brief get array of characters without change the position of stream + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_getCharArray(Stream* stream, char* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + Stream_LenType index = 0; + while (len-- > 0) { + *val++ = Stream_getCharAt(stream, index++); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +/** + * @brief get array of uint8_t without change the position of stream + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_getUInt8Array(Stream* stream, uint8_t* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + Stream_LenType index = 0; + while (len-- > 0) { + *val++ = Stream_getUInt8At(stream, index++); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +/** + * @brief get array of int8_t without change the position of stream + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_getInt8Array(Stream* stream, int8_t* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + Stream_LenType index = 0; + while (len-- > 0) { + *val++ = Stream_getInt8At(stream, index++); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +/** + * @brief get array of uint16_t without change the position of stream + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_getUInt16Array(Stream* stream, uint16_t* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + Stream_LenType index = 0; + while (len-- > 0) { + *val++ = Stream_getUInt16At(stream, index++); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +/** + * @brief get array of int16_t without change the position of stream + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_getInt16Array(Stream* stream, int16_t* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + Stream_LenType index = 0; + while (len-- > 0) { + *val++ = Stream_getInt16At(stream, index++); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +/** + * @brief get array of uint32_t without change the position of stream + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_getUInt32Array(Stream* stream, uint32_t* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + Stream_LenType index = 0; + while (len-- > 0) { + *val++ = Stream_getUInt32At(stream, index++); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +/** + * @brief get array of int32_t without change the position of stream + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_getInt32Array(Stream* stream, int32_t* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + Stream_LenType index = 0; + while (len-- > 0) { + *val++ = Stream_getInt32At(stream, index++); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +/** + * @brief get array of float without change the position of stream + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_getFloatArray(Stream* stream, float* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + Stream_LenType index = 0; + while (len-- > 0) { + *val++ = Stream_getFloatAt(stream, index++); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +#if STREAM_UINT64 +/** + * @brief get array of uint64_t without change the position of stream + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_getUInt64Array(Stream* stream, uint64_t* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + Stream_LenType index = 0; + while (len-- > 0) { + *val++ = Stream_getUInt64At(stream, index); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +/** + * @brief get array of int64_t without change the position of stream + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_getInt64Array(Stream* stream, int64_t* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + Stream_LenType index = 0; + while (len-- > 0) { + *val++ = Stream_getInt64At(stream, index++); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +#endif // STREAM_UINT64 +#if STREAM_DOUBLE +/** + * @brief get array of double without change the position of stream + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_getDoubleArray(Stream* stream, double* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + Stream_LenType index = 0; + while (len-- > 0) { + *val++ = Stream_getDoubleAt(stream, index); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +#endif // STREAM_DOUBLE + +#endif // STREAM_GET_FUNCTIONS + +#if STREAM_GET_AT_FUNCTIONS + +Stream_Result Stream_getBytesAt(Stream* stream, Stream_LenType index, uint8_t* val, Stream_LenType len) { +#if STREAM_CHECK_ZERO_LEN + if (len == 0) { + return Stream_ZeroLen; + } +#endif + if (Stream_available(stream) - index < len) { + return Stream_NoAvailable; + } + + index = (stream->RPos + index) % stream->Size; + + if (index + len >= stream->Size) { + Stream_LenType tmpLen; + + tmpLen = stream->Size - index; + len -= tmpLen; + __memCopy(stream, val, &stream->Data[index], tmpLen); + val += tmpLen; + index = (index + tmpLen) % stream->Size; + } + + __memCopy(stream, val, &stream->Data[index], len); + + return Stream_Ok; +} +Stream_Result Stream_getBytesReverseAt(Stream* stream, Stream_LenType index, uint8_t* val, Stream_LenType len) { +#if STREAM_CHECK_ZERO_LEN + if (len == 0) { + return Stream_ZeroLen; + } +#endif + if (Stream_available(stream) - index < len) { + return Stream_NoAvailable; + } + + index = (stream->RPos + index) % stream->Size; + + if (index + len >= stream->Size) { + Stream_LenType tmpLen; + + tmpLen = stream->Size - index; + len -= tmpLen; + __memCopyReverse(stream, val, &stream->Data[index + len], tmpLen); + val += tmpLen; + index = (index + tmpLen) % stream->Size; + } + + __memCopyReverse(stream, val, &stream->Data[index], len); + + return Stream_Ok; +} +char Stream_getCharAt(Stream* stream, Stream_LenType index) { + char val = STREAM_READ_DEFAULT_VALUE; + __getBytesAt(stream, index, (uint8_t*) &val, sizeof(val)); + return val; +} +uint8_t Stream_getUInt8At(Stream* stream, Stream_LenType index) { + uint8_t val = STREAM_READ_DEFAULT_VALUE; + __getBytesAt(stream, index, (uint8_t*) &val, sizeof(val)); + return val; +} +int8_t Stream_getInt8At(Stream* stream, Stream_LenType index) { + int8_t val = STREAM_READ_DEFAULT_VALUE; + __getBytesAt(stream, index, (uint8_t*) &val, sizeof(val)); + return val; +} +uint16_t Stream_getUInt16At(Stream* stream, Stream_LenType index) { + uint16_t val = STREAM_READ_DEFAULT_VALUE; + __getBytesAt(stream, index, (uint8_t*) &val, sizeof(val)); + return val; +} +int16_t Stream_getInt16At(Stream* stream, Stream_LenType index) { + int16_t val = STREAM_READ_DEFAULT_VALUE; + __getBytesAt(stream, index, (uint8_t*) &val, sizeof(val)); + return val; +} +uint32_t Stream_getUInt32At(Stream* stream, Stream_LenType index) { + uint32_t val = STREAM_READ_DEFAULT_VALUE; + __getBytesAt(stream, index, (uint8_t*) &val, sizeof(val)); + return val; +} +int32_t Stream_getInt32At(Stream* stream, Stream_LenType index) { + int32_t val = STREAM_READ_DEFAULT_VALUE; + __getBytesAt(stream, index, (uint8_t*) &val, sizeof(val)); + return val; +} +float Stream_getFloatAt(Stream* stream, Stream_LenType index) { + float val = STREAM_READ_DEFAULT_VALUE; + __getBytesAt(stream, index, (uint8_t*) &val, sizeof(val)); + return val; +} +#if STREAM_UINT64 +uint64_t Stream_getUInt64At(Stream* stream, Stream_LenType index) { + uint64_t val = STREAM_READ_DEFAULT_VALUE; + __getBytesAt(stream, index, (uint8_t*) &val, sizeof(val)); + return val; +} +int64_t Stream_getInt64At(Stream* stream, Stream_LenType index) { + int64_t val = STREAM_READ_DEFAULT_VALUE; + __getBytesAt(stream, index, (uint8_t*) &val, sizeof(val)); + return val; +} +#endif // STREAM_UINT64 +#if STREAM_DOUBLE +double Stream_getDoubleAt(Stream* stream, Stream_LenType index) { + double val = STREAM_READ_DEFAULT_VALUE; + __getBytesAt(stream, index, (uint8_t*) &val, sizeof(val)); + return val; +} +#endif // STREAM_DOUBLE + +/** + * @brief get array of string without change the position of stream at given index + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_getCharArrayAt(Stream* stream, Stream_LenType index, char* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + while (len-- > 0) { + *val++ = Stream_getCharAt(stream, index++); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +/** + * @brief get array of uint8_t without change the position of stream at given index + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_getUInt8ArrayAt(Stream* stream, Stream_LenType index, uint8_t* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + while (len-- > 0) { + *val++ = Stream_getUInt8At(stream, index++); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +/** + * @brief get array of int8_t without change the position of stream at given index + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_getInt8ArrayAt(Stream* stream, Stream_LenType index, int8_t* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + while (len-- > 0) { + *val++ = Stream_getInt8At(stream, index++); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +/** + * @brief get array of uint16_t without change the position of stream at given index + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_getUInt16ArrayAt(Stream* stream, Stream_LenType index, uint16_t* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + while (len-- > 0) { + *val++ = Stream_getUInt16At(stream, index++); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +/** + * @brief get array of int16_t without change the position of stream at given index + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_getInt16ArrayAt(Stream* stream, Stream_LenType index, int16_t* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + while (len-- > 0) { + *val++ = Stream_getInt16At(stream, index++); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +/** + * @brief get array of uint32_t without change the position of stream at given index + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_getUInt32ArrayAt(Stream* stream, Stream_LenType index, uint32_t* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + while (len-- > 0) { + *val++ = Stream_getUInt32At(stream, index++); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +/** + * @brief get array of int32_t without change the position of stream at given index + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_getInt32ArrayAt(Stream* stream, Stream_LenType index, int32_t* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + while (len-- > 0) { + *val++ = Stream_getInt32At(stream, index++); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +/** + * @brief get array of uint64_t without change the position of stream at given index + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_getFloatArrayAt(Stream* stream, Stream_LenType index, float* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + while (len-- > 0) { + *val++ = Stream_getFloatAt(stream, index++); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +#if STREAM_UINT64 +/** + * @brief get array of uint64_t without change the position of stream at given index + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_getUInt64ArrayAt(Stream* stream, Stream_LenType index, uint64_t* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + while (len-- > 0) { + *val++ = Stream_getUInt64At(stream, index++); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +/** + * @brief get array of int64_t without change the position of stream at given index + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_getInt64ArrayAt(Stream* stream, Stream_LenType index, int64_t* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + while (len-- > 0) { + *val++ = Stream_getInt64At(stream, index++); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +#endif // STREAM_UINT64 +#if STREAM_DOUBLE +/** + * @brief get array of double without change the position of stream at given index + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_getDoubleArrayAt(Stream* stream, Stream_LenType index, double* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + while (len-- > 0) { + *val++ = Stream_getDoubleAt(stream, index++); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +#endif // STREAM_DOUBLE + +#endif // STREAM_GET_AT_FUNCTIONS +/** + * @brief write array of characters + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_writeCharArray(Stream* stream, char* val, Stream_LenType len) { + Stream_Result result = Stream_Ok; + while (len-- > 0) { + if ((result = Stream_writeChar(stream, *val++)) != Stream_Ok) { + return result; + } + } + return result; +} +/** + * @brief write array of uint8_t + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_writeUInt8Array(Stream* stream, uint8_t* val, Stream_LenType len) { + Stream_Result result = Stream_Ok; + while (len-- > 0) { + if ((result = Stream_writeUInt8(stream, *val++)) != Stream_Ok) { + return result; + } + } + return result; +} +/** + * @brief write array of int8_t + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_writeInt8Array(Stream* stream, int8_t* val, Stream_LenType len) { + Stream_Result result = Stream_Ok; + while (len-- > 0) { + if ((result = Stream_writeInt8(stream, *val++)) != Stream_Ok) { + return result; + } + } + return result; +} +/** + * @brief write array of uint16_t + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_writeUInt16Array(Stream* stream, uint16_t* val, Stream_LenType len) { + Stream_Result result = Stream_Ok; + while (len-- > 0) { + if ((result = Stream_writeUInt16(stream, *val++)) != Stream_Ok) { + return result; + } + } + return result; +} +/** + * @brief write array of int16_t + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_writeInt16Array(Stream* stream, int16_t* val, Stream_LenType len) { + Stream_Result result = Stream_Ok; + while (len-- > 0) { + if ((result = Stream_writeInt16(stream, *val++)) != Stream_Ok) { + return result; + } + } + return result; +} +/** + * @brief write array of uint32_t + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_writeUInt32Array(Stream* stream, uint32_t* val, Stream_LenType len) { + Stream_Result result = Stream_Ok; + while (len-- > 0) { + if ((result = Stream_writeUInt32(stream, *val++)) != Stream_Ok) { + return result; + } + } + return result; +} +/** + * @brief write array of int32_t + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_writeInt32Array(Stream* stream, int32_t* val, Stream_LenType len) { + Stream_Result result = Stream_Ok; + while (len-- > 0) { + if ((result = Stream_writeInt32(stream, *val++)) != Stream_Ok) { + return result; + } + } + return result; +} +/** + * @brief write array of float + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_writeFloatArray(Stream* stream, float* val, Stream_LenType len) { + Stream_Result result = Stream_Ok; + while (len-- > 0) { + if ((result = Stream_writeFloat(stream, *val++)) != Stream_Ok) { + return result; + } + } + return result; +} +#if STREAM_UINT64 +/** + * @brief write array of uint64_t + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_writeUInt64Array(Stream* stream, uint64_t* val, Stream_LenType len) { + Stream_Result result = Stream_Ok; + while (len-- > 0) { + if ((result = Stream_writeUInt64(stream, *val++)) != Stream_Ok) { + return result; + } + } + return result; +} +/** + * @brief write array of int64_t + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_writeInt64Array(Stream* stream, int64_t* val, Stream_LenType len) { + Stream_Result result = Stream_Ok; + while (len-- > 0) { + if ((result = Stream_writeInt64(stream, *val++)) != Stream_Ok) { + return result; + } + } + return result; +} +#endif // STREAM_UINT64 +#if STREAM_DOUBLE +/** + * @brief write array of double + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_writeDoubleArray(Stream* stream, double val, Stream_LenType len) { + Stream_Result result = Stream_Ok; + while (len-- > 0) { + if ((result = Stream_writeDouble(stream, val)) != Stream_Ok) { + return result; + } + } + return result; +} +#endif // STREAM_DOUBLE +/** + * @brief read array of characters + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_readCharArray(Stream* stream, char* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + while (len-- > 0) { + *val++ = Stream_readChar(stream); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +/** + * @brief read array of uint8_t + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_readUInt8Array(Stream* stream, uint8_t* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + while (len-- > 0) { + *val++ = Stream_readUInt8(stream); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +/** + * @brief read array of int8_t + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_readInt8Array(Stream* stream, int8_t* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + while (len-- > 0) { + *val++ = Stream_readInt8(stream); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +/** + * @brief read array of uint16_t + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_readUInt16Array(Stream* stream, uint16_t* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + while (len-- > 0) { + *val++ = Stream_readUInt16(stream); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +/** + * @brief read array of int16_t + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_readInt16Array(Stream* stream, int16_t* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + while (len-- > 0) { + *val++ = Stream_readInt16(stream); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +/** + * @brief read array of uint32_t + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_readUInt32Array(Stream* stream, uint32_t* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + while (len-- > 0) { + *val++ = Stream_readUInt32(stream); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +/** + * @brief read array of int32_t + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_readInt32Array(Stream* stream, int32_t* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + while (len-- > 0) { + *val++ = Stream_readInt32(stream); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +/** + * @brief read array of float + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_readFloatArray(Stream* stream, float* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + while (len-- > 0) { + *val++ = Stream_readFloat(stream); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +#if STREAM_UINT64 +/** + * @brief read array of uint64_t + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_readUInt64Array(Stream* stream, uint64_t* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + while (len-- > 0) { + *val++ = Stream_readUInt64(stream); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +/** + * @brief read array of int64_t + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_readInt64Array(Stream* stream, int64_t* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + while (len-- > 0) { + *val++ = Stream_readInt64(stream); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +#endif // STREAM_UINT64 +#if STREAM_DOUBLE +/** + * @brief read array of double + * + * @param stream + * @param val + * @param len + * @return Stream_Result + */ +Stream_Result Stream_readDoubleArray(Stream* stream, double* val, Stream_LenType len) { + if (Stream_available(stream) >= len) { + while (len-- > 0) { + *val++ = Stream_readDouble(stream); + } + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +#endif // STREAM_DOUBLE +#if STREAM_WRITE_LOCK +/** + * @brief lock the stream for writing + * + * @param stream + * @return Stream_Result + */ +Stream_Result Stream_lockWrite(Stream* stream, Stream* lock, Stream_LenType len) { + Stream_LenType space = Stream_space(stream); + if (space >= len && !stream->WriteLocked) { + __memCopy(stream, lock, stream, sizeof(Stream)); + Stream_flipWrite(lock, len); + stream->WriteLocked = 1; + return Stream_Ok; + } + else { + return Stream_NoSpace; + } +} +/** + * @brief unlock the stream for writing + * + * @param stream + * @return Stream_Result + */ +void Stream_unlockWrite(Stream* stream, Stream* lock) { + if (stream->WriteLocked) { + Stream_moveWritePos(stream, Stream_lockWriteLen(stream, lock)); + stream->WriteLocked = 0; + } +} +/** + * @brief unlock stream for write with ignore changes + * + * @param stream + */ +void Stream_unlockWriteIgnore(Stream* stream) { + if (stream->WriteLocked) { + stream->WriteLocked = 0; + } +} +/** + * @brief return number of byte write in lock + * + * @param stream + * @param lock + */ +Stream_LenType Stream_lockWriteLen(Stream* stream, Stream* lock) { + if (stream->WPos != lock->WPos) { + // some data wrote + if (stream->WPos < lock->WPos) { + return lock->WPos - stream->WPos; + } + else { + return (stream->Size - stream->WPos) + lock->WPos; + } + } + else if (stream->RPos == lock->RPos && + stream->Overflow == 0 && + lock->Overflow) { + + return stream->Size; + } + else { + return 0; + } +} +#endif // STREAM_WRITE_LOCK + +#if STREAM_READ_LOCK +/** + * @brief lock the stream for reading + * + * @param stream + * @return Stream_Result + */ +Stream_Result Stream_lockRead(Stream* stream, Stream* lock, Stream_LenType len) { + Stream_LenType available = Stream_available(stream); + if (available >= len && !stream->ReadLocked) { + __memCopy(stream, lock, stream, sizeof(Stream)); + Stream_flipRead(lock, len); + stream->ReadLocked = 1; + return Stream_Ok; + } + else { + return Stream_NoAvailable; + } +} +/** + * @brief unlock the stream for reading + * + * @param stream + * @return Stream_Result + */ +void Stream_unlockRead(Stream* stream, Stream* lock) { + if (stream->ReadLocked) { + Stream_moveReadPos(stream, Stream_lockReadLen(stream, lock)); + stream->ReadLocked = 0; + } +} +/** + * @brief return number of bytes that read + * + * @param stream + * @param lock + * @return Stream_LenType + */ +Stream_LenType Stream_lockReadLen(Stream* stream, Stream* lock) { + if (stream->RPos != lock->RPos) { + // some data read + if (stream->RPos < lock->RPos) { + return lock->RPos - stream->RPos; + } + else { + return (stream->Size - stream->RPos) + lock->RPos; + } + } + else if (stream->WPos == lock->WPos && + stream->Overflow != 0 && + !lock->Overflow) { + + return stream->Size; + } + else { + return 0; + } +} +/** + * @brief unlock stream for read with ignore changes + * + * @param stream + */ +void Stream_unlockReadIgnore(Stream* stream) { + if (stream->ReadLocked) { + stream->ReadLocked = 0; + } +} +#endif // STREAM_READ_LOCK + +#if STREAM_FIND_FUNCTIONS +Stream_LenType Stream_findByte(Stream* stream, uint8_t val) { + Stream_LenType tmpLen = 0; + uint8_t* pStart = &stream->Data[stream->RPos]; + uint8_t* pEnd; + + if (Stream_available(stream) == 0) { + return -1; + } + + pEnd = memchr(pStart, val, Stream_directAvailable(stream)); + if (!pEnd && stream->Overflow) { + tmpLen = stream->Size - stream->RPos; + pStart = stream->Data; + pEnd = memchr(pStart, val, stream->WPos); + } + + return pEnd != NULL ? (Stream_LenType)(pEnd - pStart) + tmpLen : -1; +} +Stream_LenType Stream_findByteAt(Stream* stream, Stream_LenType offset, uint8_t val) { + Stream_LenType tmpLen = 0; + uint8_t* pStart = Stream_getReadPtrAt(stream, offset); + uint8_t* pEnd; + + if (Stream_available(stream) < offset) { + return -1; + } + + tmpLen = Stream_directAvailableAt(stream, offset); + pEnd = memchr(pStart, val, tmpLen); + if (!pEnd && (tmpLen + offset) < Stream_available(stream)) { + pStart = stream->Data; + pEnd = memchr(pStart, val, stream->WPos); + } + + return pEnd != NULL ? (Stream_LenType)(pEnd - pStart) + offset : -1; +} +Stream_LenType Stream_findPattern(Stream* stream, const uint8_t* pat, Stream_LenType patLen) { + Stream_LenType index = 0; + + if (Stream_available(stream) < patLen) { + return -1; + } + + while ((index = Stream_findByteAt(stream, index, *pat)) != -1) { + if (Stream_compareAt(stream, index, pat, patLen) == 0) { + break; + } + index++; + } + + return index; +} +Stream_LenType Stream_findPatternAt(Stream* stream, Stream_LenType offset, const uint8_t* pat, Stream_LenType patLen) { + if (Stream_available(stream) < patLen) { + return -1; + } + + while ((offset = Stream_findByteAt(stream, offset, *pat)) != -1) { + if (Stream_compareAt(stream, offset, pat, patLen) == 0) { + break; + } + offset++; + } + + return offset; +} +Stream_LenType Stream_readBytesUntil(Stream* stream, uint8_t end, uint8_t* val, Stream_LenType len) { + Stream_LenType tmpLen; + // find end byte + if ((tmpLen = Stream_findByte(stream, end)) >= 0) { + tmpLen++; + + if (len < tmpLen) { + tmpLen = len; + } + + if (Stream_readBytes(stream, val, tmpLen) == Stream_Ok) { + return tmpLen; + } + } + + return 0; +} +Stream_LenType Stream_readBytesUntilPattern(Stream* stream, const uint8_t* pat, Stream_LenType patLen, uint8_t* val, Stream_LenType len) { + Stream_LenType tmpLen; + // find end byte + if ((tmpLen = Stream_findPattern(stream, pat, patLen)) >= 0) { + tmpLen += patLen; + + if (len < tmpLen) { + tmpLen = len; + } + + if (Stream_readBytes(stream, val, tmpLen) == Stream_Ok) { + return tmpLen; + } + } + + return 0; +} +/** + * @brief find a uint8_t value in stream + * + * @param stream + * @param val + * @return Stream_LenType + */ +Stream_LenType Stream_findUInt8(Stream* stream, uint8_t val) { + return Stream_findByte(stream, val); +} +Stream_LenType Stream_findInt8(Stream* stream, int8_t val) { + return Stream_findByte(stream, (uint8_t) val); +} +Stream_LenType Stream_findUInt16(Stream* stream, uint16_t val) { + __checkReverse(stream, val); + return Stream_findPattern(stream, (uint8_t*) &val, sizeof(val)); +} +Stream_LenType Stream_findInt16(Stream* stream, int16_t val) { + __checkReverse(stream, val); + return Stream_findPattern(stream, (uint8_t*) &val, sizeof(val)); +} +Stream_LenType Stream_findUInt32(Stream* stream, uint32_t val) { + __checkReverse(stream, val); + return Stream_findPattern(stream, (uint8_t*) &val, sizeof(val)); +} +Stream_LenType Stream_findInt32(Stream* stream, int32_t val) { + __checkReverse(stream, val); + return Stream_findPattern(stream, (uint8_t*) &val, sizeof(val)); +} +#if STREAM_UINT64 +Stream_LenType Stream_findUInt64(Stream* stream, uint64_t val) { + __checkReverse(stream, val); + return Stream_findPattern(stream, (uint8_t*) &val, sizeof(val)); +} +Stream_LenType Stream_findInt64(Stream* stream, int64_t val) { + __checkReverse(stream, val); + return Stream_findPattern(stream, (uint8_t*) &val, sizeof(val)); +} +#endif +Stream_LenType Stream_findFloat(Stream* stream, float val) { + __checkReverse(stream, val); + return Stream_findPattern(stream, (uint8_t*) &val, sizeof(val)); +} +#if STREAM_DOUBLE +Stream_LenType Stream_findDouble(Stream* stream, double val) { + __checkReverse(stream, val); + return Stream_findPattern(stream, (uint8_t*) &val, sizeof(val)); +} +#endif + +#if STREAM_FIND_AT_FUNCTIONS +Stream_LenType Stream_findUInt8At(Stream* stream, Stream_LenType offset, uint8_t val) { + return Stream_findPatternAt(stream, offset, (uint8_t*) &val, sizeof(val)); +} +Stream_LenType Stream_findInt8At(Stream* stream, Stream_LenType offset, int8_t val) { + return Stream_findPatternAt(stream, offset, (uint8_t*) &val, sizeof(val)); +} +Stream_LenType Stream_findUInt16At(Stream* stream, Stream_LenType offset, uint16_t val) { + __checkReverse(stream, val); + return Stream_findPatternAt(stream, offset, (uint8_t*) &val, sizeof(val)); +} +Stream_LenType Stream_findInt16At(Stream* stream, Stream_LenType offset, int16_t val) { + __checkReverse(stream, val); + return Stream_findPatternAt(stream, offset, (uint8_t*) &val, sizeof(val)); +} +Stream_LenType Stream_findUInt32At(Stream* stream, Stream_LenType offset, uint32_t val) { + __checkReverse(stream, val); + return Stream_findPatternAt(stream, offset, (uint8_t*) &val, sizeof(val)); +} +Stream_LenType Stream_findInt32At(Stream* stream, Stream_LenType offset, int32_t val) { + __checkReverse(stream, val); + return Stream_findPatternAt(stream, offset, (uint8_t*) &val, sizeof(val)); +} +#if STREAM_UINT64 +Stream_LenType Stream_findUInt64At(Stream* stream, Stream_LenType offset, uint64_t val) { + __checkReverse(stream, val); + return Stream_findPatternAt(stream, offset, (uint8_t*) &val, sizeof(val)); +} +Stream_LenType Stream_findInt64At(Stream* stream, Stream_LenType offset, int64_t val) { + __checkReverse(stream, val); + return Stream_findPatternAt(stream, offset, (uint8_t*) &val, sizeof(val)); +} +#endif +Stream_LenType Stream_findFloatAt(Stream* stream, Stream_LenType offset, float val) { + __checkReverse(stream, val); + return Stream_findPatternAt(stream, offset, (uint8_t*) &val, sizeof(val)); +} +#if STREAM_DOUBLE +Stream_LenType Stream_findDoubleAt(Stream* stream, Stream_LenType offset, double val) { + __checkReverse(stream, val); + return Stream_findPatternAt(stream, offset, (uint8_t*) &val, sizeof(val)); +} +#endif +#endif // STREAM_FIND_AT_FUNCTIONS + +#endif // STREAM_FIND_FUNCTIONS + +/** + * @brief compare a given bytes at index with available bytes in stream + * + * @param stream + * @param val + * @param len + * @return int8_t + */ +int8_t Stream_compare(Stream* stream, const uint8_t* val, Stream_LenType len) { + return Stream_compareAt(stream, 0, val, len); +} +/** + * @brief compare a given bytes at index with available bytes in stream + * + * @param stream + * @param index + * @param val + * @param len + * @return int8_t + */ +int8_t Stream_compareAt(Stream* stream, Stream_LenType index, const uint8_t* val, Stream_LenType len) { + int8_t result; + Stream_LenType tmpLen; + + if (len == 0) { + return 0; + } + + if (Stream_available(stream) - index < len) { + return -2; + } + + tmpLen = Stream_directAvailableAt(stream, index); + if (tmpLen < len) { + if ((result = (int8_t) memcmp(Stream_getReadPtrAt(stream, index), val, tmpLen)) != 0) { + return result; + } + + index += tmpLen; + val += tmpLen; + len -= tmpLen; + } + + return (int8_t) memcmp(Stream_getReadPtrAt(stream, index), val, len); +} +// TODO: need to implement with more performance +static void memrcpy(void* dest, const void* src, int len) { + uint8_t* pDest = (uint8_t*) dest; + const uint8_t* pSrc = (const uint8_t*) src + len - 1; + + while (len-- > 0) { + *pDest++ = *pSrc--; + } +} +static void memreverse(void* arr, int len) { + uint8_t* pDest = (uint8_t*) arr; + uint8_t* pSrc = (uint8_t*) arr + len - 1; + uint8_t temp; + + len >>= 1; + while (len-- > 0) { + temp = *pSrc; + *pSrc++ = *pDest; + *pDest-- = temp; + } +} diff --git a/Examples/StreamOverSocket/Stream/StreamBuffer.h b/Examples/StreamOverSocket/Stream/StreamBuffer.h new file mode 100644 index 0000000..4bd260a --- /dev/null +++ b/Examples/StreamOverSocket/Stream/StreamBuffer.h @@ -0,0 +1,538 @@ +/** + * @file StreamBuffer.h + * @author Ali Mirghasemi (ali.mirghasemi1376@gmail.com) + * @brief this library implement stream buffer with read & write operations + * @version 0.5 + * @date 2021-09-01 + * + * @copyright Copyright (c) 2021 + * + */ +#ifndef _STREAM_H_ +#define _STREAM_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define STREAM_VER_MAJOR 0 +#define STREAM_VER_MINOR 6 +#define STREAM_VER_FIX 0 + +/************************************************************************/ +/* Configuration */ +/************************************************************************/ + +/** + * @brief you can enable ByteOrder option to have r/w operation + * on what endian you need + */ +#define STREAM_BYTE_ORDER 1 +#if STREAM_BYTE_ORDER + /** + * @brief save system byte order in static variable for avoid calculate each time + * run Stream_getSystemByteOrder function + */ + #define STREAM_BYTE_ORDER_SYS_STATIC 1 +#endif +/** + * @brief enable set limit for write functions + */ +#define STREAM_WRITE_LIMIT 1 +/** + * @brief enable set limit for read operations + */ +#define STREAM_READ_LIMIT 1 +/** + * @brief enable write lock feature + */ +#define STREAM_WRITE_LOCK 1 +/** + * @brief enable read lock feature + */ +#define STREAM_READ_LOCK 1 +/** + * @brief enable cursor object for check how many bytes read or write + */ +#define STREAM_CURSOR 0 +/** + * @brief if your platform support 64bit variables and you need it + * you can enable this option + */ +#define STREAM_UINT64 1 +/** + * @brief if you need r/w double variables and your platform support + * you can enable this option + */ +#define STREAM_DOUBLE 1 +/** + * @brief enable get functions + */ +#define STREAM_GET_FUNCTIONS 1 +/** + * @brief enable getAt functions + */ +#define STREAM_GET_AT_FUNCTIONS 1 +/** + * @brief enable find functions + */ +#define STREAM_FIND_FUNCTIONS 1 +/** + * @brief enable findAt functions + */ +#define STREAM_FIND_AT_FUNCTIONS 1 +/** + * @brief check len parameter in read/write functions + */ +#define STREAM_CHECK_ZERO_LEN 1 +/* Stream Memory IO States */ +#define STREAM_MEM_IO_DEFAULT 0 +#define STREAM_MEM_IO_CUSTOM 1 +#define STREAM_MEM_IO_DRIVER 2 +/** + * @brief This features help you to override memcpy, memrcpy, memset and etc with your custom functions + */ +#define STREAM_MEM_IO STREAM_MEM_IO_DEFAULT +/* Default IO functions */ +#define STREAM_MEM_COPY memcpy +#define STREAM_MEM_COPY_REVERSE memrcpy +#define STREAM_MEM_SET memset +#define STREAM_MEM_REVERSE memreverse +/** + * @brief based on maximum size of buffer that you use for stream + * you can change type of len variables + * must be signed type + */ +typedef int16_t Stream_LenType; + +/************************************************************************/ + +#define __STREAM_VER_STR(major, minor, fix) #major "." #minor "." #fix +#define _STREAM_VER_STR(major, minor, fix) __STREAM_VER_STR(major, minor, fix) +/** + * @brief show stream version in string format + */ +#define STREAM_VER_STR _STREAM_VER_STR(STREAM_VER_MAJOR, STREAM_VER_MINOR, STREAM_VER_FIX) +/** + * @brief show stream version in integer format, ex: 0.2.0 -> 200 + */ +#define STREAM_VER ((STREAM_VER_MAJOR * 10000UL) + (STREAM_VER_MINOR * 100UL) + (STREAM_VER_FIX)) + +/** + * @brief use for disable limit + */ +#define STREAM_NO_LIMIT -1 + +/** + * @brief default value for read function if cause error + */ +#define STREAM_READ_DEFAULT_VALUE 0 + +/** + * @brief you can choose what ByteOrder can use for r/w operations + */ +typedef enum { + ByteOrder_LittleEndian = 0, /**< little endian */ + ByteOrder_BigEndian = 1, /**< big endian */ + ByteOrder_Reserved = 0x0F, +} ByteOrder; +/** + * @brief result of Stream functions + */ +typedef enum { + Stream_Ok = 0, /**< everything is OK */ + Stream_NoSpace = 1, /**< there is no space for write operation */ + Stream_NoAvailable = 2, /**< there no available bytes for read operation */ + Stream_BufferFull = 3, /**< buffer full*/ + Stream_NoReceiveFn = 4, /**< no receive function set for IStream */ + Stream_NoTransmitFn = 5, /**< no transmit function set for OStream */ + Stream_NoReceive = 6, /**< stream is not in receive mode */ + Stream_NoTransmit = 7, /**< stream is not in transmit mode */ + Stream_InReceive = 8, /**< stream is in receive mode */ + Stream_InTransmit = 9, /**< stream is in transmit mode */ + Stream_ZeroLen = 10, /**< len parameter is zero */ + Stream_ReceiveFailed = 11, /**< failed in receive */ + Stream_TransmitFailed = 12, /**< failed in transmit */ + Stream_CustomError = 0x80, /**< can be used for custom errors */ +} Stream_Result; +/** + * @brief describe flush mode, use in OStream + */ +typedef enum { + Stream_FlushMode_Single = 0, /**< flush only pending bytes before call flush function */ + Stream_FlushMode_Continue = 1, /**< after flush complete if there is any pending bytes transmit pending bytes again */ +} Stream_FlushMode; +/** + * @brief Custom memcpy for override default function + */ +typedef Stream_LenType (*Stream_MemCopyFn)(void* dest, const void* src, Stream_LenType len); +/** + * @brief Custom memrcpy for override default function + */ +typedef Stream_LenType (*Stream_MemCopyReverseFn)(void* dest, const void* src, Stream_LenType len); +/** + * @brief Custom memset for override default function + */ +typedef Stream_LenType (*Stream_MemSetFn)(void* src, uint8_t val, Stream_LenType len); +/** + * @brief Custom memset for override default function + */ +typedef Stream_LenType (*Stream_MemReverseFn)(void* src, Stream_LenType len); + +typedef struct { + Stream_MemCopyFn copy; + Stream_MemCopyReverseFn copyReverse; + Stream_MemSetFn set; + Stream_MemReverseFn reverse; +} Stream_MemIO; + +/** + * @brief Stream struct + * contains everything need for handle stream + */ +typedef struct { +#if STREAM_MEM_IO == STREAM_MEM_IO_CUSTOM + Stream_MemIO Mem; /**< Custom io functions for interact with memory */ +#elif STREAM_MEM_IO == STREAM_MEM_IO_DRIVER + const Stream_MemIO* Mem; /**< Custom io functions for interact with memory in driver mode */ +#endif + uint8_t* Data; /**< pointer to buffer */ + Stream_LenType Size; /**< size of buffer */ + Stream_LenType WPos; /**< write position */ + Stream_LenType RPos; /**< read position */ +#if STREAM_WRITE_LIMIT + Stream_LenType WriteLimit; /**< limit for write operation */ +#endif // STREAM_WRITE_LIMIT +#if STREAM_READ_LIMIT + Stream_LenType ReadLimit; /**< limit for read operation */ +#endif + uint8_t Overflow : 1; /**< overflow flag */ + uint8_t InReceive : 1; /**< stream is in receive mode */ + uint8_t InTransmit : 1; /**< stream is in transmit mode */ + uint8_t Order : 1; /**< byte order */ + uint8_t OrderFn : 1; /**< byte order function */ + uint8_t WriteLocked : 1; /**< stream write locked */ + uint8_t ReadLocked : 1; /**< stream write locked */ + uint8_t FlushMode : 1; /**< flush mode */ +} Stream; +/** + * @brief hold properties of cursor over stream + */ +typedef struct { + Stream_LenType WPos; + Stream_LenType RPos; +} Stream_Cursor; + +void Stream_init(Stream* stream, uint8_t* buffer, Stream_LenType size); +void Stream_fromBuff(Stream* stream, uint8_t* buffer, Stream_LenType size); +void Stream_deinit(Stream* stream); + +#if STREAM_MEM_IO == STREAM_MEM_IO_CUSTOM +void Stream_setMemIO( + Stream* stream, + Stream_MemCopyFn copy, + Stream_MemCopyReverseFn copyReverse, + Stream_MemSetFn set, + Stream_MemReverseFn reverse +); +#elif STREAM_MEM_IO == STREAM_MEM_IO_DRIVER +void Stream_setMemIO(Stream* stream, const Stream_MemIO* mem); +#endif + +/*************** General APIs *************/ + +#if STREAM_WRITE_LIMIT + #define Stream_space(STREAM) Stream_spaceLimit((STREAM)) +#else + #define Stream_space(STREAM) Stream_spaceReal((STREAM)) +#endif // STREAM_WRITE_LIMIT + +#if STREAM_READ_LIMIT + #define Stream_available(STREAM) Stream_availableLimit((STREAM)) +#else + #define Stream_available(STREAM) Stream_availableReal((STREAM)) +#endif // STREAM_READ_LIMIT + +Stream_LenType Stream_availableReal(Stream* stream); +Stream_LenType Stream_spaceReal(Stream* stream); +uint8_t Stream_isEmpty(Stream* stream); +uint8_t Stream_isFull(Stream* stream); + +Stream_LenType Stream_directAvailable(Stream* stream); +Stream_LenType Stream_directSpace(Stream* stream); + +Stream_LenType Stream_directAvailableAt(Stream* stream, Stream_LenType index); +Stream_LenType Stream_directSpaceAt(Stream* stream, Stream_LenType index); + +uint8_t* Stream_getWritePtr(Stream* stream); +uint8_t* Stream_getReadPtr(Stream* stream); +uint8_t* Stream_getWritePtrAt(Stream* stream, Stream_LenType index); +uint8_t* Stream_getReadPtrAt(Stream* stream, Stream_LenType index); + +void Stream_reset(Stream* stream); +void Stream_resetIO(Stream* stream); +void Stream_clear(Stream* stream); + +void Stream_setFlushMode(Stream* stream, Stream_FlushMode mode); + +uint8_t Stream_inReceive(Stream* stream); +uint8_t Stream_inTransmit(Stream* stream); + +uint8_t* Stream_getBuffer(Stream* stream); + +void Stream_setBuffer(Stream* stream, uint8_t* data, Stream_LenType size); +Stream_LenType Stream_getBufferSize(Stream* stream); + +Stream_LenType Stream_getWritePos(Stream* stream); +Stream_LenType Stream_getReadPos(Stream* stream); + +Stream_Result Stream_moveWritePos(Stream* stream, Stream_LenType steps); +Stream_Result Stream_moveReadPos(Stream* stream, Stream_LenType steps); + +void Stream_flipWrite(Stream* stream, Stream_LenType len); +void Stream_flipRead(Stream* stream, Stream_LenType len); + +#if STREAM_BYTE_ORDER + ByteOrder Stream_getSystemByteOrder(void); + void Stream_setByteOrder(Stream* stream, ByteOrder order); + ByteOrder Stream_getByteOrder(Stream* stream); +#endif // STREAM_BYTE_ORDER + +#if STREAM_WRITE_LIMIT + void Stream_setWriteLimit(Stream* stream, Stream_LenType len); + uint8_t Stream_isWriteLimited(Stream* stream); + Stream_LenType Stream_spaceLimit(Stream* stream); + Stream_LenType Stream_getWriteLimit(Stream* stream); +#endif // STREAM_WRITE_LIMIT + +#if STREAM_READ_LIMIT + void Stream_setReadLimit(Stream* stream, Stream_LenType len); + uint8_t Stream_isReadLimited(Stream* stream); + Stream_LenType Stream_availableLimit(Stream* stream); + Stream_LenType Stream_getReadLimit(Stream* stream); +#endif // STREAM_READ_LIMIT + +#if STREAM_CURSOR + void Stream_getCursor(Stream* stream, Stream_Cursor* cursor); + Stream_LenType Stream_getReadLen(Stream* stream, Stream_Cursor* cursor); + Stream_LenType Stream_getWriteLen(Stream* stream, Stream_Cursor* cursor); +#endif // STREAM_CURSOR + +#if STREAM_WRITE_LOCK + Stream_Result Stream_lockWrite(Stream* stream, Stream* lock, Stream_LenType len); + void Stream_unlockWrite(Stream* stream, Stream* lock); + void Stream_unlockWriteIgnore(Stream* stream); + Stream_LenType Stream_lockWriteLen(Stream* stream, Stream* lock); +#endif // STREAM_WRITE_LOCK + +#if STREAM_READ_LOCK + Stream_Result Stream_lockRead(Stream* stream, Stream* lock, Stream_LenType len); + void Stream_unlockRead(Stream* stream, Stream* lock); + void Stream_unlockReadIgnore(Stream* stream); + Stream_LenType Stream_lockReadLen(Stream* stream, Stream* lock); +#endif // STREAM_READ_LOCK + +/**************** Write APIs **************/ +Stream_Result Stream_writeBytes(Stream* stream, uint8_t* val, Stream_LenType len); +Stream_Result Stream_writeBytesReverse(Stream* stream, uint8_t* val, Stream_LenType len); +Stream_Result Stream_writeChar(Stream* stream, char val); +Stream_Result Stream_writeStr(Stream* stream, const char* val); +Stream_Result Stream_writeUInt8(Stream* stream, uint8_t val); +Stream_Result Stream_writeInt8(Stream* stream, int8_t val); +Stream_Result Stream_writeUInt16(Stream* stream, uint16_t val); +Stream_Result Stream_writeInt16(Stream* stream, int16_t val); +Stream_Result Stream_writeUInt32(Stream* stream, uint32_t val); +Stream_Result Stream_writeInt32(Stream* stream, int32_t val); +Stream_Result Stream_writeFloat(Stream* stream, float val); +#if STREAM_UINT64 + Stream_Result Stream_writeUInt64(Stream* stream, uint64_t val); + Stream_Result Stream_writeInt64(Stream* stream, int64_t val); +#endif // STREAM_UINT64 +#if STREAM_DOUBLE + Stream_Result Stream_writeDouble(Stream* stream, double val); +#endif // STREAM_DOUBLE + +Stream_Result Stream_writeCharArray(Stream* stream, char* val, Stream_LenType len); +Stream_Result Stream_writeUInt8Array(Stream* stream, uint8_t* val, Stream_LenType len); +Stream_Result Stream_writeInt8Array(Stream* stream, int8_t* val, Stream_LenType len); +Stream_Result Stream_writeUInt16Array(Stream* stream, uint16_t* val, Stream_LenType len); +Stream_Result Stream_writeInt16Array(Stream* stream, int16_t* val, Stream_LenType len); +Stream_Result Stream_writeUInt32Array(Stream* stream, uint32_t* val, Stream_LenType len); +Stream_Result Stream_writeInt32Array(Stream* stream, int32_t* val, Stream_LenType len); +Stream_Result Stream_writeFloatArray(Stream* stream, float* val, Stream_LenType len); +#if STREAM_UINT64 + Stream_Result Stream_writeUInt64Array(Stream* stream, uint64_t* val, Stream_LenType len); + Stream_Result Stream_writeInt64Array(Stream* stream, int64_t* val, Stream_LenType len); +#endif // STREAM_UINT64 +#if STREAM_DOUBLE + Stream_Result Stream_writeDoubleArray(Stream* stream, double val, Stream_LenType len); +#endif // STREAM_DOUBLE + +Stream_Result Stream_writeStream(Stream* out, Stream* in, Stream_LenType len); + +Stream_Result Stream_writePadding(Stream* stream, uint8_t val, Stream_LenType len); + +/**************** Read APIs **************/ +int16_t Stream_read(Stream* stream); +Stream_Result Stream_readBytes(Stream* stream, uint8_t* val, Stream_LenType len); +Stream_Result Stream_readBytesReverse(Stream* stream, uint8_t* val, Stream_LenType len); +char Stream_readChar(Stream* stream); +uint8_t Stream_readUInt8(Stream* stream); +int8_t Stream_readInt8(Stream* stream); +uint16_t Stream_readUInt16(Stream* stream); +int16_t Stream_readInt16(Stream* stream); +uint32_t Stream_readUInt32(Stream* stream); +int32_t Stream_readInt32(Stream* stream); +float Stream_readFloat(Stream* stream); +#if STREAM_UINT64 + uint64_t Stream_readUInt64(Stream* stream); + int64_t Stream_readInt64(Stream* stream); +#endif // STREAM_UINT64 +#if STREAM_DOUBLE + double Stream_readDouble(Stream* stream); +#endif // STREAM_DOUBLE + +Stream_Result Stream_readCharArray(Stream* stream, char* val, Stream_LenType len); +Stream_Result Stream_readUInt8Array(Stream* stream, uint8_t* val, Stream_LenType len); +Stream_Result Stream_readInt8Array(Stream* stream, int8_t* val, Stream_LenType len); +Stream_Result Stream_readUInt16Array(Stream* stream, uint16_t* val, Stream_LenType len); +Stream_Result Stream_readInt16Array(Stream* stream, int16_t* val, Stream_LenType len); +Stream_Result Stream_readUInt32Array(Stream* stream, uint32_t* val, Stream_LenType len); +Stream_Result Stream_readInt32Array(Stream* stream, int32_t* val, Stream_LenType len); +Stream_Result Stream_readFloatArray(Stream* stream, float* val, Stream_LenType len); +#if STREAM_UINT64 + Stream_Result Stream_readUInt64Array(Stream* stream, uint64_t* val, Stream_LenType len); + Stream_Result Stream_readInt64Array(Stream* stream, int64_t* val, Stream_LenType len); +#endif // STREAM_UINT64 +#if STREAM_DOUBLE + Stream_Result Stream_readDoubleArray(Stream* stream, double* val, Stream_LenType len); +#endif // STREAM_DOUBLE + +Stream_Result Stream_readStream(Stream* in, Stream* out, Stream_LenType len); + +#if STREAM_GET_AT_FUNCTIONS && STREAM_GET_FUNCTIONS +Stream_Result Stream_getBytes(Stream* stream, uint8_t* val, Stream_LenType len); +Stream_Result Stream_getBytesReverse(Stream* stream, uint8_t* val, Stream_LenType len); +char Stream_getChar(Stream* stream); +uint8_t Stream_getUInt8(Stream* stream); +int8_t Stream_getInt8(Stream* stream); +uint16_t Stream_getUInt16(Stream* stream); +int16_t Stream_getInt16(Stream* stream); +uint32_t Stream_getUInt32(Stream* stream); +int32_t Stream_getInt32(Stream* stream); +float Stream_getFloat(Stream* stream); +#if STREAM_UINT64 + uint64_t Stream_getUInt64(Stream* stream); + int64_t Stream_getInt64(Stream* stream); +#endif // STREAM_UINT64 +#if STREAM_DOUBLE + double Stream_getDouble(Stream* stream); +#endif // STREAM_DOUBLE + +Stream_Result Stream_getCharArray(Stream* stream, char* val, Stream_LenType len); +Stream_Result Stream_getUInt8Array(Stream* stream, uint8_t* val, Stream_LenType len); +Stream_Result Stream_getInt8Array(Stream* stream, int8_t* val, Stream_LenType len); +Stream_Result Stream_getUInt16Array(Stream* stream, uint16_t* val, Stream_LenType len); +Stream_Result Stream_getInt16Array(Stream* stream, int16_t* val, Stream_LenType len); +Stream_Result Stream_getUInt32Array(Stream* stream, uint32_t* val, Stream_LenType len); +Stream_Result Stream_getInt32Array(Stream* stream, int32_t* val, Stream_LenType len); +Stream_Result Stream_getFloatArray(Stream* stream, float* val, Stream_LenType len); +#if STREAM_UINT64 + Stream_Result Stream_getUInt64Array(Stream* stream, uint64_t* val, Stream_LenType len); + Stream_Result Stream_getInt64Array(Stream* stream, int64_t* val, Stream_LenType len); +#endif // STREAM_UINT64 +#if STREAM_DOUBLE + Stream_Result Stream_getDoubleArray(Stream* stream, double* val, Stream_LenType len); +#endif // STREAM_DOUBLE + +#endif // STREAM_GET_FUNCTIONS + +#if STREAM_GET_AT_FUNCTIONS + +Stream_Result Stream_getBytesAt(Stream* stream, Stream_LenType index, uint8_t* val, Stream_LenType len); +Stream_Result Stream_getBytesReverseAt(Stream* stream, Stream_LenType index, uint8_t* val, Stream_LenType len); +char Stream_getCharAt(Stream* stream, Stream_LenType index); +uint8_t Stream_getUInt8At(Stream* stream, Stream_LenType index); +int8_t Stream_getInt8At(Stream* stream, Stream_LenType index); +uint16_t Stream_getUInt16At(Stream* stream, Stream_LenType index); +int16_t Stream_getInt16At(Stream* stream, Stream_LenType index); +uint32_t Stream_getUInt32At(Stream* stream, Stream_LenType index); +int32_t Stream_getInt32At(Stream* stream, Stream_LenType index); +float Stream_getFloatAt(Stream* stream, Stream_LenType index); +#if STREAM_UINT64 + uint64_t Stream_getUInt64At(Stream* stream, Stream_LenType index); + int64_t Stream_getInt64At(Stream* stream, Stream_LenType index); +#endif // STREAM_UINT64 +#if STREAM_DOUBLE + double Stream_getDoubleAt(Stream* stream, Stream_LenType index); +#endif // STREAM_DOUBLE + +Stream_Result Stream_getCharArrayAt(Stream* stream, Stream_LenType index, char* val, Stream_LenType len); +Stream_Result Stream_getUInt8ArrayAt(Stream* stream, Stream_LenType index, uint8_t* val, Stream_LenType len); +Stream_Result Stream_getInt8ArrayAt(Stream* stream, Stream_LenType index, int8_t* val, Stream_LenType len); +Stream_Result Stream_getUInt16ArrayAt(Stream* stream, Stream_LenType index, uint16_t* val, Stream_LenType len); +Stream_Result Stream_getInt16ArrayAt(Stream* stream, Stream_LenType index, int16_t* val, Stream_LenType len); +Stream_Result Stream_getUInt32ArrayAt(Stream* stream, Stream_LenType index, uint32_t* val, Stream_LenType len); +Stream_Result Stream_getInt32ArrayAt(Stream* stream, Stream_LenType index, int32_t* val, Stream_LenType len); +Stream_Result Stream_getFloatArrayAt(Stream* stream, Stream_LenType index, float* val, Stream_LenType len); +#if STREAM_UINT64 + Stream_Result Stream_getUInt64ArrayAt(Stream* stream, Stream_LenType index, uint64_t* val, Stream_LenType len); + Stream_Result Stream_getInt64ArrayAt(Stream* stream, Stream_LenType index, int64_t* val, Stream_LenType len); +#endif // STREAM_UINT64 +#if STREAM_DOUBLE + Stream_Result Stream_getDoubleArrayAt(Stream* stream, Stream_LenType index, double* val, Stream_LenType len); +#endif // STREAM_DOUBLE + +#endif // STREAM_GET_AT_FUNCTION + +#if STREAM_FIND_FUNCTIONS + Stream_LenType Stream_findByte(Stream* stream, uint8_t val); + Stream_LenType Stream_findByteAt(Stream* stream, Stream_LenType offset, uint8_t val); + Stream_LenType Stream_findPattern(Stream* stream, const uint8_t* pat, Stream_LenType patLen); + Stream_LenType Stream_findPatternAt(Stream* stream, Stream_LenType offset, const uint8_t* pat, Stream_LenType patLen); + Stream_LenType Stream_findUInt8(Stream* stream, uint8_t val); + Stream_LenType Stream_findInt8(Stream* stream, int8_t val); + Stream_LenType Stream_findUInt16(Stream* stream, uint16_t val); + Stream_LenType Stream_findInt16(Stream* stream, int16_t val); + Stream_LenType Stream_findUInt32(Stream* stream, uint32_t val); + Stream_LenType Stream_findInt32(Stream* stream, int32_t val); +#if STREAM_UINT64 + Stream_LenType Stream_findUInt64(Stream* stream, uint64_t val); + Stream_LenType Stream_findInt64(Stream* stream, int64_t val); +#endif + Stream_LenType Stream_findFloat(Stream* stream, float val); +#if STREAM_DOUBLE + Stream_LenType Stream_findDouble(Stream* stream, double val); +#endif + +#if STREAM_FIND_AT_FUNCTIONS + Stream_LenType Stream_findUInt8At(Stream* stream, Stream_LenType offset, uint8_t val); + Stream_LenType Stream_findInt8At(Stream* stream, Stream_LenType offset, int8_t val); + Stream_LenType Stream_findUInt16At(Stream* stream, Stream_LenType offset, uint16_t val); + Stream_LenType Stream_findInt16At(Stream* stream, Stream_LenType offset, int16_t val); + Stream_LenType Stream_findUInt32At(Stream* stream, Stream_LenType offset, uint32_t val); + Stream_LenType Stream_findInt32At(Stream* stream, Stream_LenType offset, int32_t val); +#if STREAM_UINT64 + Stream_LenType Stream_findUInt64At(Stream* stream, Stream_LenType offset, uint64_t val); + Stream_LenType Stream_findInt64At(Stream* stream, Stream_LenType offset, int64_t val); +#endif + Stream_LenType Stream_findFloatAt(Stream* stream, Stream_LenType offset, float val); +#if STREAM_DOUBLE + Stream_LenType Stream_findDoubleAt(Stream* stream, Stream_LenType offset, double val); +#endif +#endif // STREAM_FIND_AT_FUNCTIONS + + Stream_LenType Stream_readBytesUntil(Stream* stream, uint8_t end, uint8_t* val, Stream_LenType len); + Stream_LenType Stream_readBytesUntilPattern(Stream* stream, const uint8_t* pat, Stream_LenType patLen, uint8_t* val, Stream_LenType len); +#endif // STREAM_FIND_FUNCTIONS + +int8_t Stream_compare(Stream* stream, const uint8_t* val, Stream_LenType len); +int8_t Stream_compareAt(Stream* stream, Stream_LenType index, const uint8_t* val, Stream_LenType len); + +#ifdef __cplusplus +}; +#endif + +#endif /* _STREAM_H_ */ diff --git a/Examples/StreamOverSocket/Stream/UARTStream.c b/Examples/StreamOverSocket/Stream/UARTStream.c new file mode 100644 index 0000000..ecb98a2 --- /dev/null +++ b/Examples/StreamOverSocket/Stream/UARTStream.c @@ -0,0 +1,137 @@ +#include "UARTStream.h" + +/** + * @brief Initialize UARTStream object + * + * @param stream + * @param huart + * @param rxBuff + * @param rxBuffSize + * @param txBuff + * @param txBuffSize + */ +bool UARTStream_init( + UARTStream* stream, const char* ip, uint16_t port, const char* name, + uint8_t* rxBuff, Stream_LenType rxBuffSize, + uint8_t* txBuff, Stream_LenType txBuffSize +) { + + void * socketInit(void* args,const char* ip, uint16_t port, const char* name,void (*txComp)(void*),void (*rxComp)(void*)); + void * ptr = socketInit(stream,ip,port,name,UARTStream_txHandle,UARTStream_rxHandle); + if(ptr == NULL){ + return false; + } + stream->uartOverSock = ptr; + + IStream_init(&stream->Input, UARTStream_receive, rxBuff, rxBuffSize); + IStream_setCheckReceive(&stream->Input, UARTStream_checkReceive); + IStream_setArgs(&stream->Input, stream); + + OStream_init(&stream->Output, UARTStream_transmit, txBuff, txBuffSize); + OStream_setCheckTransmit(&stream->Output, UARTStream_checkTransmit); + OStream_setArgs(&stream->Output, stream); + return true; +} + +void UARTStream_deInit(UARTStream* stream){ + void socketDeInit(void *obj); + socketDeInit(stream->uartOverSock); +} +/** + * @brief Handle Receive Data for Input Stream, user must put it in + * HAL_UART_RxCpltCallback or other callbacks + * + * @param stream + */ +void UARTStream_rxHandle(void* ptr) { + UARTStream* stream = (UARTStream*)ptr; + IStream_handle(&stream->Input, IStream_incomingBytes(&stream->Input)); +} +/** + * @brief Handle Transmit Data for Output Stream, user must put it in + * HAL_UART_TxCpltCallback or other callbacks + * + * @param stream + */ +void UARTStream_txHandle(void* ptr) { + UARTStream* stream = (UARTStream*)ptr; + OStream_handle(&stream->Output, OStream_outgoingBytes(&stream->Output)); +} +/** + * @brief Check Received bytes in DMA or IT and add to stream + * + * @param stream + * @return Stream_LenType + */ +Stream_LenType UARTStream_checkReceive(IStream* stream) { + UARTStream* uartStream = (UARTStream*) IStream_getArgs(stream); + // if (uartStream->HUART->hdmarx) { + // return IStream_incomingBytes(stream) - __HAL_DMA_GET_COUNTER(uartStream->HUART->hdmarx); + // } + // else { + // return IStream_incomingBytes(stream) - uartStream->HUART->RxXferCount; + // } + size_t socketinReceive(void *obj); + return IStream_incomingBytes(stream) - socketinReceive(uartStream->uartOverSock); +} +/** + * @brief Check Transmitted bytes in DMA or IT and removed from stream + * + * @param stream + * @return Stream_LenType + */ +Stream_LenType UARTStream_checkTransmit(OStream* stream) { + UARTStream* uartStream = (UARTStream*) OStream_getArgs(stream); + // if (uartStream->HUART->hdmarx) { + // return OStream_outgoingBytes(stream) - __HAL_DMA_GET_COUNTER(uartStream->HUART->hdmatx); + // } + // else { + // return OStream_outgoingBytes(stream) - uartStream->HUART->TxXferCount; + // } + return 0; +} +/** + * @brief Stream receive function + * + * @param stream + * @param buff + * @param len + */ +Stream_Result UARTStream_receive(IStream* stream, uint8_t* buff, Stream_LenType len) { + // HAL_StatusTypeDef status; + // UARTStream* uartStream = (UARTStream*) IStream_getArgs(stream); + // if (uartStream->HUART->hdmarx) { + // status = HAL_UART_Receive_DMA(uartStream->HUART, buff, len); + // } + // else { + // status = HAL_UART_Receive_IT(uartStream->HUART, buff, len); + // } + // return status == HAL_OK ? Stream_Ok : Stream_CustomError | status; + UARTStream* uartStream = (UARTStream*) IStream_getArgs(stream); + void socketReceive(void *obj, uint8_t *buffer, size_t len); + socketReceive(uartStream->uartOverSock,buff,len); + return 0; +} +/** + * @brief Stream transmit function + * + * @param stream + * @param buff + * @param len + */ +Stream_Result UARTStream_transmit(OStream* stream, uint8_t* buff, Stream_LenType len) { + // HAL_StatusTypeDef status; + // UARTStream* uartStream = (UARTStream*) OStream_getArgs(stream); + // if (uartStream->HUART->hdmatx) { + // status = HAL_UART_Transmit_DMA(uartStream->HUART, buff, len); + // } + // else { + // status = HAL_UART_Transmit_IT(uartStream->HUART, buff, len); + // } + // return status == HAL_OK ? Stream_Ok : Stream_CustomError | status; + UARTStream* uartStream = (UARTStream*) OStream_getArgs(stream); + void socketTransmit(void *obj, uint8_t *buffer, size_t len); + //printf("len = %d ",len); + socketTransmit(uartStream->uartOverSock,buff,len); + return 0; +} diff --git a/Examples/StreamOverSocket/Stream/UARTStream.h b/Examples/StreamOverSocket/Stream/UARTStream.h new file mode 100644 index 0000000..19d980c --- /dev/null +++ b/Examples/StreamOverSocket/Stream/UARTStream.h @@ -0,0 +1,76 @@ +/** + * @file UARTStream.h + * @author Ali Mirghasemi (ali.mirghasemi1376@gmail.com) + * @brief This library implement Stream library for STM32Fxxx Based on HAL + * @version 0.1 + * @date 2023-01-07 + * + * @copyright Copyright (c) 2023 + * + */ +#ifndef _UART_STREAM_H_ +#define _UART_STREAM_H_ + +#include "InputStream.h" +#include "OutputStream.h" +#include "stdbool.h" + +/******************************************************************************/ +/* Configuration */ +/******************************************************************************/ +// #define UARTSTREAM_MCU_F0 0x00 +// #define UARTSTREAM_MCU_F1 0x01 +// #define UARTSTREAM_MCU_F2 0x02 +// #define UARTSTREAM_MCU_F3 0x03 +// #define UARTSTREAM_MCU_F4 0x04 +// #define UARTSTREAM_MCU_F7 0x07 +// #define UARTSTREAM_MCU_H7 0x17 + +// /** +// * @brief define your MCU series +// */ +// #define UARTSTREAM_MCU UARTSTREAM_MCU_F4 + +// /******************************************************************************/ + +// #if UARTSTREAM_MCU == UARTSTREAM_MCU_F0 +// #include "stm32f0xx.h" +// #elif UARTSTREAM_MCU == UARTSTREAM_MCU_F1 +// #include "stm32f1xx.h" +// #elif UARTSTREAM_MCU == UARTSTREAM_MCU_F2 +// #include "stm32f2xx.h" +// #elif UARTSTREAM_MCU == UARTSTREAM_MCU_F3 +// #include "stm32f3xx.h" +// #elif UARTSTREAM_MCU == UARTSTREAM_MCU_F4 +// #include "stm32f4xx.h" +// #elif UARTSTREAM_MCU == UARTSTREAM_MCU_F7 +// #include "stm32f7xx.h" +// #elif UARTSTREAM_MCU == UARTSTREAM_MCU_H7 +// #include "stm32h7xx.h" +// #else +// #error "Wrong MCU series!" +// #endif + +typedef struct { + void * uartOverSock; + IStream Input; + OStream Output; +} UARTStream; + +bool UARTStream_init( + UARTStream* stream, const char* ip, uint16_t port,const char* name, + uint8_t* rxBuff, Stream_LenType rxBuffSize, + uint8_t* txBuff, Stream_LenType txBuffSize +); +void UARTStream_deInit(UARTStream* stream); + +void UARTStream_rxHandle(void* ptr); +void UARTStream_txHandle(void* ptr); + +Stream_LenType UARTStream_checkReceive(IStream* stream); +Stream_LenType UARTStream_checkTransmit(OStream* stream); +Stream_Result UARTStream_receive(IStream* stream, uint8_t* buff, Stream_LenType len); +Stream_Result UARTStream_transmit(OStream* stream, uint8_t* buff, Stream_LenType len); + +#endif // _UART_STREAM_H_ + diff --git a/Examples/StreamOverSocket/Stream/buffer.c b/Examples/StreamOverSocket/Stream/buffer.c new file mode 100644 index 0000000..5e87bb7 --- /dev/null +++ b/Examples/StreamOverSocket/Stream/buffer.c @@ -0,0 +1,52 @@ +#include "buffer.h" + + +uint8_t *_buffer; +size_t _size; +volatile size_t _head,_tail; +void buffer_init(void * buffer,size_t len){ + _buffer = buffer; + _size = len; + _head = _tail = 0; + +} + +size_t buffer_available(){ + if(_head >= _tail){ + return _head - _tail; + } + else { + return _size - _tail + _head ; + } + +} +bool buffer_add(uint8_t* buffer ,size_t len){ + if(len <= _size - buffer_available()){ + for(size_t i=0;i + +void delay(uint32_t time) +{ + Sleep(time); +} +uint32_t millis() +{ + static uint32_t _startMillis; + if(_startMillis == 0){ + _startMillis = GetTickCount(); + return 0; + } + return GetTickCount() - _startMillis; +} + +void replaceSpecialChar(char ch, uint8_t *buffer) +{ + switch (ch) + { + case '\r': + snprintf(buffer, 6, "\\r"); + break; + case '\n': + snprintf(buffer, 6, "\\n"); + break; + case '\t': + snprintf(buffer, 6, "\\t"); + break; + case '\0': + snprintf(buffer, 6, "\\0"); + break; + default: + snprintf(buffer, 6, "%c", ch); // Return the original character if it's not a special character + } +} +void print_arr_hex(uint8_t *buffer, int len) +{ + printf("array(%d)[ ", len); + for (int i = 0; i < len; i++) + { + printf("%02X", buffer[i]); + if (i != len - 1) + { + printf(" "); + } + } + printf(" ]"); +} +void print_arr_norm(uint8_t *buffer, int len) +{ + uint8_t temp[6]; + printf("array(%d)[ ", len); + for (int i = 0; i < len; i++) + { + replaceSpecialChar(buffer[i], temp); + printf("%s", temp); + if (i != len - 1) + { + } + } + printf(" ]"); +} +void print_hex(uint8_t *buffer, int len) +{ + for (int i = 0; i < len; i++) + { + printf("%02X", buffer[i]); + if (i != len - 1) + { + printf(" "); + } + } +} +void print_norm(uint8_t *buffer, int len) +{ + uint8_t temp[6]; + for (int i = 0; i < len; i++) + { + replaceSpecialChar(buffer[i], temp); + printf("%s", temp); + if (i != len - 1) + { + } + } +} + +void print_f(const char *format, ...) +{ + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); +} + diff --git a/Examples/StreamOverSocket/arduino/arduino.h b/Examples/StreamOverSocket/arduino/arduino.h new file mode 100644 index 0000000..0f210e6 --- /dev/null +++ b/Examples/StreamOverSocket/arduino/arduino.h @@ -0,0 +1,20 @@ +#ifndef SERIALPORT_GENERAL_H +#define SERIALPORT_GENERAL_H +#include "stdint.h" +#include "stdio.h" +#include "stdarg.h" + +#define STR(X) X, strlen(X) +#define STR_C(X) X, sizeof(X)-1 + +void delay(uint32_t time); +uint32_t millis(); +void print_arr_hex(uint8_t *buffer, int len); +void print_arr_norm(uint8_t *buffer, int len); +void print_hex(uint8_t *buffer, int len); +void print_norm(uint8_t *buffer, int len); +void print_f(const char *format, ...); + + + +#endif //SERIALPORT_GENERAL_H diff --git a/Examples/StreamOverSocket/main.c b/Examples/StreamOverSocket/main.c new file mode 100644 index 0000000..ca665e4 --- /dev/null +++ b/Examples/StreamOverSocket/main.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include "stdint.h" +#include + + +#pragma comment(lib, "ws2_32.lib") + +void setup(); +void loop(); + + + +void* LoopThread(void *args) +{ + int sleepIndexer=0; + while (1) + { + loop(); + + sleepIndexer++; + if(sleepIndexer == 1000) + { + sleepIndexer = 0; + Sleep(1); + } + } + pthread_exit(NULL); +} + + +int main() +{ + WSADATA wsa; + +// printf("Initializing Winsock...\n"); + if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) + { + printf("Initializing Winsock Failed. Error Code: %d\n", WSAGetLastError()); + return 0; + } + +// printf("Initialized.\n"); + setup(); + + + pthread_t loopThread; + + // Create producer and consumer threads + int ret =pthread_create(&loopThread, NULL, LoopThread, NULL); + if(ret != 0){ + printf("create loopThread Failed. Error Code: %d\n",ret); + } + else { + pthread_join(loopThread, NULL); + } + // Close the socket + // closesocket(s); + WSACleanup(); + + return 0; +} diff --git a/Examples/StreamOverSocket/serial_server.py b/Examples/StreamOverSocket/serial_server.py new file mode 100644 index 0000000..d22760c --- /dev/null +++ b/Examples/StreamOverSocket/serial_server.py @@ -0,0 +1,150 @@ +import socket +import serial +import threading +import argparse + +BUFFER_SIZE = 1024 + +# Parse command-line arguments +parser = argparse.ArgumentParser(description="TCP server to pipe data between a TCP client and a serial port") +parser.add_argument('-ip', '--ip-address', type=str, help="TCP server IP address", required=False,default='127.0.0.1') +parser.add_argument('-p', '--port', type=int, help="TCP server port", required=False,default=8888) +parser.add_argument('-com', '--com-port', type=str, help="Serial port name (e.g., COM1)", required=False,default='COM5') +parser.add_argument('-b', '--baudrate', type=int, help="Serial port baud rate", required=False,default='115200') +parser.add_argument('-tx', '--tx', type=str, help="file address to tx data in", required=False,default='') +parser.add_argument('-rx', '--rx', type=str, help="file address to rx data in", required=False,default='') +parser.add_argument("-v", "--verbose", help="Enable verbose mode", action="store_true") +args = parser.parse_args() + +# Create a TCP socket server +tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +tcp_server_socket.bind((args.ip_address, args.port)) +tcp_server_socket.listen(1) + +verbos = True +if args.verbose: + verbos = True + +# def custom_decode(bytes_data): +# special_chars = { +# b"\n": "\\n", +# b"\r": "\\r", +# b"\t": "\\t", +# b"\0": "\\0", +# b"\x1A": "\\x1A", # Ctrl+Z +# # Add more special characters as needed +# } + +# decoded_str = bytes_data.decode("utf-8") + +# for char, escape_seq in special_chars.items(): +# decoded_str = decoded_str.replace(char.decode("utf-8"), escape_seq) + +# return decoded_str + +def custom_decode(byte_array): + decoded_chars = "" + special_chars = { + '\n': "\\n", + '\r': "\\r", + '\t': "\\t", + '\0': "\\0", + + } + + for byte in byte_array: + char = chr(byte) + if 32 <= ord(char) <= 126: # Filter only printable ASCII characters + decoded_chars+=(char) + elif char in ['\n','\r','\t','\0']: + decoded_chars += special_chars[char] + else : + decoded_chars += "\\x{:02x}".format(byte) + + return decoded_chars + + +print(f"serial {args.com_port}:{args.baudrate}\nTCP server started on {args.ip_address}:{args.port}, Waiting for client connection...") + +while True: + + + # Accept a client connection + conn, addr = tcp_server_socket.accept() + print("Client connected. IP address:", addr) + + # Create a serial connection + serial_port = serial.Serial(args.com_port, baudrate=args.baudrate, timeout=0.001) + + #handle file dump + tx = None + if args.tx: + tx = open(args.tx,"ab"); + rx = None + if args.rx: + rx = open(args.rx,"ab"); + + def read_serial_and_send(): + while True: + try: + # Read data from the serial port + serial_data = serial_port.read(BUFFER_SIZE) + if serial_data: + # Send data back to the client + conn.send(serial_data) + if verbos: + print(f"port({len(serial_data)}):", custom_decode(serial_data)) + if tx: + tx.write(serial_data) + tx.flush(); + except: + conn.close() + break + + def receive_client_data(): + while True: + try: + # Receive data from the client + data = conn.recv(BUFFER_SIZE) + if not data: + raise + except: + print("Client disconnected: ",addr) + break + + # Print received data + if verbos: + print(f"client({len(data)}):", custom_decode(data)) + if rx: + rx.write(data) + rx.flush(); + try: + # Send data to the serial port + serial_port.write(data) + except: + print("cannt write data to serial"); + break + + # Start the threads + read_thread = threading.Thread(target=read_serial_and_send) + read_thread.start() + + receive_thread = threading.Thread(target=receive_client_data) + receive_thread.start() + + + # Wait for the threads to finish + # read_thread.join() + receive_thread.join() + + # Close the TCP connection and serial port + print("close client and serial") + conn.close() + serial_port.close() + if tx: + tx.close() + if rx: + rx.close() + +# Close the TCP server socket +tcp_server_socket.close() diff --git a/Examples/StreamOverSocket/uart_sock.c b/Examples/StreamOverSocket/uart_sock.c new file mode 100644 index 0000000..02ea8ab --- /dev/null +++ b/Examples/StreamOverSocket/uart_sock.c @@ -0,0 +1,184 @@ +#include +#include "stdbool.h" +#include "stdint.h" +#include "stdio.h" +#include "stdlib.h" +#include + +// bool dumpData = false; +typedef struct { + SOCKET sock; + struct sockaddr_in server; + volatile bool isRunnig; + const char *name; + + pthread_t sendThread; + void *txBuffer; + pthread_cond_t txCond; + pthread_mutex_t txMutex; + size_t inTx; + void (*txComp)(void *); + + + pthread_t recThread; + uint8_t *rxBuffer; + pthread_cond_t rxCond; + pthread_mutex_t rxMutex; + size_t inRx; + void (*rxComp)(void *); + + + + void *args; +} UARTStreamOverSocket; + +void *SendThread(void *args) { + UARTStreamOverSocket *stream = (UARTStreamOverSocket *) args; + SOCKET s = stream->sock; + while (1) { + pthread_mutex_lock(&stream->txMutex); + while (stream->inTx == 0) { + pthread_cond_wait(&stream->txCond, &stream->txMutex); + } + while (stream->inTx != 0) { + int sent = send(s, stream->txBuffer, stream->inTx, 0); + if (send < 0) { + printf("%s->Send Failed.Error Code: %d .Exiting...\n", stream->name, sent); + exit(0); + } + stream->inTx -= sent; + stream->txBuffer += sent; + } + pthread_mutex_unlock(&stream->txMutex); + + if (stream->txComp != NULL) { + stream->txComp(stream->args); + } + } +} + +// Function executed by the receiving thread +void *ReceiveThread(void *args) { + UARTStreamOverSocket *stream = (UARTStreamOverSocket *) args; + SOCKET socket = stream->sock; + int recv_size; + + while (1) { + pthread_mutex_lock(&stream->rxMutex); + while (stream->inRx == 0) { + pthread_cond_wait(&stream->rxCond, &stream->rxMutex); + } + while(stream->inRx != 0) { + recv_size = recv(socket, (char *) stream->rxBuffer, stream->inRx, 0); + if (recv_size > 0) { + stream->inRx -= recv_size; + stream->rxBuffer += recv_size; + } + else { + printf("%s->disconnected.Exiting...\n", stream->name); + exit(0); + break; + } + } + pthread_mutex_unlock(&stream->rxMutex); + + if (stream->rxComp != NULL) { + stream->rxComp(stream->args); + } + + } +} + +size_t socketinReceive(void *obj) +{ + UARTStreamOverSocket *stream = (UARTStreamOverSocket *)obj; + return stream->inRx; +} + +void socketReceive(void *obj, uint8_t *buffer, size_t len) { + UARTStreamOverSocket *stream = (UARTStreamOverSocket *) obj; + pthread_mutex_lock(&stream->rxMutex); + + // Set the data and signal the sending thread + + stream->rxBuffer = buffer; + stream->inRx = len; + + pthread_cond_signal(&stream->rxCond); + pthread_mutex_unlock(&stream->rxMutex); +} + +void socketTransmit(void *obj, uint8_t *buffer, size_t len) { + UARTStreamOverSocket *stream = (UARTStreamOverSocket *) obj; + pthread_mutex_lock(&stream->txMutex); + + // Set the data and signal the sending thread + + stream->txBuffer = buffer; + stream->inTx = len; + + pthread_cond_signal(&stream->txCond); + pthread_mutex_unlock(&stream->txMutex); + +} + +void *socketInit(void *args, const char *ip, uint16_t port, const char *name, void (*txComp)(void *), + void (*rxComp)(void *)) { + UARTStreamOverSocket *stream = malloc(sizeof(UARTStreamOverSocket)); + if (stream == NULL) { + printf("%s->cannot alloc memory\n", name); + return NULL; + } + // stream->HUART = huart; + stream->name = name; + stream->isRunnig = false; + stream->txComp = txComp; + stream->rxComp = rxComp; + stream->args = args; + stream->inTx = stream->inRx = 0; + // Create a socket + if ((stream->sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { + printf("%s->Could not create socket : %d\n", stream->name, WSAGetLastError()); + return NULL; + } +// printf("%s->Socket created.\n", stream->name); + + stream->server.sin_addr.s_addr = inet_addr(ip); // Replace with the IP address of your server + stream->server.sin_family = AF_INET; + stream->server.sin_port = htons(port); // Replace with the port number of your server + + // Connect to remote server + if (connect(stream->sock, (struct sockaddr *) &stream->server, sizeof(stream->server)) < 0) { + printf("%s->Connect error\n", stream->name); + return NULL; + } + + printf("%s->Connected\n", stream->name); + + stream->rxCond = PTHREAD_COND_INITIALIZER; + stream->rxMutex = PTHREAD_MUTEX_INITIALIZER; + int ret = pthread_create(&stream->recThread, NULL, ReceiveThread, stream); + if (ret != 0) { + printf("%s->Failed to create ReceiveThread.Error Code: %d\n", stream->name, ret); + return NULL; + } + + stream->txCond = PTHREAD_COND_INITIALIZER; + stream->txMutex = PTHREAD_MUTEX_INITIALIZER; + ret = pthread_create(&stream->sendThread, NULL, SendThread, stream); + if (ret != 0) { + printf("%s->Failed to create SendThread.Error Code: %d\n", stream->name, ret); + pthread_cancel(stream->recThread); + // Wait for the created thread to finish (note that it may not terminate immediately) + pthread_join(stream->recThread, NULL); + return NULL; + } + Sleep(1); + stream->isRunnig = true; + return stream; +} + +void socketDeInit(void *obj) { + closesocket(((UARTStreamOverSocket *) obj)->sock); + free(obj); +} diff --git a/Examples/StreamOverSocket/userCodes.c b/Examples/StreamOverSocket/userCodes.c new file mode 100644 index 0000000..dfa989e --- /dev/null +++ b/Examples/StreamOverSocket/userCodes.c @@ -0,0 +1,40 @@ +#include +#include +#include "string.h" +#include "UARTStream.h" +#include "Str.h" +#include "arduino.h" + + +uint8_t rxBuf1[64]; +uint8_t txBuf1[64]; +UARTStream uart1; + + +void setup() +{ + millis(); // reference it from now + setbuf(stdout, NULL); // Disable buffering for stdout + bool ret = UARTStream_init( + &uart1, "127.0.0.1", 8888, "COM16", + rxBuf1, sizeof(rxBuf1), + txBuf1, sizeof(txBuf1)); + if (ret == false) + { + printf("ret == false"); + exit(0); + } + + + IStream_receive(&uart1.Input); + +} +void loop() +{ + if(IStream_available(&uart1.Input)) { + OStream_writeStream(&uart1.Output, &uart1.Input, IStream_available(&uart1.Input)); + OStream_flush(&uart1.Output); + } + +} +