initial commit

This commit is contained in:
Syping 2021-04-23 12:41:16 +02:00
commit 85196faccd
14 changed files with 1095 additions and 0 deletions

48
CMakeLists.txt Normal file
View File

@ -0,0 +1,48 @@
cmake_minimum_required(VERSION 3.7)
project(dhtserver LANGUAGES C CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Network REQUIRED)
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(DHT_SOURCES
src/dht/linux/common_dht_read.c
src/dht/linux/common_dht_read.h
src/dht/linux/libdht.c
src/dht/linux/libdht.h
src/dht/linux/pi_2_dht_read.c
src/dht/linux/pi_2_dht_read.h
src/dht/linux/pi_2_mmio.c
src/dht/linux/pi_2_mmio.h
)
list(APPEND DHT_INCLUDEDIR
src/dht/linux
)
elseif(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
set(DHT_SOURCES
src/dht/freebsd/gpio.c
src/dht/freebsd/libdht.c
src/dht/freebsd/libdht.h
src/dht/freebsd/libgpio.h
)
list(APPEND DHT_INCLUDEDIR
src/dht/freebsd
)
endif()
add_executable(dhtserver
src/main.cpp
${DHT_SOURCES}
)
target_include_directories(dhtserver PRIVATE ${DHT_INCLUDEDIR})
target_link_libraries(dhtserver Qt${QT_VERSION_MAJOR}::Network)

260
src/dht/freebsd/gpio.c Normal file
View File

@ -0,0 +1,260 @@
/*-
* Copyright (c) 2013-2014 Rui Paulo <rpaulo@felyko.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <libgpio.h>
gpio_handle_t
gpio_open(unsigned int unit)
{
char device[16];
snprintf(device, sizeof(device), "/dev/gpioc%u", unit);
return (gpio_open_device(device));
}
gpio_handle_t
gpio_open_device(const char *device)
{
int fd, maxpins;
int serr;
fd = open(device, O_RDONLY);
if (fd < 0)
return (GPIO_INVALID_HANDLE);
/*
* Check whether a simple ioctl works.
*/
if (ioctl(fd, GPIOMAXPIN, &maxpins) < 0) {
serr = errno;
close(fd);
errno = serr;
return (GPIO_INVALID_HANDLE);
}
return (fd);
}
void
gpio_close(gpio_handle_t handle)
{
close(handle);
}
int
gpio_pin_list(gpio_handle_t handle, gpio_config_t **pcfgs)
{
int maxpins, i;
gpio_config_t *cfgs;
*pcfgs = NULL;
if (ioctl(handle, GPIOMAXPIN, &maxpins) < 0)
return (-1);
/* Reasonable values. */
if (maxpins < 0 || maxpins > 4096) {
errno = EINVAL;
return (-1);
}
cfgs = calloc(maxpins, sizeof(*cfgs));
if (cfgs == NULL)
return (-1);
for (i = 0; i <= maxpins; i++) {
cfgs[i].g_pin = i;
gpio_pin_config(handle, &cfgs[i]);
}
*pcfgs = cfgs;
return (maxpins);
}
int
gpio_pin_config(gpio_handle_t handle, gpio_config_t *cfg)
{
struct gpio_pin gppin;
if (cfg == NULL)
return (-1);
gppin.gp_pin = cfg->g_pin;
if (ioctl(handle, GPIOGETCONFIG, &gppin) < 0)
return (-1);
strlcpy(cfg->g_name, gppin.gp_name, GPIOMAXNAME);
cfg->g_caps = gppin.gp_caps;
cfg->g_flags = gppin.gp_flags;
return (0);
}
int
gpio_pin_set_flags(gpio_handle_t handle, gpio_config_t *cfg)
{
struct gpio_pin gppin;
if (cfg == NULL)
return (-1);
gppin.gp_pin = cfg->g_pin;
gppin.gp_flags = cfg->g_flags;
if (ioctl(handle, GPIOSETCONFIG, &gppin) < 0)
return (-1);
return (0);
}
gpio_value_t
gpio_pin_get(gpio_handle_t handle, gpio_pin_t pin)
{
struct gpio_req gpreq;
bzero(&gpreq, sizeof(gpreq));
gpreq.gp_pin = pin;
if (ioctl(handle, GPIOGET, &gpreq) < 0)
return (GPIO_VALUE_INVALID);
return (gpreq.gp_value);
}
int
gpio_pin_set(gpio_handle_t handle, gpio_pin_t pin, gpio_value_t value)
{
struct gpio_req gpreq;
if (value == GPIO_VALUE_INVALID)
return (-1);
bzero(&gpreq, sizeof(gpreq));
gpreq.gp_pin = pin;
gpreq.gp_value = value;
if (ioctl(handle, GPIOSET, &gpreq) < 0)
return (-1);
return (0);
}
int
gpio_pin_toggle(gpio_handle_t handle, gpio_pin_t pin)
{
gpio_value_t value;
value = gpio_pin_get(handle, pin);
if (value == GPIO_VALUE_INVALID)
return (-1);
value = !value;
return (gpio_pin_set(handle, pin, value));
}
int
gpio_pin_low(gpio_handle_t handle, gpio_pin_t pin)
{
return (gpio_pin_set(handle, pin, GPIO_VALUE_LOW));
}
int
gpio_pin_high(gpio_handle_t handle, gpio_pin_t pin)
{
return (gpio_pin_set(handle, pin, GPIO_VALUE_HIGH));
}
static int
gpio_pin_set_flag(gpio_handle_t handle, gpio_pin_t pin, uint32_t flag)
{
gpio_config_t cfg;
bzero(&cfg, sizeof(cfg));
cfg.g_pin = pin;
if (gpio_pin_config(handle, &cfg) < 0)
return (-1);
cfg.g_flags = flag;
return (gpio_pin_set_flags(handle, &cfg));
}
int
gpio_pin_input(gpio_handle_t handle, gpio_pin_t pin)
{
return (gpio_pin_set_flag(handle, pin, GPIO_PIN_INPUT));
}
int
gpio_pin_output(gpio_handle_t handle, gpio_pin_t pin)
{
return (gpio_pin_set_flag(handle, pin, GPIO_PIN_OUTPUT));
}
int
gpio_pin_opendrain(gpio_handle_t handle, gpio_pin_t pin)
{
return (gpio_pin_set_flag(handle, pin, GPIO_PIN_OPENDRAIN));
}
int
gpio_pin_pushpull(gpio_handle_t handle, gpio_pin_t pin)
{
return (gpio_pin_set_flag(handle, pin, GPIO_PIN_PUSHPULL));
}
int
gpio_pin_tristate(gpio_handle_t handle, gpio_pin_t pin)
{
return (gpio_pin_set_flag(handle, pin, GPIO_PIN_TRISTATE));
}
int
gpio_pin_pullup(gpio_handle_t handle, gpio_pin_t pin)
{
return (gpio_pin_set_flag(handle, pin, GPIO_PIN_PULLUP));
}
int
gpio_pin_pulldown(gpio_handle_t handle, gpio_pin_t pin)
{
return (gpio_pin_set_flag(handle, pin, GPIO_PIN_PULLDOWN));
}
int
gpio_pin_invin(gpio_handle_t handle, gpio_pin_t pin)
{
return (gpio_pin_set_flag(handle, pin, GPIO_PIN_INVIN));
}
int
gpio_pin_invout(gpio_handle_t handle, gpio_pin_t pin)
{
return (gpio_pin_set_flag(handle, pin, GPIO_PIN_INVOUT));
}
int
gpio_pin_pulsate(gpio_handle_t handle, gpio_pin_t pin)
{
return (gpio_pin_set_flag(handle, pin, GPIO_PIN_PULSATE));
}

