Android DHT 11駆動

8655 ワード

Android DHT 11駆動

struct dht11_sensor_dev{
	struct cdev cdev;
	unsigned long pin;
	unsigned char value[5];
	unsigned char lock;
	unsigned int irq;
	struct timeval lasttv;
	int bitcount;
	int bytecount;
	int started;
	struct timer_list timer;
	void (*write_bit)(unsigned long pin, char bit);
	void (*delay)(short t);
};

static struct dht11_sensor_dev *dht11_dev;
struct class *dht11_class;
static int major = DEVICE_MAJOR;

static inline void usdelay(short t)
{
	return ndelay(t * 1000);
}

static inline void gpio_write_bit(unsigned long pin, char bit)
{
	gpio_set_value(pin, bit);
}
#if 0
static char gpio_read_bit(unsigned long pin)
{
	return gpio_get_value(pin) ? 1 : 0;
	//return gpio_get_value(pin);
}
static void gpio_write_bit_dir(unsigned long pin, char bit)
{
	if (bit)
		gpio_direction_input(pin);
	else
		gpio_direction_output(pin, 0);
}

static void gpio_write_bit_val(unsigned long pin, char bit)
{
	gpio_set_value(pin, bit);
}

static int dht11_get_temperature(struct dht11_sensor_dev *dev)
{
	return dev->value[0] * 1000 + dev->value[1];
}

static int dht11_get_humidity(struct dht11_sensor_dev *dev)
{
	return dev->value[2] * 1000 + dev->value[3];
}
#endif

static irqreturn_t dht11_interrupt(int irq, void *dev_id)
{
	struct dht11_sensor_dev *dev = (struct dht11_sensor_dev *)dev_id;
	struct timeval tv;
	long deltv = 0;
	int signal = 0, data = 0;

	signal = gpio_get_value(dev->pin);

	do_gettimeofday(&tv);	

	deltv = tv.tv_sec - dev->lasttv.tv_sec;
	data = (int)(deltv * 1000000 + (tv.tv_usec - dev->lasttv.tv_usec)); 
	dev->lasttv = tv;

	if(dev->bytecount == 5) return IRQ_HANDLED;
	if((signal == 1) & (data > 40)){
		dev->started = 1;
		return IRQ_HANDLED;
	}
	if((signal == 0) & (dev->started == 1)){
			if(data > 80)
				return IRQ_HANDLED;
			if(data < 30){
				dev->bitcount++;
				if(dev->bitcount == 8){
					dev->bitcount = 0;
					dev->bytecount++;
				}
				return IRQ_HANDLED;
			}
			if (data > 60)//55 
				dev->value[dev->bytecount] = dev->value[dev->bytecount] | (0x80 >> dev->bitcount);
			
			dev->bitcount++;
			if(dev->bitcount == 8){
				dev->bitcount = 0;
				dev->bytecount++;
			}
	
	}

	return IRQ_HANDLED;
}


