MinGW C Demo: Retrieve Battery Voltage

1.Environment

2.How to use

  • Compile following code in Visual Studio or or MinGW
gcc -o opbt_battery.exe opbt_battery_voltage.c
  • Run program:
opbt_battery.exe COM3 9600
  • 运行结果
Entering command mode...
Response: {"OK":true}
Querying battery voltage...
Response: {"BatteryVoltage":4011}

Battery voltage: 4011 mV (4.01 V)
Exiting command mode...
Response: {"OK":false}

3. Understand the code

Features

  • Connect OP-BT/BTS by using serial port
  • Send command to enter command mode
  • Query battery voltage
  • Parse and display voltage
  • Exit command mode
  • Shutdown serial port connection

Key Steps

  • Use Windows API (CreateFile, WriteFile, ReadFile等) to access serial port
  • Send command to enter command mode: {“AtCommandMode”:true}
  • Send command to query device information: {“BatteryVoltage”:"?"}
  • Parse data to retrieve battery voltage
  • Send command to exit command mode: {“AtCommandMode”:false}

4. Code

// opbt_battery_voltage.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>

#define BUFFER_SIZE 1024
#define DEFAULT_COM "COM3"  // Default COM port, can be modified as needed
#define DEFAULT_BAUDRATE 9600  // Default baud rate, can be modified as needed

// Send command and receive response
int sendCommand(HANDLE hSerial, const char* command, char* response, int responseSize) {
    DWORD bytesWritten = 0;
    DWORD bytesRead = 0;
    BOOL status;
    
    // Clear receive buffer
    PurgeComm(hSerial, PURGE_RXCLEAR | PURGE_TXCLEAR);
    
    // Send command
    status = WriteFile(hSerial, command, strlen(command), &bytesWritten, NULL);
    if (!status || bytesWritten != strlen(command)) {
        printf("Failed to send command\n");
        return -1;
    }
    
    // Wait for device response
    Sleep(500);  // Wait 500ms, can be adjusted based on device response time
    
    // Read response
    memset(response, 0, responseSize);
    status = ReadFile(hSerial, response, responseSize - 1, &bytesRead, NULL);
    if (!status) {
        printf("Failed to read response\n");
        return -1;
    }
    
    response[bytesRead] = '\0';  // Ensure string is null-terminated
    return bytesRead;
}

// Parse battery voltage from JSON response
int parseBatteryVoltage(const char* jsonResponse) {
    char* batteryStr = strstr(jsonResponse, "\"BatteryVoltage\":");
    if (batteryStr == NULL) {
        return -1;  // Battery voltage field not found
    }
    
    // Move pointer to value position
    batteryStr += strlen("\"BatteryVoltage\":");
    
    // Skip spaces
    while (*batteryStr == ' ') {
        batteryStr++;
    }
    
    // Parse value
    return atoi(batteryStr);
}

int main(int argc, char* argv[]) {
    HANDLE hSerial;
    DCB dcbSerialParams = {0};
    COMMTIMEOUTS timeouts = {0};
    char response[BUFFER_SIZE];
    char comPort[20] = DEFAULT_COM;
    int baudRate = DEFAULT_BAUDRATE;
    
    // Process command line arguments
    if (argc >= 2) {
        strcpy(comPort, argv[1]);
    }
    if (argc >= 3) {
        baudRate = atoi(argv[2]);
    }
    
    printf("Using COM port: %s, Baud rate: %d\n", comPort, baudRate);
    
    // Open serial port
    hSerial = CreateFile(comPort,
                         GENERIC_READ | GENERIC_WRITE,
                         0,
                         NULL,
                         OPEN_EXISTING,
                         FILE_ATTRIBUTE_NORMAL,
                         NULL);
    
    if (hSerial == INVALID_HANDLE_VALUE) {
        printf("Failed to open COM port %s, error code: %d\n", comPort, GetLastError());
        return 1;
    }
    
    // Configure serial port parameters
    dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
    if (!GetCommState(hSerial, &dcbSerialParams)) {
        printf("Failed to get COM port status\n");
        CloseHandle(hSerial);
        return 1;
    }
    
    dcbSerialParams.BaudRate = baudRate;
    dcbSerialParams.ByteSize = 8;
    dcbSerialParams.StopBits = ONESTOPBIT;
    dcbSerialParams.Parity = NOPARITY;
    
    if (!SetCommState(hSerial, &dcbSerialParams)) {
        printf("Failed to set COM port parameters\n");
        CloseHandle(hSerial);
        return 1;
    }
    
    // Set timeouts
    timeouts.ReadIntervalTimeout = 50;
    timeouts.ReadTotalTimeoutConstant = 1000;
    timeouts.ReadTotalTimeoutMultiplier = 10;
    timeouts.WriteTotalTimeoutConstant = 1000;
    timeouts.WriteTotalTimeoutMultiplier = 10;
    
    if (!SetCommTimeouts(hSerial, &timeouts)) {
        printf("Failed to set COM port timeouts\n");
        CloseHandle(hSerial);
        return 1;
    }
    
    // 1. Enter command mode
    printf("Entering command mode...\n");
    if (sendCommand(hSerial, "{\"AtCommandMode\":true}\r\n", response, BUFFER_SIZE) > 0) {
        printf("Response: %s\n", response);
        if (strstr(response, "{\"OK\":true}") == NULL) {
            printf("Failed to enter command mode\n");
            CloseHandle(hSerial);
            return 1;
        }
    } else {
        printf("Failed to send command\n");
        CloseHandle(hSerial);
        return 1;
    }
    
    // 2. Query battery voltage directly
    printf("Querying battery voltage...\n");
    if (sendCommand(hSerial, "{\"BatteryVoltage\":\"?\"}\r\n", response, BUFFER_SIZE) > 0) {
        printf("Response: %s\n", response);
        
        // Parse battery voltage
        int batteryVoltage = parseBatteryVoltage(response);
        if (batteryVoltage > 0) {
            printf("\nBattery voltage: %d mV (%.2f V)\n", batteryVoltage, batteryVoltage / 1000.0);
        } else {
            printf("Unable to parse battery voltage\n");
        }
    } else {
        printf("Failed to send command\n");
    }
    
    // 3. Exit command mode
    printf("Exiting command mode...\n");
    if (sendCommand(hSerial, "{\"AtCommandMode\":false}\r\n", response, BUFFER_SIZE) > 0) {
        printf("Response: %s\n", response);
    }
    
    // Close serial port
    CloseHandle(hSerial);
    
    return 0;
}