New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) guowenxue <guowenxue@gmail.com> |
| | | * All rights reserved. |
| | | * |
| | | * Filename: cp_atcmd.c |
| | | * Description: This is file is used to send AT command to GPRS module. |
| | | * |
| | | * Version: 1.0.0(02/02/2012~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "02/02/2012 10:28:44 AM" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #include "cp_atcmd.h" |
| | | #include "cp_string.h" |
| | | #include "cp_logger.h" |
| | | #include "cp_time.h" |
| | | |
| | | #ifndef ATCMD_REPLY_LEN |
| | | #define ATCMD_REPLY_LEN 512 |
| | | #endif |
| | | |
| | | /* |
| | | * Description: Send the AT command which modem will only reply "OK" or "ERROR", |
| | | * such as AT,ATE0,AT+CNMP=2 etc. |
| | | * |
| | | * Return Value: 0: OK -X: ERROR |
| | | */ |
| | | int send_atcmd_check_ok(comport_t *comport, char *atcmd, unsigned long timeout) |
| | | { |
| | | int retval; |
| | | retval = send_atcmd(comport, atcmd, "OK\r\n", "ERROR\r\n", timeout, NULL, 0); |
| | | |
| | | return 0==retval ? 0 : -2; |
| | | } |
| | | |
| | | /* |
| | | * Description: Send the AT command which will reply the value directly in a |
| | | * single line, such as AT+CGMM, AT+CGSN |
| | | * |
| | | * Output Value: Buf: The AT command query value |
| | | * Return Value: 0: OK -X: ERROR |
| | | * |
| | | */ |
| | | int send_atcmd_check_value(comport_t *comport, char *atcmd, unsigned long timeout, char *buf, int buf_len) |
| | | { |
| | | int i = 0; |
| | | int retval=0; |
| | | char tmp[ATCMD_REPLY_LEN]; |
| | | char *start; |
| | | |
| | | if(NULL==buf) |
| | | { |
| | | log_err("Function call arguments error!\n"); |
| | | return -1; |
| | | } |
| | | |
| | | memset(tmp, 0, sizeof(tmp)); |
| | | retval = send_atcmd(comport, atcmd, "OK\r\n", "ERROR\r\n", timeout, tmp, sizeof(tmp)); |
| | | if( 0 != retval) |
| | | { |
| | | return -2; /* AT command can not get reply */ |
| | | } |
| | | |
| | | /* Parser the receive string to get the expect value*/ |
| | | if(NULL != (start=strchr(tmp, '\n')) ) |
| | | { |
| | | start ++; /* Skip '\n' character */ |
| | | while(*start!='\r' && i<buf_len-1) |
| | | { |
| | | buf[i++] = *start; |
| | | start ++; |
| | | } |
| | | } |
| | | buf[i] = '\0'; /* End of the string */ |
| | | |
| | | return ('\0'==buf[0] ? -3 : 0); |
| | | } |
| | | |
| | | /* |
| | | * Description: Send the AT command which will reply the value with a prefix "+CMD: " |
| | | * single line, such as AT+CGMR AT+CPIN? AT+CNMP? AT+CSQ |
| | | * |
| | | * Output Value: Buf: The AT command query value by remove "+XXX:" prefix |
| | | * Return Value: 0: OK -X: ERROR |
| | | * |
| | | */ |
| | | int send_atcmd_check_request(comport_t *comport, char *atcmd, unsigned long timeout, char *buf, int buf_len) |
| | | { |
| | | int retval; |
| | | int i = 0; |
| | | char tmp[ATCMD_REPLY_LEN]; |
| | | char *ptr = NULL; |
| | | |
| | | if(NULL==buf) |
| | | { |
| | | log_err("%s() call arguments error!\n", __FUNCTION__); |
| | | return -1; |
| | | } |
| | | |
| | | memset(tmp, 0, sizeof(tmp)); |
| | | retval = send_atcmd(comport, atcmd, "OK\r\n", "ERROR\r\n", timeout, tmp, sizeof(tmp)); |
| | | if( 0 != retval) |
| | | { |
| | | return -2; |
| | | } |
| | | |
| | | /* Parser the receive string to get the expect value*/ |
| | | if(NULL != (ptr=strchr (tmp, ':')) ) |
| | | { |
| | | ptr += 2; /* Skip the ':' and SPACE character */ |
| | | while(*ptr!='\r' && i<buf_len-1) |
| | | { |
| | | buf[i++] = *ptr; |
| | | ptr ++; |
| | | } |
| | | } |
| | | buf[i] = '\0'; /* End of the string */ |
| | | |
| | | return ('\0'==buf[0] ? -3 : 0); |
| | | } |
| | | |
| | | |
| | | /* |
| | | * Description: Send ATE0 command to the GSM module to check GSM module ready or not |
| | | * Return Value: 0: Success !0:Failure |
| | | */ |
| | | int atcmd_check_at_ready(comport_t *comport) |
| | | { |
| | | int retval; |
| | | retval=send_atcmd_check_ok(comport, "ATE0\r", 500); |
| | | if(retval) |
| | | { |
| | | log_err("ATE0 check AT command ready [FAILED]\n"); |
| | | } |
| | | else |
| | | log_nrml("ATE0 check AT command ready [OK]\n"); |
| | | |
| | | return retval; |
| | | } |
| | | |
| | | /* |
| | | * Description: Send AT+CPIN? command to the GSM module to check SIM card exist or not |
| | | * Return Value: 0: Success !0:Failure |
| | | */ |
| | | int atcmd_check_sim_valid(comport_t *comport) |
| | | { |
| | | int retval = 0; |
| | | char recv_buf[ATCMD_REPLY_LEN]; |
| | | |
| | | retval = send_atcmd_check_request(comport, "AT+CPIN?\r", 800, recv_buf, sizeof(recv_buf)); |
| | | if(0x00 != retval) |
| | | { |
| | | retval = 1; |
| | | log_warn("AT+CPIN? Check SIM Validation: [FAILED]\n"); |
| | | return retval; |
| | | } |
| | | |
| | | if(strstr(recv_buf, "READY")) |
| | | { |
| | | log_nrml("AT+CPIN? Check SIM Validataion: [OK]\n"); |
| | | return 0; |
| | | } |
| | | else |
| | | return -1; |
| | | } |
| | | |
| | | /* Send AT+CSQ command to check GPRS signal*/ |
| | | int atcmd_check_gprs_signal(comport_t *comport) |
| | | { |
| | | char recv_buf[ATCMD_REPLY_LEN]; |
| | | int retval; |
| | | int signal = -1; |
| | | |
| | | memset(recv_buf, 0, sizeof(recv_buf)); |
| | | retval = send_atcmd_check_request(comport, "AT+CSQ\r", 3000, recv_buf, sizeof(recv_buf)); |
| | | if( 0 != retval) |
| | | { |
| | | log_err("AT+CSQ Check Signal Strength: [FAILED]\n"); |
| | | return retval; |
| | | } |
| | | |
| | | split_string_to_value(recv_buf, "%d,%d", &signal, NULL); |
| | | |
| | | log_nrml("AT+CSQ Check Signal Strength: [%d]\n", signal); |
| | | |
| | | return signal; |
| | | } |
| | | |
| | | /* Send AT+CREG? command to check SIM card register status */ |
| | | int atcmd_check_gprs_register(comport_t *comport) |
| | | { |
| | | int retval, stat = -1; |
| | | char recv_buf[ATCMD_REPLY_LEN]; |
| | | |
| | | memset(recv_buf, 0, sizeof(recv_buf)); |
| | | retval = send_atcmd_check_request(comport, "AT+CREG?\r", 3000, recv_buf, sizeof(recv_buf)); |
| | | if( 0 != retval) |
| | | { |
| | | log_err("AT+CREG? Check SIM card Register: [FAILED]\n"); |
| | | return stat; |
| | | } |
| | | |
| | | split_string_to_value(recv_buf, "%d,%d", NULL, &stat); |
| | | log_nrml("AT+CREG? Check SIM Card Register: [%d]\n", stat); |
| | | |
| | | return stat; |
| | | } |
| | | |
| | | |
| | | int atcmd_check_gprs_carrier(comport_t *comport, char *carrier) |
| | | { |
| | | int retval; |
| | | char recv_buf[ATCMD_REPLY_LEN]; |
| | | |
| | | if(carrier == NULL) |
| | | { |
| | | return -1; |
| | | } |
| | | |
| | | retval = send_atcmd_check_request(comport, "AT+COPS?\r", 5000, recv_buf, sizeof(recv_buf)); |
| | | if(retval) |
| | | { |
| | | log_warn("AT+COPS? Check SIM Card Carrier: [FAILED]\n"); |
| | | return retval; |
| | | } |
| | | |
| | | split_string_to_value(recv_buf, "%d,%d,%s,%d", NULL, NULL, carrier, NULL); |
| | | del_char_from_string(carrier, '\"'); |
| | | |
| | | log_nrml("AT+COPS? Check SIM Card Carrier: [%s]\n", carrier); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | int atcmd_check_gprs_mcc_mnc(comport_t *comport, char *mcc_mnc) |
| | | { |
| | | int retval; |
| | | char recv_buf[ATCMD_REPLY_LEN]; |
| | | int status; |
| | | char mcc[5]; |
| | | char mnc[5]; |
| | | char *ptr = NULL; |
| | | |
| | | retval=send_atcmd_check_ok(comport, "AT+QENG=1\r", 1000); |
| | | if(retval) |
| | | { |
| | | log_err("Send AT command AT+QENG=1 failure\n"); |
| | | return retval; |
| | | } |
| | | |
| | | retval = send_atcmd(comport, "AT+QENG?\r", "OK\r\n", "ERROR\r\n", 5000, recv_buf, sizeof(recv_buf)); |
| | | if(retval) |
| | | { |
| | | log_err("AT+QENG? Check GPRS MCC and MNC failure\n"); |
| | | return retval; |
| | | } |
| | | |
| | | /* AT+QENG? respond value: |
| | | * +QENG: 1,0 |
| | | * +QENG: 0,460,00,7108,80c4,554,41,-95,18,50,0,10,x,x,x,x,x,x,x |
| | | */ |
| | | if(NULL != (ptr=strrchr (recv_buf, ':')) ) |
| | | { |
| | | split_string_to_value(ptr, "%d,%s,%s,%s", &status, mcc, mnc, NULL); |
| | | if(!status) |
| | | { |
| | | sprintf(mcc_mnc, "%s-%s", mcc, mnc); |
| | | log_nrml("AT+QGSMLOC=1 Check GPRS Location MCC-MNC: %s\n", mcc_mnc); |
| | | return 0; |
| | | } |
| | | } |
| | | |
| | | printf("ptr: %s\n", ptr); |
| | | |
| | | return -1; |
| | | } |
| | | |
| | | |
| | | int atcmd_check_gprs_location(comport_t *comport, gprs_location_t *loc) |
| | | { |
| | | int retval; |
| | | char recv_buf[ATCMD_REPLY_LEN]; |
| | | int status; |
| | | |
| | | retval=send_atcmd_check_ok(comport, "AT+QIFGCNT=0\r", 1000); |
| | | if(retval) |
| | | { |
| | | log_warn("Send AT command AT+QIFGCNT=0 failure\n"); |
| | | return retval; |
| | | } |
| | | |
| | | retval = send_atcmd_check_request(comport, "AT+QGSMLOC=1\r", 10000, recv_buf, sizeof(recv_buf)); |
| | | if(retval) |
| | | { |
| | | log_warn("AT+QGSMLOC=1 Check GPRS Location: [FAILED]\n"); |
| | | return retval; |
| | | } |
| | | |
| | | /* +QGSMLOC: 0,114.389210,30.500380,2013/01/16,14:03:12, it's GMT time */ |
| | | split_string_to_value(recv_buf, "%d,%s,%s,%s,%s", &status, loc->longitude, loc->latitude, loc->date, loc->time); |
| | | |
| | | if(status) /* Get LOC failure */ |
| | | { |
| | | memset(loc->longitude, 0, sizeof(loc->longitude)); |
| | | memset(loc->latitude, 0, sizeof(loc->latitude)); |
| | | memset(loc->date, 0, sizeof(loc->date)); |
| | | memset(loc->time, 0, sizeof(loc->time)); |
| | | log_warn("AT+QGSMLOC=1 Check GPRS Location failure: %s\n", recv_buf); |
| | | return -1; |
| | | } |
| | | |
| | | log_nrml("GPRS location result=%d latitude,longitude: [%s,%s]\n", status, loc->latitude, loc->longitude); |
| | | log_nrml("GPRS Date and time: %s,%s\n", loc->date, loc->time); |
| | | |
| | | return retval; |
| | | } |
| | | |
| | | |
| | | int atcmd_set_network_mode(comport_t *comport, int mode) |
| | | { |
| | | int retval; |
| | | char atcmd[64]={0}; |
| | | |
| | | sprintf (atcmd, "AT+CNMP=%d\r", mode); |
| | | if(0 != (retval=send_atcmd_check_ok(comport, atcmd, 3000)) ) |
| | | { |
| | | log_warn("AT+CNMP Set Network Mode as %d: [FAILED]\n", mode); |
| | | return retval; |
| | | } |
| | | log_nrml("AT+CNMP=%d Set Network Mode: [OK]\n", mode); |
| | | |
| | | /* AT+CNAOP=?: 0->Automatic, 1->GSM,WCDMA, 2->WCDMA,GSM */ |
| | | strncpy (atcmd, "AT+CNAOP=2\r", sizeof(atcmd)); |
| | | if(0 != (retval=send_atcmd_check_ok(comport, atcmd, 3000)) ) |
| | | { |
| | | log_warn("AT+CNAOP=2 Set Acquisitions order preference to WCDMA,GSM [FAILED]\n"); |
| | | return retval; |
| | | } |
| | | log_nrml("AT+CNAOP=2 Set Network Preference [OK]\n"); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | int atcmd_check_gprs_name(comport_t *comport, char *name) |
| | | { |
| | | int retval; |
| | | char recv_buf[ATCMD_REPLY_LEN]; |
| | | |
| | | if(name == NULL) |
| | | { |
| | | return -1; |
| | | } |
| | | |
| | | retval = send_atcmd_check_value(comport, "AT+CGMM\r", 5000, recv_buf, sizeof(recv_buf)); |
| | | if(retval) |
| | | { |
| | | log_warn("AT+CGMM Check GPRS Module Name: [FAILED]\n"); |
| | | return retval; |
| | | } |
| | | |
| | | strcpy(name, recv_buf); |
| | | |
| | | log_nrml("AT+CGMM Check GPRS Module Name: [%s]\n", name); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | int atcmd_check_gprs_version(comport_t *comport, char *version) |
| | | { |
| | | int retval; |
| | | char recv_buf[ATCMD_REPLY_LEN]; |
| | | |
| | | if(version == NULL) |
| | | { |
| | | return -1; |
| | | } |
| | | |
| | | retval = send_atcmd_check_request(comport, "AT+CGMR\r", 5000, recv_buf, sizeof(recv_buf)); |
| | | if(retval) |
| | | { |
| | | log_warn("AT+CGMR Check GPRS Module Version: [FAILED]\n"); |
| | | return retval; |
| | | } |
| | | |
| | | strcpy(version, recv_buf); |
| | | log_nrml("AT+CGMR Check GPRS Module Version: [%s]\n", version); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | int atcmd_check_gprs_iemi(comport_t *comport, char *iemi) |
| | | { |
| | | int retval; |
| | | char recv_buf[ATCMD_REPLY_LEN]; |
| | | |
| | | if(iemi == NULL) |
| | | { |
| | | return -1; |
| | | } |
| | | |
| | | retval = send_atcmd_check_value(comport, "AT+CGSN\r", 5000, recv_buf, sizeof(recv_buf)); |
| | | if(retval) |
| | | { |
| | | log_warn("AT+CGSN Check GPRS Module IEMI: [FAILED]\n"); |
| | | return retval; |
| | | } |
| | | |
| | | strcpy(iemi, recv_buf); |
| | | log_nrml("AT+CGSN Check GPRS Module IEMI: [%s]\n", iemi); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | int atcmd_check_gprs_network(comport_t *comport, int *network) |
| | | { |
| | | int retval; |
| | | char recv_buf[ATCMD_REPLY_LEN]; |
| | | |
| | | if(network == NULL) |
| | | { |
| | | return -1; |
| | | } |
| | | |
| | | retval = send_atcmd_check_request(comport, "AT+CNSMOD?\r", 5000, recv_buf, sizeof(recv_buf)); |
| | | if(retval) |
| | | { |
| | | log_warn("AT+CNSMOD Check Network Mode: [FAILED]\n"); |
| | | return retval; |
| | | } |
| | | |
| | | split_string_to_value(recv_buf, "%d,%d", NULL, network); |
| | | |
| | | log_nrml("AT+CNSMOD? Check Network Mode: [%d]\n", *network); |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | int atcmd_set_apn(comport_t *comport, char *apn) |
| | | { |
| | | char atcmd[64]={0}; |
| | | int retval; |
| | | |
| | | sprintf (atcmd, "AT+CGDCONT=1,\"IP\",\"%s\"\r", apn); |
| | | if(0 != (retval=send_atcmd_check_ok(comport, atcmd, 2000)) ) |
| | | { |
| | | log_err("AT+CGDCONT Set APN as \"%s\" [FAILED]\n", apn); |
| | | return retval; |
| | | } |
| | | |
| | | log_nrml("AT+CGDCONT Set APN as \"%s\" [OK]\n"); |
| | | return retval; |
| | | } |
| | | |
| | | |
| | | unsigned char at_match (char *p_pcStr, char *p_pcMatch) |
| | | { |
| | | char acBuf [256], |
| | | *pcStart = NULL, |
| | | *pcTab = NULL; |
| | | |
| | | pcStart = p_pcMatch; |
| | | |
| | | while (0 != pcStart) |
| | | { |
| | | memset (acBuf, 0x00, sizeof (acBuf)); |
| | | |
| | | pcTab = strchr (pcStart, 9); // Find for TAB |
| | | if (0 != pcTab) |
| | | { |
| | | if (pcTab != pcStart) |
| | | { |
| | | strncpy (acBuf, pcStart, pcTab - pcStart); |
| | | } |
| | | pcStart = (0 != *(++pcTab)) ? pcTab : 0; |
| | | } |
| | | else |
| | | { |
| | | strcpy (acBuf, pcStart); |
| | | pcStart = NULL; |
| | | } |
| | | if (0 != acBuf [0] && 0 != strstr (p_pcStr, acBuf)) |
| | | { |
| | | return 0x00; |
| | | } |
| | | } |
| | | return 0x01; |
| | | } |
| | | |
| | | |
| | | /*========================================================================================================= |
| | | * Parameter Description: |
| | | * comport_t *comport: The GPRS module data port(/dev/ttyS2); |
| | | * char *atCmd: The AT command which will be sent to GPRS module |
| | | * char *expect: The EXPECT reply string by GPRS module for the AT command, such as "OK" |
| | | * char *error: The ERROR reply string by GPRS module for the AT command, such as "ERROR" |
| | | * unsigned long timeout: Read from data port timeout value |
| | | * char reply: The AT command reply output buffer |
| | | * int reply_len: The AT command reply output buffer length |
| | | * |
| | | * Return Value: |
| | | * int retval: 0->command send OK and "expect" string mached. !0->failure |
| | | * char *content: The AT command reply string by modem. |
| | | * |
| | | *=========================================================================================================*/ |
| | | |
| | | int send_atcmd(comport_t *comport, char *atCmd, char *expect, char *error, |
| | | unsigned long timeout, char *reply, int reply_len) |
| | | { |
| | | int retval = -1; |
| | | unsigned long delay = 200; |
| | | unsigned long gap = 300; |
| | | unsigned long ulStartTime; |
| | | |
| | | int iCmdLen = 0, |
| | | iRecvLen = 0, |
| | | iRecvSize = 0, |
| | | iSize = 0; |
| | | |
| | | |
| | | char acRecv[1024]; |
| | | char *pcRecvPtr = NULL; |
| | | |
| | | if(comport->is_connted != 0x01) /* Comport not opened */ |
| | | { |
| | | log_dbg("Comport not opened.\n"); |
| | | return -1; |
| | | } |
| | | |
| | | #if 0 |
| | | /*========================================= |
| | | *= Pause a while before send AT command = |
| | | *=========================================*/ |
| | | if(0 != delay) |
| | | { |
| | | ulStartTime = time_now(); |
| | | while (time_elapsed(ulStartTime) < delay) |
| | | { |
| | | micro_second_sleep(1); |
| | | } |
| | | } |
| | | #endif |
| | | |
| | | /*==================== |
| | | *= Throw Rubbish = |
| | | *====================*/ |
| | | ulStartTime = time_now(); |
| | | memset(&acRecv, 0, sizeof(acRecv)); |
| | | |
| | | while (time_elapsed(ulStartTime) < delay) |
| | | { |
| | | iSize = comport_recv(comport, acRecv, 1, 50); |
| | | if(iSize <= 0) |
| | | { |
| | | break; |
| | | } |
| | | micro_second_sleep(1); |
| | | } |
| | | |
| | | /*==================== |
| | | *= Send AT command = |
| | | *====================*/ |
| | | |
| | | iCmdLen = strlen(atCmd); |
| | | retval = comport_send (comport, atCmd, iCmdLen); |
| | | if (0 != retval) |
| | | { |
| | | retval = 0x02; |
| | | goto CleanUp; |
| | | } |
| | | |
| | | /*=================================================== |
| | | *= Pause a while before read command response. |
| | | *===================================================*/ |
| | | if(0 != gap) |
| | | { |
| | | ulStartTime = time_now(); |
| | | while (time_elapsed(ulStartTime) < gap) |
| | | { |
| | | micro_second_sleep(1); |
| | | } |
| | | } |
| | | |
| | | memset (acRecv, 0, sizeof (acRecv)); |
| | | pcRecvPtr = acRecv; |
| | | iRecvLen = 0; |
| | | iRecvSize = sizeof (acRecv); |
| | | |
| | | retval = -1; |
| | | ulStartTime = time_now(); |
| | | |
| | | while (time_elapsed(ulStartTime) < timeout) |
| | | { |
| | | if ( iRecvLen < (iRecvSize-1) ) |
| | | { |
| | | iSize = comport_recv (comport, pcRecvPtr, 1, 50); |
| | | if (iSize >0) |
| | | { |
| | | iRecvLen += iSize; |
| | | pcRecvPtr += iSize; |
| | | acRecv [iRecvSize-1] = 0; |
| | | |
| | | /*======================================== |
| | | * Match the received with expect String = |
| | | *========================================*/ |
| | | if(NULL != expect) |
| | | { |
| | | if (0x00 == at_match(acRecv, expect)) |
| | | { |
| | | retval = 0; |
| | | goto CleanUp; |
| | | } |
| | | } |
| | | |
| | | /*======================================== |
| | | * Match the received with error String = |
| | | *========================================*/ |
| | | if(NULL != error) |
| | | { |
| | | if (0x00 == at_match(acRecv, error)) |
| | | { |
| | | retval = -3; |
| | | goto CleanUp; |
| | | } |
| | | } |
| | | } /*End of (iSize > 0) */ |
| | | } /* End of (iRecvLen < (iRecvSize-1)) */ |
| | | |
| | | micro_second_sleep(1); |
| | | } /* End of time_elapsed(ulStartTime) < timeout */ |
| | | |
| | | |
| | | if(NULL==expect) |
| | | retval = 0x00; |
| | | else |
| | | retval = -4; |
| | | |
| | | CleanUp: |
| | | //printf("acRecv:\n %s\n", acRecv); |
| | | if( NULL != reply) |
| | | { |
| | | strncpy(reply, acRecv, reply_len); |
| | | } |
| | | |
| | | #if 1 /* Log the command result to log system */ |
| | | { |
| | | char log[512] = {0}; |
| | | snprintf(log, 512, "Send AT command: \"%s\" get reply \"%s\"", atCmd, acRecv); |
| | | int i = 0; |
| | | for (i=0; i<512; i++) |
| | | { |
| | | if('\r'==log[i] || '\n'==log[i] || '\t'==log[i]) |
| | | { |
| | | log[i]=' '; |
| | | } |
| | | else if (0 == log[i]) |
| | | { |
| | | break; |
| | | } |
| | | } |
| | | log_info("%s\n", log); |
| | | } |
| | | #endif |
| | | |
| | | return retval; |
| | | } |
New file |
| | |
| | | /******************************************************************************** |
| | | * Copyright: (C) guowenxue <guowenxue@gmail.com> |
| | | * All rights reserved. |
| | | * |
| | | * Filename: atcmd.h |
| | | * Description: This is the head file for atcmd.c |
| | | * |
| | | * Version: 1.0.0(05/15/2012~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "05/15/2012 05:31:10 PM" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #ifndef __CP_ATCMD_H |
| | | #define __CP_ATCMD_H |
| | | |
| | | #include "cp_comport.h" |
| | | |
| | | /* AT+CPSI command return important result*/ |
| | | typedef struct gprs_location_s |
| | | { |
| | | char longitude[15]; |
| | | char latitude[15]; |
| | | char date[15]; |
| | | char time[15]; |
| | | char mcc_mnc[16];/* Mobile Country Code, China is 460 */ |
| | | } gprs_location_t; |
| | | |
| | | typedef struct reginfo_s |
| | | { |
| | | int type; /* SIM card register type: REG_HOMEWORK,REG_SEARCHING... */ |
| | | int signal; /* GPRS signal */ |
| | | char carrier[64];/* Network operator */ |
| | | gprs_location_t loc; /* Location */ |
| | | } reginfo_t; |
| | | |
| | | |
| | | typedef struct _hwinfo_s |
| | | { |
| | | char model[64]; /* AT+CGMM check GPRS module model */ |
| | | char mrev[64]; /* AT+CGMR check GPRS module revision */ |
| | | char iemi[64]; /* AT+CGSN check GPRS module IEMI(International Mobile station Equipment Identity) number */ |
| | | } hwinfo_t; |
| | | |
| | | extern int send_atcmd(comport_t *comport, char *atCmd, char *expect, char *error, |
| | | unsigned long timeout, char *reply, int reply_len); |
| | | |
| | | extern int send_atcmd_check_ok(comport_t *comport, char *atcmd, unsigned long timeout); |
| | | extern int send_atcmd_check_value(comport_t *comport, char *atcmd, unsigned long timeout, char *buf, int buf_len); |
| | | extern int send_atcmd_check_request(comport_t *comport, char *atcmd, unsigned long timeout, char *buf, int buf_len); |
| | | |
| | | |
| | | extern int atcmd_check_at_ready(comport_t *comport); /* Send ATE0 command */ |
| | | extern int atcmd_check_sim_valid(comport_t *comport); /* Send AT+CPIN? command */ |
| | | extern int atcmd_check_gprs_signal(comport_t *comport); /* Send AT+CSQ command */ |
| | | extern int atcmd_check_gprs_register(comport_t *comport); |
| | | extern int atcmd_check_gprs_carrier(comport_t *comport, char *carrier); |
| | | extern int atcmd_check_gprs_name(comport_t *comport, char *name); |
| | | extern int atcmd_check_gprs_version(comport_t *comport, char *version); |
| | | extern int atcmd_check_gprs_iemi(comport_t *comport, char *iemi); |
| | | extern int atcmd_check_gprs_network(comport_t *comport, int *network); |
| | | extern int atcmd_check_gprs_location(comport_t *comport, gprs_location_t *location); |
| | | extern int atcmd_check_gprs_mcc_mnc(comport_t *comport, char *mcc_mnc); |
| | | |
| | | extern int atcmd_set_network_mode(comport_t *comport, int mode); |
| | | extern int atcmd_set_apn(comport_t *comport, char *apn); |
| | | |
| | | #endif /* _CP_ATCMD_H */ |
New file |
| | |
| | | /******************************************************************************** |
| | | * Copyright: (C) 2012 Guo Wenxue<guowenxue@gmail.com> |
| | | * All rights reserved. |
| | | * |
| | | * Filename: cp_common.h |
| | | * Description: This head file is for some common definition |
| | | * |
| | | * Version: 1.0.0(11/13/2012~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "11/13/2012 01:48:01 PM" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #ifndef __CP_COMMON_H |
| | | #define __CP_COMMON_H |
| | | |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | |
| | | #ifndef offsetof |
| | | #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) |
| | | #endif |
| | | |
| | | #define container_of(ptr, type, member) ({ \ |
| | | const typeof( ((type *)0)->member ) *__mptr = (ptr); \ |
| | | (type *)( (char *)__mptr - offsetof(type,member) );}) |
| | | |
| | | //#define MEM_LEAK_CHECK |
| | | |
| | | #if 0 |
| | | static inline void *_t_malloc(size_t size |
| | | #ifdef MEM_LEAK_CHECK |
| | | , const char *file, unsigned int line |
| | | #endif |
| | | ) |
| | | { |
| | | void *ptr; |
| | | |
| | | if ((ptr = malloc (size))) |
| | | memset (ptr, 0, size); |
| | | #ifdef MEM_LEAK_CHECK |
| | | printf ("MALLOC,0x%p @%s:%u\n", ptr, file, line); |
| | | #endif |
| | | return ptr; |
| | | } |
| | | |
| | | static inline void _t_free(void *ptr |
| | | #ifdef MEM_LEAK_CHECK |
| | | , const char *file, unsigned int line |
| | | #endif |
| | | ) |
| | | { |
| | | #ifdef MEM_LEAK_CHECK |
| | | printf ("FREE,0x%p @%s:%u\n", ptr, file, line); |
| | | #endif |
| | | free(ptr); |
| | | } |
| | | |
| | | #ifdef MEM_LEAK_CHECK |
| | | #define t_free(p) if(p){ _t_free(p, __FILE__, __LINE__); p=NULL; } |
| | | #define t_malloc(s) _t_malloc(s, __FILE__, __LINE__) |
| | | #else |
| | | #define t_free(p) if(p){ _t_free(p); p=NULL; } |
| | | #define t_malloc(s) _t_malloc(s) |
| | | #endif |
| | | |
| | | #endif |
| | | |
| | | #endif /* end of __CP_COMMON_H */ |
| | | |
New file |
| | |
| | | /* ******************************************************************************** |
| | | * Copyright: (C) 2012 Guo Wenxue <guowenxue@gmail.com> |
| | | * All rights reserved. |
| | | * |
| | | * Filename: cp_comport.c |
| | | * Description: It's the comport operate library. |
| | | * |
| | | * Version: 1.0.0(10/17/2011~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "10/17/2011 03:33:25 PM" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #include "cp_comport.h" |
| | | |
| | | /************************************************************************************** |
| | | * Description: Set the comport structure |
| | | * Input Args: dev_name: The comport device name path, such as '/dev/ttyS3' |
| | | * baudrate: The baudrate, such as 115200 |
| | | * settings: The databit,parity,stopbit,flowctrl settings, such as '8N1N' |
| | | * Output Args: NONE |
| | | * Return Value: The comport_t structure pointer. |
| | | *************************************************************************************/ |
| | | comport_t *comport_init(const char *dev_name, int baudrate, const char *settings) |
| | | { |
| | | comport_t *comport = NULL; |
| | | if (NULL == (comport = (comport_t *) malloc(sizeof(comport_t)))) |
| | | { |
| | | return NULL; |
| | | } |
| | | memset(comport, 0, sizeof(comport_t)); |
| | | comport->is_connted = 0; |
| | | comport->frag_size = 128; |
| | | |
| | | strncpy(comport->dev_name, dev_name, DEVNAME_LEN); |
| | | comport->baudrate = baudrate; |
| | | |
| | | set_settings(comport, settings); |
| | | #ifdef COMPORT_DEBUG |
| | | disp_settings(comport); |
| | | #endif |
| | | |
| | | return comport; |
| | | } |
| | | |
| | | #ifdef COMPORT_DEBUG |
| | | void disp_settings(comport_t * comport) |
| | | { |
| | | comport_print("Device:\t\t\t\"%s\"\n", comport->dev_name); |
| | | comport_print("Baudrate:\t\t%ld\n", comport->baudrate); |
| | | comport_print("DataBit:\t\t\'%d\'\n", comport->databit); |
| | | switch (comport->parity) |
| | | { |
| | | case 0: |
| | | comport_print("Parity:\t\t\t\'N\'\n"); |
| | | break; |
| | | case 1: |
| | | comport_print("Parity:\t\t\t\'O\'\n"); |
| | | break; |
| | | case 2: |
| | | comport_print("Parity:\t\t\t\'E\'\n"); |
| | | break; |
| | | case 3: |
| | | comport_print("Parity:\t\t\t\'S\'\n"); |
| | | break; |
| | | } |
| | | comport_print("StopBit:\t\t\'%ld\'\n", (long int)comport->stopbit); |
| | | switch (comport->flowctrl) |
| | | { |
| | | case 0: |
| | | comport_print("FlowCtrl:\t\t\'N\'\n"); |
| | | break; |
| | | case 1: |
| | | comport_print("FlowCtrl:\t\t\'S\'\n"); |
| | | break; |
| | | case 2: |
| | | comport_print("FlowCtrl:\t\t\'H\'\n"); |
| | | break; |
| | | case 3: |
| | | comport_print("FlowCtrl:\t\t\'B\'\n"); |
| | | break; |
| | | } |
| | | comport_print("\n"); |
| | | return; |
| | | } |
| | | #endif |
| | | |
| | | /************************************************************************************** |
| | | * Description: Set the comport databit,parity,stopbit,flowctrl |
| | | * Input Args: comport: the comport_t pointer |
| | | * settings: The databit/parity/stopbit/flowctrl settings as like "8N1N" |
| | | * Output Args: NONE |
| | | * Return Value: NONE |
| | | *************************************************************************************/ |
| | | void set_settings(comport_t * comport, const char *settings) |
| | | { |
| | | if(NULL==settings || NULL==comport) |
| | | return ; |
| | | |
| | | switch (settings[0]) /* data bit */ |
| | | { |
| | | case '7': |
| | | comport->databit = 7; |
| | | break; |
| | | case '8': |
| | | default: |
| | | comport->databit = 8; |
| | | break; |
| | | } |
| | | |
| | | switch (settings[1]) /* parity */ |
| | | { |
| | | case 'O': |
| | | case 'o': |
| | | comport->parity = 1; |
| | | break; |
| | | case 'E': |
| | | case 'e': |
| | | comport->parity = 2; |
| | | break; |
| | | case 'S': |
| | | case 's': |
| | | comport->parity = 3; |
| | | break; |
| | | case 'N': |
| | | case 'n': |
| | | default: |
| | | comport->parity = 0; |
| | | break; |
| | | } |
| | | |
| | | switch (settings[2]) /* stop bit */ |
| | | { |
| | | case '0': |
| | | comport->stopbit = 0; |
| | | break; |
| | | case '1': |
| | | default: |
| | | comport->stopbit = 1; |
| | | break; |
| | | } |
| | | |
| | | switch (settings[3]) /* flow control */ |
| | | { |
| | | case 'S': |
| | | case 's': |
| | | comport->flowctrl = 1; |
| | | break; |
| | | case 'H': |
| | | case 'h': |
| | | comport->flowctrl = 2; |
| | | break; |
| | | case 'B': |
| | | case 'b': |
| | | comport->flowctrl = 3; |
| | | break; |
| | | case 'N': |
| | | case 'n': |
| | | default: |
| | | comport->flowctrl = 0; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | void comport_close(comport_t * comport) |
| | | { |
| | | if (0 != comport->fd) |
| | | { |
| | | comport_print("Close device \"%s\"\n", comport->dev_name); |
| | | close(comport->fd); |
| | | } |
| | | comport->is_connted = 0x00; |
| | | comport->fd = -1; |
| | | } |
| | | |
| | | void comport_term(comport_t * comport) |
| | | { |
| | | if(NULL == comport) |
| | | return; |
| | | |
| | | if (0 != comport->fd) |
| | | { |
| | | comport_close(comport); |
| | | } |
| | | memset(comport, 0x00, sizeof(comport_t)); |
| | | free(comport); |
| | | comport = NULL; |
| | | |
| | | return; |
| | | } |
| | | |
| | | int comport_open(comport_t * comport) |
| | | { |
| | | int retval = -1; |
| | | struct termios old_cfg, new_cfg; |
| | | int old_flags; |
| | | long tmp; |
| | | |
| | | if(NULL==comport) |
| | | return -1; |
| | | |
| | | comport_close(comport); |
| | | |
| | | |
| | | /* Not a TTY device */ |
| | | if( !strstr(comport->dev_name, "tty")) |
| | | { |
| | | comport_print("Open Not tty device \"%s\"\n", comport->dev_name); |
| | | comport->fd = open(comport->dev_name, O_RDWR); |
| | | retval = comport->fd<0 ? -2 : comport->fd; |
| | | goto CleanUp; |
| | | } |
| | | |
| | | comport->fd = open(comport->dev_name, O_RDWR | O_NOCTTY | O_NONBLOCK); |
| | | if (comport->fd < 0) |
| | | { |
| | | retval = -3; |
| | | goto CleanUp; |
| | | } |
| | | comport_print("Open device \"%s\"\n", comport->dev_name); |
| | | |
| | | if ((-1 != (old_flags = fcntl(comport->fd, F_GETFL, 0))) |
| | | && (-1 != fcntl(comport->fd, F_SETFL, old_flags & ~O_NONBLOCK))) |
| | | { |
| | | // Flush input and output |
| | | if (-1 == tcflush(comport->fd, TCIOFLUSH)) |
| | | { |
| | | retval = -4; |
| | | goto CleanUp; |
| | | } |
| | | } |
| | | else // Failure |
| | | { |
| | | retval = -5; |
| | | goto CleanUp; |
| | | } |
| | | |
| | | if (0 != tcgetattr(comport->fd, &old_cfg)) |
| | | { |
| | | retval = -6; // Failed to get Com settings |
| | | goto CleanUp; |
| | | } |
| | | |
| | | memset(&new_cfg, 0, sizeof(new_cfg)); |
| | | |
| | | /*=====================================*/ |
| | | /* Configure comport */ |
| | | /*=====================================*/ |
| | | |
| | | new_cfg.c_cflag &= ~CSIZE; |
| | | new_cfg.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); |
| | | new_cfg.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); |
| | | new_cfg.c_oflag &= ~(OPOST); |
| | | |
| | | /* Set the data bit */ |
| | | switch (comport->databit) |
| | | { |
| | | case 0x07: |
| | | new_cfg.c_cflag |= CS7; |
| | | break; |
| | | case 0x06: |
| | | new_cfg.c_cflag |= CS6; |
| | | break; |
| | | case 0x05: |
| | | new_cfg.c_cflag |= CS5; |
| | | break; |
| | | default: |
| | | new_cfg.c_cflag |= CS8; |
| | | break; |
| | | } |
| | | |
| | | /* Set the parity */ |
| | | switch (comport->parity) |
| | | { |
| | | case 0x01: // Odd |
| | | new_cfg.c_cflag |= (PARENB | PARODD); |
| | | new_cfg.c_cflag |= (INPCK | ISTRIP); |
| | | break; |
| | | case 0x02: // Even |
| | | new_cfg.c_cflag |= PARENB; |
| | | new_cfg.c_cflag &= ~PARODD;; |
| | | new_cfg.c_cflag |= (INPCK | ISTRIP); |
| | | break; |
| | | case 0x03: |
| | | new_cfg.c_cflag &= ~PARENB; |
| | | new_cfg.c_cflag &= ~CSTOPB; |
| | | break; |
| | | default: |
| | | new_cfg.c_cflag &= ~PARENB; |
| | | } |
| | | |
| | | /* Set Stop bit */ |
| | | if (0x01 != comport->stopbit) |
| | | { |
| | | new_cfg.c_cflag |= CSTOPB; |
| | | } |
| | | else |
| | | { |
| | | new_cfg.c_cflag &= ~CSTOPB; |
| | | } |
| | | |
| | | /* Set flow control */ |
| | | switch (comport->flowctrl) |
| | | { |
| | | case 1: // Software control |
| | | case 3: |
| | | new_cfg.c_cflag &= ~(CRTSCTS); |
| | | new_cfg.c_iflag |= (IXON | IXOFF); |
| | | break; |
| | | case 2: // Hardware control |
| | | new_cfg.c_cflag |= CRTSCTS; // Also called CRTSCTS |
| | | new_cfg.c_iflag &= ~(IXON | IXOFF); |
| | | break; |
| | | default: // NONE |
| | | new_cfg.c_cflag &= ~(CRTSCTS); |
| | | new_cfg.c_iflag &= ~(IXON | IXOFF); |
| | | break; |
| | | } |
| | | |
| | | /* Set baudrate */ |
| | | switch (comport->baudrate) |
| | | { |
| | | case 115200: |
| | | tmp = B115200; |
| | | break; |
| | | case 57600: |
| | | tmp = B57600; |
| | | break; |
| | | case 38400: |
| | | tmp = B38400; |
| | | break; |
| | | case 19200: |
| | | tmp = B19200; |
| | | break; |
| | | case 9600: |
| | | tmp = B9600; |
| | | break; |
| | | case 4800: |
| | | tmp = B4800; |
| | | break; |
| | | case 2400: |
| | | tmp = B2400; |
| | | break; |
| | | case 1800: |
| | | tmp = B1800; |
| | | break; |
| | | case 1200: |
| | | tmp = B1200; |
| | | break; |
| | | case 600: |
| | | tmp = B600; |
| | | break; |
| | | case 300: |
| | | tmp = B300; |
| | | break; |
| | | case 200: |
| | | tmp = B200; |
| | | break; |
| | | case 150: |
| | | tmp = B150; |
| | | break; |
| | | case 134: |
| | | tmp = B134; |
| | | break; |
| | | case 110: |
| | | tmp = B110; |
| | | break; |
| | | case 75: |
| | | tmp = B75; |
| | | break; |
| | | case 50: |
| | | tmp = B50; |
| | | break; |
| | | default: |
| | | tmp = B115200; |
| | | } |
| | | cfsetispeed(&new_cfg, tmp); |
| | | cfsetispeed(&new_cfg, tmp); |
| | | |
| | | /* Set the Com port timeout settings */ |
| | | new_cfg.c_cc[VMIN] = 0; |
| | | new_cfg.c_cc[VTIME] = 0; |
| | | |
| | | tcflush(comport->fd, TCIFLUSH); |
| | | if (0 != tcsetattr(comport->fd, TCSANOW, &new_cfg)) |
| | | { |
| | | retval = -7; // Failed to set device com port settings |
| | | goto CleanUp; |
| | | } |
| | | |
| | | comport_print("Connected device \"%s\".\n", comport->dev_name); |
| | | comport->is_connted = 0x01; |
| | | retval = comport->fd; |
| | | |
| | | CleanUp: |
| | | comport_print("Open device \"%s\" %s.\n", comport->dev_name, retval>0 ? "successfully" : "failure"); |
| | | return retval; |
| | | } |
| | | |
| | | void nonblock() |
| | | { |
| | | struct termios ttystate; |
| | | |
| | | //get the terminal state |
| | | tcgetattr(STDIN_FILENO, &ttystate); |
| | | |
| | | //turn off canonical mode |
| | | ttystate.c_lflag &= ~ICANON; |
| | | //minimum of number input read. |
| | | ttystate.c_cc[VMIN] = 1; |
| | | |
| | | //set the terminal attributes. |
| | | tcsetattr(STDIN_FILENO, TCSANOW, &ttystate); |
| | | } |
| | | |
| | | int kbhit() |
| | | { |
| | | struct timeval tv; |
| | | fd_set fds; |
| | | tv.tv_sec = 0; |
| | | tv.tv_usec = 0; |
| | | FD_ZERO(&fds); |
| | | FD_SET(STDIN_FILENO, &fds); //STDIN_FILENO is 0 |
| | | select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv); |
| | | return FD_ISSET(STDIN_FILENO, &fds); |
| | | } |
| | | |
| | | int comport_recv(comport_t * comport, char *buf, int buf_size, unsigned long timeout) |
| | | { |
| | | int retval = 0; // Function return value |
| | | int iRet; |
| | | fd_set stReadFds, stExcpFds; |
| | | struct timeval stTime; |
| | | |
| | | if (NULL == buf || 0 >= buf_size) |
| | | { |
| | | comport_print("%s() usage error.\n", __FUNCTION__); |
| | | retval = -1; |
| | | goto CleanUp; |
| | | } |
| | | |
| | | if (0x01 != comport->is_connted) |
| | | { |
| | | comport_print("%s() comport not connected.\n", __FUNCTION__); |
| | | retval = -2; |
| | | goto CleanUp; |
| | | } |
| | | |
| | | //printf("bufsize=%d timeout=%lu\n", buf_size, timeout); |
| | | |
| | | FD_ZERO(&stReadFds); |
| | | FD_ZERO(&stExcpFds); |
| | | FD_SET(comport->fd, &stReadFds); |
| | | FD_SET(comport->fd, &stExcpFds); |
| | | |
| | | if (0xFFFFFFFF != timeout) |
| | | { |
| | | stTime.tv_sec = (time_t) (timeout / 1000); |
| | | stTime.tv_usec = (long)(1000 * (timeout % 1000)); |
| | | |
| | | iRet = select(comport->fd + 1, &stReadFds, 0, &stExcpFds, &stTime); |
| | | if (0 == iRet) |
| | | { |
| | | retval = 0; // No data in Com port buffer |
| | | goto CleanUp; |
| | | } |
| | | else if (0 < iRet) |
| | | { |
| | | if (0 != FD_ISSET(comport->fd, &stExcpFds)) |
| | | { |
| | | retval = -6; // Error during checking recv status |
| | | comport_print("Error checking recv status.\n"); |
| | | goto CleanUp; |
| | | } |
| | | |
| | | if (0 == FD_ISSET(comport->fd, &stReadFds)) |
| | | { |
| | | retval = 0; // No incoming data |
| | | comport_print("No incoming data.\n"); |
| | | goto CleanUp; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | if (EINTR == errno) |
| | | { |
| | | comport_print("catch interrupt signal.\n"); |
| | | retval = 0; // Interrupted signal catched |
| | | } |
| | | else |
| | | { |
| | | comport_print("Check recv status failure.\n"); |
| | | retval = -7; // Error during checking recv status |
| | | } |
| | | |
| | | goto CleanUp; |
| | | } |
| | | } |
| | | |
| | | usleep(10000); /* sleep for 10ms for data incoming */ |
| | | |
| | | // Get data from Com port |
| | | iRet = read(comport->fd, buf, buf_size); |
| | | if (0 > iRet) |
| | | { |
| | | if (EINTR == errno) |
| | | retval = 0; // Interrupted signal catched |
| | | else |
| | | retval = -3; // Failed to read Com port |
| | | |
| | | goto CleanUp; |
| | | } |
| | | |
| | | #if 0 |
| | | { |
| | | int i=0; |
| | | printf("Receive %d bytes data: \n", iRet); |
| | | for(i=0; i<iRet; i++) |
| | | { |
| | | printf("0x%02x ", buf[i]); |
| | | } |
| | | printf("\n"); |
| | | } |
| | | #endif |
| | | |
| | | retval = iRet; |
| | | |
| | | CleanUp: |
| | | return retval; |
| | | |
| | | } |
| | | |
| | | int comport_send(comport_t * comport, char *buf, int send_bytes) |
| | | { |
| | | char *ptr, *end; |
| | | int retval = 0; |
| | | int send = 0; |
| | | |
| | | if (NULL == buf || 0 >= send_bytes) |
| | | { |
| | | comport_print("%s() Usage error.\n", __FUNCTION__); |
| | | retval = -1; |
| | | goto CleanUp; |
| | | } |
| | | |
| | | if (0x01 != comport->is_connted) // Comport not opened ? |
| | | { |
| | | retval = -3; |
| | | comport_print("Serail not connected.\n"); |
| | | goto CleanUp; |
| | | } |
| | | |
| | | //printf("Send %s with %d bytes.\n", buf, send_bytes); |
| | | |
| | | // Large data, then slice them and send |
| | | if (comport->frag_size < send_bytes) |
| | | { |
| | | ptr = buf; |
| | | end = buf + send_bytes; |
| | | |
| | | do |
| | | { |
| | | // Large than frag_size |
| | | if (comport->frag_size < (end - ptr)) |
| | | { |
| | | send = write(comport->fd, ptr, comport->frag_size); |
| | | if (0 >= send || comport->frag_size != send) |
| | | { |
| | | retval = -4; |
| | | goto CleanUp; |
| | | } |
| | | ptr += comport->frag_size; |
| | | } |
| | | else // Less than frag_size, maybe last fragmention. |
| | | { |
| | | send = write(comport->fd, ptr, (end - ptr)); |
| | | if (0 >= send || (end - ptr) != send) |
| | | { |
| | | retval = -4; |
| | | goto CleanUp; |
| | | } |
| | | ptr += (end - ptr); |
| | | } |
| | | } |
| | | while (ptr < end); |
| | | } |
| | | else // The send data is not large than a fragmention. |
| | | { |
| | | send = write(comport->fd, buf, send_bytes); |
| | | if (0 >= send || send_bytes != send) |
| | | { |
| | | retval = -5; |
| | | goto CleanUp; |
| | | } |
| | | } |
| | | |
| | | CleanUp: |
| | | return retval; |
| | | } |
| | | |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2012 Guo Wenxue <guowenxue@gmail.com> |
| | | * All rights reserved. |
| | | * |
| | | * Filename: cp_comport.h |
| | | * Description: This head file is for the common TTY/Serial port operator library |
| | | * |
| | | * Version: 1.0.0(10/17/2011~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "10/17/2011 03:33:25 PM" |
| | | * |
| | | ********************************************************************************/ |
| | | #ifndef __CP_COMPORT_H |
| | | #define __CP_COMPORT_H |
| | | |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <unistd.h> |
| | | #include <string.h> |
| | | #include <getopt.h> |
| | | #include <fcntl.h> |
| | | #include <errno.h> |
| | | #include <termios.h> |
| | | #include <sys/stat.h> |
| | | #include <sys/wait.h> |
| | | #include <sys/types.h> |
| | | #include <sys/stat.h> |
| | | #include <sys/select.h> |
| | | |
| | | #define BUF_64 64 |
| | | |
| | | #ifndef DEVNAME_LEN |
| | | #define DEVNAME_LEN 64 |
| | | #endif |
| | | |
| | | //#define COMPORT_DEBUG |
| | | #ifdef COMPORT_DEBUG |
| | | #define comport_print(format,args...) printf(format, ##args) |
| | | #else |
| | | #define comport_print(format,args...) do{} while(0); |
| | | #endif |
| | | |
| | | //#define msleep(m) {struct timespec cSleep; cSleep.tv_sec = 0; cSleep.tv_nsec = m * 1000; nanosleep(&cSleep, 0);} |
| | | |
| | | typedef struct comport_s |
| | | { |
| | | unsigned char databit, parity, stopbit, flowctrl, is_connted; |
| | | char dev_name[DEVNAME_LEN]; |
| | | unsigned char used; /* This comport used or not now */ |
| | | int fd; |
| | | int frag_size; |
| | | long baudrate; |
| | | } comport_t; |
| | | |
| | | comport_t *comport_init(const char *dev_name, int baudrate, const char *settings); |
| | | void comport_close(comport_t * comport); |
| | | int comport_open(comport_t * comport); |
| | | void comport_term(comport_t * comport); |
| | | int comport_recv(comport_t * comport, char *buf, int buf_size, unsigned long timeout); |
| | | int comport_send(comport_t * comport, char *buf, int send_bytes); |
| | | |
| | | void set_settings(comport_t * comport, const char *settings); |
| | | void disp_settings(comport_t * comport); |
| | | void nonblock(); |
| | | int kbhit(); |
| | | |
| | | #endif |
New file |
| | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @file cp_dictionary.c |
| | | @author N. Devillard |
| | | @brief Implements a dictionary for string variables. |
| | | |
| | | This module implements a simple dictionary object, i.e. a list |
| | | of string/string associations. This object is useful to store e.g. |
| | | informations retrieved from a configuration file (ini files). |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | |
| | | /*--------------------------------------------------------------------------- |
| | | Includes |
| | | ---------------------------------------------------------------------------*/ |
| | | #include "cp_dictionary.h" |
| | | |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #include <unistd.h> |
| | | |
| | | /** Maximum value size for integers and doubles. */ |
| | | #define MAXVALSZ 1024 |
| | | |
| | | /** Minimal allocated number of entries in a dictionary */ |
| | | #define DICTMINSZ 128 |
| | | |
| | | /** Invalid key token */ |
| | | #define DICT_INVALID_KEY ((char*)-1) |
| | | |
| | | /*--------------------------------------------------------------------------- |
| | | Private functions |
| | | ---------------------------------------------------------------------------*/ |
| | | |
| | | /* Doubles the allocated size associated to a pointer */ |
| | | /* 'size' is the current allocated size. */ |
| | | static void * mem_double(void * ptr, int size) |
| | | { |
| | | void * newptr ; |
| | | |
| | | newptr = calloc(2*size, 1); |
| | | if (newptr==NULL) { |
| | | return NULL ; |
| | | } |
| | | memcpy(newptr, ptr, size); |
| | | free(ptr); |
| | | return newptr ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Duplicate a string |
| | | @param s String to duplicate |
| | | @return Pointer to a newly allocated string, to be freed with free() |
| | | |
| | | This is a replacement for strdup(). This implementation is provided |
| | | for systems that do not have it. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | static char * xstrdup(const char * s) |
| | | { |
| | | char * t ; |
| | | if (!s) |
| | | return NULL ; |
| | | t = (char*)malloc(strlen(s)+1) ; |
| | | if (t) { |
| | | strcpy(t,s); |
| | | } |
| | | return t ; |
| | | } |
| | | |
| | | /*--------------------------------------------------------------------------- |
| | | Function codes |
| | | ---------------------------------------------------------------------------*/ |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Compute the hash key for a string. |
| | | @param key Character string to use for key. |
| | | @return 1 unsigned int on at least 32 bits. |
| | | |
| | | This hash function has been taken from an Article in Dr Dobbs Journal. |
| | | This is normally a collision-free function, distributing keys evenly. |
| | | The key is stored anyway in the struct so that collision can be avoided |
| | | by comparing the key itself in last resort. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | unsigned dictionary_hash(const char * key) |
| | | { |
| | | int len ; |
| | | unsigned hash ; |
| | | int i ; |
| | | |
| | | len = strlen(key); |
| | | for (hash=0, i=0 ; i<len ; i++) { |
| | | hash += (unsigned)key[i] ; |
| | | hash += (hash<<10); |
| | | hash ^= (hash>>6) ; |
| | | } |
| | | hash += (hash <<3); |
| | | hash ^= (hash >>11); |
| | | hash += (hash <<15); |
| | | return hash ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Create a new dictionary object. |
| | | @param size Optional initial size of the dictionary. |
| | | @return 1 newly allocated dictionary objet. |
| | | |
| | | This function allocates a new dictionary object of given size and returns |
| | | it. If you do not know in advance (roughly) the number of entries in the |
| | | dictionary, give size=0. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | dictionary * dictionary_new(int size) |
| | | { |
| | | dictionary * d ; |
| | | |
| | | /* If no size was specified, allocate space for DICTMINSZ */ |
| | | if (size<DICTMINSZ) size=DICTMINSZ ; |
| | | |
| | | if (!(d = (dictionary *)calloc(1, sizeof(dictionary)))) { |
| | | return NULL; |
| | | } |
| | | d->size = size ; |
| | | d->val = (char **)calloc(size, sizeof(char*)); |
| | | d->key = (char **)calloc(size, sizeof(char*)); |
| | | d->hash = (unsigned int *)calloc(size, sizeof(unsigned)); |
| | | return d ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Delete a dictionary object |
| | | @param d dictionary object to deallocate. |
| | | @return void |
| | | |
| | | Deallocate a dictionary object and all memory associated to it. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void dictionary_del(dictionary * d) |
| | | { |
| | | int i ; |
| | | |
| | | if (d==NULL) return ; |
| | | for (i=0 ; i<d->size ; i++) { |
| | | if (d->key[i]!=NULL) |
| | | free(d->key[i]); |
| | | if (d->val[i]!=NULL) |
| | | free(d->val[i]); |
| | | } |
| | | free(d->val); |
| | | free(d->key); |
| | | free(d->hash); |
| | | free(d); |
| | | return ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get a value from a dictionary. |
| | | @param d dictionary object to search. |
| | | @param key Key to look for in the dictionary. |
| | | @param def Default value to return if key not found. |
| | | @return 1 pointer to internally allocated character string. |
| | | |
| | | This function locates a key in a dictionary and returns a pointer to its |
| | | value, or the passed 'def' pointer if no such key can be found in |
| | | dictionary. The returned character pointer points to data internal to the |
| | | dictionary object, you should not try to free it or modify it. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | char * dictionary_get(dictionary * d, const char * key, char * def) |
| | | { |
| | | unsigned hash ; |
| | | int i ; |
| | | |
| | | hash = dictionary_hash(key); |
| | | for (i=0 ; i<d->size ; i++) { |
| | | if (d->key[i]==NULL) |
| | | continue ; |
| | | /* Compare hash */ |
| | | if (hash==d->hash[i]) { |
| | | /* Compare string, to avoid hash collisions */ |
| | | if (!strcmp(key, d->key[i])) { |
| | | return d->val[i] ; |
| | | } |
| | | } |
| | | } |
| | | return def ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Set a value in a dictionary. |
| | | @param d dictionary object to modify. |
| | | @param key Key to modify or add. |
| | | @param val Value to add. |
| | | @return int 0 if Ok, anything else otherwise |
| | | |
| | | If the given key is found in the dictionary, the associated value is |
| | | replaced by the provided one. If the key cannot be found in the |
| | | dictionary, it is added to it. |
| | | |
| | | It is Ok to provide a NULL value for val, but NULL values for the dictionary |
| | | or the key are considered as errors: the function will return immediately |
| | | in such a case. |
| | | |
| | | Notice that if you dictionary_set a variable to NULL, a call to |
| | | dictionary_get will return a NULL value: the variable will be found, and |
| | | its value (NULL) is returned. In other words, setting the variable |
| | | content to NULL is equivalent to deleting the variable from the |
| | | dictionary. It is not possible (in this implementation) to have a key in |
| | | the dictionary without value. |
| | | |
| | | This function returns non-zero in case of failure. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | int dictionary_set(dictionary * d, const char * key, const char * val) |
| | | { |
| | | int i ; |
| | | unsigned hash ; |
| | | |
| | | if (d==NULL || key==NULL) return -1 ; |
| | | |
| | | /* Compute hash for this key */ |
| | | hash = dictionary_hash(key) ; |
| | | /* Find if value is already in dictionary */ |
| | | if (d->n>0) { |
| | | for (i=0 ; i<d->size ; i++) { |
| | | if (d->key[i]==NULL) |
| | | continue ; |
| | | if (hash==d->hash[i]) { /* Same hash value */ |
| | | if (!strcmp(key, d->key[i])) { /* Same key */ |
| | | /* Found a value: modify and return */ |
| | | if (d->val[i]!=NULL) |
| | | free(d->val[i]); |
| | | d->val[i] = val ? xstrdup(val) : NULL ; |
| | | /* Value has been modified: return */ |
| | | return 0 ; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | /* Add a new value */ |
| | | /* See if dictionary needs to grow */ |
| | | if (d->n==d->size) { |
| | | |
| | | /* Reached maximum size: reallocate dictionary */ |
| | | d->val = (char **)mem_double(d->val, d->size * sizeof(char*)) ; |
| | | d->key = (char **)mem_double(d->key, d->size * sizeof(char*)) ; |
| | | d->hash = (unsigned int *)mem_double(d->hash, d->size * sizeof(unsigned)) ; |
| | | if ((d->val==NULL) || (d->key==NULL) || (d->hash==NULL)) { |
| | | /* Cannot grow dictionary */ |
| | | return -1 ; |
| | | } |
| | | /* Double size */ |
| | | d->size *= 2 ; |
| | | } |
| | | |
| | | /* Insert key in the first empty slot. Start at d->n and wrap at |
| | | d->size. Because d->n < d->size this will necessarily |
| | | terminate. */ |
| | | for (i=d->n ; d->key[i] ; ) { |
| | | if(++i == d->size) i = 0; |
| | | } |
| | | /* Copy key */ |
| | | d->key[i] = xstrdup(key); |
| | | d->val[i] = val ? xstrdup(val) : NULL ; |
| | | d->hash[i] = hash; |
| | | d->n ++ ; |
| | | return 0 ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Delete a key in a dictionary |
| | | @param d dictionary object to modify. |
| | | @param key Key to remove. |
| | | @return void |
| | | |
| | | This function deletes a key in a dictionary. Nothing is done if the |
| | | key cannot be found. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void dictionary_unset(dictionary * d, const char * key) |
| | | { |
| | | unsigned hash ; |
| | | int i ; |
| | | |
| | | if (key == NULL) { |
| | | return; |
| | | } |
| | | |
| | | hash = dictionary_hash(key); |
| | | for (i=0 ; i<d->size ; i++) { |
| | | if (d->key[i]==NULL) |
| | | continue ; |
| | | /* Compare hash */ |
| | | if (hash==d->hash[i]) { |
| | | /* Compare string, to avoid hash collisions */ |
| | | if (!strcmp(key, d->key[i])) { |
| | | /* Found key */ |
| | | break ; |
| | | } |
| | | } |
| | | } |
| | | if (i>=d->size) |
| | | /* Key not found */ |
| | | return ; |
| | | |
| | | free(d->key[i]); |
| | | d->key[i] = NULL ; |
| | | if (d->val[i]!=NULL) { |
| | | free(d->val[i]); |
| | | d->val[i] = NULL ; |
| | | } |
| | | d->hash[i] = 0 ; |
| | | d->n -- ; |
| | | return ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Dump a dictionary to an opened file pointer. |
| | | @param d Dictionary to dump |
| | | @param f Opened file pointer. |
| | | @return void |
| | | |
| | | Dumps a dictionary onto an opened file pointer. Key pairs are printed out |
| | | as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as |
| | | output file pointers. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void dictionary_dump(dictionary * d, FILE * out) |
| | | { |
| | | int i ; |
| | | |
| | | if (d==NULL || out==NULL) return ; |
| | | if (d->n<1) { |
| | | fprintf(out, "empty dictionary\n"); |
| | | return ; |
| | | } |
| | | for (i=0 ; i<d->size ; i++) { |
| | | if (d->key[i]) { |
| | | fprintf(out, "%20s\t[%s]\n", |
| | | d->key[i], |
| | | d->val[i] ? d->val[i] : "UNDEF"); |
| | | } |
| | | } |
| | | return ; |
| | | } |
| | | |
| | | |
| | | /* Test code */ |
| | | #ifdef TESTDIC |
| | | #define NVALS 20000 |
| | | int main(int argc, char *argv[]) |
| | | { |
| | | dictionary * d ; |
| | | char * val ; |
| | | int i ; |
| | | char cval[90] ; |
| | | |
| | | /* Allocate dictionary */ |
| | | printf("allocating...\n"); |
| | | d = dictionary_new(0); |
| | | |
| | | /* Set values in dictionary */ |
| | | printf("setting %d values...\n", NVALS); |
| | | for (i=0 ; i<NVALS ; i++) { |
| | | sprintf(cval, "%04d", i); |
| | | dictionary_set(d, cval, "salut"); |
| | | } |
| | | printf("getting %d values...\n", NVALS); |
| | | for (i=0 ; i<NVALS ; i++) { |
| | | sprintf(cval, "%04d", i); |
| | | val = dictionary_get(d, cval, DICT_INVALID_KEY); |
| | | if (val==DICT_INVALID_KEY) { |
| | | printf("cannot get value for key [%s]\n", cval); |
| | | } |
| | | } |
| | | printf("unsetting %d values...\n", NVALS); |
| | | for (i=0 ; i<NVALS ; i++) { |
| | | sprintf(cval, "%04d", i); |
| | | dictionary_unset(d, cval); |
| | | } |
| | | if (d->n != 0) { |
| | | printf("error deleting values\n"); |
| | | } |
| | | printf("deallocating...\n"); |
| | | dictionary_del(d); |
| | | return 0 ; |
| | | } |
| | | #endif |
| | | /* vim: set ts=4 et sw=4 tw=75 */ |
New file |
| | |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @file cp_dictionary.h |
| | | @author N. Devillard |
| | | @brief Implements a dictionary for string variables. |
| | | |
| | | This module implements a simple dictionary object, i.e. a list |
| | | of string/string associations. This object is useful to store e.g. |
| | | informations retrieved from a configuration file (ini files). |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | |
| | | #ifndef _CP_DICTIONARY_H_ |
| | | #define _CP_DICTIONARY_H_ |
| | | |
| | | /*--------------------------------------------------------------------------- |
| | | Includes |
| | | ---------------------------------------------------------------------------*/ |
| | | |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #include <unistd.h> |
| | | |
| | | /*--------------------------------------------------------------------------- |
| | | New types |
| | | ---------------------------------------------------------------------------*/ |
| | | |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Dictionary object |
| | | |
| | | This object contains a list of string/string associations. Each |
| | | association is identified by a unique string key. Looking up values |
| | | in the dictionary is speeded up by the use of a (hopefully collision-free) |
| | | hash function. |
| | | */ |
| | | /*-------------------------------------------------------------------------*/ |
| | | typedef struct _dictionary_ { |
| | | int n ; /** Number of entries in dictionary */ |
| | | int size ; /** Storage size */ |
| | | char ** val ; /** List of string values */ |
| | | char ** key ; /** List of string keys */ |
| | | unsigned * hash ; /** List of hash values for keys */ |
| | | } dictionary ; |
| | | |
| | | |
| | | /*--------------------------------------------------------------------------- |
| | | Function prototypes |
| | | ---------------------------------------------------------------------------*/ |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Compute the hash key for a string. |
| | | @param key Character string to use for key. |
| | | @return 1 unsigned int on at least 32 bits. |
| | | |
| | | This hash function has been taken from an Article in Dr Dobbs Journal. |
| | | This is normally a collision-free function, distributing keys evenly. |
| | | The key is stored anyway in the struct so that collision can be avoided |
| | | by comparing the key itself in last resort. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | unsigned dictionary_hash(const char * key); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Create a new dictionary object. |
| | | @param size Optional initial size of the dictionary. |
| | | @return 1 newly allocated dictionary objet. |
| | | |
| | | This function allocates a new dictionary object of given size and returns |
| | | it. If you do not know in advance (roughly) the number of entries in the |
| | | dictionary, give size=0. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | dictionary * dictionary_new(int size); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Delete a dictionary object |
| | | @param d dictionary object to deallocate. |
| | | @return void |
| | | |
| | | Deallocate a dictionary object and all memory associated to it. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void dictionary_del(dictionary * vd); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get a value from a dictionary. |
| | | @param d dictionary object to search. |
| | | @param key Key to look for in the dictionary. |
| | | @param def Default value to return if key not found. |
| | | @return 1 pointer to internally allocated character string. |
| | | |
| | | This function locates a key in a dictionary and returns a pointer to its |
| | | value, or the passed 'def' pointer if no such key can be found in |
| | | dictionary. The returned character pointer points to data internal to the |
| | | dictionary object, you should not try to free it or modify it. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | char * dictionary_get(dictionary * d, const char * key, char * def); |
| | | |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Set a value in a dictionary. |
| | | @param d dictionary object to modify. |
| | | @param key Key to modify or add. |
| | | @param val Value to add. |
| | | @return int 0 if Ok, anything else otherwise |
| | | |
| | | If the given key is found in the dictionary, the associated value is |
| | | replaced by the provided one. If the key cannot be found in the |
| | | dictionary, it is added to it. |
| | | |
| | | It is Ok to provide a NULL value for val, but NULL values for the dictionary |
| | | or the key are considered as errors: the function will return immediately |
| | | in such a case. |
| | | |
| | | Notice that if you dictionary_set a variable to NULL, a call to |
| | | dictionary_get will return a NULL value: the variable will be found, and |
| | | its value (NULL) is returned. In other words, setting the variable |
| | | content to NULL is equivalent to deleting the variable from the |
| | | dictionary. It is not possible (in this implementation) to have a key in |
| | | the dictionary without value. |
| | | |
| | | This function returns non-zero in case of failure. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | int dictionary_set(dictionary * vd, const char * key, const char * val); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Delete a key in a dictionary |
| | | @param d dictionary object to modify. |
| | | @param key Key to remove. |
| | | @return void |
| | | |
| | | This function deletes a key in a dictionary. Nothing is done if the |
| | | key cannot be found. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void dictionary_unset(dictionary * d, const char * key); |
| | | |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Dump a dictionary to an opened file pointer. |
| | | @param d Dictionary to dump |
| | | @param f Opened file pointer. |
| | | @return void |
| | | |
| | | Dumps a dictionary onto an opened file pointer. Key pairs are printed out |
| | | as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as |
| | | output file pointers. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void dictionary_dump(dictionary * d, FILE * out); |
| | | |
| | | #endif |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) guowenxue<guowenxue@gmail.com> |
| | | * All rights reserved. |
| | | * |
| | | * Filename: module.c |
| | | * Description: This is the GPRS Power/SIM card control source code |
| | | * |
| | | * Version: 1.0.0(02/07/2012~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "02/07/2012 03:08:25 PM" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #include "cp_gprs.h" |
| | | #include "cp_proc.h" |
| | | |
| | | int init_gsm_module(modinfo_t *module) |
| | | { |
| | | int i=0; |
| | | char devname[DEVNAME_LEN]; |
| | | |
| | | log_info("Initialize GSM module context\n"); |
| | | |
| | | memset(module, 0, sizeof(*module)); |
| | | |
| | | module->event = REQ_POWER_RESET; /* Request to power on GPRS */ |
| | | |
| | | pthread_mutex_init(&module->lock, NULL); |
| | | |
| | | if( !(module->gsmport=comport_init(GSM_DATAPORT, 115200, "8N1N")) ) |
| | | { |
| | | return -1; |
| | | } |
| | | |
| | | /* Initialize the GPRS dataport pointer */ |
| | | module->comport_cnt = MAX_DATAPORT; |
| | | for(i=0; i<module->comport_cnt; i++) |
| | | { |
| | | snprintf(devname, DEVNAME_LEN, "%s%d", CMUX_DATAPORT, i+CMUX_PORT_START_INDEX); |
| | | module->comport[i] = comport_init(devname, 115200, "8N1N"); |
| | | if(NULL == module->comport[i]) |
| | | goto ERROR; |
| | | |
| | | //log_dbg("Initialise comport [%p] on %s on baudrate 115200 with 8N1N\n", module->comport[i], devname); |
| | | } |
| | | |
| | | return 0; |
| | | |
| | | ERROR: |
| | | while(i-- >= 0) |
| | | { |
| | | comport_term(module->comport[i]); |
| | | } |
| | | return -2; |
| | | } |
| | | |
| | | |
| | | /* |
| | | * Description: close all the GPRS control port device. |
| | | * |
| | | * Return Value: NONE |
| | | */ |
| | | void close_gsm_dataport(modinfo_t *module) |
| | | { |
| | | int i; |
| | | |
| | | for(i=0; i<module->comport_cnt; i++) |
| | | { |
| | | log_nrml("Close GPRS dataport %s=>[fd:%d]\n", module->comport[i]->dev_name, module->comport[i]->fd); |
| | | comport_close(module->comport[i]); |
| | | } |
| | | |
| | | return ; |
| | | } |
| | | |
| | | /* |
| | | * Description: open all the GPRS data port device. |
| | | * |
| | | * Return Value: 0: Open successfully !0: Open failure |
| | | */ |
| | | int open_gsm_dataport(modinfo_t *module) |
| | | { |
| | | int i, retval = -1; |
| | | |
| | | for(i=0; i<module->comport_cnt; i++) |
| | | { |
| | | if( (retval=comport_open(module->comport[i])) < 0) |
| | | { |
| | | log_err("Open GPRS dataport %s failure: %d\n", module->comport[i]->dev_name, retval); |
| | | goto ERROR; |
| | | } |
| | | log_nrml("Open GPRS dataport[%p] %s=>[fd:%d]\n", module->comport, module->comport[i]->dev_name, module->comport[i]->fd); |
| | | } |
| | | |
| | | return 0; |
| | | |
| | | ERROR: |
| | | close_gsm_dataport(module); |
| | | return retval; |
| | | } |
| | | |
| | | |
| | | /* |
| | | * Description: Alloc a comport from the comport poor for used, for we must make sure |
| | | * PPP thread can grasp a comport to work, so we will always preserved |
| | | * first comport for PPP thread. |
| | | * |
| | | * Return Value: NULL: No comport left !NULL: The alloced comport pointer |
| | | */ |
| | | comport_t *alloc_gsm_dataport(char *who, modinfo_t *module) |
| | | { |
| | | static int lock = 0; |
| | | int i; |
| | | comport_t *comport = NULL; |
| | | |
| | | if(lock) |
| | | return NULL; |
| | | |
| | | lock = 1; |
| | | |
| | | /* Preserve first comport for PPP thread */ |
| | | for(i=0; i<module->comport_cnt; i++) |
| | | { |
| | | if(module->comport[i]->used != YES) |
| | | { |
| | | comport = module->comport[i]; |
| | | comport->used = YES; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | lock = 0; |
| | | |
| | | if(comport) |
| | | { |
| | | log_dbg("%s allocate GPRS dataport[%d] %s=>[fd:%d] ok\n", who, i, comport->dev_name, comport->fd); |
| | | module->users++; |
| | | } |
| | | else |
| | | { |
| | | log_dbg("%s allocate GPRS dataport failure\n", who); |
| | | } |
| | | |
| | | |
| | | return comport; |
| | | } |
| | | |
| | | /* |
| | | * Description: Free a comport to the comport poor when we no need it. |
| | | * |
| | | * Return Value: NONE |
| | | */ |
| | | void free_gsm_dataport(char *who, modinfo_t *module, comport_t **comport) |
| | | { |
| | | int i; |
| | | |
| | | /* Preserve first comport for PPP thread */ |
| | | for(i=0; i<module->comport_cnt; i++) |
| | | { |
| | | if(module->comport[i] == *comport) |
| | | { |
| | | log_dbg("%s free GPRS dataport %s=>[fd:%d]\n", who, (*comport)->dev_name, (*comport)->fd); |
| | | module->comport[i]->used = NO; |
| | | module->users--; |
| | | *comport = NULL; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | return ; |
| | | } |
| | | |
| | | |
| | | /* |
| | | * Description: Power on the GPRS module and open all the gprs data port. For when GPRS power off, |
| | | * the GPRS module USB convert serial comport device lost, so we must bind them together. |
| | | * Return Value: 0: Open successfully !0: Open failure |
| | | */ |
| | | int power_on_module(modinfo_t *module) |
| | | { |
| | | int rv = 0; |
| | | log_dbg("Turn on GPRS module now\n"); |
| | | |
| | | micro_second_sleep(500); |
| | | |
| | | if( comport_open(module->gsmport) < 0) |
| | | { |
| | | log_err("Open GSM serial port [%s] failure\n", module->gsmport->dev_name); |
| | | return -2; |
| | | } |
| | | |
| | | if( !atcmd_check_power_on(module->gsmport) ) |
| | | { |
| | | log_err("Send ATE0 check GPRS module AT command failure\n", module->gsmport->dev_name); |
| | | return -2; |
| | | } |
| | | |
| | | if( 0 != open_gsm_dataport(module) ) |
| | | { |
| | | rv = -3; |
| | | log_err("Open GPRS module comport failure\n"); |
| | | goto cleanup; |
| | | } |
| | | |
| | | cleanup: |
| | | |
| | | if(!rv) |
| | | { |
| | | module->ready = MODULE_READY; |
| | | log_nrml("Turn on GPRS module succesfully\n"); |
| | | } |
| | | else |
| | | { |
| | | module->ready = NOT_READY; |
| | | log_nrml("Turn on GPRS module failed, rv=%d\n", rv); |
| | | } |
| | | |
| | | module->ready = 0!=rv ? NOT_READY : MODULE_READY; |
| | | memset(&(module->reg), 0, sizeof(reginfo_t)); |
| | | |
| | | return rv; |
| | | } |
| | | |
| | | /* |
| | | * Description: Power off the GPRS module and close all the gprs data port. For when GPRS power off, |
| | | * the GPRS module USB convert serial comport device lost, so we must bind them together. |
| | | * Return Value: 0: Open successfully !0: Open failure |
| | | */ |
| | | int power_off_module(modinfo_t *module) |
| | | { |
| | | while(module->users) |
| | | { |
| | | log_warn("%d application still use the GPRS module dataport, wait released...\n", module->users); |
| | | sleep(1); |
| | | } |
| | | |
| | | log_nrml("Turn off GPRS module now\n"); |
| | | close_gsm_dataport(module); |
| | | |
| | | comport_close(module->gsmport); |
| | | |
| | | module->ready = NOT_READY; |
| | | memset(&(module->reg), 0, sizeof(reginfo_t)); |
| | | |
| | | micro_second_sleep(800); |
| | | return 0; |
| | | } |
| | | |
| | | void set_module_event(modinfo_t *module, int request) |
| | | { |
| | | log_dbg("Set the module event request[%d]\n", request); |
| | | pthread_mutex_lock(&module->lock); |
| | | module->event = request; |
| | | pthread_mutex_unlock(&module->lock); |
| | | } |
| | | |
| | | /* |
| | | * Description: Set the GPRS power status according to the module request event. |
| | | * the GPRS module USB convert serial comport device lost, so we must bind them together. |
| | | * Return Value: 0:Set GPRS power status successfully !0: Open failure |
| | | */ |
| | | int set_module_event_power(modinfo_t *module) |
| | | { |
| | | int rv = 0; |
| | | switch (module->event) |
| | | { |
| | | case REQ_POWER_ON: |
| | | rv = power_on_module(module); |
| | | break; |
| | | |
| | | case REQ_POWER_OFF: |
| | | rv = power_off_module(module); |
| | | break; |
| | | |
| | | case REQ_POWER_RESET: |
| | | rv = power_off_module(module); |
| | | rv = power_on_module(module); |
| | | break; |
| | | } |
| | | |
| | | if( rv ) |
| | | { |
| | | log_nrml("Response for the GPRS request event %d failure, rv=%d\n", module->event, rv); |
| | | return rv; |
| | | } |
| | | else |
| | | { |
| | | log_nrml("Response for the GPRS request event %d and clear this event ok\n", module->event); |
| | | set_module_event(module, REQ_EVENT_NONE); |
| | | return 0; |
| | | } |
| | | } |
| | | |
| | | |
| | | int atcmd_inspect_status(modinfo_t *module) |
| | | { |
| | | comport_t *comport; |
| | | reginfo_t *reg = &(module->reg); /* SIM card Register information */ |
| | | char *who = "atcmd_inspect_status()"; |
| | | |
| | | static unsigned long start_time ; |
| | | |
| | | /* Every 10 seconds we will inspect it */ |
| | | if(start_time && time_elapsed(start_time) < 10000) |
| | | { |
| | | return 0; |
| | | } |
| | | |
| | | start_time= time_now(); |
| | | |
| | | comport = alloc_gsm_dataport(who, module); |
| | | if(NULL != comport) |
| | | { |
| | | log_dbg("Alloc dataport %s=>[fd:%d]\n", comport->dev_name, comport->fd); |
| | | } |
| | | else |
| | | return -1; |
| | | |
| | | reg->signal = atcmd_check_gprs_signal(comport); |
| | | |
| | | atcmd_check_gprs_location(comport, ®->loc); |
| | | |
| | | log_dbg("Free dataport %s=>[fd:%d]\n", comport->dev_name, comport->fd); |
| | | free_gsm_dataport(who, module, &comport); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | /* |
| | | * Description: Check the AT command and SIM card ready or not |
| | | * Input value: times: Max check times |
| | | *Return Value: 1: Already OK 0: Still on test -1: Failure |
| | | * |
| | | */ |
| | | int atcmd_check_module_ready(comport_t *comport, int times) |
| | | { |
| | | int rv; |
| | | static int fail_cnt = 0; |
| | | |
| | | /* Send ATE0 to check GPRS module AT ready or not */ |
| | | rv = atcmd_check_at_ready(comport); |
| | | if(rv) |
| | | goto cleanup; |
| | | |
| | | /* Send AT+CPIN? to check SIM card valid or not */ |
| | | rv = atcmd_check_sim_valid(comport); |
| | | |
| | | cleanup: |
| | | if(rv) |
| | | { |
| | | if(fail_cnt < times) |
| | | { |
| | | fail_cnt ++; |
| | | return 0; |
| | | } |
| | | else |
| | | { |
| | | fail_cnt = 0; |
| | | return -1; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | fail_cnt = 0; |
| | | return 1; |
| | | } |
| | | } |
| | | |
| | | int atcmd_check_power_on(comport_t *comport) |
| | | { |
| | | int i, rv = 0; |
| | | |
| | | for(i=0; i<10; i++) |
| | | { |
| | | if( !atcmd_check_at_ready(comport) ) |
| | | { |
| | | rv = 1; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | return rv; |
| | | } |
| | | |
| | | /* |
| | | * Some preset command here, such as set Module as 2G mode |
| | | */ |
| | | int atcmd_module_preset(comport_t *comport) |
| | | { |
| | | int retval = 0; |
| | | |
| | | /* Send AT+COPS=0 to set GPRS module auto select an operator */ |
| | | if(0 != (retval=send_atcmd_check_ok(comport, "AT+COPS=0\r", 3000)) ) |
| | | { |
| | | log_warn("AT+COPS=0 Set Auto Select Carrier: [FAILED]\n"); |
| | | return -2; |
| | | } |
| | | log_nrml("AT+COPS=0 Set Auto Select Carrier: [OK]\n"); |
| | | |
| | | return retval; |
| | | } |
| | | |
| | | |
| | | int atcmd_check_hwinfo(comport_t *comport, hwinfo_t *hw, int times) |
| | | { |
| | | int rv; |
| | | static int fail_cnt = 0; |
| | | |
| | | /* Send AT+CGMM to check GPRS module hardware name and type */ |
| | | rv = atcmd_check_gprs_name(comport, hw->model); |
| | | if(rv) |
| | | goto cleanup; |
| | | |
| | | /* Send AT+CGMR to check GPRS module hardware version */ |
| | | rv = atcmd_check_gprs_version(comport, hw->mrev); |
| | | if(rv) |
| | | goto cleanup; |
| | | |
| | | /* Send AT+CGSN to check GPRS module hardware IEMI number*/ |
| | | rv = atcmd_check_gprs_iemi(comport, hw->iemi); |
| | | |
| | | cleanup: |
| | | if(rv) |
| | | { |
| | | if(fail_cnt < times) |
| | | { |
| | | fail_cnt ++; |
| | | return 0; |
| | | } |
| | | else |
| | | { |
| | | fail_cnt = 0; |
| | | return -1; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | fail_cnt = 0; |
| | | return 1; |
| | | } |
| | | } |
| | | |
| | | |
| | | int atcmd_check_regist(comport_t *comport, reginfo_t *reg, int times) |
| | | { |
| | | int rv = 0; |
| | | static int fail_cnt = 0; |
| | | |
| | | /* Send AT+CSQ to check GPRS signal strength */ |
| | | reg->signal = atcmd_check_gprs_signal(comport); |
| | | if(reg->signal<2 && reg->signal>31) |
| | | { |
| | | rv = -1; |
| | | goto cleanup; |
| | | } |
| | | |
| | | /* Send AT+CREG? to check SIM card regist to network or not */ |
| | | reg->type = atcmd_check_gprs_register(comport); |
| | | |
| | | if(REG_HOMEWORK==reg->type || REG_ROAMING== reg->type) |
| | | { |
| | | /* SIM card register successfully */ |
| | | log_nrml("SIM card register successfully.\n"); |
| | | rv = 0; |
| | | } |
| | | else if(REG_DENIED==reg->type) |
| | | { |
| | | /* SIM card can not register, so request to switch SIM card */ |
| | | log_err("SIM card regist denied.\n"); |
| | | rv = -2; |
| | | goto cleanup; |
| | | } |
| | | else |
| | | { |
| | | log_err("SIM card regist failure.\n"); |
| | | rv = -3; |
| | | goto cleanup; |
| | | } |
| | | |
| | | rv = atcmd_check_gprs_carrier(comport, reg->carrier); |
| | | if(rv) |
| | | { |
| | | rv = -4; |
| | | log_err("Check SIM card acrrier failure.\n"); |
| | | goto cleanup; |
| | | } |
| | | |
| | | rv = atcmd_check_gprs_mcc_mnc(comport, reg->loc.mcc_mnc); |
| | | if(rv) |
| | | { |
| | | rv = -4; |
| | | log_err("Check SIM card register MCC-MNC failure\n"); |
| | | goto cleanup; |
| | | } |
| | | |
| | | |
| | | cleanup: |
| | | if(rv) |
| | | { |
| | | if(fail_cnt < times) |
| | | { |
| | | fail_cnt ++; |
| | | return 0; |
| | | } |
| | | else |
| | | { |
| | | fail_cnt = 0; |
| | | return -1; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | fail_cnt = 0; |
| | | return 1; |
| | | } |
| | | |
| | | } |
| | | |
| | | int atcmd_check_network_info(comport_t *comport, reginfo_t *reg) |
| | | { |
| | | int retval = 0; |
| | | |
| | | /* Send AT+COPS to check SIM card registed network carrier */ |
| | | retval = atcmd_check_gprs_carrier(comport, reg->carrier); |
| | | if(retval) return -1; |
| | | |
| | | /* Send AT+QGSMLOC=1 to check GPRS module location */ |
| | | retval = atcmd_check_gprs_location(comport, &(reg->loc)); |
| | | if(retval) return -3; |
| | | |
| | | return retval; |
| | | } |
| | | |
| | | |
| | | int atcmd_check_ready(modinfo_t *module) |
| | | { |
| | | int rv; |
| | | comport_t *comport; |
| | | char *who = "atcmd_check_ready()"; |
| | | |
| | | log_nrml("AT command check GPRS registry status now\n"); |
| | | /* Alloc a comport to send AT command */ |
| | | comport = alloc_gsm_dataport(who, module); |
| | | if(NULL == comport) |
| | | { |
| | | log_warn("Alloc dataport for %s() failure.\n", __FUNCTION__); |
| | | return -1; |
| | | } |
| | | log_dbg("Alloc dataport %s=>[fd:%d]\n", comport->dev_name, comport->fd); |
| | | |
| | | switch(module->ready) |
| | | { |
| | | case MODULE_READY: |
| | | rv = atcmd_check_module_ready(comport, 10); |
| | | if(rv > 0) |
| | | { |
| | | log_nrml("GPRS AT command ready and SIM card valid successfully\n"); |
| | | module->ready++; /* Continue to check, not break */ |
| | | } |
| | | else if(rv == 0) |
| | | { |
| | | log_nrml("GPRS AT command ready and SIM card valid check continue...\n"); |
| | | } |
| | | else if(rv < 0) |
| | | { |
| | | log_nrml("GPRS AT command ready and SIM card valid check failed\n"); |
| | | set_module_event(module, REQ_POWER_RESET); |
| | | } |
| | | break; |
| | | |
| | | case CHECK_HWINFO: |
| | | rv = atcmd_check_hwinfo(comport, &(module->hw), 10); |
| | | if(rv > 0) |
| | | { |
| | | log_nrml("Check the GPRS Module hardware information successfully\n"); |
| | | module->ready++; /* Continue to check, not break */ |
| | | } |
| | | else if(rv == 0) |
| | | { |
| | | log_nrml("Check the GPRS Module hardware information continue...\n"); |
| | | } |
| | | else if(rv < 0) |
| | | { |
| | | log_nrml("Check the GPRS Module hardware information failed...\n"); |
| | | set_module_event(module, REQ_POWER_RESET); |
| | | } |
| | | break; |
| | | |
| | | case CHECK_REGISTRY: |
| | | rv = atcmd_check_regist(comport, &(module->reg), 10); |
| | | if(rv > 0) |
| | | { |
| | | log_nrml("Check the SIM card registry successfully\n"); |
| | | module->ready++; /* Continue to check, not break */ |
| | | } |
| | | else if(rv == 0) |
| | | { |
| | | log_nrml("Check the SIM card registry continue...\n"); |
| | | } |
| | | else if(rv < 0) |
| | | { |
| | | log_nrml("Check the SIM card registry failed\n"); |
| | | set_module_event(module, REQ_POWER_RESET); |
| | | } |
| | | break; |
| | | } |
| | | |
| | | free_gsm_dataport(who, module, &comport); |
| | | return rv; |
| | | } |
| | | |
| | | |
| | | /* |
| | | * Description: Terminate the control thread work context |
| | | * Return Value: NONE |
| | | */ |
| | | void ctrl_thread_term(void *thread_arg) |
| | | { |
| | | int i=0; |
| | | modinfo_t *module = (modinfo_t *)thread_arg; |
| | | |
| | | log_nrml("start terminate GPRS main(control) thread\n"); |
| | | |
| | | power_off_module(module); |
| | | |
| | | for(i=0; i<module->comport_cnt; i++) |
| | | { |
| | | comport_term(module->comport[i]); |
| | | } |
| | | } |
| | | |
| | | |
| | | /* Description: Continue the main thread as the control thread, which used to control/inspect the GPRS |
| | | * module power status. If it exit, then whole program exit.So when it exit, we must |
| | | * make sure all other threads exit. |
| | | * |
| | | *Return Value: NONE |
| | | */ |
| | | void ctrl_thread_start(void *thread_arg) |
| | | { |
| | | modinfo_t *module = (modinfo_t *)thread_arg; |
| | | |
| | | log_nrml("GPRS power control thread start running\n"); |
| | | |
| | | while( !g_cp_signal.stop ) |
| | | { |
| | | /* If someone request to change the power status, then set the power*/ |
| | | if(module->event) |
| | | { |
| | | set_module_event_power(module); |
| | | } |
| | | |
| | | if(ALL_READY == module->ready) |
| | | { |
| | | /* If GPRS already registed then we just need to inspect the GPRS |
| | | * module status, such as signal, location */ |
| | | atcmd_inspect_status(module); |
| | | } |
| | | else |
| | | { |
| | | /* If GPRS module just already power on, then we use AT command to |
| | | * check the SIM card can work or not now. */ |
| | | if( ON == module->pwr_status ) |
| | | { |
| | | atcmd_check_ready(module); |
| | | } |
| | | } |
| | | |
| | | sleep(1); |
| | | } |
| | | |
| | | /* thread exit */ |
| | | ctrl_thread_term(thread_arg); |
| | | |
| | | return ; |
| | | } |
New file |
| | |
| | | /******************************************************************************** |
| | | * Copyright: (C) guowenxue <guowenxue@gmail.com> |
| | | * All rights reserved. |
| | | * |
| | | * Filename: module.h |
| | | * Description: This is the GPRS module head file |
| | | * |
| | | * Version: 1.0.0(02/02/2012~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "02/02/2012 11:33:33 AM" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #ifndef __CP_GPRS_H |
| | | #define __CP_GPRS_H |
| | | |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <unistd.h> |
| | | #include <pthread.h> |
| | | |
| | | #include "cp_common.h" |
| | | #include "cp_logger.h" |
| | | #include "cp_comport.h" |
| | | #include "cp_atcmd.h" |
| | | #include "cp_time.h" |
| | | |
| | | #define YES 1 |
| | | #define NO 0 |
| | | |
| | | #define OFF 0 |
| | | #define ON 1 |
| | | |
| | | #define GSM_CTRLPORT "/dev/gprs" |
| | | #define GSM_DATAPORT "/dev/ttyS2" |
| | | |
| | | #define MAX_DATAPORT 4 /* CMUX driver will generate 4 TTY port */ |
| | | #define CMUX_PORT_START_INDEX 1 |
| | | #define CMUX_DATAPORT "/dev/gsmtty" |
| | | |
| | | /*GPRS module power status control request event*/ |
| | | enum |
| | | { |
| | | REQ_EVENT_NONE = 0, |
| | | REQ_POWER_OFF, |
| | | REQ_POWER_ON, |
| | | REQ_POWER_RESET, |
| | | }; |
| | | |
| | | /* GPRS Module Ready status */ |
| | | enum |
| | | { |
| | | NOT_READY, |
| | | MODULE_READY, /* GPRS AT command active and SIM card valid */ |
| | | CHECK_HWINFO, /* Get GPRS hardware Information */ |
| | | CHECK_REGISTRY, /* Check GPRS register network information */ |
| | | ALL_READY, |
| | | }; |
| | | |
| | | /* AT+CREG? command show SIM card register status */ |
| | | enum |
| | | { |
| | | REG_UNREGIST = 0, /* not registered, ME is not currently searching a new operator to register to */ |
| | | REG_HOMEWORK, /* registered, home network */ |
| | | REG_SEARCHING, /* not registered, but ME is currently searching a new operator to register to */ |
| | | REG_DENIED, /* registration denied */ |
| | | REG_UNKNOW, /* unknow */ |
| | | REG_ROAMING, /* registered, roaming */ |
| | | }; |
| | | |
| | | /* AT+CNMP=? command to set GPRS module work on which mode */ |
| | | #define MODE_AUTO 2 /* Automatic */ |
| | | #define MODE_GSM 13 /* GSM Only */ |
| | | #define MODE_WCDMA 14 /* WCDMA Only */ |
| | | |
| | | /* AT+CNSMOD? command show network system mode */ |
| | | enum |
| | | { |
| | | NS_NONE = 0, /* No service */ |
| | | NS_GSM, /* GSM */ |
| | | NS_GPRS, /* GPRS */ |
| | | NS_EGPRS, /* EGPRS(EDGE) */ |
| | | NS_WCDMA, /* WCDMA */ |
| | | NS_HSDPA, /* HSDPA only */ |
| | | NS_HSUPA, /* HSUPA only */ |
| | | NS_HSPA, /* HSDPA and HSUPA */ |
| | | }; |
| | | |
| | | typedef struct modinfo_s |
| | | { |
| | | int users; /* How many users use the module now */ |
| | | unsigned char ready; /* SIM card regist and can work or not */ |
| | | unsigned char event; /* Request to set GPRS power REQ_POWER_ON, REQ_POWER_OFF or REQ_POWER_RESET */ |
| | | unsigned char pwr_status; /* Current module power status */ |
| | | |
| | | pthread_mutex_t lock; /* Module control mutex lock */ |
| | | |
| | | hwinfo_t hw; /* GPRS Hardware information */ |
| | | reginfo_t reg; /* SIM card register network information */ |
| | | |
| | | comport_t *gsmport; /* The GSM hardware UART port */ |
| | | |
| | | int comport_cnt; /* GPRS data channel count */ |
| | | comport_t *comport[MAX_DATAPORT]; /* CMUX driver generate CMUX port */ |
| | | } modinfo_t; |
| | | |
| | | |
| | | extern int init_gsm_module(modinfo_t *module); |
| | | extern int open_gsm_dataport(modinfo_t *module); |
| | | extern void close_gsm_dataport(modinfo_t *module); |
| | | extern comport_t *alloc_gsm_dataport(char *who, modinfo_t *module); |
| | | extern void free_gsm_dataport(char *who, modinfo_t *module, comport_t **comport); |
| | | |
| | | extern int power_on_module(modinfo_t *module); |
| | | extern int power_off_module(modinfo_t *module); |
| | | |
| | | extern int atcmd_check_ready(modinfo_t *module); |
| | | extern int atcmd_inspect_status(modinfo_t *module); |
| | | extern int atcmd_check_power_on(comport_t *comport); |
| | | //unsigned char atcmd_inspect(modinfo_t *module, comport_t *comport); |
| | | |
| | | extern void set_module_event(modinfo_t *module, int request); |
| | | extern int set_module_event_power(modinfo_t *module); |
| | | |
| | | extern void ctrl_thread_start(void *thread_arg); |
| | | extern void ctrl_thread_term(void *thread_arg); |
| | | |
| | | #endif /* End of __CP_GPRS_H */ |
New file |
| | |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @file cp_iniparser.c |
| | | @author N. Devillard |
| | | @brief Parser for ini files. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | /*---------------------------- Includes ------------------------------------*/ |
| | | #include <ctype.h> |
| | | #include "cp_iniparser.h" |
| | | |
| | | /*---------------------------- Defines -------------------------------------*/ |
| | | #define ASCIILINESZ (1024) |
| | | #define INI_INVALID_KEY ((char*)-1) |
| | | |
| | | /*--------------------------------------------------------------------------- |
| | | Private to this module |
| | | ---------------------------------------------------------------------------*/ |
| | | /** |
| | | * This enum stores the status for each parsed line (internal use only). |
| | | */ |
| | | typedef enum _line_status_ { |
| | | LINE_UNPROCESSED, |
| | | LINE_ERROR, |
| | | LINE_EMPTY, |
| | | LINE_COMMENT, |
| | | LINE_SECTION, |
| | | LINE_VALUE |
| | | } line_status ; |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Convert a string to lowercase. |
| | | @param s String to convert. |
| | | @return ptr to statically allocated string. |
| | | |
| | | This function returns a pointer to a statically allocated string |
| | | containing a lowercased version of the input string. Do not free |
| | | or modify the returned string! Since the returned string is statically |
| | | allocated, it will be modified at each function call (not re-entrant). |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | static char * strlwc(const char * s) |
| | | { |
| | | static char l[ASCIILINESZ+1]; |
| | | int i ; |
| | | |
| | | if (s==NULL) return NULL ; |
| | | memset(l, 0, ASCIILINESZ+1); |
| | | i=0 ; |
| | | while (s[i] && i<ASCIILINESZ) { |
| | | l[i] = (char)tolower((int)s[i]); |
| | | i++ ; |
| | | } |
| | | l[ASCIILINESZ]=(char)0; |
| | | return l ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Remove blanks at the beginning and the end of a string. |
| | | @param s String to parse. |
| | | @return ptr to statically allocated string. |
| | | |
| | | This function returns a pointer to a statically allocated string, |
| | | which is identical to the input string, except that all blank |
| | | characters at the end and the beg. of the string have been removed. |
| | | Do not free or modify the returned string! Since the returned string |
| | | is statically allocated, it will be modified at each function call |
| | | (not re-entrant). |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | static char * strstrip(const char * s) |
| | | { |
| | | static char l[ASCIILINESZ+1]; |
| | | char * last ; |
| | | |
| | | if (s==NULL) return NULL ; |
| | | |
| | | while (isspace((int)*s) && *s) s++; |
| | | memset(l, 0, ASCIILINESZ+1); |
| | | strcpy(l, s); |
| | | last = l + strlen(l); |
| | | while (last > l) { |
| | | if (!isspace((int)*(last-1))) |
| | | break ; |
| | | last -- ; |
| | | } |
| | | *last = (char)0; |
| | | return (char*)l ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get number of sections in a dictionary |
| | | @param d Dictionary to examine |
| | | @return int Number of sections found in dictionary |
| | | |
| | | This function returns the number of sections found in a dictionary. |
| | | The test to recognize sections is done on the string stored in the |
| | | dictionary: a section name is given as "section" whereas a key is |
| | | stored as "section:key", thus the test looks for entries that do not |
| | | contain a colon. |
| | | |
| | | This clearly fails in the case a section name contains a colon, but |
| | | this should simply be avoided. |
| | | |
| | | This function returns -1 in case of error. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | int iniparser_getnsec(dictionary * d) |
| | | { |
| | | int i ; |
| | | int nsec ; |
| | | |
| | | if (d==NULL) return -1 ; |
| | | nsec=0 ; |
| | | for (i=0 ; i<d->size ; i++) { |
| | | if (d->key[i]==NULL) |
| | | continue ; |
| | | if (strchr(d->key[i], ':')==NULL) { |
| | | nsec ++ ; |
| | | } |
| | | } |
| | | return nsec ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get name for section n in a dictionary. |
| | | @param d Dictionary to examine |
| | | @param n Section number (from 0 to nsec-1). |
| | | @return Pointer to char string |
| | | |
| | | This function locates the n-th section in a dictionary and returns |
| | | its name as a pointer to a string statically allocated inside the |
| | | dictionary. Do not free or modify the returned string! |
| | | |
| | | This function returns NULL in case of error. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | char * iniparser_getsecname(dictionary * d, int n) |
| | | { |
| | | int i ; |
| | | int foundsec ; |
| | | |
| | | if (d==NULL || n<0) return NULL ; |
| | | foundsec=0 ; |
| | | for (i=0 ; i<d->size ; i++) { |
| | | if (d->key[i]==NULL) |
| | | continue ; |
| | | if (strchr(d->key[i], ':')==NULL) { |
| | | foundsec++ ; |
| | | if (foundsec>n) |
| | | break ; |
| | | } |
| | | } |
| | | if (foundsec<=n) { |
| | | return NULL ; |
| | | } |
| | | return d->key[i] ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Dump a dictionary to an opened file pointer. |
| | | @param d Dictionary to dump. |
| | | @param f Opened file pointer to dump to. |
| | | @return void |
| | | |
| | | This function prints out the contents of a dictionary, one element by |
| | | line, onto the provided file pointer. It is OK to specify @c stderr |
| | | or @c stdout as output files. This function is meant for debugging |
| | | purposes mostly. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void iniparser_dump(dictionary * d, FILE * f) |
| | | { |
| | | int i ; |
| | | |
| | | if (d==NULL || f==NULL) return ; |
| | | for (i=0 ; i<d->size ; i++) { |
| | | if (d->key[i]==NULL) |
| | | continue ; |
| | | if (d->val[i]!=NULL) { |
| | | fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]); |
| | | } else { |
| | | fprintf(f, "[%s]=UNDEF\n", d->key[i]); |
| | | } |
| | | } |
| | | return ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Save a dictionary to a loadable ini file |
| | | @param d Dictionary to dump |
| | | @param f Opened file pointer to dump to |
| | | @return void |
| | | |
| | | This function dumps a given dictionary into a loadable ini file. |
| | | It is Ok to specify @c stderr or @c stdout as output files. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void iniparser_dump_ini(dictionary * d, FILE * f) |
| | | { |
| | | int i ; |
| | | int nsec ; |
| | | char * secname ; |
| | | |
| | | if (d==NULL || f==NULL) return ; |
| | | |
| | | nsec = iniparser_getnsec(d); |
| | | if (nsec<1) { |
| | | /* No section in file: dump all keys as they are */ |
| | | for (i=0 ; i<d->size ; i++) { |
| | | if (d->key[i]==NULL) |
| | | continue ; |
| | | fprintf(f, "%s = %s\n", d->key[i], d->val[i]); |
| | | } |
| | | return ; |
| | | } |
| | | for (i=0 ; i<nsec ; i++) { |
| | | secname = iniparser_getsecname(d, i) ; |
| | | iniparser_dumpsection_ini(d, secname, f) ; |
| | | } |
| | | fprintf(f, "\n"); |
| | | return ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Save a dictionary section to a loadable ini file |
| | | @param d Dictionary to dump |
| | | @param s Section name of dictionary to dump |
| | | @param f Opened file pointer to dump to |
| | | @return void |
| | | |
| | | This function dumps a given section of a given dictionary into a loadable ini |
| | | file. It is Ok to specify @c stderr or @c stdout as output files. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void iniparser_dumpsection_ini(dictionary * d, char * s, FILE * f) |
| | | { |
| | | int j ; |
| | | char keym[ASCIILINESZ+1]; |
| | | int seclen ; |
| | | |
| | | if (d==NULL || f==NULL) return ; |
| | | if (! iniparser_find_entry(d, s)) return ; |
| | | |
| | | seclen = (int)strlen(s); |
| | | fprintf(f, "\n[%s]\n", s); |
| | | sprintf(keym, "%s:", s); |
| | | for (j=0 ; j<d->size ; j++) { |
| | | if (d->key[j]==NULL) |
| | | continue ; |
| | | if (!strncmp(d->key[j], keym, seclen+1)) { |
| | | fprintf(f, |
| | | "%-30s = %s\n", |
| | | d->key[j]+seclen+1, |
| | | d->val[j] ? d->val[j] : ""); |
| | | } |
| | | } |
| | | fprintf(f, "\n"); |
| | | return ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get the number of keys in a section of a dictionary. |
| | | @param d Dictionary to examine |
| | | @param s Section name of dictionary to examine |
| | | @return Number of keys in section |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | int iniparser_getsecnkeys(dictionary * d, char * s) |
| | | { |
| | | int seclen, nkeys ; |
| | | char keym[ASCIILINESZ+1]; |
| | | int j ; |
| | | |
| | | nkeys = 0; |
| | | |
| | | if (d==NULL) return nkeys; |
| | | if (! iniparser_find_entry(d, s)) return nkeys; |
| | | |
| | | seclen = (int)strlen(s); |
| | | sprintf(keym, "%s:", s); |
| | | |
| | | for (j=0 ; j<d->size ; j++) { |
| | | if (d->key[j]==NULL) |
| | | continue ; |
| | | if (!strncmp(d->key[j], keym, seclen+1)) |
| | | nkeys++; |
| | | } |
| | | |
| | | return nkeys; |
| | | |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get the number of keys in a section of a dictionary. |
| | | @param d Dictionary to examine |
| | | @param s Section name of dictionary to examine |
| | | @return pointer to statically allocated character strings |
| | | |
| | | This function queries a dictionary and finds all keys in a given section. |
| | | Each pointer in the returned char pointer-to-pointer is pointing to |
| | | a string allocated in the dictionary; do not free or modify them. |
| | | |
| | | This function returns NULL in case of error. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | char ** iniparser_getseckeys(dictionary * d, char * s) |
| | | { |
| | | |
| | | char **keys; |
| | | |
| | | int i, j ; |
| | | char keym[ASCIILINESZ+1]; |
| | | int seclen, nkeys ; |
| | | |
| | | keys = NULL; |
| | | |
| | | if (d==NULL) return keys; |
| | | if (! iniparser_find_entry(d, s)) return keys; |
| | | |
| | | nkeys = iniparser_getsecnkeys(d, s); |
| | | |
| | | keys = (char**) malloc(nkeys*sizeof(char*)); |
| | | |
| | | seclen = (int)strlen(s); |
| | | sprintf(keym, "%s:", s); |
| | | |
| | | i = 0; |
| | | |
| | | for (j=0 ; j<d->size ; j++) { |
| | | if (d->key[j]==NULL) |
| | | continue ; |
| | | if (!strncmp(d->key[j], keym, seclen+1)) { |
| | | keys[i] = d->key[j]; |
| | | i++; |
| | | } |
| | | } |
| | | |
| | | return keys; |
| | | |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get the string associated to a key |
| | | @param d Dictionary to search |
| | | @param key Key string to look for |
| | | @param def Default value to return if key not found. |
| | | @return pointer to statically allocated character string |
| | | |
| | | This function queries a dictionary for a key. A key as read from an |
| | | ini file is given as "section:key". If the key cannot be found, |
| | | the pointer passed as 'def' is returned. |
| | | The returned char pointer is pointing to a string allocated in |
| | | the dictionary, do not free or modify it. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | char * iniparser_getstring(dictionary * d, const char * key, char * def) |
| | | { |
| | | char * lc_key ; |
| | | char * sval ; |
| | | |
| | | if (d==NULL || key==NULL) |
| | | return def ; |
| | | |
| | | lc_key = strlwc(key); |
| | | sval = dictionary_get(d, lc_key, def); |
| | | return sval ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get the string associated to a key, convert to an int |
| | | @param d Dictionary to search |
| | | @param key Key string to look for |
| | | @param notfound Value to return in case of error |
| | | @return integer |
| | | |
| | | This function queries a dictionary for a key. A key as read from an |
| | | ini file is given as "section:key". If the key cannot be found, |
| | | the notfound value is returned. |
| | | |
| | | Supported values for integers include the usual C notation |
| | | so decimal, octal (starting with 0) and hexadecimal (starting with 0x) |
| | | are supported. Examples: |
| | | |
| | | "42" -> 42 |
| | | "042" -> 34 (octal -> decimal) |
| | | "0x42" -> 66 (hexa -> decimal) |
| | | |
| | | Warning: the conversion may overflow in various ways. Conversion is |
| | | totally outsourced to strtol(), see the associated man page for overflow |
| | | handling. |
| | | |
| | | Credits: Thanks to A. Becker for suggesting strtol() |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | int iniparser_getint(dictionary * d, const char * key, int notfound) |
| | | { |
| | | char * str ; |
| | | |
| | | str = iniparser_getstring(d, key, INI_INVALID_KEY); |
| | | if (str==INI_INVALID_KEY) return notfound ; |
| | | return (int)strtol(str, NULL, 0); |
| | | } |
| | | |
| | | int iniparser_getlong(dictionary * d, const char * key, int notfound) |
| | | { |
| | | char * str ; |
| | | |
| | | str = iniparser_getstring(d, key, INI_INVALID_KEY); |
| | | if (str==INI_INVALID_KEY) return notfound ; |
| | | return strtol(str, NULL, 0); |
| | | } |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get the string associated to a key, convert to a double |
| | | @param d Dictionary to search |
| | | @param key Key string to look for |
| | | @param notfound Value to return in case of error |
| | | @return double |
| | | |
| | | This function queries a dictionary for a key. A key as read from an |
| | | ini file is given as "section:key". If the key cannot be found, |
| | | the notfound value is returned. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | double iniparser_getdouble(dictionary * d, const char * key, double notfound) |
| | | { |
| | | char * str ; |
| | | |
| | | str = iniparser_getstring(d, key, INI_INVALID_KEY); |
| | | if (str==INI_INVALID_KEY) return notfound ; |
| | | return atof(str); |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get the string associated to a key, convert to a boolean |
| | | @param d Dictionary to search |
| | | @param key Key string to look for |
| | | @param notfound Value to return in case of error |
| | | @return integer |
| | | |
| | | This function queries a dictionary for a key. A key as read from an |
| | | ini file is given as "section:key". If the key cannot be found, |
| | | the notfound value is returned. |
| | | |
| | | A true boolean is found if one of the following is matched: |
| | | |
| | | - A string starting with 'y' |
| | | - A string starting with 'Y' |
| | | - A string starting with 't' |
| | | - A string starting with 'T' |
| | | - A string starting with '1' |
| | | |
| | | A false boolean is found if one of the following is matched: |
| | | |
| | | - A string starting with 'n' |
| | | - A string starting with 'N' |
| | | - A string starting with 'f' |
| | | - A string starting with 'F' |
| | | - A string starting with '0' |
| | | |
| | | The notfound value returned if no boolean is identified, does not |
| | | necessarily have to be 0 or 1. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | int iniparser_getboolean(dictionary * d, const char * key, int notfound) |
| | | { |
| | | char * c ; |
| | | int ret ; |
| | | |
| | | c = iniparser_getstring(d, key, INI_INVALID_KEY); |
| | | if (c==INI_INVALID_KEY) return notfound ; |
| | | if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') { |
| | | ret = 1 ; |
| | | } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') { |
| | | ret = 0 ; |
| | | } else { |
| | | ret = notfound ; |
| | | } |
| | | return ret; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Finds out if a given entry exists in a dictionary |
| | | @param ini Dictionary to search |
| | | @param entry Name of the entry to look for |
| | | @return integer 1 if entry exists, 0 otherwise |
| | | |
| | | Finds out if a given entry exists in the dictionary. Since sections |
| | | are stored as keys with NULL associated values, this is the only way |
| | | of querying for the presence of sections in a dictionary. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | int iniparser_find_entry( |
| | | dictionary * ini, |
| | | const char * entry |
| | | ) |
| | | { |
| | | int found=0 ; |
| | | if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) { |
| | | found = 1 ; |
| | | } |
| | | return found ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Set an entry in a dictionary. |
| | | @param ini Dictionary to modify. |
| | | @param entry Entry to modify (entry name) |
| | | @param val New value to associate to the entry. |
| | | @return int 0 if Ok, -1 otherwise. |
| | | |
| | | If the given entry can be found in the dictionary, it is modified to |
| | | contain the provided value. If it cannot be found, -1 is returned. |
| | | It is Ok to set val to NULL. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | int iniparser_set(dictionary * ini, const char * entry, const char * val) |
| | | { |
| | | return dictionary_set(ini, strlwc(entry), val) ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Delete an entry in a dictionary |
| | | @param ini Dictionary to modify |
| | | @param entry Entry to delete (entry name) |
| | | @return void |
| | | |
| | | If the given entry can be found, it is deleted from the dictionary. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void iniparser_unset(dictionary * ini, const char * entry) |
| | | { |
| | | dictionary_unset(ini, strlwc(entry)); |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Load a single line from an INI file |
| | | @param input_line Input line, may be concatenated multi-line input |
| | | @param section Output space to store section |
| | | @param key Output space to store key |
| | | @param value Output space to store value |
| | | @return line_status value |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | static line_status iniparser_line( |
| | | char * input_line, |
| | | char * section, |
| | | char * key, |
| | | char * value) |
| | | { |
| | | line_status sta ; |
| | | char line[ASCIILINESZ+1]; |
| | | static char left_line[ASCIILINESZ+1]; |
| | | int len, offset ; |
| | | |
| | | strcpy(line, strstrip(input_line)); |
| | | len = (int)strlen(line); |
| | | |
| | | sta = LINE_UNPROCESSED ; |
| | | if (len<1) { |
| | | /* Empty line */ |
| | | sta = LINE_EMPTY ; |
| | | memset(input_line, 0, len); |
| | | } else if (line[0]=='#' || line[0]==';') { |
| | | /* Comment line */ |
| | | sta = LINE_COMMENT ; |
| | | memset(input_line, 0, len); |
| | | } else if (line[0]=='[') { |
| | | /* Section name */ |
| | | sscanf(line, "[%[^]]", section); |
| | | strcpy(section, strstrip(section)); |
| | | strcpy(section, strlwc(section)); |
| | | |
| | | /* Left configure will go to next time to parser */ |
| | | offset = strlen(section) + 2; |
| | | strcpy( left_line, strstrip(&(line[offset])) ); |
| | | strcpy( left_line, strstrip(left_line)); |
| | | |
| | | if( strlen(left_line) > 0) |
| | | { |
| | | strcpy(input_line, left_line); |
| | | strcat(input_line, "\n"); |
| | | } |
| | | else |
| | | { |
| | | memset(input_line, 0, len); |
| | | } |
| | | sta = LINE_SECTION ; |
| | | } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2 |
| | | || sscanf (line, "%[^=] = '%[^\']'", key, value) == 2 |
| | | || sscanf (line, "%[^=] = %[^;#]", key, value) == 2) { |
| | | char *ptr = NULL; |
| | | |
| | | /* Usual key=value, with or without comments */ |
| | | strcpy(key, strstrip(key)); |
| | | strcpy(key, strlwc(key)); |
| | | strcpy(value, strstrip(value)); |
| | | /* |
| | | * sscanf cannot handle '' or "" as empty values |
| | | * this is done here |
| | | */ |
| | | if (!strncmp(value, "\"\"", 2) || (!strncmp(value, "''", 2)) ) { |
| | | value[0]=0 ; |
| | | } |
| | | |
| | | ptr = strchr(line, '='); |
| | | if('\''==*(ptr+1) || '\"'==*(ptr+1)) |
| | | { |
| | | offset = strlen(key)+strlen(value) + 1 + 2; /* Skip $key='$val' */ |
| | | } |
| | | else |
| | | { |
| | | offset = strlen(key)+strlen(value) + 1; /* Skip $key=$val */ |
| | | } |
| | | strcpy( left_line, strstrip(&(line[offset])) ); |
| | | |
| | | if( strlen(left_line) > 0) |
| | | { |
| | | strcpy(input_line, left_line); |
| | | strcat(input_line, "\n"); |
| | | } |
| | | else |
| | | { |
| | | memset(input_line, 0, len); |
| | | } |
| | | sta = LINE_VALUE ; |
| | | } else if (sscanf(line, "%[^=] = %[;#]", key, value)==2 |
| | | || sscanf(line, "%[^=] %[=]", key, value) == 2) { |
| | | /* |
| | | * Special cases: |
| | | * key= |
| | | * key=; |
| | | * key=# |
| | | */ |
| | | strcpy(key, strstrip(key)); |
| | | strcpy(key, strlwc(key)); |
| | | value[0]=0 ; |
| | | sta = LINE_VALUE ; |
| | | } else { |
| | | /* Generate syntax error */ |
| | | sta = LINE_ERROR ; |
| | | memset(input_line, 0, len); |
| | | } |
| | | return sta ; |
| | | } |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Parse an ini file and return an allocated dictionary object |
| | | @param ininame Name of the ini file to read. |
| | | @return Pointer to newly allocated dictionary |
| | | |
| | | This is the parser for ini files. This function is called, providing |
| | | the name of the file to be read. It returns a dictionary object that |
| | | should not be accessed directly, but through accessor functions |
| | | instead. |
| | | |
| | | The returned dictionary must be freed using iniparser_freedict(). |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | dictionary * iniparser_load(const char * ininame) |
| | | { |
| | | FILE * in ; |
| | | |
| | | char line [ASCIILINESZ+1] ; |
| | | char section [ASCIILINESZ+1] ; |
| | | char key [ASCIILINESZ+1] ; |
| | | char tmp [ASCIILINESZ+1] ; |
| | | char val [ASCIILINESZ+1] ; |
| | | |
| | | int last=0 ; |
| | | int len ; |
| | | int lineno=0 ; |
| | | int errs=0; |
| | | |
| | | dictionary * dict ; |
| | | |
| | | if ((in=fopen(ininame, "r"))==NULL) { |
| | | fprintf(stderr, "iniparser: cannot open %s\n", ininame); |
| | | return NULL ; |
| | | } |
| | | |
| | | dict = dictionary_new(0) ; |
| | | if (!dict) { |
| | | fclose(in); |
| | | return NULL ; |
| | | } |
| | | |
| | | memset(line, 0, ASCIILINESZ); |
| | | memset(section, 0, ASCIILINESZ); |
| | | memset(key, 0, ASCIILINESZ); |
| | | memset(val, 0, ASCIILINESZ); |
| | | last=0 ; |
| | | |
| | | while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) { |
| | | lineno++ ; |
| | | CONTINUE_PARSER: |
| | | len = (int)strlen(line)-1; |
| | | if (len==0) |
| | | continue; |
| | | /* Safety check against buffer overflows */ |
| | | if (line[len]!='\n') { |
| | | fprintf(stderr, |
| | | "iniparser: input line too long in %s (%d)\n", |
| | | ininame, |
| | | lineno); |
| | | dictionary_del(dict); |
| | | fclose(in); |
| | | return NULL ; |
| | | } |
| | | /* Get rid of \n and spaces at end of line */ |
| | | while ((len>=0) && |
| | | ((line[len]=='\n') || (isspace(line[len])))) { |
| | | line[len]=0 ; |
| | | len-- ; |
| | | } |
| | | /* Detect multi-line */ |
| | | if (line[len]=='\\') { |
| | | /* Multi-line value */ |
| | | last=len ; |
| | | continue ; |
| | | } else { |
| | | last=0 ; |
| | | } |
| | | |
| | | switch ( iniparser_line(line, section, key, val) ) { |
| | | case LINE_EMPTY: |
| | | case LINE_COMMENT: |
| | | break ; |
| | | |
| | | case LINE_SECTION: |
| | | errs = dictionary_set(dict, section, NULL); |
| | | break ; |
| | | |
| | | case LINE_VALUE: |
| | | sprintf(tmp, "%s:%s", section, key); |
| | | errs = dictionary_set(dict, tmp, val) ; |
| | | break ; |
| | | |
| | | case LINE_ERROR: |
| | | fprintf(stderr, "iniparser: syntax error in %s (%d):\n", |
| | | ininame, |
| | | lineno); |
| | | fprintf(stderr, "-> %s\n", line); |
| | | errs++ ; |
| | | break; |
| | | |
| | | default: |
| | | break ; |
| | | } |
| | | |
| | | if( strlen(line) > 0) |
| | | { |
| | | goto CONTINUE_PARSER; |
| | | } |
| | | |
| | | memset(line, 0, ASCIILINESZ); |
| | | last=0; |
| | | if (errs<0) { |
| | | fprintf(stderr, "iniparser: memory allocation failure\n"); |
| | | break ; |
| | | } |
| | | } |
| | | if (errs) { |
| | | dictionary_del(dict); |
| | | dict = NULL ; |
| | | } |
| | | fclose(in); |
| | | return dict ; |
| | | } |
| | | |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Free all memory associated to an ini dictionary |
| | | @param d Dictionary to free |
| | | @return void |
| | | |
| | | Free all memory associated to an ini dictionary. |
| | | It is mandatory to call this function before the dictionary object |
| | | gets out of the current context. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void iniparser_freedict(dictionary * d) |
| | | { |
| | | dictionary_del(d); |
| | | } |
| | | |
| | | /* vim: set ts=4 et sw=4 tw=75 */ |
New file |
| | |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @file cp_iniparser.h |
| | | @author N. Devillard |
| | | @brief Parser for ini files. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | |
| | | #ifndef _CP_INIPARSER_H_ |
| | | #define _CP_INIPARSER_H_ |
| | | |
| | | /*--------------------------------------------------------------------------- |
| | | Includes |
| | | ---------------------------------------------------------------------------*/ |
| | | |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | |
| | | /* |
| | | * The following #include is necessary on many Unixes but not Linux. |
| | | * It is not needed for Windows platforms. |
| | | * Uncomment it if needed. |
| | | */ |
| | | /* #include <unistd.h> */ |
| | | |
| | | #include "cp_dictionary.h" |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get number of sections in a dictionary |
| | | @param d Dictionary to examine |
| | | @return int Number of sections found in dictionary |
| | | |
| | | This function returns the number of sections found in a dictionary. |
| | | The test to recognize sections is done on the string stored in the |
| | | dictionary: a section name is given as "section" whereas a key is |
| | | stored as "section:key", thus the test looks for entries that do not |
| | | contain a colon. |
| | | |
| | | This clearly fails in the case a section name contains a colon, but |
| | | this should simply be avoided. |
| | | |
| | | This function returns -1 in case of error. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | |
| | | int iniparser_getnsec(dictionary * d); |
| | | |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get name for section n in a dictionary. |
| | | @param d Dictionary to examine |
| | | @param n Section number (from 0 to nsec-1). |
| | | @return Pointer to char string |
| | | |
| | | This function locates the n-th section in a dictionary and returns |
| | | its name as a pointer to a string statically allocated inside the |
| | | dictionary. Do not free or modify the returned string! |
| | | |
| | | This function returns NULL in case of error. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | |
| | | char * iniparser_getsecname(dictionary * d, int n); |
| | | |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Save a dictionary to a loadable ini file |
| | | @param d Dictionary to dump |
| | | @param f Opened file pointer to dump to |
| | | @return void |
| | | |
| | | This function dumps a given dictionary into a loadable ini file. |
| | | It is Ok to specify @c stderr or @c stdout as output files. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | |
| | | void iniparser_dump_ini(dictionary * d, FILE * f); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Save a dictionary section to a loadable ini file |
| | | @param d Dictionary to dump |
| | | @param s Section name of dictionary to dump |
| | | @param f Opened file pointer to dump to |
| | | @return void |
| | | |
| | | This function dumps a given section of a given dictionary into a loadable ini |
| | | file. It is Ok to specify @c stderr or @c stdout as output files. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | |
| | | void iniparser_dumpsection_ini(dictionary * d, char * s, FILE * f); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Dump a dictionary to an opened file pointer. |
| | | @param d Dictionary to dump. |
| | | @param f Opened file pointer to dump to. |
| | | @return void |
| | | |
| | | This function prints out the contents of a dictionary, one element by |
| | | line, onto the provided file pointer. It is OK to specify @c stderr |
| | | or @c stdout as output files. This function is meant for debugging |
| | | purposes mostly. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void iniparser_dump(dictionary * d, FILE * f); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get the number of keys in a section of a dictionary. |
| | | @param d Dictionary to examine |
| | | @param s Section name of dictionary to examine |
| | | @return Number of keys in section |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | int iniparser_getsecnkeys(dictionary * d, char * s); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get the number of keys in a section of a dictionary. |
| | | @param d Dictionary to examine |
| | | @param s Section name of dictionary to examine |
| | | @return pointer to statically allocated character strings |
| | | |
| | | This function queries a dictionary and finds all keys in a given section. |
| | | Each pointer in the returned char pointer-to-pointer is pointing to |
| | | a string allocated in the dictionary; do not free or modify them. |
| | | |
| | | This function returns NULL in case of error. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | char ** iniparser_getseckeys(dictionary * d, char * s); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get the string associated to a key |
| | | @param d Dictionary to search |
| | | @param key Key string to look for |
| | | @param def Default value to return if key not found. |
| | | @return pointer to statically allocated character string |
| | | |
| | | This function queries a dictionary for a key. A key as read from an |
| | | ini file is given as "section:key". If the key cannot be found, |
| | | the pointer passed as 'def' is returned. |
| | | The returned char pointer is pointing to a string allocated in |
| | | the dictionary, do not free or modify it. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | char * iniparser_getstring(dictionary * d, const char * key, char * def); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get the string associated to a key, convert to an int |
| | | @param d Dictionary to search |
| | | @param key Key string to look for |
| | | @param notfound Value to return in case of error |
| | | @return integer |
| | | |
| | | This function queries a dictionary for a key. A key as read from an |
| | | ini file is given as "section:key". If the key cannot be found, |
| | | the notfound value is returned. |
| | | |
| | | Supported values for integers include the usual C notation |
| | | so decimal, octal (starting with 0) and hexadecimal (starting with 0x) |
| | | are supported. Examples: |
| | | |
| | | - "42" -> 42 |
| | | - "042" -> 34 (octal -> decimal) |
| | | - "0x42" -> 66 (hexa -> decimal) |
| | | |
| | | Warning: the conversion may overflow in various ways. Conversion is |
| | | totally outsourced to strtol(), see the associated man page for overflow |
| | | handling. |
| | | |
| | | Credits: Thanks to A. Becker for suggesting strtol() |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | int iniparser_getint(dictionary * d, const char * key, int notfound); |
| | | int iniparser_getlong(dictionary * d, const char * key, int notfound); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get the string associated to a key, convert to a double |
| | | @param d Dictionary to search |
| | | @param key Key string to look for |
| | | @param notfound Value to return in case of error |
| | | @return double |
| | | |
| | | This function queries a dictionary for a key. A key as read from an |
| | | ini file is given as "section:key". If the key cannot be found, |
| | | the notfound value is returned. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | double iniparser_getdouble(dictionary * d, const char * key, double notfound); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Get the string associated to a key, convert to a boolean |
| | | @param d Dictionary to search |
| | | @param key Key string to look for |
| | | @param notfound Value to return in case of error |
| | | @return integer |
| | | |
| | | This function queries a dictionary for a key. A key as read from an |
| | | ini file is given as "section:key". If the key cannot be found, |
| | | the notfound value is returned. |
| | | |
| | | A true boolean is found if one of the following is matched: |
| | | |
| | | - A string starting with 'y' |
| | | - A string starting with 'Y' |
| | | - A string starting with 't' |
| | | - A string starting with 'T' |
| | | - A string starting with '1' |
| | | |
| | | A false boolean is found if one of the following is matched: |
| | | |
| | | - A string starting with 'n' |
| | | - A string starting with 'N' |
| | | - A string starting with 'f' |
| | | - A string starting with 'F' |
| | | - A string starting with '0' |
| | | |
| | | The notfound value returned if no boolean is identified, does not |
| | | necessarily have to be 0 or 1. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | int iniparser_getboolean(dictionary * d, const char * key, int notfound); |
| | | |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Set an entry in a dictionary. |
| | | @param ini Dictionary to modify. |
| | | @param entry Entry to modify (entry name) |
| | | @param val New value to associate to the entry. |
| | | @return int 0 if Ok, -1 otherwise. |
| | | |
| | | If the given entry can be found in the dictionary, it is modified to |
| | | contain the provided value. If it cannot be found, -1 is returned. |
| | | It is Ok to set val to NULL. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | int iniparser_set(dictionary * ini, const char * entry, const char * val); |
| | | |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Delete an entry in a dictionary |
| | | @param ini Dictionary to modify |
| | | @param entry Entry to delete (entry name) |
| | | @return void |
| | | |
| | | If the given entry can be found, it is deleted from the dictionary. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void iniparser_unset(dictionary * ini, const char * entry); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Finds out if a given entry exists in a dictionary |
| | | @param ini Dictionary to search |
| | | @param entry Name of the entry to look for |
| | | @return integer 1 if entry exists, 0 otherwise |
| | | |
| | | Finds out if a given entry exists in the dictionary. Since sections |
| | | are stored as keys with NULL associated values, this is the only way |
| | | of querying for the presence of sections in a dictionary. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | int iniparser_find_entry(dictionary * ini, const char * entry) ; |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Parse an ini file and return an allocated dictionary object |
| | | @param ininame Name of the ini file to read. |
| | | @return Pointer to newly allocated dictionary |
| | | |
| | | This is the parser for ini files. This function is called, providing |
| | | the name of the file to be read. It returns a dictionary object that |
| | | should not be accessed directly, but through accessor functions |
| | | instead. |
| | | |
| | | The returned dictionary must be freed using iniparser_freedict(). |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | dictionary * iniparser_load(const char * ininame); |
| | | |
| | | /*-------------------------------------------------------------------------*/ |
| | | /** |
| | | @brief Free all memory associated to an ini dictionary |
| | | @param d Dictionary to free |
| | | @return void |
| | | |
| | | Free all memory associated to an ini dictionary. |
| | | It is mandatory to call this function before the dictionary object |
| | | gets out of the current context. |
| | | */ |
| | | /*--------------------------------------------------------------------------*/ |
| | | void iniparser_freedict(dictionary * d); |
| | | |
| | | #endif |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2012 Guo Wenxue <guowenxue@gmail.com> |
| | | * All rights reserved. |
| | | * |
| | | * Filename: cp_list.h |
| | | * Description: This file is copied from Linux kernel, which provide link list API. |
| | | * |
| | | * Version: 1.0.0(08/09/2012~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "08/09/2012 02:24:34 AM" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #ifndef _LINUX_LIST_H |
| | | #define _LINUX_LIST_H |
| | | |
| | | #include <linux/stddef.h> |
| | | |
| | | |
| | | /** |
| | | * container_of - cast a member of a structure out to the containing structure |
| | | * @ptr: the pointer to the member. |
| | | * @type: the type of the container struct this is embedded in. |
| | | * @member: the name of the member within the struct. |
| | | * |
| | | */ |
| | | #undef offsetof |
| | | #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) |
| | | #define container_of(ptr, type, member) ({ \ |
| | | const typeof( ((type *)0)->member ) *__mptr = (ptr); \ |
| | | (type *)( (char *)__mptr - offsetof(type,member) );}) |
| | | |
| | | |
| | | /* |
| | | * Architectures might want to move the poison pointer offset |
| | | * into some well-recognized area such as 0xdead000000000000, |
| | | * that is also not mappable by user-space exploits: |
| | | */ |
| | | #ifdef CONFIG_ILLEGAL_POINTER_VALUE |
| | | # define POISON_POINTER_DELTA _AC(CONFIG_ILLEGAL_POINTER_VALUE, UL) |
| | | #else |
| | | # define POISON_POINTER_DELTA 0 |
| | | #endif |
| | | |
| | | /* |
| | | * These are non-NULL pointers that will result in page faults |
| | | * under normal circumstances, used to verify that nobody uses |
| | | * non-initialized list entries. |
| | | */ |
| | | #define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA) |
| | | #define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA) |
| | | |
| | | #ifndef ARCH_HAS_PREFETCH |
| | | #define ARCH_HAS_PREFETCH |
| | | static inline void prefetch(const void *x) {;} |
| | | #endif |
| | | |
| | | /* |
| | | * Simple doubly linked list implementation. |
| | | * |
| | | * Some of the internal functions ("__xxx") are useful when |
| | | * manipulating whole lists rather than single entries, as |
| | | * sometimes we already know the next/prev entries and we can |
| | | * generate better code by using them directly rather than |
| | | * using the generic single-entry routines. |
| | | */ |
| | | |
| | | struct list_head { |
| | | struct list_head *next, *prev; |
| | | }; |
| | | |
| | | #define LIST_HEAD_INIT(name) { &(name), &(name) } |
| | | |
| | | #define LIST_HEAD(name) \ |
| | | struct list_head name = LIST_HEAD_INIT(name) |
| | | |
| | | static inline void INIT_LIST_HEAD(struct list_head *list) |
| | | { |
| | | list->next = list; |
| | | list->prev = list; |
| | | } |
| | | |
| | | /* |
| | | * Insert a new entry between two known consecutive entries. |
| | | * |
| | | * This is only for internal list manipulation where we know |
| | | * the prev/next entries already! |
| | | */ |
| | | static inline void __list_add(struct list_head *new, |
| | | struct list_head *prev, |
| | | struct list_head *next) |
| | | { |
| | | next->prev = new; |
| | | new->next = next; |
| | | new->prev = prev; |
| | | prev->next = new; |
| | | } |
| | | |
| | | /** |
| | | * list_add - add a new entry |
| | | * @new: new entry to be added |
| | | * @head: list head to add it after |
| | | * |
| | | * Insert a new entry after the specified head. |
| | | * This is good for implementing stacks. |
| | | */ |
| | | static inline void list_add(struct list_head *new, struct list_head *head) |
| | | { |
| | | __list_add(new, head, head->next); |
| | | } |
| | | |
| | | /** |
| | | * list_add_tail - add a new entry |
| | | * @new: new entry to be added |
| | | * @head: list head to add it before |
| | | * |
| | | * Insert a new entry before the specified head. |
| | | * This is useful for implementing queues. |
| | | */ |
| | | static inline void list_add_tail(struct list_head *new, struct list_head *head) |
| | | { |
| | | __list_add(new, head->prev, head); |
| | | } |
| | | |
| | | /* |
| | | * Delete a list entry by making the prev/next entries |
| | | * point to each other. |
| | | * |
| | | * This is only for internal list manipulation where we know |
| | | * the prev/next entries already! |
| | | */ |
| | | static inline void __list_del(struct list_head *prev, struct list_head *next) |
| | | { |
| | | next->prev = prev; |
| | | prev->next = next; |
| | | } |
| | | |
| | | /** |
| | | * list_del - deletes entry from list. |
| | | * @entry: the element to delete from the list. |
| | | * Note: list_empty() on entry does not return true after this, the entry is |
| | | * in an undefined state. |
| | | */ |
| | | static inline void list_del(struct list_head *entry) |
| | | { |
| | | __list_del(entry->prev, entry->next); |
| | | entry->next = LIST_POISON1; |
| | | entry->prev = LIST_POISON2; |
| | | } |
| | | |
| | | /** |
| | | * list_replace - replace old entry by new one |
| | | * @old : the element to be replaced |
| | | * @new : the new element to insert |
| | | * |
| | | * If @old was empty, it will be overwritten. |
| | | */ |
| | | static inline void list_replace(struct list_head *old, |
| | | struct list_head *new) |
| | | { |
| | | new->next = old->next; |
| | | new->next->prev = new; |
| | | new->prev = old->prev; |
| | | new->prev->next = new; |
| | | } |
| | | |
| | | static inline void list_replace_init(struct list_head *old, |
| | | struct list_head *new) |
| | | { |
| | | list_replace(old, new); |
| | | INIT_LIST_HEAD(old); |
| | | } |
| | | |
| | | /** |
| | | * list_del_init - deletes entry from list and reinitialize it. |
| | | * @entry: the element to delete from the list. |
| | | */ |
| | | static inline void list_del_init(struct list_head *entry) |
| | | { |
| | | __list_del(entry->prev, entry->next); |
| | | INIT_LIST_HEAD(entry); |
| | | } |
| | | |
| | | /** |
| | | * list_move - delete from one list and add as another's head |
| | | * @list: the entry to move |
| | | * @head: the head that will precede our entry |
| | | */ |
| | | static inline void list_move(struct list_head *list, struct list_head *head) |
| | | { |
| | | __list_del(list->prev, list->next); |
| | | list_add(list, head); |
| | | } |
| | | |
| | | /** |
| | | * list_move_tail - delete from one list and add as another's tail |
| | | * @list: the entry to move |
| | | * @head: the head that will follow our entry |
| | | */ |
| | | static inline void list_move_tail(struct list_head *list, |
| | | struct list_head *head) |
| | | { |
| | | __list_del(list->prev, list->next); |
| | | list_add_tail(list, head); |
| | | } |
| | | |
| | | /** |
| | | * list_is_last - tests whether @list is the last entry in list @head |
| | | * @list: the entry to test |
| | | * @head: the head of the list |
| | | */ |
| | | static inline int list_is_last(const struct list_head *list, |
| | | const struct list_head *head) |
| | | { |
| | | return list->next == head; |
| | | } |
| | | |
| | | /** |
| | | * list_empty - tests whether a list is empty |
| | | * @head: the list to test. |
| | | */ |
| | | static inline int list_empty(const struct list_head *head) |
| | | { |
| | | return head->next == head; |
| | | } |
| | | |
| | | /** |
| | | * list_empty_careful - tests whether a list is empty and not being modified |
| | | * @head: the list to test |
| | | * |
| | | * Description: |
| | | * tests whether a list is empty _and_ checks that no other CPU might be |
| | | * in the process of modifying either member (next or prev) |
| | | * |
| | | * NOTE: using list_empty_careful() without synchronization |
| | | * can only be safe if the only activity that can happen |
| | | * to the list entry is list_del_init(). Eg. it cannot be used |
| | | * if another CPU could re-list_add() it. |
| | | */ |
| | | static inline int list_empty_careful(const struct list_head *head) |
| | | { |
| | | struct list_head *next = head->next; |
| | | return (next == head) && (next == head->prev); |
| | | } |
| | | |
| | | /** |
| | | * list_is_singular - tests whether a list has just one entry. |
| | | * @head: the list to test. |
| | | */ |
| | | static inline int list_is_singular(const struct list_head *head) |
| | | { |
| | | return !list_empty(head) && (head->next == head->prev); |
| | | } |
| | | |
| | | static inline void __list_cut_position(struct list_head *list, |
| | | struct list_head *head, struct list_head *entry) |
| | | { |
| | | struct list_head *new_first = entry->next; |
| | | list->next = head->next; |
| | | list->next->prev = list; |
| | | list->prev = entry; |
| | | entry->next = list; |
| | | head->next = new_first; |
| | | new_first->prev = head; |
| | | } |
| | | |
| | | /** |
| | | * list_cut_position - cut a list into two |
| | | * @list: a new list to add all removed entries |
| | | * @head: a list with entries |
| | | * @entry: an entry within head, could be the head itself |
| | | * and if so we won't cut the list |
| | | * |
| | | * This helper moves the initial part of @head, up to and |
| | | * including @entry, from @head to @list. You should |
| | | * pass on @entry an element you know is on @head. @list |
| | | * should be an empty list or a list you do not care about |
| | | * losing its data. |
| | | * |
| | | */ |
| | | static inline void list_cut_position(struct list_head *list, |
| | | struct list_head *head, struct list_head *entry) |
| | | { |
| | | if (list_empty(head)) |
| | | return; |
| | | if (list_is_singular(head) && |
| | | (head->next != entry && head != entry)) |
| | | return; |
| | | if (entry == head) |
| | | INIT_LIST_HEAD(list); |
| | | else |
| | | __list_cut_position(list, head, entry); |
| | | } |
| | | |
| | | static inline void __list_splice(const struct list_head *list, |
| | | struct list_head *prev, |
| | | struct list_head *next) |
| | | { |
| | | struct list_head *first = list->next; |
| | | struct list_head *last = list->prev; |
| | | |
| | | first->prev = prev; |
| | | prev->next = first; |
| | | |
| | | last->next = next; |
| | | next->prev = last; |
| | | } |
| | | |
| | | /** |
| | | * list_splice - join two lists, this is designed for stacks |
| | | * @list: the new list to add. |
| | | * @head: the place to add it in the first list. |
| | | */ |
| | | static inline void list_splice(const struct list_head *list, |
| | | struct list_head *head) |
| | | { |
| | | if (!list_empty(list)) |
| | | __list_splice(list, head, head->next); |
| | | } |
| | | |
| | | /** |
| | | * list_splice_tail - join two lists, each list being a queue |
| | | * @list: the new list to add. |
| | | * @head: the place to add it in the first list. |
| | | */ |
| | | static inline void list_splice_tail(struct list_head *list, |
| | | struct list_head *head) |
| | | { |
| | | if (!list_empty(list)) |
| | | __list_splice(list, head->prev, head); |
| | | } |
| | | |
| | | /** |
| | | * list_splice_init - join two lists and reinitialise the emptied list. |
| | | * @list: the new list to add. |
| | | * @head: the place to add it in the first list. |
| | | * |
| | | * The list at @list is reinitialised |
| | | */ |
| | | static inline void list_splice_init(struct list_head *list, |
| | | struct list_head *head) |
| | | { |
| | | if (!list_empty(list)) { |
| | | __list_splice(list, head, head->next); |
| | | INIT_LIST_HEAD(list); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * list_splice_tail_init - join two lists and reinitialise the emptied list |
| | | * @list: the new list to add. |
| | | * @head: the place to add it in the first list. |
| | | * |
| | | * Each of the lists is a queue. |
| | | * The list at @list is reinitialised |
| | | */ |
| | | static inline void list_splice_tail_init(struct list_head *list, |
| | | struct list_head *head) |
| | | { |
| | | if (!list_empty(list)) { |
| | | __list_splice(list, head->prev, head); |
| | | INIT_LIST_HEAD(list); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * list_entry - get the struct for this entry |
| | | * @ptr: the &struct list_head pointer. |
| | | * @type: the type of the struct this is embedded in. |
| | | * @member: the name of the list_struct within the struct. |
| | | */ |
| | | #define list_entry(ptr, type, member) \ |
| | | container_of(ptr, type, member) |
| | | |
| | | /** |
| | | * list_first_entry - get the first element from a list |
| | | * @ptr: the list head to take the element from. |
| | | * @type: the type of the struct this is embedded in. |
| | | * @member: the name of the list_struct within the struct. |
| | | * |
| | | * Note, that list is expected to be not empty. |
| | | */ |
| | | #define list_first_entry(ptr, type, member) \ |
| | | list_entry((ptr)->next, type, member) |
| | | |
| | | /** |
| | | * list_for_each - iterate over a list |
| | | * @pos: the &struct list_head to use as a loop cursor. |
| | | * @head: the head for your list. |
| | | */ |
| | | #define list_for_each(pos, head) \ |
| | | for (pos = (head)->next; prefetch(pos->next), pos != (head); \ |
| | | pos = pos->next) |
| | | |
| | | /** |
| | | * __list_for_each - iterate over a list |
| | | * @pos: the &struct list_head to use as a loop cursor. |
| | | * @head: the head for your list. |
| | | * |
| | | * This variant differs from list_for_each() in that it's the |
| | | * simplest possible list iteration code, no prefetching is done. |
| | | * Use this for code that knows the list to be very short (empty |
| | | * or 1 entry) most of the time. |
| | | */ |
| | | #define __list_for_each(pos, head) \ |
| | | for (pos = (head)->next; pos != (head); pos = pos->next) |
| | | |
| | | /** |
| | | * list_for_each_prev - iterate over a list backwards |
| | | * @pos: the &struct list_head to use as a loop cursor. |
| | | * @head: the head for your list. |
| | | */ |
| | | #define list_for_each_prev(pos, head) \ |
| | | for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ |
| | | pos = pos->prev) |
| | | |
| | | /** |
| | | * list_for_each_safe - iterate over a list safe against removal of list entry |
| | | * @pos: the &struct list_head to use as a loop cursor. |
| | | * @n: another &struct list_head to use as temporary storage |
| | | * @head: the head for your list. |
| | | */ |
| | | #define list_for_each_safe(pos, n, head) \ |
| | | for (pos = (head)->next, n = pos->next; pos != (head); \ |
| | | pos = n, n = pos->next) |
| | | |
| | | /** |
| | | * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry |
| | | * @pos: the &struct list_head to use as a loop cursor. |
| | | * @n: another &struct list_head to use as temporary storage |
| | | * @head: the head for your list. |
| | | */ |
| | | #define list_for_each_prev_safe(pos, n, head) \ |
| | | for (pos = (head)->prev, n = pos->prev; \ |
| | | prefetch(pos->prev), pos != (head); \ |
| | | pos = n, n = pos->prev) |
| | | |
| | | /** |
| | | * list_for_each_entry - iterate over list of given type |
| | | * @pos: the type * to use as a loop cursor. |
| | | * @head: the head for your list. |
| | | * @member: the name of the list_struct within the struct. |
| | | */ |
| | | #define list_for_each_entry(pos, head, member) \ |
| | | for (pos = list_entry((head)->next, typeof(*pos), member); \ |
| | | prefetch(pos->member.next), &pos->member != (head); \ |
| | | pos = list_entry(pos->member.next, typeof(*pos), member)) |
| | | |
| | | /** |
| | | * list_for_each_entry_reverse - iterate backwards over list of given type. |
| | | * @pos: the type * to use as a loop cursor. |
| | | * @head: the head for your list. |
| | | * @member: the name of the list_struct within the struct. |
| | | */ |
| | | #define list_for_each_entry_reverse(pos, head, member) \ |
| | | for (pos = list_entry((head)->prev, typeof(*pos), member); \ |
| | | prefetch(pos->member.prev), &pos->member != (head); \ |
| | | pos = list_entry(pos->member.prev, typeof(*pos), member)) |
| | | |
| | | /** |
| | | * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() |
| | | * @pos: the type * to use as a start point |
| | | * @head: the head of the list |
| | | * @member: the name of the list_struct within the struct. |
| | | * |
| | | * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). |
| | | */ |
| | | #define list_prepare_entry(pos, head, member) \ |
| | | ((pos) ? : list_entry(head, typeof(*pos), member)) |
| | | |
| | | /** |
| | | * list_for_each_entry_continue - continue iteration over list of given type |
| | | * @pos: the type * to use as a loop cursor. |
| | | * @head: the head for your list. |
| | | * @member: the name of the list_struct within the struct. |
| | | * |
| | | * Continue to iterate over list of given type, continuing after |
| | | * the current position. |
| | | */ |
| | | #define list_for_each_entry_continue(pos, head, member) \ |
| | | for (pos = list_entry(pos->member.next, typeof(*pos), member); \ |
| | | prefetch(pos->member.next), &pos->member != (head); \ |
| | | pos = list_entry(pos->member.next, typeof(*pos), member)) |
| | | |
| | | /** |
| | | * list_for_each_entry_continue_reverse - iterate backwards from the given point |
| | | * @pos: the type * to use as a loop cursor. |
| | | * @head: the head for your list. |
| | | * @member: the name of the list_struct within the struct. |
| | | * |
| | | * Start to iterate over list of given type backwards, continuing after |
| | | * the current position. |
| | | */ |
| | | #define list_for_each_entry_continue_reverse(pos, head, member) \ |
| | | for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ |
| | | prefetch(pos->member.prev), &pos->member != (head); \ |
| | | pos = list_entry(pos->member.prev, typeof(*pos), member)) |
| | | |
| | | /** |
| | | * list_for_each_entry_from - iterate over list of given type from the current point |
| | | * @pos: the type * to use as a loop cursor. |
| | | * @head: the head for your list. |
| | | * @member: the name of the list_struct within the struct. |
| | | * |
| | | * Iterate over list of given type, continuing from current position. |
| | | */ |
| | | #define list_for_each_entry_from(pos, head, member) \ |
| | | for (; prefetch(pos->member.next), &pos->member != (head); \ |
| | | pos = list_entry(pos->member.next, typeof(*pos), member)) |
| | | |
| | | /** |
| | | * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry |
| | | * @pos: the type * to use as a loop cursor. |
| | | * @n: another type * to use as temporary storage |
| | | * @head: the head for your list. |
| | | * @member: the name of the list_struct within the struct. |
| | | */ |
| | | #define list_for_each_entry_safe(pos, n, head, member) \ |
| | | for (pos = list_entry((head)->next, typeof(*pos), member), \ |
| | | n = list_entry(pos->member.next, typeof(*pos), member); \ |
| | | &pos->member != (head); \ |
| | | pos = n, n = list_entry(n->member.next, typeof(*n), member)) |
| | | |
| | | /** |
| | | * list_for_each_entry_safe_continue |
| | | * @pos: the type * to use as a loop cursor. |
| | | * @n: another type * to use as temporary storage |
| | | * @head: the head for your list. |
| | | * @member: the name of the list_struct within the struct. |
| | | * |
| | | * Iterate over list of given type, continuing after current point, |
| | | * safe against removal of list entry. |
| | | */ |
| | | #define list_for_each_entry_safe_continue(pos, n, head, member) \ |
| | | for (pos = list_entry(pos->member.next, typeof(*pos), member), \ |
| | | n = list_entry(pos->member.next, typeof(*pos), member); \ |
| | | &pos->member != (head); \ |
| | | pos = n, n = list_entry(n->member.next, typeof(*n), member)) |
| | | |
| | | /** |
| | | * list_for_each_entry_safe_from |
| | | * @pos: the type * to use as a loop cursor. |
| | | * @n: another type * to use as temporary storage |
| | | * @head: the head for your list. |
| | | * @member: the name of the list_struct within the struct. |
| | | * |
| | | * Iterate over list of given type from current point, safe against |
| | | * removal of list entry. |
| | | */ |
| | | #define list_for_each_entry_safe_from(pos, n, head, member) \ |
| | | for (n = list_entry(pos->member.next, typeof(*pos), member); \ |
| | | &pos->member != (head); \ |
| | | pos = n, n = list_entry(n->member.next, typeof(*n), member)) |
| | | |
| | | /** |
| | | * list_for_each_entry_safe_reverse |
| | | * @pos: the type * to use as a loop cursor. |
| | | * @n: another type * to use as temporary storage |
| | | * @head: the head for your list. |
| | | * @member: the name of the list_struct within the struct. |
| | | * |
| | | * Iterate backwards over list of given type, safe against removal |
| | | * of list entry. |
| | | */ |
| | | #define list_for_each_entry_safe_reverse(pos, n, head, member) \ |
| | | for (pos = list_entry((head)->prev, typeof(*pos), member), \ |
| | | n = list_entry(pos->member.prev, typeof(*pos), member); \ |
| | | &pos->member != (head); \ |
| | | pos = n, n = list_entry(n->member.prev, typeof(*n), member)) |
| | | |
| | | /* |
| | | * Double linked lists with a single pointer list head. |
| | | * Mostly useful for hash tables where the two pointer list head is |
| | | * too wasteful. |
| | | * You lose the ability to access the tail in O(1). |
| | | */ |
| | | |
| | | struct hlist_head { |
| | | struct hlist_node *first; |
| | | }; |
| | | |
| | | struct hlist_node { |
| | | struct hlist_node *next, **pprev; |
| | | }; |
| | | |
| | | #define HLIST_HEAD_INIT { .first = NULL } |
| | | #define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } |
| | | #define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) |
| | | static inline void INIT_HLIST_NODE(struct hlist_node *h) |
| | | { |
| | | h->next = NULL; |
| | | h->pprev = NULL; |
| | | } |
| | | |
| | | static inline int hlist_unhashed(const struct hlist_node *h) |
| | | { |
| | | return !h->pprev; |
| | | } |
| | | |
| | | static inline int hlist_empty(const struct hlist_head *h) |
| | | { |
| | | return !h->first; |
| | | } |
| | | |
| | | static inline void __hlist_del(struct hlist_node *n) |
| | | { |
| | | struct hlist_node *next = n->next; |
| | | struct hlist_node **pprev = n->pprev; |
| | | *pprev = next; |
| | | if (next) |
| | | next->pprev = pprev; |
| | | } |
| | | |
| | | static inline void hlist_del(struct hlist_node *n) |
| | | { |
| | | __hlist_del(n); |
| | | n->next = LIST_POISON1; |
| | | n->pprev = LIST_POISON2; |
| | | } |
| | | |
| | | static inline void hlist_del_init(struct hlist_node *n) |
| | | { |
| | | if (!hlist_unhashed(n)) { |
| | | __hlist_del(n); |
| | | INIT_HLIST_NODE(n); |
| | | } |
| | | } |
| | | |
| | | static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) |
| | | { |
| | | struct hlist_node *first = h->first; |
| | | n->next = first; |
| | | if (first) |
| | | first->pprev = &n->next; |
| | | h->first = n; |
| | | n->pprev = &h->first; |
| | | } |
| | | |
| | | /* next must be != NULL */ |
| | | static inline void hlist_add_before(struct hlist_node *n, |
| | | struct hlist_node *next) |
| | | { |
| | | n->pprev = next->pprev; |
| | | n->next = next; |
| | | next->pprev = &n->next; |
| | | *(n->pprev) = n; |
| | | } |
| | | |
| | | static inline void hlist_add_after(struct hlist_node *n, |
| | | struct hlist_node *next) |
| | | { |
| | | next->next = n->next; |
| | | n->next = next; |
| | | next->pprev = &n->next; |
| | | |
| | | if(next->next) |
| | | next->next->pprev = &next->next; |
| | | } |
| | | |
| | | #define hlist_entry(ptr, type, member) container_of(ptr,type,member) |
| | | |
| | | #define hlist_for_each(pos, head) \ |
| | | for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ |
| | | pos = pos->next) |
| | | |
| | | #define hlist_for_each_safe(pos, n, head) \ |
| | | for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ |
| | | pos = n) |
| | | |
| | | /** |
| | | * hlist_for_each_entry - iterate over list of given type |
| | | * @tpos: the type * to use as a loop cursor. |
| | | * @pos: the &struct hlist_node to use as a loop cursor. |
| | | * @head: the head for your list. |
| | | * @member: the name of the hlist_node within the struct. |
| | | */ |
| | | #define hlist_for_each_entry(tpos, pos, head, member) \ |
| | | for (pos = (head)->first; \ |
| | | pos && ({ prefetch(pos->next); 1;}) && \ |
| | | ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ |
| | | pos = pos->next) |
| | | |
| | | /** |
| | | * hlist_for_each_entry_continue - iterate over a hlist continuing after current point |
| | | * @tpos: the type * to use as a loop cursor. |
| | | * @pos: the &struct hlist_node to use as a loop cursor. |
| | | * @member: the name of the hlist_node within the struct. |
| | | */ |
| | | #define hlist_for_each_entry_continue(tpos, pos, member) \ |
| | | for (pos = (pos)->next; \ |
| | | pos && ({ prefetch(pos->next); 1;}) && \ |
| | | ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ |
| | | pos = pos->next) |
| | | |
| | | /** |
| | | * hlist_for_each_entry_from - iterate over a hlist continuing from current point |
| | | * @tpos: the type * to use as a loop cursor. |
| | | * @pos: the &struct hlist_node to use as a loop cursor. |
| | | * @member: the name of the hlist_node within the struct. |
| | | */ |
| | | #define hlist_for_each_entry_from(tpos, pos, member) \ |
| | | for (; pos && ({ prefetch(pos->next); 1;}) && \ |
| | | ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ |
| | | pos = pos->next) |
| | | |
| | | /** |
| | | * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry |
| | | * @tpos: the type * to use as a loop cursor. |
| | | * @pos: the &struct hlist_node to use as a loop cursor. |
| | | * @n: another &struct hlist_node to use as temporary storage |
| | | * @head: the head for your list. |
| | | * @member: the name of the hlist_node within the struct. |
| | | */ |
| | | #define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ |
| | | for (pos = (head)->first; \ |
| | | pos && ({ n = pos->next; 1; }) && \ |
| | | ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ |
| | | pos = n) |
| | | |
| | | |
| | | #endif |
| | | |
| | | |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2012 Guo Wenxue <guowenxue@gmail.com> |
| | | * All rights reserved. |
| | | * |
| | | * Filename: cp_log.c |
| | | * Description: This file is the linux infrastructural logger system library |
| | | * |
| | | * Version: 1.0.0(08/08/2012~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "08/08/2012 04:24:01 PM" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #include "cp_logger.h" |
| | | #include "cp_common.h" |
| | | |
| | | #define PRECISE_TIME_FACTOR 1000 |
| | | |
| | | static unsigned long log_rollback_size = LOG_ROLLBACK_NONE; |
| | | |
| | | static cp_logger *logger = NULL; |
| | | |
| | | char *log_str[LOG_LEVEL_MAX + 1] = { "", "F", "E", "W", "N", "D", "I", "T", "M" }; |
| | | |
| | | static char *cp_time_format = DEFAULT_TIME_FORMAT; |
| | | |
| | | void cp_log_set_time_format(char *time_format) |
| | | { |
| | | cp_time_format = time_format; |
| | | } |
| | | |
| | | static void cp_log_default_signal_handler(int sig) |
| | | { |
| | | if(!logger) |
| | | return ; |
| | | |
| | | if (sig == SIGHUP) |
| | | { |
| | | signal(SIGHUP, cp_log_default_signal_handler); |
| | | log_fatal("SIGHUP received - reopenning log file [%s]", logger->file); |
| | | cp_log_reopen(); |
| | | } |
| | | } |
| | | |
| | | static void log_banner(char *prefix) |
| | | { |
| | | if(!logger) |
| | | return ; |
| | | |
| | | fprintf(logger->fp, "%s log \"%s\" on level [%s] size [%lu], log system version %s\n", |
| | | prefix, logger->file, log_str[logger->level], log_rollback_size / 1024, LOG_VERSION_STR); |
| | | #ifdef LOG_FILE_LINE |
| | | fprintf(logger->fp, " [Date] [Time] [Level] [PID/TID] [File/Line] [Content]\n"); |
| | | #else |
| | | fprintf(logger->fp, " [Date] [Time] [Level] [PID/TID] [Content]\n"); |
| | | #endif |
| | | fprintf(logger->fp, "-------------------------------------------------------------\n"); |
| | | } |
| | | |
| | | static void check_and_rollback(void) |
| | | { |
| | | if(!logger) |
| | | return ; |
| | | |
| | | if (log_rollback_size != LOG_ROLLBACK_NONE) |
| | | { |
| | | long _curOffset = ftell(logger->fp); |
| | | |
| | | if ((_curOffset != -1) && (_curOffset >= log_rollback_size)) |
| | | { |
| | | char cmd[512]; |
| | | |
| | | snprintf(cmd, sizeof(cmd), "cp -f %s %s.roll", logger->file, logger->file); |
| | | system(cmd); |
| | | |
| | | if (-1 == fseek(logger->fp, 0L, SEEK_SET)) |
| | | fprintf(logger->fp, "log rollback fseek failed \n"); |
| | | |
| | | rewind(logger->fp); |
| | | |
| | | truncate(logger->file, 0); |
| | | log_banner("Already rollback"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | cp_logger *cp_log_init(cp_logger *log, char *filename, int level, int log_size) |
| | | { |
| | | if(NULL == log) |
| | | { |
| | | logger = malloc(sizeof(cp_logger)); |
| | | memset(logger, 0, sizeof(cp_logger)); |
| | | logger->flag |= CP_LOGGER_MALLOC; |
| | | } |
| | | else |
| | | { |
| | | logger = log; |
| | | memset(logger, 0, sizeof(cp_logger)); |
| | | logger->flag |= CP_LOGGER_ARGUMENT; |
| | | } |
| | | |
| | | if(NULL == logger) |
| | | { |
| | | return NULL; |
| | | } |
| | | |
| | | strncpy(logger->file, filename, FILENAME_LEN); |
| | | logger->level = level; |
| | | logger->size = log_size; |
| | | |
| | | return logger; |
| | | } |
| | | |
| | | int cp_log_open(void) |
| | | { |
| | | struct sigaction act; |
| | | char *filemode; |
| | | |
| | | if(!logger) |
| | | { |
| | | return -1; |
| | | } |
| | | |
| | | log_rollback_size = logger->size <= 0 ? LOG_ROLLBACK_NONE : logger->size*1024; /* Unit KiB */ |
| | | |
| | | if ('\0' == logger->file) |
| | | return -1; |
| | | |
| | | if (!strcmp(logger->file, DBG_LOG_FILE)) |
| | | { |
| | | logger->fp = stderr; |
| | | log_rollback_size = LOG_ROLLBACK_NONE; |
| | | logger->flag |= CP_LOGGER_CONSOLE; |
| | | goto OUT; |
| | | } |
| | | |
| | | //filemode = (log_rollback_size==LOG_ROLLBACK_NONE) ? "a+" : "w+"; |
| | | filemode = "a+"; |
| | | |
| | | logger->fp = fopen(logger->file, filemode); |
| | | if (NULL == logger->fp) |
| | | { |
| | | fprintf(stderr, "Open log file \"%s\" in %s failure\n", logger->file, filemode); |
| | | return -2; |
| | | } |
| | | |
| | | act.sa_handler = cp_log_default_signal_handler; |
| | | sigemptyset(&act.sa_mask); |
| | | act.sa_flags = 0; |
| | | sigaction(SIGHUP, &act, NULL); |
| | | |
| | | OUT: |
| | | log_banner("Initialize"); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | void cp_log_close(void) |
| | | { |
| | | if (!logger || !logger->fp ) |
| | | return; |
| | | |
| | | log_banner("\nTerminate"); |
| | | cp_log_raw("\n\n\n\n"); |
| | | |
| | | fflush(logger->fp); |
| | | |
| | | fclose(logger->fp); |
| | | logger->fp = NULL; |
| | | |
| | | return ; |
| | | } |
| | | |
| | | int cp_log_reopen(void) |
| | | { |
| | | int rc = 0; |
| | | char *filemode; |
| | | |
| | | if( !logger ) |
| | | return -1; |
| | | |
| | | if (logger->flag & CP_LOGGER_CONSOLE ) |
| | | { |
| | | fflush(logger->fp); |
| | | logger->fp = stderr; |
| | | return 0; |
| | | } |
| | | |
| | | if (logger->fp) |
| | | { |
| | | cp_log_close(); |
| | | //filemode = log_rollback_size == LOG_ROLLBACK_NONE ? "a+" : "w+"; |
| | | filemode = "a+"; |
| | | logger->fp = fopen(logger->file, filemode); |
| | | |
| | | if (logger->fp == NULL) |
| | | rc = -2; |
| | | } |
| | | else |
| | | { |
| | | rc = -3; |
| | | } |
| | | |
| | | if (!rc) |
| | | { |
| | | log_banner("\nReopen"); |
| | | } |
| | | return rc; |
| | | } |
| | | |
| | | void cp_log_term(void) |
| | | { |
| | | if(!logger) |
| | | return ; |
| | | |
| | | cp_log_close(); |
| | | |
| | | if (logger->flag & CP_LOGGER_MALLOC ) |
| | | { |
| | | free(logger); |
| | | } |
| | | logger = NULL; |
| | | } |
| | | |
| | | void cp_log_raw(const char *fmt, ...) |
| | | { |
| | | va_list argp; |
| | | |
| | | if (!logger || !logger->fp) |
| | | return; |
| | | |
| | | check_and_rollback(); |
| | | |
| | | va_start(argp, fmt); |
| | | vfprintf(logger->fp, fmt, argp); |
| | | va_end(argp); |
| | | } |
| | | |
| | | static void cp_printout(char *level, char *fmt, va_list argp) |
| | | { |
| | | char buf[MAX_LOG_MESSAGE_LEN]; |
| | | struct tm *local; |
| | | struct timeval now; |
| | | char timestr[256]; |
| | | |
| | | if(!logger) |
| | | return ; |
| | | |
| | | pthread_t tid; |
| | | |
| | | check_and_rollback(); |
| | | |
| | | #ifdef MULTHREADS |
| | | tid = pthread_self(); |
| | | #else |
| | | tid = getpid(); |
| | | #endif |
| | | |
| | | gettimeofday(&now, NULL); |
| | | local = localtime(&now.tv_sec); |
| | | |
| | | strftime(timestr, 256, cp_time_format, local); |
| | | vsnprintf(buf, MAX_LOG_MESSAGE_LEN, fmt, argp); |
| | | |
| | | #ifdef DUMPLICATE_OUTPUT |
| | | printf("%s.%03ld [%s] [%06lu]: %s", |
| | | timestr, now.tv_usec / PRECISE_TIME_FACTOR, level, tid, buf); |
| | | #endif |
| | | |
| | | if (logger->fp) |
| | | fprintf(logger->fp, "%s.%03ld [%s] [%06lu]: %s", timestr, now.tv_usec / PRECISE_TIME_FACTOR, |
| | | level, tid, buf); |
| | | |
| | | if (logger->fp) |
| | | fflush(logger->fp); |
| | | } |
| | | |
| | | static void cp_printout_line(char *level, char *fmt, char *file, int line, va_list argp) |
| | | { |
| | | char buf[MAX_LOG_MESSAGE_LEN]; |
| | | struct tm *local; |
| | | struct timeval now; |
| | | char timestr[256]; |
| | | |
| | | if(!logger) |
| | | return ; |
| | | |
| | | pthread_t tid; |
| | | |
| | | check_and_rollback(); |
| | | |
| | | #ifdef MULTHREADS |
| | | tid = pthread_self(); |
| | | #else |
| | | tid = getpid(); |
| | | #endif |
| | | |
| | | gettimeofday(&now, NULL); |
| | | local = localtime(&now.tv_sec); |
| | | |
| | | strftime(timestr, 256, cp_time_format, local); |
| | | vsnprintf(buf, MAX_LOG_MESSAGE_LEN, fmt, argp); |
| | | |
| | | #ifdef DUMPLICATE_OUTPUT |
| | | printf("%s.%03ld [%s] [%06lu] (%s [%04d]) : %s", |
| | | timestr, now.tv_usec / PRECISE_TIME_FACTOR, level, tid, file, line, buf); |
| | | #endif |
| | | |
| | | if (logger->fp) |
| | | fprintf(logger->fp, "%s.%03ld [%s] [%06lu] (%s [%04d]) : %s", |
| | | timestr, now.tv_usec / PRECISE_TIME_FACTOR, level, tid, file, line, buf); |
| | | |
| | | if (logger->fp) |
| | | fflush(logger->fp); |
| | | } |
| | | |
| | | void cp_log(int level, char *fmt, ...) |
| | | { |
| | | va_list argp; |
| | | |
| | | if (!logger || level>logger->level) |
| | | return; |
| | | |
| | | va_start(argp, fmt); |
| | | cp_printout(log_str[level], fmt, argp); |
| | | va_end(argp); |
| | | } |
| | | |
| | | void cp_log_line(int level, char *file, int line, char *fmt, ...) |
| | | { |
| | | va_list argp; |
| | | |
| | | if (!logger || level>logger->level) |
| | | return; |
| | | |
| | | va_start(argp, fmt); |
| | | cp_printout_line(log_str[level], fmt, file, line, argp); |
| | | |
| | | va_end(argp); |
| | | } |
| | | |
| | | #define LINELEN 81 |
| | | #define CHARS_PER_LINE 16 |
| | | static char *print_char = |
| | | " " |
| | | " " |
| | | " !\"#$%&'()*+,-./" |
| | | "0123456789:;<=>?" |
| | | "@ABCDEFGHIJKLMNO" |
| | | "PQRSTUVWXYZ[\\]^_" |
| | | "`abcdefghijklmno" |
| | | "pqrstuvwxyz{|}~ " |
| | | " " |
| | | " " |
| | | " ???????????????" |
| | | "????????????????" |
| | | "????????????????" |
| | | "????????????????" |
| | | "????????????????" |
| | | "????????????????"; |
| | | |
| | | void cp_log_dump(int level, char *buf, int len) |
| | | { |
| | | int rc; |
| | | int idx; |
| | | char prn[LINELEN]; |
| | | char lit[CHARS_PER_LINE + 2]; |
| | | char hc[4]; |
| | | short line_done = 1; |
| | | |
| | | if (!logger || level>logger->level) |
| | | return; |
| | | |
| | | rc = len; |
| | | idx = 0; |
| | | lit[CHARS_PER_LINE] = '\0'; |
| | | |
| | | while (rc > 0) |
| | | { |
| | | if (line_done) |
| | | snprintf(prn, LINELEN, "%08X: ", idx); |
| | | |
| | | do |
| | | { |
| | | unsigned char c = buf[idx]; |
| | | snprintf(hc, 4, "%02X ", c); |
| | | strncat(prn, hc, LINELEN); |
| | | |
| | | lit[idx % CHARS_PER_LINE] = print_char[c]; |
| | | } |
| | | while (--rc > 0 && (++idx % CHARS_PER_LINE != 0)); |
| | | |
| | | line_done = (idx % CHARS_PER_LINE) == 0; |
| | | if (line_done) |
| | | { |
| | | #ifdef DUMPLICATE_OUTPUT |
| | | printf("%s %s\n", prn, lit); |
| | | #endif |
| | | if (logger->fp) |
| | | fprintf(logger->fp, "%s %s\n", prn, lit); |
| | | } |
| | | } |
| | | |
| | | if (!line_done) |
| | | { |
| | | int ldx = idx % CHARS_PER_LINE; |
| | | lit[ldx++] = print_char[(int)buf[idx]]; |
| | | lit[ldx] = '\0'; |
| | | |
| | | while ((++idx % CHARS_PER_LINE) != 0) |
| | | strncat(prn, " ", LINELEN); |
| | | |
| | | #ifdef DUMPLICATE_OUTPUT |
| | | printf("%s %s\n", prn, lit); |
| | | #endif |
| | | if (logger->fp) |
| | | fprintf(logger->fp, "%s %s\n", prn, lit); |
| | | |
| | | } |
| | | } |
New file |
| | |
| | | /******************************************************************************** |
| | | * Copyright: (C) 2012 Guo Wenxue <guowenxue@gmail.com> |
| | | * All rights reserved. |
| | | * |
| | | * Filename: cp_logger.h |
| | | * Description: This file is the linux infrastructural logger system library |
| | | * |
| | | * Version: 1.0.0(08/08/2012~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "08/08/2012 05:16:56 PM" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #ifndef __CP_LOG_H |
| | | #define __CP_LOG_H |
| | | |
| | | #include <stdarg.h> |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #include <unistd.h> |
| | | #include <signal.h> |
| | | #include <time.h> |
| | | #include <errno.h> |
| | | |
| | | #include <pthread.h> |
| | | #include <sys/types.h> |
| | | #include <sys/time.h> |
| | | |
| | | #define LOG_VERSION_STR "1.0.0" |
| | | |
| | | #ifndef FILENAME_LEN |
| | | #define FILENAME_LEN 64 |
| | | #endif |
| | | |
| | | #define DEFAULT_LOGFILE "cp_logger.log" |
| | | #define DBG_LOG_FILE "console" /* Debug mode log file is console */ |
| | | |
| | | #define LOG_ROLLBACK_SIZE 512 /* Default rollback log size */ |
| | | #define LOG_ROLLBACK_NONE 0 /* Set rollback size to 0 will not rollback */ |
| | | |
| | | #define DEFAULT_TIME_FORMAT "%Y-%m-%d %H:%M:%S" |
| | | #define MAX_LOG_MESSAGE_LEN 0x1000 |
| | | |
| | | //#define DUMPLICATE_OUTPUT /* Log to file and printf on console */ |
| | | #define LOG_FILE_LINE /* Log the file and line */ |
| | | |
| | | enum |
| | | { |
| | | LOG_LEVEL_DISB = 0, /* Disable "Debug" */ |
| | | LOG_LEVEL_FATAL, /* Debug Level "Fatal" */ |
| | | LOG_LEVEL_ERROR, /* Debug Level "ERROR" */ |
| | | LOG_LEVEL_WARN, /* Debug Level "warnning" */ |
| | | LOG_LEVEL_NRML, /* Debug Level "Normal" */ |
| | | LOG_LEVEL_DEBUG, /* Debug Level "Debug" */ |
| | | LOG_LEVEL_INFO, /* Debug Level "Information" */ |
| | | LOG_LEVEL_TRACE, /* Debug Level "Trace" */ |
| | | LOG_LEVEL_MAX, |
| | | }; |
| | | |
| | | #define CP_LOGGER_MALLOC 1<<0 |
| | | #define CP_LOGGER_ARGUMENT 0<<0 |
| | | |
| | | #define CP_LOGGER_CONSOLE 1<<1 |
| | | #define CP_LOGGER_FILE 0<<1 |
| | | |
| | | #define CP_LOGGER_LEVEL_OPT 1<<2 /* The log level is sepcified by the command option */ |
| | | typedef struct _cp_logger |
| | | { |
| | | unsigned char flag; /* This logger pointer is malloc() or passed by argument */ |
| | | char file[FILENAME_LEN]; |
| | | int level; |
| | | int size; |
| | | |
| | | FILE *fp; |
| | | } cp_logger; |
| | | |
| | | extern char *log_str[]; |
| | | |
| | | extern cp_logger *cp_log_init(cp_logger *log, char *filename, int level, int log_size); |
| | | extern int cp_log_open(void); |
| | | extern void cp_log_set_time_format(char *time_format); |
| | | extern int cp_log_reopen(void); |
| | | extern void cp_log_term(void); |
| | | extern void cp_log_raw(const char *fmt, ...); |
| | | extern void cp_log(int level, char *fmt, ...); |
| | | extern void cp_log_line(int level, char *file, int line, char *fmt, ...); |
| | | |
| | | extern void cp_log_dump(int level, char *buf, int len); |
| | | |
| | | #ifdef LOG_FILE_LINE |
| | | #define log_trace(fmt, ...) cp_log_line(LOG_LEVEL_TRACE, __FILE__, __LINE__, fmt, ##__VA_ARGS__) |
| | | #define log_info(fmt, ...) cp_log_line(LOG_LEVEL_INFO, __FILE__, __LINE__, fmt, ##__VA_ARGS__) |
| | | #define log_dbg(fmt, ...) cp_log_line(LOG_LEVEL_DEBUG, __FILE__, __LINE__, fmt, ##__VA_ARGS__) |
| | | #define log_nrml(fmt, ...) cp_log_line(LOG_LEVEL_NRML, __FILE__, __LINE__, fmt, ##__VA_ARGS__) |
| | | #define log_warn(fmt, ...) cp_log_line(LOG_LEVEL_WARN, __FILE__, __LINE__, fmt, ##__VA_ARGS__) |
| | | #define log_err(fmt, ...) cp_log_line(LOG_LEVEL_ERROR, __FILE__, __LINE__, fmt, ##__VA_ARGS__) |
| | | #define log_fatal(fmt, ...) cp_log_line(LOG_LEVEL_FATAL, __FILE__, __LINE__, fmt, ##__VA_ARGS__) |
| | | #else |
| | | #define log_trace(fmt, ...) cp_log(LOG_LEVEL_TRACE, fmt, ##__VA_ARGS__) |
| | | #define log_info(fmt, ...) cp_log(LOG_LEVEL_INFO, fmt, ##__VA_ARGS__) |
| | | #define log_dbg(fmt, ...) cp_log(LOG_LEVEL_DEBUG, fmt, ##__VA_ARGS__) |
| | | #define log_nrml(fmt, ...) cp_log(LOG_LEVEL_NRML, fmt, ##__VA_ARGS__) |
| | | #define log_warn(fmt, ...) cp_log(LOG_LEVEL_WARN, fmt, ##__VA_ARGS__) |
| | | #define log_err(fmt, ...) cp_log(LOG_LEVEL_ERROR, fmt, ##__VA_ARGS__) |
| | | #define log_fatal(fmt, ...) cp_log(LOG_LEVEL_FATAL, fmt, ##__VA_ARGS__) |
| | | #endif |
| | | |
| | | |
| | | #endif /* __CP_LOG_H */ |
New file |
| | |
| | | /******************************************************************************** |
| | | * Copyright: (C) guowenxue <guowenxue@gmail.com> |
| | | * All rights reserved. |
| | | * |
| | | * Filename: ppp.c |
| | | * Description: This file is the ppp thread file,used to do PPP dial up |
| | | * |
| | | * Version: 1.0.0(02/02/2012~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "02/02/2012 11:33:33 AM" |
| | | * |
| | | ********************************************************************************/ |
| | | #include <sys/ioctl.h> |
| | | #include <netinet/in.h> |
| | | #include <net/if.h> |
| | | #include <net/if_arp.h> |
| | | #include <arpa/inet.h> |
| | | #include "cp_ppp.h" |
| | | #include "cp_string.h" |
| | | #include "cp_iniparser.h" |
| | | //#include "cp_network.h" |
| | | //#include "gsmd.h" |
| | | |
| | | /* |
| | | * Description: Check PPP10 device exist or not, and set the PPP context status |
| | | * |
| | | * |
| | | * Return Value: 0: PPP10 device exist -1:PPP10 device not exist |
| | | * |
| | | */ |
| | | int check_ppp_interface(char *ppp_dev) |
| | | { |
| | | int fd = -1; |
| | | int retval = -1; |
| | | char buf[512]; |
| | | |
| | | if ((fd = open("/proc/net/dev", O_RDONLY, 0666)) < 0) |
| | | { |
| | | return -1; /* System error, take as PPP10 device not exist too */ |
| | | } |
| | | |
| | | while (read(fd, buf, sizeof(buf)) > 0) |
| | | { |
| | | if (NULL != strstr(buf, ppp_dev)) |
| | | { |
| | | retval = 0; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | close(fd); |
| | | return retval; |
| | | } |
| | | |
| | | int check_ppp_ipaddr(pppd_info_t *pppd_info, char *ppp_dev) |
| | | { |
| | | int fd; |
| | | struct ifreq ifr; |
| | | struct sockaddr_in *sin; |
| | | |
| | | if(check_ppp_interface(ppp_dev)) |
| | | return -2; |
| | | |
| | | fd = socket(AF_INET, SOCK_DGRAM, 0); |
| | | strcpy(ifr.ifr_name, ppp_dev); |
| | | |
| | | if ((ioctl(fd, SIOCGIFADDR, (caddr_t) & ifr, sizeof(struct ifreq))) < 0) |
| | | { |
| | | log_fatal("System call ioctl() with SIOCGIFADDR failure.\n", ppp_dev); |
| | | return -1; |
| | | } |
| | | |
| | | sin = (struct sockaddr_in *)&ifr.ifr_addr; |
| | | strcpy(pppd_info->netaddr, (const char *)inet_ntoa(sin->sin_addr)); |
| | | log_nrml("Get %s local IP address: %s\n", ppp_dev, pppd_info->netaddr); |
| | | |
| | | if ((ioctl(fd, SIOCGIFDSTADDR, (caddr_t) & ifr, sizeof(struct ifreq))) < 0) |
| | | { |
| | | log_fatal("System call ioctl() with SIOCGIFDSTADDR failure.\n", ppp_dev); |
| | | return -1; |
| | | } |
| | | sin = (struct sockaddr_in *)&ifr.ifr_dstaddr; |
| | | strcpy(pppd_info->ptpaddr, (const char *)inet_ntoa(sin->sin_addr)); |
| | | log_nrml("Get %s remote IP address: %s\n", ppp_dev, pppd_info->ptpaddr); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | /* Description: Use ping do network test |
| | | * Input args: $from: : use which NIC(Network Interface Card: eth0, eth1) or |
| | | * source IP address do ping test. if it's NULL, use default route |
| | | * $ping_ip: The ping test destination IP address |
| | | * Output args: NONE |
| | | * Return Value: >=0 ping test packet lost percent, <0: failure |
| | | */ |
| | | int network_ping_test(char *from, char *ping_ip) |
| | | { |
| | | FILE *fp; |
| | | char cmd[256]; |
| | | char buf[512]; |
| | | int lost_percent = 100; |
| | | unsigned long tx_packets = 0; |
| | | unsigned long rx_packets = 0; |
| | | |
| | | memset(cmd, 0, sizeof(cmd)); |
| | | if(from) |
| | | { |
| | | snprintf(cmd, sizeof(cmd), "ping -W1 -c5 -s4 %s -I %s", ping_ip, from); |
| | | } |
| | | else |
| | | { |
| | | snprintf(cmd, sizeof(cmd), "ping -W1 -c5 -s4 %s", ping_ip); |
| | | } |
| | | |
| | | if (NULL == (fp = popen(cmd, "r"))) |
| | | { |
| | | return -2; |
| | | } |
| | | |
| | | while (NULL != fgets(buf, sizeof(buf), fp)) |
| | | { |
| | | if (strstr(buf, "transmitted")) |
| | | { |
| | | split_string_to_value(buf, "%l,%l,%d", &tx_packets, &rx_packets, &lost_percent); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | pclose(fp); |
| | | return lost_percent; |
| | | } |
| | | |
| | | int check_ppp_stat(ppp_stat_t *ppp_stat, char *ppp_dev) |
| | | { |
| | | int retval; |
| | | FILE *fp; |
| | | char *ptr; |
| | | char buf[512]; |
| | | |
| | | if( NULL == (fp=fopen(PPP_PROC_NET_DEV, "r")) ) |
| | | { |
| | | log_err("Can not open %s.\n", PPP_PROC_NET_DEV); |
| | | return -1; |
| | | } |
| | | |
| | | fgets(buf, sizeof(buf), fp); |
| | | fgets(buf, sizeof(buf), fp); |
| | | |
| | | while (fgets(buf, sizeof(buf), fp)) |
| | | { |
| | | ptr=strstr(buf, ppp_dev); |
| | | if(NULL == ptr) |
| | | { |
| | | log_err("Can not find %s interface statistic data in %s\n", ppp_dev, PPP_PROC_NET_DEV); |
| | | retval = -1; |
| | | break; |
| | | } |
| | | else |
| | | { |
| | | ptr = strchr(ptr, ':'); |
| | | ptr++; |
| | | sscanf(ptr, "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu", |
| | | &(ppp_stat->ullRx_Bytes), |
| | | &(ppp_stat->ullRx_Packets), |
| | | &(ppp_stat->ulRx_Errors), |
| | | &(ppp_stat->ulRx_Dropped), |
| | | &(ppp_stat->ulRx_FIFO_Errors), |
| | | &(ppp_stat->ulRx_Frame_Errors), |
| | | &(ppp_stat->ulRx_Compressed), |
| | | &(ppp_stat->ulRx_Multicast), |
| | | &(ppp_stat->ullTx_Bytes), |
| | | &(ppp_stat->ullTx_Packets), |
| | | &(ppp_stat->ulTx_Errors), |
| | | &(ppp_stat->ulTx_Dropped), |
| | | &(ppp_stat->ulTx_FIFO_Errors), |
| | | &(ppp_stat->ulCollisions), |
| | | &(ppp_stat->ulTx_Carrier_Errors), |
| | | &(ppp_stat->ulTx_Compressed) |
| | | ); |
| | | retval = 0; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if(0 == retval ) |
| | | log_dbg("Check PPP network traffic: Tx %llu bytes, Rx %llu bytes.\n", ppp_stat->ullTx_Bytes, ppp_stat->ullRx_Bytes); |
| | | fclose(fp); |
| | | return retval; |
| | | } |
| | | |
| | | int kill_pppd_process(comport_t *comport) |
| | | { |
| | | int pid = -1; |
| | | |
| | | while( (pid=check_pppd_pid(comport->dev_name)) > 0) |
| | | { |
| | | log_nrml("Terminate pppd process [pid=%d]\n", pid); |
| | | kill(pid, SIGTERM); |
| | | sleep(1); /* Wait pppd process exit */ |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | int stop_ppp_connect(ppp_ctx_t *ppp_ctx) |
| | | { |
| | | log_warn("Stop PPP connection now.\n"); |
| | | |
| | | if(check_ppp_interface(ppp_ctx->dev)) |
| | | return 0; |
| | | |
| | | kill_pppd_process(ppp_ctx->comport); |
| | | |
| | | if(ppp_ctx->comport) |
| | | { |
| | | free_gsm_dataport("stop_ppp_connect()", ppp_ctx->module, &(ppp_ctx->comport)); |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | int get_apn_conf(char *ini_name, char *ini_key, apn_account_t *apn, unsigned char type) |
| | | { |
| | | dictionary *ini ; |
| | | char tmp[64]; |
| | | char *str; |
| | | |
| | | if(NULL==ini_name || NULL==ini_key || NULL==apn) |
| | | { |
| | | return -1; |
| | | } |
| | | |
| | | ini = iniparser_load(ini_name); |
| | | if (ini==NULL) |
| | | { |
| | | log_err("cannot load default APN configure file: %s\n", ini_name); |
| | | return -2 ; |
| | | } |
| | | log_dbg("Parser default APN configure file %s\n", ini_name); |
| | | |
| | | /* Parser APN configure */ |
| | | snprintf(tmp, 64, "%s:%s", ini_key, APN_3G==type?"3g_apn":"apn"); |
| | | if( !(str=iniparser_getstring(ini, tmp, NULL)) ) |
| | | { |
| | | log_err("cannot find APN setting for SIM [%s] in file: %s\n", ini_key, ini_name); |
| | | memset(apn, 0, sizeof(apn_account_t)); |
| | | return -1; |
| | | } |
| | | else |
| | | { |
| | | strncpy(apn->apn, str, APN_LEN); |
| | | } |
| | | |
| | | /* Paser APN username information */ |
| | | snprintf(tmp, 64, "%s:%s", ini_key, APN_3G==type?"3g_uid":"uid"); |
| | | str = iniparser_getstring(ini, tmp, NULL); |
| | | strncpy(apn->uid, str, UID_LEN); |
| | | |
| | | |
| | | /* Paser APN password information */ |
| | | snprintf(tmp, 64, "%s:%s", ini_key, APN_3G==type?"3g_pwd":"pwd"); |
| | | str = iniparser_getstring(ini, tmp, NULL); |
| | | strncpy(apn->pwd, str, PWD_LEN); |
| | | |
| | | iniparser_freedict(ini); |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | int select_apn(ppp_ctx_t *ppp_ctx, char *key) |
| | | { |
| | | int retval; |
| | | unsigned char type = APN_2G; |
| | | |
| | | log_nrml("GPRS module work on GPRS mode, select APN now.\n"); |
| | | |
| | | retval = get_apn_conf(APN_DEF_CONF_FILE, key, &(ppp_ctx->apn), type); |
| | | if(!retval) |
| | | { |
| | | log_err("Get default APN [%s] from %s ok\n", ppp_ctx->apn.apn, APN_DEF_CONF_FILE); |
| | | return 0; |
| | | } |
| | | |
| | | return -1; |
| | | } |
| | | |
| | | #define PPPD_CMD_LEN 512 |
| | | int start_ppp_dial_cmd(comport_t *comport, apn_account_t *apn, char *ppp_dev) |
| | | { |
| | | char tmp[64]; |
| | | char pppd_cmd[PPPD_CMD_LEN]; |
| | | pid_t pid; |
| | | |
| | | if( !comport || !comport->is_connted ) |
| | | { |
| | | log_err("GPRS module data port %s is not opened.\n", comport->dev_name); |
| | | return -1; |
| | | } |
| | | |
| | | if( !apn || strlen(apn->apn)<=0 ) |
| | | { |
| | | log_err("No valid APN was set.\n"); |
| | | return -1; |
| | | } |
| | | |
| | | log_nrml("Start PPP connection with APN \"%s\" now.\n", apn->apn); |
| | | |
| | | memset(pppd_cmd, 0, PPPD_CMD_LEN); |
| | | snprintf(pppd_cmd, PPPD_CMD_LEN, "%s -d %s ", PPPD_DIAL_SCRIPTS, comport->dev_name); |
| | | |
| | | snprintf(tmp, sizeof(tmp), " -a %s ", apn->apn); |
| | | strncat(pppd_cmd, tmp, PPPD_CMD_LEN); |
| | | |
| | | if( strlen(apn->uid) > 0 ) |
| | | { |
| | | snprintf(tmp, sizeof(tmp), " -u %s ", apn->uid); |
| | | strncat(pppd_cmd, tmp, PPPD_CMD_LEN); |
| | | } |
| | | |
| | | if( strlen(apn->pwd) > 0 ) |
| | | { |
| | | snprintf(tmp, sizeof(tmp), " -p %s ", apn->pwd); |
| | | strncat(pppd_cmd, tmp, PPPD_CMD_LEN); |
| | | } |
| | | |
| | | if( strlen(apn->auth) > 0 ) |
| | | { |
| | | snprintf(tmp, sizeof(tmp), " -v %s ", apn->auth); |
| | | strncat(pppd_cmd, tmp, PPPD_CMD_LEN); |
| | | } |
| | | |
| | | strncat(pppd_cmd, ppp_dev, PPPD_CMD_LEN); |
| | | |
| | | log_nrml("ppp dial up command: %s\n", pppd_cmd); |
| | | |
| | | pid = fork(); |
| | | if( 0 == pid ) /* Child process */ |
| | | { |
| | | system(pppd_cmd); |
| | | exit(0); |
| | | } |
| | | else if (pid < 0) |
| | | { |
| | | log_err("Create new process failure.\n"); |
| | | return -1; |
| | | } |
| | | else |
| | | { |
| | | log_dbg("pppd program already running.\n"); |
| | | micro_second_sleep(1000); |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | int check_pppd_pid(char *find_key) |
| | | { |
| | | char buf[10]; |
| | | char cmd[128]; |
| | | FILE *fp = NULL; |
| | | int pid = -1; |
| | | |
| | | snprintf(cmd, sizeof(cmd), "ps | grep -v grep | grep pppd | grep %s | awk '{print $1}'", find_key); |
| | | |
| | | fp = popen(cmd, "r"); |
| | | if(NULL == fp) |
| | | { |
| | | log_fatal("popen() to check the pppd process ID failure.\n"); |
| | | return -1; |
| | | } |
| | | |
| | | memset(buf, 0, sizeof(buf)); |
| | | fgets(buf, sizeof(buf), fp); |
| | | |
| | | pid = atoi(buf); |
| | | |
| | | if(pid <= 1) |
| | | { |
| | | log_err("Get pppd program running pid failure\n"); |
| | | pid = -1; |
| | | } |
| | | #if 0 |
| | | else |
| | | { |
| | | log_trace("pppd program running pid is [%d]\n", pid); |
| | | } |
| | | #endif |
| | | |
| | | pclose(fp); |
| | | return pid; |
| | | } |
| | | |
| | | void set_ppp_disconnect(ppp_ctx_t *ppp_ctx) |
| | | { |
| | | ppp_ctx->status = DISCONNECT; |
| | | ppp_ctx->pppd_info.start_time = 0; |
| | | |
| | | memset(&(ppp_ctx->pppd_info), 0, sizeof(pppd_info_t)); |
| | | memset(&(ppp_ctx->ppp_stat), 0, sizeof(ppp_stat_t)); |
| | | ppp_ctx->network = PPP_STOP; |
| | | } |
| | | |
| | | |
| | | int ppp_context_init(ppp_ctx_t *ppp_ctx, modinfo_t *module) |
| | | { |
| | | memset(ppp_ctx, 0, sizeof(*ppp_ctx)); |
| | | |
| | | ppp_ctx->thread_id = pthread_self(); |
| | | ppp_ctx->module = module; |
| | | strncpy(ppp_ctx->dev, PPP_INTERFACE_NAME, sizeof(ppp_ctx->dev)); |
| | | strncpy(ppp_ctx->ping_ip, DEF_PING_DST, sizeof(ppp_ctx->ping_ip)); |
| | | ppp_ctx->ping_interval = PING_INTERVAL_TIME; |
| | | set_ppp_disconnect(ppp_ctx); |
| | | |
| | | log_nrml("Initialize PPP thread context ok\n"); |
| | | return 0; |
| | | } |
| | | |
| | | void ppp_context_term(ppp_ctx_t *ppp_ctx) |
| | | { |
| | | stop_ppp_connect(ppp_ctx); |
| | | set_ppp_disconnect(ppp_ctx); |
| | | |
| | | log_nrml("Terminate PPP thread context ok\n"); |
| | | } |
| | | |
| | | int start_ppp_connect(ppp_ctx_t *ppp_ctx) |
| | | { |
| | | int retval; |
| | | modinfo_t *module = ppp_ctx->module; |
| | | |
| | | if( !ppp_ctx->comport ) |
| | | { |
| | | ppp_ctx->comport=alloc_gsm_dataport("start_ppp_connect()", ppp_ctx->module); |
| | | if(!ppp_ctx->comport) |
| | | return -1; |
| | | |
| | | log_dbg("PPP thread alloc GPRS dataport %s=>[fd:%d]\n", ppp_ctx->comport->dev_name, ppp_ctx->comport->fd); |
| | | } |
| | | |
| | | |
| | | switch(ppp_ctx->status) |
| | | { |
| | | case DISCONNECT: /* Select the APN now */ |
| | | set_ppp_disconnect(ppp_ctx); |
| | | retval = select_apn(ppp_ctx, module->reg.loc.mcc_mnc); |
| | | if(!retval) |
| | | { |
| | | log_nrml("Select APN successfully, go to next stage.\n"); |
| | | ppp_ctx->fail_cnt = 0; |
| | | ppp_ctx->status++; |
| | | } |
| | | else |
| | | { |
| | | log_warn("Select APN failure, request to reset GPRS module\n"); |
| | | ppp_ctx->fail_cnt ++; |
| | | set_module_event(module, REQ_POWER_RESET); |
| | | break; |
| | | } |
| | | |
| | | case SELECTED_APN: /* Select the APN now */ |
| | | log_warn("Run pppd program to start PPP connection now\n"); |
| | | ppp_ctx->network = PPP_CONN; |
| | | start_ppp_dial_cmd(ppp_ctx->comport, &(ppp_ctx->apn), ppp_ctx->dev); |
| | | ppp_ctx->status++; |
| | | break; |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | int inspect_network_status(ppp_ctx_t *ppp_ctx) |
| | | { |
| | | pppd_info_t *pppd_info = &(ppp_ctx->pppd_info); |
| | | ppp_stat_t *ppp_stat = &(ppp_ctx->ppp_stat); |
| | | int lost_percent; |
| | | unsigned long long last_tx_bytes= ppp_stat->ullTx_Bytes; |
| | | unsigned long long last_rx_bytes= ppp_stat->ullRx_Bytes; |
| | | |
| | | if( CONNECTED != ppp_ctx->status) |
| | | { |
| | | ppp_ctx->pppd_info.ping_time = 0; |
| | | memset(ppp_stat, 0, sizeof(*ppp_stat)); |
| | | |
| | | pppd_info->pid = check_pppd_pid(ppp_ctx->comport->dev_name); |
| | | if(pppd_info->pid <= 0) |
| | | { |
| | | /* pppd can not connect in 30s, then set it to DISCONNECT status */ |
| | | if(time_elapsed(pppd_info->start_time) >= PPPD_DIAL_TIMEOUT) |
| | | { |
| | | /* Sleep for 2 seconds, make sure the exit pppd process release the TTY device */ |
| | | micro_second_sleep(2000); |
| | | log_err("pppd process exit when do ppp dialing, set status to DISCONNECT.\n"); |
| | | set_ppp_disconnect(ppp_ctx); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | if(strlen(pppd_info->netaddr) <=0 ) |
| | | { |
| | | check_ppp_ipaddr(pppd_info, ppp_ctx->dev); |
| | | log_dbg("pppd running process ID [%d].\n", pppd_info->pid); |
| | | } |
| | | } |
| | | } |
| | | |
| | | if( time_elapsed(pppd_info->ping_time) >= ppp_ctx->ping_interval*1000 ) |
| | | { |
| | | if(ppp_ctx->fail_cnt >= MAX_PPP_FAIL_CNT) |
| | | { |
| | | /* Sleep for 2 seconds, make sure the exit pppd process release the TTY device */ |
| | | micro_second_sleep(2000); |
| | | log_warn("PPP network inspect status failure, set status to DISCONNECT.\n"); |
| | | set_ppp_disconnect(ppp_ctx); |
| | | return 0; |
| | | } |
| | | |
| | | lost_percent = network_ping_test(ppp_ctx->dev, ppp_ctx->ping_ip); |
| | | ppp_ctx->network = lost_percent<=60 ? PPP_GOOD : PPP_BAD; |
| | | |
| | | if(lost_percent <= 80) |
| | | { |
| | | check_ppp_stat(ppp_stat, ppp_ctx->dev); |
| | | if(last_tx_bytes==ppp_stat->ullTx_Bytes || last_rx_bytes==ppp_stat->ullRx_Bytes) |
| | | { |
| | | log_warn("PPP interface traffic not increased, maybe ppp disconnected?\n"); |
| | | ppp_ctx->fail_cnt++; |
| | | } |
| | | else |
| | | { |
| | | log_nrml("Set PPP connection status to CONNECTED.\n"); |
| | | set_ppp_disconnect(ppp_ctx); |
| | | ppp_ctx->fail_cnt=0; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | ppp_ctx->fail_cnt++; |
| | | } |
| | | ppp_ctx->pppd_info.ping_time = time_now(); |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | void *ppp_thread_workbody(void *thread_arg) |
| | | { |
| | | ppp_ctx_t ppp_ctx; |
| | | modinfo_t *module; |
| | | |
| | | module = (modinfo_t *)thread_arg; |
| | | ppp_context_init(&ppp_ctx, module); |
| | | |
| | | log_nrml("GPRS PPP thread start running\n"); |
| | | |
| | | while( !g_cp_signal.stop ) |
| | | { |
| | | if(ALL_READY != module->ready) |
| | | { |
| | | if(ppp_ctx.status>=CONNECTING) |
| | | { |
| | | log_nrml("Stop exist PPP connection and free TTY data port\n"); |
| | | stop_ppp_connect(&ppp_ctx); |
| | | } |
| | | |
| | | /* GPRS not ready, sleep for 200ms and check again */ |
| | | micro_second_sleep(200); |
| | | continue; |
| | | } |
| | | else |
| | | { |
| | | if(ppp_ctx.status>=CONNECTING) |
| | | { |
| | | inspect_network_status(&ppp_ctx); |
| | | } |
| | | else |
| | | { |
| | | start_ppp_connect(&ppp_ctx); |
| | | } |
| | | } |
| | | |
| | | sleep(1); |
| | | } |
| | | |
| | | ppp_context_term(&ppp_ctx); |
| | | pthread_exit(0); |
| | | return NULL; |
| | | } |
| | | |
| | | int start_thread_ppp(modinfo_t *module) |
| | | { |
| | | pthread_t tid; |
| | | |
| | | return thread_start(&tid, ppp_thread_workbody, module); |
| | | } |
New file |
| | |
| | | /******************************************************************************** |
| | | * Copyright: (C) guowenxue<guowenxue@gmail.com> |
| | | * All rights reserved. |
| | | * |
| | | * Filename: ppp.h |
| | | * Description: This head file is for PPP dial up thread. |
| | | * |
| | | * Version: 1.0.0(02/17/2012~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "02/17/2012 11:11:54 AM" |
| | | * |
| | | ********************************************************************************/ |
| | | #ifndef __PPP_H |
| | | #define __PPP_H |
| | | |
| | | #include <netinet/in.h> |
| | | |
| | | #include "cp_comport.h" |
| | | #include "cp_proc.h" |
| | | #include "cp_gprs.h" |
| | | |
| | | #define PPPD_DIAL_TIMEOUT 20000 /* 20 seconds */ |
| | | #define PING_INTERVAL_TIME 10000 /* 10 seconds */ |
| | | |
| | | #define DEFAULT_PING_INTERVAL 30 |
| | | #define APN_LEN 128 |
| | | #define UID_LEN 64 |
| | | #define PWD_LEN 64 |
| | | |
| | | #define APN_3G 3 |
| | | #define APN_2G 2 |
| | | |
| | | #define PPPD_DIAL_SCRIPTS "/apps/tools/ifup-ppp" |
| | | #define PPP_INTERFACE_NAME "ppp10" |
| | | #define PPP_PROC_NET_DEV "/proc/net/dev" |
| | | |
| | | #define DEF_PING_DST "4.2.2.2" |
| | | |
| | | #define APN_DEF_CONF_FILE "/apps/etc/ppp/default_apn.conf" |
| | | |
| | | enum |
| | | { |
| | | DISCONNECT = 0, |
| | | SELECTED_APN, |
| | | CONNECTING, |
| | | CONNECTED, |
| | | }; |
| | | |
| | | |
| | | typedef struct apn_account_s |
| | | { |
| | | char apn[APN_LEN]; |
| | | char uid[UID_LEN]; |
| | | char pwd[PWD_LEN]; |
| | | char auth[10]; /* PAP or CHAP */ |
| | | } apn_account_t; |
| | | |
| | | typedef struct pppd_info_s |
| | | { |
| | | char netaddr[INET_ADDRSTRLEN]; |
| | | char ptpaddr[INET_ADDRSTRLEN]; |
| | | unsigned long start_time; |
| | | unsigned long ping_time; |
| | | pid_t pid; |
| | | } pppd_info_t; |
| | | |
| | | typedef struct ppp_stat_s |
| | | { |
| | | unsigned long long ullRx_Packets; // total packets received |
| | | unsigned long long ullTx_Packets; // total packets transmitted |
| | | unsigned long long ullRx_Bytes; // total bytes received |
| | | unsigned long long ullTx_Bytes; // total bytes transmitted |
| | | |
| | | unsigned long ulRx_Errors; // bad packets received |
| | | unsigned long ulTx_Errors; // packet transmit problems |
| | | unsigned long ulRx_Dropped; // no space in linux buffers |
| | | unsigned long ulTx_Dropped; // no space available in linux |
| | | unsigned long ulRx_Multicast; // multicast packets received |
| | | unsigned long ulRx_Compressed; |
| | | unsigned long ulTx_Compressed; |
| | | unsigned long ulCollisions; |
| | | |
| | | /* detailed rx_errors */ |
| | | unsigned long ulRx_Length_Errors; |
| | | unsigned long ulRx_Over_Errors; // receiver ring buff overflow |
| | | unsigned long ulRx_CRC_Errors; // recved pkt with crc error |
| | | unsigned long ulRx_Frame_Errors; // recv'd frame alignment error |
| | | unsigned long ulRx_FIFO_Errors; // recv'r fifo overrun |
| | | unsigned long ulRx_Missed_Errors; // receiver missed packet |
| | | |
| | | /* detailed tx_errors */ |
| | | unsigned long ulTx_Aborted_Errors; |
| | | unsigned long ulTx_Carrier_Errors; |
| | | unsigned long ulTx_FIFO_Errors; |
| | | unsigned long ulTx_Heartbeat_Errors; |
| | | unsigned long ulTx_Window_Errors; |
| | | } ppp_stat_t; |
| | | |
| | | #define MAX_PPP_FAIL_CNT 3 |
| | | |
| | | #define PPP_STOP 0 /* PPP not work, but signal good */ |
| | | #define SIG_WEAK 1 /* PPP not work and signal is very weak */ |
| | | #define PPP_CONN 2 /* PPP is connecting */ |
| | | #define PPP_BAD 3 /* PPP is connected, but network/signal not good */ |
| | | #define PPP_GOOD 4 /* PPP is connected and network/signal good */ |
| | | typedef struct ppp_ctx_s |
| | | { |
| | | unsigned char enable; /* Enable PPP thread running or not, RFU */ |
| | | unsigned char status; /* Current PPP connection status */ |
| | | unsigned char network; /* PPP network status: PPP_FAIL,PPP_BAD,PPP_GOOD */ |
| | | char dev[10]; /* PPP dial up device name, such as PPP10 */ |
| | | |
| | | pthread_t thread_id; /* PPP Thread ID, RFU */ |
| | | |
| | | pppd_info_t pppd_info; /* pppd process information */ |
| | | ppp_stat_t ppp_stat; /* PPP network statistic */ |
| | | unsigned char fail_cnt; /* PPP failure count */ |
| | | |
| | | apn_account_t apn; /* PPP dial up APN */ |
| | | |
| | | char ping_ip[INET_ADDRSTRLEN]; |
| | | long ping_interval; |
| | | |
| | | comport_t *comport; |
| | | modinfo_t *module; |
| | | } ppp_ctx_t; |
| | | |
| | | int get_apn_conf(char *ini_name, char *ini_key, apn_account_t *apn, unsigned char type); |
| | | int check_pppd_pid(char *find_key); |
| | | int check_ppp_interface(char *ppp_inf); |
| | | int start_ppp_dial_cmd(comport_t *comport, apn_account_t *apn, char *ppp_inf); |
| | | int check_ppp_ipaddr(pppd_info_t *pppd_info, char *ppp_inf); |
| | | int check_ppp_stat_t(ppp_stat_t *ppp_stat, char *ppp_inf); |
| | | int stop_ppp_connect(ppp_ctx_t *ppp_ctx); |
| | | |
| | | int start_thread_ppp(modinfo_t *module); |
| | | |
| | | #endif /* End of __PPP_H */ |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2012 Guo Wenxue<guowenxue@gmail.com> |
| | | * All rights reserved. |
| | | * |
| | | * Filename: cp_proc.c |
| | | * Description: This file is the process API |
| | | * |
| | | * Version: 1.0.0(11/06/2012~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "11/06/2012 09:19:02 PM" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <unistd.h> |
| | | #include <libgen.h> |
| | | #include <fcntl.h> |
| | | #include <sys/types.h> |
| | | #include <sys/stat.h> |
| | | |
| | | #include "cp_proc.h" |
| | | #include "cp_logger.h" |
| | | |
| | | CP_PROC_SIG g_cp_signal={0}; |
| | | |
| | | void cp_proc_sighandler(int sig) |
| | | { |
| | | switch(sig) |
| | | { |
| | | case SIGINT: |
| | | log_warn("SIGINT - stopping\n"); |
| | | g_cp_signal.stop = 1; |
| | | break; |
| | | |
| | | case SIGTERM: |
| | | //log_warn("SIGTERM - stopping\n"); |
| | | g_cp_signal.stop = 1; |
| | | break; |
| | | #if 0 |
| | | case SIGSEGV: |
| | | log_err("SIGSEGV - stopping\n"); |
| | | if(g_cp_signal.stop) |
| | | exit(0); |
| | | |
| | | g_cp_signal.stop = 1; |
| | | break; |
| | | #endif |
| | | |
| | | case SIGPIPE: |
| | | log_warn("SIGPIPE - warnning\n"); |
| | | g_cp_signal.stop = 1; |
| | | break; |
| | | |
| | | default: |
| | | break; |
| | | } |
| | | } |
| | | |
| | | |
| | | void cp_install_proc_signal(void) |
| | | { |
| | | struct sigaction sigact, sigign; |
| | | |
| | | log_nrml("Install default signal handler.\n"); |
| | | |
| | | /* Initialize the catch signal structure. */ |
| | | sigemptyset(&sigact.sa_mask); |
| | | sigact.sa_flags = 0; |
| | | sigact.sa_handler = cp_proc_sighandler; |
| | | |
| | | /* Setup the ignore signal. */ |
| | | sigemptyset(&sigign.sa_mask); |
| | | sigign.sa_flags = 0; |
| | | sigign.sa_handler = SIG_IGN; |
| | | |
| | | sigaction(SIGTERM, &sigact, 0); /* catch terminate signal "kill" command */ |
| | | sigaction(SIGINT, &sigact, 0); /* catch interrupt signal CTRL+C */ |
| | | //sigaction(SIGSEGV, &sigact, 0); /* catch segmentation faults */ |
| | | sigaction(SIGPIPE, &sigact, 0); /* catch broken pipe */ |
| | | #if 0 |
| | | sigaction(SIGCHLD, &sigact, 0); /* catch child process return */ |
| | | sigaction(SIGUSR2, &sigact, 0); /* catch USER signal */ |
| | | #endif |
| | | } |
| | | |
| | | |
| | | /* **************************************************************************** |
| | | * FunctionName: daemonize |
| | | * Description : Set the programe runs as daemon in background |
| | | * Inputs : nodir: DON'T change the work directory to / : 1:NoChange 0:Change |
| | | * noclose: close the opened file descrtipion or not 1:Noclose 0:Close |
| | | * Output : NONE |
| | | * Return : NONE |
| | | * *****************************************************************************/ |
| | | void daemonize(int nochdir, int noclose) |
| | | { |
| | | int retval, fd; |
| | | int i; |
| | | |
| | | /* already a daemon */ |
| | | if (1 == getppid()) |
| | | return; |
| | | |
| | | /* fork error */ |
| | | retval = fork(); |
| | | if (retval < 0) exit(1); |
| | | |
| | | /* parent process exit */ |
| | | if (retval > 0) |
| | | exit(0); |
| | | |
| | | /* obtain a new process session group */ |
| | | setsid(); |
| | | |
| | | if (!noclose) |
| | | { |
| | | /* close all descriptors */ |
| | | for (i = getdtablesize(); i >= 0; --i) |
| | | { |
| | | //if (i != g_logPtr->fd) |
| | | close(i); |
| | | } |
| | | |
| | | /* Redirect Standard input [0] to /dev/null */ |
| | | fd = open("/dev/null", O_RDWR); |
| | | |
| | | /* Redirect Standard output [1] to /dev/null */ |
| | | dup(fd); |
| | | |
| | | /* Redirect Standard error [2] to /dev/null */ |
| | | dup(fd); |
| | | } |
| | | |
| | | umask(0); |
| | | |
| | | if (!nochdir) |
| | | chdir("/"); |
| | | |
| | | return; |
| | | } |
| | | |
| | | /* **************************************************************************** |
| | | * FunctionName: record_daemon_pid |
| | | * Description : Record the running daemon program PID to the file "pid_file" |
| | | * Inputs : pid_file:The record PID file path |
| | | * Output : NONE |
| | | * Return : 0: Record successfully Else: Failure |
| | | * *****************************************************************************/ |
| | | int record_daemon_pid(const char *pid_file) |
| | | { |
| | | struct stat fStatBuf; |
| | | int fd = -1; |
| | | int mode = S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU; |
| | | char ipc_dir[64] = { 0 }; |
| | | |
| | | strncpy(ipc_dir, pid_file, 64); |
| | | |
| | | /* dirname() will modify ipc_dir and save the result */ |
| | | dirname(ipc_dir); |
| | | |
| | | /* If folder pid_file PATH doesnot exist, then we will create it" */ |
| | | if (stat(ipc_dir, &fStatBuf) < 0) |
| | | { |
| | | if (mkdir(ipc_dir, mode) < 0) |
| | | { |
| | | log_fatal("cannot create %s: %s\n", ipc_dir, strerror(errno)); |
| | | return -1; |
| | | } |
| | | |
| | | (void)chmod(ipc_dir, mode); |
| | | } |
| | | |
| | | /* Create the process running PID file */ |
| | | mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; |
| | | if ((fd = open(pid_file, O_RDWR | O_CREAT | O_TRUNC, mode)) >= 0) |
| | | { |
| | | char pid[PID_ASCII_SIZE]; |
| | | snprintf(pid, sizeof(pid), "%u\n", (unsigned)getpid()); |
| | | write(fd, pid, strlen(pid)); |
| | | close(fd); |
| | | |
| | | log_dbg("Record PID<%u> to file %s.\n", getpid(), pid_file); |
| | | } |
| | | else |
| | | { |
| | | log_fatal("cannot create %s: %s\n", pid_file, strerror(errno)); |
| | | return -1; |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | /* **************************************************************************** |
| | | * FunctionName: get_daemon_pid |
| | | * Description : Get the daemon process PID from the PID record file "pid_file" |
| | | * Inputs : pid_file: the PID record file |
| | | * Output : NONE |
| | | * Return : pid_t: The daemon process PID number |
| | | * *****************************************************************************/ |
| | | pid_t get_daemon_pid(const char *pid_file) |
| | | { |
| | | FILE *f; |
| | | pid_t pid; |
| | | |
| | | if ((f = fopen(pid_file, "rb")) != NULL) |
| | | { |
| | | char pid_ascii[PID_ASCII_SIZE]; |
| | | (void)fgets(pid_ascii, PID_ASCII_SIZE, f); |
| | | (void)fclose(f); |
| | | pid = atoi(pid_ascii); |
| | | } |
| | | else |
| | | { |
| | | log_fatal("Can't open PID record file %s: %s\n", pid_file, strerror(errno)); |
| | | return -1; |
| | | } |
| | | return pid; |
| | | } |
| | | |
| | | /* **************************************************************************** |
| | | * FunctionName: check_daemon_running |
| | | * Description : Check the daemon program already running or not |
| | | * Inputs : pid_file: The record running daemon program PID |
| | | * Output : NONE |
| | | * Return : 1: The daemon program alread running 0: Not running |
| | | * *****************************************************************************/ |
| | | int check_daemon_running(const char *pid_file) |
| | | { |
| | | int retVal = -1; |
| | | struct stat fStatBuf; |
| | | |
| | | retVal = stat(pid_file, &fStatBuf); |
| | | if (0 == retVal) |
| | | { |
| | | pid_t pid = -1; |
| | | printf("PID record file \"%s\" exist.\n", pid_file); |
| | | |
| | | pid = get_daemon_pid(pid_file); |
| | | if (pid > 0) /* Process pid exist */ |
| | | { |
| | | if ((retVal = kill(pid, 0)) == 0) |
| | | { |
| | | printf("Program with PID[%d] seems running.\n", pid); |
| | | return 1; |
| | | } |
| | | else /* Send signal to the old process get no reply. */ |
| | | { |
| | | printf("Program with PID[%d] seems exit.\n", pid); |
| | | remove(pid_file); |
| | | return 0; |
| | | } |
| | | } |
| | | else if (0 == pid) |
| | | { |
| | | printf("Can not read program PID form record file.\n"); |
| | | remove(pid_file); |
| | | return 0; |
| | | } |
| | | else /* Read pid from file "pid_file" failure */ |
| | | { |
| | | printf("Read record file \"%s\" failure, maybe program still running.\n", pid_file); |
| | | return 1; |
| | | } |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | /* **************************************************************************** |
| | | * FunctionName: set_daemon_running |
| | | * Description : Set the programe running as daemon if it's not running and record |
| | | * its PID to the pid_file. |
| | | * Inputs : pid_file: The record running daemon program PID |
| | | * Output : NONE |
| | | * Return : 0: Successfully. 1: Failure |
| | | * *****************************************************************************/ |
| | | int set_daemon_running(const char *pid_file) |
| | | { |
| | | daemonize(0, 1); |
| | | log_nrml("Program running as daemon [PID:%d].\n", getpid()); |
| | | |
| | | if (record_daemon_pid(pid_file) < 0) |
| | | { |
| | | log_fatal("Record PID to file \"%s\" failure.\n", pid_file); |
| | | return -2; |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | int thread_start(pthread_t * thread_id, THREAD_BODY * thread_workbody, void *thread_arg) |
| | | { |
| | | int retval = 0; |
| | | |
| | | pthread_attr_t thread_attr; |
| | | |
| | | /* Initialize the thread attribute */ |
| | | retval = pthread_attr_init(&thread_attr); |
| | | if(retval) |
| | | return -1; |
| | | |
| | | /* Set the stack size of the thread */ |
| | | retval = pthread_attr_setstacksize(&thread_attr, 120 * 1024); |
| | | if(retval) |
| | | goto CleanUp; |
| | | |
| | | /* Set thread to detached state:Don`t need pthread_join */ |
| | | retval = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); |
| | | if(retval) |
| | | goto CleanUp; |
| | | |
| | | /* Create the thread */ |
| | | retval = pthread_create(thread_id, &thread_attr, thread_workbody, thread_arg); |
| | | if(retval) |
| | | goto CleanUp; |
| | | |
| | | CleanUp: |
| | | /* Destroy the attributes of thread */ |
| | | pthread_attr_destroy(&thread_attr); |
| | | return retval; |
| | | } |
| | | |
| | | |
| | | void exec_system_cmd(const char *format, ...) |
| | | { |
| | | char cmd[256]; |
| | | va_list args; |
| | | |
| | | memset(cmd, 0, sizeof(cmd)); |
| | | |
| | | va_start(args, format); |
| | | vsnprintf(cmd, sizeof(cmd), format, args); |
| | | va_end(args); |
| | | |
| | | system(cmd); |
| | | } |
| | | |
| | | |
New file |
| | |
| | | /******************************************************************************** |
| | | * Copyright: (C) 2012 Guo Wenxue<guowenxue@gmail.com> |
| | | * All rights reserved. |
| | | * |
| | | * Filename: cp_proc.h |
| | | * Description: This head file is for Linux process API |
| | | * |
| | | * Version: 1.0.0(11/06/2012~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "11/06/2012 09:21:33 PM" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #ifndef __CP_PROC_H |
| | | #define __CP_PROC_H |
| | | |
| | | #include <signal.h> |
| | | |
| | | #define PID_ASCII_SIZE 11 |
| | | |
| | | typedef struct __CP_PROC_SIG |
| | | { |
| | | int signal; |
| | | unsigned stop; /* 0: Not term 1: Stop */ |
| | | } CP_PROC_SIG; |
| | | |
| | | typedef void *(THREAD_BODY) (void *thread_arg); |
| | | |
| | | extern CP_PROC_SIG g_cp_signal; |
| | | extern void cp_install_proc_signal(void); |
| | | |
| | | extern void daemonize(int nochdir, int noclose); |
| | | extern int record_daemon_pid(const char *pid_file); |
| | | extern pid_t get_daemon_pid(const char *pid_file); |
| | | extern int check_daemon_running(const char *pid_file); |
| | | extern int set_daemon_running(const char *pid_file); |
| | | |
| | | extern void exec_system_cmd(const char *format, ...); |
| | | |
| | | extern int thread_start(pthread_t * thread_id, THREAD_BODY * thread_workbody, void *thread_arg); |
| | | |
| | | #endif |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2012 Guo Wenxue<guowenxue@gmail.com> |
| | | * All rights reserved. |
| | | * |
| | | * Filename: cp_queue.c |
| | | * Description: This file is the queue implement based on link list. |
| | | * |
| | | * Version: 1.0.0(11/12/2012~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "11/12/2012 01:25:26 PM" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #include "cp_queue.h" |
| | | #include "cp_common.h" |
| | | |
| | | CP_QUEUE *cp_queue_init(CP_QUEUE *queue, int size) |
| | | { |
| | | if(!queue) |
| | | { |
| | | queue = malloc(sizeof(*queue)); |
| | | } |
| | | memset(queue, 0, sizeof(*queue)); |
| | | |
| | | queue->size = size; |
| | | queue->items = 0; |
| | | queue->rear = queue->front = NULL; |
| | | |
| | | return queue; |
| | | } |
| | | |
| | | void *cp_enqueue(CP_QUEUE *queue, void *data) |
| | | { |
| | | CP_QNODE *node; |
| | | |
| | | if(!queue || cp_queue_is_full(queue)) |
| | | { |
| | | return NULL; |
| | | } |
| | | |
| | | node = malloc(sizeof(*node)); |
| | | if(NULL == node) |
| | | { |
| | | return NULL; |
| | | } |
| | | |
| | | node->item = data; |
| | | node->next = NULL; |
| | | |
| | | if(cp_queue_is_empty(queue)) |
| | | { |
| | | queue->front = node; |
| | | } |
| | | else |
| | | { |
| | | queue->rear->next = node; |
| | | } |
| | | |
| | | queue->rear = node; |
| | | queue->items++; |
| | | |
| | | return data; |
| | | } |
| | | |
| | | void cp_travel_queue(CP_QUEUE *queue) |
| | | { |
| | | CP_QNODE *node; |
| | | |
| | | for(node=queue->front; node!=NULL; node=node->next) |
| | | { |
| | | printf("queue node[%p] save data [%p]\n", node, node->item); |
| | | } |
| | | } |
| | | |
| | | void *cp_rmqueue(CP_QUEUE *queue, void *data) |
| | | { |
| | | CP_QNODE *node, *tmp; |
| | | |
| | | if(!queue || cp_queue_is_empty(queue)) |
| | | { |
| | | return NULL; |
| | | } |
| | | |
| | | /* The first node->item is the data, we find it */ |
| | | if(queue->front->item==data) |
| | | { |
| | | tmp = queue->front; |
| | | queue->front = queue->front->next; |
| | | queue->items -= 1; |
| | | free(tmp); |
| | | return data; |
| | | } |
| | | |
| | | for(node=queue->front; node!=NULL; node=node->next) |
| | | { |
| | | if(node->next->item == data) |
| | | { |
| | | tmp = node->next; |
| | | queue->items -= 1; |
| | | |
| | | if(node->next != queue->rear) |
| | | node->next = node->next->next; |
| | | else |
| | | { |
| | | queue->rear = node; |
| | | queue->rear->next = NULL; |
| | | } |
| | | |
| | | free(tmp); |
| | | return data; |
| | | } |
| | | } |
| | | |
| | | return data; |
| | | } |
| | | |
| | | void *cp_dequeue(CP_QUEUE *queue) |
| | | { |
| | | CP_QNODE *node; |
| | | void *item; |
| | | |
| | | if(!queue || cp_queue_is_empty(queue)) |
| | | { |
| | | return NULL; |
| | | } |
| | | |
| | | node = queue->front; |
| | | queue->front = queue->front->next; |
| | | |
| | | item = node->item; |
| | | free(node); |
| | | |
| | | queue->items--; |
| | | |
| | | if(queue->items == 0) |
| | | queue->rear = NULL; |
| | | |
| | | return item; |
| | | } |
| | | |
| | | void cp_queue_destroy(CP_QUEUE *queue) |
| | | { |
| | | if(!queue) |
| | | return ; |
| | | |
| | | while( !cp_queue_is_empty(queue) ) |
| | | { |
| | | cp_dequeue(queue); |
| | | } |
| | | |
| | | free(queue); |
| | | |
| | | return ; |
| | | } |
| | | |
New file |
| | |
| | | /******************************************************************************** |
| | | * Copyright: (C) 2012 Guo Wenxue<guowenxue@gmail.com> |
| | | * All rights reserved. |
| | | * |
| | | * Filename: cp_queue.h |
| | | * Description: This head file is for the queue implement based on link list. |
| | | * |
| | | * Version: 1.0.0(11/12/2012~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "11/12/2012 01:26:34 PM" |
| | | * |
| | | ********************************************************************************/ |
| | | #ifndef __CP_QUEUE |
| | | #define __CP_QUEUE |
| | | |
| | | #include <stdio.h> |
| | | #include <unistd.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | |
| | | typedef struct _CP_QNODE |
| | | { |
| | | void *item; |
| | | struct _CP_QNODE *next; |
| | | } CP_QNODE; |
| | | |
| | | |
| | | typedef struct _CP_QUEUE |
| | | { |
| | | CP_QNODE *front; |
| | | CP_QNODE *rear; |
| | | int items; |
| | | int size; |
| | | } CP_QUEUE; |
| | | |
| | | #define cp_queue_is_full(pq) ( (pq)->size==(pq)->items ? 1 :0 ) |
| | | #define cp_queue_is_empty(pq) ( 0==(pq)->items ? 1 : 0) |
| | | #define cp_queue_count(pq) ( (pq)->items ) |
| | | #define cp_queue_size(pq) ( (pq)->size ) |
| | | |
| | | CP_QUEUE *cp_queue_init(CP_QUEUE *queue, int size); |
| | | void *cp_enqueue(CP_QUEUE *queue, void *data); |
| | | void cp_travel_queue(CP_QUEUE *queue); |
| | | void *cp_rmqueue(CP_QUEUE *queue, void *data); |
| | | void *cp_dequeue(CP_QUEUE *queue); |
| | | void cp_queue_destroy(CP_QUEUE *queue); |
| | | #define cp_queue_destroy_clear(queue) {cp_queue_destroy(queue); queue=NULL;} |
| | | |
| | | #endif |
New file |
| | |
| | | /* |
| | | This program is free software; you can redistribute it and/or modify |
| | | it under the terms of the GNU General Public License as published by |
| | | the Free Software Foundation; either version 2 of the License, or |
| | | (at your option) any later version. |
| | | |
| | | This program is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | GNU General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU General Public License |
| | | along with this program; if not, write to the Free Software |
| | | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| | | |
| | | Based on ringbuffer.c by Patrick Prasse (patrick.prasse@gmx.net). Code |
| | | has been modified by Telenor and Gemalto. |
| | | |
| | | */ |
| | | |
| | | |
| | | #include <string.h> |
| | | #include <assert.h> |
| | | #include "cp_ringbuf.h" |
| | | |
| | | void rb_init (struct ring_buffer *ring, u_char* buff, int size) { |
| | | memset (ring, 0, sizeof (struct ring_buffer)); |
| | | ring->rd_pointer = 0; |
| | | ring->wr_pointer = 0; |
| | | ring->buffer= buff; |
| | | ring->size = size; |
| | | } |
| | | |
| | | int |
| | | rb_write (struct ring_buffer *rb, u_char * buf, int len) |
| | | { |
| | | int total; |
| | | int i; |
| | | |
| | | /* total = len = min(space, len) */ |
| | | total = rb_free_size(rb); |
| | | if(len > total) |
| | | len = total; |
| | | else |
| | | total = len; |
| | | |
| | | i = rb->wr_pointer; |
| | | if(i + len > rb->size) |
| | | { |
| | | memcpy(rb->buffer + i, buf, rb->size - i); |
| | | buf += rb->size - i; |
| | | len -= rb->size - i; |
| | | i = 0; |
| | | } |
| | | memcpy(rb->buffer + i, buf, len); |
| | | rb->wr_pointer = i + len; |
| | | return total; |
| | | } |
| | | |
| | | int rb_free_size (struct ring_buffer *rb){ |
| | | return (rb->size - 1 - rb_data_size(rb)); |
| | | } |
| | | |
| | | int rb_read (struct ring_buffer *rb, u_char * buf, int max) { |
| | | int total; |
| | | int i; |
| | | /* total = len = min(used, len) */ |
| | | total = rb_data_size(rb); |
| | | |
| | | if(max > total) |
| | | max = total; |
| | | else |
| | | total = max; |
| | | |
| | | i = rb->rd_pointer; |
| | | if(i + max > rb->size) |
| | | { |
| | | memcpy(buf, rb->buffer + i, rb->size - i); |
| | | buf += rb->size - i; |
| | | max -= rb->size - i; |
| | | i = 0; |
| | | } |
| | | memcpy(buf, rb->buffer + i, max); |
| | | rb->rd_pointer = i + max; |
| | | |
| | | return total; |
| | | } |
| | | |
| | | int rb_data_size (struct ring_buffer *rb) { |
| | | return ((rb->wr_pointer - rb->rd_pointer) & (rb->size-1)); |
| | | } |
| | | |
| | | void rb_clear (struct ring_buffer *rb) { |
| | | memset(rb->buffer,0,rb->size); |
| | | rb->rd_pointer=0; |
| | | rb->wr_pointer=0; |
| | | } |
| | | |
| | | u_char rb_peek(struct ring_buffer* rb, int index) { |
| | | assert(index < rb_data_size(rb)); |
| | | |
| | | return rb->buffer[((rb->rd_pointer + index) % rb->size)]; |
| | | } |
New file |
| | |
| | | /* |
| | | This program is free software; you can redistribute it and/or modify |
| | | it under the terms of the GNU General Public License as published by |
| | | the Free Software Foundation; either version 2 of the License, or |
| | | (at your option) any later version. |
| | | |
| | | This program is distributed in the hope that it will be useful, |
| | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | | GNU General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU General Public License |
| | | along with this program; if not, write to the Free Software |
| | | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| | | |
| | | Based on ringbuffer.h by Patrick Prasse (patrick.prasse@gmx.net). Code |
| | | has been modified by Telenor and Gemalto. |
| | | |
| | | */ |
| | | |
| | | #ifndef __CP_RINGBUF_H_ |
| | | #define __CP_RINGBUF_H_ |
| | | |
| | | #include <sys/types.h> |
| | | |
| | | struct ring_buffer { |
| | | u_char *buffer; |
| | | int wr_pointer; |
| | | int rd_pointer; |
| | | int size; |
| | | }; |
| | | |
| | | /* Initial the ring buffer */ |
| | | void rb_init (struct ring_buffer *ring, u_char* buff, int size) ; |
| | | |
| | | /* Description: Write $len bytes data in $buf into ring buffer $rb |
| | | * Return Value: The actual written into ring buffer data size, if ring buffer |
| | | * left space size small than $len, then only part of the data be written into. |
| | | */ |
| | | int rb_write (struct ring_buffer *rb, u_char * buf, int len) ; |
| | | |
| | | /* Get ring buffer left free size */ |
| | | int rb_free_size (struct ring_buffer *rb); |
| | | |
| | | /* Read $max bytes data from ring buffer $rb to $buf */ |
| | | int rb_read (struct ring_buffer *rb, u_char * buf, int max); |
| | | |
| | | /* Read a specify $index byte data in ring buffer $rb */ |
| | | u_char rb_peek(struct ring_buffer* rb, int index); |
| | | |
| | | /* Get data size in the ring buffer */ |
| | | int rb_data_size (struct ring_buffer *); |
| | | |
| | | /* Clear the ring buffer data */ |
| | | void rb_clear (struct ring_buffer *rb) ; |
| | | |
| | | #endif /* __CP_RINGBUF_H_ */ |
New file |
| | |
| | | |
| | | /** |
| | | * @addtogroup cp_string |
| | | */ |
| | | /** @{ */ |
| | | /** |
| | | * @file |
| | | * cp_string - 'safe' string implementation |
| | | */ |
| | | |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #include <unistd.h> |
| | | #include <errno.h> |
| | | |
| | | #include "cp_string.h" |
| | | #include "cp_common.h" |
| | | |
| | | cp_string *cp_string_create(char *data, int len) |
| | | { |
| | | cp_string *str; |
| | | |
| | | #ifdef DEBUG |
| | | if (len < 0) |
| | | { |
| | | return NULL; |
| | | } |
| | | #endif |
| | | |
| | | str = malloc(sizeof(cp_string)); |
| | | |
| | | if (str) |
| | | { |
| | | str->len = len; |
| | | str->size = str->len + 1; |
| | | str->data = malloc(str->size * sizeof(char)); |
| | | if (str->data) |
| | | memcpy(str->data, data, str->len); |
| | | else |
| | | { |
| | | free(str); |
| | | str = NULL; |
| | | } |
| | | } |
| | | |
| | | return str; |
| | | } |
| | | |
| | | cp_string *cp_string_create_empty(int initial_size) |
| | | { |
| | | cp_string *str = malloc(sizeof(cp_string)); |
| | | |
| | | if (str) |
| | | { |
| | | str->len = 0; |
| | | str->size = initial_size; |
| | | str->data = (char *) malloc(str->size * sizeof(char)); |
| | | if (str->data == NULL) |
| | | { |
| | | free(str); |
| | | str = NULL; |
| | | } |
| | | } |
| | | |
| | | return str; |
| | | } |
| | | |
| | | void cp_string_destroy(cp_string *str) |
| | | { |
| | | if (str) |
| | | { |
| | | if (str->data) |
| | | { |
| | | free(str->data); |
| | | } |
| | | |
| | | free(str); |
| | | } |
| | | } |
| | | |
| | | |
| | | void cp_string_clear_data(cp_string *str) |
| | | { |
| | | if (str && str->data) |
| | | { |
| | | memset(str->data, 0, str->size); |
| | | str->len = 0; |
| | | } |
| | | } |
| | | |
| | | cp_string *cp_string_cstrcpy(cp_string *str, char *cstr) |
| | | { |
| | | if (str) |
| | | { |
| | | str->len = strlen(cstr); |
| | | if (str->size < str->len + 1) |
| | | { |
| | | str->size = str->len + 1; |
| | | str->data = malloc(str->size * sizeof(char)); |
| | | } |
| | | if (str->data) |
| | | memcpy(str->data, cstr, str->size * sizeof(char)); |
| | | else |
| | | { |
| | | free(str); |
| | | str = NULL; |
| | | } |
| | | } |
| | | |
| | | return str; |
| | | } |
| | | |
| | | int cp_string_copy(cp_string *dst, cp_string *src) |
| | | { |
| | | int left; |
| | | int size; |
| | | |
| | | if(!dst || !dst->data || !src || !src->data) |
| | | return 0; |
| | | |
| | | left=dst->size - dst->len; |
| | | size = left>src->len ? src->len : left; |
| | | |
| | | memcpy(&dst->data[dst->len], src->data, size); |
| | | dst->len += size; |
| | | |
| | | return size; |
| | | } |
| | | |
| | | int cp_string_cstrcopy(cp_string *dst, char *string, int len) |
| | | { |
| | | int left; |
| | | int size; |
| | | |
| | | if(!dst || !dst->data || !string || len<=0) |
| | | return 0; |
| | | |
| | | left=dst->size - dst->len; |
| | | size = left>len ? len : left; |
| | | |
| | | memcpy(&dst->data[dst->len], string, size); |
| | | dst->len += size; |
| | | |
| | | return size; |
| | | } |
| | | |
| | | |
| | | int cp_string_move(cp_string *dst, cp_string *src) |
| | | { |
| | | int left; |
| | | int size; |
| | | |
| | | if(!dst || !dst->data || !src || !src->data) |
| | | return 0; |
| | | |
| | | /* Check how many left size in $dst and set the size */ |
| | | left=dst->size - dst->len; |
| | | size = left>src->len ? src->len : left; |
| | | |
| | | /* copy the $src data to $dst */ |
| | | memcpy(&dst->data[dst->len], src->data, size); |
| | | dst->len += size; |
| | | |
| | | /* remove the $src copied data in it*/ |
| | | src->len -= size; |
| | | memmove (src->data, src->data+size, src->len); |
| | | |
| | | return size; |
| | | } |
| | | |
| | | cp_string *cp_string_dup(cp_string *src) |
| | | { |
| | | cp_string *str = malloc(sizeof(cp_string)); |
| | | |
| | | if (str) |
| | | { |
| | | *str = *src; /* bitwise copy */ |
| | | str->data = malloc((str->len + 1) * sizeof(char)); |
| | | if (str->data) |
| | | memcpy(str->data, src->data, (str->len + 1) * sizeof(char)); |
| | | else |
| | | { |
| | | free(str); |
| | | str = NULL; |
| | | } |
| | | } |
| | | |
| | | return str; |
| | | } |
| | | |
| | | cp_string *cp_string_cstrdup(char *src) |
| | | { |
| | | cp_string *str = malloc(sizeof(cp_string)); |
| | | |
| | | if (str) |
| | | { |
| | | str->len = strlen(src); |
| | | str->size = str->len + 1; |
| | | str->data = malloc(str->size * sizeof(char)); |
| | | if (str->data == NULL) |
| | | { |
| | | free(str); |
| | | return NULL; |
| | | } |
| | | memcpy(str->data, src, str->size); |
| | | } |
| | | |
| | | return str; |
| | | } |
| | | |
| | | cp_string *cp_string_cat(cp_string *str, cp_string *appendum) |
| | | { |
| | | int len = str->len; |
| | | str->len += appendum->len; |
| | | if (str->len + 1 > str->size) |
| | | { |
| | | str->size = str->len + 1; |
| | | str->data = realloc(str->data, str->size * sizeof(char)); |
| | | } |
| | | if (str->data) |
| | | memcpy(str->data + len * sizeof(char), appendum->data, |
| | | appendum->len * sizeof(char)); |
| | | |
| | | return str; |
| | | } |
| | | |
| | | cp_string *cp_string_cstrcat(cp_string *str, char *cstr) |
| | | { |
| | | int len = str->len; |
| | | int clen = strlen(cstr); |
| | | |
| | | str->len += clen * sizeof(char); |
| | | if (str->len + 1 > str->size) |
| | | { |
| | | // str->size = str->len + 0x400 - (str->len % 0x400); /* align to 1kb block */ |
| | | str->size = str->len + 1; |
| | | str->data = realloc(str->data, str->size * sizeof(char)); |
| | | } |
| | | if (str->data) |
| | | memcpy(str->data + len * sizeof(char), cstr, clen); |
| | | |
| | | return str; |
| | | } |
| | | |
| | | cp_string *cp_string_append_char(cp_string *str, char ch) |
| | | { |
| | | if (str->len + 1 > str->size) |
| | | { |
| | | str->size = str->len + 0x100; |
| | | str->data = realloc(str->data, str->size * sizeof(char)); |
| | | if (str->data == NULL) return NULL; |
| | | } |
| | | str->data[str->len++] = ch; |
| | | |
| | | return str; |
| | | } |
| | | |
| | | cp_string *cp_string_cat_bin(cp_string *str, void *bin, int len) |
| | | { |
| | | int olen = str->len; |
| | | str->len += len; |
| | | |
| | | if (str->len > str->size) |
| | | { |
| | | str->size = str->len + 0x400 - (str->len % 0x400); /* align to 1kb block */ |
| | | str->data = realloc(str->data, str->size * sizeof(char)); |
| | | } |
| | | memcpy(&str->data[olen], bin, len); |
| | | |
| | | return str; |
| | | } |
| | | |
| | | int cp_string_cmp(cp_string *s1, cp_string *s2) |
| | | { |
| | | if (s1 == s2) return 0; //~~ implies cp_string_cmp(NULL, NULL) == 0 |
| | | |
| | | if (s1 == NULL) return -1; |
| | | if (s2 == NULL) return 1; |
| | | |
| | | if (s1->len == s2->len) |
| | | return memcmp(s1->data, s2->data, s1->len); |
| | | else |
| | | { |
| | | int p = (s1->len > s2->len) ? s2->len : s1->len; |
| | | int rc = memcmp(s1->data, s2->data, p); |
| | | if (rc == 0) |
| | | return s1->len - s2->len; |
| | | return rc; |
| | | } |
| | | } |
| | | |
| | | char *cp_string_tocstr(cp_string *str) |
| | | { |
| | | char *cstr = NULL; |
| | | |
| | | if (str) |
| | | { |
| | | str->data[str->len * sizeof(char)] = '\0'; |
| | | // str->data[str->len * sizeof(char) + 1] = '\0'; |
| | | cstr = str->data; |
| | | } |
| | | |
| | | return cstr; |
| | | } |
| | | |
| | | int cp_string_len(cp_string *s) |
| | | { |
| | | return s->len; |
| | | } |
| | | |
| | | char *cp_string_data(cp_string *s) |
| | | { |
| | | return s->data; |
| | | } |
| | | |
| | | #define CHUNK 0x1000 |
| | | cp_string *cp_string_read(int fd, int len) |
| | | { |
| | | char buf[CHUNK]; |
| | | int read_len; |
| | | cp_string *res = NULL; |
| | | |
| | | if (len == 0) |
| | | read_len = CHUNK; |
| | | else |
| | | read_len = len < CHUNK ? len : CHUNK; |
| | | |
| | | while (len == 0 || res == NULL || res->len < len) |
| | | { |
| | | int rc = |
| | | read(fd, buf, read_len); |
| | | if (rc <= 0) break; |
| | | if (res == NULL) |
| | | { |
| | | res = cp_string_create(buf, rc); |
| | | if (res == NULL) return NULL; |
| | | } |
| | | else |
| | | cp_string_cat_bin(res, buf, rc); |
| | | } |
| | | |
| | | return res; |
| | | } |
| | | |
| | | int cp_string_write(cp_string *str, int fd) |
| | | { |
| | | int rc; |
| | | int total = 0; |
| | | |
| | | while (total < str->len) |
| | | { |
| | | rc = write(fd, &str->data[total], str->len - total); |
| | | |
| | | /* write sets EAGAIN when a socket is marked non-blocking and the |
| | | * write would block. trying to write again could result in spinning |
| | | * on the write call. |
| | | */ |
| | | if (rc == -1) |
| | | { |
| | | if (errno == EINTR /* || errno == EAGAIN */) /* try again */ |
| | | continue; |
| | | else |
| | | break; |
| | | } |
| | | total += rc; |
| | | } |
| | | |
| | | return total; |
| | | } |
| | | |
| | | cp_string *cp_string_read_file(char *filename) |
| | | { |
| | | cp_string *res; |
| | | FILE *fp = fopen(filename, "rb"); |
| | | if (fp == NULL) return NULL; |
| | | |
| | | res = cp_string_read(fileno(fp), 0); |
| | | fclose(fp); |
| | | |
| | | return res; |
| | | } |
| | | |
| | | int cp_string_write_file(cp_string *str, char *filename) |
| | | { |
| | | int rc; |
| | | FILE *fp = fopen(filename, "wb"); |
| | | if (fp == NULL) return 0; |
| | | |
| | | rc = cp_string_write(str, fileno(fp)); |
| | | fclose(fp); |
| | | |
| | | return rc; |
| | | } |
| | | |
| | | #define LINELEN 81 |
| | | #define CHARS_PER_LINE 16 |
| | | |
| | | static char *print_char = |
| | | " " |
| | | " " |
| | | " !\"#$%&'()*+,-./" |
| | | "0123456789:;<=>?" |
| | | "@ABCDEFGHIJKLMNO" |
| | | "PQRSTUVWXYZ[\\]^_" |
| | | "`abcdefghijklmno" |
| | | "pqrstuvwxyz{|}~ " |
| | | " " |
| | | " " |
| | | " ???????????????" |
| | | "????????????????" |
| | | "????????????????" |
| | | "????????????????" |
| | | "????????????????" |
| | | "????????????????"; |
| | | |
| | | void cp_cstring_dump(char *data, int len) |
| | | { |
| | | int rc; |
| | | int idx; |
| | | char prn[LINELEN]; |
| | | char lit[CHARS_PER_LINE + 1]; |
| | | char hc[4]; |
| | | short line_done = 1; |
| | | |
| | | rc = len; |
| | | idx = 0; |
| | | lit[CHARS_PER_LINE] = '\0'; |
| | | while (rc > 0) |
| | | { |
| | | if (line_done) |
| | | snprintf(prn, LINELEN, "%08X: ", idx); |
| | | do |
| | | { |
| | | unsigned char c = data[idx]; |
| | | snprintf(hc, 4, "%02X ", c); |
| | | strncat(prn, hc, 4); |
| | | lit[idx % CHARS_PER_LINE] = print_char[c]; |
| | | ++idx; |
| | | } while (--rc > 0 && (idx % CHARS_PER_LINE != 0)); |
| | | line_done = (idx % CHARS_PER_LINE) == 0; |
| | | if (line_done) |
| | | printf("%s %s\n", prn, lit); |
| | | else if (rc == 0) |
| | | strncat(prn, " ", LINELEN); |
| | | } |
| | | if (!line_done) |
| | | { |
| | | lit[(idx % CHARS_PER_LINE)] = '\0'; |
| | | while ((++idx % CHARS_PER_LINE) != 0) |
| | | strncat(prn, " ", LINELEN); |
| | | |
| | | printf("%s %s\n", prn, lit); |
| | | |
| | | } |
| | | } |
| | | |
| | | const char *cp_hexdump_string(const void *data, size_t len) |
| | | { |
| | | static char string[1024]; |
| | | unsigned char *d = (unsigned char *)data; |
| | | unsigned int i; |
| | | |
| | | string[0] = '\0'; |
| | | |
| | | for (i = 0; len--; i += 3) { |
| | | if (i >= sizeof(string) - 4) |
| | | break; |
| | | snprintf(string + i, 4, " %02x", *d++); |
| | | } |
| | | |
| | | return string; |
| | | } |
| | | |
| | | |
| | | void cp_string_dump(cp_string *str) |
| | | { |
| | | int rc; |
| | | int idx; |
| | | char prn[LINELEN]; |
| | | char lit[CHARS_PER_LINE + 1]; |
| | | char hc[4]; |
| | | short line_done = 1; |
| | | |
| | | rc = str->len; |
| | | idx = 0; |
| | | lit[CHARS_PER_LINE] = '\0'; |
| | | while (rc > 0) |
| | | { |
| | | if (line_done) |
| | | snprintf(prn, LINELEN, "%08X: ", idx); |
| | | do |
| | | { |
| | | unsigned char c = str->data[idx]; |
| | | snprintf(hc, 4, "%02X ", c); |
| | | strncat(prn, hc, 4); |
| | | lit[idx % CHARS_PER_LINE] = print_char[c]; |
| | | ++idx; |
| | | } while (--rc > 0 && (idx % CHARS_PER_LINE != 0)); |
| | | line_done = (idx % CHARS_PER_LINE) == 0; |
| | | if (line_done) |
| | | printf("%s %s\n", prn, lit); |
| | | else if (rc == 0) |
| | | strncat(prn, " ", LINELEN); |
| | | } |
| | | if (!line_done) |
| | | { |
| | | lit[(idx % CHARS_PER_LINE)] = '\0'; |
| | | while ((++idx % CHARS_PER_LINE) != 0) |
| | | strncat(prn, " ", LINELEN); |
| | | |
| | | printf("%s %s\n", prn, lit); |
| | | } |
| | | } |
| | | |
| | | /** flip the contents of a cp_string */ |
| | | void cp_string_flip(cp_string *str) |
| | | { |
| | | if (str->len) |
| | | { |
| | | char *i, *f, ch; |
| | | f = &str->data[str->len - 1]; |
| | | i = str->data; |
| | | while (i < f) |
| | | { |
| | | ch = *i; |
| | | *i = *f; |
| | | *f = ch; |
| | | i++; |
| | | f--; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /* remove all occurrences of letters from str */ |
| | | cp_string *cp_string_filter(cp_string *str, char *letters) |
| | | { |
| | | char *i; |
| | | char *f; |
| | | |
| | | str->data[str->len] = '\0'; |
| | | i = str->data; |
| | | while ((f = strpbrk(i, letters))) |
| | | { |
| | | i = f; |
| | | while (*f && strchr(letters, *f)) f++; |
| | | if (*f) |
| | | { |
| | | memmove(i, f, str->len - (f - str->data)); |
| | | str->len -= f - i; |
| | | str->data[str->len] = '\0'; |
| | | } |
| | | else |
| | | { |
| | | *i = '\0'; |
| | | str->len -= str->len - (i - str->data); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | return str; |
| | | } |
| | | |
| | | /** @} */ |
| | | |
| | | |
| | | char *del_char_from_string(char *str, char delchar) |
| | | { |
| | | char *idx = str; |
| | | char *end = str; |
| | | while (*idx) |
| | | { |
| | | if (*idx == delchar) |
| | | { |
| | | ++idx; |
| | | } |
| | | else |
| | | { |
| | | *end = *idx; |
| | | ++end; |
| | | ++idx; |
| | | } |
| | | } |
| | | *end = '\0'; |
| | | return str; |
| | | } |
| | | |
| | | int split_string_to_value(char *str, char *fmt, ...) |
| | | { |
| | | va_list ap; |
| | | |
| | | int *iPtr; |
| | | long *lPtr; |
| | | char *pcPtr; |
| | | |
| | | char delim[2]={*(fmt+2), '\0'}; |
| | | char *result; |
| | | |
| | | va_start(ap, fmt); |
| | | |
| | | result = strtok( str, delim ); |
| | | |
| | | while(*fmt) |
| | | { |
| | | switch (*fmt++) |
| | | { |
| | | case 's': /* string */ |
| | | pcPtr = va_arg(ap, char *); |
| | | if(NULL!= result) |
| | | { |
| | | if(NULL!=pcPtr) |
| | | { |
| | | strcpy(pcPtr, result); |
| | | } |
| | | result = strtok( NULL, delim ); |
| | | } |
| | | else |
| | | goto OUT; |
| | | |
| | | break; |
| | | |
| | | case 'd': /* int */ |
| | | iPtr = va_arg(ap, int *); |
| | | if(NULL!= result) |
| | | { |
| | | if(NULL!=iPtr) |
| | | { |
| | | *iPtr = atoi(result); |
| | | } |
| | | result = strtok( NULL, delim ); |
| | | } |
| | | else |
| | | goto OUT; |
| | | |
| | | break; |
| | | |
| | | case 'l': /* long */ |
| | | lPtr = va_arg(ap, long *); |
| | | if(NULL!= result) |
| | | { |
| | | if(NULL!=lPtr) |
| | | { |
| | | *lPtr = strtol(result, NULL, 10); |
| | | } |
| | | result = strtok( NULL, delim ); |
| | | } |
| | | else |
| | | goto OUT; |
| | | |
| | | break; |
| | | |
| | | case 'x': /* long hex*/ |
| | | lPtr = va_arg(ap, long *); |
| | | if(NULL!= result) |
| | | { |
| | | if(NULL!=lPtr) |
| | | { |
| | | *lPtr = strtol(result, NULL, 16); |
| | | } |
| | | result = strtok( NULL, delim ); |
| | | } |
| | | else |
| | | goto OUT; |
| | | |
| | | break; |
| | | } |
| | | } |
| | | |
| | | OUT: |
| | | va_end(ap); |
| | | return 0; |
| | | } |
| | | |
New file |
| | |
| | | #ifndef _CP_STRING_H |
| | | #define _CP_STRING_H |
| | | |
| | | /** @{ */ |
| | | /** |
| | | * @file |
| | | * cp_string - 'safe' string allowing binary content |
| | | */ |
| | | |
| | | #include <stdio.h> |
| | | #include <string.h> |
| | | #include <stdlib.h> |
| | | #include <unistd.h> |
| | | #include <stdarg.h> |
| | | |
| | | /** cp_string definition */ |
| | | typedef struct _cp_string |
| | | { |
| | | int size; /**< size allocated */ |
| | | int len; /**< size used */ |
| | | char *data; /**< internal buffer */ |
| | | } cp_string; |
| | | |
| | | /** allocate a new cp_string */ |
| | | cp_string *cp_string_create(char *data, int len); |
| | | /** allocate an empty cp_string with a given buffer size */ |
| | | cp_string *cp_string_create_empty(int initial_size); |
| | | /** deallocate a cp_string */ |
| | | void cp_string_destroy(cp_string *str); |
| | | /** Sets string data to 0 */ |
| | | void cp_string_clear_data(cp_string *str); |
| | | /** copies the content of a null terminated c string */ |
| | | cp_string *cp_string_cstrcpy(cp_string *str, char *cstr); |
| | | /** copies the content of a cp_string */ |
| | | //cp_string *cp_string_cp(cp_string *dst, cp_string *src); |
| | | int cp_string_copy(cp_string *dst, cp_string *src); |
| | | int cp_string_move(cp_string *dst, cp_string *src); |
| | | /** copy the string into *dst */ |
| | | int cp_string_cstrcopy(cp_string *dst, char *string, int len); |
| | | /** creates a copy of src string. internal buffer is duplicated. */ |
| | | cp_string *cp_string_dup(cp_string *src); |
| | | /** creates a cp_string with src as its content */ |
| | | cp_string *cp_string_cstrdup(char *src); |
| | | /** concatenate cp_strings */ |
| | | cp_string *cp_string_cat(cp_string *str, cp_string *appendum); |
| | | /** append data from a buffer */ |
| | | cp_string *cp_string_cat_bin(cp_string *str, void *bin, int len); |
| | | /** append data from a null terminated c string */ |
| | | cp_string *cp_string_cstrcat(cp_string *str, char *cstr); |
| | | /** append a character to a string */ |
| | | cp_string *cp_string_append_char(cp_string *str, char ch); |
| | | /** compare cp_strings */ |
| | | int cp_string_cmp(cp_string *s1, cp_string *s2); |
| | | /** return a pointer to the internal buffer */ |
| | | char *cp_string_tocstr(cp_string *str); |
| | | /** return the length of the internal buffer */ |
| | | int cp_string_len(cp_string *s); |
| | | /** return the internal buffer */ |
| | | char *cp_string_data(cp_string *s); |
| | | |
| | | /** read len bytes from an open file descriptor (blocking) */ |
| | | cp_string *cp_string_read(int fd, int len); |
| | | /** write the content of a cp_string to a file descriptor (blocking) */ |
| | | int cp_string_write(cp_string *str, int fd); |
| | | /** read the contents of a file into a cp_string */ |
| | | cp_string *cp_string_read_file(char *filename); |
| | | /** write the contents of a cp_string to a file */ |
| | | int cp_string_write_file(cp_string *str, char *filename); |
| | | |
| | | /** flip the contents of a cp_string */ |
| | | void cp_string_flip(cp_string *str); |
| | | /** remove all occurrences of letters from str */ |
| | | cp_string *cp_string_filter(cp_string *str, char *letters); |
| | | |
| | | /** dump a cp_string to stdout */ |
| | | const char *cp_hexdump_string(const void *data, size_t len); |
| | | void cp_string_dump(cp_string *str); |
| | | void cp_cstring_dump(char *data, int len); |
| | | |
| | | char *del_char_from_string(char *str, char delchar); |
| | | int split_string_to_value(char *str, char *fmt, ...); |
| | | |
| | | /** @} */ |
| | | |
| | | #endif |
| | | |
New file |
| | |
| | | /******************************************************************************** |
| | | * Copyright: (C) 2012 CoherentPlus Sdn. Bhd. |
| | | * All rights reserved. |
| | | * |
| | | * Filename: cp_time.h |
| | | * Description: This head file |
| | | * |
| | | * Version: 1.0.0(02/23/2012~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "02/23/2012 07:46:37 AM" |
| | | * |
| | | ********************************************************************************/ |
| | | #ifndef __CP_TIME_H |
| | | #define __CP_TIME_H |
| | | |
| | | #include <unistd.h> |
| | | #include <string.h> |
| | | #include <fcntl.h> |
| | | #include <time.h> |
| | | |
| | | #include <linux/rtc.h> |
| | | #include <sys/ioctl.h> |
| | | #include <sys/types.h> |
| | | #include <sys/stat.h> |
| | | #include <sys/time.h> |
| | | |
| | | typedef struct __DATE_TIME |
| | | { |
| | | int iYear; |
| | | int iMonth; |
| | | int iDay; |
| | | int iHour; |
| | | int iMinute; |
| | | int iSecond; |
| | | int iDayOfWeek; |
| | | } DATE_TIME; |
| | | |
| | | static inline void micro_second_sleep(unsigned long ms) |
| | | { |
| | | struct timespec cSleep; |
| | | unsigned long ulTmp; |
| | | cSleep.tv_sec = ms / 1000; |
| | | if (cSleep.tv_sec == 0) |
| | | { |
| | | ulTmp = ms * 10000; |
| | | cSleep.tv_nsec = ulTmp * 100; |
| | | } |
| | | else |
| | | { |
| | | cSleep.tv_nsec = 0; |
| | | } |
| | | |
| | | nanosleep(&cSleep, 0); |
| | | } |
| | | |
| | | /*UNIT: micro second*/ |
| | | static inline unsigned long time_now() |
| | | { |
| | | struct timeval now; |
| | | gettimeofday(&now, 0); |
| | | return (now.tv_sec * 1000) + (now.tv_usec / 1000); |
| | | } |
| | | |
| | | /*UNIT: micro second*/ |
| | | static inline unsigned long time_elapsed(unsigned long start) |
| | | { |
| | | unsigned long current = time_now(); |
| | | |
| | | if (current < start) |
| | | { |
| | | return (0xFFFFFFFF - start) + current; |
| | | } |
| | | |
| | | //printf("time_elapsed: %ld\n", current-start); |
| | | return current - start; |
| | | } |
| | | |
| | | static inline void get_current_time(DATE_TIME * date) |
| | | { |
| | | time_t now = time(NULL); |
| | | struct tm *tnow = localtime(&now); |
| | | |
| | | memset(date, 0, sizeof(DATE_TIME)); |
| | | date->iYear = 1900 + tnow->tm_year; |
| | | date->iMonth = 1 + tnow->tm_mon; |
| | | date->iDay = tnow->tm_mday; |
| | | |
| | | date->iHour = tnow->tm_hour; |
| | | date->iMinute = tnow->tm_min; |
| | | date->iSecond = tnow->tm_sec; |
| | | date->iDayOfWeek = tnow->tm_wday; |
| | | return; |
| | | } |
| | | #define get_sys_time(date) get_current_time(date) |
| | | |
| | | static inline int get_rtc_time(DATE_TIME *date) |
| | | { |
| | | int rv, fd = -1; |
| | | struct rtc_time rtc_tm; |
| | | |
| | | memset(date, 0, sizeof(DATE_TIME)); |
| | | |
| | | if ((fd=open("/dev/rtc0", O_RDONLY)) < 0) |
| | | return -1; |
| | | |
| | | if((rv=ioctl(fd, RTC_RD_TIME, &rtc_tm)) < 0) |
| | | return -2; |
| | | |
| | | date->iYear = 1900 + rtc_tm.tm_year; |
| | | date->iMonth = 1 + rtc_tm.tm_mon; |
| | | date->iDay = rtc_tm.tm_mday; |
| | | |
| | | date->iHour = rtc_tm.tm_hour; |
| | | date->iMinute = rtc_tm.tm_min; |
| | | date->iSecond = rtc_tm.tm_sec; |
| | | date->iDayOfWeek = rtc_tm.tm_wday; |
| | | |
| | | close(fd); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | #endif |
New file |
| | |
| | | #********************************************************************************* |
| | | # Copyright: (C) 2012 Guo Wenxue <guowenxue@gmail.com> |
| | | # All rights reserved. |
| | | # |
| | | # Filename: Makefile |
| | | # Description: This is the common subdir Makefile which to compile all the C |
| | | # source code to object files and then generate the shared or |
| | | # static library named lib$(FOLDER_NAME).a orlib $(FOLDER_NAME).so, |
| | | # which depends on the variable $LINK_MODE. |
| | | # |
| | | # Version: 1.0.0(10/08/2011~) |
| | | # Author: Guo Wenxue <guowenxue@gmail.com> |
| | | # ChangeLog: 1, Release initial version on "10/08/2011 01:29:33 AM" |
| | | # |
| | | #********************************************************************************/ |
| | | |
| | | PWD=$(shell pwd) |
| | | |
| | | #If wanna compile in the subdir, not called by top makefile, uncomment it |
| | | ifneq (${TOP_COMPILE}, YES) |
| | | LOCAL_COMPILE=YES |
| | | endif |
| | | |
| | | LINK_MODE=STATIC |
| | | #MULTHREADS=YES |
| | | |
| | | LIBNAME=$(shell basename ${PWD}) |
| | | STALIB=lib${LIBNAME}.a |
| | | DYNLIB=lib${LIBNAME}.so |
| | | |
| | | VPATH= . |
| | | SRCS = $(wildcard ${VPATH}/*.c) |
| | | OBJS = $(patsubst %.c,%.o,$(SRCS)) |
| | | |
| | | #====================================================== |
| | | # ---> Doesn't call by top makefile, compile by local |
| | | #====================================================== |
| | | ifeq (${LOCAL_COMPILE}, YES) |
| | | ARCH?=arm |
| | | #ARCH?=i386 |
| | | CFLAGS+=-fPIC |
| | | TMP=$(shell echo $(ARCH) | tr "[A-Z]" "[a-z]") |
| | | ifneq (,$(filter i386,$(TMP))) |
| | | CROSS_COMPILE= |
| | | else |
| | | CROSS_COMPILE=/opt/rpi/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf- |
| | | endif |
| | | |
| | | PRJDIR?=$(shell dirname ${PWD}) |
| | | CFLAGS+=-I${PRJDIR} -g -Wall -Werror |
| | | CC = ${CROSS_COMPILE}gcc |
| | | AR = ${CROSS_COMPILE}ar |
| | | |
| | | endif #End local compile |
| | | |
| | | ifeq ("${LINK_MODE}", "STATIC") |
| | | LIBS = ${STALIB} |
| | | else |
| | | LIBS=${DYNLIB} ${STALIB} |
| | | endif |
| | | |
| | | ifeq ("${MULTHREADS}", "YES") |
| | | LDFLAGS+=-lpthread |
| | | CFLAGS+=-DMULTHREADS |
| | | endif |
| | | |
| | | all: entry clean ${LIBS} install |
| | | |
| | | entry: |
| | | @echo " "; |
| | | @echo " ========================================================="; |
| | | @echo " ** Compile subdir ${LIBNAME} for ${ARCH} "; |
| | | @echo " ========================================================="; |
| | | |
| | | #$(LD) -g --relocatable $(OBJS) -o lib${LIBNAME}.o |
| | | ${STALIB}: $(OBJS) |
| | | $(AR) -rcu $@ $(OBJS) |
| | | |
| | | ${DYNLIB}: $(OBJS) |
| | | $(CC) -fPIC -shared -o $@ $(OBJS) |
| | | |
| | | %.o : %.c |
| | | $(CC) -c $< $(CFLAGS) |
| | | |
| | | test: clean ${LIBS} |
| | | make -C test ARCH=${ARCH} |
| | | |
| | | tag: |
| | | @ctags --c-kinds=+defglmnstuvx --langmap=c:.c.h.ho.hem.het.hec.hev.him.hit.hic.hiv -R . |
| | | @cscope -Rbq |
| | | |
| | | install: |
| | | @if [ ! -z "${LIBS_PATH}" ] ; then \ |
| | | mkdir -p ${LIBS_PATH} ; \ |
| | | cp ${LIBS} ${LIBS_PATH}; \ |
| | | fi; |
| | | |
| | | clean: |
| | | @rm -f *.o *.lo *~ |
| | | @rm -rf *.gdb *.a *.so |
| | | @make clean -C test |
| | | @rm -f *.log |
| | | |
| | | distclean: clean |
| | | @rm -f tags cscope* |
| | | |
| | | .PHONY: clean entry |
| | | |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2012 Guo Wenxue <guowenxue@gmail.com> |
| | | * All rights reserved. |
| | | * |
| | | * Filename: comport.c |
| | | * Description: This file used to do ioctl() on common device or communicate |
| | | * with serial port/TTY device. |
| | | * |
| | | * Version: 1.0.0(10/18/2011~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "10/18/2011 10:08:05 AM" |
| | | * |
| | | ********************************************************************************/ |
| | | #include <getopt.h> |
| | | #include <libgen.h> |
| | | #include <sys/ioctl.h> |
| | | |
| | | #include "cp_comport.h" |
| | | #include "cp_common.h" |
| | | #include "version.h" |
| | | |
| | | unsigned char g_ucProcToken = 0x01; |
| | | unsigned char g_ucCtrlZ; |
| | | |
| | | void print_version(char *name); |
| | | void usage(char *name); |
| | | int do_ioctl(char *dev_name, int cmd, int arg); |
| | | void signal_handler(int i_sig); |
| | | |
| | | int main(int argc, char **argv) |
| | | { |
| | | int opt = 0; |
| | | int retval = 0; |
| | | int recv_size = 0; |
| | | int i; |
| | | char *dev_name = NULL; |
| | | int baudrate = 115200; |
| | | char *settings = "8N1N"; |
| | | char buf[512]; |
| | | unsigned char disp_mode = 0x00; |
| | | |
| | | struct sigaction sigact; |
| | | |
| | | struct option long_options[] = { |
| | | {"device", required_argument, NULL, 'd'}, |
| | | {"baudrate", required_argument, NULL, 'b'}, |
| | | {"settings", required_argument, NULL, 's'}, |
| | | {"ioctl", required_argument, NULL, 'i'}, |
| | | {"hex", no_argument, NULL, 'x'}, |
| | | {"version", no_argument, NULL, 'v'}, |
| | | {"help", no_argument, NULL, 'h'}, |
| | | {NULL, 0, NULL, 0} |
| | | }; |
| | | |
| | | while ((opt = getopt_long(argc, argv, "d:b:s:ivh", long_options, NULL)) != -1) |
| | | { |
| | | switch (opt) |
| | | { |
| | | case 'd': |
| | | dev_name = optarg; |
| | | break; |
| | | case 'b': |
| | | baudrate = atoi(optarg); |
| | | break; |
| | | case 's': /* Default settings as 8N1N */ |
| | | settings = optarg; |
| | | break; |
| | | case 'i': |
| | | if (5 != argc) |
| | | { |
| | | usage(argv[0]); |
| | | } |
| | | else |
| | | { |
| | | do_ioctl(argv[2], atoi(argv[3]), atoi(argv[4])); |
| | | } |
| | | return 0; |
| | | case 'x': /* Display receive data as Hex mode */ |
| | | disp_mode = 0x01; |
| | | break; |
| | | case 'v': /* version */ |
| | | print_version(argv[0]); |
| | | return 0; |
| | | case 'h': /* help */ |
| | | usage(argv[0]); |
| | | return 0; |
| | | default: |
| | | break; |
| | | } /* end of "switch(opt)" */ |
| | | } |
| | | |
| | | if (argc < 2) |
| | | { |
| | | usage(argv[0]); |
| | | return 0; |
| | | } |
| | | |
| | | comport_t *comport = NULL; |
| | | if (NULL == (comport = comport_init(dev_name, baudrate, settings))) |
| | | { |
| | | printf("Comport initialize failure.\n"); |
| | | return -1; |
| | | } |
| | | |
| | | if ( (retval=comport_open(comport)) < 0) |
| | | { |
| | | printf("Failed to open %s with baudrate %d, %s. RetCode [%d]\n", dev_name, baudrate, |
| | | settings, retval); |
| | | return -1; |
| | | } |
| | | |
| | | nonblock(); |
| | | |
| | | /* Process level signal handler */ |
| | | sigemptyset(&sigact.sa_mask); |
| | | sigact.sa_flags = 0; |
| | | sigact.sa_handler = signal_handler; |
| | | |
| | | sigaction(SIGTERM, &sigact, NULL); /* catch terminate signal */ |
| | | sigaction(SIGINT, &sigact, NULL); /* catch interrupt signal */ |
| | | sigaction(SIGSEGV, &sigact, NULL); /* catch segmentation faults */ |
| | | sigaction(SIGTSTP, &sigact, NULL); /* catch ctrl+Z */ |
| | | sigaction(SIGSTOP, &sigact, NULL); /* catch ctrl+Z */ |
| | | |
| | | while (0x01 == g_ucProcToken) |
| | | { |
| | | recv_size = comport_recv(comport, buf, sizeof(buf) - 1, 10); |
| | | if (recv_size > 0) |
| | | { |
| | | for (i = 0; i < recv_size; i++) |
| | | { |
| | | if (0 == disp_mode) |
| | | printf("%c", buf[i]); |
| | | else |
| | | printf("%02X ", buf[i]); |
| | | } |
| | | fflush(stdout); |
| | | } |
| | | if (0 != kbhit()) |
| | | { |
| | | retval = fgetc(stdin); |
| | | |
| | | if (0x0A == retval) |
| | | { |
| | | buf[0] = 0x0D; /* 13 == 0x0D */ |
| | | } |
| | | else |
| | | { |
| | | buf[0] = retval; |
| | | } |
| | | |
| | | comport_send(comport, buf, 1); |
| | | } |
| | | else if (0x00 != g_ucCtrlZ) |
| | | { |
| | | g_ucCtrlZ = 0x00; |
| | | buf[0] = 0x1A; |
| | | comport_send(comport, buf, 1); |
| | | } |
| | | } |
| | | |
| | | comport_term(comport); |
| | | return 0; |
| | | } /* ----- End of main() ----- */ |
| | | |
| | | void print_version(char *name) |
| | | { |
| | | char *progname = NULL; |
| | | char *ptr = NULL; |
| | | |
| | | ptr = strdup(name); |
| | | progname = basename(ptr); |
| | | |
| | | printf("%s version: %d.%d.%d Build %04d on %s\n", progname, MAJOR, MINOR, REVER, SVNVER, DATE); |
| | | printf("Copyright (C) 2010 guowenxue <guowenxue@gmail.com>\n"); |
| | | |
| | | free(ptr); |
| | | return; |
| | | } |
| | | |
| | | void usage(char *name) |
| | | { |
| | | char *progname = NULL; |
| | | char *ptr = NULL; |
| | | |
| | | ptr = strdup(name); |
| | | progname = basename(ptr); |
| | | printf("Usage1: comport -d <device> [-b <baudrate>][-s <settings>] [-x]\n"); |
| | | printf("Usage2: comport [-i <driver port> <cmd> <arg>][--help][--version]\n"); |
| | | printf(" -d[device ] device name\n"); |
| | | printf(" -b[baudrate] device baudrate (115200, 57600, 19200, 9600), default is 115200\n"); |
| | | printf(" -s[settings] device settings as like 8N1N(default setting)\n"); |
| | | printf(" - data bits: 8, 7\n"); |
| | | printf(" - parity: N=None, O=Odd, E=Even, S=Space\n"); |
| | | printf(" - stop bits: 1, 0\n"); |
| | | printf(" - flow control: N=None, H=Hardware, S=Software, B=Both\n"); |
| | | printf(" -x[hex ] display received data in hex format\n"); |
| | | printf(" -i[ioctl ] ioctl system call (cmd & arg only support int)\n"); |
| | | printf(" -v[version ] Display the program version\n"); |
| | | printf(" -h[help ] Display this help information\n"); |
| | | |
| | | print_version(progname); |
| | | |
| | | free(ptr); |
| | | |
| | | return; |
| | | } |
| | | |
| | | int do_ioctl(char *dev_name, int cmd, int arg) |
| | | { |
| | | int fd = -1; |
| | | int retval = -1; |
| | | if (((fd = open(dev_name, O_RDWR)) < 0)) |
| | | { |
| | | printf("Open device \"%s\" failure: %s\n", dev_name, strerror(errno)); |
| | | return -1; |
| | | } |
| | | |
| | | retval = ioctl(fd, cmd, arg); |
| | | printf("ioctl (%s, %d, %d) returned %d\n", dev_name, cmd, arg, retval); |
| | | |
| | | close(fd); |
| | | return retval; |
| | | } |
| | | |
| | | void signal_handler(int i_sig) |
| | | { |
| | | if (SIGTERM == i_sig || SIGINT == i_sig) |
| | | { |
| | | g_ucProcToken = 0x00; |
| | | } |
| | | else if (20 == i_sig) |
| | | { |
| | | g_ucCtrlZ = 0x01; |
| | | } |
| | | } |
| | | |
| | | |
New file |
| | |
| | | #********************************************************************************* |
| | | # Copyright: (C) 2012 Guo Wenxue <guowenxue@gmail.com> |
| | | # All rights reserved. |
| | | # |
| | | # Filename: Makefile |
| | | # Description: This Makefile used to compile all the C source code file in current |
| | | # folder to respective excutable binary files. |
| | | # |
| | | # Version: 1.0.0(10/08/2011~) |
| | | # Author: Guo Wenxue <guowenxue@gmail.com> |
| | | # ChangeLog: 1, Release initial version on "11/11/2011 01:29:33 PM" |
| | | # |
| | | #********************************************************************************/ |
| | | |
| | | PWD=$(shell pwd) |
| | | LIB_PATH=$(shell dirname ${PWD}) |
| | | LIB_NAME=$(shell basename ${LIB_PATH}) |
| | | INSTPATH=/tftp |
| | | |
| | | #ARCH ?= i386 |
| | | ARCH?=arm |
| | | |
| | | LINK_MODE=STATIC |
| | | MODE=PRODUCTION |
| | | DEBUG=1 |
| | | |
| | | CFLAGS+=-Wall -Werror |
| | | #CFLAGS+=-Wno-unused |
| | | |
| | | ifeq ("${MODE}", "PRODUCTION") |
| | | CFLAGS+=-DPRODUCTION_MODE |
| | | endif |
| | | ifdef DEBUG |
| | | CFLAGS+=-g -DDEBUG |
| | | endif |
| | | |
| | | COMPILE_DATE=$(shell date -u +"%Y-%m-%d %H:%M") |
| | | VPATH= . |
| | | SRCS = $(wildcard ${VPATH}/*.c) |
| | | OBJS = $(patsubst %.c,%.o,$(SRCS)) |
| | | |
| | | TMP=$(shell echo $(ARCH) | tr "[A-Z]" "[a-z]") |
| | | ifneq (,$(filter i386,$(TMP))) |
| | | CROSS_COMPILE= |
| | | else |
| | | CROSS_COMPILE=/opt/rpi/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf- |
| | | endif |
| | | |
| | | |
| | | CFLAGS+=-I${LIB_PATH} |
| | | LDFLAGS+=-L${LIB_PATH} -l${LIB_NAME} |
| | | |
| | | export CC=${CROSS_COMPILE}gcc |
| | | export CXX=${CROSS_COMPILE}g++ |
| | | export AR=${CROSS_COMPILE}ar |
| | | export AS=${CROSS_COMPILE}as |
| | | export RANLIB=${CROSS_COMPILE}ranlib |
| | | export STRIP=${CROSS_COMPILE}strip |
| | | export CFLAGS |
| | | export LDFLAGS |
| | | export ARCH |
| | | export LINK_MODE |
| | | |
| | | LDFLAGS+=-lpthread |
| | | ifeq ("${LINK_MODE}", "STATIC") |
| | | CFLAGS+=--static |
| | | LDFLAGS+=-static |
| | | else |
| | | LDFLAGS+=-ldl |
| | | endif |
| | | |
| | | SRCFILES = $(wildcard *.c) |
| | | BINARIES=$(SRCFILES:%.c=%) |
| | | |
| | | all: entry version binaries install |
| | | entry: |
| | | @echo "#### ${LIB_PATH}" |
| | | @echo " "; |
| | | @echo " ========================================================="; |
| | | @echo " ** Compile \"${BINARIES}\" for ${ARCH} "; |
| | | @echo " ========================================================="; |
| | | |
| | | version: |
| | | @echo "/* Generated by makefile, don't Edit it by hand */" > version.h |
| | | @echo "#define DATE \"$(COMPILE_DATE)\"" >> version.h |
| | | @echo "#define MAJOR 1" >>version.h |
| | | @echo "#define MINOR 0" >>version.h |
| | | @echo "#define REVER 0" >>version.h |
| | | @if [ -f .svn/entries ] ; then \ |
| | | echo "#define SVNVER `sed -n -e 11p .svn/entries`" >>version.h; \ |
| | | else \ |
| | | echo "#define SVNVER 0" >>version.h; \ |
| | | fi; |
| | | @echo "" >> version.h |
| | | @echo '#define version(progname) printf("%s Version %d.%d.%d Build @%05d (%s)\\n", progname, MAJOR, MINOR, REVER,SVNVER, DATE)' >> version.h |
| | | @echo '#define copyright() printf("Copyright: (C) 2012 Guo Wenxue<Email:guowenxue@gmail.com\\n")' >>version.h |
| | | @echo '#define banner(progname) {version(progname); copyright(); printf("\\n");}' >>version.h |
| | | @echo "" >> version.h |
| | | |
| | | binaries: ${BINARIES} |
| | | @echo " Compile over" |
| | | |
| | | %: %.c |
| | | $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) |
| | | |
| | | tag: |
| | | @ctags --c-kinds=+defglmnstuvx --langmap=c:.c.h.ho.hem.het.hec.hev.him.hit.hic.hiv -R . |
| | | @cscope -Rbq |
| | | |
| | | install: |
| | | @cp $(BINARIES) ${INSTPATH} |
| | | |
| | | clean: |
| | | @rm -f version.h |
| | | @rm -f *.o *.lo $(BINARIES) |
| | | @rm -rf *.gdb *.a *.so *.elf* |
| | | @rm -f *.log |
| | | |
| | | distclean: clean |
| | | @rm -f tags cscope* |
| | | |
| | | .PHONY: clean entry |
New file |
| | |
| | | # Program configure file sample |
| | | [log] |
| | | file=/var/log/testd.log |
| | | |
| | | #Loglevel: 0:Disable 1:Fatal 2:ERROR 3:warnning 4:Normal 5:Debug 6:Infor 7:Trace |
| | | level=5 |
| | | |
| | | #Unit Kib |
| | | size=1024 |
| | | |
| | | [comport] |
| | | #Comport device |
| | | devname="/dev/ttyS1" |
| | | |
| | | #Baudrate: 115200,57600,38400,19200,9600,4800,2400,1800,1200,... |
| | | baudrate=115200 |
| | | |
| | | #Settings format is: Databit[8/7],Parity[O/E/S/N],StopBit[1/0],FlowControl[S/H/N] |
| | | settings="8N1N" |
| | | |
| | | timeout=1000 |
| | | |
| | | |
| | | [server] |
| | | hostname=stuidio.iot-yun.com |
| | | port=9999 |
| | | heartbeat=30 |
| | | |
| | | |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2012 Guo Wenxue<guowenxue@gmail.com> |
| | | * All rights reserved. |
| | | * |
| | | * Filename: test_ini.c |
| | | * Description: This file |
| | | * |
| | | * Version: 1.0.0(12/18/2012~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "12/18/2012 10:54:09 AM" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #include "cp_iniparser.h" |
| | | |
| | | |
| | | #define SAMPLE_CONF "sample.conf" |
| | | |
| | | /******************************************************************************** |
| | | * Description: |
| | | * Input Args: |
| | | * Output Args: |
| | | * Return Value: |
| | | ********************************************************************************/ |
| | | int main (int argc, char **argv) |
| | | { |
| | | dictionary *ini; |
| | | char *ini_name = SAMPLE_CONF; |
| | | char *str; |
| | | int data; |
| | | |
| | | ini = iniparser_load(ini_name); |
| | | if (ini==NULL) |
| | | { |
| | | printf("cannot parse file: %s\n", ini_name); |
| | | return -2 ; |
| | | } |
| | | |
| | | printf("+----------------------------------+\n" |
| | | "| Program logger configuration |\n" |
| | | "+----------------------------------+\n"); |
| | | |
| | | str = iniparser_getstring(ini, "log:file", NULL); |
| | | printf("Configure logger file name: %s\n", str); |
| | | |
| | | data = iniparser_getint(ini, "log:level", 0); |
| | | printf("Configure logger level: %d\n", data); |
| | | |
| | | data = iniparser_getint(ini, "log:size", 1024); |
| | | printf("Configure logger size: %d\n", data); |
| | | |
| | | |
| | | |
| | | printf("\n+----------------------------------+\n" |
| | | "| Comport configuration |\n" |
| | | "+----------------------------------+\n"); |
| | | |
| | | str = iniparser_getstring(ini, "comport:devname", NULL); |
| | | printf("Comport device name: %s\n", str); |
| | | |
| | | data = iniparser_getint(ini, "comport:baudrate", 115200); |
| | | printf("Comport baudrate: %d\n", data); |
| | | |
| | | str = iniparser_getstring(ini, "comport:settings", NULL); |
| | | printf("Comport settings: %s\n", str); |
| | | |
| | | data = iniparser_getint(ini, "comport:timeout", 3000); |
| | | printf("Comport timeout: %d\n", data); |
| | | |
| | | |
| | | |
| | | printf("\n+----------------------------------+\n" |
| | | "| Server host configuration |\n" |
| | | "+----------------------------------+\n"); |
| | | str = iniparser_getstring(ini, "server:hostname", NULL); |
| | | printf("Connect server hostname: %s\n", str); |
| | | |
| | | data = iniparser_getint(ini, "server:port", 8000); |
| | | printf("Connect server port: %d\n", data); |
| | | |
| | | data = iniparser_getint(ini, "server:heartbeat", 60); |
| | | printf("Connect server heartbeat: %d\n", data); |
| | | |
| | | |
| | | |
| | | iniparser_freedict(ini); |
| | | |
| | | return 0; |
| | | } /* ----- End of main() ----- */ |
| | | |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2012 Guo Wenxue<guowenxue@gmail.com> |
| | | * All rights reserved. |
| | | * |
| | | * Filename: test_klist.c |
| | | * Description: This file is for test kernel space double linked list. |
| | | * |
| | | * Version: 1.0.0(11/12/2012~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "11/12/2012 04:26:39 PM" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #include <stdlib.h> |
| | | #include <stdio.h> |
| | | #include <string.h> |
| | | #include "cp_klist.h" |
| | | |
| | | typedef struct node_s |
| | | { |
| | | int data; |
| | | struct list_head link; |
| | | } node_t; |
| | | |
| | | |
| | | |
| | | |
| | | void travel_list(struct list_head *head) |
| | | { |
| | | node_t *new_node; |
| | | node_t *node, *tmp; |
| | | |
| | | |
| | | if( (new_node=malloc(sizeof(node_t))) ) |
| | | { |
| | | list_add_tail(&new_node->link, head); |
| | | printf("Add new node %p to list \n", new_node); |
| | | } |
| | | |
| | | /* Use list_for_each_entry to travel the list, we can not remove the node in it */ |
| | | list_for_each_entry_safe(node, tmp, head, link) |
| | | { |
| | | printf("Travel2 list on node %p\n", node); |
| | | } |
| | | } |
| | | |
| | | |
| | | /******************************************************************************** |
| | | * Description: |
| | | * Input Args: |
| | | * Output Args: |
| | | * Return Value: |
| | | ********************************************************************************/ |
| | | int main (int argc, char **argv) |
| | | { |
| | | int i; |
| | | struct list_head header; |
| | | node_t *node; |
| | | node_t *tmp; |
| | | |
| | | INIT_LIST_HEAD(&header); |
| | | |
| | | for(i=0; i<10; i++) |
| | | { |
| | | node=malloc(sizeof(node_t)); |
| | | memset(node, 0, sizeof(node_t)); |
| | | node->data=i; |
| | | if( node ) |
| | | { |
| | | list_add_tail(&node->link, &header); |
| | | printf("Add node %p to list \n", node); |
| | | } |
| | | } |
| | | |
| | | /* Use list_for_each_entry to travel the list, we can not remove the node in it */ |
| | | list_for_each_entry(node, &header, link) |
| | | { |
| | | printf("Travel list on node %p\n", node); |
| | | } |
| | | travel_list(&header); |
| | | |
| | | /* Use list_for_each_entry_safe to travel the list and destroy the node */ |
| | | list_for_each_entry_safe(node, tmp, &header, link) |
| | | { |
| | | list_del(&node->link); |
| | | printf("Remove and destroy node %p from list\n", node); |
| | | free(node); |
| | | } |
| | | |
| | | return 0; |
| | | } /* ----- End of main() ----- */ |
| | | |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2012 Guo Wenxue <guowenxue@gmail.com> |
| | | * All rights reserved. |
| | | * |
| | | * Filename: test_logger.c |
| | | * Description: This is the linux logger system test code. |
| | | * |
| | | * Version: 1.0.0(08/08/2012~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "08/08/2012 06:51:40 PM" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #include <unistd.h> |
| | | #include <stdio.h> |
| | | #include <string.h> |
| | | #include <libgen.h> |
| | | #include "cp_logger.h" |
| | | |
| | | |
| | | /******************************************************************************** |
| | | * Description: |
| | | * Input Args: |
| | | * Output Args: |
| | | * Return Value: |
| | | ********************************************************************************/ |
| | | int main (int argc, char **argv) |
| | | { |
| | | char buf[30]="Hello World!\n"; |
| | | char file[FILENAME_LEN]; |
| | | |
| | | snprintf(file, FILENAME_LEN, "%s.log", basename(argv[0]) ); |
| | | |
| | | //if (! cp_log_init(NULL, DBG_LOG_FILE, LOG_LEVEL_NRML, LOG_ROLLBACK_NONE) ) |
| | | //if (! cp_log_init(NULL, DEFAULT_LOGFILE, LOG_LEVEL_MAX, LOG_ROLLBACK_SIZE) ) |
| | | if(! cp_log_init(NULL, file, LOG_LEVEL_MAX, 12) || cp_log_open() ) |
| | | return 0; |
| | | |
| | | |
| | | while(1) |
| | | { |
| | | log_info("1connection.\n"); |
| | | log_dbg("2connection.\n"); |
| | | log_nrml("3connection.\n"); |
| | | log_warn("4connection.\n"); |
| | | log_err("5connection.\n"); |
| | | log_fatal("6connection.\n"); |
| | | |
| | | cp_log_dump(LOG_LEVEL_DEBUG, buf, 30); |
| | | |
| | | sleep(1); |
| | | } |
| | | |
| | | cp_log_term(); |
| | | |
| | | return 0; |
| | | } /* ----- End of main() ----- */ |
| | | |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2012 Guo Wenxue<guowenxue@gmail.com> |
| | | * All rights reserved. |
| | | * |
| | | * Filename: test_queue.c |
| | | * Description: This file used to test the queue library |
| | | * |
| | | * Version: 1.0.0(08/14/2012~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "08/14/2012 05:17:03 PM" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #include <stdio.h> |
| | | #include <string.h> |
| | | #include <stdlib.h> |
| | | |
| | | #include "cp_queue.h" |
| | | |
| | | typedef struct node_s |
| | | { |
| | | int data; |
| | | CP_QNODE *link; |
| | | } node_t; |
| | | |
| | | #define MAX_ITEMS 10 |
| | | |
| | | /******************************************************************************** |
| | | * Description: |
| | | * Input Args: |
| | | * Output Args: |
| | | * Return Value: |
| | | ********************************************************************************/ |
| | | int main (int argc, char **argv) |
| | | { |
| | | int i; |
| | | |
| | | node_t *node = NULL; |
| | | node_t *tmp = NULL; |
| | | |
| | | CP_QUEUE *queue = NULL; |
| | | |
| | | queue = cp_queue_init(NULL, MAX_ITEMS); |
| | | |
| | | for (i=0; i<MAX_ITEMS+10; i++) |
| | | { |
| | | node = malloc(sizeof(node_t)); |
| | | if( !node ) |
| | | break; |
| | | |
| | | if( NULL==cp_enqueue(queue, node) ) |
| | | { |
| | | free(node); |
| | | } |
| | | else |
| | | { |
| | | if(i==3) |
| | | { |
| | | tmp = node; |
| | | } |
| | | printf("enqueue node %p\n", node); |
| | | } |
| | | } |
| | | |
| | | |
| | | printf("queue usage %d/%d \n", cp_queue_count(queue), cp_queue_size(queue)); |
| | | |
| | | cp_travel_queue(queue); |
| | | if( cp_rmqueue(queue, tmp) ) |
| | | { |
| | | printf("remove and terminate node [%p] from queue\n", tmp); |
| | | free(tmp); |
| | | } |
| | | cp_travel_queue(queue); |
| | | |
| | | while(!cp_queue_is_empty(queue)) |
| | | { |
| | | if( (node=cp_dequeue(queue)) ) |
| | | { |
| | | printf("Terminate node: %p\n", node); |
| | | free(node); |
| | | } |
| | | } |
| | | |
| | | cp_queue_destroy(queue); |
| | | |
| | | return 0; |
| | | |
| | | } /* ----- End of main() ----- */ |
| | | |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2012 Guo Wenxue<guowenxue@gmail.com> |
| | | * All rights reserved. |
| | | * |
| | | * Filename: test_string.c |
| | | * Description: This file |
| | | * |
| | | * Version: 1.0.0(11/27/2012~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "11/27/2012 01:28:39 PM" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #include <cp_string.h> |
| | | |
| | | |
| | | /******************************************************************************** |
| | | * Description: |
| | | * Input Args: |
| | | * Output Args: |
| | | * Return Value: |
| | | ********************************************************************************/ |
| | | int main (int argc, char **argv) |
| | | { |
| | | int i; |
| | | cp_string *rcv; |
| | | cp_string *snd; |
| | | |
| | | rcv = cp_string_create_empty(64); |
| | | snd = cp_string_create_empty(64); |
| | | |
| | | printf("=======================\n"); |
| | | printf("Test cp_string_copy \n"); |
| | | printf("=======================\n"); |
| | | cp_string_clear_data(rcv); |
| | | cp_string_cstrcpy(rcv, "Hello world!"); |
| | | printf("Receive buffer data:\n"); |
| | | cp_string_dump(rcv); |
| | | |
| | | for(i=0; i<20; i++) |
| | | { |
| | | if( cp_string_copy(snd, rcv) > 0) |
| | | { |
| | | printf("[%d] Send buffer data:\n", i); |
| | | cp_string_dump(snd); |
| | | } |
| | | } |
| | | |
| | | printf("\n=======================\n"); |
| | | printf("Test cp_string_move \n"); |
| | | printf("=======================\n"); |
| | | |
| | | cp_string_clear_data(snd); |
| | | cp_string_clear_data(rcv); |
| | | for(i=0; i<20; i++) |
| | | { |
| | | cp_string_cstrcpy(rcv, "Hello world!"); |
| | | //printf("Set new receive buffer data [%d] bytes:\n", cp_string_len(rcv)); |
| | | cp_string_dump(rcv); |
| | | |
| | | if( cp_string_move(snd, rcv) > 0) |
| | | { |
| | | printf("[%d] Send buffer [%d] bytes data:\n", i, cp_string_len(snd)); |
| | | cp_string_dump(snd); |
| | | |
| | | printf("[%d] receive buffer [%d] bytes data:\n", i, cp_string_len(rcv)); |
| | | cp_string_dump(rcv); |
| | | } |
| | | } |
| | | |
| | | cp_string_destroy(rcv); |
| | | cp_string_destroy(snd); |
| | | |
| | | |
| | | return 0; |
| | | } /* ----- End of main() ----- */ |
| | | |