119
src/dht/freebsd/libdht.c Normal file
View File

@ -0,0 +1,119 @@
/*-
* Copyright (c) 2015 lex
* Copyright (c) 2020-2021 Syping
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "libdht.h"
#include "libgpio.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define DHT_PULSES 40
#define DHT_MAXCOUNT 32000
int getdhtstring(int PIN, char* string)
{
// these values seem to work best
int firstSleep = 5000;
int secondSleep = 200;
uint8_t rawData[DHT_PULSES] = {0};
uint8_t values[4] = {0};
gpio_handle_t handle = gpio_open(0);
// wake up the sensor
gpio_pin_output(handle, PIN);
gpio_pin_low(handle, PIN);
usleep(firstSleep);
gpio_pin_high(handle, PIN);
usleep(secondSleep);
// begin to receive data
gpio_pin_input(handle, PIN);
for (volatile int i = 0; i < 50; ++i) {
}
uint total = 0;
for (int i = 0; i < DHT_MAXCOUNT; ++i) {
int c = 0;
while (gpio_pin_get(handle, PIN) != 1) {
}
while (gpio_pin_get(handle, PIN) != 0 && c < 256) {
// transmitting, 26-28 us = 0, 70 us = 1
// results should be something like 3-4 c for 0, 12-14 for 1
c++;
}
if (c == 256) {
// reading probably failed
break;
}
total++;
rawData[i] = c;
if (total == DHT_PULSES) {
// got all we need
break;
}
}
if (total != DHT_PULSES) {
gpio_close(handle);
return 1;
}
for (int i = 0; i < 4; ++i) {
uint8_t value = 0;
for (int j = 0; j < 8; ++j) {
uint8_t measuredLength = rawData[i * 8 + j];
// hax
if (measuredLength > 9)
value |= 0x01;
if (j != 7)
value <<= 1;
}
values[i] = value;
}
float humid = (values[0] * 256 + values[1]) / 10.0f;
float temp = ((values[2] & 0x7F) * 256 + values[3]) / 10.0f;
if (values[2] & 0x80) {
temp *= -1.0f;
}
sprintf(string, "{\"humidity\": %.1f, \"temp\": %.1f}\n", humid, temp);
gpio_close(handle);
return 0;
}

38
src/dht/freebsd/libdht.h Normal file
View File

@ -0,0 +1,38 @@
/*-
* Copyright (c) 2021 Syping
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _LIBDHT_H_
#define _LIBDHT_H_
#include <stdint.h>
__BEGIN_DECLS
int getdhtstring(int PIN, char* string);
__END_DECLS
#endif /* _LIBDHT_H_ */

105
src/dht/freebsd/libgpio.h Normal file
View File

@ -0,0 +1,105 @@
/*-
* Copyright (c) 2013-2014 Rui Paulo <rpaulo@felyko.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _LIBGPIO_H_
#define _LIBGPIO_H_
#include <sys/gpio.h>
#include <stdint.h>
__BEGIN_DECLS
#define GPIO_INVALID_HANDLE -1
typedef int gpio_handle_t;
typedef uint32_t gpio_pin_t;
/*
* Structure describing a GPIO pin configuration.
*/
typedef struct {
gpio_pin_t g_pin;
char g_name[GPIOMAXNAME];
uint32_t g_caps;
uint32_t g_flags;
} gpio_config_t;
typedef enum {
GPIO_VALUE_INVALID = -1,
GPIO_VALUE_LOW = GPIO_PIN_LOW,
GPIO_VALUE_HIGH = GPIO_PIN_HIGH
} gpio_value_t;
/*
* Open /dev/gpiocN or a specific device.
*/
gpio_handle_t gpio_open(unsigned int);
gpio_handle_t gpio_open_device(const char *);
void gpio_close(gpio_handle_t);
/*
* Get a list of all the GPIO pins.
*/
int gpio_pin_list(gpio_handle_t, gpio_config_t **);
/*
* GPIO pin configuration.
*
* Retrieve the configuration of a specific GPIO pin. The pin number is
* passed through the gpio_config_t structure.
*/
int gpio_pin_config(gpio_handle_t, gpio_config_t *);
/*
* Sets the GPIO flags on a specific GPIO pin. The pin number and the flags
* to be set are passed through the gpio_config_t structure.
*/
int gpio_pin_set_flags(gpio_handle_t, gpio_config_t *);
/*
* GPIO pin values.
*/
int gpio_pin_get(gpio_handle_t, gpio_pin_t);
int gpio_pin_set(gpio_handle_t, gpio_pin_t, int);
int gpio_pin_toggle(gpio_handle_t, gpio_pin_t);
/*
* Helper functions to set pin states.
*/
int gpio_pin_low(gpio_handle_t, gpio_pin_t);
int gpio_pin_high(gpio_handle_t, gpio_pin_t);
/*
* Helper functions to configure pins.
*/
int gpio_pin_input(gpio_handle_t, gpio_pin_t);
int gpio_pin_output(gpio_handle_t, gpio_pin_t);
int gpio_pin_opendrain(gpio_handle_t, gpio_pin_t);
int gpio_pin_pushpull(gpio_handle_t, gpio_pin_t);
int gpio_pin_tristate(gpio_handle_t, gpio_pin_t);
int gpio_pin_pullup(gpio_handle_t, gpio_pin_t);
int gpio_pin_pulldown(gpio_handle_t, gpio_pin_t);
int gpio_pin_invin(gpio_handle_t, gpio_pin_t);
int gpio_pin_invout(gpio_handle_t, gpio_pin_t);
int gpio_pin_pulsate(gpio_handle_t, gpio_pin_t);
__END_DECLS
#endif /* _LIBGPIO_H_ */

