Advertisement
Guest User

goto

a guest
Nov 27th, 2014
161
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 5.76 KB | None | 0 0
  1. /*
  2.  * sim_dht22.c
  3.  *
  4.  * Copyright 2013 Michel Pollet <buserror@gmail.com>
  5.  *
  6.  *  This file is part of simavr.
  7.  *
  8.  *  simavr is free software: you can redistribute it and/or modify
  9.  *  it under the terms of the GNU General Public License as published by
  10.  *  the Free Software Foundation, either version 3 of the License, or
  11.  *  (at your option) any later version.
  12.  *
  13.  *  simavr is distributed in the hope that it will be useful,
  14.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  *  GNU General Public License for more details.
  17.  *
  18.  *  You should have received a copy of the GNU General Public License
  19.  *  along with simavr.  If not, see <http://www.gnu.org/licenses/>.
  20.  */
  21.  
  22. /*
  23.  * Simulates a DHT22/AM2302 humidity and temperature sensor, using one input IRQ
  24.  * to detect the input start pulse, then sends 40 bits of data on the output
  25.  */
  26. #include <stdlib.h>
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include <unistd.h>
  30. #include "sim_avr.h"
  31. #include "sim_time.h"
  32. #include "sim_cycle_timers.h"
  33. #include "sim_dht22.h"
  34.  
  35. /*
  36.  * These are generic preprocessor tricks. Allows concatenating names together.
  37.  * You need the two of them, you really do.
  38.  */
  39. #define _CONCAT2(p1, p2) p1##p2
  40. #define _CONCAT(p1, p2) _CONCAT2(p1,p2)
  41.  
  42. /* protothread trick macros */
  43. #define _RESUME(_enc) if ((_enc).wstate) goto *(_enc).wstate;
  44. #define _WAIT(_enc) \
  45.     { (_enc).wstate = &&_CONCAT(wait,__LINE__); goto _exit; _CONCAT(wait,__LINE__): ; }
  46. #define _EXIT(_enc) { (_enc).wstate = NULL; goto _exit; }
  47.  
  48. static avr_cycle_count_t
  49. _dht_timer_callback(
  50.         struct avr_t * avr,
  51.         avr_cycle_count_t when,
  52.         void * param)
  53. {
  54.     dht22_p d = (dht22_p)param;
  55.     avr_cycle_count_t res = 0;
  56.  
  57.     _RESUME(d->timer_state);
  58.  
  59. //  printf("%s starting sequence\r\n", __func__);
  60.     // first, pull the line low for 80us
  61.     avr_raise_irq(d->irq + IRQ_DHT_OUT, 0);
  62.     res = avr_usec_to_cycles(d->avr, 80);
  63.     _WAIT(d->timer_state);
  64.  
  65.     // then pull it high for 80us + 50 us as preamble 'bit'
  66.     avr_raise_irq(d->irq + IRQ_DHT_OUT, 1);
  67.     res = avr_usec_to_cycles(d->avr, 80);
  68.     _WAIT(d->timer_state);
  69.     avr_raise_irq(d->irq + IRQ_DHT_OUT, 0);
  70.     res = avr_usec_to_cycles(d->avr, 50);
  71.     _WAIT(d->timer_state);
  72.  
  73.     d->packet =
  74.             ((int)d->hum << 16) |
  75.             abs(d->temp) |
  76.             (d->temp < 0 ? (1 << 15) : 0);
  77.     uint8_t chk = 0;
  78.     for (int i = 0; i < 4; i++)
  79.         chk += (d->packet >> (i * 8));
  80.     d->packet = (d->packet << 8) | chk;
  81.  
  82.     printf("dh22 packet is %010llx\r\n", (unsigned long long)d->packet);
  83.     /*
  84.      * Now send the data proper, using th 27us for a zero, and 70us for a 1,
  85.      * then a 50us 'zero' suffix
  86.      */
  87.     for (d->bitpos = 0; d->bitpos < 40; d->bitpos++) {
  88.         avr_raise_irq(d->irq + IRQ_DHT_OUT, 1);
  89.         res = avr_usec_to_cycles(d->avr,
  90.                 (d->packet >> (39 - d->bitpos)) & 1 ? 70 : 27);
  91.         avr_raise_irq(d->irq + IRQ_DHT_ACTIVE, 39-d->bitpos);
  92.         _WAIT(d->timer_state);
  93.         avr_raise_irq(d->irq + IRQ_DHT_OUT, 0);
  94.         res = avr_usec_to_cycles(d->avr, 50);
  95.         _WAIT(d->timer_state);
  96.     }
  97.  
  98.     res = 0;
  99.     d->driving = 0;
  100.     avr_raise_irq(d->irq + IRQ_DHT_OUT, 1);
  101.     _EXIT(d->timer_state);
  102. _exit:
  103.     return res ? when + res : 0;
  104. }
  105.  
  106.  
  107. static void
  108. dht_input_irq(
  109.         struct avr_irq_t * irq,
  110.         uint32_t value,
  111.         void * param)
  112. {
  113.     dht22_p d = (dht22_p)param;
  114.  
  115.     _RESUME(d->input_state);
  116.  
  117.     avr_raise_irq(d->irq + IRQ_DHT_ACTIVE, 0);
  118.  
  119.     if (value == 1)
  120.         _EXIT(d->input_state);
  121.  
  122.     d->stamp = d->avr->cycle;
  123.     _WAIT(d->input_state);
  124.     while (value == 0)
  125.         _WAIT(d->input_state);
  126.     d->stamp = d->avr->cycle - d->stamp;
  127. //  printf("%s low pulse start is %d usec\r\n", __func__,
  128. //          avr_cycles_to_usec(d->avr, d->stamp));
  129.     if (d->stamp < 500) {
  130.         printf("%s start low pulse too short (%d), ignoring\r\n", __func__,
  131.                 avr_cycles_to_usec(d->avr, d->stamp));
  132.         _EXIT(d->input_state);
  133.     }
  134. //  printf("%s start low pulse GOOD, starting output\r\n", __func__);
  135.     avr_raise_irq(d->irq + IRQ_DHT_ACTIVE, 1);
  136.  
  137.     // start sequence, wait 30us, lower output, wait 80us, raise it 80us etc
  138. //  avr_raise_irq(d->irq + IRQ_DHT_OUT, 1);
  139.     d->driving = 1;
  140.     avr_cycle_timer_register_usec(
  141.             d->avr,
  142.             30 /* us */,
  143.             _dht_timer_callback,
  144.             param);
  145.     // ignore any input while we drive that 'pin'
  146.     while (d->driving)
  147.         _WAIT(d->input_state);
  148.  
  149. //  printf("%s finished!\r\n", __func__);
  150.     avr_raise_irq(d->irq + IRQ_DHT_ACTIVE, 0);
  151.  
  152.     _EXIT(d->input_state);
  153. _exit:
  154.     return;
  155. }
  156.  
  157. static void
  158. dht_temp_input_irq(
  159.         struct avr_irq_t * irq,
  160.         uint32_t value,
  161.         void * param)
  162. {
  163.     dht22_p d = (dht22_p)param;
  164.     d->temp = (int16_t)value;
  165. }
  166.  
  167. static void
  168. dht_hum_input_irq(
  169.         struct avr_irq_t * irq,
  170.         uint32_t value,
  171.         void * param)
  172. {
  173.     dht22_p d = (dht22_p)param;
  174.     d->hum = value;
  175. }
  176.  
  177.  
  178. static const char * irq_names[IRQ_DHT_COUNT] = {
  179.     [IRQ_DHT_IN] = "<dht22.in",
  180.     [IRQ_DHT_OUT] = ">dht22.out",
  181.     [IRQ_DHT_TEMP_IN] = ">dht22.temp",
  182.     [IRQ_DHT_HUM_IN] = ">dht22.hum",
  183.     [IRQ_DHT_ACTIVE] = ">dht22.active",
  184. };
  185.  
  186. void
  187. dht22_init(
  188.     struct dht22_t * d,
  189.     struct avr_t * avr )
  190. {
  191.     memset(d, 0, sizeof(*d));
  192.     d->avr = avr;
  193.     d->irq = avr_alloc_irq(&avr->irq_pool, 0, IRQ_DHT_COUNT, irq_names);
  194.     avr_irq_register_notify(d->irq + IRQ_DHT_IN, dht_input_irq, d);
  195.     avr_irq_register_notify(d->irq + IRQ_DHT_TEMP_IN, dht_temp_input_irq, d);
  196.     avr_irq_register_notify(d->irq + IRQ_DHT_HUM_IN, dht_hum_input_irq, d);
  197.     d->irq[IRQ_DHT_OUT].flags |= IRQ_FLAG_FILTERED;
  198.     d->hum = 567;
  199.     d->temp = 234;
  200. }
  201.  
  202. void
  203. dht22_connect(
  204.     struct dht22_t * d,
  205.     avr_irq_t * output_irq,
  206.     avr_irq_t * input_irq,
  207.     avr_irq_t * temp_in_irq,
  208.     avr_irq_t * hum_in_irq )
  209. {
  210.     avr_connect_irq(input_irq, d->irq + IRQ_DHT_IN);
  211.     avr_connect_irq(d->irq + IRQ_DHT_OUT, output_irq);
  212.     if (temp_in_irq)
  213.         avr_connect_irq(temp_in_irq, d->irq + IRQ_DHT_TEMP_IN);
  214.     if (hum_in_irq)
  215.         avr_connect_irq(hum_in_irq, d->irq + IRQ_DHT_HUM_IN);
  216. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement