/*nice*/
顯示具有 C++ 標籤的文章。 顯示所有文章
顯示具有 C++ 標籤的文章。 顯示所有文章

2023年8月28日 星期一

C on Win10

後來才知道DevC++已經沒有在更新了
所以…

codeblocks + MSVCRT runtime (UCRT runtime這兩個不知道有什麼分別)


CodeBlock安裝好後,
把MinGW-w64解壓縮後,放到某個路徑下

CodeBlock, Setting->Compiler
有Toolchain executables,
這裡指定MinGW-w64的路徑,ex: C:\mingw64\
如果有另外的library(可以在 mingw64 資料夾下找尋)
就在Linker settings那加入

Search for a specific COM port on Win10

#include <windows.h>
#include <setupapi.h>
#include <stdio.h>
#include <devguid.h>
#include <wchar.h>

#define SEARCH_STRINT "Cinterion PLSx3 USB Com Port1 "


int main() {

    // Get a handle to a device information set for COM ports
    HDEVINFO hdevinfo;
    
    //GUID ClassGuid = {0x4d36e978,0xe325,0x11ce,{0xbf,0xc1,0x08,0x00,0x2b,0xe1,0x03,0x18}};
    GUID guid = {0x4d36e978,0xe325,0x11ce,{0xbf,0xc1,0x08,0x00,0x2b,0xe1,0x03,0x18}}; //GUID_DEVCLASS_PORTS
    
    //查到資料大多這樣寫,devguid.h也宣告了
    //但mingw64編譯卻一直說找不到GUID_DEVCLASS_USB @@
    //所以改用查guid碼方式來避開
    //hDevInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_USB, 0, 0, DIGCF_PRESENT);
    
    
    hdevinfo = SetupDiGetClassDevs((LPGUID)&guid, NULL, NULL, DIGCF_PRESENT );

    if (hdevinfo == INVALID_HANDLE_VALUE) {
        printf("SetupDiGetClassDevs failed with error code %d\n", GetLastError());
        return 1;
    }

    // Enumerate through the COM ports
    SP_DEVINFO_DATA devinfoData;
    devinfoData.cbSize = sizeof(SP_DEVINFO_DATA);

    SP_DEVICE_INTERFACE_DATA interfaceData;
    interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

    DWORD index = 0;
    for(index=0; SetupDiEnumDeviceInfo(hdevinfo, index, &devinfoData); index++)
    {
        wchar_t friendlyName[128];

        if (SetupDiGetDeviceRegistryProperty(hdevinfo, &devinfoData, SPDRP_HARDWAREID, NULL, (BYTE*)friendlyName, sizeof(friendlyName), NULL))
        {
            // Check if the COM port information matches the USB modem's VID and PID
            //printf("friendlyName=%s\n", friendlyName);
            char cpy[128];
            char comport[COMPORT_SIZE];
            strcpy(cpy, (char *)friendlyName);
            //printf("%d. cpy=%s\n", (int)index, cpy);
            if (strcmp(cpy, SEARCH_STR0))
                continue;

            if (SetupDiGetDeviceRegistryProperty(hdevinfo, &devinfoData, SPDRP_FRIENDLYNAME, NULL, (BYTE*)friendlyName, sizeof(friendlyName), NULL))
            {
                strcpy(cpy, (char *)friendlyName);
                //printf("%d. cpy=%s\n", (int)index, cpy);

                char *p;
                p = strtok(cpy, SEARCH_STR2);
                for (; p != NULL; )
                {
                    //printf( "pp=%s\n", p );
                    p = strtok(NULL, "M");
                    if(p)
                        strncpy(comport, p, COMPORT_SIZE);
                }
            }
            //printf("p=%s, len=%zu\n", comport, strlen(comport));
            comport[strlen(comport)-1]='\0';
            //printf("comport=%s\n", comport);
            strcpy(com, comport);
            //printf("com=%s\n", com);
        }
    }

    // Clean up
    SetupDiDestroyDeviceInfoList(hdevinfo);

    return 0;
}
Ref: ChatGPT

2023年8月25日 星期五

List all serial com port on Win10

Copied the code from Here
#define WIN32_LEAN_AND_MEAN  // excludes stuff frokm windows.h that we won't need here.
#include  <Windows.h>
#include  <string.h>
#include  <tchar.h>
#include  <malloc.h>
#include  <stdio.h>

void ShowErrorFromLStatus(LSTATUS lResult)
{
    LPTSTR psz;
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
        NULL,
        lResult,
        0,
        (LPTSTR)&psz,
        1024,
        NULL);

    _tprintf(_T("Windows reports error: (0x%08X): %s\n"), lResult, (psz) ? psz : _T("(null)"));
    if (psz)
    {
        LocalFree(psz);
    }
}

int main()
{
    DWORD nValues, nMaxValueNameLen, nMaxValueLen;
    HKEY hKey = NULL;
    LPTSTR szDeviceName = NULL;
    LPTSTR szFriendlyName = NULL;
    DWORD dwType = 0;
    DWORD nValueNameLen = 0;
    DWORD nValueLen = 0;
    DWORD dwIndex = 0;

    LSTATUS lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DEVICEMAP\\SERIALCOMM"), 0, KEY_READ, &hKey);
    if (ERROR_SUCCESS != lResult)
    {
        printf("Failed to open key \'HARDWARE\\DEVICEMAP\\SERIALCOMM\' \n");
        ShowErrorFromLStatus(lResult);
        return 1;
    }

    lResult = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL,
        &nValues, &nMaxValueNameLen, &nMaxValueLen, NULL, NULL);

    if (ERROR_SUCCESS != lResult)
    {
        _tprintf(_T("Failed to RegQueryInfoKey()\n"));
        ShowErrorFromLStatus(lResult);
        RegCloseKey(hKey);
        return 2;
    }

    szDeviceName = (LPTSTR)malloc(nMaxValueNameLen + sizeof(TCHAR));
    if (!szDeviceName)
    {
        _tprintf(_T("malloc() fail\n"));
        RegCloseKey(hKey);
        return 3;
    }

    szFriendlyName = (LPTSTR)malloc(nMaxValueLen + sizeof(TCHAR));
    if (!szFriendlyName)
    {
        free(szDeviceName);
        _tprintf(_T("malloc() fail\n"));
        RegCloseKey(hKey);
        return 3;
    }

    _tprintf(_T("Found %d serial device(s) registered with PnP and active or available at the moment.\n"), nValues);

    for (DWORD dwIndex = 0; dwIndex  &lt; nValues; ++dwIndex)
    {
        dwType = 0;
        nValueNameLen = nMaxValueNameLen + sizeof(TCHAR);
        nValueLen = nMaxValueLen + sizeof(TCHAR);

        lResult = RegEnumValueW(hKey, dwIndex, 
            (LPWSTR)szDeviceName, &nValueNameLen,
            NULL, &dwType, 
            (LPBYTE)szFriendlyName, &nValueLen);

        if (ERROR_SUCCESS != lResult || REG_SZ != dwType)
        {
            _tprintf(_T("SerialPortEnumerator::Init() : can't process registry value, index: %d\n"), dwIndex);
            ShowErrorFromLStatus(lResult);
            continue;
        }
        _tprintf(_T("Found port \'%ls\': Device name for CreateFile(): \'\\.%ls\'\n"), szFriendlyName, szDeviceName);
    }

    free(szDeviceName);
    free(szFriendlyName);
    RegCloseKey(hKey);
    return 0;
}

Output:
C:\Test>auto_com_port.exe
Found 8 serial device(s) registered with PnP and active or available at the moment.
Found port 'COM1': Device name for CreateFile(): '\.\Device\Serial0'
Found port 'COM24': Device name for CreateFile(): '\.\Device\USBSER00COM24'
Found port 'COM25': Device name for CreateFile(): '\.\Device\USBSER00COM25'
Found port 'COM22': Device name for CreateFile(): '\.\Device\USBSER00COM22'
Found port 'COM23': Device name for CreateFile(): '\.\Device\USBSER00COM23'
Found port 'COM15': Device name for CreateFile(): '\.\Device\QCUSB_COCOM15'
Found port 'COM16': Device name for CreateFile(): '\.\Device\QCUSB_COCOM16'
Found port 'COM17': Device name for CreateFile(): '\.\Device\QCUSB_COCOM17'


ref:
Here

2022年9月30日 星期五

xdo on linux (按鍵精靈)

xdo, 按鍵精靈, works on XUbuntu 20.04

Install:
$ sudo apt-get install libxdo-dev libxdo3 xdotool 

Exsample:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <xdo.h>
#include <unistd.h>


void mouse_left_click(const xdo_t *xdo, int x, int y)
{
    xdo_click_window(xdo, CURRENTWINDOW, Button1); //left mouse key
    return;
}

void keyboard_enter_string(const xdo_t *xdo, const char *str, size_t slen)
{
    int i=0;
    char character[2]={'\0'};

    for(i=0; i<slen; i++)
    {
        character[0]=*(str+i);
        xdo_send_keysequence_window(xdo, CURRENTWINDOW, character, 0);
    }
    return;
}

int main(void)
{
    //xdo_t *x = xdo_new(":0.0");
    xdo_t * x = xdo_new(NULL);
    xdo_send_keysequence_window(x, CURRENTWINDOW, "Alt_L+Tab", 0);
    sleep(3);

    xdo_move_mouse(x, 628, 435, CURRENTWINDOW);
    sleep(2);
    mouse_left_click(x, 0, 0);


    //xdo_send_keysequence_window(x, CURRENTWINDOW, "Alt_L+Tab", 0);
    //sleep(1);
    ////keyboard_enter_string(x, "Hello", strlen("Hello"));
    xdo_enter_text_window(x, CURRENTWINDOW, "hello world", 1000);

    //xdo_send_keysequence_window(x, CURRENTWINDOW, "KP_Enter", 0); //ok
    //xdo_send_keysequence_window(x, CURRENTWINDOW, "Alt_L+F4", 0); //ok
    //xdo_send_keysequence_window(x, CURRENTWINDOW, "Shift_L+Super_L+s", 0); //ok

    xdo_free(x);
    return 0; 
}
$ gcc example.c -o ex -lxdo

get current mouse coordinates:
$ xdotool getmouselocation --shell


ref:
1. How would I get the current mouse coordinates in bash?
2. C language - trigger key events in Linux with xdo

2022年9月18日 星期日

Parse CCLK with strptime

example:
ctime="+CCLK: "22/09/19,03:21:12+32""
void parsetime (const char *ctime)
{

    char ptime[32]; //parse time
    char *buf=(char *)malloc(sizeof(char) * 32);
    struct tm tt;
    time_t putime, \
           nutime;
    int time_zone=0;

    sscanf(ctime, "%s %s", buf, ptime);
    free(buf);

    buf=strstr(ptime, "+");
    if (buf == NULL)
	buf=strstr(ptime, "-");
    if (buf == NULL)
    {
        printf("err: can't find the time zone\n");
        exit(1);
    }
	
    ptime[strlen(ptime)-strlen(buf)]='\0'; //remove time zone and late character
    buf++; //get time zone
    time_zone=atoi(buf);
    buf=ptime+1; //remove first character
    strncpy(ptime, buf, 32);
    printf("time_zone=%d, buf=%s, ptime=%s\n", time_zone, buf, ptime);
    

    strptime(ptime, "%y/%m/%d,%H:%M:%S", &tt);
    tt.tm_hour+=(time_zone/4);
    printf("tm_sec:  %d\n",tt.tm_sec);
    printf("tm_min:  %d\n",tt.tm_min);
    printf("tm_hour:  %d\n",tt.tm_hour);
    printf("tm_mday:  %d\n",tt.tm_mday);
    printf("tm_mon:  %d\n",tt.tm_mon+1);
    printf("tm_year:  %d\n",tt.tm_year-100);


    putime = mktime(&tt);
    nutime=(long int)time(NULL);
    printf("nutime-putime=%ld\n", nutime-putime);
    return;
}

ref:
strptime



PLS83, RIL(libril-cwm-lte) network.c
void parseNITZresponse(char *szNITZrepsonse)
{
    ...
    ...
    // All parameters available: generate NITZ notifications.
    generateNITZnotification(nitzUtUCS2, nitzTZ, nitzDST);
}


other keywords:
    RIL_UNSOL_NITZ_TIME_RECEIVED

Other keywords in Android:
frameworks/opt/telephony/src/java/com/android/internal/telephony/ServiceStateTracker.java
    setTimeFromNITZString(nitzString, nitzReceiveTime)

ref:
1. android 手機的網絡時間同步
2. https://www.itdaan.com/tw/7a3b63850d9d

2022年7月24日 星期日

AT command and PLS83

read: cat /dev/ttyACM0
write: echo "ACT" > /dev/ttyACM0
read line: get_next_line.git


main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h> 

#include <limits.h>
#include "get_next_line.h"
#include "utool.h"

#define TEST_THERMAL 1

#if TEST_THERMAL
const char *Thermal_atc[] = 
{   
    "at\r",
    "ati1\r",
    "at+csq\r",
    "at^sctm=1,1\r",
    "at^sctm?\r"
};
#else //connect to Internet
const char *QMI_atc[] = 
{   
    "at\r",
    "at+cpin?\r",
    "at+cops?\r",
};
const char *ECM_atc[] = 
{   
    "at\r",
    "at+cpin?\r",
    "at+cops?\r",
    "AT+CGPADDR=?\r,"
    "AT+CGPADDR\r",
    "AT+CGPADDR=1,1\r",
    "AT^SWWAN=?\r",
    "AT^SWWAN?\r",
    "AT^SWWAN=1,1,1\r",
};

//QMI, PID=006F
const char *QMIMODE[] =
{
    "at^ssrvset=\"actSrvset\",11\r",
    "at+cfun=1,1"
};

//ECM, PID=0069
const char *ECMMODE[] =
{
    "at^ssrvset=\"actSrvset\",1\r",
    "at+cfun=1,1"
};

#endif

int STOP_PROCESS=0;

void *test_cat(void *fd_)
{
    #ifdef TEST_THERMAL
    #else
    char *err="";
    #endif
    int fd= *((int *)fd_);
    int ret=0;
    char *line;

    while ((ret = get_next_line(fd, &line)) == STATUS_LINE)
    {
        printf("output=%s\n", line);
        #ifdef TEST_THERMAL
        #else
        err=strstr(line, "ERR");
        if ( err != NULL)
        {
            STOP_PROCESS=1;
            printf(cRED "err=%s\n" cRESET, err);
            pthread_exit(NULL);
        }
        err=strstr(line, "SHUTDOWN");
        if ( err != NULL)
        {
            STOP_PROCESS=1;
            printf(cRED "err=%s\n" cRESET, err);
            pthread_exit(NULL);
        }
        #endif
        free(line);
    }

    if (ret == -1)
        printf("error\n");
    else if (ret == 0)
    {
        printf("at EOF: [%s]\n", line);
        free(line);
        printf("EOF\n");
    }
    printf("thread done\n");

    return NULL;
}

int todoECM(void)
{
    ssize_t size=128;
    char *file_path=(char *)malloc(sizeof(char)*size);
    char *wwan_path=(char *)malloc(sizeof(char)*size);
    char *wwan;
    char *cmd=(char *)malloc(sizeof(char)*size);

    int fd;
    DIR *d;
    struct dirent *dir;
    char *line;
    int ret=0;
    char *sret;
    ssize_t slen=0;


    d = opendir("/sys/class/net");
    if (d) 
    {
        while ((dir = readdir(d)) != NULL) 
        {
            printf("%s\n", dir->d_name);
            if (strlen (dir->d_name) <= 2)
                continue;
            sprintf(file_path, "/sys/class/net/%s/uevent", dir->d_name);
            printf("file_path=%s\n", file_path);
            fd=open(file_path, O_RDONLY);
            while ((ret = get_next_line(fd, &line)) == STATUS_LINE)
            {
                printf("line=%s\n", line);
                sret=strstr(line, "wwan");
                slen =( sret == NULL ? 0 : strlen(sret));
                if (slen > 0)
                    break;
            }
            if (slen > 0)
                if (get_next_line(fd, &line) == STATUS_LINE)
                {
                    printf("line2=%s\n", line);
                    break;
                }
        }
        closedir(d);
    }

    wwan=strtok(line, "=");
    wwan=strtok(NULL, "=");
    printf("wwan=%s\n", wwan);

    sprintf(cmd, "sudo ifconfig %s up", wwan);
    printf("cmd=%s\n", cmd);
    system(cmd);
    memset(cmd, '\0', sizeof(char));
    
    sprintf(cmd, "sudo dhclient %s", wwan);
    printf("cmd=%s\n", cmd);
    system(cmd);
    memset(cmd, '\0', sizeof(char));
    
    free(cmd);
    free(wwan_path);

    return 0;
}

int todoQMI(void)
{
    int i=0;
    ssize_t size=128;
    char *cdcwdm_path =(char *)malloc(sizeof(char)*size);
    char *wwan_path=(char *)malloc(sizeof(char)*size);
    char wwan[8];
    char *cmd=(char *)malloc(sizeof(char)*size);

    for (i=0; i<9; i++) // Suppose cdc-wdm ranges from 0 to 9
    {
        memset(cdcwdm_path, '\0', sizeof(char)*size);
        sprintf(cdcwdm_path, "/dev/cdc-wdm%d", i);
        if ( access(cdcwdm_path, F_OK) == 0 )  //file exists
            break;
    }
    sprintf(cmd, "sudo qmicli -d %s -p --dms-get-operating-mode", cdcwdm_path);
    printf("cmd=%s\n", cmd);
    system(cmd);
    memset(cmd, '\0', sizeof(char)*size);
    sprintf(cmd, "sudo qmicli -d %s -p --get-wwan-iface", cdcwdm_path);
    printf("cmd=%s\n", cmd);
    system(cmd);
    memset(cmd, '\0', sizeof(char));
    
    for (i=0; i<9; i++) // Suppose cdc-wdm ranges from 0 to 9
    {
        memset(wwan_path, '\0', sizeof(char)*size);
        sprintf(wwan_path, "/sys/class/net/wwan%d", i);
        if ( access(wwan_path, F_OK) == 0 )  //file exists
        {
            sprintf(wwan, "wwan%d", i);
            break;
        }
    }
    sprintf(cmd, "sudo ip link set %s down", wwan);
    printf("cmd=%s\n", cmd);
    system(cmd);
    memset(cmd, '\0', sizeof(char));
    
    sprintf(cmd, "echo \'Y\' | sudo tee /sys/class/net/%s/qmi/raw_ip", wwan);
    printf("cmd=%s\n", cmd);
    system(cmd);
    memset(cmd, '\0', sizeof(char));
    
    sprintf(cmd, "udo ip link set %s up", wwan);
    printf("cmd=%s\n", cmd);
    system(cmd);
    memset(cmd, '\0', sizeof(char));

    sprintf(cmd, "sudo qmicli -p -d %s -p --wds-start-network=\"apn='Internet',ip-type=4\" --client-no-release-cid", cdcwdm_path);
    printf("cmd=%s\n", cmd);
    system(cmd);
    memset(cmd, '\0', sizeof(char));

    sprintf(cmd, "sudo udhcpc -i %s", wwan);
    printf("cmd=%s\n", cmd);
    system(cmd);
    memset(cmd, '\0', sizeof(char));
    
    free(cmd);
    free(wwan_path);
    free(cdcwdm_path);
    return 0;
}

