| | |
| | | *.a |
| | | cscope.* |
| | | tags |
| | | *.tar* |
| | | *.log |
| | | *.db |
| | |
| | | return 0; |
| | | } |
| | | |
| | | int packet_segmented_pack(pack_info_t *pack_info, char *pack_buf, int size) |
| | | int packet_segmented_pack(pack_info_t *pack_info, uint8_t *pack_buf, int size) |
| | | { |
| | | char strtime[TIME_LEN] = {'\0'}; |
| | | struct tm *ptm; |
| | | char *buf = (char *)pack_buf; |
| | | |
| | | if( !pack_info || !pack_buf || size<=0 ) |
| | | if( !pack_info || !buf || size<=0 ) |
| | | { |
| | | log_error("Invalid input arguments\n"); |
| | | return -1; |
| | |
| | | ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday, |
| | | ptm->tm_hour, ptm->tm_min, ptm->tm_sec); |
| | | |
| | | memset(pack_buf, 0, size); |
| | | snprintf(pack_buf, size, "%s|%s|%.3f", pack_info->devid, strtime, pack_info->temper); |
| | | memset(buf, 0, size); |
| | | snprintf(buf, size, "%s|%s|%.3f", pack_info->devid, strtime, pack_info->temper); |
| | | |
| | | return strlen(pack_buf); |
| | | return strlen(buf); |
| | | } |
| | | |
| | | int packet_json_pack(pack_info_t *pack_info, char *pack_buf, int size) |
| | | int packet_json_pack(pack_info_t *pack_info, uint8_t *pack_buf, int size) |
| | | { |
| | | char strtime[TIME_LEN] = {'\0'}; |
| | | struct tm *ptm; |
| | | char *buf = (char *)pack_buf; |
| | | |
| | | if( !pack_info || !pack_buf || size<=0 ) |
| | | if( !pack_info || !buf || size<=0 ) |
| | | { |
| | | log_error("Invalid input arguments\n"); |
| | | return -1; |
| | |
| | | ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday, |
| | | ptm->tm_hour, ptm->tm_min, ptm->tm_sec); |
| | | |
| | | memset(pack_buf, 0, size); |
| | | snprintf(pack_buf, size, "{\"devid\":\"%s\", \"time\":\"%s\",\"temperature\":\"%.3f\"}", |
| | | memset(buf, 0, size); |
| | | snprintf(buf, size, "{\"devid\":\"%s\", \"time\":\"%s\",\"temperature\":\"%.3f\"}", |
| | | pack_info->devid, strtime, pack_info->temper); |
| | | |
| | | return strlen(pack_buf); |
| | | return strlen(buf); |
| | | } |
| | | |
| | | /* |
| | | * The CRC-ITU-T, also known as CRC-16-ITU-T or CRC-16-V.41, uses the polynomial: |
| | | * 0x1021: x^16 + x^12 + x^5 + 1 |
| | | */ |
| | | |
| | | #define CRC16_ITU_T_POLY 0x1021 /* Define the CRC-ITU-T polynomial */ |
| | | static uint16_t crc_itu_t(const uint8_t *data, size_t length) |
| | | { |
| | | uint16_t crc = 0xFFFF; |
| | | size_t i, j; |
| | | |
| | | for (i=0; i<length; i++) |
| | | { |
| | | crc ^= ((uint16_t)data[i] << 8); |
| | | |
| | | for(j=0; j<8; j++) |
| | | { |
| | | if (crc & 0x8000) |
| | | { |
| | | crc = (crc << 1) ^ CRC16_ITU_T_POLY; |
| | | } |
| | | else |
| | | { |
| | | crc <<= 1; |
| | | } |
| | | } |
| | | } |
| | | |
| | | return crc; |
| | | } |
| | | |
| | | uint16_t to_big_endian(uint16_t num) |
| | | { |
| | | return (num << 8) | (num >> 8); |
| | | } |
| | | |
| | | /* TLV(Tag Length Value) PDU(Protocal Data Unit) format: |
| | | * |
| | | * +-----------+-----------+------------+-------------+-------------+ |
| | | * | Header(2B)| Tag(1B) | Length(2B) | Value(nB) | CRC16(2B) | |
| | | * +-----------+-----------+------------+-------------+-------------+ |
| | | * |
| | | * Header(2B): 0xFE 0xFD |
| | | * Tag(1B): 0x01->temperature 0x02->Humidity 0x03->Noisy ... |
| | | * Length(2B): Data value length |
| | | * Value(nB): Data value |
| | | * CRC16(2B): CRC from Header to Value |
| | | */ |
| | | |
| | | int packet_tlv_pack(pack_info_t *pack_info, uint8_t *pack_buf, int size) |
| | | { |
| | | struct tm *ptm; |
| | | int ofset = 0; |
| | | uint16_t crc; |
| | | |
| | | if( !pack_info || !pack_buf || size<TLV_MINSIZE ) |
| | | |
| | | { |
| | | log_error("Invalid input arguments\n"); |
| | | return -1; |
| | | } |
| | | |
| | | /*+----------------------+ |
| | | *| TLV Header(2B) | |
| | | *+----------------------+*/ |
| | | *(uint16_t *)pack_buf = to_big_endian(TLV_HEADER); |
| | | ofset += 2; |
| | | |
| | | /*+----------------------+ |
| | | *| TLV Tag(1B) | |
| | | *+----------------------+*/ |
| | | pack_buf[ofset++] = TAG_TEMPERATURE; |
| | | |
| | | /* Skip data length here, we will calculate it later */ |
| | | ofset += 2; |
| | | |
| | | /*+----------------------+ |
| | | *| payload data value | |
| | | *+----------------------+*/ |
| | | |
| | | /* 6 bytes sample time */ |
| | | ptm = &pack_info->sample_time; |
| | | pack_buf[ofset++] = (uint8_t)(ptm->tm_year+1900-2000); |
| | | pack_buf[ofset++] = (uint8_t)(ptm->tm_mon+1); |
| | | pack_buf[ofset++] = (uint8_t)(ptm->tm_mday); |
| | | pack_buf[ofset++] = (uint8_t)(ptm->tm_hour); |
| | | pack_buf[ofset++] = (uint8_t)(ptm->tm_min); |
| | | pack_buf[ofset++] = (uint8_t)(ptm->tm_sec); |
| | | |
| | | /* 8 bytes device SN */ |
| | | strncpy((char *)(pack_buf+ofset), pack_info->devid, DEVID_LEN); |
| | | ofset += DEVID_LEN; |
| | | |
| | | /* 2 bytes temperature value */ |
| | | pack_buf[ofset++] = (int)pack_info->temper; /* integer part */ |
| | | pack_buf[ofset++] = (((int)(pack_info->temper*100))%100); /* fractional part */ |
| | | |
| | | /*+----------------------+ |
| | | *| TLV Length(2B) | |
| | | *+----------------------+*/ |
| | | *(uint16_t *)(pack_buf+3) = (ofset-5); |
| | | |
| | | /*+----------------------+ |
| | | *| TLV CRC(2B) | |
| | | *+----------------------+*/ |
| | | crc = crc_itu_t(pack_buf, ofset); |
| | | *(uint16_t *)(pack_buf+ofset) = crc; |
| | | ofset += 2; |
| | | |
| | | return ofset; |
| | | } |
| | | |
| | |
| | | #include <stdint.h> |
| | | #include <time.h> |
| | | |
| | | #define DEVID_LEN 16 |
| | | #define DEVID_LEN 8 |
| | | #define TIME_LEN 32 |
| | | |
| | | typedef struct pack_info_s |
| | | { |
| | | char devid[DEVID_LEN]; /* device ID */ |
| | | char devid[DEVID_LEN+1]; /* device ID */ |
| | | struct tm sample_time; /* sample time */ |
| | | float temper; /* sample temperature */ |
| | | } pack_info_t; |
| | | |
| | | /* packet function pointer type */ |
| | | typedef int (* pack_proc_t)(pack_info_t *pack_info, char *pack_buf, int size); |
| | | typedef int (* pack_proc_t)(pack_info_t *pack_info, uint8_t *pack_buf, int size); |
| | | |
| | | /* description: get device ID |
| | | * input args: |
| | |
| | | * $size : packet output buffer size |
| | | * return value: <0: failure >0: packet bytes |
| | | */ |
| | | extern int packet_segmented_pack(pack_info_t *pack_info, char *pack_buf, int size); |
| | | extern int packet_segmented_pack(pack_info_t *pack_info, uint8_t *pack_buf, int size); |
| | | |
| | | |
| | | /* description: package a json string packet: {"devid":"xxx", "time":"xxx", "temperature":"xxx"} |
| | |
| | | * $size : packet output buffer size |
| | | * return value: <0: failure >0: packet bytes |
| | | */ |
| | | extern int packet_json_pack(pack_info_t *pack_info, char *pack_buf, int size); |
| | | extern int packet_json_pack(pack_info_t *pack_info, uint8_t *pack_buf, int size); |
| | | |
| | | |
| | | /* TLV(Tag Length Value) PDU(Protocal Data Unit) format: |
| | | * |
| | | * +-----------+-----------+------------+-------------+-------------+ |
| | | * | Header(2B)| Tag(1B) | Length(2B) | Value(nB) | CRC16(2B) | |
| | | * +-----------+-----------+------------+-------------+-------------+ |
| | | * |
| | | * Header(2B): 0xFE 0xED |
| | | * Tag(1B): 0x01->temperature 0x02->Humidity 0x03->Noisy ... |
| | | * Length(2B): Data length |
| | | * Value(nB): Data value |
| | | * CRC16(2B): CRC from Header to Value |
| | | */ |
| | | |
| | | /* TLV Header */ |
| | | #define TLV_HEADER 0xFEED |
| | | |
| | | /* TLV bytes without payload: Header(2B)+Tag(1B)+Length(2B)+CRC16(2B) */ |
| | | #define TLV_MINSIZE 7 |
| | | |
| | | /* TVL Tag definition */ |
| | | enum |
| | | { |
| | | TAG_TEMPERATURE = 1, |
| | | TAG_HUMIDITY, |
| | | TAG_NOISY, |
| | | }; |
| | | |
| | | /* description: package a TLV packet: 0xFD 0xFE |
| | | * input args: |
| | | * $pack_info: packet data contains devid, time and temperature |
| | | * $pack_buf : packet output buffer |
| | | * $size : packet output buffer size |
| | | * return value: <0: failure >0: packet bytes |
| | | */ |
| | | |
| | | int packet_tlv_pack(pack_info_t *pack_info, uint8_t *pack_buf, int size); |
| | | |
| | | #endif /* ----- #ifndef _PACKET_H_ ----- */ |
| | |
| | | * *****************************************************************************/ |
| | | int set_daemon_running(const char *pid_file) |
| | | { |
| | | daemonize(0, 1); |
| | | daemon(0, 1); |
| | | log_info("Program running as daemon [PID:%d].\n", getpid()); |
| | | |
| | | if (record_daemon_pid(pid_file) < 0) |
| | |
| | | { |
| | | close(sock->fd); |
| | | sock->fd = -1; |
| | | sock->connected = 0; |
| | | } |
| | | |
| | | return 0; |
| | |
| | | set_socket_rlimit(); /* set max open socket count */ |
| | | } |
| | | #endif |
| | | |
| | | /* description: check socket connect status |
| | | * input args: |
| | | * $sock: socket context pointer |
| | | * return value: 1: connected 0:disconnected |
| | | */ |
| | | int socket_connected(socket_ctx_t *sock) |
| | | { |
| | | struct tcp_info info; |
| | | int len=sizeof(info); |
| | | int changed = 0; |
| | | |
| | | if( !sock ) |
| | | { |
| | | return 0; |
| | | } |
| | | |
| | | if( sock->fd < 0 ) |
| | | { |
| | | /* socket is connected before but got disconnected now */ |
| | | changed = sock->connected ? 1 : 0; |
| | | sock->connected = 0; |
| | | goto out; |
| | | } |
| | | |
| | | getsockopt(sock->fd, IPPROTO_TCP, TCP_INFO, &info, (socklen_t *)&len); |
| | | if( TCP_ESTABLISHED==info.tcpi_state ) |
| | | { |
| | | /* socket is disconnected before but got connected now */ |
| | | changed = !sock->connected ? 1 : 0; |
| | | sock->connected = 1; |
| | | } |
| | | else |
| | | { |
| | | /* socket is connected before but got disconnected now */ |
| | | changed = sock->connected ? 1 : 0; |
| | | sock->connected = 0; |
| | | } |
| | | |
| | | out: |
| | | if( changed ) |
| | | { |
| | | log_info("socket status got %s\n", sock->connected?"connected":"disconnected"); |
| | | } |
| | | return sock->connected; |
| | | } |
| | | |
| | | /* description: socket connect to server in block mode |
| | | * input args: |
| | |
| | | } |
| | | |
| | | |
| | | |
| | | /*+-------------------------------------------------------------------+ |
| | | *| socket utils function | |
| | | *+-------------------------------------------------------------------+*/ |
| | | |
| | | |
| | | /* socket connected or not: <0: failure 0:ok */ |
| | | int sock_check_connect(int sockfd) |
| | | { |
| | | struct tcp_info info; |
| | | int len=sizeof(info); |
| | | |
| | | if( sockfd < 0 ) |
| | | return -1; |
| | | |
| | | getsockopt(sockfd, IPPROTO_TCP, TCP_INFO, &info, (socklen_t *)&len); |
| | | |
| | | if( TCP_CLOSE==info.tcpi_state || TCP_CLOSING==info.tcpi_state || TCP_CLOSE_WAIT==info.tcpi_state ) |
| | | { |
| | | return -3; |
| | | } |
| | | |
| | | return -0; |
| | | } |
| | | |
| | | /* description: set socket listen port as reusable, fix port already used bug */ |
| | | int socket_set_reuseaddr(int sockfd) |
| | |
| | | char host[HOSTNAME_LEN]; /* CLIENT: Connect server hostname; SERVER: Unused */ |
| | | int port; /* CLIENT: Connect server port; SERVER: listen port */ |
| | | int fd; /* socket descriptor */ |
| | | int connected; /* socket connect status: 1->connected 0->disconnected */ |
| | | } socket_ctx_t; |
| | | |
| | | /* description: initial socket context |
| | |
| | | * return value: <0: failure 0:ok |
| | | */ |
| | | extern int socket_listen(socket_ctx_t *sock); |
| | | |
| | | /* description: check socket connect status |
| | | * input args: |
| | | * $sock: socket context pointer |
| | | * return value: 1: connected 0:disconnected |
| | | */ |
| | | extern int socket_connected(socket_ctx_t *sock); |
| | | |
| | | /* description: socket client connect to server |
| | | * input args: |
| | |
| | | /*+-------------------------------------------------------------------+ |
| | | *| socket utils function | |
| | | *+-------------------------------------------------------------------+*/ |
| | | |
| | | |
| | | /* socket connected or not: <0: failure 0:ok */ |
| | | extern int sock_check_connect(int sockfd); |
| | | |
| | | /* description: set socket listen port as reusable, fix port already used bug */ |
| | | extern int socket_set_reuseaddr(int sockfd); |
| | |
| | | char pack_buf[1024]; |
| | | int pack_bytes = 0; |
| | | pack_info_t pack_info; |
| | | pack_proc_t pack_proc = packet_segmented_pack; /* use string packet */ |
| | | pack_proc_t pack_proc = packet_segmented_pack; /* use segmented string packet */ |
| | | //pack_proc_t pack_proc = packet_json_pack; /* use JSON string packet */ |
| | | //pack_proc_t pack_proc = packet_tlv_pack; /* use TLV(Tag Length Value) packet */ |
| | | |
| | | struct option opts[] = { |
| | | {"ipaddr", required_argument, NULL, 'i'}, |
| | |
| | | } |
| | | log_info("DS18B20 sample termperature %.3f oC\n", pack_info.temper); |
| | | |
| | | get_devid(pack_info.devid, DEVID_LEN, 40); |
| | | get_devid(pack_info.devid, sizeof(pack_info.devid), 88); |
| | | get_time(&pack_info.sample_time); |
| | | |
| | | pack_bytes = pack_proc(&pack_info, pack_buf, sizeof(pack_buf)); |
| | | pack_bytes = pack_proc(&pack_info, (uint8_t *)pack_buf, sizeof(pack_buf)); |
| | | log_dump(LOG_LEVEL_DEBUG, NULL, pack_buf, pack_bytes); |
| | | |
| | | sample_flag = 1; /* set sample flag */ |
| | | } |
| | | |
| | |
| | | * +---------------------------------+*/ |
| | | |
| | | /* start connect to server if not connected */ |
| | | if( sock.fd < 0 ) |
| | | if( !socket_connected(&sock) ) |
| | | { |
| | | socket_connect(&sock); |
| | | } |
| | | |
| | | /* check socket connected or not */ |
| | | if( sock_check_connect(sock.fd) < 0 ) |
| | | { |
| | | if( sock.fd > 0 ) |
| | | { |
| | | log_error("socket got disconnected, terminate it and reconnect now.\n"); |
| | | socket_term(&sock); /* close the soket */ |
| | | } |
| | | } |
| | | |
| | | /* +-------------------------------+ |
| | | * | socket disconnect | |
| | | * +-------------------------------+*/ |
| | | if( sock.fd < 0 ) |
| | | if( !socket_connected(&sock) ) |
| | | { |
| | | if( sample_flag ) |
| | | { |
| | |
| | | { |
| | | log_warn("socket send sample packet failure, save it in database now.\n"); |
| | | database_push_packet(pack_buf, pack_bytes); |
| | | socket_term(&sock); /* close the soket */ |
| | | continue; |
| | | } |
| | | } |
| | | |
| | |
| | | if( socket_send(&sock, pack_buf, pack_bytes) < 0 ) |
| | | { |
| | | log_error("socket send database packet failure"); |
| | | socket_term(&sock); /* close the soket */ |
| | | continue; |
| | | } |
| | | else |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | msleep(50); |
| | | msleep(5); |
| | | } |
| | | |
| | | cleanup: |
| | |
| | | |
| | | time(&now); |
| | | |
| | | if( now >= *last_time+interval ) |
| | | if( difftime(now, *last_time)>interval ) |
| | | { |
| | | need = 1; /* need sample now */ |
| | | *last_time = now; |