-
Notifications
You must be signed in to change notification settings - Fork 0
/
state_machine.c
92 lines (73 loc) · 2.08 KB
/
state_machine.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <linux/kernel.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/hrtimer.h>
#include <linux/string.h>
#include "dht22.h"
#include "state_machine.h"
static void startup_pulse(unsigned gpio);
static DECLARE_WAIT_QUEUE_HEAD(acquisition);
static void startup_pulse(unsigned gpio) {
gpio_direction_output(gpio,0);
usleep_range(500, 2000);
gpio_direction_input(gpio);
}
int read_dht22(struct device* dev) {
struct dht22_priv* priv;
int r;
priv = dev_get_drvdata(dev);
priv->lastIntTime = ktime_get();
priv->state = READY;
memset(priv->data,0,5);
priv->bitCount = 7;
priv->byteCount = 0;
startup_pulse(priv->gpio);
if(wait_event_interruptible_timeout(acquisition, priv->state==DONE, msecs_to_jiffies(100)) > 0)
r = 0;
else
r = -1;
return r;
}
irqreturn_t dht22_handler(int irq, void* dev_id) {
ktime_t currTime;
struct device* dev;
struct dht22_priv* priv;
s64 timeDiff;
int currBit;
currTime = ktime_get();
dev = (struct device*)dev_id;
priv = dev_get_drvdata(dev);
timeDiff = ktime_us_delta(currTime,priv->lastIntTime);
trace_printk("tD = %lld us, state = %d, byte.bit = %u.%u, data = %x:%x:%x:%x:%x\n", (long long)timeDiff, priv->state, priv->byteCount, priv->bitCount, priv->rh_int, priv->rh_dec, priv->t_int, priv->t_dec, priv->checksum);
switch(priv->state) {
case READY:
priv->state = START;
break;
case START:
priv->state = WARMUP;
break;
case WARMUP:
priv->state = DATA_READ;
break;
case DATA_READ:
currBit = (timeDiff < 100) ? 0 : 1;
priv->data[priv->byteCount] |= currBit << priv->bitCount;
priv->bitCount--;
if (priv->bitCount < 0) {
priv->byteCount++;
priv->bitCount = 7;
}
if (priv->byteCount > 4) {
priv->state = DONE;
wake_up(&acquisition);
}
if (timeDiff > 140)
currTime = ktime_sub_us(currTime, timeDiff-140);
break;
case DONE:
dev_err(dev, "Interrupt occured while state is DONE\n");
}
priv->lastIntTime = currTime;
return IRQ_HANDLED;
}