int main (void)
{

    pthread_t thread1;
    char *getMode=(char *)malloc(sizeof(char)*32);
    void *ret;

    int fd=-1;
    int i=0;
    ssize_t count=0;
    int sleep_time=0;
    const char **MODE_atc;
    int (*todoMode)(void)=NULL;

    fd=open("/dev/ttyACM0", O_RDWR);
    if (fd < 0)
    {
        printf("cant' find the ACM0\n");
    }
    
    isPID69or6f(&getMode);

    printf("get_mode=%s\n", getMode);

    pthread_create(&thread1, NULL, test_cat, (void *)&fd);

#if TEST_THERMAL
    //count=sizeof(Thermal_atc)/sizeof(Thermal_atc[0]);
    count=NUM_ELEMS(Thermal_atc);
    printf("count=%ld\n", count);
    sleep_time = 500*2;
    for (i=0 ; STOP_PROCESS == 0; i++)
    {
        if (i == count)
            i=0;
        //printf(cGREEN "start the process...atc=%s\n" cRESET, Thermal_atc[i]);
        //write(fd, Thermal_atc[i], strlen(Thermal_atc[i]));
        MODE_atc=Thermal_atc;
#else
    if (!strcmp("QMI", getMode))
    {
        //QMI to do
        //count=sizeof(QMI_atc)/sizeof(QMI_atc[0]);
        count=NUM_ELEMS(QMI_atc[0]);
        printf("count=%ld\n", count);
        MODE_atc=QMI_atc;
        todoMode=todoQMI;
    }
    else
    {
        //ECM to do
        //count=sizeof(ECM_atc)/sizeof(ECM_atc[0]);
        count=NUM_ELEMS(ECM_atc);
        printf("count=%ld\n", count);
        MODE_atc=ECM_atc;
        todoMode=todoECM;
    }
    sleep_time = 500;
    for (i=0; i < count && STOP_PROCESS == 0; i++)
    {   
#endif
        printf(cGREEN "start the process...%s, atc=%s\n" cRESET, getMode, MODE_atc[i]);
        write(fd, MODE_atc[i], strlen(MODE_atc[i]));
        msleep(sleep_time);
    }
    todoMode();
    if (i == count)
    {
        printf("iiii=%d, count=%ld\n", i, count);
        pthread_cancel(thread1);
        close(fd);
    }

    pthread_join( thread1, (void *)(&ret));
    

    printf("main done\n");

    free(getMode);

    return 0;
}

utool.c
#define _GNU_SOURCE
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <dirent.h> 
#include <signal.h>
#include <errno.h>
#include <time.h>
#include "utool.h"


void msleep(unsigned long msec) {
    struct timespec ts;
    int err;

    ts.tv_sec = (msec / 1000);
    ts.tv_nsec = (msec % 1000) * 1000 * 1000;

    do {
        err = nanosleep (&ts, &ts);
    } while (err < 0 && errno == EINTR);
}

//缺點:USB沒有拔掉的話,路徑好像不會被移除
int isPID69or6f(char **mode)
{
    const char *QMIpath="/sys/bus/usb/drivers/qmi_wwan";
    const char *ECMpath="/sys/bus/usb/drivers/cdc_acm"; //or cdc_ether

    if ( access(QMIpath, F_OK) == 0 )  //file exists
    {
	strcpy( *mode, "QMI");
        printf(cRED "QMI mode\n" cRESET);
    }
    else if ( access(ECMpath, F_OK) == 0 )
    {
	strcpy( *mode, "ECM");
        printf(cRED "ECM mode\n" cRESET);
    }

    return 0;
}

utool.h
#include <pthread.h>

#define cRED "\x1b[;31;1m"
#define cGREEN "\x1b[;32;1m"
#define cRESET "\x1b[0;m"

#define NUM_ELEMS(a)        (sizeof(a) / sizeof(a[0]))

int isPID69or6f(char **mode);
void msleep(unsigned long msec);
int executeSystemCmd(const char *cmd, char **response, int timeout);

2021年8月11日 星期三

basic CMakeLists.txt for hello_world

$ tree
cmake-hello-world/
├── CMakeLists.txt
├── linux-android.toolchain.cmake
└── src
    ├── main.cpp
    └── TestHello
        ├── test.cpp
        └── test.h

CMakeLists.txt (下面還有一個,比較好用, Cross compile for Android)
cmake_minimum_required (VERSION 3.10)
project (CMakeHelloWorld)

#version number
set (CMakeHelloWorld_VERSION_MAJOR 1)
set (CMakeHelloWorld_VERSION_MINOR 0)

message (STATUS "CXX is $ENV{CXX}")

set(argument_list)

option(USE_ANDROID "" OFF) #OFF by default
if (USE_ANDROID)
    set (CMAKE_ANDROID_ARCH_ABI arm64-v8a)
    set (ANDROID_STL "c++_static")
    set (CMAKE_CXX_COMPILER $ENV{CXX})
    set (CMAKE_AR $ENV{AR})
    set (CMAKE_RANLIB $ENV{RANLIB})
    set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif()


include_directories(src/TestHello)         # 指定 include header path        
set(HELLO_SOURCES src/TestHello/test.cpp)    # 設定變數, 將第二個所給予的內容指定到第一個變數名稱當中
#set(HELLO_SOURCES src/HelloWorld.cpp)
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)   # PROJECT....是CMAKE寫好的變數
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

#add_library(test_hello SHARED src/main.cpp src/TestHello/test.cpp src/TestHello/test.h)

add_library(hello ${HELLO_SOURCES})
#add_library(hello2 ${HELLO_SOURCES2})
add_executable(main src/main.cpp ${HELLO_SOURCES})    #  產生可執行檔
if (USE_ANDROID)
    #target_link_libraries需寫在add_executable的下方
    target_link_libraries(main hello -latomic -lc++_static -lc++abi)
else()
    target_link_libraries(main hello)
endif()
APP_STL := c++_shared or c++_static
不要在ndk中使用系统预编译好的C++库

main.cpp
#include <test.h>

using namespace std;

int main(void)
{
    Test t;
    t.Hello();
}

test.cpp
#include "test.h"

using namespace std;

void Test::Hello(void)
{
    cout << "Hello, world!\n" << endl;
}

test.h
#include <stdio.h>
#include <iostream>

using namespace std;

class Test{
    public:
        void Hello (void);
};

compile
$ mkdir build; cd build
$ cmake ..
or
$ cmake -D USE_ANDROID=ON ..
沒有問題後
$ cd build
$ make


ref:
1. cmake
2. How to cross-compile for embedded with CMake like a champ
3. 不要在ndk中使用系统预编译好的C++库
4. CMake 入門/運算子
5. 关于安卓的交叉编译

CMakeLists.txt
cmake_minimum_required (VERSION 3.10)
project (CMakeHelloWorld)

#version number
set (CMakeHelloWorld_VERSION_MAJOR 1)
set (CMakeHelloWorld_VERSION_MINOR 0)

message (STATUS "CXX is $ENV{CXX}")

set(argument_list)

option(USE_ANDROID "" OFF) #OFF by default
if (USE_ANDROID)
    set (CMAKE_ANDROID_ARCH_ABI arm64-v8a)
    set (ANDROID_STL "c++_static")
    set (CMAKE_CXX_COMPILER $ENV{CXX})
    set (CMAKE_AR $ENV{AR})
    set (CMAKE_RANLIB $ENV{RANLIB})
    set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
endif()
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
    message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")

endif()


include_directories(src/TestHello)         # 指定 include header path        
#set(HELLO_SOURCES src/TestHello/test.cpp)    # 設定變數, 將第二個所給予的內容指定到第一個變數名稱當中
file(GLOB SOURCES src/TestHello/*.cpp src/TestHello/*.h)
#set(HELLO_SOURCES src/HelloWorld.cpp)
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)   # PROJECT....是CMAKE寫好的變數
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

#add_library(test_hello SHARED src/main.cpp src/TestHello/test.cpp src/TestHello/test.h)

#add_library(hello ${HELLO_SOURCES})
#add_library(hello2 ${HELLO_SOURCES2})
add_executable(main src/main.cpp ${SOURCES})    #  產生可執行檔
if (USE_ANDROID)
    target_link_libraries(main  -latomic -lc++_static -lc++abi)
else()
    target_link_libraries(main)
endif()

linux-android.toolchain.cmake
if (USE_ANDROID)
    if (NOT NDKDIR)
        message(FATAL_ERROR "Set NDK_DIR, Recommended version 22.1.7171670")
    endif()

#set (NDK "/opt/android_studio/sdk/ndk/22.1.7171670")
set (TOOLCHAIN "${NDKDIR}/toolchains/llvm/prebuilt/linux-x86_64")

#set (CMAKE_ANDROID_API 29)
set (ANDROID_STL "c++_static")

if (${CMAKE_ANDROID_ARCH_ABI} STREQUAL "arm64-v8a")
    set (TARGET "aarch64-linux-android")
elseif (${CMAKE_ANDROID_ARCH_ABI} STREQUAL "armeabi-v7a")
    set (TARGET "armv7a-linux-androideabi")
else()
    set (TARGET "x86_64-linux-android")
endif()

set (CMAKE_C_COMPILER ${TOOLCHAIN}/bin/${TARGET}${CMAKE_ANDROID_API}-clang)
message (STATUS "1111111111 is ${CMAKE_C_COMPILER}")
set (CMAKE_CXX_COMPILER ${TOOLCHAIN}/bin/${TARGET}${CMAKE_ANDROID_API}-clang++)
set (CMAKE_AR     ${TOOLCHAIN}/bin/${TARGET}$-ar)
set (CMAKE_RANLIB ${TOOLCHAIN}/bin/${TARGET}$-ranlib)

# set searching rules for cross-compiler
SET (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
SET (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
endif()

compile
$ mkdir build; cd build
$ cmake -D USE_ANDROID=ON -D CMAKE_TOOLCHAIN_FILE=../linux-android.toolchain.cmake  -D NDKDIR=/opt/android_studio/sdk/ndk/22.1.7171670 -D CMAKE_ANDROID_ARCH_ABI=arm64-v8a -D CMAKE_ANDROID_API=29 ..
沒有問題後
$ make

2021年3月12日 星期五

Get EDID

1.  EDID 1.4 Spec
2.  EDID解析
3.  EDID簡介


$ sudo find /sys/ | grep -i edid


/sys/kernel/debug/dri/0/HDMI-A-1/edid_override
/sys/kernel/debug/dri/0/VGA-1/edid_override
/sys/kernel/debug/dri/0/eDP-1/edid_override
/sys/devices/pci0000:00/0000:00:02.0/drm/card0/card0-HDMI-A-1/edid
/sys/devices/pci0000:00/0000:00:02.0/drm/card0/card0-VGA-1/edid
/sys/devices/pci0000:00/0000:00:02.0/drm/card0/card0-eDP-1/edid
/sys/module/drm_kms_helper/parameters/edid_firmware
/sys/module/drm/parameters/edid_firmware
/sys/module/drm/parameters/edid_fixup

cp /sys/devices/pci0000:00/0000:00:02.0/drm/card0/card0-HDMI-A-1/edid ~/edid.txt
#include <stdio.h>
#include <string.h>
#include <stdint.h>

int main()
{
    FILE *fp;
    char ch[1];
    int i=0, j=0;

    fp = fopen("eee.txt", "r");
    for (i=0; i<16; i++)
        printf("   %2X", i);
    printf("\n");

    i=0, j=0;
    for(;fread(ch, sizeof(ch), 1, fp);)
    {
        if (j==0)
            printf("0");
        if (j%16==0)
            printf("%1x ", j);
        printf("0x%2.2x ", (uint8_t)ch[0]);
        i++; j++;
        if(i==16)
        {
            printf("\n");
            i=0;
        }
    }
    fclose(fp);
    return 0;
}



輸出:
    0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
00 0x00 0xff 0xff 0xff 0xff 0xff 0xff 0x00 0x10 0xac 0x79 0xa0 0x4c 0x31 0x37 0x32
10 0x24 0x16 0x01 0x03 0x80 0x34 0x20 0x78 0xea 0xee 0x95 0xa3 0x54 0x4c 0x99 0x26
20 0x0f 0x50 0x54 0xa1 0x08 0x00 0x81 0x40 0x81 0x80 0xa9 0x40 0xb3 0x00 0xd1 0xc0
30 0x01 0x01 0x01 0x01 0x01 0x01 0x28 0x3c 0x80 0xa0 0x70 0xb0 0x23 0x40 0x30 0x20
40 0x36 0x00 0x06 0x44 0x21 0x00 0x00 0x1a 0x00 0x00 0x00 0xff 0x00 0x59 0x52 0x34
50 0x38 0x56 0x32 0x39 0x38 0x32 0x37 0x31 0x4c 0x0a 0x00 0x00 0x00 0xfc 0x00 0x44
60 0x45 0x4c 0x4c 0x20 0x55 0x32 0x34 0x31 0x32 0x4d 0x0a 0x20 0x00 0x00 0x00 0xfd
70 0x00 0x32 0x3d 0x1e 0x53 0x11 0x00 0x0a 0x20 0x20 0x20 0x20 0x20 0x20 0x01 0x65
80 0x02 0x03 0x1b 0x61 0x23 0x09 0x07 0x07 0x83 0x01 0x00 0x00 0x67 0x03 0x0c 0x00
90 0x20 0x00 0x80 0x2d 0x43 0x90 0x84 0x02 0xe2 0x00 0x0f 0x8c 0x0a 0xd0 0x8a 0x20
a0 0xe0 0x2d 0x10 0x10 0x3e 0x96 0x00 0xa0 0x5a 0x00 0x00 0x00 0x00 0x00 0x00 0x00
b0 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
c0 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
d0 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
e0 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
f0 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x29


可以再把輸出放到此網站分析, Here

GStreamer(Gst) - play wav file

環境: apq8009
gst-launch-1.0
gst-launch-1.0 filesrc location=a.wav ! wavparse ! audioconvert ! autoaudiosink

copy if from gst_HelloWorld and modify it
#include <gst/gst.h>
#include <glib.h>


static gboolean bus_call (GstBus *bus,
                          GstMessage *msg,
                          gpointer data)
{
    GMainLoop *loop = (GMainLoop *) data;

    switch (GST_MESSAGE_TYPE (msg))
    {

        case GST_MESSAGE_EOS:
            g_print ("End of stream\n");
            g_main_loop_quit (loop);
            break;

        case GST_MESSAGE_ERROR:
        {
            gchar  *debug;
            GError *error;

            gst_message_parse_error (msg, &error, &debug);
            g_free (debug);

            g_printerr ("Error: %s\n", error->message);
            g_error_free (error);

            g_main_loop_quit (loop);
            break;
        }
        default:
            break;
    }

    return TRUE;
}


static void on_pad_added (GstElement *element,
                          GstPad     *pad,
                          gpointer    data)
{
    GstPad *sinkpad;
    GstElement *decoder = (GstElement *) data;

    /* We can now link this pad with the vorbis-decoder sink pad */
    g_print ("Dynamic pad created, linking demuxer/decoder\n");

    sinkpad = gst_element_get_static_pad (decoder, "sink");

    gst_pad_link (pad, sinkpad);

    gst_object_unref (sinkpad);
}


int main (int argc, char *argv[])
{
    GMainLoop *loop;

    GstElement *pipeline, *source, *decoder, *conv, *sink;
    GstBus *bus;
    guint bus_watch_id;

    /* Initialisation */
    gst_init (&argc, &argv);

    loop = g_main_loop_new (NULL, FALSE);


    /* Check input arguments */
    if (argc != 2)
    {
        g_printerr ("Usage: %s <Ogg/Vorbis filename>\n", argv[0]);
        return -1;
    }

    /* Create gstreamer elements */
    pipeline = gst_pipeline_new ("audio-player");
    source   = gst_element_factory_make ("filesrc",       "file-source");
    decoder  = gst_element_factory_make ("wavparse", "wav-decoder");
    conv     = gst_element_factory_make ("audioconvert",  "converter");
    sink     = gst_element_factory_make ("autoaudiosink", "audio-output");

    if (!pipeline || !source || !decoder || !conv || !sink)
    {
        g_printerr ("One element could not be created. Exiting.\n");
        return -1;
    }

    g_object_set (G_OBJECT (source), "location", argv[1], NULL);

    bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
    bus_watch_id = gst_bus_add_watch (bus, bus_call, loop);
    gst_object_unref (bus);

    gst_bin_add_many (GST_BIN (pipeline),
                      source, decoder, conv, sink, NULL);

    gst_element_link_many (source, decoder, conv, sink, NULL);
    g_signal_connect (source, "pad-added", G_CALLBACK (on_pad_added), decoder);


    g_print ("Now playing: %s\n", argv[1]);
    gst_element_set_state (pipeline, GST_STATE_PLAYING);


    g_print ("Running...\n");
    g_main_loop_run (loop);


    g_print ("Returned, stopping playback\n");
    gst_element_set_state (pipeline, GST_STATE_NULL);

    g_print ("Deleting pipeline\n");
    gst_object_unref (GST_OBJECT (pipeline));
    g_source_remove (bus_watch_id);
    g_main_loop_unref (loop);

    return 0;
}


Compile:
gcc -Wall helloworld.c -o helloworld $(pkg-config --cflags --libs gstreamer-1.0)


Makefile
CC=gcc
CFLAGS = -MMD
CFLAGS += `pkg-config --cflags --libs gstreamer-1.0`
CFLAGS += -lrt -lpthread

SRCS=$(shell ls *.c)
OBJS = $(patsubst %.c, %.o, $(SRCS))

#Output
OUT_DIR = build
OUT_OBJS = $(addprefix $(OUT_DIR)/, $(OBJS))
DEPS = $(patsubst %.o, %.d, $(OUT_OBJS))

TARGET = y_gst_server

$(OUT_DIR)/$(TARGET): $(OUT_OBJS)
        $(CC) -o $@ $^ $(CFLAGS)

$(OUT_DIR)/%.o:%.c
        mkdir -p $(OUT_DIR)
        $(CC) -c $< -o $@ $(CFLAGS)

clean:
        -rm -rf $(OUT_DIR) $(TARGET) $(OBJS)
ref:
1. gst_HelloWorld(basic-tutorial-1.c)
2. gst_Seeking_example(basic-tutorial-4.c)
3. gst_plugin

2021年2月22日 星期一

bluethoothctl with C

Server Mode (Playback from external BT source)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main()
{
    int pfds[2];
    int status;
    pid_t pid;

    if ( pipe(pfds) == -1 )
    {
        perror("pipe error\n");
        exit(1);
    }

    pid = fork();
    if ( pid == 0 ) //child, run the bluetoothctl command
    {
        close(STDIN_FILENO);
        dup2( pfds[0], STDIN_FILENO );
        close( pfds[1] );
        execl("/usr/bin/bluetoothctl", "bluetoothctl", (char*) NULL);
        exit(0);

    }
    else //father, send the command to bluetoothctl
    {
        close(STDOUT_FILENO);
        dup2( pfds[1], STDOUT_FILENO );
        write(STDOUT_FILENO, "power on\n", strlen("power off\n"));
        sleep(1);
        write(STDOUT_FILENO, "agent on\n", strlen("agent on\n"));
        write(STDOUT_FILENO, "default-agent\n", strlen("default-agent\n"));
        write(STDOUT_FILENO, "pairable on\n", strlen("pairable on\n"));
        write(STDOUT_FILENO, "pair A8:87:B3:1E:D9:66\n", strlen("pair A8:87:B3:1E:D9:66\n"));
        write(STDOUT_FILENO, "trust A8:87:B3:1E:D9:66\n", strlen("trust A8:87:B3:1E:D9:66\n"));
        write(STDOUT_FILENO, "connect A8:87:B3:1E:D9:66\n", strlen("connect A8:87:B3:1E:D9:66\n"));
        sleep(2);
        write(STDOUT_FILENO, "exit\n", strlen("exit\n"));
        write(STDOUT_FILENO, "connect A8:87:B3:1E:D9:66\n", strlen("connect A8:87:B3:1E:D9:66\n"));
        close( pfds[0] );
        waitpid((pid_t)pid, &status, 0);
        exit(0);
    }
}
ref:Bluetooth A2DP



無法啟動 power on
[bluetooth]# power on
Failed to set power on: org.bluez.Error.Blocked

查找原因
$ sudo systemctl status bluetooth.service
● bluetooth.service - Bluetooth service
   Loaded: loaded (/lib/systemd/system/bluetooth.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2021-02-22 17:08:08 CST; 1min 55s ago
     Docs: man:bluetoothd(8)
 Main PID: 4723 (bluetoothd)
   Status: "Running"
    Tasks: 1 (limit: 4915)
   CGroup: /system.slice/bluetooth.service
           └─4723 /usr/lib/bluetooth/bluetoothd

 二  22 17:08:08 hello-W230ST systemd[1]: Starting Bluetooth service...
 二  22 17:08:08 hello-W230ST bluetoothd[4723]: Bluetooth daemon 5.48
 二  22 17:08:08 hello-W230ST systemd[1]: Started Bluetooth service.
 二  22 17:08:08 hello-W230ST bluetoothd[4723]: Starting SDP server
 二  22 17:08:08 hello-W230ST bluetoothd[4723]: Bluetooth management interface 1.14 initialized
 二  22 17:08:08 hello-W230ST bluetoothd[4723]: Failed to set mode: Blocked through rfkill (0x12)
 二  22 17:08:08 hello-W230ST bluetoothd[4723]: Endpoint registered: sender=:1.91 path=/MediaEndpoint/A2DPSource
 二  22 17:08:08 hello-W230ST bluetoothd[4723]: Endpoint registered: sender=:1.91 path=/MediaEndpoint/A2DPSink
 二  22 17:09:55 hello-W230ST bluetoothd[4723]: Failed to set mode: Blocked through rfkill (0x12)

$ sudo systemctl restart bluetooth.service  <-沒用

$ sudo rfkill list
0: hci0: Bluetooth
        Soft blocked: yes <- 被block住了@@?
        Hard blocked: no
1: phy0: Wireless LAN
        Soft blocked: no
        Hard blocked: no


解決
$ sudo rfkill unblock bluetooth


$ sudo rfkill list
0: hci0: Bluetooth
        Soft blocked: no
        Hard blocked: no
1: phy0: Wireless LAN
        Soft blocked: no
        Hard blocked: no



ref:
1. Cannot unblock soft-blocked bluetooth

2020年8月20日 星期四

字串搜尋比較

run.sh
#!/bin/bash

str="Aug 20 10:34:45 cs2=home_ubuntu cs2_1234 Aug 20 10:34:45 cs2_1234 cs2=home_ubuntu12345"

ii=0
while true
do
    fstr=$(echo $str | awk -F" " '{print $argv0}' argv0=$ii)
    if [ -z "$fstr" ];
    then
        break
    fi  

    if [ ${fstr:0:4} = "cs2=" ];
    then
        echo $fstr
    fi  
    ii=$((ii+1))
    #echo "ii="$ii
done
$ time ./run.sh

cs2=home_ubuntu
cs2=home_ubuntu12345

real	0m0.033s
user	0m0.031s
sys	    0m0.011s
ref: how-do-i-use-shell-variables-in-an-awk-script

run.py
#!/bin/python3
import os
  
  def test():
  
      str="Aug 20 10:34:45 cs2=home_ubuntu cs2_1234 Aug 20 10:34:45 cs2_1234 cs2=home_ubuntu12345"
  
      fstr = str.split(" ")
  
      for i in fstr: 
          if "cs2=" in i:
              print(i)
  
  if __name__=='__main__':
       test()
$ time python3 ./run.py

cs2=home_ubuntu
cs2=home_ubuntu12345

real	0m0.027s
user	0m0.023s
sys 	0m0.004s

run.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    char buf[128]="Aug 20 10:34:45 cs2=home_ubuntu cs2_1234 Aug 20 10:34:45 cs2_1234 cs2=home_ubuntu12345";
    char *target="cs2=";
    char *tmp;
    char *pch, *delim=" ";
    
    pch = strtok(buf,delim);
    for(; pch != NULL; ) 
    {
        tmp=strstr(pch, target);
        if(tmp != NULL)
        {
            printf("%s\n", tmp);
        }
        pch = strtok (NULL, delim);
    }
    return 0;
}
$ time ./run
cs2=home_ubuntu
cs2=home_ubuntu12345

real	0m0.001s
user	0m0.001s
sys	0m0.000s

2020年7月8日 星期三

ADC-read battery

kernel有留ioctl來讀資料
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/fcntl.h>
#include <unistd.h>
#include <signal.h>

//#define DEBUG_ENV
#ifdef DEBUG_ENV
#define fprintfs(fmt,args...) fprintf(stdout, fmt ,##args)
#define fprintfe(fmt,args...) fprintf(stderr, fmt ,##args)
#define DEBUGMSG __FILE__, __LINE__, __FUNCTION__
#else
#define fprintfs(fmt,args...)
#define fprintfe(fmt,args...)
#endif

#define SARADC_IOC_MAGIC 'a'
#define MS_SAR_INIT _IO(SARADC_IOC_MAGIC, 0)
#define MS_SAR_SET_CHANNEL_READ_VALUE _IO(SARADC_IOC_MAGIC, 1)

int STOP_FLAG=0;
typedef struct
{
    int channel_value;
    int adc_value;
}READ_ADC_t;

int read_saradc (char *argv[], int fd, int *val)
{
    READ_ADC_t radc;
    //sscanf(argv[1], "%d", &radc.channel_value);
    sscanf("3", "%d", &radc.channel_value); //PAD_SAR_GPIO
    if (fd < 0)
    {
        fprintf(stderr, "/dev/saradc");
        return 0; 
    }
    if (ioctl(fd, MS_SAR_SET_CHANNEL_READ_VALUE, &radc)< 0)
    {
        fprintf(stderr, "ioctl failed\n");
        return 0;
    }
    fprintfs("radc_channel=%d\n", radc.channel_value);
    fprintfs("radc_adc_value=%d\n", radc.adc_value);
    *val=radc.adc_value;
    return 1;
}

void sigroutine(int dunno)
{
    switch(dunno){
        case SIGINT:
            fprintfs("ctrl-c signal\n");
            STOP_FLAG=1;
        break;
        case SIGTERM:
            fprintfs("terminal signal\n");
            STOP_FLAG=1;
        break;
        case SIGQUIT:
            fprintfs("quit signal\n");
            STOP_FLAG=1;
        break;
        default:
            fprintfs("Unknow signal\n");
    }
}

