Beispiel #1
0
bool ets_run(void) {
#if USE_ETS_TASK
    #if SDK_BELOW_1_1_1
    ets_isr_attach(10, my_timer_isr, NULL);
    #endif
    _ets_run();
#else
//    ets_timer_init();
    *(char*)0x3FFFC6FC = 0;
    ets_intr_lock();
    printf("ets_alt_task: ets_run\n");
#if DEBUG
    dump_tasks();
#endif
    ets_intr_unlock();
    while (1) {
        if (!ets_loop_iter()) {
            //printf("idle\n");
            ets_intr_lock();
            if (idle_cb) {
                idle_cb(idle_arg);
            }
            asm("waiti 0");
            ets_intr_unlock();
        }
    }
#endif
}
Beispiel #2
0
int pp_post(int x)
{
	ets_intr_lock();
	if(t0x3FFEB460[x] == 0) {
		ets_intr_unlock();
		t0x3FFEB460[x]++;
		return ets_post(32, x, 0);
	}
	ets_intr_unlock();
	return 0;
}
Beispiel #3
0
// Byte triples in the buffer are interpreted as G R B values and sent to the hardware as G R B.
int ICACHE_FLASH_ATTR ws2812_writegrb(uint8_t gpio, char *buffer, size_t length)
{
    // Initialize the output pin:
    pinMode(gpio, OUTPUT);
    digitalWrite(gpio, 0);

    // Ignore incomplete Byte triples at the end of buffer:
    length -= length % 3;

    // Do not remove these:
    os_delay_us(1);
    os_delay_us(1);

    // Send the buffer:
    ets_intr_lock();
    const char * const end = buffer + length;
    while (buffer != end) {
        uint8_t mask = 0x80;
        while (mask) {
            (*buffer & mask) ? send_ws_1(gpio) : send_ws_0(gpio);
            mask >>= 1;
        }
        ++buffer;
    }
    ets_intr_unlock();
}
Beispiel #4
0
bool ets_post(uint8 prio, os_signal_t sig, os_param_t param) {
//    static unsigned cnt; printf("#%d ets_post(%d, %x, %x)\n", cnt++, prio, sig, param);
#if USE_ETS_TASK
    return _ets_post(prio, sig, param);
#else
    ets_intr_lock();

    const int id = prio2id(prio);
    os_event_t *q = emu_tasks[id].queue;
    if (emu_tasks[id].i_put == -1) {
        // queue is full
        printf("ets_post: task %d queue full\n", prio);
        return false;
    }
    q = &q[emu_tasks[id].i_put++];
    q->sig = sig;
    q->par = param;
    if (emu_tasks[id].i_put == emu_tasks[id].qlen) {
        emu_tasks[id].i_put = 0;
    }
    if (emu_tasks[id].i_put == emu_tasks[id].i_get) {
        // queue got full
        emu_tasks[id].i_put = -1;
    }
    //printf("after ets_post: "); dump_task(prio, &emu_tasks[id]);
    //dump_tasks();

    ets_intr_unlock();

    return true;
#endif
}
Beispiel #5
0
bool ets_loop_iter(void) {
    if (query_irq() != 0) {
        return false;
    }
    //static unsigned cnt;
    bool progress = false;
    for (volatile struct task_entry *t = emu_tasks; t < &emu_tasks[MP_ARRAY_SIZE(emu_tasks)]; t++) {
        system_soft_wdt_feed();
        ets_intr_lock();
        //printf("etc_loop_iter: "); dump_task(t - emu_tasks + FIRST_PRIO, t);
        if (t->i_get != t->i_put) {
            progress = true;
            //printf("#%d Calling task %d(%p) (%x, %x)\n", cnt++,
            //    t - emu_tasks + FIRST_PRIO, t->task, t->queue[t->i_get].sig, t->queue[t->i_get].par);
            int idx = t->i_get;
            if (t->i_put == -1) {
                t->i_put = t->i_get;
            }
            if (++t->i_get == t->qlen) {
                t->i_get = 0;
            }
            //ets_intr_unlock();
            t->task(&t->queue[idx]);
            //ets_intr_lock();
            //printf("Done calling task %d\n", t - emu_tasks + FIRST_PRIO);
        }
        ets_intr_unlock();
    }
    return progress;
}
Beispiel #6
0
// Byte triples in the buffer are interpreted as R G B values and sent to the hardware as G R B.
int ICACHE_FLASH_ATTR ws2812_writergb(uint8_t gpio, char *buffer, size_t length)
{
    // Initialize the output pin:
    pinMode(gpio, OUTPUT);
    digitalWrite(gpio, 0);

    // Ignore incomplete Byte triples at the end of buffer:
    length -= length % 3;

    // Rearrange R G B values to G R B order needed by WS2812 LEDs:
    size_t i;
    for (i = 0; i < length; i += 3) {
        const char r = buffer[i];
        const char g = buffer[i + 1];
        buffer[i] = g;
        buffer[i + 1] = r;
    }

    // Do not remove these:
    os_delay_us(1);
    os_delay_us(1);

    // Send the buffer:
    ets_intr_lock();
    const char * const end = buffer + length;
    while (buffer != end) {
        uint8_t mask = 0x80;
        while (mask) {
            (*buffer & mask) ? send_ws_1(gpio) : send_ws_0(gpio);
            mask >>= 1;
        }
        ++buffer;
    }
    ets_intr_unlock();
}
int tcpserver_send(struct espconn *conn, void *data, uint16 len, enum Memtype mem)
{
	DEBUG("enter tcpserver_send");
	ets_intr_lock();

	if (MessageQueue_push(&sendq, conn, data, len, mem) != 0) {
		ets_intr_unlock();
		ets_uart_printf("Failed to push data into send queue.\n");
		DEBUG("exit tcpserver_send");
		return -1;
	}

	ets_intr_unlock();
	system_os_post(SERVER_TASK_PRIO, SERVER_SIG_TX, 0);
	DEBUG("exit tcpserver_send");
	return 0;
}
Beispiel #8
0
void _pp_task_12(void)
{
	ets_intr_lock();
	if(dbg_stop_sw_wdt == false) wdt_flg = false;
	if(dbg_stop_hw_wdt == false) {
		WDT_FEED = WDT_FEED_MAGIC;
	}
	ets_intr_unlock();
}
Beispiel #9
0
void wdt_task(ETSEvent *e)
{
	ets_intr_lock();
	if(wdt_flg) {
		wdt_flg = false;
		if (RTC_MEM(0) <= RST_EVENT_WDT) RTC_MEM(0) = 0;
		WDT_FEED = WDT_FEED_MAGIC;
	}
	ets_intr_unlock();
}
Beispiel #10
0
int do_flash_write(uint32_t addr, uint32_t len, uint32_t erase) {
  struct uart_buf ub;
  uint8_t digest[16];
  uint32_t num_written = 0, num_erased = 0;
  struct MD5Context ctx;
  MD5Init(&ctx);

  if (addr % FLASH_SECTOR_SIZE != 0) return 0x32;
  if (len % FLASH_SECTOR_SIZE != 0) return 0x33;
  if (SPIUnlock() != 0) return 0x34;

  ub.nr = 0;
  ub.pr = ub.pw = ub.data;
  ets_isr_attach(ETS_UART_INUM, uart_isr, &ub);
  SET_PERI_REG_MASK(UART_INT_ENA(0), UART_RX_INTS);
  ets_isr_unmask(1 << ETS_UART_INUM);

  SLIP_send(&num_written, 4);

  while (num_written < len) {
    volatile uint32_t *nr = &ub.nr;
    /* Prepare the space ahead. */
    while (erase && num_erased < num_written + SPI_WRITE_SIZE) {
      const uint32_t num_left = (len - num_erased);
      if (num_left > FLASH_BLOCK_SIZE && addr % FLASH_BLOCK_SIZE == 0) {
        if (SPIEraseBlock(addr / FLASH_BLOCK_SIZE) != 0) return 0x35;
        num_erased += FLASH_BLOCK_SIZE;
      } else {
        /* len % FLASH_SECTOR_SIZE == 0 is enforced, no further checks needed */
        if (SPIEraseSector(addr / FLASH_SECTOR_SIZE) != 0) return 0x36;
        num_erased += FLASH_SECTOR_SIZE;
      }
    }
    /* Wait for data to arrive. */
    while (*nr < SPI_WRITE_SIZE) {
    }
    MD5Update(&ctx, ub.pr, SPI_WRITE_SIZE);
    if (SPIWrite(addr, ub.pr, SPI_WRITE_SIZE) != 0) return 0x37;
    ets_intr_lock();
    *nr -= SPI_WRITE_SIZE;
    ets_intr_unlock();
    num_written += SPI_WRITE_SIZE;
    addr += SPI_WRITE_SIZE;
    ub.pr += SPI_WRITE_SIZE;
    if (ub.pr >= ub.data + UART_BUF_SIZE) ub.pr = ub.data;
    SLIP_send(&num_written, 4);
  }

  ets_isr_mask(1 << ETS_UART_INUM);

  MD5Final(digest, &ctx);
  SLIP_send(digest, 16);

  return 0;
}
static void ICACHE_FLASH_ATTR tcpserver_recv_cb(void *arg, char *pdata, unsigned short len)
{
	DEBUG("enter tcpserver_recv_cb");
	uint32 remote_ip;
	int remote_port;
	char *data;

	ets_uart_printf("tcpserver_recv_cb\n");
	remote_port = ((struct espconn *)arg)->proto.tcp->remote_port;
	remote_ip = *(uint32 *)((struct espconn *)arg)->proto.tcp->remote_ip;

	ets_uart_printf("Received %d bytes from %s:%d!\n", len,
			inet_ntoa(remote_ip), remote_port);
	ets_uart_printf("%s\n", pdata);

	data = (char *)os_zalloc(len + 1);	/* Leave 1 byte for NULL char */

	if (data == NULL) {
		ets_uart_printf("Failed to alloc memory for recieved data.\n\n");
		DEBUG("exit tcpserver_recv_cb");
		return;
	}

	/* Need to copy it because the pdata might get freed after exiting the callback. */
	os_memcpy(data, pdata, len);

	ets_intr_lock();

	if (MessageQueue_push(&recvq, (struct espconn *)arg, data, len, HEAP_MEM) != 0) {
		ets_intr_unlock();
		ets_uart_printf("Failed to push recieved message in recv message queue.\n\n");
		return;
	}

	ets_intr_unlock();

	/* Post TCP_SIG_RX to server task. */
	system_os_post(SERVER_TASK_PRIO, SERVER_SIG_RX, 0);

	ets_uart_printf("\n");
	DEBUG("exit tcpserver_recv_cb");
}
Beispiel #12
0
//-------------------------------------------------------------------------------
// tcp2uart_int_rxtx_disable
//-------------------------------------------------------------------------------
void ICACHE_FLASH_ATTR tcp2uart_int_rxtx_disable(void)
{
    tcp2uart_conn = NULL;
    ets_intr_lock(); //	ETS_UART_INTR_DISABLE();
    MEMW();
    UART0_CONF1 &= ~UART_RX_FLOW_EN; // update RST
    UART0_INT_ENA &= ~(UART_RXFIFO_FULL_INT_ENA | UART_TXFIFO_EMPTY_INT_ENA);
    //clear rx and tx fifo, not ready
    uint32 conf0 = UART0_CONF0;
    UART0_CONF0 = conf0 | UART_RXFIFO_RST | UART_TXFIFO_RST;
    UART0_CONF0 = conf0 & (~ (UART_RXFIFO_RST | UART_TXFIFO_RST));
//	update_rts0();
    ets_intr_unlock(); // ETS_UART_INTR_ENABLE();
//?	WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_CLR | UART_TXFIFO_EMPTY_INT_CLR);
    os_timer_disarm(&uart0_tx_buf_timer);
    os_timer_setfn(&uart0_tx_buf_timer, (os_timer_func_t *)send_tx_buf, NULL);
    os_timer_disarm(&uart0_rx_buf_timer);
    os_timer_setfn(&uart0_rx_buf_timer, (os_timer_func_t *)loading_rx_buf, NULL);
}
Beispiel #13
0
int pp_post(int x)
{
	int ret = 0;
	ets_intr_lock();
	if(t0x3FFEB020[x] == 0) {
		t0x3FFEB020[x]++;
		if(x == 12) {
			b0x3FFEAE99 = 1;
		}
		int ret = ets_post(32, x, 0);
		if(ret != 0) {
			ets_intr_lock();
			t0x3FFEB020[0] = 0;
			t0x3FFEB020[x]--;
			WDT_FEED = WDT_FEED_MAGIC;
		}
	}
	ets_intr_unlock();
	return 0;
}
Beispiel #14
0
//===============================================================================
// Timer: UART->TCP (UART->bufo->TCP)
// loading_rx_buf() чтение fifo UART rx в буфер передачи TCP
// Сигнал CTS/RTS пока не огранизован в связи с неясностью,
// на какую ногу модуля его делать
//-------------------------------------------------------------------------------
void ICACHE_FLASH_ATTR loading_rx_buf(void)
{
    TCP_SERV_CONN *conn = tcp2uart_conn;
    if(conn == NULL || conn->pbufo == NULL || conn->flag.user_flg1) return; // нет буфера + тест на повторное вхождение
    conn->flag.user_flg1 = 1;
    ets_intr_lock(); //	ETS_UART_INTR_DISABLE();
    MEMW();
    UART0_INT_ENA &= ~ UART_RXFIFO_FULL_INT_ENA; // запретить прерывание по приему символа
    ets_intr_unlock(); // ETS_UART_INTR_ENABLE();
    os_timer_disarm(&uart0_rx_buf_timer);
    if(conn->flag.busy_bufo) { // в данный момент bufo обрабатывается (передается LwIP-у)?
        // попробовать повторить через время
        ets_timer_arm_new(&uart0_rx_buf_timer, 10, 0, 0); // 10us
        conn->flag.user_flg1 = 0;
        return;
    }
    uint8 *pend = conn->pbufo + conn->sizeo;
    // дополнить буфер передачи символами из rx fifo
    while((conn->ptrtx + conn->cntro) < pend) {
        MEMW();
        if((UART0_STATUS >> UART_RXFIFO_CNT_S) & UART_RXFIFO_CNT) conn->ptrtx[conn->cntro++] = UART0_FIFO;
        else break;
    }
Beispiel #15
0
// Start up a waveform on a pin, or change the current one.  Will change to the new
// waveform smoothly on next low->high transition.  For immediate change, stopWaveform()
// first, then it will immediately begin.
int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS) {
  Waveform *wave = NULL;
  for (size_t i = 0; i < countof(waveform); i++) {
    if (((pin == 16) && waveform[i].gpio16Mask==1) || ((pin != 16) && (waveform[i].gpioMask == 1<<pin))) {
      wave = (Waveform*) & (waveform[i]);
      break;
    }
  }
  if (!wave) {
    return false;
  }

  // To safely update the packed bitfields we need to stop interrupts while setting them as we could
  // get an IRQ in the middle of a multi-instruction mask-and-set required to change them which would
  // then cause an IRQ update of these values (.enabled only, for now) to be lost.
  ets_intr_lock();

  wave->nextTimeHighCycles = MicrosecondsToCycles(timeHighUS) - 70;  // Take out some time for IRQ codepath
  wave->nextTimeLowCycles = MicrosecondsToCycles(timeLowUS) - 70;  // Take out some time for IRQ codepath
  wave->timeLeftCycles = MicrosecondsToCycles(runTimeUS);
  if (!wave->enabled) {
    wave->state = 0;
    // Actually set the pin high or low in the IRQ service to guarantee times
    wave->nextServiceCycle = GetCycleCount() + MicrosecondsToCycles(1);
    wave->enabled = 1;
    if (!timerRunning) {
      initTimer();
    }
    ReloadTimer(MicrosecondsToCycles(1)); // Cause an interrupt post-haste
  }

  // Re-enable interrupts here since we're done with the update
  ets_intr_unlock();

  return true;
}
Beispiel #16
0
// return values:
// DHTLIB_OK
// DHTLIB_ERROR_TIMEOUT
int dht_readSensor(uint8_t pin, uint8_t wakeupDelay)
{
    // INIT BUFFERVAR TO RECEIVE DATA
    uint8_t mask = 128;
    uint8_t idx = 0;
    uint8_t i = 0;

    // replace digitalRead() with Direct Port Reads.
    // reduces footprint ~100 bytes => portability issue?
    // direct port read is about 3x faster
    // uint8_t bit = digitalPinToBitMask(pin);
    // uint8_t port = digitalPinToPort(pin);
    // volatile uint8_t *PIR = portInputRegister(port);

    // EMPTY BUFFER
    for (i = 0; i < 5; i++) dht_bytes[i] = 0;

    // REQUEST SAMPLE
    // pinMode(pin, OUTPUT);
    platform_gpio_mode(pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_PULLUP);
    DIRECT_MODE_OUTPUT(pin);
    // digitalWrite(pin, LOW); // T-be
    DIRECT_WRITE_LOW(pin);
    // delay(wakeupDelay);
    for (i = 0; i < wakeupDelay; i++) os_delay_us(1000);
    // Disable interrupts
    ets_intr_lock();
    // digitalWrite(pin, HIGH);   // T-go
    DIRECT_WRITE_HIGH(pin);
    os_delay_us(40);
    // pinMode(pin, INPUT);
    DIRECT_MODE_INPUT(pin);

    // GET ACKNOWLEDGE or TIMEOUT
    uint16_t loopCntLOW = DHTLIB_TIMEOUT;
    while (DIRECT_READ(pin) == LOW )  // T-rel
    {
        os_delay_us(1);
        if (--loopCntLOW == 0) return DHTLIB_ERROR_TIMEOUT;
    }

    uint16_t loopCntHIGH = DHTLIB_TIMEOUT;
    while (DIRECT_READ(pin) != LOW )  // T-reh
    {
        os_delay_us(1);
        if (--loopCntHIGH == 0) return DHTLIB_ERROR_TIMEOUT;
    }

    // READ THE OUTPUT - 40 BITS => 5 BYTES
    for (i = 40; i != 0; i--)
    {
        loopCntLOW = DHTLIB_TIMEOUT;
        while (DIRECT_READ(pin) == LOW )
        {
            os_delay_us(1);
            if (--loopCntLOW == 0) return DHTLIB_ERROR_TIMEOUT;
        }

        uint32_t t = system_get_time();

        loopCntHIGH = DHTLIB_TIMEOUT;
        while (DIRECT_READ(pin) != LOW )
        {
            os_delay_us(1);
            if (--loopCntHIGH == 0) return DHTLIB_ERROR_TIMEOUT;
        }

        if ((system_get_time() - t) > 40)
        {
            dht_bytes[idx] |= mask;
        }
        mask >>= 1;
        if (mask == 0)   // next byte?
        {
            mask = 128;
            idx++;
        }
    }
    // Enable interrupts
    ets_intr_unlock();
    // pinMode(pin, OUTPUT);
    DIRECT_MODE_OUTPUT(pin);
    // digitalWrite(pin, HIGH);
    DIRECT_WRITE_HIGH(pin);

    return DHTLIB_OK;
}
Beispiel #17
0
void jshInterruptOn()  { ets_intr_unlock(); }
static void ICACHE_FLASH_ATTR server_task(os_event_t *e)
{
	DEBUG("enter server_task");
	static bool sending = false;
	static bool more_fragments = false;
	static struct espconn *sending_conn;
	static uint8 *first_sending_chunk;
	static uint8 *current_sending_chunk;
	static uint16 sending_len;
	static enum Memtype sending_mem;

	struct espconn *conn;
	void *data;
	uint16 len;
	enum Memtype mem;

	switch (e->sig) {
		case SERVER_SIG_RX:
			ets_intr_lock();

			if (MessageQueue_unshift(&recvq, &conn, &data, &len, &mem) == 0) {
				ets_intr_unlock();
				tcpparser_process_data(data, len, conn);

				if (mem == HEAP_MEM)
					os_free(data);
			} else {
				ets_intr_unlock();
			}

			break;

		case SERVER_SIG_TX:
			ets_intr_lock();

			if (!sending) {
				if (MessageQueue_unshift(&sendq, &conn, &data, &len, &mem) == 0) {
					sending = true;
					ets_intr_unlock();

					if (len <= TCP_MAX_PACKET_SIZE) {
						more_fragments = false;

						if (espconn_sent(conn, data, len) != ESPCONN_OK)
							ets_uart_printf("Failed to send data.\n\n");

						if (mem == HEAP_MEM)
							os_free(data);
					} else {
						more_fragments = true;
						sending_conn = conn;
						first_sending_chunk = (uint8 *)data;
						current_sending_chunk = (uint8 *)data;
						sending_len = len;
						sending_mem = mem;

						if (espconn_sent(conn, data, TCP_MAX_PACKET_SIZE) != ESPCONN_OK)
							ets_uart_printf("Failed to send data.\n\n");

						current_sending_chunk += TCP_MAX_PACKET_SIZE;
						sending_len -= TCP_MAX_PACKET_SIZE;
						ets_uart_printf("More data to send.\n");
					}
				} else {
					ets_intr_unlock();
				}
			} else {
				ets_intr_unlock();
			}

			break;

		case SERVER_SIG_TX_DONE:
			ets_intr_lock();

			if (sending && more_fragments) {
				ets_intr_unlock();

				if (sending_len <= TCP_MAX_PACKET_SIZE) {
					more_fragments = false;

					if (espconn_sent(sending_conn, current_sending_chunk, sending_len) != ESPCONN_OK)
						ets_uart_printf("Failed to send data.\n\n");

					if (sending_mem == HEAP_MEM)
						os_free(first_sending_chunk);

					ets_intr_lock();
					sending = false;
					ets_intr_unlock();
				} else {
					more_fragments = true;

					if (espconn_sent(sending_conn, current_sending_chunk, TCP_MAX_PACKET_SIZE) != ESPCONN_OK)
						ets_uart_printf("Failed to send data.\n\n");

					current_sending_chunk += TCP_MAX_PACKET_SIZE;
					sending_len -= TCP_MAX_PACKET_SIZE;
					ets_uart_printf("More data to send.\n");
				}
			} else if (MessageQueue_empty(&sendq)) {
				sending = false;
				ets_intr_unlock();
			} else {
				sending = false;
				ets_intr_unlock();
				system_os_post(SERVER_TASK_PRIO, SERVER_SIG_TX, 0);
			}

			break;

		default:
			break;
	}

	DEBUG("exit server_task");
}
Beispiel #19
0
void jshInterruptOn() {
  //os_printf("> jshInterruptOn\n");
  ets_intr_unlock();
  //os_printf("< jshInterruptOn\n");
} // End of jshInterruptOn
Beispiel #20
0
//=============================================================================
void tests(void)
{
	ets_set_idle_cb(NULL, NULL); // снять callback
	ets_intr_unlock();
	ets_printf(">");
}
Beispiel #21
0
/**
    Originally from: http://harizanov.com/2014/11/esp8266-powered-web-server-led-control-dht22-temperaturehumidity-sensor-reading/
    Adapted from: https://github.com/adafruit/Adafruit_Python_DHT/blob/master/source/Raspberry_Pi/pi_dht_read.c
    LICENSE:
    // 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.
    */
static  void ICACHE_FLASH_ATTR pollDHTCb(void * arg){
  int counter = 0;
  int laststate = 1;
  int i = 0;
  int bits_in = 0;
  // int bitidx = 0;
  // int bits[250];

  int data[100];

  data[0] = data[1] = data[2] = data[3] = data[4] = 0;

  //disable interrupts, start of critical section
  ets_intr_lock();
  system_soft_wdt_feed();
  /* wdt_feed(); */

  // Wake up device, 250ms of high
  GPIO_OUTPUT_SET(OKA_DHT_IO_NUM, 1);
  delay_ms(20);

  // Hold low for 20ms
  GPIO_OUTPUT_SET(OKA_DHT_IO_NUM, 0);
  delay_ms(20);

  // High for 40ms
  // GPIO_OUTPUT_SET(2, 1);

  GPIO_DIS_OUTPUT(OKA_DHT_IO_NUM);
  os_delay_us(40);

  // Set pin to input with pullup
  // PIN_PULLUP_EN(PERIPHS_IO_MUX_GPIO2_U);

  // os_printf("Waiting for GPIO to drop \n");

  // wait for pin to drop?
  while (GPIO_INPUT_GET(OKA_DHT_IO_NUM) == 1 && i < DHT_MAXCOUNT) {
    if (i >= DHT_MAXCOUNT) {
      goto fail;
    }
    i++;
  }

  //  os_printf("Reading DHT\n");

  // read data!
  for (i = 0; i < MAXTIMINGS; i++) {
    // Count high time (in approx us)
    counter = 0;
    while (GPIO_INPUT_GET(OKA_DHT_IO_NUM) == laststate) {
      counter++;
      os_delay_us(1);
      if (counter == 1000)
        break;
    }
    laststate = GPIO_INPUT_GET(OKA_DHT_IO_NUM);

    if (counter == 1000)
      break;

    // store data after 3 reads
    if ((i > 3) && (i % 2 == 0)) {
      // shove each bit into the storage bytes
      data[bits_in / 8] <<= 1;
      if (counter > BREAKTIME) {
        //os_printf("1");
        data[bits_in / 8] |= 1;
      } else {
        //os_printf("0");
      }
      bits_in++;
    }
  }

  //Re-enable interrupts, end of critical section
  ets_intr_unlock();

  if (bits_in < 40) {
    // INFO
    os_printf("DHT sensor: Got too few bits: %d should be at least 40\n", bits_in);
    goto fail;
  }


  int checksum = (data[0] + data[1] + data[2] + data[3]) & 0xFF;

  // DEBUG
  /* os_printf("DHT: %02x %02x %02x %02x [%02x] CS: %02x\n", data[0], data[1],data[2],data[3],data[4],checksum); */

  if (data[4] != checksum) {
    os_printf("DHT sensor: Checksum was incorrect after %d bits. Expected %d but got %d",
              bits_in, data[4], checksum);
    goto fail;
  }

  reading.humidity = data[0] * 256 + data[1];
  reading.temperature = (data[2] & 0x7f) * 256 + data[3];
  if (data[2] & 0x80) {
    reading.temperature *= -1;
  }

  /* reading.humidity = (data[0] << 8) | data[1]; */
  /* reading.temperature = (data[2] << 7) | data[3]; */

  /* reading.humidity = ((int16_t *)data)[0]; */
  /* reading.temperature = ((int16_t *)data)[1]; */
  /* reading.temperature = scale_temperature(data); */
  /* reading.humidity = scale_humidity(data); */
  // DEBUG
  /* os_printf("Temp =  %d *C, Hum = %d %% -- 0x%04x\n", reading.temperature, reading.humidity, *(int32_t*)data); */

  /* os_printf("Temp =  %d *C, Hum = %d %%\n", (int)(reading.temperature * 100), */
  /*           (int)(reading.humidity * 100)); */

  reading.success = 1;
  if (dht_update_cb) {
    dht_update_cb(&reading);
  }
  return;
 fail:
  reading.success = 0;
  if (dht_update_cb) {
    dht_update_cb(&reading);
  }
  /* os_printf("DHT sensor: Failed to get reading, dying\n"); */
}