View File

@ -0,0 +1,66 @@
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <errno.h>
#include <sched.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include "common_dht_read.h"
void busy_wait_milliseconds(uint32_t millis) {
// Set delay time period.
struct timeval deltatime;
deltatime.tv_sec = millis / 1000;
deltatime.tv_usec = (millis % 1000) * 1000;
struct timeval walltime;
// Get current time and add delay to find end time.
gettimeofday(&walltime, NULL);
struct timeval endtime;
timeradd(&walltime, &deltatime, &endtime);
// Tight loop to waste time (and CPU) until enough time as elapsed.
while (timercmp(&walltime, &endtime, <)) {
gettimeofday(&walltime, NULL);
}
}
void sleep_milliseconds(uint32_t millis) {
struct timespec sleep;
sleep.tv_sec = millis / 1000;
sleep.tv_nsec = (millis % 1000) * 1000000L;
while (clock_nanosleep(CLOCK_MONOTONIC, 0, &sleep, &sleep) && errno == EINTR);
}
void set_max_priority(void) {
struct sched_param sched;
memset(&sched, 0, sizeof(sched));
// Use FIFO scheduler with highest priority for the lowest chance of the kernel context switching.
sched.sched_priority = sched_get_priority_max(SCHED_FIFO);
sched_setscheduler(0, SCHED_FIFO, &sched);
}
void set_default_priority(void) {
struct sched_param sched;
memset(&sched, 0, sizeof(sched));
// Go back to default scheduler with default 0 priority.
sched.sched_priority = 0;
sched_setscheduler(0, SCHED_OTHER, &sched);
}

View File

@ -0,0 +1,51 @@
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef COMMON_DHT_READ_H
#define COMMON_DHT_READ_H
#include <stdint.h>
// Define errors and return values.
#define DHT_ERROR_TIMEOUT -1
#define DHT_ERROR_CHECKSUM -2
#define DHT_ERROR_ARGUMENT -3
#define DHT_ERROR_GPIO -4
#define DHT_SUCCESS 0
// Define sensor types.
#define DHT11 11
#define DHT22 22
#define AM2302 22
// Busy wait delay for most accurate timing, but high CPU usage.
// Only use this for short periods of time (a few hundred milliseconds at most)!
void busy_wait_milliseconds(uint32_t millis);
// General delay that sleeps so CPU usage is low, but accuracy is potentially bad.
void sleep_milliseconds(uint32_t millis);
// Increase scheduling priority and algorithm to try to get 'real time' results.
void set_max_priority(void);
// Drop scheduling priority back to normal/default.
void set_default_priority(void);
#endif

17
src/dht/linux/libdht.c Normal file
View File

@ -0,0 +1,17 @@
#include "libdht.h"
#include <stdio.h>
#include <unistd.h>
#include <pi_2_dht_read.h>
int getdhtstring(int PIN, char* string)
{
float humid;
float temp;
while (1) {
if (pi_2_dht_read(PIN, PIN, &humid, &temp) == DHT_SUCCESS) {
sprintf(string, "{\"humidity\": %.1f, \"temp\": %.1f}", humid, temp);
break;
}
}
return 0;
}

12
src/dht/linux/libdht.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef _LIBDHT_H_
#define _LIBDHT_H_
#include <stdint.h>
__BEGIN_DECLS
int getdhtstring(int PIN, char* string);
__END_DECLS
#endif /* _LIBDHT_H_ */

View File

@ -0,0 +1,158 @@
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <stdbool.h>
#include <stdlib.h>
#include "pi_2_dht_read.h"
#include "pi_2_mmio.h"
// This is the only processor specific magic value, the maximum amount of time to
// spin in a loop before bailing out and considering the read a timeout. This should
// be a high value, but if you're running on a much faster platform than a Raspberry
// Pi or Beaglebone Black then it might need to be increased.
#define DHT_MAXCOUNT 32000
// Number of bit pulses to expect from the DHT. Note that this is 41 because
// the first pulse is a constant 50 microsecond pulse, with 40 pulses to represent
// the data afterwards.
#define DHT_PULSES 41
int pi_2_dht_read(int type, int pin, float* humidity, float* temperature) {
// Validate humidity and temperature arguments and set them to zero.
if (humidity == NULL || temperature == NULL) {
return DHT_ERROR_ARGUMENT;
}
*temperature = 0.0f;
*humidity = 0.0f;
// Initialize GPIO library.
if (pi_2_mmio_init() < 0) {
return DHT_ERROR_GPIO;
}
// Store the count that each DHT bit pulse is low and high.
// Make sure array is initialized to start at zero.
int pulseCounts[DHT_PULSES*2] = {0};
// Set pin to output.
pi_2_mmio_set_output(pin);
// Bump up process priority and change scheduler to try to try to make process more 'real time'.
set_max_priority();
// Set pin high for ~500 milliseconds.
pi_2_mmio_set_high(pin);
sleep_milliseconds(500);
// The next calls are timing critical and care should be taken
// to ensure no unnecssary work is done below.
// Set pin low for ~20 milliseconds.
pi_2_mmio_set_low(pin);
busy_wait_milliseconds(20);
// Set pin at input.
pi_2_mmio_set_input(pin);
// Need a very short delay before reading pins or else value is sometimes still low.
for (volatile int i = 0; i < 50; ++i) {
}
// Wait for DHT to pull pin low.
uint32_t count = 0;
while (pi_2_mmio_input(pin)) {
if (++count >= DHT_MAXCOUNT) {
// Timeout waiting for response.
set_default_priority();
return DHT_ERROR_TIMEOUT;
}
}
// Record pulse widths for the expected result bits.
for (int i=0; i < DHT_PULSES*2; i+=2) {
// Count how long pin is low and store in pulseCounts[i]
while (!pi_2_mmio_input(pin)) {
if (++pulseCounts[i] >= DHT_MAXCOUNT) {
// Timeout waiting for response.
set_default_priority();
return DHT_ERROR_TIMEOUT;
}
}
// Count how long pin is high and store in pulseCounts[i+1]
while (pi_2_mmio_input(pin)) {
if (++pulseCounts[i+1] >= DHT_MAXCOUNT) {
// Timeout waiting for response.
set_default_priority();
return DHT_ERROR_TIMEOUT;
}
}
}
// Done with timing critical code, now interpret the results.
// Drop back to normal priority.
set_default_priority();
// Compute the average low pulse width to use as a 50 microsecond reference threshold.
// Ignore the first two readings because they are a constant 80 microsecond pulse.
uint32_t threshold = 0;
for (int i=2; i < DHT_PULSES*2; i+=2) {
threshold += pulseCounts[i];
}
threshold /= DHT_PULSES-1;
// Interpret each high pulse as a 0 or 1 by comparing it to the 50us reference.
// If the count is less than 50us it must be a ~28us 0 pulse, and if it's higher
// then it must be a ~70us 1 pulse.
uint8_t data[5] = {0};
for (int i=3; i < DHT_PULSES*2; i+=2) {
int index = (i-3)/16;
data[index] <<= 1;
if (pulseCounts[i] >= threshold) {
// One bit for long pulse.
data[index] |= 1;
}
// Else zero bit for short pulse.
}
// Useful debug info:
//printf("Data: 0x%x 0x%x 0x%x 0x%x 0x%x\n", data[0], data[1], data[2], data[3], data[4]);
// Verify checksum of received data.
if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) {
if (type == DHT11) {
// Get humidity and temp for DHT11 sensor.
*humidity = (float)data[0];
*temperature = (float)data[2];
}
else if (type == DHT22) {
// Calculate humidity and temp for DHT22 sensor.
*humidity = (data[0] * 256 + data[1]) / 10.0f;
*temperature = ((data[2] & 0x7F) * 256 + data[3]) / 10.0f;
if (data[2] & 0x80) {
*temperature *= -1.0f;
}
}
return DHT_SUCCESS;
}
else {
return DHT_ERROR_CHECKSUM;
}
}