unsigned char bat_percent(int val)
{
    int i=0, j=0;
    int bat[16]={644, 628, 616,
                 600, 583, 570, 552, 
                 530, 522, 500, 492, 
                 476, 461, 0};
   
    for(j=0; j<(int)(sizeof(bat)/sizeof(bat[0])); j++)
    {
        if (bat[j] == 0)
            break;
    } 

    for (i=0; i<j; i++)
    {
        if (val >= bat[i])
        {
            break;
        }
    }
    if ( 10-i == -1)
        return 5;
    if ( 10-i == -2 || 10-i == -3)
        return 0;

    return (10-i)*10;
}

void min_max(int *val, int *minval)
{
    static int min=0;
    static int max=0;

    if (min == 0 && max == 0)
    { 
        min=*val;
        *minval=*val;
        max=*val;
    }

    if (*val < min)
    {
        min=*val;
        *minval=min;
    }
    if (*val > max)
        max=*val;
    fprintfs("min=%d, minval=%d, max=%d\n", min, *minval, max);
    return;
}

int main(int argc, char *argv[])
{
    int adc_val=0, get_min_val=0;
    int fd=0;
    int i=0, j=0;
    unsigned char ret=0;
    if(!(fd = open("/dev/saradc", O_RDONLY|O_NONBLOCK)))
        return 0;
    signal(SIGINT , sigroutine);
    signal(SIGQUIT, sigroutine);
    for(i=0;i<10 && !STOP_FLAG;i++)
    {
        read_saradc(argv, fd, &adc_val);
        min_max(&adc_val, &get_min_val);
        for(j=0; j<10; j++)
            usleep(1000*5); //5ms
    }
    ret=bat_percent(get_min_val);
    printf("bat=%d%%\n", ret);
    close(fd);
    return 1;
}

2020年3月28日 星期六

aplay -L

Copy it form alsa.c
#include <alsa/asoundlib.h>


static void pcm_list(snd_pcm_stream_t stream)
{
    void **hints, **n;
    char *name, *descr, *descr1, *io;
    const char *filter;
    if (snd_device_name_hint(-1, "pcm", &hints) < 0)
        return;
    n = hints;
    filter = stream == SND_PCM_STREAM_CAPTURE ? "Input" : "Output";
    while (*n != NULL) {
        name = snd_device_name_get_hint(*n, "NAME");
        descr = snd_device_name_get_hint(*n, "DESC");
        io = snd_device_name_get_hint(*n, "IOID");
        if (io != NULL && strcmp(io, filter) != 0)
            goto __end;
        printf("%s\n", name);
        if ((descr1 = descr) != NULL) {
            printf("    ");
            while (*descr1) {
                if (*descr1 == '\n')
                    printf("\n    ");
                else
                    putchar(*descr1);
                descr1++;
            }
            putchar('\n');
         }
       __end:
         if (name != NULL)
             free(name);
         if (descr != NULL)
             free(descr);
         if (io != NULL)
            free(io);
         n++;
    }
    snd_device_name_free_hint(hints);
}

void main (void)
{
    printf("-------capture-------\n");
    pcm_list(SND_PCM_STREAM_CAPTURE);
    printf("\n");
    printf("\n");
    printf("-------playback-------\n");
    pcm_list(SND_PCM_STREAM_PLAYBACK);
    return;
}
Copy it form alsa.c ref:
Linux Sound Programming

2020年2月15日 星期六

Alsa Audio Capture - RMS

ref : Introduction to Sound Programming with ALSA
Simple Sound Recording
/*

This example reads from the default PCM device
and writes to standard output for 5 seconds of data.

*/

/* Use the newer ALSA API */
#define ALSA_PCM_NEW_HW_PARAMS_API

#include <alsa/asoundlib.h>
#include <math.h>
#include <unistd.h>

//#define DEVICE "hw:1,0"
#define DEVICE "default"
/
#define CH_2 1
//#define CH_4 1

float rmsValue(signed char arr[], int n)
  {
      float square = 0.0;
      float mean = 0.0, root = 0.0, db= 0.0;
      int i;

      // Calculate square.
      for (i = 0; i < n; i++)
      {
          //printf("arr[%d]=%d, pow=%f\n", i, arr[i], pow(arr[i], 2));
          square += pow(arr[i], 2); 
      }
      //printf("n=%d, square=%f\n", n, square);
  
      // Calculate Mean.
      mean = (square / (float)(n));
  
      // Calculate Root.
      root = sqrt(mean);

      return root;
  }

//for ARMv7
signed char complement (signed char *a)
{
     if((*a>>7))
     {
         *a=*a&0xEF;
         *a = ~(*a) + 1;
         *a = *a * (-1); //for ARMv7
     }
     else
     {
         *a=*a & 0xEF;
     }
  return *a;
}


int main() 
{
  long loops;
  int rc;
  int size;
  snd_pcm_t *handle;
  snd_pcm_hw_params_t *params;
  unsigned int val;
  int dir;
  snd_pcm_uframes_t frames;
  signed char *buffer;
  signed char *channelbuf;
  int i=0, j=0, k=0, m=0, n=0;
#if CH_2
  int channels=2;
  float root[2]={0}, aroot[2]={0};
#endif
#if CH_4
  int channels=4;
  float root[4]={0}, aroot[4]={0};
#endif
  int rate = 16000;
  signed char tmp=0;

  /* Open PCM device for recording (capture). */
  rc = snd_pcm_open(&handle, DEVICE,
                    SND_PCM_STREAM_CAPTURE, 0);
  //can use "dsnoop_test", "pulghw", or others to replace "default"
  if (rc < 0) {
    fprintf(stderr,
            "unable to open pcm device: %s\n",
            snd_strerror(rc));
    exit(1);
  }

  /* Allocate a hardware parameters object. */
  snd_pcm_hw_params_alloca(&params);

  /* Fill it in with default values. */
  snd_pcm_hw_params_any(handle, params);

  /* Set the desired hardware parameters. */

  /* Interleaved mode */
  snd_pcm_hw_params_set_access(handle, params,
                      SND_PCM_ACCESS_RW_INTERLEAVED);
  /* Signed 16-bit little-endian format */
  snd_pcm_hw_params_set_format(handle, params,
                              SND_PCM_FORMAT_S16_LE);

  /* Two channels (stereo) */
  snd_pcm_hw_params_set_channels(handle, params, channels);

  val = rate;
  snd_pcm_hw_params_set_rate_near(handle, params,
                                  &val, &dir);

  /* Set period size to 32 frames. */
#if CH_2
  frames = 32;
#endif
#if CH_4
  frames = 32 * 2;
#endif
  snd_pcm_hw_params_set_period_size_near(handle,
                              params, &frames, &dir);
#if 1
  /* Write the parameters to the driver */
  rc = snd_pcm_hw_params(handle, params);
  if (rc < 0) {
    fprintf(stderr,
            "unable to set hw parameters: %s\n",
            snd_strerror(rc));
    exit(1);
  }

  /* Use a buffer large enough to hold one period */
  snd_pcm_hw_params_get_period_size(params,
                                      &frames, &dir);
#if CH_2
  size = frames * 4; /* 2 bytes/sample, 2 channels */
#endif
#if CH_4
  size = frames * 4 * 2; /* 2 bytes/sample, 2 channels */
#endif
  buffer = (signed char *) malloc(sizeof(signed char)*size);

  /* We want to loop for 5 seconds */
  snd_pcm_hw_params_get_period_time(params,
                                         &val, &dir);
    loops = 5000000 / val;
    printf("loops=%ld, val=%d, frames=%ld, size=%d\n", loops, val, frames, size);
    channelbuf = (signed char *) malloc(sizeof(signed char)*size);
  
    while (loops > 0) 
    {
      loops--;
      //memset(buffer, '0', sizeof(signed char)*size);
      for(m=0; m<size; m++)
          buffer[m]=0;
      rc = snd_pcm_readi(handle, buffer, frames);
      if (rc == -EPIPE) {
        /* EPIPE means overrun */
        fprintf(stderr, "overrun occurred\n");
        snd_pcm_prepare(handle);
        break;
      } else if (rc < 0) {
        fprintf(stderr,
                "error from read: %s\n",
                snd_strerror(rc));
      } else if (rc != (int)frames) {
        fprintf(stderr, "short read, read %d frames\n", rc);
      }
  #if 0  //for recording
      rc = write(1, buffer, size);
      if (rc != size)
        fprintf(stderr, "short write: wrote %d bytes\n", rc);
    } //while
  #else

      for(j=0; j<channels; ++j)
      {
          for (i=j, k=0; i <rc ; i += channels, ++k)
          {

             memset(channelbuf, '0', sizeof(signed char)*size);
             for(m=0; m<size; m++)
                  channelbuf[m]=0;
             tmp=complement(buffer+(i+j)); //for ARMv7
#if 0
             printf("k=%3d,tmp=%4d;  ",k , tmp);
             if ( k%channels==0)
                 printf("\n");
#else
             channelbuf[k]=tmp;
             //printf("ch=%d, chbuf[%d]=%3d;  ", j, k, channelbuf[k]);
             //if ( k%channels==0)
             //    printf("\n");
#endif
          }
          root[j]=rmsValue(channelbuf, k+1);
#if 0
          printf("root[%d]=%f  ",j, root[j]);
          if ( j%channels==1)
              printf("\n");
#endif
          aroot[j] += root[j];
          //printf("aroot[%i]=%f\n", j, aroot[j]);
      }
    } //while
