Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * sim_dht22.c
- *
- * Copyright 2013 Michel Pollet <buserror@gmail.com>
- *
- * This file is part of simavr.
- *
- * simavr is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * simavr is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with simavr. If not, see <http://www.gnu.org/licenses/>.
- */
- /*
- * Simulates a DHT22/AM2302 humidity and temperature sensor, using one input IRQ
- * to detect the input start pulse, then sends 40 bits of data on the output
- */
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <unistd.h>
- #include "sim_avr.h"
- #include "sim_time.h"
- #include "sim_cycle_timers.h"
- #include "sim_dht22.h"
- /*
- * These are generic preprocessor tricks. Allows concatenating names together.
- * You need the two of them, you really do.
- */
- #define _CONCAT2(p1, p2) p1##p2
- #define _CONCAT(p1, p2) _CONCAT2(p1,p2)
- /* protothread trick macros */
- #define _RESUME(_enc) if ((_enc).wstate) goto *(_enc).wstate;
- #define _WAIT(_enc) \
- { (_enc).wstate = &&_CONCAT(wait,__LINE__); goto _exit; _CONCAT(wait,__LINE__): ; }
- #define _EXIT(_enc) { (_enc).wstate = NULL; goto _exit; }
- static avr_cycle_count_t
- _dht_timer_callback(
- struct avr_t * avr,
- avr_cycle_count_t when,
- void * param)
- {
- dht22_p d = (dht22_p)param;
- avr_cycle_count_t res = 0;
- _RESUME(d->timer_state);
- // printf("%s starting sequence\r\n", __func__);
- // first, pull the line low for 80us
- avr_raise_irq(d->irq + IRQ_DHT_OUT, 0);
- res = avr_usec_to_cycles(d->avr, 80);
- _WAIT(d->timer_state);
- // then pull it high for 80us + 50 us as preamble 'bit'
- avr_raise_irq(d->irq + IRQ_DHT_OUT, 1);
- res = avr_usec_to_cycles(d->avr, 80);
- _WAIT(d->timer_state);
- avr_raise_irq(d->irq + IRQ_DHT_OUT, 0);
- res = avr_usec_to_cycles(d->avr, 50);
- _WAIT(d->timer_state);
- d->packet =
- ((int)d->hum << 16) |
- abs(d->temp) |
- (d->temp < 0 ? (1 << 15) : 0);
- uint8_t chk = 0;
- for (int i = 0; i < 4; i++)
- chk += (d->packet >> (i * 8));
- d->packet = (d->packet << 8) | chk;
- printf("dh22 packet is %010llx\r\n", (unsigned long long)d->packet);
- /*
- * Now send the data proper, using th 27us for a zero, and 70us for a 1,
- * then a 50us 'zero' suffix
- */
- for (d->bitpos = 0; d->bitpos < 40; d->bitpos++) {
- avr_raise_irq(d->irq + IRQ_DHT_OUT, 1);
- res = avr_usec_to_cycles(d->avr,
- (d->packet >> (39 - d->bitpos)) & 1 ? 70 : 27);
- avr_raise_irq(d->irq + IRQ_DHT_ACTIVE, 39-d->bitpos);
- _WAIT(d->timer_state);
- avr_raise_irq(d->irq + IRQ_DHT_OUT, 0);
- res = avr_usec_to_cycles(d->avr, 50);
- _WAIT(d->timer_state);
- }
- res = 0;
- d->driving = 0;
- avr_raise_irq(d->irq + IRQ_DHT_OUT, 1);
- _EXIT(d->timer_state);
- _exit:
- return res ? when + res : 0;
- }
- static void
- dht_input_irq(
- struct avr_irq_t * irq,
- uint32_t value,
- void * param)
- {
- dht22_p d = (dht22_p)param;
- _RESUME(d->input_state);
- avr_raise_irq(d->irq + IRQ_DHT_ACTIVE, 0);
- if (value == 1)
- _EXIT(d->input_state);
- d->stamp = d->avr->cycle;
- _WAIT(d->input_state);
- while (value == 0)
- _WAIT(d->input_state);
- d->stamp = d->avr->cycle - d->stamp;
- // printf("%s low pulse start is %d usec\r\n", __func__,
- // avr_cycles_to_usec(d->avr, d->stamp));
- if (d->stamp < 500) {
- printf("%s start low pulse too short (%d), ignoring\r\n", __func__,
- avr_cycles_to_usec(d->avr, d->stamp));
- _EXIT(d->input_state);
- }
- // printf("%s start low pulse GOOD, starting output\r\n", __func__);
- avr_raise_irq(d->irq + IRQ_DHT_ACTIVE, 1);
- // start sequence, wait 30us, lower output, wait 80us, raise it 80us etc
- // avr_raise_irq(d->irq + IRQ_DHT_OUT, 1);
- d->driving = 1;
- avr_cycle_timer_register_usec(
- d->avr,
- 30 /* us */,
- _dht_timer_callback,
- param);
- // ignore any input while we drive that 'pin'
- while (d->driving)
- _WAIT(d->input_state);
- // printf("%s finished!\r\n", __func__);
- avr_raise_irq(d->irq + IRQ_DHT_ACTIVE, 0);
- _EXIT(d->input_state);
- _exit:
- return;
- }
- static void
- dht_temp_input_irq(
- struct avr_irq_t * irq,
- uint32_t value,
- void * param)
- {
- dht22_p d = (dht22_p)param;
- d->temp = (int16_t)value;
- }
- static void
- dht_hum_input_irq(
- struct avr_irq_t * irq,
- uint32_t value,
- void * param)
- {
- dht22_p d = (dht22_p)param;
- d->hum = value;
- }
- static const char * irq_names[IRQ_DHT_COUNT] = {
- [IRQ_DHT_IN] = "<dht22.in",
- [IRQ_DHT_OUT] = ">dht22.out",
- [IRQ_DHT_TEMP_IN] = ">dht22.temp",
- [IRQ_DHT_HUM_IN] = ">dht22.hum",
- [IRQ_DHT_ACTIVE] = ">dht22.active",
- };
- void
- dht22_init(
- struct dht22_t * d,
- struct avr_t * avr )
- {
- memset(d, 0, sizeof(*d));
- d->avr = avr;
- d->irq = avr_alloc_irq(&avr->irq_pool, 0, IRQ_DHT_COUNT, irq_names);
- avr_irq_register_notify(d->irq + IRQ_DHT_IN, dht_input_irq, d);
- avr_irq_register_notify(d->irq + IRQ_DHT_TEMP_IN, dht_temp_input_irq, d);
- avr_irq_register_notify(d->irq + IRQ_DHT_HUM_IN, dht_hum_input_irq, d);
- d->irq[IRQ_DHT_OUT].flags |= IRQ_FLAG_FILTERED;
- d->hum = 567;
- d->temp = 234;
- }
- void
- dht22_connect(
- struct dht22_t * d,
- avr_irq_t * output_irq,
- avr_irq_t * input_irq,
- avr_irq_t * temp_in_irq,
- avr_irq_t * hum_in_irq )
- {
- avr_connect_irq(input_irq, d->irq + IRQ_DHT_IN);
- avr_connect_irq(d->irq + IRQ_DHT_OUT, output_irq);
- if (temp_in_irq)
- avr_connect_irq(temp_in_irq, d->irq + IRQ_DHT_TEMP_IN);
- if (hum_in_irq)
- avr_connect_irq(hum_in_irq, d->irq + IRQ_DHT_HUM_IN);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement