Add monitred and mqttd source code
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2018 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: led.c |
| | | * Description: This file is used to control Passive buzzer or Active buzzer |
| | | * |
| | | * pi@raspberrypi:~ $ gpio readall show BCM and wPi pinmap |
| | | * |
| | | * VCC ---- 5V/3.3V |
| | | * GND ---- GND |
| | | * I/O ---- GPIO.18 ---- GPIO.1 |
| | | * BCM wPi |
| | | * |
| | | * Version: 1.0.0(2018/10/14) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "2018/10/14 12:13:26" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <unistd.h> |
| | | #include <fcntl.h> |
| | | #include <dirent.h> |
| | | #include <string.h> |
| | | #include <time.h> |
| | | #include <errno.h> |
| | | |
| | | #include <wiringPi.h> |
| | | #include "beep.h" |
| | | |
| | | //#define CONFIG_ACTV_BEEP |
| | | |
| | | /* Only passive buzzer can play tone */ |
| | | #ifndef CONFIG_ACTV_BEEP |
| | | #define CONFIG_PLAY_LITTLE_STAR |
| | | //#define CONFIG_PLAY_TONE_TEST |
| | | #endif |
| | | |
| | | void play_tone_freq(void); |
| | | void play_little_star(void); |
| | | |
| | | |
| | | /*+-----------------------------+ |
| | | *| Turn buzzer on or off API | |
| | | *+-----------------------------+*/ |
| | | int turn_passive_beep(int cmd, int freq) |
| | | { |
| | | int range; |
| | | |
| | | if(OFF == cmd) |
| | | { |
| | | pwmWrite(PWM_PIN, 0); |
| | | pinMode(PWM_PIN, INPUT) ; |
| | | } |
| | | else |
| | | { |
| | | |
| | | if(freq<2000 || freq>5000) |
| | | { |
| | | printf("Beep set invalid PWM frequency[%d]!\n", freq); |
| | | return -1; |
| | | } |
| | | |
| | | /* Set GPIO as PWM output mode */ |
| | | pinMode(PWM_PIN, PWM_OUTPUT) ; |
| | | |
| | | /* Set PWM mode as ms mode */ |
| | | pwmSetMode(PWM_MODE_MS); |
| | | |
| | | /* Set PWM clock: 19.2MHz/32=600KHz */ |
| | | pwmSetClock(32); |
| | | |
| | | /* Set PWM frequency */ |
| | | range=600000/freq; |
| | | pwmSetRange(range); |
| | | |
| | | /* Set PWM duty 50% */ |
| | | pwmWrite(PWM_PIN, range/2); |
| | | } |
| | | } |
| | | |
| | | |
| | | /* Turn ON/OFF buzzer, Active Buzzer can not set frequency */ |
| | | int turn_active_beep(int cmd) |
| | | { |
| | | |
| | | /* Active buzzer VCC connect to: |
| | | 5V: Both high and low level will be on |
| | | 3.3V: Low level be on and High level be off |
| | | |
| | | So we use INPUT or OUTPUT to control the Beeper |
| | | */ |
| | | if(OFF == cmd) |
| | | { |
| | | pinMode(PWM_PIN, INPUT); |
| | | } |
| | | else |
| | | { |
| | | pinMode(PWM_PIN, OUTPUT); |
| | | digitalWrite(PWM_PIN, LOW); |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | /*+---------------------------------+ |
| | | *| Play Tone OD,RE,MI....XI,DO1 | |
| | | *+---------------------------------+*/ |
| | | |
| | | enum |
| | | { |
| | | UNUSED=0, |
| | | DO, |
| | | RE, |
| | | MI, |
| | | FA, |
| | | SO, |
| | | LA, |
| | | XI, |
| | | DO1, |
| | | RI1, |
| | | TONE_MAX, |
| | | }; |
| | | |
| | | #define msleep(x) usleep( 1000*(x) ) |
| | | |
| | | static int tone_freq[TONE_MAX]={0, 2093, 2349, 2637, 2794, 3136, 3520, 3952, 4186, 4698 }; |
| | | //static int tone_freq[TONE_MAX]={0, 2000, 2130, 2250, 2360, 2450, 2530, 2620, 2700, 2780}; |
| | | |
| | | static inline void play_tone(int tone, int delay) |
| | | { |
| | | if(tone<DO || tone>RI1) |
| | | return ; |
| | | |
| | | turn_passive_beep(ON, tone_freq[tone]); |
| | | msleep(delay); |
| | | turn_passive_beep(OFF, 0); |
| | | } |
| | | |
| | | void play_tone_freq(void) |
| | | { |
| | | int i; |
| | | |
| | | for(i=DO; i<TONE_MAX; i++) |
| | | { |
| | | play_tone( i, 500 ); |
| | | msleep(500); |
| | | } |
| | | } |
| | | |
| | | |
| | | /*+------------------------------+ |
| | | *| Play song "Little Start" | |
| | | *+------------------------------+*/ |
| | | |
| | | typedef struct tone_s |
| | | { |
| | | int tone; |
| | | int delay_ms; |
| | | |
| | | } tone_t; |
| | | |
| | | #define DEF_DELAY 350 |
| | | static tone_t little_start_notation[]= |
| | | { |
| | | {DO, DEF_DELAY}, |
| | | {DO, DEF_DELAY}, |
| | | {SO, DEF_DELAY}, |
| | | {SO, DEF_DELAY}, |
| | | {LA, DEF_DELAY}, |
| | | {LA, DEF_DELAY}, |
| | | {SO, DEF_DELAY*2}, |
| | | |
| | | {FA, DEF_DELAY}, |
| | | {FA, DEF_DELAY}, |
| | | {MI, DEF_DELAY}, |
| | | {MI, DEF_DELAY}, |
| | | {RE, DEF_DELAY}, |
| | | {RE, DEF_DELAY}, |
| | | {DO, DEF_DELAY*2}, |
| | | |
| | | |
| | | {SO, DEF_DELAY}, |
| | | {SO, DEF_DELAY}, |
| | | {FA, DEF_DELAY}, |
| | | {FA, DEF_DELAY}, |
| | | {MI, DEF_DELAY}, |
| | | {MI, DEF_DELAY}, |
| | | {RE, DEF_DELAY*2}, |
| | | |
| | | |
| | | {SO, DEF_DELAY}, |
| | | {SO, DEF_DELAY}, |
| | | {FA, DEF_DELAY}, |
| | | {FA, DEF_DELAY}, |
| | | {MI, DEF_DELAY}, |
| | | {MI, DEF_DELAY}, |
| | | {RE, DEF_DELAY*2}, |
| | | }; |
| | | |
| | | #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) |
| | | void play_little_star(void) |
| | | { |
| | | int i; |
| | | |
| | | for(i=0; i<ARRAY_SIZE(little_start_notation); i++) |
| | | { |
| | | play_tone(little_start_notation[i].tone, little_start_notation[i].delay_ms); |
| | | msleep(30); |
| | | } |
| | | } |
| | | |
| | | |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2018 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: beep.h |
| | | * Description: This file is used to control Passive buzzer or Active buzzer |
| | | * |
| | | * pi@raspberrypi:~ $ gpio readall show BCM and wPi pinmap |
| | | * |
| | | * VCC ---- 5V/3.3V |
| | | * GND ---- GND |
| | | * I/O ---- GPIO.18 ---- GPIO.1 |
| | | * BCM wPi |
| | | * |
| | | * Version: 1.0.0(2018/10/14) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "2018/10/14 12:13:26" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #ifndef __BEEP_H |
| | | #define __BEEP_H |
| | | |
| | | #define OFF 0 |
| | | #define ON 1 |
| | | |
| | | #define BEEP_FREQ 2400 |
| | | |
| | | /* Use Pin12 == GPIO18(BCM) == GPIO.1(wPi) */ |
| | | #define PWM_PIN 1 |
| | | |
| | | |
| | | int turn_passive_beep(int cmd, int freq); |
| | | |
| | | int turn_active_beep(int cmd); |
| | | |
| | | #endif |
| | | |
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 cp_comport_t structure pointer. |
| | | *************************************************************************************/ |
| | | cp_comport_t *comport_init(const char *dev_name, int baudrate, const char *settings) |
| | | { |
| | | cp_comport_t *comport = NULL; |
| | | if (NULL == (comport = (cp_comport_t *) malloc(sizeof(cp_comport_t)))) |
| | | { |
| | | return NULL; |
| | | } |
| | | memset(comport, 0, sizeof(cp_comport_t)); |
| | | comport->connected = 0; |
| | | comport->frag_size = 128; |
| | | |
| | | strncpy(comport->dev_name, dev_name, DEVNAME_LEN); |
| | | comport->baudrate = baudrate; |
| | | |
| | | set_settings(comport, settings); |
| | | #ifdef COM_DEBUG |
| | | disp_settings(comport); |
| | | #endif |
| | | |
| | | return comport; |
| | | } |
| | | |
| | | #ifdef COM_DEBUG |
| | | void disp_settings(cp_comport_t * comport) |
| | | { |
| | | COM_PRINT("Device:\t\t\t\"%s\"\n", comport->dev_name); |
| | | COM_PRINT("Baudrate:\t\t%ld\n", comport->baudrate); |
| | | COM_PRINT("DataBit:\t\t\'%d\'\n", comport->databit); |
| | | switch (comport->parity) |
| | | { |
| | | case 0: |
| | | COM_PRINT("Parity:\t\t\t\'N\'\n"); |
| | | break; |
| | | case 1: |
| | | COM_PRINT("Parity:\t\t\t\'O\'\n"); |
| | | break; |
| | | case 2: |
| | | COM_PRINT("Parity:\t\t\t\'E\'\n"); |
| | | break; |
| | | case 3: |
| | | COM_PRINT("Parity:\t\t\t\'S\'\n"); |
| | | break; |
| | | } |
| | | COM_PRINT("StopBit:\t\t\'%ld\'\n", (long int)comport->stopbit); |
| | | switch (comport->flowctrl) |
| | | { |
| | | case 0: |
| | | COM_PRINT("FlowCtrl:\t\t\'N\'\n"); |
| | | break; |
| | | case 1: |
| | | COM_PRINT("FlowCtrl:\t\t\'S\'\n"); |
| | | break; |
| | | case 2: |
| | | COM_PRINT("FlowCtrl:\t\t\'H\'\n"); |
| | | break; |
| | | case 3: |
| | | COM_PRINT("FlowCtrl:\t\t\'B\'\n"); |
| | | break; |
| | | } |
| | | COM_PRINT("\n"); |
| | | return; |
| | | } |
| | | #endif |
| | | |
| | | /************************************************************************************** |
| | | * Description: Set the comport databit,parity,stopbit,flowctrl |
| | | * Input Args: comport: the cp_comport_t pointer |
| | | * settings: The databit/parity/stopbit/flowctrl settings as like "8N1N" |
| | | * Output Args: NONE |
| | | * Return Value: NONE |
| | | *************************************************************************************/ |
| | | void set_settings(cp_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(cp_comport_t * comport) |
| | | { |
| | | if (0 != comport->fd) |
| | | { |
| | | COM_PRINT("Close device \"%s\"\n", comport->dev_name); |
| | | close(comport->fd); |
| | | } |
| | | comport->connected = 0x00; |
| | | comport->fd = -1; |
| | | } |
| | | |
| | | void cp_comport_term(cp_comport_t * comport) |
| | | { |
| | | if(NULL == comport) |
| | | return; |
| | | |
| | | if (0 != comport->fd) |
| | | { |
| | | comport_close(comport); |
| | | } |
| | | memset(comport, 0x00, sizeof(cp_comport_t)); |
| | | free(comport); |
| | | comport = NULL; |
| | | |
| | | return; |
| | | } |
| | | |
| | | int comport_open(cp_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")) |
| | | { |
| | | COM_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; |
| | | } |
| | | COM_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; |
| | | } |
| | | |
| | | COM_PRINT("Connected device \"%s\".\n", comport->dev_name); |
| | | comport->connected = 0x01; |
| | | retval = comport->fd; |
| | | |
| | | CleanUp: |
| | | COM_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(cp_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) |
| | | { |
| | | COM_PRINT("%s() usage error.\n", __FUNCTION__); |
| | | retval = -1; |
| | | goto CleanUp; |
| | | } |
| | | |
| | | if (0x01 != comport->connected) |
| | | { |
| | | COM_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 |
| | | COM_PRINT("Error checking recv status.\n"); |
| | | goto CleanUp; |
| | | } |
| | | |
| | | if (0 == FD_ISSET(comport->fd, &stReadFds)) |
| | | { |
| | | retval = 0; // No incoming data |
| | | COM_PRINT("No incoming data.\n"); |
| | | goto CleanUp; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | if (EINTR == errno) |
| | | { |
| | | COM_PRINT("catch interrupt signal.\n"); |
| | | retval = 0; // Interrupted signal catched |
| | | } |
| | | else |
| | | { |
| | | COM_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(cp_comport_t * comport, char *buf, int send_bytes) |
| | | { |
| | | char *ptr, *end; |
| | | int retval = 0; |
| | | int send = 0; |
| | | |
| | | if (NULL == buf || 0 >= send_bytes) |
| | | { |
| | | COM_PRINT("%s() Usage error.\n", __FUNCTION__); |
| | | retval = -1; |
| | | goto CleanUp; |
| | | } |
| | | |
| | | if (0x01 != comport->connected) // Comport not opened ? |
| | | { |
| | | retval = -3; |
| | | COM_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 COM_DEBUG |
| | | #ifdef COM_DEBUG |
| | | #define COM_PRINT(format,args...) printf(format, ##args) |
| | | #else |
| | | #define COM_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 cp_comport_s |
| | | { |
| | | unsigned char databit, parity, stopbit, flowctrl, connected; |
| | | char dev_name[DEVNAME_LEN]; |
| | | unsigned char used; /* This comport used or not now */ |
| | | int fd; |
| | | int frag_size; |
| | | long baudrate; |
| | | } cp_comport_t; |
| | | |
| | | cp_comport_t *comport_init(const char *dev_name, int baudrate, const char *settings); |
| | | void comport_close(cp_comport_t * comport); |
| | | int comport_open(cp_comport_t * comport); |
| | | void cp_comport_term(cp_comport_t * comport); |
| | | int comport_recv(cp_comport_t * comport, char *buf, int buf_size, unsigned long timeout); |
| | | int comport_send(cp_comport_t * comport, char *buf, int send_bytes); |
| | | |
| | | void set_settings(cp_comport_t * comport, const char *settings); |
| | | void disp_settings(cp_comport_t * comport); |
| | | void nonblock(); |
| | | int kbhit(); |
| | | |
| | | #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] KiB, 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; |
| | | 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+"; |
| | | |
| | | 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; |
| | | |
| | | log_rollback_size = logger->size <= 0 ? LOG_ROLLBACK_NONE : logger->size*1024; /* Unit KiB */ |
| | | |
| | | 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+"; |
| | | 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_str(int level, const char *msg) |
| | | { |
| | | if (!logger || level>logger->level) |
| | | return; |
| | | |
| | | check_and_rollback(); |
| | | |
| | | if (logger->fp) |
| | | fwrite(msg, 1, strlen(msg), logger->fp); |
| | | |
| | | 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_str(int level, const char *msg); |
| | | |
| | | 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) 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 <pthread.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; |
| | | case SIGSEGV: |
| | | log_warn("SIGSEGV - stopping\n"); |
| | | #if 0 |
| | | if(g_cp_signal.stop) |
| | | exit(0); |
| | | |
| | | g_cp_signal.stop = 1; |
| | | #endif |
| | | break; |
| | | |
| | | case SIGPIPE: |
| | | log_warn("SIGPIPE - warnning\n"); |
| | | 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; |
| | | //int done = 0; |
| | | |
| | | memset(cmd, 0, sizeof(cmd)); |
| | | |
| | | va_start(args, format); |
| | | //done = vsnprintf(cmd, sizeof(cmd), format, args); |
| | | 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) 2014 Guo Wenxue<guowenxue@gmail.com> |
| | | * All rights reserved. |
| | | * |
| | | * Filename: cp_socket.c |
| | | * Description: This file |
| | | * |
| | | * Version: 1.0.0(11/18/2014) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "11/18/2014 11:15:04 PM" |
| | | * |
| | | ********************************************************************************/ |
| | | #include <stdio.h> |
| | | #include <unistd.h> |
| | | #include <string.h> |
| | | #include <netdb.h> |
| | | #include <unistd.h> |
| | | #include <fcntl.h> |
| | | |
| | | #include <sys/un.h> |
| | | #include <sys/types.h> |
| | | #include <linux/sockios.h> |
| | | #include <sys/ioctl.h> |
| | | #include <sys/socket.h> |
| | | #include <netinet/in.h> |
| | | #include <arpa/inet.h> |
| | | |
| | | #include "cp_logger.h" |
| | | #include "cp_socket.h" |
| | | |
| | | int cp_sock_block_connect(cp_socket_t *sock, char *servaddr, unsigned short servport) |
| | | { |
| | | int rv = -1; |
| | | int sock_fd = -1; |
| | | char service[20]; |
| | | struct addrinfo hints, *rp; |
| | | struct addrinfo *res = NULL; |
| | | struct in_addr inaddr; |
| | | char ipstr[20]; |
| | | int len; |
| | | |
| | | if(!sock || !servaddr || !servport ) |
| | | { |
| | | log_err("Invalid input argument\n"); |
| | | return -1; |
| | | } |
| | | |
| | | if(SOCK_STAT_CONNECTED == sock->status) |
| | | { |
| | | return 0; |
| | | } |
| | | |
| | | len = strlen(servaddr); |
| | | len = len>DOMAIN_MAX_LEN ? DOMAIN_MAX_LEN : len; |
| | | |
| | | memcpy(sock->servaddr, servaddr, strlen(servaddr)); |
| | | sock->servport = servport; |
| | | |
| | | log_nrml("Start socket connect to [%s:%d]...\n", sock->servaddr, sock->servport); |
| | | |
| | | memset(&hints, 0, sizeof(struct addrinfo)); |
| | | hints.ai_family = AF_INET; /* Only support IPv4 */ |
| | | hints.ai_socktype = SOCK_STREAM; |
| | | |
| | | /* If Hostname is a valid IP address, then don't use name resolution */ |
| | | if( inet_aton(sock->servaddr, &inaddr) ) |
| | | { |
| | | log_info("%s is a valid IP address, don't use name resolution.\n", sock->servaddr); |
| | | hints.ai_flags |= AI_NUMERICHOST; |
| | | } |
| | | |
| | | /* Obtain address(es) matching servaddr/servport */ |
| | | snprintf(service, sizeof(service), "%d", sock->servport); |
| | | if( (rv=getaddrinfo(sock->servaddr, service, &hints, &res)) ) |
| | | { |
| | | log_err("getaddrinfo() parser [%s:%s] failed: %s\n", sock->servaddr, service, gai_strerror(rv)); |
| | | rv = -2; |
| | | goto out; |
| | | } |
| | | |
| | | /* getaddrinfo() returns a list of address structures. Try each address until connected */ |
| | | rv = -3; /* default return value set be connect failure */ |
| | | sock->status = SOCK_STAT_DISCONNECT; |
| | | for (rp=res; rp!=NULL; rp=rp->ai_next) |
| | | { |
| | | /* create the socket */ |
| | | sock_fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); |
| | | if( sock_fd < 0) |
| | | { |
| | | log_err("socket() create failed: %s\n", strerror(errno)); |
| | | rv = -4; |
| | | continue; |
| | | } |
| | | |
| | | inet_ntop(AF_INET, &(((struct sockaddr_in *)(rp->ai_addr))->sin_addr), ipstr, sizeof(ipstr)); |
| | | log_dbg("DNS resolve IP address [%s]\n", ipstr); |
| | | |
| | | /* connect to the remote server successfully */ |
| | | if(0==connect(sock_fd, rp->ai_addr, rp->ai_addrlen)) |
| | | { |
| | | memcpy(&sock->saddr, &rp->ai_addr, sizeof(sock->saddr)); |
| | | sock->fd = sock_fd; |
| | | sock->status = SOCK_STAT_CONNECTED; |
| | | rv = 0; |
| | | goto out; |
| | | } |
| | | else /* Connect to server failed. */ |
| | | { |
| | | rv = -5; |
| | | log_err("connect() to server IP[%s] failed: %s\n", ipstr, strerror(errno)); |
| | | } |
| | | |
| | | close(sock_fd); |
| | | } |
| | | |
| | | |
| | | out: |
| | | if( rv < 0 ) |
| | | { |
| | | log_err("create socket connect to [%s:%d] failed: %s\n", sock->servaddr, sock->servport, strerror(errno)); |
| | | sock->status = SOCK_STAT_DISCONNECT; |
| | | sock->fd = -1; |
| | | } |
| | | else |
| | | { |
| | | log_nrml("create socket connect to [%s:%d] successfully\n", sock->servaddr, sock->servport); |
| | | sock->status = SOCK_STAT_CONNECTED; |
| | | } |
| | | |
| | | if(res) |
| | | { |
| | | freeaddrinfo(res); |
| | | } |
| | | |
| | | return rv; |
| | | } |
| | | |
| | | int cp_sock_nonblock_connect(cp_socket_t *sock, char *servaddr, unsigned short servport) |
| | | { |
| | | int rv = -1; |
| | | int sock_fd = -1; |
| | | char service[20]; |
| | | struct addrinfo hints, *rp; |
| | | struct addrinfo *res = NULL; |
| | | struct in_addr inaddr; |
| | | char ipstr[20]; |
| | | |
| | | if( !sock || !servaddr || !servport ) |
| | | { |
| | | log_err("Invalid input argument\n"); |
| | | return -1; |
| | | } |
| | | |
| | | if(SOCK_STAT_CONNECTED == sock->status) |
| | | { |
| | | return 0; |
| | | } |
| | | else if(SOCK_STAT_CONNECTING == sock->status) |
| | | { |
| | | goto connecting; |
| | | } |
| | | |
| | | log_nrml("Start socket connect to [%s:%d]...\n", sock->servaddr, sock->servport); |
| | | |
| | | memset(&hints, 0, sizeof(struct addrinfo)); |
| | | hints.ai_family = AF_INET; /* Only support IPv4 */ |
| | | hints.ai_socktype = SOCK_STREAM; |
| | | |
| | | /* If Hostname is a valid IP address, then don't use name resolution */ |
| | | if( inet_aton(sock->servaddr, &inaddr) ) |
| | | { |
| | | log_info("%s is a valid IP address, don't use name resolution.\n", sock->servaddr); |
| | | hints.ai_flags |= AI_NUMERICHOST; |
| | | } |
| | | |
| | | /* Obtain address(es) matching servaddr/servport */ |
| | | snprintf(service, sizeof(service), "%d", sock->servport); |
| | | if( (rv=getaddrinfo(sock->servaddr, service, &hints, &res)) ) |
| | | { |
| | | log_err("getaddrinfo() parser [%s:%s] failed: %s\n", sock->servaddr, service, gai_strerror(rv)); |
| | | rv = -2; |
| | | goto failed; |
| | | } |
| | | |
| | | |
| | | /* getaddrinfo() returns a list of address structures. Try each |
| | | * address until we successfully connect or bind |
| | | */ |
| | | rv = -3; /* Connect failure */ |
| | | for (rp=res; rp!=NULL; rp=rp->ai_next) |
| | | { |
| | | /* Create the socket */ |
| | | sock_fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); |
| | | if( sock_fd < 0) |
| | | { |
| | | log_err("socket() create failed: %s\n", strerror(errno)); |
| | | rv = -4; |
| | | continue; |
| | | } |
| | | |
| | | inet_ntop(AF_INET, &(((struct sockaddr_in *)(rp->ai_addr))->sin_addr), ipstr, sizeof(ipstr)); |
| | | log_dbg("DNS resolve IP address [%s]\n", ipstr); |
| | | |
| | | cp_sock_set_nonblock(sock_fd); |
| | | |
| | | /* Nono block Connect to the remote server */ |
| | | if(0==connect(sock_fd, rp->ai_addr, rp->ai_addrlen)) |
| | | { |
| | | /* Conenct to server successfully */ |
| | | memcpy(&sock->saddr, &rp->ai_addr, sizeof(sock->saddr)); |
| | | sock->fd = sock_fd; |
| | | sock->status = SOCK_STAT_CONNECTED; |
| | | rv = 0; |
| | | goto connected; |
| | | } |
| | | else |
| | | { |
| | | if(EINPROGRESS == errno) |
| | | { |
| | | /* Connect to server now in progress */ |
| | | memcpy(&sock->saddr, &rp->ai_addr, sizeof(sock->saddr)); |
| | | sock->fd = sock_fd; |
| | | sock->status = SOCK_STAT_CONNECTING; |
| | | rv = 0; |
| | | goto connecting; |
| | | } |
| | | else |
| | | { |
| | | /* Connect to server failed. */ |
| | | close(sock_fd); |
| | | rv = -5; |
| | | log_err("connect() to server failed: %s\n", strerror(errno)); |
| | | goto failed; |
| | | } |
| | | } |
| | | |
| | | close(sock_fd); |
| | | } |
| | | |
| | | |
| | | failed: |
| | | log_err("create socket connect to [%s:%d] failed: %s\n", sock->servaddr, sock->servport, strerror(errno)); |
| | | sock->status = SOCK_STAT_DISCONNECT; |
| | | sock->fd = -1; |
| | | return rv; |
| | | |
| | | connecting: |
| | | if(SOCK_STAT_CONNECTING == sock->status) |
| | | { |
| | | int len; |
| | | |
| | | len = sizeof(sock->saddr); |
| | | |
| | | errno = 0; |
| | | if( 0 == connect(sock->fd, &sock->saddr, len) ) |
| | | { |
| | | /* connect() return 0 means it already connected */ |
| | | sock->status = SOCK_STAT_CONNECTED; |
| | | rv = 0; |
| | | goto connected; |
| | | } |
| | | |
| | | /* Connect failure will continue to check */ |
| | | switch (errno) |
| | | { |
| | | case EISCONN: |
| | | sock->status = SOCK_STAT_CONNECTED; |
| | | rv = 0; |
| | | goto connected; |
| | | |
| | | case EALREADY: |
| | | case EINPROGRESS: |
| | | log_dbg("socket[%d] connect to remote [%s:%d] in progress\n", sock->fd, sock->servaddr, sock->servport); |
| | | rv = 0; |
| | | goto cleanup; |
| | | |
| | | default: |
| | | log_err("socket[%d] connect to remote [%s:%d] failed: %s\n", sock->fd, sock->servaddr, sock->servport, strerror(errno)); |
| | | sock->status = SOCK_STAT_DISCONNECT; |
| | | rv = -7; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | connected: |
| | | if(SOCK_STAT_CONNECTED == sock->status) |
| | | { |
| | | rv = 0; |
| | | log_nrml("socket[%d] connected to remote server [%s:%d]\n", sock->fd, sock->servaddr, sock->servport); |
| | | goto cleanup; |
| | | } |
| | | |
| | | cleanup: |
| | | if(res) |
| | | freeaddrinfo(res); /* No longer needed */ |
| | | |
| | | return rv; |
| | | } |
| | | |
| | | |
| | | int cp_sock_set_nonblock(int sockfd) |
| | | { |
| | | int opts; |
| | | /* |
| | | * fcntl may set: |
| | | * |
| | | * EACCES, EAGAIN: Operation is prohibited by locks held by other |
| | | * processes. Or, operation is prohibited because the file has |
| | | * been memory-mapped by another process. |
| | | * EBADF: fd is not an open file descriptor, or the command was F_SETLK |
| | | * or F_SETLKW and the file descriptor open mode doesn't match |
| | | * with the type of lock requested. |
| | | * EDEADLK: It was detected that the specified F_SETLKW command would |
| | | * cause a deadlock. |
| | | * EFAULT: lock is outside your accessible address space. |
| | | * EINTR: For F_SETLKW, the command was interrupted by a signal. For |
| | | * F_GETLK and F_SETLK, the command was interrupted by a signal |
| | | * before the lock was checked or acquired. Most likely when |
| | | * locking a remote file (e.g. locking over NFS), but can |
| | | * sometimes happen locally. |
| | | * EINVAL: For F_DUPFD, arg is negative or is greater than the maximum |
| | | * allowable value. For F_SETSIG, arg is not an allowable signal |
| | | * number. |
| | | * EMFILE: For F_DUPFD, the process already has the maximum number of |
| | | * file descriptors open. |
| | | * ENOLCK: Too many segment locks open, lock table is full, or a remote |
| | | * locking protocol failed (e.g. locking over NFS). |
| | | * EPERM: Attempted to clear the O_APPEND flag on a file that has the |
| | | * append-only attribute set. |
| | | */ |
| | | opts = fcntl(sockfd, F_GETFL); |
| | | if (opts < 0) |
| | | { |
| | | log_warn("fcntl() get socket options failure: %s\n", strerror(errno)); |
| | | return -1; |
| | | } |
| | | |
| | | opts |= O_NONBLOCK; |
| | | if (fcntl(sockfd, F_SETFL, opts) < 0) |
| | | { |
| | | log_warn("fcntl() set socket options failure: %s\n", strerror(errno)); |
| | | return -1; |
| | | } |
| | | |
| | | log_dbg("Set socket[%d] none blocking\n", sockfd); |
| | | return opts; |
| | | } |
| | | |
| | | |
| | | |
| | | void cp_sock_close(cp_socket_t *sock) |
| | | { |
| | | close(sock->fd); |
| | | sock->fd = 0; |
| | | sock->status = SOCK_STAT_INIT; |
| | | } |
| | | |
New file |
| | |
| | | /******************************************************************************** |
| | | * Copyright: (C) 2014 Guo Wenxue<guowenxue@gmail.com> |
| | | * All rights reserved. |
| | | * |
| | | * Filename: cp_socket.h |
| | | * Description: This head file |
| | | * |
| | | * Version: 1.0.0(11/19/2014) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "11/19/2014 12:16:45 AM" |
| | | * |
| | | ********************************************************************************/ |
| | | #ifndef __CP_SOCKET_H_ |
| | | #define __CP_SOCKET_H_ |
| | | |
| | | #include <sys/types.h> |
| | | #include <sys/socket.h> |
| | | |
| | | #define DOMAIN_MAX_LEN 128 |
| | | |
| | | #define SOCK_STAT_INIT 0 |
| | | #define SOCK_STAT_CONNECTING 1 |
| | | #define SOCK_STAT_CONNECTED 2 |
| | | #define SOCK_STAT_DISCONNECT 3 |
| | | |
| | | typedef struct cp_socket_s |
| | | { |
| | | char servaddr[DOMAIN_MAX_LEN]; /* connect server hostname or IP address */ |
| | | unsigned short servport; /* connect server port */ |
| | | int fd; /* socket fd */ |
| | | struct sockaddr saddr; /* sockaddr for none-block connect */ |
| | | unsigned char status; /* socket connect status: 0:disconnect 1:connecting 2:connected */ |
| | | } cp_socket_t; |
| | | |
| | | |
| | | /* Description: create socket object and connect to server in block mode |
| | | * $sock: socket object, if it's NULL will be malloced. |
| | | * $servaddr: connect server hostname or IP address |
| | | * $servport: connect to server port |
| | | * |
| | | * Return: socket object address |
| | | */ |
| | | extern int cp_sock_block_connect(cp_socket_t *sock, char * servaddr, unsigned short servport); |
| | | |
| | | |
| | | /* Description: set socket to none block mode */ |
| | | extern int cp_sock_set_nonblock(int sockfd); |
| | | |
| | | /* Description: create socket object and connect to server in none block mode |
| | | * $sock: socket object, if it's NULL will be malloced. |
| | | * $servaddr: connect server hostname or IP address |
| | | * $servport: connect to server port |
| | | * |
| | | * Return: 0: connecting or connected <0: connect failure |
| | | */ |
| | | |
| | | extern int cp_sock_nonblock_connect(cp_socket_t *sock, char * servaddr, unsigned short servport); |
| | | |
| | | |
| | | /* Description: close socket */ |
| | | extern void cp_sock_close(cp_socket_t *sock); |
| | | |
| | | |
| | | #endif |
| | | |
New file |
| | |
| | | #********************************************************************************* |
| | | # Copyright: (C) 2012 Guo Wenxue<Email:guowenxue@gmail.com QQ:281143292> |
| | | # All rights reserved. |
| | | # |
| | | # Filename: Makefile |
| | | # Description: This Makefile used to compile all the C source code file in current |
| | | # folder to one 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) |
| | | INSTPATH=/usr/bin |
| | | |
| | | CFLAGS+=-I${PWD} |
| | | #CFLAGS+=-Wall -Werror |
| | | |
| | | LDFLAGS+=-lwiringPi |
| | | LDFLAGS+=-lpthread |
| | | |
| | | VPATH= . |
| | | SRCS = $(wildcard ${VPATH}/*.c) |
| | | OBJS = $(patsubst %.c,%.o,$(SRCS)) |
| | | |
| | | #CC=arm-linux- |
| | | 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 |
| | | |
| | | SRCFILES = $(wildcard *.c) |
| | | IMAGE_NAME=$(shell basename ${PWD}) |
| | | |
| | | all: entry binary |
| | | entry: |
| | | @echo " "; |
| | | @echo " ========================================================="; |
| | | @echo " ** Compile \"${BINARIES}\" for ${ARCH} "; |
| | | @echo " ========================================================="; |
| | | |
| | | binary: ${SRCFILES} |
| | | $(CC) $(CFLAGS) -o ${IMAGE_NAME} $^ ${LDFLAGS} |
| | | @echo " Compile over" |
| | | |
| | | tag: |
| | | @ctags --c-kinds=+defglmnstuvx --langmap=c:.c.h.ho.hem.het.hec.hev.him.hit.hic.hiv -R . |
| | | @cscope -Rbq |
| | | |
| | | install: |
| | | @cp $(IMAGE_NAME) ${INSTPATH} |
| | | |
| | | clean: |
| | | @rm -f version.h |
| | | @rm -f *.o $(IMAGE_NAME) |
| | | @rm -rf *.gdb *.a *.so *.elf* |
| | | |
| | | distclean: clean |
| | | @rm -f tags cscope* |
| | | |
| | | .PHONY: clean entry |
| | | |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2018 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: monitord.c |
| | | * Description: This file is the monitord program, which use infrared to detect human |
| | | * incoming, then turn on the LED by relay and take a photo for it. |
| | | * |
| | | * Version: 1.0.0(2018年05月29日) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "2018年05月29日 21时03分54秒" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #include <unistd.h> |
| | | #include <libgen.h> |
| | | #include <getopt.h> |
| | | #include "monitord.h" |
| | | #include "cp_logger.h" |
| | | #include "cp_proc.h" |
| | | |
| | | |
| | | /* Show program version information, can used by 'monitord --version or monitord -v'*/ |
| | | static inline void prog_version(const char *progname) |
| | | { |
| | | printf("%s Version 1.0.0 Build(%s)\n", progname, __DATE__); |
| | | return ; |
| | | } |
| | | |
| | | |
| | | /* Show program help information, can used by 'monitord --help or monitord -h'*/ |
| | | static void prog_usage(const char *progname) |
| | | { |
| | | prog_version(progname); |
| | | |
| | | printf("Usage: %s [OPTION]...\n", progname); |
| | | printf("Receive date from a serial port and transfer the data to remote server by socket.\n"); |
| | | printf("\nMandatory arguments to long options are mandatory for short options too:\n"); |
| | | |
| | | printf(" -d[debug ] Running in debug mode\n"); |
| | | printf(" -l[level ] Set the log level as [0..%d]\n", LOG_LEVEL_MAX-1); |
| | | printf(" -s[server ] Socket connect server host and port, format as: Hostname:Port, default as 127.0.0.1:8900\n"); |
| | | |
| | | printf(" -v[version ] Display program version\n"); |
| | | printf(" -h[help ] Display this help information\n"); |
| | | return ; |
| | | } |
| | | |
| | | void *infrared_worker(void *arg); |
| | | |
| | | int main (int argc, char **argv) |
| | | { |
| | | const char *progname=NULL; |
| | | |
| | | int opt; |
| | | int debug = 0; /* program running information log to stdard output */ |
| | | char pid_file[64] = { 0 }; /* The file used to record the PID */ |
| | | int log_level = LOG_LEVEL_TRACE; /* program running information log to file level */ |
| | | cp_logger *logger; |
| | | char *log_file="monitord.log"; /* program running information log file name */ |
| | | |
| | | char *server="127.0.0.1:8900"; /* default connect server address, can use '-s' option to change */ |
| | | |
| | | int rv; |
| | | pthread_t tid; |
| | | |
| | | /* progranm command options */ |
| | | struct option long_options[] = { |
| | | {"debug", no_argument, NULL, 'd'}, /* monitord -d or monitord --debug, log to standard output or not */ |
| | | {"level", required_argument, NULL, 'l'}, /* monitord -l 7, specify log to file level */ |
| | | {"server", required_argument, NULL, 's'}, /* monitord -s 192.168.0.5:9999, specify server address and port */ |
| | | {"version", no_argument, NULL, 'v'}, /* monitord -v or monitord --version to check program version information */ |
| | | {"help", no_argument, NULL, 'h'}, /* monitord -h or monitord --help to get program help information */ |
| | | {NULL, 0, NULL, 0} /* array end flag */ |
| | | }; |
| | | |
| | | |
| | | progname = basename(argv[0]); |
| | | |
| | | /* Parser the command line options */ |
| | | while ((opt = getopt_long(argc, argv, "s:dl:vh", long_options, NULL)) != -1) |
| | | { |
| | | switch (opt) |
| | | { |
| | | case 'd': /* monitord -d or monitord --debug */ |
| | | debug = 1; |
| | | log_file = DBG_LOG_FILE; |
| | | break; |
| | | |
| | | case 'l': /* monitord -l 7 */ |
| | | rv = atoi(optarg); |
| | | log_level = rv>LOG_LEVEL_MAX ? LOG_LEVEL_MAX-1 : rv; |
| | | break; |
| | | |
| | | case 'v': /* monitord -v */ |
| | | prog_version(progname); |
| | | return EXIT_SUCCESS; |
| | | |
| | | case 'h': /* monitord -h */ |
| | | prog_usage(progname); |
| | | return 0; |
| | | |
| | | default: |
| | | break; |
| | | } /* end of "switch(opt)" */ |
| | | } |
| | | |
| | | |
| | | /* parser hostname and port by server*/ |
| | | { |
| | | char *ptr; |
| | | |
| | | ptr=strchr(server, ':'); |
| | | if( !ptr ) |
| | | { |
| | | printf("Invalid server host[%s], which format should be [HostName:Port] such as \"127.0.0.1:8900\"", server); |
| | | return -1; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /* check program already running on background or not */ |
| | | if( !debug ) |
| | | { |
| | | snprintf(pid_file, sizeof(pid_file), "/var/run/%s.pid", progname); |
| | | if( check_daemon_running(pid_file) ) |
| | | { |
| | | printf("Programe already running, exit now.\n"); |
| | | return -1; |
| | | } |
| | | } |
| | | |
| | | /* initialise logger system */ |
| | | if( !(logger=cp_log_init(NULL, log_file, log_level, 0)) || cp_log_open()<0 ) |
| | | { |
| | | printf("Init logger system failed, program exit now...\n"); |
| | | return -1; |
| | | } |
| | | /* set program running in background */ |
| | | if( !debug ) |
| | | { |
| | | if( set_daemon_running(pid_file) ) |
| | | { |
| | | log_fatal("Set program \"%s\" running as daemon failure.\n", progname); |
| | | return -2; |
| | | } |
| | | } |
| | | |
| | | /* install signal process handler */ |
| | | cp_install_proc_signal(); |
| | | |
| | | /* start infrared detected thread */ |
| | | thread_start(&tid, infrared_worker, NULL); |
| | | |
| | | while( !g_cp_signal.stop ) |
| | | { |
| | | /* control/main thread do nothing here */ |
| | | sleep(1); |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | void *infrared_worker(void *arg) |
| | | { |
| | | int rv = 0; |
| | | |
| | | #if 0 |
| | | if( !arg ) |
| | | { |
| | | log_err("Invalid arguments\n"); |
| | | return NULL; |
| | | } |
| | | #endif |
| | | |
| | | log_nrml("Thread worker for infrared start\n"); |
| | | |
| | | while( !g_cp_signal.stop ) |
| | | { |
| | | } |
| | | |
| | | return NULL; |
| | | } |
| | | |
| | | |
New file |
| | |
| | | /******************************************************************************** |
| | | * Copyright: (C) 2018 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: monitord.h |
| | | * Description: This head file |
| | | * |
| | | * Version: 1.0.0(2018年05月29日) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "2018年05月29日 21时05分43秒" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #ifndef _MONITORD_H_ |
| | | #define _MONITORD_H_ |
| | | |
| | | |
| | | #endif /* ----- #ifndef _MONITORD_H_ ----- */ |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2018 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: ds18b20.c |
| | | * Description: This file is temperature sensor DS18B20 code |
| | | * |
| | | * Version: 1.0.0(2018/10/14) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "2018/10/14 12:13:26" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <unistd.h> |
| | | #include <fcntl.h> |
| | | #include <dirent.h> |
| | | #include <string.h> |
| | | #include <time.h> |
| | | #include <errno.h> |
| | | |
| | | /* File Content: |
| | | pi@raspberrypi:~/guowenxue $ cat /sys/bus/w1/devices/28-041731f7c0ff/w1_slave |
| | | 3a 01 4b 46 7f ff 0c 10 a5 : crc=a5 YES |
| | | 3a 01 4b 46 7f ff 0c 10 a5 t=19625 |
| | | */ |
| | | |
| | | int ds18b20_get_temperature(float *temp) |
| | | { |
| | | char w1_path[50] = "/sys/bus/w1/devices/"; |
| | | char chip[20]; |
| | | char buf[128]; |
| | | DIR *dirp; |
| | | struct dirent *direntp; |
| | | int fd =-1; |
| | | char *ptr; |
| | | float value; |
| | | int found = 0; |
| | | |
| | | if( !temp ) |
| | | { |
| | | return -1; |
| | | } |
| | | |
| | | /*+-------------------------------------------------------------------+ |
| | | *| open dierectory /sys/bus/w1/devices to get chipset Serial Number | |
| | | *+-------------------------------------------------------------------+*/ |
| | | if((dirp = opendir(w1_path)) == NULL) |
| | | { |
| | | printf("opendir error: %s\n", strerror(errno)); |
| | | return -2; |
| | | } |
| | | |
| | | while((direntp = readdir(dirp)) != NULL) |
| | | { |
| | | if(strstr(direntp->d_name,"28-")) |
| | | { |
| | | /* find and get the chipset SN filename */ |
| | | strcpy(chip,direntp->d_name); |
| | | found = 1; |
| | | break; |
| | | } |
| | | } |
| | | closedir(dirp); |
| | | |
| | | if( !found ) |
| | | { |
| | | printf("Can not find ds18b20 in %s\n", w1_path); |
| | | return -3; |
| | | } |
| | | |
| | | /* get DS18B20 sample file full path: /sys/bus/w1/devices/28-xxxx/w1_slave */ |
| | | strncat(w1_path, chip, sizeof(w1_path)-strlen(w1_path)); |
| | | strncat(w1_path, "/w1_slave", sizeof(w1_path)-strlen(w1_path)); |
| | | |
| | | /* open file /sys/bus/w1/devices/28-xxxx/w1_slave to get temperature */ |
| | | if( (fd=open(w1_path, O_RDONLY)) < 0 ) |
| | | { |
| | | printf("open %s error: %s\n", w1_path, strerror(errno)); |
| | | return -4; |
| | | } |
| | | |
| | | if(read(fd, buf, sizeof(buf)) < 0) |
| | | { |
| | | printf("read %s error: %s\n", w1_path, strerror(errno)); |
| | | return -5; |
| | | } |
| | | |
| | | ptr = strstr(buf, "t="); |
| | | if( !ptr ) |
| | | { |
| | | printf("ERROR: Can not get temperature\n"); |
| | | return -6; |
| | | } |
| | | |
| | | ptr+=2; |
| | | |
| | | /* convert string value to float value */ |
| | | *temp = atof(ptr)/1000; |
| | | |
| | | close(fd); |
| | | |
| | | return 0; |
| | | } |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2018 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: ds18b20.c |
| | | * Description: This file is temperature sensor DS18B20 code |
| | | * |
| | | * Version: 1.0.0(2018/10/14) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "2018/10/14 12:13:26" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #ifndef __DS18B20_H |
| | | #define __DS18B20_H |
| | | |
| | | extern int ds18b20_get_temperature(float *temp); |
| | | |
| | | #endif |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2018 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: led.c |
| | | * Description: This file is used to control RGB 3-colours LED |
| | | * |
| | | * pi@raspberrypi:~ $ gpio readall show BCM and wPi pinmap |
| | | * |
| | | * LED BCM wPi |
| | | * G ---- GPIO.13 ---- GPIO.23 |
| | | * R ---- GPIO.19 ---- GPIO.24 |
| | | * B ---- GPIO.26 ---- GPIO.25 |
| | | * I ---- GND ---- |
| | | * |
| | | * Version: 1.0.0(2018/10/14) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "2018/10/14 12:13:26" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <unistd.h> |
| | | #include <fcntl.h> |
| | | #include <dirent.h> |
| | | #include <string.h> |
| | | #include <time.h> |
| | | #include <errno.h> |
| | | |
| | | #include <wiringPi.h> |
| | | #include "led.h" |
| | | |
| | | void init_led(void) |
| | | { |
| | | int i; |
| | | |
| | | wiringPiSetup(); |
| | | |
| | | for(i=0; i<LED_MAX; i++) |
| | | { |
| | | pinMode( led_gpio[i], OUTPUT ); |
| | | } |
| | | } |
| | | |
| | | int turn_led(int which, int cmd) |
| | | { |
| | | if( which<0 || which>=LED_MAX ) |
| | | return -1; |
| | | |
| | | |
| | | if( OFF == cmd ) |
| | | digitalWrite (led_gpio[which], LOW); |
| | | else |
| | | digitalWrite (led_gpio[which], HIGH); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2018 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: led.h |
| | | * Description: This file is used to control RGB 3-colours LED |
| | | * |
| | | * pi@raspberrypi:~ $ gpio readall show BCM and wPi pinmap |
| | | * |
| | | * LED BCM wPi |
| | | * G ---- GPIO.13 ---- GPIO.23 |
| | | * R ---- GPIO.19 ---- GPIO.24 |
| | | * B ---- GPIO.26 ---- GPIO.25 |
| | | * I ---- GND ---- |
| | | * |
| | | * Version: 1.0.0(2018/10/14) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "2018/10/14 12:13:26" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #ifndef __LED_H |
| | | #define __LED_H |
| | | |
| | | #define OFF 0 |
| | | #define ON 1 |
| | | |
| | | /* Three LEDs code */ |
| | | enum |
| | | { |
| | | LED_R = 0, |
| | | LED_G, |
| | | LED_B, |
| | | LED_MAX, |
| | | }; |
| | | |
| | | /* 3 LEDs WiringPi GPIO port */ |
| | | |
| | | /* LED_R LED_G LED_B */ |
| | | static int led_gpio[LED_MAX]= { 24, 23, 25 }; |
| | | |
| | | |
| | | void init_led(void); |
| | | int turn_led(int which, int cmd); |
| | | |
| | | |
| | | #endif |
| | | |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2019 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: main.c |
| | | * Description: This file |
| | | * |
| | | * Version: 1.0.0(29/01/19) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "29/01/19 15:34:41" |
| | | * |
| | | ********************************************************************************/ |
| | | #include <stdio.h> |
| | | #include <time.h> |
| | | #include <unistd.h> |
| | | |
| | | #include "led.h" |
| | | #include "ds18b20.h" |
| | | #include "sht20.h" |
| | | |
| | | int hal_init(void); |
| | | |
| | | /******************************************************************************** |
| | | * Description: |
| | | * Input Args: |
| | | * Output Args: |
| | | * Return Value: |
| | | ********************************************************************************/ |
| | | int main (int argc, char **argv) |
| | | { |
| | | float temp; |
| | | float rh; |
| | | |
| | | if( hal_init() < 0 ) |
| | | { |
| | | printf("Initialise hardware failure\n"); |
| | | return -1; |
| | | } |
| | | |
| | | while(1) |
| | | { |
| | | turn_led(LED_R, ON); |
| | | sleep(1); |
| | | turn_led(LED_R, OFF); |
| | | sleep(1); |
| | | |
| | | turn_led(LED_G, ON); |
| | | sleep(1); |
| | | turn_led(LED_G, OFF); |
| | | sleep(1); |
| | | |
| | | turn_led(LED_B, ON); |
| | | sleep(1); |
| | | turn_led(LED_B, OFF); |
| | | sleep(1); |
| | | |
| | | if(sht2x_get_temp_humidity(&temp, &rh) < 0) |
| | | { |
| | | printf("SHT2X get temperature and relative humidity failure\n"); |
| | | } |
| | | else |
| | | { |
| | | printf("SHT2X Temperature=%lf ℃ relative humidity=%lf%\n", temp, rh); |
| | | } |
| | | |
| | | |
| | | if( ds18b20_get_temperature(&temp) < 0) |
| | | { |
| | | printf("DS18B20 get temperature failure\n"); |
| | | } |
| | | else |
| | | { |
| | | printf("DS18B20 get temperature=%lf ℃ \n", temp); |
| | | } |
| | | } |
| | | |
| | | return 0; |
| | | } /* ----- End of main() ----- */ |
| | | |
| | | |
| | | int hal_init(void) |
| | | { |
| | | init_led(); |
| | | |
| | | if( sht2x_init() < 0 ) |
| | | { |
| | | printf("Initialise SHT20 failure\n"); |
| | | return -2; |
| | | } |
| | | |
| | | return 0; |
| | | } |
New file |
| | |
| | | #********************************************************************************* |
| | | # Copyright: (C) 2012 Guo Wenxue<Email:guowenxue@gmail.com QQ:281143292> |
| | | # All rights reserved. |
| | | # |
| | | # Filename: Makefile |
| | | # Description: This Makefile used to compile all the C source code file in current |
| | | # folder to one 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) |
| | | INSTPATH=/usr/bin |
| | | |
| | | CFLAGS+=-I${PWD} |
| | | #CFLAGS+=-Wall -Werror |
| | | |
| | | LDFLAGS+=-lwiringPi |
| | | LDFLAGS+=-lpthread |
| | | |
| | | VPATH= . |
| | | SRCS = $(wildcard ${VPATH}/*.c) |
| | | OBJS = $(patsubst %.c,%.o,$(SRCS)) |
| | | |
| | | #CC=arm-linux- |
| | | 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 |
| | | |
| | | SRCFILES = $(wildcard *.c) |
| | | IMAGE_NAME=$(shell basename ${PWD}) |
| | | |
| | | all: entry binary |
| | | entry: |
| | | @echo " "; |
| | | @echo " ========================================================="; |
| | | @echo " ** Compile \"${BINARIES}\" for ${ARCH} "; |
| | | @echo " ========================================================="; |
| | | |
| | | binary: ${SRCFILES} |
| | | $(CC) $(CFLAGS) -o ${IMAGE_NAME} $^ ${LDFLAGS} |
| | | @echo " Compile over" |
| | | |
| | | tag: |
| | | @ctags --c-kinds=+defglmnstuvx --langmap=c:.c.h.ho.hem.het.hec.hev.him.hit.hic.hiv -R . |
| | | @cscope -Rbq |
| | | |
| | | install: |
| | | @cp $(IMAGE_NAME) ${INSTPATH} |
| | | |
| | | clean: |
| | | @rm -f version.h |
| | | @rm -f *.o $(IMAGE_NAME) |
| | | @rm -rf *.gdb *.a *.so *.elf* |
| | | |
| | | distclean: clean |
| | | @rm -f tags cscope* |
| | | |
| | | .PHONY: clean entry |
| | | |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2018 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: sht20.c |
| | | * Description: This file is temperature and relative humidity sensor SHT20 code |
| | | * |
| | | * Version: 1.0.0(2018/10/14) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "2018/10/14 12:13:26" |
| | | * |
| | | ********************************************************************************/ |
| | | |
| | | #include <stdio.h> |
| | | #include <fcntl.h> |
| | | #include <unistd.h> |
| | | #include <sys/ioctl.h> |
| | | #include <linux/types.h> |
| | | #include <sys/stat.h> |
| | | #include <linux/i2c.h> |
| | | #include <linux/i2c-dev.h> |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <sys/types.h> |
| | | #include <string.h> |
| | | #include <stdint.h> |
| | | #include <time.h> |
| | | #include <errno.h> |
| | | #include <string.h> |
| | | |
| | | #include "sht20.h" |
| | | |
| | | static int s_sht2x_fd = -1; |
| | | |
| | | void sht2x_term(void) |
| | | { |
| | | close(s_sht2x_fd); |
| | | s_sht2x_fd = -1; |
| | | printf("Terminate SHT2X\n"); |
| | | } |
| | | |
| | | #ifdef I2C_API_RDWR /* Use I2C userspace driver read/write API */ |
| | | |
| | | int sht2x_softreset(int fd) |
| | | { |
| | | uint8_t buf[4]; |
| | | |
| | | if( fd<0 ) |
| | | { |
| | | printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__ ); |
| | | return -1; |
| | | } |
| | | |
| | | /* software reset SHT2x */ |
| | | memset(buf, 0, sizeof(buf)); |
| | | |
| | | buf[0] = SOFTRESET; |
| | | write(fd, buf, 1); |
| | | |
| | | msleep(50); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | int sht2x_init(void) |
| | | { |
| | | |
| | | if( (s_sht2x_fd=open("/dev/i2c-1", O_RDWR)) < 0) |
| | | { |
| | | printf("i2c device open failed: %s\n", strerror(errno)); |
| | | return -1; |
| | | } |
| | | |
| | | /* set I2C mode and SHT2x slave address */ |
| | | ioctl(s_sht2x_fd, I2C_TENBIT, 0); /* Not 10-bit but 7-bit mode */ |
| | | ioctl(s_sht2x_fd, I2C_SLAVE, 0x40); /* set SHT2x slava address 0x40*/ |
| | | |
| | | if( sht2x_softreset(s_sht2x_fd) < 0 ) |
| | | { |
| | | printf("SHT2x softreset failure\n"); |
| | | sht2x_term(); |
| | | return -2; |
| | | } |
| | | |
| | | return s_sht2x_fd; |
| | | } |
| | | |
| | | int sht2x_get_temp_humidity(float *temp, float *rh) |
| | | { |
| | | uint8_t buf[4]; |
| | | |
| | | if( !temp || !rh ) |
| | | { |
| | | printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__ ); |
| | | return -1; |
| | | } |
| | | |
| | | if( s_sht2x_fd < 0 ) |
| | | { |
| | | if( sht2x_init() < 0) |
| | | { |
| | | printf("SHT2x initialise failure\n"); |
| | | return -2; |
| | | } |
| | | } |
| | | |
| | | /* send trigger temperature measure command and read the data */ |
| | | memset(buf, 0, sizeof(buf)); |
| | | buf[0]=TRIGGER_TEMPERATURE_NO_HOLD; |
| | | write(s_sht2x_fd, buf, 1); |
| | | |
| | | msleep(85); /* datasheet: typ=66, max=85 */ |
| | | |
| | | memset(buf, 0, sizeof(buf)); |
| | | read(s_sht2x_fd, buf, 3); |
| | | //dump_buf("Temperature sample data: ", buf, 3); |
| | | *temp = 175.72 * (((((int) buf[0]) << 8) + buf[1]) / 65536.0) - 46.85; |
| | | |
| | | /* send trigger humidity measure command and read the data */ |
| | | memset(buf, 0, sizeof(buf)); |
| | | buf[0] = TRIGGER_HUMIDITY_NO_HOLD; |
| | | write(s_sht2x_fd, buf, 1); |
| | | |
| | | msleep(29); /* datasheet: typ=22, max=29 */ |
| | | memset(buf, 0, sizeof(buf)); |
| | | |
| | | read(s_sht2x_fd, buf, 3); |
| | | //dump_buf("Relative humidity sample data: ", buf, 3); |
| | | *rh = 125 * (((((int) buf[0]) << 8) + buf[1]) / 65536.0) - 6; |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | int sht2x_get_serialnumber(uint8_t *serialnumber, int size) |
| | | { |
| | | uint8_t buf[4]; |
| | | |
| | | if( !serialnumber || size!=8 ) |
| | | { |
| | | printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__ ); |
| | | return -1; |
| | | } |
| | | |
| | | if( s_sht2x_fd < 0 ) |
| | | { |
| | | if( sht2x_init() < 0) |
| | | { |
| | | printf("SHT2x initialise failure\n"); |
| | | return -2; |
| | | } |
| | | } |
| | | |
| | | /* Read SerialNumber from Location 1 */ |
| | | memset(buf, 0, sizeof(buf)); |
| | | buf[0] = 0xfa; /* command for readout on-chip memory */ |
| | | buf[1] = 0x0f; /* on-chip memory address */ |
| | | write(s_sht2x_fd, buf, 2); |
| | | |
| | | memset(buf, 0, sizeof(buf)); |
| | | read(s_sht2x_fd, buf, 4); |
| | | |
| | | serialnumber[5]=buf[0]; /* Read SNB_3 */ |
| | | serialnumber[4]=buf[1]; /* Read SNB_2 */ |
| | | serialnumber[3]=buf[2]; /* Read SNB_1 */ |
| | | serialnumber[2]=buf[3]; /* Read SNB_0 */ |
| | | |
| | | /* Read SerialNumber from Location 2 */ |
| | | memset(buf, 0, sizeof(buf) ); |
| | | buf[0]=0xfc; /* command for readout on-chip memory */ |
| | | buf[1]=0xc9; /* on-chip memory address */ |
| | | write(s_sht2x_fd, buf, 2); |
| | | |
| | | memset(buf, 0, sizeof(buf) ); |
| | | read(s_sht2x_fd, buf, 4); |
| | | |
| | | serialnumber[1]=buf[0]; /* Read SNC_1 */ |
| | | serialnumber[0]=buf[1]; /* Read SNC_0 */ |
| | | serialnumber[7]=buf[2]; /* Read SNA_1 */ |
| | | serialnumber[6]=buf[3]; /* Read SNA_0 */ |
| | | |
| | | //dump_buf("SHT2x Serial number: ", serialnumber, 8); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | #elif (defined I2C_API_IOCTL) /* Use I2C userspace driver read/write API */ |
| | | |
| | | int sht2x_softreset(int fd) |
| | | { |
| | | struct i2c_msg msg; |
| | | struct i2c_rdwr_ioctl_data sht2x_data; |
| | | uint8_t buf[2]; |
| | | |
| | | if( fd<0 ) |
| | | { |
| | | printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__ ); |
| | | return -1; |
| | | } |
| | | |
| | | msg.addr= 0x40; |
| | | msg.flags=0; //write |
| | | msg.len= 1; |
| | | msg.buf= buf; |
| | | msg.buf[0]=SOFTRESET; |
| | | |
| | | sht2x_data.nmsgs= 1; |
| | | sht2x_data.msgs= &msg; |
| | | |
| | | if( ioctl(fd, I2C_RDWR, &sht2x_data) < 0 ) |
| | | { |
| | | printf("%s() ioctl failure: %s\n", __func__, strerror(errno)); |
| | | sht2x_term(); |
| | | return -2; |
| | | } |
| | | |
| | | msleep(50); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | int sht2x_init(void) |
| | | { |
| | | if( (s_sht2x_fd=open("/dev/i2c-1", O_RDWR)) < 0) |
| | | { |
| | | printf("i2c device open failed: %s\n", strerror(errno)); |
| | | return -1; |
| | | } |
| | | |
| | | if( sht2x_softreset(s_sht2x_fd) < 0 ) |
| | | { |
| | | printf("SHT2x softreset failure\n"); |
| | | sht2x_term(); |
| | | return -2; |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | int sht2x_get_serialnumber(uint8_t *serialnumber, int size) |
| | | { |
| | | struct i2c_msg msgs[2]; |
| | | struct i2c_rdwr_ioctl_data sht2x_data; |
| | | uint8_t sbuf[2]; |
| | | uint8_t rbuf[4]; |
| | | |
| | | if( !serialnumber || size!=8 ) |
| | | { |
| | | printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__ ); |
| | | return -1; |
| | | } |
| | | |
| | | if( s_sht2x_fd < 0 ) |
| | | { |
| | | if( sht2x_init() < 0) |
| | | { |
| | | printf("SHT2x initialise failure\n"); |
| | | return -2; |
| | | } |
| | | } |
| | | |
| | | /*+------------------------------------------+ |
| | | *| Read SerialNumber from Location 1 | |
| | | *+------------------------------------------+*/ |
| | | |
| | | msgs[0].addr= 0x40; |
| | | msgs[0].flags=0; //write |
| | | msgs[0].len= 2; |
| | | msgs[0].buf= sbuf; |
| | | msgs[0].buf[0]=0xfa; /* command for readout on-chip memory */ |
| | | msgs[0].buf[1]=0x0f; /* on-chip memory address */ |
| | | |
| | | msgs[1].addr=0x40; |
| | | msgs[1].flags=I2C_M_RD; //write |
| | | msgs[1].len= 4; |
| | | msgs[1].buf= rbuf; |
| | | |
| | | sht2x_data.nmsgs= 2; |
| | | sht2x_data.msgs= msgs; |
| | | |
| | | if( ioctl(s_sht2x_fd, I2C_RDWR, &sht2x_data) < 0 ) |
| | | { |
| | | printf("%s() ioctl failure: %s\n", __func__, strerror(errno)); |
| | | sht2x_term(); |
| | | return -2; |
| | | } |
| | | |
| | | serialnumber[5]=rbuf[0]; /* Read SNB_3 */ |
| | | serialnumber[4]=rbuf[1]; /* Read SNB_2 */ |
| | | serialnumber[3]=rbuf[2]; /* Read SNB_1 */ |
| | | serialnumber[2]=rbuf[3]; /* Read SNB_0 */ |
| | | |
| | | |
| | | /*+------------------------------------------+ |
| | | *| Read SerialNumber from Location 2 | |
| | | *+------------------------------------------+*/ |
| | | |
| | | msgs[0].addr= 0x40; |
| | | msgs[0].flags=0; //write |
| | | msgs[0].len= 2; |
| | | msgs[0].buf= sbuf; |
| | | msgs[0].buf[0]=0xfc; /* command for readout on-chip memory */ |
| | | msgs[0].buf[1]=0xc9; /* on-chip memory address */ |
| | | |
| | | msgs[1].addr=0x40; |
| | | msgs[1].flags=I2C_M_RD; //write |
| | | msgs[1].len= 4; |
| | | msgs[1].buf= rbuf; |
| | | |
| | | sht2x_data.nmsgs= 2; |
| | | sht2x_data.msgs= msgs; |
| | | |
| | | if( ioctl(s_sht2x_fd, I2C_RDWR, &sht2x_data) < 0 ) |
| | | { |
| | | printf("%s() ioctl failure: %s\n", __func__, strerror(errno)); |
| | | sht2x_term(); |
| | | return -2; |
| | | } |
| | | |
| | | serialnumber[1]=rbuf[0]; /* Read SNC_1 */ |
| | | serialnumber[0]=rbuf[1]; /* Read SNC_0 */ |
| | | serialnumber[7]=rbuf[2]; /* Read SNA_1 */ |
| | | serialnumber[6]=rbuf[3]; /* Read SNA_0 */ |
| | | |
| | | //dump_buf("SHT2x Serial number: ", serialnumber, 8); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | int sht2x_get_temp_humidity(float *temp, float *rh) |
| | | { |
| | | struct i2c_msg msg; |
| | | struct i2c_rdwr_ioctl_data sht2x_data; |
| | | uint8_t buf[4]; |
| | | |
| | | if( !temp || !rh ) |
| | | { |
| | | printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__ ); |
| | | return -1; |
| | | } |
| | | |
| | | if( s_sht2x_fd < 0 ) |
| | | { |
| | | if( sht2x_init() < 0) |
| | | { |
| | | printf("SHT2x initialise failure\n"); |
| | | return -2; |
| | | } |
| | | } |
| | | |
| | | /*+------------------------------------------+ |
| | | *| measure and get temperature | |
| | | *+------------------------------------------+*/ |
| | | |
| | | msg.addr= 0x40; |
| | | msg.flags=0; //write |
| | | msg.len= 1; |
| | | msg.buf= buf; |
| | | msg.buf[0]=TRIGGER_TEMPERATURE_NO_HOLD; /* trigger temperature without hold I2C bus */ |
| | | |
| | | sht2x_data.nmsgs= 1; |
| | | sht2x_data.msgs= &msg; |
| | | |
| | | if( ioctl(s_sht2x_fd, I2C_RDWR, &sht2x_data) < 0 ) |
| | | { |
| | | printf("%s() ioctl failure: %s\n", __func__, strerror(errno)); |
| | | sht2x_term(); |
| | | return -2; |
| | | } |
| | | |
| | | msleep(85); |
| | | |
| | | memset(buf, 0, sizeof(buf)); |
| | | msg.addr=0x40; |
| | | msg.flags=I2C_M_RD; //write |
| | | msg.len= 3; |
| | | msg.buf= buf; |
| | | |
| | | sht2x_data.nmsgs= 1; |
| | | sht2x_data.msgs= &msg; |
| | | |
| | | if( ioctl(s_sht2x_fd, I2C_RDWR, &sht2x_data) < 0 ) |
| | | { |
| | | printf("%s() ioctl failure: %s\n", __func__, strerror(errno)); |
| | | sht2x_term(); |
| | | return -2; |
| | | } |
| | | |
| | | //dump_buf("Temperature sample data: ", buf, 3); |
| | | *temp = 175.72 * (((((int) buf[0]) << 8) + buf[1]) / 65536.0) - 46.85; |
| | | |
| | | |
| | | /*+------------------------------------------+ |
| | | *| measure and get relative humidity | |
| | | *+------------------------------------------+*/ |
| | | |
| | | msg.addr= 0x40; |
| | | msg.flags=0; //write |
| | | msg.len= 1; |
| | | msg.buf= buf; |
| | | msg.buf[0]=TRIGGER_HUMIDITY_NO_HOLD; /* trigger humidity without hold I2C bus */ |
| | | |
| | | sht2x_data.nmsgs= 1; |
| | | sht2x_data.msgs= &msg; |
| | | |
| | | if( ioctl(s_sht2x_fd, I2C_RDWR, &sht2x_data) < 0 ) |
| | | { |
| | | printf("%s() ioctl failure: %s\n", __func__, strerror(errno)); |
| | | sht2x_term(); |
| | | return -2; |
| | | } |
| | | |
| | | msleep(29); |
| | | |
| | | memset(buf, 0, sizeof(buf)); |
| | | msg.addr=0x40; |
| | | msg.flags=I2C_M_RD; //write |
| | | msg.len= 3; |
| | | msg.buf= buf; |
| | | |
| | | sht2x_data.nmsgs= 1; |
| | | sht2x_data.msgs= &msg; |
| | | |
| | | if( ioctl(s_sht2x_fd, I2C_RDWR, &sht2x_data) < 0 ) |
| | | { |
| | | printf("%s() ioctl failure: %s\n", __func__, strerror(errno)); |
| | | sht2x_term(); |
| | | return -2; |
| | | } |
| | | |
| | | //dump_buf("Relative humidity sample data: ", buf, 3); |
| | | *rh = 125 * (((((int) buf[0]) << 8) + buf[1]) / 65536.0) - 6; |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | #endif |
| | | |
New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2018 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: sht20.c |
| | | * Description: This file is temperature and relative humidity sensor SHT20 code |
| | | * |
| | | * Version: 1.0.0(2018/10/14) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "2018/10/14 12:13:26" |
| | | * |
| | | ********************************************************************************/ |
| | | #ifndef __SHT20_H |
| | | #define __SHT20_H |
| | | |
| | | #include <stdint.h> |
| | | #include <time.h> |
| | | |
| | | #define SOFTRESET 0xFE |
| | | #define TRIGGER_TEMPERATURE_NO_HOLD 0xF3 |
| | | #define TRIGGER_HUMIDITY_NO_HOLD 0xF5 |
| | | |
| | | //#define I2C_API_IOCTL /* Use I2C userspace driver ioctl API */ |
| | | #define I2C_API_RDWR /* Use I2C userspace driver read/write API */ |
| | | |
| | | void sht2x_term(void); |
| | | int sht2x_init(void); |
| | | int sht2x_get_serialnumber(uint8_t *serialnumber, int size); |
| | | int sht2x_get_temp_humidity(float *temp, float *rh); |
| | | |
| | | static inline void msleep(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); |
| | | } |
| | | |
| | | static inline void dump_buf(const char *prompt, uint8_t *buf, int size) |
| | | { |
| | | int i; |
| | | |
| | | if( !buf ) |
| | | { |
| | | return ; |
| | | } |
| | | |
| | | if( prompt ) |
| | | { |
| | | printf("%s ", prompt); |
| | | } |
| | | |
| | | for(i=0; i<size; i++) |
| | | { |
| | | printf("%02x ", buf[i]); |
| | | } |
| | | printf("\n"); |
| | | |
| | | return ; |
| | | } |
| | | |
| | | #endif |
| | | |