#if 1
    for(j=0; j<channels; j++)
        fprintf(stderr, "aroot[%i]=%f\n", j, aroot[j]);
    for(j=0; j<channels; j++)
    {
        root[j] = 10 * log10(aroot[j]);
        fprintf(stderr, "root[%i]=%f\n", j, root[j]);
    }
#endif
  #endif
  
    snd_pcm_drain(handle);
    snd_pcm_close(handle);
    free(buffer);
    free(channelbuf);
  #endif
    return 0;
}


Compile: gcc rec.c -o rec -lasound -lm

ref:
1.通过pcm音频数据计算分贝
2.Some typical Sound Pressure and Sound Pressure Levels
3.db-rms
4.Alsa Audio Capture by c language

2019年10月29日 星期二

123

123

2019年9月14日 星期六

操作gpio - mmap and gpiohandle_request, gpiochip

gpio.h
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sched.h>
#include <sys/mman.h>
#include <errno.h>
#include <linux/ioctl.h>
#include <linux/types.h>

#define MMIO_SUCCESS 0
#define MMIO_ERROR_DEVMEM -1
#define MMIO_ERROR_MMAP -2

#define PAD_TOP_BK_ADDR     (0x00000B00)
#define TOP_GPIO_OUT_OFFSET (0x0000006A)
#define TOP_GPIO_IN_OFFSET  (0x00000019)
#define PAD_TOP_BK_ADDR     (0x00000B00)
#define TOP_GPIO_OUT_OFFSET (0x0000006A)
#define TOP_GPIO_IN_OFFSET  (0x00000019)
#define GPIO_OUT_REG_ADDR   (0x1F000000+(PAD_TOP_BK_ADDR<<1)+(TOP_GPIO_OUT_OFFSET<<2))
#define GPIO_IN_REG_ADDR    (0x1F000000+(PAD_TOP_BK_ADDR<<1)+(TOP_GPIO_IN_OFFSET <<2))

#define BASE 0x1F001000

#define GPIO_NUM_RANGE_MIN 84

/* Linerequest flags */
#define GPIOHANDLE_REQUEST_INPUT        (1UL << 0)
#define GPIOHANDLE_REQUEST_OUTPUT       (1UL << 1)
#define GPIOHANDLE_REQUEST_ACTIVE_LOW   (1UL << 2)
#define GPIOHANDLE_REQUEST_OPEN_DRAIN   (1UL << 3)
#define GPIOHANDLE_REQUEST_OPEN_SOURCE  (1UL << 4)


#define GPIO_GET_CHIPINFO_IOCTL   _IOR(0xB4,  0x01, struct gpiochip_info)
#define GPIO_GET_LINEINFO_IOCTL   _IOWR(0xB4, 0x02, struct gpioline_info)
#define GPIO_GET_LINEHANDLE_IOCTL _IOWR(0xB4, 0x03, struct gpiohandle_request)
#define GPIO_GET_LINEEVENT_IOCTL  _IOWR(0xB4, 0x04, struct gpioevent_request)



#define GPIOHANDLES_MAX 64
struct gpiohandle_request {
        __u32 lineoffsets[GPIOHANDLES_MAX];
        __u32 flags;
        __u8 default_values[GPIOHANDLES_MAX];
        char consumer_label[32];
        __u32 lines;
        int fd;
};


#ifdef DEBUG_ENV
#define fprintff(fmt,args...) fprintf(fmt ,##args)
#define DEBINFO __FILE__, __LINE__, __FUNCTION__
#else
#define fprintff(fmt,args...)
#endif

int  s500_mmio_init(void);
int  s500_mmio_set_output(int gpio_number, char *device_name);
int  s500_mmio_set_input(int gpio_number, char *device_name);
void s500_mmio_set_high(int gpio_number);
void s500_mmio_set_low(int gpio_number);
int  s500_mmio_read_input(int gpio_number);

void set_max_priority(void);
void set_default_priority(void);

gpio.c
#include "gpio.h"

volatile unsigned char *s500_mmio_gpio_out = NULL;
volatile unsigned char *s500_mmio_gpio_in = NULL;
off_t page_base;
off_t page_offset_in, page_offset_out;

int s500_mmio_init(void) {
  if (s500_mmio_gpio_in == NULL && s500_mmio_gpio_out == NULL) 
  {
    size_t pagesize = sysconf(_SC_PAGE_SIZE);
    int fd = open("/dev/mem", O_RDWR | O_SYNC);
    if (fd == -1) {
      // Error opening /dev/mem.  Probably not running as root.
      return MMIO_ERROR_DEVMEM;
    }
    // Map GPIO memory to location in process space.
    page_base = (GPIO_IN_REG_ADDR / pagesize) * pagesize;
    page_offset_in = GPIO_IN_REG_ADDR - page_base;
    fprintff(stdout, "page_offset_in=0x%X, page_offset_out=0x%x\n", page_offset_in, page_offset_out); 
    s500_mmio_gpio_in = mmap(NULL,  page_offset_in+1, PROT_READ | PROT_WRITE, MAP_SHARED, fd, page_base);

    page_base = (GPIO_OUT_REG_ADDR / pagesize) * pagesize;
    page_offset_out = GPIO_OUT_REG_ADDR - page_base;
    s500_mmio_gpio_out = mmap(NULL, page_offset_out+1, PROT_READ | PROT_WRITE, MAP_SHARED, fd, page_base);
    close(fd);
    if (s500_mmio_gpio_in  == MAP_FAILED || s500_mmio_gpio_out == MAP_FAILED) 
    {
      // Don't save the result if the memory mapping failed.
      s500_mmio_gpio_in  = NULL;
      s500_mmio_gpio_out = NULL;
      return MMIO_ERROR_MMAP;
    }
  }
  return MMIO_SUCCESS;
}

int s500_mmio_set_input(int gpio_number, char *device_name) 
{
    int fd=0;  
    int ret=0;
    char *chrdev_name;
    struct gpiohandle_request req;
    ret = asprintf(&chrdev_name, "/dev/%s", device_name);
    if (ret < 0) 
    {
        fprintf(stderr, "can't open /dev/%s", device_name);
        return -ENOMEM;
    }
    fd = open(chrdev_name, 0);
    if (fd == -1) 
    {
        ret = -errno;
        fprintf(stderr, "Failed to open %s\n", chrdev_name);
        goto exit_close_error;
    }

    req.lineoffsets[0] = gpio_number;
    req.flags = GPIOHANDLE_REQUEST_INPUT;
    req.lines = 1;
    ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
    if (ret == -1) 
    {
        ret = -errno;
        fprintf(stderr, "Failed to issue GET LINEHANDLE IOCTL (%d)\n",ret);
        goto exit_close_error;
    }
exit_close_error:
    if (close(fd) == -1)
        perror("Failed to close GPIO character device file");
    free(chrdev_name);
    return ret;
}

int s500_mmio_set_output(int gpio_number, char *device_name)
{
    int fd=0;  
    int ret=0;
    char *chrdev_name;
    struct gpiohandle_request req;
    ret = asprintf(&chrdev_name, "/dev/%s", device_name);
    if (ret < 0) 
    {
        fprintf(stderr, "can't open /dev/%s", device_name);
        return -ENOMEM;
    }
    fd = open(chrdev_name, 0);
    if (fd == -1) 
    {
        ret = -errno;
        fprintf(stderr, "Failed to open %s\n", chrdev_name);
        goto exit_close_error;
    }

    req.lineoffsets[0] = gpio_number;
    req.flags = GPIOHANDLE_REQUEST_OUTPUT;
    req.lines = 1;
    ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
    if (ret == -1) 
    {
      ret = -errno;
      fprintf(stderr, "Failed to issue GET LINEHANDLE IOCTL (%d)\n",ret);
        goto exit_close_error;
    }
exit_close_error:
    if (close(fd) == -1)
        perror("Failed to close GPIO character device file");
    free(chrdev_name);
    return ret;
}

int s500_mmio_read_input(int gpio_number) {
  return  (*(s500_mmio_gpio_in+page_offset_in) & (1 << (gpio_number - GPIO_NUM_RANGE_MIN )) ? 1 : 0);
}

void s500_mmio_set_high(int gpio_number)
{
    *(s500_mmio_gpio_out+page_offset_out) |= (1 << (gpio_number-GPIO_NUM_RANGE_MIN));
}
void s500_mmio_set_low(int gpio_number)
{
    *(s500_mmio_gpio_out+page_offset_out) &= (1 << (gpio_number-GPIO_NUM_RANGE_MIN));
}

void set_max_priority(void) {
  struct sched_param sched;
  memset(&sched, 0, sizeof(sched));
  // Use FIFO scheduler with highest priority for the lowest chance of the kernel context switching.
  sched.sched_priority = sched_get_priority_max(SCHED_FIFO);
  sched_setscheduler(0, SCHED_FIFO, &sched);
}

void set_default_priority(void) {
  struct sched_param sched;
  memset(&sched, 0, sizeof(sched));
  // Go back to default scheduler with default 0 priority.
  sched.sched_priority = 0;
  sched_setscheduler(0, SCHED_OTHER, &sched);
}

main.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "gpio.h"

