Introduction
During study and development work, I often need to perform uncommon operations and write small utilities to handle them. Because they are used infrequently, they are often not saved, and I end up rewriting them the next time I need them, which wastes time.
This article collects several practical small C programs for embedded development for future reuse. The code is intended to be practical; if you find defects, please point them out.
1. Hexadecimal string to integer
Purpose: Convert a hex string to an integer. Standard functions like atoi and atol handle decimal strings only, so they are not suitable for hex input. The code below converts a hex string such as "0x1de" to an int.
/*============================================================================= FileName: hex2dec.cpp Desc: Convert a hex string to an int number Author: Caibiao Lee LastChange: 2018-11-26 History: =============================================================================*/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> int c2i(char ch) { // If it is a digit, subtract '0' to get the numeric value. e.g. '2' - '0' = 2 if (isdigit(ch)) return ch - '0'; // If not A-F or a-f, return -1 if (ch < 'A' || (ch > 'F' && ch < 'a') || ch > 'z') return -1; // If it is a letter, map 'A'..'F'->10..15 and 'a'..'f'->10..15 if (isalpha(ch)) return isupper(ch) ? ch - 55 : ch - 87; return -1; } int hex2dec(char *hex) { int len; int num = 0; int temp; int bits; int i; char str[64] = {0}; if (NULL == hex) { printf("input para error "); return 0; } if (('0' == hex[0]) && (('X' == hex[1]) || ('x' == hex[1]))) { strcpy(str, &hex[2]); } else { strcpy(str, hex); } printf("input num = %s ", str); // Example: str = "1de", len = 3 len = strlen(str); for (i = 0; i < len; i++) { temp = c2i(*(str + i)); // Each hex digit uses 4 bits. Shift according to position. bits = (len - i - 1) * 4; if (bits > 0) temp = temp << bits; num |= temp; } return num; } int main(int argc, char **argv) { int l_s32ret = 0; if (2 != argc) { printf("====ERROR!===="); printf("usage: %s num ", argv[0]); printf("eg 1: %s 0x400", argv[0]); return 0; } l_s32ret = hex2dec(argv[1]); printf("value hex = 0x%x ", l_s32ret); printf("value dec = %d ", l_s32ret); return 0; }
2. String to integer (hex or decimal)
Purpose: Convert a string representing either a hex number (with 0x or 0X prefix) or a decimal number to an int.
/*============================================================================= FileName: String2int.cpp Desc: Convert a hex/dec string to an int number Author: Caibiao Lee LastChange: 2018-12-03 History: =============================================================================*/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> int String2int(char *strChar) { int len = 0; const char *pstrCmp1 = "0123456789ABCDEF"; const char *pstrCmp2 = "0123456789abcdef"; char *pstr = NULL; int uiValue = 0; unsigned int t = 0; int i = 0; if (NULL == strChar) return -1; if (0 >= (len = strlen((const char *)strChar))) return -1; // Check for "0x" or "0X" prefix if (NULL != (pstr = strstr(strChar, "0x")) || NULL != (pstr = strstr(strChar, "0X"))) { pstr = (char *)strChar + 2; if (0 >= (len = strlen((const char *)pstr))) return -1; // Parse hex string uiValue = 0; for (i = 0; i < len; i++) { char ch = pstr[i]; for (t = 0; t < strlen(pstrCmp1); t++) { if (pstrCmp1[t] == ch || pstrCmp2[t] == ch) { uiValue = (uiValue << 4) | t; break; } } } } else { // Decimal input uiValue = atoi((const char *)strChar); } return uiValue; } int main(int argc, char **argv) { int l_s32ret = 0; if (2 != argc) { printf("====ERROR!===="); printf("usage: %s num ", argv[0]); printf("eg 1: %s 0x400", argv[0]); return 0; } l_s32ret = String2int(argv[1]); printf("value hex = 0x%x ", l_s32ret); printf("value dec = %d ", l_s32ret); return 0; }
3. Create a file and fill with fixed data
Purpose: Create a file of a fixed size and fill it with a fixed data value.
/*============================================================================= FileName: CreateFile.cpp Desc: Create a fixed-size file and fill it with a given value Author: Caibiao Lee LastChange: 2018-11-26 History: =============================================================================*/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #define FILL_DATA_VALUE 0x30 // fill byte value int c2i(char ch) { if (isdigit(ch)) return ch - '0'; if (ch < 'A' || (ch > 'F' && ch < 'a') || ch > 'z') return -1; if (isalpha(ch)) return isupper(ch) ? ch - 55 : ch - 87; return -1; } int hex2dec(char *hex) { int len; int num = 0; int temp; int bits; int i; char str[64] = {0}; if (NULL == hex) { printf("input para error "); return 0; } if (('0' == hex[0]) && (('X' == hex[1]) || ('x' == hex[1]))) { strcpy(str, &hex[2]); } else { strcpy(str, hex); } printf("input num = %s ", str); len = strlen(str); for (i = 0; i < len; i++) { temp = c2i(*(str + i)); bits = (len - i - 1) * 4; if (bits > 0) temp = temp << bits; num |= temp; } return num; } int main(int argc, char **argv) { FILE *l_pFile = NULL; int l_s32rest = 0; unsigned int l_writelen = 0; unsigned int l_filelen = 0; unsigned char tempdata[1024]; memset(tempdata, FILL_DATA_VALUE, sizeof(tempdata)); if (3 != argc) { printf("usage: %s filename filelen ", argv[0]); printf("eg: %s outfile.bin 0x400", argv[0]); return 0; } const char *l_pfilename = argv[1]; if (('0' == argv[2][0]) && (('X' == argv[2][1]) || ('x' == argv[2][1]))) l_filelen = hex2dec(argv[2]); else l_filelen = atoi(argv[2]); printf("Need To Write Data Len %d ", l_filelen); printf("Fill Data Vale = 0x%x ", FILL_DATA_VALUE); l_pFile = fopen(l_pfilename, "w+"); if (l_pFile == NULL) { printf("open file %s error ", l_pfilename); return -1; } while (l_writelen < l_filelen) { unsigned int write_len = (l_filelen - l_writelen) < sizeof(tempdata) ? (l_filelen - l_writelen) : sizeof(tempdata); l_s32rest = fwrite(tempdata, 1, write_len, l_pFile); if (l_s32rest <= 0) break; l_writelen += l_s32rest; } if (l_pFile != NULL) fclose(l_pFile); return 0; }
4. Batch process images (remove fixed header bytes)
Purpose: Batch process image files by removing a fixed number of leading bytes from each file.
Before running, create two directories: "image" for source files and "outfile" for processed files.
/*============================================================================= FileName: CutFile.cpp Desc: Batch process images, remove a fixed number of leading bytes Author: Caibiao Lee LastChange: 2018-11-26 History: =============================================================================*/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/stat.h> #define START_READ_POSITION 128 #define PHOTO_START_TIME 83641 int Cut_file(char *InputFile) { FILE *l_pFileInput = NULL; FILE *l_pFileOutput = NULL; char l_ars8OutputName[128] = {0}; unsigned char l_arru8TempData[1024] = {0}; int l_s32Ret = 0; static unsigned int ls_u32Num = 0; if (NULL == InputFile) goto ERROR; sprintf(l_ars8OutputName, "./outfile/%03d.jpg", ls_u32Num++); l_pFileInput = fopen(InputFile, "rb"); if (NULL == l_pFileInput) { printf("input file open error"); goto ERROR; } l_pFileOutput = fopen(l_ars8OutputName, "w+"); if (NULL == l_pFileOutput) { printf("out file open error"); goto ERROR; } fseek(l_pFileInput, START_READ_POSITION, SEEK_SET); while (!feof(l_pFileInput)) { l_s32Ret = fread(l_arru8TempData, 1, sizeof(l_arru8TempData), l_pFileInput); if (l_s32Ret <= 0) break; l_s32Ret = fwrite(l_arru8TempData, 1, l_s32Ret, l_pFileOutput); if (l_s32Ret <= 0) break; } ERROR: if (NULL != l_pFileOutput) { fclose(l_pFileOutput); l_pFileOutput = NULL; } if (NULL != l_pFileInput) { fclose(l_pFileInput); l_pFileInput = NULL; } return 0; } int main(void) { char l_arrs8InputName[128] = {0}; int l_s8PhotoChannel = 3; int l_s32PhotoTime = PHOTO_START_TIME; // Iterate channels and times to build file names like "./image/1Yhhmmss.jpg" for (int j = 1; j <= l_s8PhotoChannel; j++) { for (int i = l_s32PhotoTime; i < 235959; i++) { memset(l_arrs8InputName, 0, sizeof(l_arrs8InputName)); sprintf(l_arrs8InputName, "./image/%dY%06d.jpg", j, i); if (0 == access(l_arrs8InputName, F_OK)) { printf("%s ", l_arrs8InputName); Cut_file(l_arrs8InputName); } } } return 0; }
5. GPIO I/O control utility
On space-limited embedded systems, many commands can be removed. Debugging on such devices is often limited to serial logs. The following small utility reads and writes GPIO levels on HiSilicon Hi3520DV300-based systems using the board's GPIO API.
/*============================================================================= FileName: Hi3520_IO_CTRL.cpp Desc: Hi3520DV300 IO Write and Read Author: Caibiao Lee LastChange: 2018-11-30 History: =============================================================================*/ #include <stdio.h> #include <stdlib.h> #include "hstGpioAL.h" int PrintfInputTips(char *ps8Name) { printf("=========== error!!! ========="); printf("usage Write: %s GPIO bit value ", ps8Name); printf("usage Read : %s GPIO bit ", ps8Name); printf("eg Write 1 to GPIO1_bit02 : %s 1 2 1", ps8Name); printf("eg Read GPIO1_bit02 Value : %s 1 2 ", ps8Name); printf("=============BT20=================="); printf("USB HUB GPIO_0_2 1_UP 0_Down "); printf("RESET_HD GPIO_13_0 0_EN 1_disEN"); printf("Power_HD GPIO_13_3 1_UP 0_Down "); return 0; } int main(int argc, char **argv) { if ((3 != argc) && (4 != argc)) { PrintfInputTips(argv[0]); return -1; } unsigned char l_u8GPIONum = 0; unsigned char l_u8GPIOBit = 0; unsigned char l_u8SetValue = 0; GPIO_GROUP_E l_eGpioGroup; GPIO_BIT_E l_eBit; GPIO_DATA_E l_eData; l_u8GPIONum = atoi(argv[1]); l_u8GPIOBit = atoi(argv[2]); if (l_u8GPIONum < 14) { l_eGpioGroup = (GPIO_GROUP_E)l_u8GPIONum; } else { printf("l_u8GPIONum error l_u8GPIONum = %d", l_u8GPIONum); return -1; } if (l_u8GPIOBit < 8) { l_eBit = (GPIO_BIT_E)l_u8GPIOBit; } else { printf("l_u8GPIOBit error l_u8GPIOBit = %d", l_u8GPIOBit); return -1; } if (NULL != argv[3]) { l_u8SetValue = atoi(argv[3]); if (0 == l_u8SetValue) { l_eData = (GPIO_DATA_E)l_u8SetValue; } else if (1 == l_u8SetValue) { l_eData = (GPIO_DATA_E)l_u8SetValue; } else { printf("l_u8SetValue error l_u8SetValue = %d", l_u8SetValue); } } if (3 == argc) { /** read **/ printf("read GPIO%d Bit%d ", l_u8GPIONum, l_u8GPIOBit); /** set input **/ HstGpio_Set_Direction(l_eGpioGroup, l_eBit, GPIO_INPUT); /** read **/ char l_s8bit_val = 0; HstGpio_Get_Value(l_eGpioGroup, l_eBit, &l_s8bit_val); printf("read Data = %d ", l_s8bit_val); } else if (4 == argc) { /** write **/ printf("Write GPIO %d; Bit %d; Value %d", l_u8GPIONum, l_u8GPIOBit, l_u8SetValue); /** set IO output */ HstGpio_Set_Direction(l_eGpioGroup, l_eBit, GPIO_OUPUT); /** Write To IO */ HstGpio_Set_Value(l_eGpioGroup, l_eBit, l_eData); } else { } return 0; }
6. Insert data into a file at fixed positions
Purpose: Insert binary blobs at fixed offsets within a base binary image, useful when constructing flash images with components placed at specific positions.
#include <stdio.h> #include <stdlib.h> #include <string.h> #define BASIC_FILE_NAME "./nandflash.bin" #define UBOOT_FILE_NAME "./u-boot.bin" #define KERNEL_FILE_NAME "./kernel.bin" #define ROOTFS_FILE_NAME "./rootfs.bin" #define APP_FILE_NAME "./app.bin" #define UBOOT_POSITION 0x00 #define KERNEL_POSITION 0x100000 #define ROOTFS_POSITION 0x500000 #define APP_POSITION 0x2700000 int InsertData(FILE *pfBasic, FILE *psInsert, int s32Position) { int l_S32Ret = 0; unsigned char l_arru8Temp[1024] = {0xff}; fseek(pfBasic, s32Position, SEEK_SET); fseek(psInsert, 0, SEEK_SET); while (1) { l_S32Ret = fread(l_arru8Temp, 1, sizeof(l_arru8Temp), psInsert); if (l_S32Ret > 0) { l_S32Ret = fwrite(l_arru8Temp, 1, l_S32Ret, pfBasic); if (l_S32Ret <= 0) { printf("line %d error l_S32Ret = %d ", __LINE__, l_S32Ret); return -1; } } else { break; } } return 0; } int main(void) { int l_s32Ret = 0; FILE *l_pfBasec = NULL; FILE *l_pfUboot = NULL; FILE *l_pfKernel = NULL; FILE *l_pfRootfs = NULL; FILE *l_pfApp = NULL; l_pfBasec = fopen(BASIC_FILE_NAME, "r+"); if (NULL == l_pfBasec) { printf("line %d error ", __LINE__); goto ERROR; } l_pfUboot = fopen(UBOOT_FILE_NAME, "r"); if (NULL == l_pfUboot) { printf("line %d error ", __LINE__); goto ERROR; } l_pfKernel = fopen(KERNEL_FILE_NAME, "r"); if (NULL == l_pfKernel) { printf("line %d error ", __LINE__); goto ERROR; } l_pfRootfs = fopen(ROOTFS_FILE_NAME, "r"); if (NULL == l_pfRootfs) { printf("line %d error ", __LINE__); goto ERROR; } l_pfApp = fopen(APP_FILE_NAME, "r"); if (NULL == l_pfApp) { printf("line %d error ", __LINE__); goto ERROR; } if (0 > InsertData(l_pfBasec, l_pfUboot, UBOOT_POSITION)) { printf("line %d error ", __LINE__); goto ERROR; } if (0 > InsertData(l_pfBasec, l_pfKernel, KERNEL_POSITION)) { printf("line %d error ", __LINE__); goto ERROR; } if (0 > InsertData(l_pfBasec, l_pfRootfs, ROOTFS_POSITION)) { printf("line %d error ", __LINE__); goto ERROR; } if (0 > InsertData(l_pfBasec, l_pfApp, APP_POSITION)) { printf("line %d error ", __LINE__); goto ERROR; } ERROR: if (NULL != l_pfBasec) { fclose(l_pfBasec); l_pfBasec = NULL; } if (NULL != l_pfUboot) { fclose(l_pfUboot); l_pfUboot = NULL; } if (NULL != l_pfKernel) { fclose(l_pfKernel); l_pfKernel = NULL; } if (NULL != l_pfRootfs) { fclose(l_pfRootfs); l_pfRootfs = NULL; } if (NULL != l_pfApp) { fclose(l_pfApp); l_pfApp = NULL; } return 0; }
7. Get local IP addresses on Linux
Purpose: Enumerate local IPv4 addresses on a Linux device. The example supports up to three interfaces, but the buffer sizes can be adjusted for more.
#include <stdio.h> #include <ifaddrs.h> #include <netinet/in.h> #include <string.h> #include <arpa/inet.h> int get_local_ip(char *ps8IpList) { struct ifaddrs *ifAddrStruct; char l_s8IpAddr[INET_ADDRSTRLEN]; void *tmpAddrPtr; int l_s32IPCount = 0; getifaddrs(&ifAddrStruct); while (ifAddrStruct != NULL) { if (ifAddrStruct->ifa_addr->sa_family == AF_INET) { tmpAddrPtr = &((struct sockaddr_in *)ifAddrStruct->ifa_addr)->sin_addr; inet_ntop(AF_INET, tmpAddrPtr, l_s8IpAddr, INET_ADDRSTRLEN); if (strcmp(l_s8IpAddr, "127.0.0.1") != 0) { if (l_s32IPCount == 0) { memcpy(ps8IpList, l_s8IpAddr, INET_ADDRSTRLEN); } else { memcpy(ps8IpList + INET_ADDRSTRLEN * l_s32IPCount, l_s8IpAddr, INET_ADDRSTRLEN); } l_s32IPCount++; } } ifAddrStruct = ifAddrStruct->ifa_next; } freeifaddrs(ifAddrStruct); return l_s32IPCount; } int main() { char l_arrs8IpAddrList[3][INET_ADDRSTRLEN]; int l_s32AddrCount; memset(l_arrs8IpAddrList, 0, sizeof(l_arrs8IpAddrList)); l_s32AddrCount = get_local_ip((char *)l_arrs8IpAddrList); for (int i = 0; i < l_s32AddrCount; i++) { printf("Server Local IP%d: %s", i + 1, l_arrs8IpAddrList[i]); } return 0; }
ALLPCB