View File

@ -0,0 +1,32 @@
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef PI_2_DHT_READ_H
#define PI_2_DHT_READ_H
#include "common_dht_read.h"
// Read DHT sensor connected to GPIO pin (using BCM numbering). Humidity and temperature will be
// returned in the provided parameters. If a successfull reading could be made a value of 0
// (DHT_SUCCESS) will be returned. If there was an error reading the sensor a negative value will
// be returned. Some errors can be ignored and retried, specifically DHT_ERROR_TIMEOUT or DHT_ERROR_CHECKSUM.
int pi_2_dht_read(int sensor, int pin, float* humidity, float* temperature);
#endif

71
src/dht/linux/pi_2_mmio.c Normal file
View File

@ -0,0 +1,71 @@
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// Based on code from Gert van Loo & Dom: http://elinux.org/RPi_Low-level_peripherals#GPIO_Code_examples
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "pi_2_mmio.h"
#define GPIO_BASE_OFFSET 0x200000
#define GPIO_LENGTH 4096
volatile uint32_t* pi_2_mmio_gpio = NULL;
int pi_2_mmio_init(void) {
if (pi_2_mmio_gpio == NULL) {
// Check for GPIO and peripheral addresses from device tree.
// Adapted from code in the RPi.GPIO library at:
// http://sourceforge.net/p/raspberry-gpio-python/
FILE *fp = fopen("/proc/device-tree/soc/ranges", "rb");
if (fp == NULL) {
return MMIO_ERROR_OFFSET;
}
fseek(fp, 4, SEEK_SET);
unsigned char buf[4];
if (fread(buf, 1, sizeof(buf), fp) != sizeof(buf)) {
return MMIO_ERROR_OFFSET;
}
uint32_t peri_base = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0;
uint32_t gpio_base = peri_base + GPIO_BASE_OFFSET;
fclose(fp);
int fd = open("/dev/gpiomem", O_RDWR | O_SYNC);
if (fd == -1) {
// Error opening /dev/gpiomem.
return MMIO_ERROR_DEVMEM;
}
// Map GPIO memory to location in process space.
pi_2_mmio_gpio = (uint32_t*)mmap(NULL, GPIO_LENGTH, PROT_READ | PROT_WRITE, MAP_SHARED, fd, gpio_base);
close(fd);
if (pi_2_mmio_gpio == MAP_FAILED) {
// Don't save the result if the memory mapping failed.
pi_2_mmio_gpio = NULL;
return MMIO_ERROR_MMAP;
}
}
return MMIO_SUCCESS;
}