int main (int argc, char **argv)
{
    if (argc < 2)
    {
        printf("ex: ./main 88");
        return;
    }

    int gpio_num=atoi(argv[1]);
    int ret=0;
    printf("num=%d\n", gpio_num);

    if (s500_mmio_init() < 0)
        printf("error open mem!n");

    set_max_priority();
    ret=s500_mmio_set_input(gpio_num, "gpiochip0");
    for(;;)
    {
        ret=s500_mmio_read_input(gpio_num);
        usleep(500*1000);
        fprintf(stdout, "\rret=%d", ret);
        fflush(stdout);
    }
    set_default_priority();
}

2018年12月28日 星期五

tinyalsa

  • Tiny library
    Source code and Download
    or
    (沒裝過)
    sudo apt-add-repository ppa:taylorcholberton/tinyalsa
    sudo apt-get update
    sudo apt-get install tinyalsa
    sudo apt-get install libtinyalsa-dev
  • Sample code - ics-mr1
    tinyplay.c
    tinycap.c

2018年9月10日 星期一

top 指定 program, cpu loading

script
top -p `pgrep -d, -f program1`, `pgrep -d, -f program2`


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>

#define DEBUG 0
#define CPU_CORE 2
#define STR_ROW 16
#define STR_LEN 64
#define CSV_FORMAT

typedef struct target
{
    char **cpu;
    char **name;
}target_t;

int STOP_FLAG;

void sigroutine(int dunno)
{
    switch(dunno){
        case SIGINT:
            printf("ctrl-c signal\n");
            STOP_FLAG=1;
        break;
        case SIGTERM:
            printf("terminal signal\n");
            STOP_FLAG=1;
        break;
        case SIGQUIT:
            printf("quit signal\n");
            STOP_FLAG=1;
        break;
        default:
            printf("Unknow signal\n");
    }
}

char **getMem()
{
    int i=0, j=0;
    char **ptr = (char **)malloc(sizeof(char*) * STR_ROW);
    for (i = 0; i <STR_ROW; i++)
        ptr[i] = (char *)malloc(sizeof(char *) * STR_LEN);

    for (i = 0; i <STR_ROW; i++)
        for(j=0; j< STR_LEN; j++)
            ptr[i][j]=0;
    return ptr;
}

int get_count(const char *cmd)
{
    FILE *pp=NULL;
    char buf[32];
    int count=0;
    pp=popen(cmd, "r");
    while (fgets(buf, 255, pp) != NULL)
    {
        //printf("buf=%s", buf);
    }
    sscanf(buf, "%d", &count);
    printf("cound=%d\n", count-1);
    pclose(pp);
    return count-1;
}


int ttop (const char *cmd, char **val)
{
    int i=0,j=0;
    FILE *pp=NULL;
    char buf[32];

    for (i=0; i<STR_ROW; i++)
    {
        for(j=0; j<STR_LEN; j++)
        {
            val[i][j]=0;
        }
    }

    i=0;j=0;
    pp=popen(cmd, "r");
    while (fgets(buf, 255, pp) != NULL)
    {
#if DEBUG
        printf("buf=%s", buf);
#endif
        strncpy(val[i], buf, strlen(buf)-1);
        i++;
    }
    pclose(pp);
    return 0;
}


int do_str (target_t *aim, char **top_str)
{
    int i=0;

    for(i=0; i<STR_ROW; i++)
    {
        if(top_str[i] == NULL)
            break;
        sscanf(top_str[i], "%s %s", aim->cpu[i], aim->name[i]);
    }
#if DEBUG
    for(i=0; i<STR_ROW; i++)
    {
        if(top_str[i] == NULL)
            break;
        printf("cpu_loading=%s, name=%s\n", aim->cpu[i], aim->name[i]);
    }
#endif
    return 0;
}

void analysis (target_t *aim, int count, char *argv[])
{
    int i=0, j=0, k=0;
    //double *total_cpu=(double *)malloc(sizeof(double)*(count-1));
    double cpu[STR_ROW];
    double pcpu=0.0; //signal process cpu loading
    double tcpu=0.0; //total process cpu loading, ex: (A+B)/cpu_core

    for(i=0; i<STR_ROW; i++)
    {
        if((aim->cpu[i] != NULL) && (aim->name[i] != NULL))
        {
            cpu[i]=strtod(aim->cpu[i],NULL);
        }       
    }
    for(j=1; j<count; j++)
    {
#if DEBUG
        printf("aim_name[%d]=%s\n", j, argv[j]);
#endif
        pcpu=0.0;
        for(i=0; i<STR_ROW; i++)
        {
            if (strcmp(aim->name[i], argv[j]) == 0)   
            {
                pcpu+=cpu[i];
                k=i; //for cmd_name
#if DEBUG
                printf("k=%d, cpu_loading=%s, cmd_name=%s\n", i, aim->cpu[i], aim->name[i]);
#endif
            }
        }    
        tcpu+=pcpu;
#ifdef CSV_FORMAT
        if(!strcmp("", aim->name[k]))
            printf("didn't find target name\n");
        else
            printf("%.2lf, %s, ", pcpu, aim->name[k]);
#else
        printf("sum_cpu=%.2lf, name=%s ", pcpu, aim->name[k]);
#endif
        //total_cpu[j-1]=sum_cpu;
    }
#ifdef CSV_FORMAT
    if(strcmp("", aim->name[k]))
        printf("%.2lf, cpu\n", tcpu/CPU_CORE);
#else
    printf("cpu=%.2lf\n", tcpu/CPU_CORE);
#endif
    return;
}

void print_useage(void)
{
    printf("\nPlease enter the target name:\n");
    printf("Btw, 1, The limit is three process names\n");
    printf("     2, the output value takes about 10 seconds\n");
    printf("ex: ./get_top process_name process_name\n");
}

int init (int argc, char *argv[])
{
    if(argc < 2)
    {
        print_useage();
        return 1;    
    }
    if((strcmp(argv[0], "-h")==0) || (strcmp(argv[0], "--help")==0))
    {
        print_useage();
        return 1;    
    }
    return 0;
}

/*
 * "top -n 3 -d 5", the output value takes about 10 seconds
 * (d * (n-1))=5*2=10
 * -n : Number-of-iterations
 *      use 2 because: When you first run it, it has no previous sample to compare to, so these initial values are the percentages since boot.
 * -d : delay-time
 */ 
char *ccmd(int argc, char *argv[], const char *opt, int count)
{
    int i=0;
    char *cmd, *tmp1, *tmp2;
    char *str;
    cmd =(char *)malloc(sizeof(char)*STR_LEN*2);
    tmp1=(char *)malloc(sizeof(char)*STR_LEN*2);
    tmp2=(char *)malloc(sizeof(char)*STR_LEN*2);

    if(!strcmp("top", opt))
        str="top -n 3 -d 5 | grep ";
    else
        str="ps -ef | grep ";

    memset(tmp1, 0, sizeof(char)*STR_LEN*2);
    memset(tmp2, 0, sizeof(char)*STR_LEN*2);

    strcpy(cmd, str);
    int ret=0;
    for(i=0; i<argc-1; i++)
    {
        if( strlen(tmp1) > STR_LEN*2-1)
        {    
            printf("too many target_name\n");
            return NULL; 
        }
        ret=snprintf(tmp1, STR_LEN*2-1, "-e \'%s\' ", argv[i+1]);
        strcat(tmp2, tmp1);
    }

#if DEBUG
    printf("%s, tmp1=%s, tmp2=%s\n", __FUNCTION__, tmp1, tmp2);
#endif

    if(!strcmp("top", opt))
        str="| tail -n %d |";
    else
        str="| grep -v grep | wc -l";

    sprintf(tmp1, str, count);
    strcat(cmd, tmp2);
    strcat(cmd, tmp1);

    if(!strcmp("top", opt))
        str=" awk \'{print $10, $13}\'";
    else
        str="";

    strcat(cmd, str);
#if DEBUG
    printf("%s, cmd=%s\n", __FUNCTION__, cmd);
#endif
    free(tmp1);
    free(tmp2);

    return cmd;
}

int main(int argc, char *argv[])
{
    int i=0;
    int count=0;
    char **top_str = getMem();
    char *cmd;
    target_t aim;

    if(init(argc, argv))
        return 1;

    signal(SIGINT , sigroutine);
    signal(SIGQUIT, sigroutine);
    STOP_FLAG=0;
    
    aim.cpu=getMem(); 
    aim.name=getMem(); 

    cmd=ccmd(argc, argv, "ps", count);
    if (cmd == NULL)
        return 1;
    count=get_count(cmd);
#if 1
    if (count > STR_ROW || count < 0)
    {
        printf("Process more or less, the range is 0~%d\n", STR_LEN);
        return 1;
    }

    cmd=ccmd(argc, argv, "top", count);
    while(!STOP_FLAG)
    {
        ttop(cmd, top_str);
        do_str(&aim, top_str);
        analysis(&aim, argc, argv);
    }

    //free
    for (i = 0; i <STR_ROW; i++)
    {
        free(top_str[i]);
        free(aim.cpu[i]);
        free(aim.name[i]);
    }
#endif
    free(top_str);
    free(aim.cpu);
    free(aim.name);
    free(cmd);

    return 0;
}

copy form Here
ps command (should not use):
top command (should use):
ref:
1. stackoverflow
/*nice*/