diff --git a/CMakeLists.txt b/CMakeLists.txt index 94b6064f93e..1b58181be08 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,7 @@ option(WITH_IN_XBEE "Enable XBee input plugin" No) option(WITH_IN_CPU "Enable CPU input plugin" Yes) option(WITH_IN_MEM "Enable Memory input plugin" Yes) option(WITH_IN_KMSG "Enable Kernel log input plugin" Yes) +option(WITH_IN_AM2320 "Enable AM2320/AM2321 input plugin" No) option(WITH_OUT_FLUENTD "Enable Fluentd output plugin" Yes) option(WITH_OUT_TD "Enable Treasure Data output plugin" Yes) option(WITH_OUT_STDOUT "Enable STDOUT output plugin" Yes) diff --git a/README.md b/README.md index c30fdd9ad34..437f42e5401 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ When building _Fluent-Bit_, the following options are available when running __c ------------|------------|---------------------------------------------|--------- WITH_ALL | bool | Enable all features available | off WITH_XBEE | bool | Enable XBee support (input) | off +WITH_AM2320 | bool | Enable AM2320/2321 Sensor support (input) | off WITH_DEBUG | bool | Include debug symbols when building targets | off WITHOUT_BIN | bool | Do not build the fluent-bit executable | off @@ -47,6 +48,7 @@ Once the tool have been compiled, a binary file called _Fluent-Bit_ will be foun | Memory | mem | usage of system memory | | Kernel Ring Buffer | kmsg | read Linux Kernel messages, same behavior as the __dmesg__ command line program | | XBee | xbee | listen for incoming messages over a Xbee device | +| AM2320 | am2320 | read temperature and humidity from AM2320/2321 from I2C senor device | ### Output Plugins diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 91cfb1ae45a..5a43adc721b 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -35,6 +35,7 @@ REGISTER_IN_PLUGIN("in_xbee") REGISTER_IN_PLUGIN("in_cpu") REGISTER_IN_PLUGIN("in_mem") REGISTER_IN_PLUGIN("in_kmsg") +REGISTER_IN_PLUGIN("in_am2320") REGISTER_OUT_PLUGIN("out_fluentd") REGISTER_OUT_PLUGIN("out_td") REGISTER_OUT_PLUGIN("out_stdout") diff --git a/plugins/in_am2320/CMakeLists.txt b/plugins/in_am2320/CMakeLists.txt new file mode 100644 index 00000000000..4bff31de8ac --- /dev/null +++ b/plugins/in_am2320/CMakeLists.txt @@ -0,0 +1,4 @@ +set(src + in_am2320.c am2320.c) + +FLB_PLUGIN(in_am2320 "${src}" "") diff --git a/plugins/in_am2320/README b/plugins/in_am2320/README new file mode 100644 index 00000000000..dea0623a060 --- /dev/null +++ b/plugins/in_am2320/README @@ -0,0 +1,20 @@ +AM2320/AM2321 input support for Fluent Bit +Developed and tested on Raspbian and Raspberry Pi Type B+ + +Remarks: +- needs i2c-dev.h in i2c-tools (or equivalent) to comple this plug-in. +- I2C device path is hard-coded to /dev/i2c-1. +- fluent-bit process needs access to /dev/i2c-1. + +License: +- am2320.[ch] is licensed under LGPL. +- in_am2320.[ch] is licensed under Apache License 2.0. + +Thanks to: +- original authors of am2320.c + https://github.com/takagi/am2321 + https://gist.github.com/yenjoji/40d135519a0741d3718b + +-- +Takeshi HASEGAWA + diff --git a/plugins/in_am2320/am2320.c b/plugins/in_am2320/am2320.c new file mode 100644 index 00000000000..7dd64438e5b --- /dev/null +++ b/plugins/in_am2320/am2320.c @@ -0,0 +1,173 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* + * am2320: AM2320/2321 I2C Sensor Driver + * Copyright (C) 2015 Takeshi HASEGAWA + * + * This file is modified version of: + * https://github.com/takagi/am2321 + * + * Licensed under the LGPL License. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include "in_am2320.h" +#include "am2320.h" + +/* + * udelay function + */ + +long timeval_to_usec(struct timeval tm) { + return tm.tv_sec * 1000000 + tm.tv_usec; +} + +void udelay(long us) { + struct timeval current; + struct timeval start; + + gettimeofday(&start, NULL); + do { + gettimeofday( ¤t, NULL); + } while(timeval_to_usec(current) - timeval_to_usec( start ) < us); +} + +/* + * CRC16 + */ + +unsigned short crc16(unsigned char *ptr, unsigned char len) { + unsigned short crc = 0xFFFF; + unsigned char i; + + while(len--) { + crc ^= *ptr++; + for(i = 0; i < 8; i++) { + if(crc & 0x01) { + crc >>= 1; + crc ^= 0xA001; + } else { + crc >>= 1; + } + } + } + + return crc; +} + +unsigned char crc16_low(unsigned short crc) { + return crc & 0xFF; +} + +unsigned char crc16_high(unsigned short crc) { + return crc >> 8; +} + +int in_am2320_check_crc16(unsigned char* data) { + unsigned short crc_m, crc_s; + + crc_m = crc16(data, 6); + crc_s = (data[7] << 8) + data[6]; + if (crc_m != crc_s) { + return 0; + } + + return 1; +} + +int in_am2320_read(struct flb_config *config, void *in_context) { + int retries = 5; + + struct flb_in_am2320_config *ctx = in_context; + int fd; + unsigned char data[8]; + + fd = open(IN_AM2320_I2C_DEVICE, O_RDWR); + if (fd < 0) { + flb_debug("[in_am2320] could not open I2C device: %s", + IN_AM2320_I2C_DEVICE); + return 1; + } + + /* set address of I2C device in 7 bits */ + int ret = ioctl( fd, I2C_SLAVE, IN_AM2320_I2C_ADDRESS); + if (ret < 0) { + flb_debug("[in_am2320] could not select I2C address: %x", + IN_AM2320_I2C_ADDRESS); + goto error; + } + + /* write measurement request */ + data[0] = 0x03; + data[1] = 0x00; + data[2] = 0x04; + + while (retries) { + /* wake I2C device up */ + write( fd, NULL, 0); + + ret = write(fd, data, 3); + + if (ret >= 0) + break; + + flb_debug("[in_am2320] write error, retries = %d"); + udelay(1000); + retries--; + } + + if (ret < 0) { + flb_debug("[in_am2320] write error"); + goto error; + } + + /* wait for having measured */ + udelay(1500); + + /* read measured result */ + memset(data, 0x00, 8); + ret = read(fd, data, 8); + if (ret < 0) + goto error; + + /* close I2C device */ + close(fd); + + if (! in_am2320_check_crc16(data)) { + flb_debug("[in_am2320] CRC error"); + return 0; + } + + double temp = (double) ((data[4] << 8) + data[5]) / 10; + double humidity = (double) ((data[2] << 8) + data[3]) / 10; + + msgpack_pack_map(&ctx->pckr, 3); + msgpack_pack_raw(&ctx->pckr, 4); + msgpack_pack_raw_body(&ctx->pckr, "time", 4); + msgpack_pack_uint64(&ctx->pckr, time(NULL)); + msgpack_pack_raw(&ctx->pckr, 11); + msgpack_pack_raw_body(&ctx->pckr, "temperature", 11); + msgpack_pack_double(&ctx->pckr, temp); + msgpack_pack_raw(&ctx->pckr, 8); + msgpack_pack_raw_body(&ctx->pckr, "humidity", 8); + msgpack_pack_double(&ctx->pckr, humidity); + + flb_debug("[in_am2320] temperature %f humidity %f (buffer=%i)", + temp, humidity, ctx->idx); + ctx->idx++; + + return 1; +error: + /* close I2C device */ + close(fd); + + return 0; +} diff --git a/plugins/in_am2320/am2320.h b/plugins/in_am2320/am2320.h new file mode 100644 index 00000000000..fdead64659c --- /dev/null +++ b/plugins/in_am2320/am2320.h @@ -0,0 +1,18 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* + * am2320: AM2320/2321 I2C Sensor Driver + * Copyright (C) 2015 Takeshi HASEGAWA + * + * This file is modified version of: + * https://github.com/takagi/am2321 + * + * Licensed under the LGPL License. + */ + +/* I2C character device */ +#define IN_AM2320_I2C_DEVICE "/dev/i2c-1" +#define IN_AM2320_I2C_ADDRESS (0xB8 >> 1) + +/* I2C device access */ +int in_am2320_read(struct flb_config *config, void *in_context); diff --git a/plugins/in_am2320/in_am2320.c b/plugins/in_am2320/in_am2320.c new file mode 100644 index 00000000000..e946c003ea8 --- /dev/null +++ b/plugins/in_am2320/in_am2320.c @@ -0,0 +1,108 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* + * in_am2320: AM2320/2321 I2C Sensor device input + * Copyright (C) 2015 Takeshi HASEGAWA + * + * Fluent Bit + * ========== + * Copyright (C) 2015 Treasure Data Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include "in_am2320.h" +#include "am2320.h" + +int in_am2320_collect(struct flb_config *config, void *in_context); + +int in_am2320_init(struct flb_config *config) +{ + int ret; + struct flb_in_am2320_config *ctx; + + ctx = malloc(sizeof(struct flb_in_am2320_config)); + if (!ctx) { + return -1; + } + ctx->idx = 0; + msgpack_sbuffer_init(&ctx->sbuf); + msgpack_packer_init(&ctx->pckr, &ctx->sbuf, msgpack_sbuffer_write); + ret = flb_input_set_context("am2320", ctx, config); + if (ret == -1) { + flb_utils_error_c("[in_am2320] Could not set configuration for memory input plugin"); + } + ret = flb_input_set_collector_time("am2320", + in_am2320_collect, + IN_AM2320_COLLECT_SEC, + IN_AM2320_COLLECT_NSEC, + config); + if (ret == -1) { + flb_utils_error_c("Could not set collector for memory input plugin"); + } + return 0; +} + +int in_am2320_pre_run(void *in_context, struct flb_config *config) +{ + struct flb_in_am2320_config *ctx = in_context; + + ctx->tag_len = snprintf(ctx->tag, sizeof(ctx->tag), "%s.am2320", config->tag); + if (ctx->tag_len == -1) { + flb_utils_error_c("Could not set custom tag on memory input plugin"); + } + return 0; +} + +int in_am2320_collect(struct flb_config *config, void *in_context) +{ + return in_am2320_read(config, in_context); +} + +void *in_am2320_flush(void *in_context, int *size) +{ + char *buf; + struct flb_in_am2320_config *ctx = in_context; + + if (ctx->idx == 0) + return NULL; + + buf = malloc(ctx->sbuf.size); + if (!buf) + return NULL; + + memcpy(buf, ctx->sbuf.data, ctx->sbuf.size); + *size = ctx->sbuf.size; + msgpack_sbuffer_destroy(&ctx->sbuf); + msgpack_sbuffer_init(&ctx->sbuf); + msgpack_packer_init(&ctx->pckr, &ctx->sbuf, msgpack_sbuffer_write); + ctx->idx = 0; + return buf; +} + +struct flb_input_plugin in_am2320_plugin = { + .name = "am2320", + .description = "AM2320/AM2321 Sensor", + .cb_init = in_am2320_init, + .cb_pre_run = in_am2320_pre_run, + .cb_collect = in_am2320_collect, + .cb_flush_buf = in_am2320_flush +}; diff --git a/plugins/in_am2320/in_am2320.h b/plugins/in_am2320/in_am2320.h new file mode 100644 index 00000000000..3fe861778db --- /dev/null +++ b/plugins/in_am2320/in_am2320.h @@ -0,0 +1,41 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015 Treasure Data Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLB_IN_AM2320_H +#define FLB_IN_AM2320_H + +#include +#include +#include +#include + +#define IN_AM2320_COLLECT_SEC 60 +#define IN_AM2320_COLLECT_NSEC 0 + +struct flb_in_am2320_config { + int tag_len; + char tag[32]; + int idx; + msgpack_packer pckr; + msgpack_sbuffer sbuf; +}; + +extern struct flb_input_plugin in_am2320_plugin; + +#endif