62
src/dht/linux/pi_2_mmio.h Normal file
View File

@ -0,0 +1,62 @@
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// Based on code from Gert van Loo & Dom: http://elinux.org/RPi_Low-level_peripherals#GPIO_Code_examples
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// Simple fast memory-mapped GPIO library for the Raspberry Pi.
#ifndef PI_2_MMIO_H
#define PI_2_MMIO_H
#include <stdint.h>
#define MMIO_SUCCESS 0
#define MMIO_ERROR_DEVMEM -1
#define MMIO_ERROR_MMAP -2
#define MMIO_ERROR_OFFSET -3
extern volatile uint32_t* pi_2_mmio_gpio;
int pi_2_mmio_init(void);
static inline void pi_2_mmio_set_input(const int gpio_number) {
// Set GPIO register to 000 for specified GPIO number.
*(pi_2_mmio_gpio+((gpio_number)/10)) &= ~(7<<(((gpio_number)%10)*3));
}
static inline void pi_2_mmio_set_output(const int gpio_number) {
// First set to 000 using input function.
pi_2_mmio_set_input(gpio_number);
// Next set bit 0 to 1 to set output.
*(pi_2_mmio_gpio+((gpio_number)/10)) |= (1<<(((gpio_number)%10)*3));
}
static inline void pi_2_mmio_set_high(const int gpio_number) {
*(pi_2_mmio_gpio+7) = 1 << gpio_number;
}
static inline void pi_2_mmio_set_low(const int gpio_number) {
*(pi_2_mmio_gpio+10) = 1 << gpio_number;
}
static inline uint32_t pi_2_mmio_input(const int gpio_number) {
return *(pi_2_mmio_gpio+13) & (1 << gpio_number);
}
#endif

56
src/main.cpp Normal file
View File

@ -0,0 +1,56 @@
#include <QCoreApplication>
#include <QLocalServer>
#include <QLocalSocket>
#include <QTextStream>
#include <QObject>
#include <QTimer>
extern "C" {
#include "libdht.h"
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
const QStringList args = a.arguments();
int PIN = 22; // PIN 22 is default for dhtserver
if (args.length() == 2) {
bool ok;
const int aPIN = args.at(1).toInt(&ok);
if (ok) {
PIN = aPIN;
}
}
QByteArray dhtJson;
QLocalServer localServer;
localServer.setSocketOptions(QLocalServer::WorldAccessOption);
bool isListen = localServer.listen("/var/run/dhtserver/dhtserver.sock");
if (!isListen) {
QTextStream(stderr) << "dhtserver: Unix socket can't listen!" << Qt::endl;
return -1;
}
QObject::connect(&localServer, &QLocalServer::newConnection, [&]() {
QLocalSocket *localSocket = localServer.nextPendingConnection();
if (localSocket) {
QObject::connect(localSocket, &QLocalSocket::disconnected, localSocket, &QLocalSocket::deleteLater);
localSocket->write(dhtJson);
localSocket->flush();
localSocket->disconnectFromServer();
}
});
QTimer timer;
QObject::connect(&timer, &QTimer::timeout, [&]() {
char *dhtstring = static_cast<char*>(malloc(512));
int result = getdhtstring(PIN, dhtstring);
if (result == 0) {
dhtJson = QByteArray(dhtstring).trimmed();
}
free(dhtstring);
});
timer.start(1000);
QTextStream(stderr) << "dhtserver: Server started successfully!" << Qt::endl;
return a.exec();
}