static int setup_interrupts(void)
{
	int result;

	dht11_dev->irq = gpio_to_irq(dht11_dev->pin);
	result = request_irq(dht11_dev->irq, dht11_interrupt, 
			IRQ_TYPE_EDGE_BOTH, DEVICE_NAME, (void *)dht11_dev);

	switch (result) {
		case -EBUSY:
			printk(KERN_ERR "*%s(): IRQ %d is busy
", __func__, dht11_dev->irq); return -EBUSY; case -EINVAL: printk(KERN_ERR "*%s(): Bad irq number or handler
", __func__); return -EINVAL; default: //printk(KERN_INFO "*%s():Interrupt %04x obtained
", __func__, dht11_dev->irq); break; } return 0; } static void clear_interrupts(void) { free_irq(dht11_dev->irq, (void *)dht11_dev); if(gpio_request(dht11_dev->pin, DEVICE_NAME)){ printk(KERN_INFO "[%s] gpio_request
", __func__); return; } s3c_gpio_cfgpin(dht11_dev->pin, S3C_GPIO_OUTPUT); s3c_gpio_setpull(dht11_dev->pin, S3C_GPIO_PULL_NONE); //s5p_gpio_set_drvstr(dht11_dev->pin, S5P_GPIO_DRVSTR_LV2); gpio_set_value(dht11_dev->pin, 1); gpio_free(dht11_dev->pin); } static int dht11_reset(struct dht11_sensor_dev *dev) { if(gpio_request(dht11_dev->pin, DEVICE_NAME)){ printk(KERN_INFO "[%s] gpio_request
", __func__); return -1; } //s3c_gpio_cfgpin(dht11_dev->pin, S3C_GPIO_OUTPUT); s3c_gpio_cfgpin(dht11_dev->pin, S3C_GPIO_OUTPUT); s3c_gpio_setpull(dht11_dev->pin, S3C_GPIO_PULL_NONE); //s5p_gpio_set_drvstr(dht11_dev->pin, S5P_GPIO_DRVSTR_LV2); gpio_set_value(dht11_dev->pin, 1); dev->write_bit(dev->pin, 0); msleep(18); dev->write_bit(dev->pin, 1); s3c_gpio_cfgpin(dev->pin, S3C_GPIO_INPUT); dev->delay(20); gpio_free(dht11_dev->pin); return 0; } static int dht11_checksum(struct dht11_sensor_dev *dev) { char tmp = 0; tmp = dev->value[0] + dev->value[1] + dev->value[2] + dev->value[3]; if(tmp != dev->value[4]){ //printk(KERN_INFO "[%s] %d %d
", __func__, dev->value[4], tmp); return 0; } return 1; } static int dht11_sensor_open(struct inode *inode, struct file *filp) { if(dht11_dev->lock) return -EBUSY; try_module_get(THIS_MODULE); dht11_dev->lock = 1; return 0; } static int dht11_sensor_release(struct inode *inode,struct file *filp) { module_put(THIS_MODULE); dht11_dev->lock = 0; return 0; } static ssize_t dht11_sensor_read( struct file *filp,char __user *buf,size_t size,loff_t *f_pos) { unsigned long length =(size>48)? 48:size; int result = 0; char msg[48]; dht11_dev->started = 0; dht11_dev->bitcount = 0; dht11_dev->bytecount = 0; dht11_dev->value[0] = 0; dht11_dev->value[1] = 0; dht11_dev->value[2] = 0; dht11_dev->value[3] = 0; dht11_dev->value[4] = 0; if(!dht11_reset(dht11_dev)){ do_gettimeofday(&dht11_dev->lasttv); setup_interrupts(); } else{ dprint("*%s(): reset fail
", __func__); return -1; } msleep(20); clear_interrupts(); //for(i = 0; i < 48; i++) dht11_dev->msg[i] = -1; sprintf(msg, "Humidity=%d.%d%%
Temperature=%d.%dC
Result=%d
%c",\ dht11_dev->value[0], dht11_dev->value[1], \ dht11_dev->value[2], dht11_dev->value[3], \ dht11_checksum(dht11_dev), '\0'); length = strlen(msg); dprint(KERN_INFO "*%s(): length %lu
", __func__, length); #if 0 while (length && *ptr) { put_user(*(ptr++), buf++); length--; result++; } put_user('\0', buf++); result++; *f_pos += result; return result; #else result=copy_to_user(buf, msg + *f_pos, length); //*f_pos += length; *f_pos = 0; //if(result) return length - result; //else result = length; return length; #endif } #if 0 static ssize_t dht11_sensor_write(struct file *filp,const char __user *buf,size_t size,loff_t *f_pos) { return 0; } #endif static struct file_operations dht11_sensor_fops={ .owner = THIS_MODULE, .read = dht11_sensor_read, .open = dht11_sensor_open, .release = dht11_sensor_release, }; static void dht11_sensor_setup_cdev( struct dht11_sensor_dev *dev,int minor,struct file_operations *fops) { int err, devno = MKDEV(major, minor); cdev_init(&(dev->cdev), fops); dev->cdev.owner = THIS_MODULE; dev->cdev.ops = fops; err=cdev_add(&(dev->cdev), devno, 1); if(err){ printk(KERN_NOTICE"erro %d adding %s %d
",err,DEVICE_NAME,minor); } } int __init dht11_sensor_init(void){ int result; dev_t devno=MKDEV(major,0); if(major){ result = register_chrdev_region(devno, 1, DEVICE_NAME); } else{ result = alloc_chrdev_region(&devno, 0, 1, DEVICE_NAME); } if(result < 0){ printk(KERN_WARNING"%s: unable to get major %d
",DEVICE_NAME,major); return result; } dht11_dev=kmalloc(sizeof(struct dht11_sensor_dev),GFP_KERNEL); if(!dht11_dev){ result=-ENOMEM; goto fail_malloc; } dht11_class = class_create(THIS_MODULE, DEVICE_NAME); device_create(dht11_class, NULL, MKDEV(DEVICE_MAJOR, 0), NULL, DEVICE_NAME); dht11_sensor_setup_cdev(dht11_dev, 0, &dht11_sensor_fops); dht11_dev->pin = GPIO_DOUT; dht11_dev->delay = usdelay; dht11_dev->write_bit = gpio_write_bit; result = gpio_request(dht11_dev->pin, DEVICE_NAME); if(result){ printk(KERN_INFO "[%s] gpio_request
", __func__); goto fail_gpio; } //s3c_gpio_cfgpin(dht11_dev->pin, S3C_GPIO_OUTPUT); s3c_gpio_cfgpin(dht11_dev->pin, S3C_GPIO_OUTPUT); s3c_gpio_setpull(dht11_dev->pin, S3C_GPIO_PULL_NONE); //s5p_gpio_set_drvstr(dht11_dev->pin, S5P_GPIO_DRVSTR_LV2); gpio_set_value(dht11_dev->pin, 1); //gpio_direction_output(dht11_dev->pin, 1); gpio_free(dht11_dev->pin); return 0; fail_gpio: kfree(dht11_dev); fail_malloc: unregister_chrdev_region(MKDEV(major,0),1); return result; } void __exit dht11_sensor_exit(void) { cdev_del(&dht11_dev->cdev); device_destroy(dht11_class, MKDEV(major, 0)); class_destroy(dht11_class); //gpio_free(dht11_dev->pin); kfree(dht11_dev); unregister_chrdev_region(MKDEV(major, 0), 1); //printk("%s device uninstalled OK!
", DEVICE_NAME); } module_init(dht11_sensor_init); module_exit(dht11_sensor_exit); MODULE_AUTHOR("jvaemape"); MODULE_DESCRIPTION("S3C GPIO MQ2 Drive"); MODULE_LICENSE("Dual BSD/GPL");