Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
56ba21c081
299 changed files with 16208 additions and 13185 deletions
181
extras/ad770x/ad770x.c
Normal file
181
extras/ad770x/ad770x.c
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
/**
|
||||
* Driver for AD7705/AD7706 SPI ADC
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2017 Ruslan V. Uss <unclerus@gmail.com>
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include "ad770x.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <esp/gpio.h>
|
||||
#include <esp/spi.h>
|
||||
#include <espressif/esp_common.h>
|
||||
|
||||
#define AD770X_DEBUG
|
||||
|
||||
#define BUS 1
|
||||
#define INIT_TIMEOUT 500000 // 500ms
|
||||
|
||||
#ifdef AD770X_DEBUG
|
||||
#include <stdio.h>
|
||||
#define debug(fmt, ...) printf("%s" fmt "\n", "AD770x: ", ## __VA_ARGS__)
|
||||
#else
|
||||
#define debug(fmt, ...)
|
||||
#endif
|
||||
|
||||
#define timeout_expired(start, len) ((uint32_t)(sdk_system_get_time() - (start)) >= (len))
|
||||
|
||||
#define _BV(x) (1 << (x))
|
||||
|
||||
#define REG_COMM 0x00 // 8 bits
|
||||
#define REG_SETUP 0x01 // 8 bits
|
||||
#define REG_CLOCK 0x02 // 8 bits
|
||||
#define REG_DATA 0x03 // 16 bits
|
||||
#define REG_TEST 0x04 // 8 bits
|
||||
#define REG_OFFS 0x06 // 24 bits
|
||||
#define REG_GAIN 0x07 // 24 bits
|
||||
|
||||
#define BIT_COMM_CH0 0
|
||||
#define BIT_COMM_CH1 1
|
||||
#define BIT_COMM_STBY 2
|
||||
#define BIT_COMM_RW 3
|
||||
#define BIT_COMM_RS0 4
|
||||
#define BIT_COMM_RS1 5
|
||||
#define BIT_COMM_RS2 6
|
||||
#define BIT_COMM_DRDY 7
|
||||
|
||||
#define MASK_COMM_CH 0x03
|
||||
#define MASK_COMM_RS 0x70
|
||||
|
||||
#define BIT_CLOCK_FS0 0
|
||||
#define BIT_CLOCK_FS1 1
|
||||
#define BIT_CLOCK_CLK 2
|
||||
#define BIT_CLOCK_CLKDIV 3
|
||||
#define BIT_CLOCK_CLKDIS 4
|
||||
|
||||
#define MASK_CLOCK_FS 0x03
|
||||
#define MASK_CLOCK_CLK 0x0c
|
||||
|
||||
#define BIT_SETUP_FSYNC 0
|
||||
#define BIT_SETUP_BUF 1
|
||||
#define BIT_SETUP_BU 2
|
||||
#define BIT_SETUP_G0 3
|
||||
#define BIT_SETUP_G1 4
|
||||
#define BIT_SETUP_G2 5
|
||||
#define BIT_SETUP_MD0 6
|
||||
#define BIT_SETUP_MD1 7
|
||||
|
||||
#define MASK_SETUP_GAIN 0x38
|
||||
#define MASK_SETUP_MODE 0xc0
|
||||
|
||||
static const spi_settings_t config = {
|
||||
.endianness = SPI_BIG_ENDIAN,
|
||||
.msb = true,
|
||||
.minimal_pins = true,
|
||||
.mode = SPI_MODE3,
|
||||
.freq_divider = SPI_FREQ_DIV_500K
|
||||
};
|
||||
|
||||
static uint8_t write(uint8_t cs_pin, uint8_t value)
|
||||
{
|
||||
spi_settings_t old;
|
||||
spi_get_settings(BUS, &old);
|
||||
spi_set_settings(BUS, &config);
|
||||
|
||||
gpio_write(cs_pin, false);
|
||||
uint8_t res = spi_transfer_8(BUS, value);
|
||||
//debug("byte wr: 0x%02x", value);
|
||||
gpio_write(cs_pin, true);
|
||||
|
||||
spi_set_settings(BUS, &old);
|
||||
return res;
|
||||
}
|
||||
|
||||
inline static uint8_t read_byte(uint8_t cs_pin)
|
||||
{
|
||||
return write(cs_pin, 0);
|
||||
}
|
||||
|
||||
static uint16_t read_word(uint8_t cs_pin)
|
||||
{
|
||||
spi_settings_t old;
|
||||
spi_get_settings(BUS, &old);
|
||||
spi_set_settings(BUS, &config);
|
||||
|
||||
gpio_write(cs_pin, false);
|
||||
uint16_t res = spi_transfer_16(BUS, 0);
|
||||
gpio_write(cs_pin, true);
|
||||
|
||||
spi_set_settings(BUS, &old);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void prepare(uint8_t channel, uint8_t reg, bool read, uint8_t cs_pin, bool standby)
|
||||
{
|
||||
write(cs_pin,
|
||||
(channel & MASK_COMM_CH) |
|
||||
(read ? _BV(BIT_COMM_RW) : 0) |
|
||||
((reg << BIT_COMM_RS0) & MASK_COMM_RS) |
|
||||
(standby ? _BV(BIT_COMM_STBY) : 0)
|
||||
);
|
||||
}
|
||||
|
||||
int ad770x_init(const ad770x_params_t *params, uint8_t channel)
|
||||
{
|
||||
if (!spi_set_settings(BUS, &config))
|
||||
{
|
||||
debug("Cannot init SPI");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if ((params->master_clock >= AD770X_MCLK_2_4576MHz && params->update_rate < AD770X_RATE_50)
|
||||
|| (params->master_clock < AD770X_MCLK_2_4576MHz && params->update_rate > AD770X_RATE_200))
|
||||
{
|
||||
debug("Invalid update rate / master clock combination");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gpio_enable(params->cs_pin, GPIO_OUTPUT);
|
||||
gpio_write(params->cs_pin, true);
|
||||
|
||||
prepare(channel, REG_CLOCK, false, params->cs_pin, false);
|
||||
write(params->cs_pin,
|
||||
((params->master_clock << BIT_CLOCK_CLK) & MASK_CLOCK_CLK) |
|
||||
(params->update_rate & MASK_CLOCK_FS)
|
||||
);
|
||||
|
||||
ad770x_set_mode(params, channel, AD770X_MODE_CALIBRATION);
|
||||
|
||||
uint32_t start = sdk_system_get_time();
|
||||
while (!ad770x_data_ready(params, channel))
|
||||
if (timeout_expired(start, INIT_TIMEOUT))
|
||||
{
|
||||
debug("Timeout while calibration");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ad770x_set_mode(const ad770x_params_t *params, uint8_t channel, ad770x_mode_t mode)
|
||||
{
|
||||
prepare(channel, REG_SETUP, false, params->cs_pin, false);
|
||||
write(params->cs_pin,
|
||||
((params->gain << BIT_SETUP_G0) & MASK_SETUP_GAIN) |
|
||||
(params->bipolar ? 0 : _BV(BIT_SETUP_BU)) |
|
||||
((mode << BIT_SETUP_MD0) & MASK_SETUP_MODE)
|
||||
);
|
||||
}
|
||||
|
||||
bool ad770x_data_ready(const ad770x_params_t *params, uint8_t channel)
|
||||
{
|
||||
prepare(channel, REG_COMM, true, params->cs_pin, false);
|
||||
return !(read_byte(params->cs_pin) & _BV(BIT_COMM_DRDY));
|
||||
}
|
||||
|
||||
uint16_t ad770x_raw_adc_value(const ad770x_params_t *params, uint8_t channel)
|
||||
{
|
||||
prepare(channel, REG_DATA, true, params->cs_pin, false);
|
||||
return read_word(params->cs_pin);
|
||||
}
|
||||
118
extras/ad770x/ad770x.h
Normal file
118
extras/ad770x/ad770x.h
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/**
|
||||
* Driver for AD7705/AD7706 SPI ADC
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2017 Ruslan V. Uss <unclerus@gmail.com>
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#ifndef _EXTRAS_AD770X_H_
|
||||
#define _EXTRAS_AD770X_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Input gain
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
AD770X_GAIN_1 = 0,
|
||||
AD770X_GAIN_2,
|
||||
AD770X_GAIN_4,
|
||||
AD770X_GAIN_8,
|
||||
AD770X_GAIN_16,
|
||||
AD770X_GAIN_32,
|
||||
AD770X_GAIN_64,
|
||||
AD770X_GAIN_128
|
||||
} ad770x_gain_t;
|
||||
|
||||
/**
|
||||
* Master clock frequency
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
AD770X_MCLK_1MHz = 0, //!< 1 MHz
|
||||
AD770X_MCLK_2MHz, //!< 2 MHz
|
||||
AD770X_MCLK_2_4576MHz, //!< 2.4576 MHz
|
||||
AD770X_MCLK_4_9152MHz, //!< 4.9152 MHz
|
||||
} ad770x_master_clock_t;
|
||||
|
||||
/**
|
||||
* Output update rate
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
AD770X_RATE_20 = 0, //!< Output update rate is 20 Hz, -3 dB filter cutoff = 5.24 Hz, works with 1 or 2 MHz master clock
|
||||
AD770X_RATE_25, //!< Output update rate is 25 Hz, -3 dB filter cutoff = 6.55 Hz, works with 1 or 2 MHz master clock
|
||||
AD770X_RATE_100, //!< Output update rate is 100 Hz, -3 dB filter cutoff = 26.2 Hz, works with 1 or 2 MHz master clock
|
||||
AD770X_RATE_200, //!< Output update rate is 200 Hz, -3 dB filter cutoff = 52.4 Hz, works with 1 or 2 MHz master clock
|
||||
AD770X_RATE_50, //!< Output update rate is 50 Hz, -3 dB filter cutoff = 13.1 Hz, works with 2.4576 or 4.9152 MHz master clock
|
||||
AD770X_RATE_60, //!< Output update rate is 60 Hz, -3 dB filter cutoff = 15.7 Hz, works with 2.4576 or 4.9152 MHz master clock
|
||||
AD770X_RATE_250, //!< Output update rate is 250 Hz, -3 dB filter cutoff = 65.5 Hz, works with 2.4576 or 4.9152 MHz master clock
|
||||
AD770X_RATE_500, //!< Output update rate is 500 Hz, -3 dB filter cutoff = 131 Hz, works with 2.4576 or 4.9152 MHz master clock
|
||||
} ad770x_update_rate_t;
|
||||
|
||||
/**
|
||||
* Device mode
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
AD770X_MODE_NORMAL = 0,
|
||||
AD770X_MODE_CALIBRATION,
|
||||
AD770X_MODE_ZERO_CALIBRATION,
|
||||
AD770X_MODE_FULL_CALIBRATION
|
||||
} ad770x_mode_t;
|
||||
|
||||
/**
|
||||
* Device descriptor
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t cs_pin; //!< GPIO pin for chip select
|
||||
ad770x_master_clock_t master_clock; //!< Master clock frequency
|
||||
bool bipolar; //!< Bipolar/Unipolar mode
|
||||
ad770x_gain_t gain; //!< Input gain
|
||||
ad770x_update_rate_t update_rate; //!< Output update rate
|
||||
} ad770x_params_t;
|
||||
|
||||
/**
|
||||
* Init device and setup channel params
|
||||
* @param params Device descriptor pointer
|
||||
* @param channel Input channel
|
||||
* @return Non-zero when error occured
|
||||
*/
|
||||
int ad770x_init(const ad770x_params_t *params, uint8_t channel);
|
||||
|
||||
/**
|
||||
* Set device mode (see datasheet)
|
||||
* @param params Device descriptor pointer
|
||||
* @param channel Input channel
|
||||
* @param mode Device mode
|
||||
*/
|
||||
void ad770x_set_mode(const ad770x_params_t *params, uint8_t channel, ad770x_mode_t mode);
|
||||
|
||||
/**
|
||||
* Get conversion status
|
||||
* @param params Device descriptor pointer
|
||||
* @param channel Input channel
|
||||
* @return true when data is ready
|
||||
*/
|
||||
bool ad770x_data_ready(const ad770x_params_t *params, uint8_t channel);
|
||||
|
||||
/**
|
||||
* Get converted ADC value
|
||||
* @param params Device descriptor pointer
|
||||
* @param channel Input channel
|
||||
* @return Raw ADC value
|
||||
*/
|
||||
uint16_t ad770x_raw_adc_value(const ad770x_params_t *params, uint8_t channel);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _EXTRAS_AD770X_H_ */
|
||||
9
extras/ad770x/component.mk
Normal file
9
extras/ad770x/component.mk
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# Component makefile for extras/ad770x (AD7705/AD7706 driver)
|
||||
|
||||
# expected anyone using ADC driver includes it as 'ad770x/ad770x.h'
|
||||
INC_DIRS += $(ad770x_ROOT)..
|
||||
|
||||
# args for passing into compile rule generation
|
||||
ad770x_SRC_DIR = $(ad770x_ROOT)
|
||||
|
||||
$(eval $(call component_compile_rules,ad770x))
|
||||
|
|
@ -6,7 +6,6 @@
|
|||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include "ads111x.h"
|
||||
#include <i2c/i2c.h>
|
||||
|
||||
#define ADS111X_DEBUG
|
||||
|
||||
|
|
@ -52,144 +51,144 @@ const float ads111x_gain_values[] = {
|
|||
[ADS111X_GAIN_0V256_3] = 0.256
|
||||
};
|
||||
|
||||
static uint16_t read_reg(uint8_t addr, uint8_t reg)
|
||||
static uint16_t read_reg(i2c_dev_t* dev, uint8_t reg)
|
||||
{
|
||||
uint16_t res = 0;
|
||||
if (!i2c_slave_read(addr, reg, (uint8_t *)&res, 2))
|
||||
if (i2c_slave_read(dev->bus, dev->addr, ®, (uint8_t *)&res, 2))
|
||||
debug("Could not read register %d", reg);
|
||||
//debug("Read %d: 0x%04x", reg, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void write_reg(uint8_t addr, uint8_t reg, uint16_t val)
|
||||
static void write_reg(i2c_dev_t* dev, uint8_t reg, uint16_t val)
|
||||
{
|
||||
//debug("Write %d: 0x%04x", reg, val);
|
||||
uint8_t buf[3] = {reg, val >> 8, val};
|
||||
if (!i2c_slave_write(addr, buf, 3))
|
||||
uint8_t buf[2] = { val >> 8, val};
|
||||
if (i2c_slave_write(dev->bus, dev->addr, ®, buf, 2))
|
||||
debug("Could not write 0x%04x to register %d", val, reg);
|
||||
}
|
||||
|
||||
static uint16_t read_conf_bits(uint8_t addr, uint8_t offs, uint16_t mask)
|
||||
static uint16_t read_conf_bits(i2c_dev_t* dev, uint8_t offs, uint16_t mask)
|
||||
{
|
||||
return (read_reg(addr, REG_CONFIG) >> offs) & mask;
|
||||
return (read_reg(dev, REG_CONFIG) >> offs) & mask;
|
||||
}
|
||||
|
||||
static void write_conf_bits(uint8_t addr, uint16_t val, uint8_t offs, uint16_t mask)
|
||||
static void write_conf_bits(i2c_dev_t* dev, uint16_t val, uint8_t offs, uint16_t mask)
|
||||
{
|
||||
write_reg(addr, REG_CONFIG, (read_reg(addr, REG_CONFIG) & ~(mask << offs)) | (val << offs));
|
||||
write_reg(dev, REG_CONFIG, (read_reg(dev, REG_CONFIG) & ~(mask << offs)) | (val << offs));
|
||||
}
|
||||
|
||||
bool ads111x_busy(uint8_t addr)
|
||||
bool ads111x_busy(i2c_dev_t* dev)
|
||||
{
|
||||
return read_conf_bits(addr, OS_OFFSET, OS_MASK);
|
||||
return read_conf_bits(dev, OS_OFFSET, OS_MASK);
|
||||
}
|
||||
|
||||
void ads111x_start_conversion(uint8_t addr)
|
||||
void ads111x_start_conversion(i2c_dev_t* dev)
|
||||
{
|
||||
write_conf_bits(addr, 1, OS_OFFSET, OS_MASK);
|
||||
write_conf_bits(dev, 1, OS_OFFSET, OS_MASK);
|
||||
}
|
||||
|
||||
int16_t ads111x_get_value(uint8_t addr)
|
||||
int16_t ads111x_get_value(i2c_dev_t* dev)
|
||||
{
|
||||
return read_reg(addr, REG_CONVERSION);
|
||||
return read_reg(dev, REG_CONVERSION);
|
||||
}
|
||||
|
||||
ads111x_gain_t ads111x_get_gain(uint8_t addr)
|
||||
ads111x_gain_t ads111x_get_gain(i2c_dev_t* dev)
|
||||
{
|
||||
return read_conf_bits(addr, PGA_OFFSET, PGA_MASK);
|
||||
return read_conf_bits(dev, PGA_OFFSET, PGA_MASK);
|
||||
}
|
||||
|
||||
void ads111x_set_gain(uint8_t addr, ads111x_gain_t gain)
|
||||
void ads111x_set_gain(i2c_dev_t* dev, ads111x_gain_t gain)
|
||||
{
|
||||
write_conf_bits(addr, gain, PGA_OFFSET, PGA_MASK);
|
||||
write_conf_bits(dev, gain, PGA_OFFSET, PGA_MASK);
|
||||
}
|
||||
|
||||
ads111x_mux_t ads111x_get_input_mux(uint8_t addr)
|
||||
ads111x_mux_t ads111x_get_input_mux(i2c_dev_t* dev)
|
||||
{
|
||||
return read_conf_bits(addr, MUX_OFFSET, MUX_MASK);
|
||||
return read_conf_bits(dev, MUX_OFFSET, MUX_MASK);
|
||||
}
|
||||
|
||||
void ads111x_set_input_mux(uint8_t addr, ads111x_mux_t mux)
|
||||
void ads111x_set_input_mux(i2c_dev_t* dev, ads111x_mux_t mux)
|
||||
{
|
||||
write_conf_bits(addr, mux, MUX_OFFSET, MUX_MASK);
|
||||
write_conf_bits(dev, mux, MUX_OFFSET, MUX_MASK);
|
||||
}
|
||||
|
||||
ads111x_mode_t ads111x_get_mode(uint8_t addr)
|
||||
ads111x_mode_t ads111x_get_mode(i2c_dev_t* dev)
|
||||
{
|
||||
return read_conf_bits(addr, MODE_OFFSET, MODE_MASK);
|
||||
return read_conf_bits(dev, MODE_OFFSET, MODE_MASK);
|
||||
}
|
||||
|
||||
void ads111x_set_mode(uint8_t addr, ads111x_mode_t mode)
|
||||
void ads111x_set_mode(i2c_dev_t* dev, ads111x_mode_t mode)
|
||||
{
|
||||
write_conf_bits(addr, mode, MODE_OFFSET, MODE_MASK);
|
||||
write_conf_bits(dev, mode, MODE_OFFSET, MODE_MASK);
|
||||
}
|
||||
|
||||
ads111x_data_rate_t ads111x_get_data_rate(uint8_t addr)
|
||||
ads111x_data_rate_t ads111x_get_data_rate(i2c_dev_t* dev)
|
||||
{
|
||||
return read_conf_bits(addr, DR_OFFSET, DR_MASK);
|
||||
return read_conf_bits(dev, DR_OFFSET, DR_MASK);
|
||||
}
|
||||
|
||||
void ads111x_set_data_rate(uint8_t addr, ads111x_data_rate_t rate)
|
||||
void ads111x_set_data_rate(i2c_dev_t* dev, ads111x_data_rate_t rate)
|
||||
{
|
||||
write_conf_bits(addr, rate, DR_OFFSET, DR_MASK);
|
||||
write_conf_bits(dev, rate, DR_OFFSET, DR_MASK);
|
||||
}
|
||||
|
||||
ads111x_comp_mode_t ads111x_get_comp_mode(uint8_t addr)
|
||||
ads111x_comp_mode_t ads111x_get_comp_mode(i2c_dev_t* dev)
|
||||
{
|
||||
return read_conf_bits(addr, COMP_MODE_OFFSET, COMP_MODE_MASK);
|
||||
return read_conf_bits(dev, COMP_MODE_OFFSET, COMP_MODE_MASK);
|
||||
}
|
||||
|
||||
void ads111x_set_comp_mode(uint8_t addr, ads111x_comp_mode_t mode)
|
||||
void ads111x_set_comp_mode(i2c_dev_t* dev, ads111x_comp_mode_t mode)
|
||||
{
|
||||
write_conf_bits(addr, mode, COMP_MODE_OFFSET, COMP_MODE_MASK);
|
||||
write_conf_bits(dev, mode, COMP_MODE_OFFSET, COMP_MODE_MASK);
|
||||
}
|
||||
|
||||
ads111x_comp_polarity_t ads111x_get_comp_polarity(uint8_t addr)
|
||||
ads111x_comp_polarity_t ads111x_get_comp_polarity(i2c_dev_t* dev)
|
||||
{
|
||||
return read_conf_bits(addr, COMP_POL_OFFSET, COMP_POL_MASK);
|
||||
return read_conf_bits(dev, COMP_POL_OFFSET, COMP_POL_MASK);
|
||||
}
|
||||
|
||||
void ads111x_set_comp_polarity(uint8_t addr, ads111x_comp_polarity_t polarity)
|
||||
void ads111x_set_comp_polarity(i2c_dev_t* dev, ads111x_comp_polarity_t polarity)
|
||||
{
|
||||
write_conf_bits(addr, polarity, COMP_POL_OFFSET, COMP_POL_MASK);
|
||||
write_conf_bits(dev, polarity, COMP_POL_OFFSET, COMP_POL_MASK);
|
||||
}
|
||||
|
||||
ads111x_comp_latch_t ads111x_get_comp_latch(uint8_t addr)
|
||||
ads111x_comp_latch_t ads111x_get_comp_latch(i2c_dev_t* dev)
|
||||
{
|
||||
return read_conf_bits(addr, COMP_LAT_OFFSET, COMP_LAT_MASK);
|
||||
return read_conf_bits(dev, COMP_LAT_OFFSET, COMP_LAT_MASK);
|
||||
}
|
||||
|
||||
void ads111x_set_comp_latch(uint8_t addr, ads111x_comp_latch_t latch)
|
||||
void ads111x_set_comp_latch(i2c_dev_t* dev, ads111x_comp_latch_t latch)
|
||||
{
|
||||
write_conf_bits(addr, latch, COMP_LAT_OFFSET, COMP_LAT_MASK);
|
||||
write_conf_bits(dev, latch, COMP_LAT_OFFSET, COMP_LAT_MASK);
|
||||
}
|
||||
|
||||
ads111x_comp_queue_t ads111x_get_comp_queue(uint8_t addr)
|
||||
ads111x_comp_queue_t ads111x_get_comp_queue(i2c_dev_t* dev)
|
||||
{
|
||||
return read_conf_bits(addr, COMP_QUE_OFFSET, COMP_QUE_MASK);
|
||||
return read_conf_bits(dev, COMP_QUE_OFFSET, COMP_QUE_MASK);
|
||||
}
|
||||
|
||||
void ads111x_set_comp_queue(uint8_t addr, ads111x_comp_queue_t queue)
|
||||
void ads111x_set_comp_queue(i2c_dev_t* dev, ads111x_comp_queue_t queue)
|
||||
{
|
||||
write_conf_bits(addr, queue, COMP_QUE_OFFSET, COMP_QUE_MASK);
|
||||
write_conf_bits(dev, queue, COMP_QUE_OFFSET, COMP_QUE_MASK);
|
||||
}
|
||||
|
||||
int16_t ads111x_get_comp_low_thresh(uint8_t addr)
|
||||
int16_t ads111x_get_comp_low_thresh(i2c_dev_t* dev)
|
||||
{
|
||||
return read_reg(addr, REG_THRESH_L);
|
||||
return read_reg(dev, REG_THRESH_L);
|
||||
}
|
||||
|
||||
void ads111x_set_comp_low_thresh(uint8_t addr, int16_t thresh)
|
||||
void ads111x_set_comp_low_thresh(i2c_dev_t* dev, int16_t thresh)
|
||||
{
|
||||
write_reg(addr, REG_THRESH_L, thresh);
|
||||
write_reg(dev, REG_THRESH_L, thresh);
|
||||
}
|
||||
|
||||
int16_t ads111x_get_comp_high_thresh(uint8_t addr)
|
||||
int16_t ads111x_get_comp_high_thresh(i2c_dev_t* dev)
|
||||
{
|
||||
return read_reg(addr, REG_THRESH_H);
|
||||
return read_reg(dev, REG_THRESH_H);
|
||||
}
|
||||
|
||||
void ads111x_set_comp_high_thresh(uint8_t addr, int16_t thresh)
|
||||
void ads111x_set_comp_high_thresh(i2c_dev_t* dev, int16_t thresh)
|
||||
{
|
||||
write_reg(addr, REG_THRESH_H, thresh);
|
||||
write_reg(dev, REG_THRESH_H, thresh);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <i2c/i2c.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
@ -124,20 +125,20 @@ typedef enum
|
|||
* @param addr Deivce address
|
||||
* @return true when device performing conversion
|
||||
*/
|
||||
bool ads111x_busy(uint8_t addr);
|
||||
bool ads111x_busy(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* Begin a single conversion (when in single-shot mode)
|
||||
* @param addr Deivce address
|
||||
*/
|
||||
void ads111x_start_conversion(uint8_t addr);
|
||||
void ads111x_start_conversion(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* Read last conversion result
|
||||
* @param addr
|
||||
* @return Last conversion result
|
||||
*/
|
||||
int16_t ads111x_get_value(uint8_t addr);
|
||||
int16_t ads111x_get_value(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* Read the programmable gain amplifier configuration
|
||||
|
|
@ -145,70 +146,70 @@ int16_t ads111x_get_value(uint8_t addr);
|
|||
* @param addr Deivce address
|
||||
* @return Gain value
|
||||
*/
|
||||
ads111x_gain_t ads111x_get_gain(uint8_t addr);
|
||||
ads111x_gain_t ads111x_get_gain(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* Configure the programmable gain amplifier (ADS1114 and ADS1115 only)
|
||||
* @param addr Deivce address
|
||||
* @param gain Gain value
|
||||
*/
|
||||
void ads111x_set_gain(uint8_t addr, ads111x_gain_t gain);
|
||||
void ads111x_set_gain(i2c_dev_t* dev, ads111x_gain_t gain);
|
||||
|
||||
/**
|
||||
* Read the input multiplexer configuration (ADS1115 only)
|
||||
* @param addr Deivce address
|
||||
* @return Input multiplexer configuration
|
||||
*/
|
||||
ads111x_mux_t ads111x_get_input_mux(uint8_t addr);
|
||||
ads111x_mux_t ads111x_get_input_mux(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* Configure the input multiplexer configuration (ADS1115 only)
|
||||
* @param addr Deivce address
|
||||
* @param mux Input multiplexer configuration
|
||||
*/
|
||||
void ads111x_set_input_mux(uint8_t addr, ads111x_mux_t mux);
|
||||
void ads111x_set_input_mux(i2c_dev_t* dev, ads111x_mux_t mux);
|
||||
|
||||
/**
|
||||
* Read the device operating mode
|
||||
* @param addr Deivce address
|
||||
* @return Device operating mode
|
||||
*/
|
||||
ads111x_mode_t ads111x_get_mode(uint8_t addr);
|
||||
ads111x_mode_t ads111x_get_mode(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* Set the device operating mode
|
||||
* @param addr Deivce address
|
||||
* @param mode Device operating mode
|
||||
*/
|
||||
void ads111x_set_mode(uint8_t addr, ads111x_mode_t mode);
|
||||
void ads111x_set_mode(i2c_dev_t* dev, ads111x_mode_t mode);
|
||||
|
||||
/**
|
||||
* Read the data rate
|
||||
* @param addr Deivce address
|
||||
* @return Data rate
|
||||
*/
|
||||
ads111x_data_rate_t ads111x_get_data_rate(uint8_t addr);
|
||||
ads111x_data_rate_t ads111x_get_data_rate(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* Configure the data rate
|
||||
* @param addr Deivce address
|
||||
* @param rate Data rate
|
||||
*/
|
||||
void ads111x_set_data_rate(uint8_t addr, ads111x_data_rate_t rate);
|
||||
void ads111x_set_data_rate(i2c_dev_t* dev, ads111x_data_rate_t rate);
|
||||
|
||||
/**
|
||||
* Get comparator mode (ADS1114 and ADS1115 only)
|
||||
* @param addr Deivce address
|
||||
* @return Comparator mode
|
||||
*/
|
||||
ads111x_comp_mode_t ads111x_get_comp_mode(uint8_t addr);
|
||||
ads111x_comp_mode_t ads111x_get_comp_mode(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* Set comparator mode (ADS1114 and ADS1115 only)
|
||||
* @param addr Deivce address
|
||||
* @param mode Comparator mode
|
||||
*/
|
||||
void ads111x_set_comp_mode(uint8_t addr, ads111x_comp_mode_t mode);
|
||||
void ads111x_set_comp_mode(i2c_dev_t* dev, ads111x_comp_mode_t mode);
|
||||
|
||||
/**
|
||||
* Get polarity of the comparator output pin ALERT/RDY
|
||||
|
|
@ -216,7 +217,7 @@ void ads111x_set_comp_mode(uint8_t addr, ads111x_comp_mode_t mode);
|
|||
* @param addr Deivce address
|
||||
* @return Comparator output pin polarity
|
||||
*/
|
||||
ads111x_comp_polarity_t ads111x_get_comp_polarity(uint8_t addr);
|
||||
ads111x_comp_polarity_t ads111x_get_comp_polarity(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* Set polarity of the comparator output pin ALERT/RDY
|
||||
|
|
@ -224,7 +225,7 @@ ads111x_comp_polarity_t ads111x_get_comp_polarity(uint8_t addr);
|
|||
* @param addr Deivce address
|
||||
* @param polarity Comparator output pin polarity
|
||||
*/
|
||||
void ads111x_set_comp_polarity(uint8_t addr, ads111x_comp_polarity_t polarity);
|
||||
void ads111x_set_comp_polarity(i2c_dev_t* dev, ads111x_comp_polarity_t polarity);
|
||||
|
||||
/**
|
||||
* Get comparator output latch mode, see datasheet.
|
||||
|
|
@ -232,14 +233,14 @@ void ads111x_set_comp_polarity(uint8_t addr, ads111x_comp_polarity_t polarity);
|
|||
* @param addr Deivce address
|
||||
* @return Comparator output latch mode
|
||||
*/
|
||||
ads111x_comp_latch_t ads111x_get_comp_latch(uint8_t addr);
|
||||
ads111x_comp_latch_t ads111x_get_comp_latch(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* Set comparator output latch mode (ADS1114 and ADS1115 only)
|
||||
* @param addr Deivce address
|
||||
* @param latch Comparator output latch mode
|
||||
*/
|
||||
void ads111x_set_comp_latch(uint8_t addr, ads111x_comp_latch_t latch);
|
||||
void ads111x_set_comp_latch(i2c_dev_t* dev, ads111x_comp_latch_t latch);
|
||||
|
||||
/**
|
||||
* Set number of the comparator conversions before pin ALERT/RDY
|
||||
|
|
@ -247,7 +248,7 @@ void ads111x_set_comp_latch(uint8_t addr, ads111x_comp_latch_t latch);
|
|||
* @param addr Deivce address
|
||||
* @return Number of the comparator conversions
|
||||
*/
|
||||
ads111x_comp_queue_t ads111x_get_comp_queue(uint8_t addr);
|
||||
ads111x_comp_queue_t ads111x_get_comp_queue(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* Get number of the comparator conversions before pin ALERT/RDY
|
||||
|
|
@ -255,35 +256,35 @@ ads111x_comp_queue_t ads111x_get_comp_queue(uint8_t addr);
|
|||
* @param addr Deivce address
|
||||
* @param queue Number of the comparator conversions
|
||||
*/
|
||||
void ads111x_set_comp_queue(uint8_t addr, ads111x_comp_queue_t queue);
|
||||
void ads111x_set_comp_queue(i2c_dev_t* dev, ads111x_comp_queue_t queue);
|
||||
|
||||
/**
|
||||
* Get the lower threshold value used by comparator
|
||||
* @param addr Deivce address
|
||||
* @return Lower threshold value
|
||||
*/
|
||||
int16_t ads111x_get_comp_low_thresh(uint8_t addr);
|
||||
int16_t ads111x_get_comp_low_thresh(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* Set the lower threshold value used by comparator
|
||||
* @param addr Deivce address
|
||||
* @param thresh Lower threshold value
|
||||
*/
|
||||
void ads111x_set_comp_low_thresh(uint8_t addr, int16_t thresh);
|
||||
void ads111x_set_comp_low_thresh(i2c_dev_t* dev, int16_t thresh);
|
||||
|
||||
/**
|
||||
* Get the upper threshold value used by comparator
|
||||
* @param addr Deivce address
|
||||
* @return Upper threshold value
|
||||
*/
|
||||
int16_t ads111x_get_comp_high_thresh(uint8_t addr);
|
||||
int16_t ads111x_get_comp_high_thresh(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* Set the upper threshold value used by comparator
|
||||
* @param addr Deivce address
|
||||
* @param thresh Upper threshold value
|
||||
*/
|
||||
void ads111x_set_comp_high_thresh(uint8_t addr, int16_t thresh);
|
||||
void ads111x_set_comp_high_thresh(i2c_dev_t* dev, int16_t thresh);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit f0c00466018e4bcdaa2d965ac723d53f015cde9a
|
||||
Subproject commit 2b738493bd16d57fdb12d38d03631981370259be
|
||||
27
extras/bh1750/bh1750.c
Normal file
27
extras/bh1750/bh1750.c
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Driver for BH1750 light sensor
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2017 Andrej Krutak <dev@andree.sk>
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include "bh1750.h"
|
||||
#include <stdio.h>
|
||||
|
||||
void bh1750_configure(i2c_dev_t *dev, uint8_t mode)
|
||||
{
|
||||
i2c_slave_write(dev->bus, dev->addr, NULL, &mode, 1);
|
||||
}
|
||||
|
||||
uint16_t bh1750_read(i2c_dev_t *dev)
|
||||
{
|
||||
uint8_t buf[2];
|
||||
uint16_t level;
|
||||
|
||||
i2c_slave_read(dev->bus, dev->addr, NULL, buf, 2);
|
||||
|
||||
level = buf[0] << 8 | buf[1];
|
||||
level = (level * 10) / 12; // convert to LUX
|
||||
|
||||
return level;
|
||||
}
|
||||
83
extras/bh1750/bh1750.h
Normal file
83
extras/bh1750/bh1750.h
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Driver for BH1750 light sensor
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2017 Andrej Krutak <dev@andree.sk>
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*
|
||||
* ROHM Semiconductor bh1750fvi-e.pdf
|
||||
*/
|
||||
#ifndef EXTRAS_BH1750_H_
|
||||
#define EXTRAS_BH1750_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
#include <i2c/i2c.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Possible chip addresses */
|
||||
#define BH1750_ADDR_LO 0x23 // ADDR pin floating/low
|
||||
#define BH1750_ADDR_HI 0x5c
|
||||
|
||||
|
||||
/* Configuration options */
|
||||
|
||||
// No active state
|
||||
#define BH1750_POWER_DOWN 0x00
|
||||
|
||||
// Wating for measurement command
|
||||
#define BH1750_POWER_ON 0x01
|
||||
|
||||
// Reset data register value - not accepted in POWER_DOWN mode
|
||||
#define BH1750_RESET 0x07
|
||||
|
||||
|
||||
/* Measurement modes */
|
||||
|
||||
#define BH1750_CONTINUOUS_MODE 0x10
|
||||
#define BH1750_ONE_TIME_MODE 0x20
|
||||
|
||||
// Start measurement at 1 lx resolution (measurement time typically 120ms)
|
||||
#define BH1750_HIGH_RES_MODE 0x00
|
||||
// Start measurement at 0.5 lx resolution (measurement time typically 120ms)
|
||||
#define BH1750_HIGH_RES_MODE2 0x01
|
||||
// Start measurement at 4 lx resolution (measurement time typically 16ms)
|
||||
#define BH1750_LOW_RES_MODE 0x03
|
||||
|
||||
/* Adjust measurement time to account for optical window size (see datasheet).
|
||||
* Procedure from datasheet suggests order Hi, Low and finally measurement mode
|
||||
*/
|
||||
#define BH1750_MEASURE_TIME_HI(mt) (0x40 | (((mt) >> 5) & 0x7))
|
||||
#define BH1750_MEASURE_TIME_LO(mt) (0x60 | ((mt) & 0x1f))
|
||||
#define BH1750_DEFAULT_MEASURE_TIME 0x45
|
||||
|
||||
|
||||
/**
|
||||
* Configure the device.
|
||||
* @param addr Device address
|
||||
* @param mode Combination of BH1750_* flags
|
||||
*
|
||||
* May be called multiple times e.g. to configure the measurement time and
|
||||
* the readout mode afterwards - or if one time mode is used consecutively.
|
||||
*
|
||||
* Example: BH1750_ADDR_LO, BH1750_CONTINUOUS_MODE | BH1750_HIGH_RES_MODE
|
||||
*/
|
||||
void bh1750_configure(i2c_dev_t *dev, uint8_t mode);
|
||||
|
||||
/**
|
||||
* Read LUX value from the device.
|
||||
*
|
||||
* @param addr Device address
|
||||
* @returns read value in lux units
|
||||
*/
|
||||
uint16_t bh1750_read(i2c_dev_t *dev);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* EXTRAS_BH1750_H_ */
|
||||
9
extras/bh1750/component.mk
Normal file
9
extras/bh1750/component.mk
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# Component makefile for extras/bh1750
|
||||
|
||||
# expected anyone using RTC driver includes it as 'bh1750/bh1750.h'
|
||||
INC_DIRS += $(bh1750_ROOT)..
|
||||
|
||||
# args for passing into compile rule generation
|
||||
bh1750_SRC_DIR = $(bh1750_ROOT)
|
||||
|
||||
$(eval $(call component_compile_rules,bh1750))
|
||||
|
|
@ -7,13 +7,9 @@
|
|||
#include "espressif/esp_common.h"
|
||||
#include "espressif/sdk_private.h"
|
||||
|
||||
#include "i2c/i2c.h"
|
||||
|
||||
#define BMP180_RX_QUEUE_SIZE 10
|
||||
#define BMP180_TASK_PRIORITY 9
|
||||
|
||||
#define BMP180_DEVICE_ADDRESS 0x77
|
||||
|
||||
#define BMP180_VERSION_REG 0xD0
|
||||
#define BMP180_CONTROL_REG 0xF4
|
||||
#define BMP180_RESET_REG 0xE0
|
||||
|
|
@ -39,42 +35,43 @@
|
|||
//
|
||||
#define BMP180_RESET_VALUE 0xB6
|
||||
|
||||
static bool bmp180_readRegister16(uint8_t reg, int16_t *r)
|
||||
static int bmp180_readRegister16(i2c_dev_t *dev, uint8_t reg, int16_t *r)
|
||||
{
|
||||
uint8_t d[] = { 0, 0 };
|
||||
int error ;
|
||||
|
||||
if (!i2c_slave_read(BMP180_DEVICE_ADDRESS, reg, d, 2))
|
||||
return false;
|
||||
if ((error = i2c_slave_read(dev->bus, dev->addr, ®, d, 2)))
|
||||
return error;
|
||||
|
||||
*r = ((int16_t)d[0] << 8) | (d[1]);
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool bmp180_start_Messurement(uint8_t cmd)
|
||||
static int bmp180_start_Messurement(i2c_dev_t *dev, uint8_t cmd)
|
||||
{
|
||||
uint8_t d[] = { BMP180_CONTROL_REG, cmd };
|
||||
uint8_t reg = BMP180_CONTROL_REG ;
|
||||
|
||||
return i2c_slave_write(BMP180_DEVICE_ADDRESS, d, 2);
|
||||
return i2c_slave_write(dev->bus, dev->addr, ®, &cmd, 1);
|
||||
}
|
||||
|
||||
static bool bmp180_get_uncompensated_temperature(int32_t *ut)
|
||||
static bool bmp180_get_uncompensated_temperature(i2c_dev_t *dev, int32_t *ut)
|
||||
{
|
||||
// Write Start Code into reg 0xF4.
|
||||
if (!bmp180_start_Messurement(BMP180_MEASURE_TEMP))
|
||||
if (bmp180_start_Messurement(dev, BMP180_MEASURE_TEMP))
|
||||
return false;
|
||||
|
||||
// Wait 5ms, datasheet states 4.5ms
|
||||
sdk_os_delay_us(5000);
|
||||
|
||||
int16_t v;
|
||||
if (!bmp180_readRegister16(BMP180_OUT_MSB_REG, &v))
|
||||
if (bmp180_readRegister16(dev, BMP180_OUT_MSB_REG, &v))
|
||||
return false;
|
||||
|
||||
*ut = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool bmp180_get_uncompensated_pressure(uint8_t oss, uint32_t *up)
|
||||
static bool bmp180_get_uncompensated_pressure(i2c_dev_t *dev, uint8_t oss, uint32_t *up)
|
||||
{
|
||||
uint16_t us;
|
||||
|
||||
|
|
@ -88,13 +85,14 @@ static bool bmp180_get_uncompensated_pressure(uint8_t oss, uint32_t *up)
|
|||
}
|
||||
|
||||
// Write Start Code into reg 0xF4
|
||||
if (!bmp180_start_Messurement(BMP180_MEASURE_PRESS | (oss << 6)))
|
||||
if (bmp180_start_Messurement(dev, BMP180_MEASURE_PRESS | (oss << 6)))
|
||||
return false;
|
||||
|
||||
sdk_os_delay_us(us);
|
||||
|
||||
uint8_t d[] = { 0, 0, 0 };
|
||||
if (!i2c_slave_read(BMP180_DEVICE_ADDRESS, BMP180_OUT_MSB_REG, d, 3))
|
||||
uint8_t reg = BMP180_OUT_MSB_REG;
|
||||
if (i2c_slave_read(dev->bus, dev->addr, ®, d, 3))
|
||||
return false;
|
||||
|
||||
uint32_t r = ((uint32_t)d[0] << 16) | ((uint32_t)d[1] << 8) | d[2];
|
||||
|
|
@ -104,19 +102,19 @@ static bool bmp180_get_uncompensated_pressure(uint8_t oss, uint32_t *up)
|
|||
}
|
||||
|
||||
// Returns true of success else false.
|
||||
bool bmp180_fillInternalConstants(bmp180_constants_t *c)
|
||||
bool bmp180_fillInternalConstants(i2c_dev_t *dev, bmp180_constants_t *c)
|
||||
{
|
||||
if (!bmp180_readRegister16(BMP180_CALIBRATION_REG+0, &c->AC1) ||
|
||||
!bmp180_readRegister16(BMP180_CALIBRATION_REG+2, &c->AC2) ||
|
||||
!bmp180_readRegister16(BMP180_CALIBRATION_REG+4, &c->AC3) ||
|
||||
!bmp180_readRegister16(BMP180_CALIBRATION_REG+6, (int16_t *)&c->AC4) ||
|
||||
!bmp180_readRegister16(BMP180_CALIBRATION_REG+8, (int16_t *)&c->AC5) ||
|
||||
!bmp180_readRegister16(BMP180_CALIBRATION_REG+10, (int16_t *)&c->AC6) ||
|
||||
!bmp180_readRegister16(BMP180_CALIBRATION_REG+12, &c->B1) ||
|
||||
!bmp180_readRegister16(BMP180_CALIBRATION_REG+14, &c->B2) ||
|
||||
!bmp180_readRegister16(BMP180_CALIBRATION_REG+16, &c->MB) ||
|
||||
!bmp180_readRegister16(BMP180_CALIBRATION_REG+18, &c->MC) ||
|
||||
!bmp180_readRegister16(BMP180_CALIBRATION_REG+20, &c->MD)) {
|
||||
if (bmp180_readRegister16(dev, BMP180_CALIBRATION_REG+0, &c->AC1) ||
|
||||
bmp180_readRegister16(dev, BMP180_CALIBRATION_REG+2, &c->AC2) ||
|
||||
bmp180_readRegister16(dev, BMP180_CALIBRATION_REG+4, &c->AC3) ||
|
||||
bmp180_readRegister16(dev, BMP180_CALIBRATION_REG+6, (int16_t *)&c->AC4) ||
|
||||
bmp180_readRegister16(dev, BMP180_CALIBRATION_REG+8, (int16_t *)&c->AC5) ||
|
||||
bmp180_readRegister16(dev, BMP180_CALIBRATION_REG+10, (int16_t *)&c->AC6) ||
|
||||
bmp180_readRegister16(dev, BMP180_CALIBRATION_REG+12, &c->B1) ||
|
||||
bmp180_readRegister16(dev, BMP180_CALIBRATION_REG+14, &c->B2) ||
|
||||
bmp180_readRegister16(dev, BMP180_CALIBRATION_REG+16, &c->MB) ||
|
||||
bmp180_readRegister16(dev, BMP180_CALIBRATION_REG+18, &c->MC) ||
|
||||
bmp180_readRegister16(dev, BMP180_CALIBRATION_REG+20, &c->MD)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -137,14 +135,16 @@ bool bmp180_fillInternalConstants(bmp180_constants_t *c)
|
|||
c->MB == 0xffff || c->MC == 0xffff || c->MD == 0xffff);
|
||||
}
|
||||
|
||||
bool bmp180_is_available()
|
||||
bool bmp180_is_available(i2c_dev_t *dev)
|
||||
{
|
||||
uint8_t id;
|
||||
return i2c_slave_read(BMP180_DEVICE_ADDRESS, BMP180_VERSION_REG, &id, 1) &&
|
||||
id == BMP180_CHIP_ID;
|
||||
uint8_t reg = BMP180_VERSION_REG;
|
||||
if (i2c_slave_read(dev->bus, dev->addr, ®, &id, 1))
|
||||
return false;
|
||||
return id == BMP180_CHIP_ID;
|
||||
}
|
||||
|
||||
bool bmp180_measure(bmp180_constants_t *c, int32_t *temperature,
|
||||
bool bmp180_measure(i2c_dev_t *dev, bmp180_constants_t *c, int32_t *temperature,
|
||||
uint32_t *pressure, uint8_t oss)
|
||||
{
|
||||
int32_t T, P;
|
||||
|
|
@ -152,11 +152,11 @@ bool bmp180_measure(bmp180_constants_t *c, int32_t *temperature,
|
|||
if (!temperature && !pressure)
|
||||
return false;
|
||||
|
||||
// Temperature is always needed, allso required for pressure only.
|
||||
// Temperature is always needed, also required for pressure only.
|
||||
//
|
||||
// Calculation taken from BMP180 Datasheet
|
||||
int32_t UT, X1, X2, B5;
|
||||
if (!bmp180_get_uncompensated_temperature(&UT))
|
||||
if (!bmp180_get_uncompensated_temperature(dev, &UT))
|
||||
return false;
|
||||
|
||||
X1 = ((UT - (int32_t)c->AC6) * (int32_t)c->AC5) >> 15;
|
||||
|
|
@ -173,7 +173,7 @@ bool bmp180_measure(bmp180_constants_t *c, int32_t *temperature,
|
|||
int32_t X3, B3, B6;
|
||||
uint32_t B4, B7, UP;
|
||||
|
||||
if (!bmp180_get_uncompensated_pressure(oss, &UP))
|
||||
if (!bmp180_get_uncompensated_pressure(dev, oss, &UP))
|
||||
return false;
|
||||
|
||||
// Calculation taken from BMP180 Datasheet
|
||||
|
|
@ -208,8 +208,6 @@ bool bmp180_measure(bmp180_constants_t *c, int32_t *temperature,
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// BMP180_Event_Command
|
||||
typedef struct
|
||||
{
|
||||
|
|
@ -218,8 +216,8 @@ typedef struct
|
|||
} bmp180_command_t;
|
||||
|
||||
// Just works due to the fact that QueueHandle_t is a "void *"
|
||||
static QueueHandle_t bmp180_rx_queue = NULL;
|
||||
static TaskHandle_t bmp180_task_handle = NULL;
|
||||
static QueueHandle_t bmp180_rx_queue[MAX_I2C_BUS] = { NULL };
|
||||
static TaskHandle_t bmp180_task_handle[MAX_I2C_BUS] = { NULL };
|
||||
|
||||
//
|
||||
// Forward declarations
|
||||
|
|
@ -235,6 +233,7 @@ static void bmp180_driver_task(void *pvParameters)
|
|||
// Data to be received from user
|
||||
bmp180_command_t current_command;
|
||||
bmp180_constants_t bmp180_constants;
|
||||
i2c_dev_t *dev = (i2c_dev_t*)pvParameters;
|
||||
|
||||
#ifdef BMP180_DEBUG
|
||||
// Wait for commands from the outside
|
||||
|
|
@ -242,14 +241,14 @@ static void bmp180_driver_task(void *pvParameters)
|
|||
#endif
|
||||
|
||||
// Initialize all internal constants.
|
||||
if (!bmp180_fillInternalConstants(&bmp180_constants)) {
|
||||
if (!bmp180_fillInternalConstants(dev, &bmp180_constants)) {
|
||||
printf("%s: reading internal constants failed\n", __FUNCTION__);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
while(1) {
|
||||
// Wait for user to insert commands
|
||||
if (xQueueReceive(bmp180_rx_queue, ¤t_command, portMAX_DELAY) == pdTRUE) {
|
||||
if (xQueueReceive(bmp180_rx_queue[dev->bus], ¤t_command, portMAX_DELAY) == pdTRUE) {
|
||||
#ifdef BMP180_DEBUG
|
||||
printf("%s: Received user command %d 0x%p\n", __FUNCTION__, current_command.cmd, current_command.resultQueue);
|
||||
#endif
|
||||
|
|
@ -259,7 +258,7 @@ static void bmp180_driver_task(void *pvParameters)
|
|||
int32_t T = 0;
|
||||
uint32_t P = 0;
|
||||
|
||||
if (bmp180_measure(&bmp180_constants, &T, (current_command.cmd & BMP180_PRESSURE) ? &P : NULL, 3)) {
|
||||
if (bmp180_measure(dev, &bmp180_constants, &T, (current_command.cmd & BMP180_PRESSURE) ? &P : NULL, 3)) {
|
||||
// Inform the user ...
|
||||
if (!bmp180_informUser(current_command.resultQueue,
|
||||
current_command.cmd,
|
||||
|
|
@ -274,22 +273,22 @@ static void bmp180_driver_task(void *pvParameters)
|
|||
}
|
||||
}
|
||||
|
||||
static bool bmp180_create_communication_queues()
|
||||
static bool bmp180_create_communication_queues(i2c_dev_t *dev)
|
||||
{
|
||||
// Just create them once
|
||||
if (bmp180_rx_queue == NULL)
|
||||
bmp180_rx_queue = xQueueCreate(BMP180_RX_QUEUE_SIZE, sizeof(bmp180_result_t));
|
||||
// Just create them once by bus
|
||||
if (bmp180_rx_queue[dev->bus] == NULL)
|
||||
bmp180_rx_queue[dev->bus] = xQueueCreate(BMP180_RX_QUEUE_SIZE, sizeof(bmp180_result_t));
|
||||
|
||||
return bmp180_rx_queue != NULL;
|
||||
return bmp180_rx_queue[dev->bus] != NULL;
|
||||
}
|
||||
|
||||
static bool bmp180_createTask()
|
||||
static bool bmp180_createTask(i2c_dev_t *dev)
|
||||
{
|
||||
// We already have a task
|
||||
portBASE_TYPE x = pdPASS;
|
||||
|
||||
if (bmp180_task_handle == NULL) {
|
||||
x = xTaskCreate(bmp180_driver_task, "bmp180_driver_task", 256, NULL, BMP180_TASK_PRIORITY, &bmp180_task_handle);
|
||||
if (bmp180_task_handle[dev->bus] == NULL) {
|
||||
x = xTaskCreate(bmp180_driver_task, "bmp180_driver_task", 256, (void*)dev, BMP180_TASK_PRIORITY, &bmp180_task_handle[dev->bus]); //TODO: name task with i2c bus
|
||||
}
|
||||
return x == pdPASS;
|
||||
}
|
||||
|
|
@ -307,54 +306,51 @@ static bool bmp180_informUser_Impl(const QueueHandle_t* resultQueue, uint8_t cmd
|
|||
}
|
||||
|
||||
// Just init all needed queues
|
||||
bool bmp180_init(uint8_t scl, uint8_t sda)
|
||||
bool bmp180_init(i2c_dev_t *dev)
|
||||
{
|
||||
// 1. Create required queues
|
||||
bool result = false;
|
||||
|
||||
if (bmp180_create_communication_queues()) {
|
||||
// 2. Init i2c driver
|
||||
i2c_init(scl, sda);
|
||||
// 3. Check for bmp180 ...
|
||||
if (bmp180_is_available()) {
|
||||
// 4. Start driver task
|
||||
if (bmp180_createTask()) {
|
||||
if (bmp180_create_communication_queues(dev)) {
|
||||
// 2. Check for bmp180 ...
|
||||
if (bmp180_is_available(dev)) {
|
||||
// 3. Start driver task
|
||||
if (bmp180_createTask(dev)) {
|
||||
// We are finished
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void bmp180_trigger_measurement(const QueueHandle_t* resultQueue)
|
||||
void bmp180_trigger_measurement(i2c_dev_t *dev, const QueueHandle_t* resultQueue)
|
||||
{
|
||||
bmp180_command_t c;
|
||||
|
||||
c.cmd = BMP180_PRESSURE + BMP180_TEMPERATURE;
|
||||
c.resultQueue = resultQueue;
|
||||
|
||||
xQueueSend(bmp180_rx_queue, &c, 0);
|
||||
xQueueSend(bmp180_rx_queue[dev->bus], &c, 0);
|
||||
}
|
||||
|
||||
|
||||
void bmp180_trigger_pressure_measurement(const QueueHandle_t* resultQueue)
|
||||
void bmp180_trigger_pressure_measurement(i2c_dev_t *dev, const QueueHandle_t* resultQueue)
|
||||
{
|
||||
bmp180_command_t c;
|
||||
|
||||
c.cmd = BMP180_PRESSURE;
|
||||
c.resultQueue = resultQueue;
|
||||
|
||||
xQueueSend(bmp180_rx_queue, &c, 0);
|
||||
xQueueSend(bmp180_rx_queue[dev->bus], &c, 0);
|
||||
}
|
||||
|
||||
void bmp180_trigger_temperature_measurement(const QueueHandle_t* resultQueue)
|
||||
void bmp180_trigger_temperature_measurement(i2c_dev_t *dev, const QueueHandle_t* resultQueue)
|
||||
{
|
||||
bmp180_command_t c;
|
||||
|
||||
c.cmd = BMP180_TEMPERATURE;
|
||||
c.resultQueue = resultQueue;
|
||||
|
||||
xQueueSend(bmp180_rx_queue, &c, 0);
|
||||
xQueueSend(bmp180_rx_queue[dev->bus], &c, 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,9 +14,13 @@
|
|||
#include "FreeRTOS.h"
|
||||
#include "queue.h"
|
||||
|
||||
#include "i2c/i2c.h"
|
||||
|
||||
// Uncomment to enable debug output
|
||||
//#define BMP180_DEBUG
|
||||
|
||||
#define BMP180_DEVICE_ADDRESS 0x77
|
||||
|
||||
#define BMP180_TEMPERATURE (1<<0)
|
||||
#define BMP180_PRESSURE (1<<1)
|
||||
|
||||
|
|
@ -42,16 +46,16 @@ typedef struct
|
|||
} bmp180_result_t;
|
||||
|
||||
// Init bmp180 driver ...
|
||||
bool bmp180_init(uint8_t scl, uint8_t sda);
|
||||
bool bmp180_init(i2c_dev_t *dev);
|
||||
|
||||
// Trigger a "complete" measurement (temperature and pressure will be valid when given to "bmp180_informUser)
|
||||
void bmp180_trigger_measurement(const QueueHandle_t* resultQueue);
|
||||
void bmp180_trigger_measurement(i2c_dev_t *dev, const QueueHandle_t* resultQueue);
|
||||
|
||||
// Trigger a "temperature only" measurement (only temperature will be valid when given to "bmp180_informUser)
|
||||
void bmp180_trigger_temperature_measurement(const QueueHandle_t* resultQueue);
|
||||
void bmp180_trigger_temperature_measurement(i2c_dev_t *dev, const QueueHandle_t* resultQueue);
|
||||
|
||||
// Trigger a "pressure only" measurement (only pressure will be valid when given to "bmp180_informUser)
|
||||
void bmp180_trigger_pressure_measurement(const QueueHandle_t* resultQueue);
|
||||
void bmp180_trigger_pressure_measurement(i2c_dev_t *dev, const QueueHandle_t* resultQueue);
|
||||
|
||||
// Give the user the chance to create it's own handler
|
||||
extern bool (*bmp180_informUser)(const QueueHandle_t* resultQueue, uint8_t cmd, bmp180_temp_t temperature, bmp180_press_t pressure);
|
||||
|
|
@ -75,12 +79,12 @@ typedef struct
|
|||
} bmp180_constants_t;
|
||||
|
||||
// Returns true if the bmp180 is detected.
|
||||
bool bmp180_is_available();
|
||||
bool bmp180_is_available(i2c_dev_t *dev);
|
||||
// Reads all the internal constants, returning true on success.
|
||||
bool bmp180_fillInternalConstants(bmp180_constants_t *c);
|
||||
bool bmp180_fillInternalConstants(i2c_dev_t *dev, bmp180_constants_t *c);
|
||||
// Reads an optional temperature and pressure. The over sampling
|
||||
// setting, oss, may be 0 to 3. Returns true on success.
|
||||
bool bmp180_measure(bmp180_constants_t *c, int32_t *temperature,
|
||||
bool bmp180_measure(i2c_dev_t *dev, bmp180_constants_t *c, int32_t *temperature,
|
||||
uint32_t *pressure, uint8_t oss);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
*/
|
||||
#include <stddef.h>
|
||||
#include "bmp280.h"
|
||||
#include "i2c/i2c.h"
|
||||
|
||||
#ifdef BMP280_DEBUG
|
||||
#include <stdio.h>
|
||||
|
|
@ -66,32 +65,36 @@ void bmp280_init_default_params(bmp280_params_t *params)
|
|||
params->standby = BMP280_STANDBY_250;
|
||||
}
|
||||
|
||||
static bool read_register16(uint8_t i2c_addr, uint8_t addr, uint16_t *value)
|
||||
static bool read_register16(i2c_dev_t* dev, uint8_t addr, uint16_t *value)
|
||||
{
|
||||
uint8_t d[] = {0, 0};
|
||||
if (i2c_slave_read(i2c_addr, addr, d, sizeof(d))) {
|
||||
if (!i2c_slave_read(dev->bus, dev->addr, &addr, d, sizeof(d))) {
|
||||
*value = d[0] | (d[1] << 8);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int read_data(i2c_dev_t* dev, uint8_t addr, uint8_t *value, uint8_t len)
|
||||
{
|
||||
return i2c_slave_read(dev->bus, dev->addr, &addr, value, len);
|
||||
}
|
||||
|
||||
static bool read_calibration_data(bmp280_t *dev)
|
||||
{
|
||||
uint8_t i2c_addr = dev->i2c_addr;
|
||||
|
||||
if (read_register16(i2c_addr, 0x88, &dev->dig_T1) &&
|
||||
read_register16(i2c_addr, 0x8a, (uint16_t *)&dev->dig_T2) &&
|
||||
read_register16(i2c_addr, 0x8c, (uint16_t *)&dev->dig_T3) &&
|
||||
read_register16(i2c_addr, 0x8e, &dev->dig_P1) &&
|
||||
read_register16(i2c_addr, 0x90, (uint16_t *)&dev->dig_P2) &&
|
||||
read_register16(i2c_addr, 0x92, (uint16_t *)&dev->dig_P3) &&
|
||||
read_register16(i2c_addr, 0x94, (uint16_t *)&dev->dig_P4) &&
|
||||
read_register16(i2c_addr, 0x96, (uint16_t *)&dev->dig_P5) &&
|
||||
read_register16(i2c_addr, 0x98, (uint16_t *)&dev->dig_P6) &&
|
||||
read_register16(i2c_addr, 0x9a, (uint16_t *)&dev->dig_P7) &&
|
||||
read_register16(i2c_addr, 0x9c, (uint16_t *)&dev->dig_P8) &&
|
||||
read_register16(i2c_addr, 0x9e, (uint16_t *)&dev->dig_P9)) {
|
||||
if (read_register16(&dev->i2c_dev, 0x88, &dev->dig_T1) &&
|
||||
read_register16(&dev->i2c_dev, 0x8a, (uint16_t *)&dev->dig_T2) &&
|
||||
read_register16(&dev->i2c_dev, 0x8c, (uint16_t *)&dev->dig_T3) &&
|
||||
read_register16(&dev->i2c_dev, 0x8e, &dev->dig_P1) &&
|
||||
read_register16(&dev->i2c_dev, 0x90, (uint16_t *)&dev->dig_P2) &&
|
||||
read_register16(&dev->i2c_dev, 0x92, (uint16_t *)&dev->dig_P3) &&
|
||||
read_register16(&dev->i2c_dev, 0x94, (uint16_t *)&dev->dig_P4) &&
|
||||
read_register16(&dev->i2c_dev, 0x96, (uint16_t *)&dev->dig_P5) &&
|
||||
read_register16(&dev->i2c_dev, 0x98, (uint16_t *)&dev->dig_P6) &&
|
||||
read_register16(&dev->i2c_dev, 0x9a, (uint16_t *)&dev->dig_P7) &&
|
||||
read_register16(&dev->i2c_dev, 0x9c, (uint16_t *)&dev->dig_P8) &&
|
||||
read_register16(&dev->i2c_dev, 0x9e, (uint16_t *)&dev->dig_P9)) {
|
||||
|
||||
debug("Calibration data received:");
|
||||
debug("dig_T1=%d", dev->dig_T1);
|
||||
|
|
@ -115,15 +118,14 @@ static bool read_calibration_data(bmp280_t *dev)
|
|||
|
||||
static bool read_hum_calibration_data(bmp280_t *dev)
|
||||
{
|
||||
uint8_t i2c_addr = dev->i2c_addr;
|
||||
uint16_t h4, h5;
|
||||
|
||||
if (i2c_slave_read(i2c_addr, 0xa1, &dev->dig_H1, 1) &&
|
||||
read_register16(i2c_addr, 0xe1, (uint16_t *)&dev->dig_H2) &&
|
||||
i2c_slave_read(i2c_addr, 0xe3, &dev->dig_H3, 1) &&
|
||||
read_register16(i2c_addr, 0xe4, &h4) &&
|
||||
read_register16(i2c_addr, 0xe5, &h5) &&
|
||||
i2c_slave_read(i2c_addr, 0xe7, (uint8_t *)&dev->dig_H6, 1)) {
|
||||
if (!read_data(&dev->i2c_dev, 0xa1, &dev->dig_H1, 1) &&
|
||||
read_register16(&dev->i2c_dev, 0xe1, (uint16_t *)&dev->dig_H2) &&
|
||||
!read_data(&dev->i2c_dev, 0xe3, &dev->dig_H3, 1) &&
|
||||
read_register16(&dev->i2c_dev, 0xe4, &h4) &&
|
||||
read_register16(&dev->i2c_dev, 0xe5, &h5) &&
|
||||
!read_data(&dev->i2c_dev, 0xe7, (uint8_t *)&dev->dig_H6, 1)) {
|
||||
dev->dig_H4 = (h4 & 0x00ff) << 4 | (h4 & 0x0f00) >> 8;
|
||||
dev->dig_H5 = h5 >> 4;
|
||||
debug("Calibration data received:");
|
||||
|
|
@ -139,23 +141,20 @@ static bool read_hum_calibration_data(bmp280_t *dev)
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool write_register8(uint8_t i2c_addr, uint8_t addr, uint8_t value)
|
||||
static int write_register8(i2c_dev_t* dev, uint8_t addr, uint8_t value)
|
||||
{
|
||||
uint8_t d[] = {addr, value};
|
||||
|
||||
return i2c_slave_write(i2c_addr, d, 2);
|
||||
return i2c_slave_write(dev->bus, dev->addr, &addr, &value, 1);
|
||||
}
|
||||
|
||||
bool bmp280_init(bmp280_t *dev, bmp280_params_t *params)
|
||||
{
|
||||
uint8_t i2c_addr = dev->i2c_addr;
|
||||
|
||||
if (i2c_addr != BMP280_I2C_ADDRESS_0 && i2c_addr != BMP280_I2C_ADDRESS_1) {
|
||||
if (dev->i2c_dev.addr != BMP280_I2C_ADDRESS_0 && dev->i2c_dev.addr != BMP280_I2C_ADDRESS_1) {
|
||||
debug("Invalid I2C address");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!i2c_slave_read(i2c_addr, BMP280_REG_ID, &dev->id, 1)) {
|
||||
if (read_data(&dev->i2c_dev, BMP280_REG_ID, &dev->id, 1)) {
|
||||
debug("Sensor not found");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -166,7 +165,7 @@ bool bmp280_init(bmp280_t *dev, bmp280_params_t *params)
|
|||
}
|
||||
|
||||
// Soft reset.
|
||||
if (!write_register8(i2c_addr, BMP280_REG_RESET, BMP280_RESET_VALUE)) {
|
||||
if (write_register8(&dev->i2c_dev, BMP280_REG_RESET, BMP280_RESET_VALUE)) {
|
||||
debug("Failed resetting sensor");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -174,7 +173,7 @@ bool bmp280_init(bmp280_t *dev, bmp280_params_t *params)
|
|||
// Wait until finished copying over the NVP data.
|
||||
while (1) {
|
||||
uint8_t status;
|
||||
if (i2c_slave_read(i2c_addr, BMP280_REG_STATUS, &status, 1) && (status & 1) == 0)
|
||||
if (!read_data(&dev->i2c_dev, BMP280_REG_STATUS, &status, 1) && (status & 1) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -190,7 +189,7 @@ bool bmp280_init(bmp280_t *dev, bmp280_params_t *params)
|
|||
|
||||
uint8_t config = (params->standby << 5) | (params->filter << 2);
|
||||
debug("Writing config reg=%x", config);
|
||||
if (!write_register8(i2c_addr, BMP280_REG_CONFIG, config)) {
|
||||
if (write_register8(&dev->i2c_dev, BMP280_REG_CONFIG, config)) {
|
||||
debug("Failed configuring sensor");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -207,14 +206,14 @@ bool bmp280_init(bmp280_t *dev, bmp280_params_t *params)
|
|||
// Write crtl hum reg first, only active after write to BMP280_REG_CTRL.
|
||||
uint8_t ctrl_hum = params->oversampling_humidity;
|
||||
debug("Writing ctrl hum reg=%x", ctrl_hum);
|
||||
if (!write_register8(i2c_addr, BMP280_REG_CTRL_HUM, ctrl_hum)) {
|
||||
if (write_register8(&dev->i2c_dev, BMP280_REG_CTRL_HUM, ctrl_hum)) {
|
||||
debug("Failed controlling sensor");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
debug("Writing ctrl reg=%x", ctrl);
|
||||
if (!write_register8(i2c_addr, BMP280_REG_CTRL, ctrl)) {
|
||||
if (write_register8(&dev->i2c_dev, BMP280_REG_CTRL, ctrl)) {
|
||||
debug("Failed controlling sensor");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -225,12 +224,12 @@ bool bmp280_init(bmp280_t *dev, bmp280_params_t *params)
|
|||
bool bmp280_force_measurement(bmp280_t *dev)
|
||||
{
|
||||
uint8_t ctrl;
|
||||
if (!i2c_slave_read(dev->i2c_addr, BMP280_REG_CTRL, &ctrl, 1))
|
||||
if (read_data(&dev->i2c_dev, BMP280_REG_CTRL, &ctrl, 1))
|
||||
return false;
|
||||
ctrl &= ~0b11; // clear two lower bits
|
||||
ctrl |= BMP280_MODE_FORCED;
|
||||
debug("Writing ctrl reg=%x", ctrl);
|
||||
if (!write_register8(dev->i2c_addr, BMP280_REG_CTRL, ctrl)) {
|
||||
if (write_register8(&dev->i2c_dev, BMP280_REG_CTRL, ctrl)) {
|
||||
debug("Failed starting forced mode");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -240,7 +239,7 @@ bool bmp280_force_measurement(bmp280_t *dev)
|
|||
bool bmp280_is_measuring(bmp280_t *dev)
|
||||
{
|
||||
uint8_t status;
|
||||
if (!i2c_slave_read(dev->i2c_addr, BMP280_REG_STATUS, &status, 1))
|
||||
if (read_data(&dev->i2c_dev, BMP280_REG_STATUS, &status, 1))
|
||||
return false;
|
||||
if (status & (1 << 3)) {
|
||||
debug("Status: measuring");
|
||||
|
|
@ -342,7 +341,7 @@ bool bmp280_read_fixed(bmp280_t *dev, int32_t *temperature,
|
|||
|
||||
// Need to read in one sequence to ensure they match.
|
||||
size_t size = humidity ? 8 : 6;
|
||||
if (!i2c_slave_read(dev->i2c_addr, 0xf7, data, size)) {
|
||||
if (read_data(&dev->i2c_dev, 0xf7, data, size)) {
|
||||
debug("Failed reading");
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "i2c/i2c.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
@ -127,7 +128,7 @@ typedef struct {
|
|||
int16_t dig_H5;
|
||||
int8_t dig_H6;
|
||||
|
||||
uint8_t i2c_addr; /* I2C address. */
|
||||
i2c_dev_t i2c_dev; /* I2C dev setting. */
|
||||
uint8_t id; /* Chip ID */
|
||||
} bmp280_t;
|
||||
|
||||
|
|
|
|||
|
|
@ -14,18 +14,22 @@
|
|||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
#include <lwip/netif.h>
|
||||
#include <lwip/api.h>
|
||||
#include "esplibs/libmain.h"
|
||||
|
||||
/* Grow the size of the lwip dhcp_msg struct's options field, as LWIP
|
||||
defaults to a 68 octet options field for its DHCP client, and most
|
||||
full-sized clients send us more than this. */
|
||||
#define DHCP_OPTIONS_LEN 312
|
||||
|
||||
#include <lwip/dhcp.h>
|
||||
#include <lwip/ip.h>
|
||||
#include <lwip/prot/dhcp.h>
|
||||
#include <lwip/prot/iana.h>
|
||||
|
||||
_Static_assert(sizeof(struct dhcp_msg) == offsetof(struct dhcp_msg, options) + 312, "dhcp_msg_t should have extended options size");
|
||||
|
||||
|
|
@ -35,15 +39,20 @@ _Static_assert(sizeof(struct dhcp_msg) == offsetof(struct dhcp_msg, options) + 3
|
|||
|
||||
typedef struct {
|
||||
uint8_t hwaddr[NETIF_MAX_HWADDR_LEN];
|
||||
uint8_t active;
|
||||
uint32_t expires;
|
||||
} dhcp_lease_t;
|
||||
|
||||
typedef struct {
|
||||
struct netconn *nc;
|
||||
uint8_t max_leases;
|
||||
ip_addr_t first_client_addr;
|
||||
ip4_addr_t first_client_addr;
|
||||
struct netif *server_if;
|
||||
dhcp_lease_t *leases; /* length max_leases */
|
||||
/* Optional router */
|
||||
ip4_addr_t router;
|
||||
/* Optional DNS server */
|
||||
ip4_addr_t dns;
|
||||
} server_state_t;
|
||||
|
||||
/* Only one DHCP server task can run at once, so we have global state
|
||||
|
|
@ -68,51 +77,67 @@ static uint8_t *add_dhcp_option_bytes(uint8_t *opt, uint8_t type, void *value, u
|
|||
static dhcp_lease_t *find_lease_slot(uint8_t *hwaddr);
|
||||
|
||||
/* Copy IP address as dotted decimal to 'dest', must be at least 16 bytes long */
|
||||
inline static void sprintf_ipaddr(const ip_addr_t *addr, char *dest)
|
||||
inline static void sprintf_ipaddr(const ip4_addr_t *addr, char *dest)
|
||||
{
|
||||
if(addr == NULL)
|
||||
if (addr == NULL)
|
||||
sprintf(dest, "NULL");
|
||||
else
|
||||
sprintf(dest, "%d.%d.%d.%d", ip4_addr1(addr),
|
||||
ip4_addr2(addr), ip4_addr3(addr), ip4_addr4(addr));
|
||||
}
|
||||
|
||||
void dhcpserver_start(const ip_addr_t *first_client_addr, uint8_t max_leases)
|
||||
void dhcpserver_start(const ip4_addr_t *first_client_addr, uint8_t max_leases)
|
||||
{
|
||||
/* Stop any existing running dhcpserver */
|
||||
if(dhcpserver_task_handle)
|
||||
if (dhcpserver_task_handle)
|
||||
dhcpserver_stop();
|
||||
|
||||
state = malloc(sizeof(server_state_t));
|
||||
state->max_leases = max_leases;
|
||||
state->leases = calloc(max_leases, sizeof(dhcp_lease_t));
|
||||
bzero(state->leases, max_leases * sizeof(dhcp_lease_t));
|
||||
// state->server_if is assigned once the task is running - see comment in dhcpserver_task()
|
||||
ip_addr_copy(state->first_client_addr, *first_client_addr);
|
||||
ip4_addr_copy(state->first_client_addr, *first_client_addr);
|
||||
|
||||
xTaskCreate(dhcpserver_task, "DHCPServer", 768, NULL, 8, &dhcpserver_task_handle);
|
||||
/* Clear options */
|
||||
ip4_addr_set_zero(&state->router);
|
||||
ip4_addr_set_zero(&state->dns);
|
||||
|
||||
xTaskCreate(dhcpserver_task, "DHCP Server", 448, NULL, 2, &dhcpserver_task_handle);
|
||||
}
|
||||
|
||||
void dhcpserver_stop(void)
|
||||
{
|
||||
if(dhcpserver_task_handle) {
|
||||
if (dhcpserver_task_handle) {
|
||||
vTaskDelete(dhcpserver_task_handle);
|
||||
free(state);
|
||||
dhcpserver_task_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void dhcpserver_set_router(const ip4_addr_t *router)
|
||||
{
|
||||
ip4_addr_copy(state->router, *router);
|
||||
}
|
||||
|
||||
void dhcpserver_set_dns(const ip4_addr_t *dns)
|
||||
{
|
||||
ip4_addr_copy(state->dns, *dns);
|
||||
}
|
||||
|
||||
static void dhcpserver_task(void *pxParameter)
|
||||
{
|
||||
/* netif_list isn't assigned until after user_init completes, which is why we do it inside the task */
|
||||
state->server_if = netif_list; /* TODO: Make this configurable */
|
||||
|
||||
state->nc = netconn_new (NETCONN_UDP);
|
||||
if(!state->nc) {
|
||||
if (!state->nc) {
|
||||
printf("DHCP Server Error: Failed to allocate socket.\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
netconn_bind(state->nc, IP_ADDR_ANY, DHCP_SERVER_PORT);
|
||||
netconn_bind(state->nc, IP4_ADDR_ANY, LWIP_IANA_PORT_DHCP_SERVER);
|
||||
netconn_bind_if (state->nc, netif_get_index(state->server_if));
|
||||
|
||||
while(1)
|
||||
{
|
||||
|
|
@ -121,29 +146,32 @@ static void dhcpserver_task(void *pxParameter)
|
|||
|
||||
/* Receive a DHCP packet */
|
||||
err_t err = netconn_recv(state->nc, &netbuf);
|
||||
if(err != ERR_OK) {
|
||||
if (err != ERR_OK) {
|
||||
printf("DHCP Server Error: Failed to receive DHCP packet. err=%d\r\n", err);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* expire any leases that have passed */
|
||||
uint32_t now = xTaskGetTickCount();
|
||||
for(int i = 0; i < state->max_leases; i++) {
|
||||
uint32_t expires = state->leases[i].expires;
|
||||
if(expires && expires < now)
|
||||
state->leases[i].expires = 0;
|
||||
for (int i = 0; i < state->max_leases; i++) {
|
||||
if (state->leases[i].active) {
|
||||
uint32_t expires = state->leases[i].expires - now;
|
||||
if (expires >= 0x80000000) {
|
||||
state->leases[i].active = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ip_addr_t received_ip;
|
||||
u16_t port;
|
||||
netconn_addr(state->nc, &received_ip, &port);
|
||||
|
||||
if(netbuf_len(netbuf) < offsetof(struct dhcp_msg, options)) {
|
||||
if (netbuf_len(netbuf) < offsetof(struct dhcp_msg, options)) {
|
||||
/* too short to be a valid DHCP client message */
|
||||
netbuf_delete(netbuf);
|
||||
continue;
|
||||
}
|
||||
if(netbuf_len(netbuf) >= sizeof(struct dhcp_msg)) {
|
||||
if (netbuf_len(netbuf) >= sizeof(struct dhcp_msg)) {
|
||||
printf("DHCP Server Warning: Client sent more options than we know how to parse. len=%d\r\n", netbuf_len(netbuf));
|
||||
}
|
||||
|
||||
|
|
@ -152,18 +180,18 @@ static void dhcpserver_task(void *pxParameter)
|
|||
|
||||
uint8_t *message_type = find_dhcp_option(&received, DHCP_OPTION_MESSAGE_TYPE,
|
||||
DHCP_OPTION_MESSAGE_TYPE_LEN, NULL);
|
||||
if(!message_type) {
|
||||
if (!message_type) {
|
||||
printf("DHCP Server Error: No message type field found");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
printf("State dump. Message type %d\n", *message_type);
|
||||
for(int i = 0; i < state->max_leases; i++) {
|
||||
for (int i = 0; i < state->max_leases; i++) {
|
||||
dhcp_lease_t *lease = &state->leases[i];
|
||||
printf("lease slot %d expiry %d hwaddr %02x:%02x:%02x:%02x:%02x:%02x\r\n", i, lease->expires, lease->hwaddr[0],
|
||||
lease->hwaddr[1], lease->hwaddr[2], lease->hwaddr[3], lease->hwaddr[4],
|
||||
lease->hwaddr[5]);
|
||||
printf("lease slot %d active %d expiry %d hwaddr %02x:%02x:%02x:%02x:%02x:%02x\r\n", i,
|
||||
lease->active, lease->expires - now,
|
||||
lease->hwaddr[0], lease->hwaddr[1], lease->hwaddr[2],
|
||||
lease->hwaddr[3], lease->hwaddr[4], lease->hwaddr[5]);
|
||||
}
|
||||
|
||||
switch(*message_type) {
|
||||
|
|
@ -184,13 +212,13 @@ static void dhcpserver_task(void *pxParameter)
|
|||
|
||||
static void handle_dhcp_discover(struct dhcp_msg *dhcpmsg)
|
||||
{
|
||||
if(dhcpmsg->htype != DHCP_HTYPE_ETH)
|
||||
if (dhcpmsg->htype != LWIP_IANA_HWTYPE_ETHERNET)
|
||||
return;
|
||||
if(dhcpmsg->hlen > NETIF_MAX_HWADDR_LEN)
|
||||
if (dhcpmsg->hlen > NETIF_MAX_HWADDR_LEN)
|
||||
return;
|
||||
|
||||
dhcp_lease_t *freelease = find_lease_slot(dhcpmsg->chaddr);
|
||||
if(!freelease) {
|
||||
if (!freelease) {
|
||||
printf("DHCP Server: All leases taken.\r\n");
|
||||
return; /* Nothing available, so do nothing */
|
||||
}
|
||||
|
|
@ -199,13 +227,19 @@ static void handle_dhcp_discover(struct dhcp_msg *dhcpmsg)
|
|||
dhcpmsg->op = DHCP_BOOTREPLY;
|
||||
bzero(dhcpmsg->options, DHCP_OPTIONS_LEN);
|
||||
|
||||
ip_addr_copy(dhcpmsg->yiaddr, state->first_client_addr);
|
||||
ip4_addr4(&(dhcpmsg->yiaddr)) += (freelease - state->leases);
|
||||
dhcpmsg->yiaddr.addr = lwip_htonl(lwip_ntohl(state->first_client_addr.addr) + (freelease - state->leases));
|
||||
|
||||
uint8_t *opt = (uint8_t *)&dhcpmsg->options;
|
||||
opt = add_dhcp_option_byte(opt, DHCP_OPTION_MESSAGE_TYPE, DHCP_OFFER);
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SERVER_ID, &state->server_if->ip_addr, 4);
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SUBNET_MASK, &state->server_if->netmask, 4);
|
||||
if (!ip4_addr_isany_val(state->router)) {
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_ROUTER, &state->router, 4);
|
||||
}
|
||||
if (!ip4_addr_isany_val(state->dns)) {
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_DNS_SERVER, &state->dns, 4);
|
||||
}
|
||||
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_END, NULL, 0);
|
||||
|
||||
struct netbuf *netbuf = netbuf_new();
|
||||
|
|
@ -218,17 +252,17 @@ static void handle_dhcp_discover(struct dhcp_msg *dhcpmsg)
|
|||
static void handle_dhcp_request(struct dhcp_msg *dhcpmsg)
|
||||
{
|
||||
static char ipbuf[16];
|
||||
if(dhcpmsg->htype != DHCP_HTYPE_ETH)
|
||||
if (dhcpmsg->htype != LWIP_IANA_HWTYPE_ETHERNET)
|
||||
return;
|
||||
if(dhcpmsg->hlen > NETIF_MAX_HWADDR_LEN)
|
||||
if (dhcpmsg->hlen > NETIF_MAX_HWADDR_LEN)
|
||||
return;
|
||||
|
||||
ip_addr_t requested_ip;
|
||||
ip4_addr_t requested_ip;
|
||||
uint8_t *requested_ip_opt = find_dhcp_option(dhcpmsg, DHCP_OPTION_REQUESTED_IP, 4, NULL);
|
||||
if(requested_ip_opt) {
|
||||
memcpy(&requested_ip.addr, requested_ip_opt, 4);
|
||||
} else if(ip_addr_cmp(&requested_ip, IP_ADDR_ANY)) {
|
||||
ip_addr_copy(requested_ip, dhcpmsg->ciaddr);
|
||||
if (requested_ip_opt) {
|
||||
memcpy(&requested_ip.addr, requested_ip_opt, 4);
|
||||
} else if (ip4_addr_cmp(&requested_ip, IP4_ADDR_ANY4)) {
|
||||
ip4_addr_copy(requested_ip, dhcpmsg->ciaddr);
|
||||
} else {
|
||||
printf("DHCP Server Error: No requested IP\r\n");
|
||||
send_dhcp_nak(dhcpmsg);
|
||||
|
|
@ -236,7 +270,7 @@ static void handle_dhcp_request(struct dhcp_msg *dhcpmsg)
|
|||
}
|
||||
|
||||
/* Test the first 4 octets match */
|
||||
if(ip4_addr1(&requested_ip) != ip4_addr1(&state->first_client_addr)
|
||||
if (ip4_addr1(&requested_ip) != ip4_addr1(&state->first_client_addr)
|
||||
|| ip4_addr2(&requested_ip) != ip4_addr2(&state->first_client_addr)
|
||||
|| ip4_addr3(&requested_ip) != ip4_addr3(&state->first_client_addr)) {
|
||||
sprintf_ipaddr(&requested_ip, ipbuf);
|
||||
|
|
@ -246,14 +280,14 @@ static void handle_dhcp_request(struct dhcp_msg *dhcpmsg)
|
|||
}
|
||||
/* Test the last octet is in the MAXCLIENTS range */
|
||||
int16_t octet_offs = ip4_addr4(&requested_ip) - ip4_addr4(&state->first_client_addr);
|
||||
if(octet_offs < 0 || octet_offs >= state->max_leases) {
|
||||
if (octet_offs < 0 || octet_offs >= state->max_leases) {
|
||||
printf("DHCP Server Error: Address out of range\r\n");
|
||||
send_dhcp_nak(dhcpmsg);
|
||||
return;
|
||||
}
|
||||
|
||||
dhcp_lease_t *requested_lease = state->leases + octet_offs;
|
||||
if(requested_lease->expires != 0 && memcmp(requested_lease->hwaddr, dhcpmsg->chaddr,dhcpmsg->hlen))
|
||||
if (requested_lease->active && memcmp(requested_lease->hwaddr, dhcpmsg->chaddr,dhcpmsg->hlen))
|
||||
{
|
||||
printf("DHCP Server Error: Lease for address already taken\r\n");
|
||||
send_dhcp_nak(dhcpmsg);
|
||||
|
|
@ -265,13 +299,17 @@ static void handle_dhcp_request(struct dhcp_msg *dhcpmsg)
|
|||
printf("DHCP lease addr %s assigned to MAC %02x:%02x:%02x:%02x:%02x:%02x\r\n", ipbuf, requested_lease->hwaddr[0],
|
||||
requested_lease->hwaddr[1], requested_lease->hwaddr[2], requested_lease->hwaddr[3], requested_lease->hwaddr[4],
|
||||
requested_lease->hwaddr[5]);
|
||||
requested_lease->expires = DHCPSERVER_LEASE_TIME * configTICK_RATE_HZ;
|
||||
uint32_t now = xTaskGetTickCount();
|
||||
requested_lease->expires = now + DHCPSERVER_LEASE_TIME * configTICK_RATE_HZ;
|
||||
requested_lease->active = 1;
|
||||
|
||||
sdk_wifi_softap_set_station_info(requested_lease->hwaddr, &requested_ip);
|
||||
|
||||
/* Reuse the REQUEST message as the ACK message */
|
||||
dhcpmsg->op = DHCP_BOOTREPLY;
|
||||
bzero(dhcpmsg->options, DHCP_OPTIONS_LEN);
|
||||
|
||||
ip_addr_copy(dhcpmsg->yiaddr, requested_ip);
|
||||
ip4_addr_copy(dhcpmsg->yiaddr, requested_ip);
|
||||
|
||||
uint8_t *opt = (uint8_t *)&dhcpmsg->options;
|
||||
opt = add_dhcp_option_byte(opt, DHCP_OPTION_MESSAGE_TYPE, DHCP_ACK);
|
||||
|
|
@ -279,6 +317,13 @@ static void handle_dhcp_request(struct dhcp_msg *dhcpmsg)
|
|||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_LEASE_TIME, &expiry, 4);
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SERVER_ID, &state->server_if->ip_addr, 4);
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SUBNET_MASK, &state->server_if->netmask, 4);
|
||||
if (!ip4_addr_isany_val(state->router)) {
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_ROUTER, &state->router, 4);
|
||||
}
|
||||
if (!ip4_addr_isany_val(state->dns)) {
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_DNS_SERVER, &state->dns, 4);
|
||||
}
|
||||
|
||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_END, NULL, 0);
|
||||
|
||||
struct netbuf *netbuf = netbuf_new();
|
||||
|
|
@ -291,7 +336,8 @@ static void handle_dhcp_request(struct dhcp_msg *dhcpmsg)
|
|||
static void handle_dhcp_release(struct dhcp_msg *dhcpmsg)
|
||||
{
|
||||
dhcp_lease_t *lease = find_lease_slot(dhcpmsg->chaddr);
|
||||
if(lease) {
|
||||
if (lease) {
|
||||
lease->active = 0;
|
||||
lease->expires = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -319,17 +365,17 @@ static uint8_t *find_dhcp_option(struct dhcp_msg *msg, uint8_t option_num, uint8
|
|||
uint8_t *start = (uint8_t *)&msg->options;
|
||||
uint8_t *msg_end = (uint8_t *)msg + sizeof(struct dhcp_msg);
|
||||
|
||||
for(uint8_t *p = start; p < msg_end-2;) {
|
||||
for (uint8_t *p = start; p < msg_end-2;) {
|
||||
uint8_t type = *p++;
|
||||
uint8_t len = *p++;
|
||||
if(type == DHCP_OPTION_END)
|
||||
if (type == DHCP_OPTION_END)
|
||||
return NULL;
|
||||
if(p+len >= msg_end)
|
||||
if (p+len >= msg_end)
|
||||
break; /* We've overrun our valid DHCP message size, or this isn't a valid option */
|
||||
if(type == option_num) {
|
||||
if(len < min_length)
|
||||
if (type == option_num) {
|
||||
if (len < min_length)
|
||||
break;
|
||||
if(length)
|
||||
if (length)
|
||||
*length = len;
|
||||
return p; /* start of actual option data */
|
||||
}
|
||||
|
|
@ -349,7 +395,7 @@ static uint8_t *add_dhcp_option_byte(uint8_t *opt, uint8_t type, uint8_t value)
|
|||
static uint8_t *add_dhcp_option_bytes(uint8_t *opt, uint8_t type, void *value, uint8_t len)
|
||||
{
|
||||
*opt++ = type;
|
||||
if(len) {
|
||||
if (len) {
|
||||
*opt++ = len;
|
||||
memcpy(opt, value, len);
|
||||
}
|
||||
|
|
@ -360,8 +406,8 @@ static uint8_t *add_dhcp_option_bytes(uint8_t *opt, uint8_t type, void *value, u
|
|||
static dhcp_lease_t *find_lease_slot(uint8_t *hwaddr)
|
||||
{
|
||||
dhcp_lease_t *empty_lease = NULL;
|
||||
for(int i = 0; i < state->max_leases; i++) {
|
||||
if(state->leases[i].expires == 0 && !empty_lease)
|
||||
for (int i = 0; i < state->max_leases; i++) {
|
||||
if (!state->leases[i].active && !empty_lease)
|
||||
empty_lease = &state->leases[i];
|
||||
else if (memcmp(hwaddr, state->leases[i].hwaddr, 6) == 0)
|
||||
return &state->leases[i];
|
||||
|
|
|
|||
|
|
@ -26,14 +26,20 @@ extern "C" {
|
|||
to a client. Subsequent lease addresses are calculated by
|
||||
incrementing the final octet of the IPv4 address, up to max_leases.
|
||||
*/
|
||||
void dhcpserver_start(const ip_addr_t *first_client_addr, uint8_t max_leases);
|
||||
void dhcpserver_start(const ip4_addr_t *first_client_addr, uint8_t max_leases);
|
||||
|
||||
void dhcpserver_get_lease(const ip_addr_t *first_client_addr, uint8_t max_leases);
|
||||
void dhcpserver_get_lease(const ip4_addr_t *first_client_addr, uint8_t max_leases);
|
||||
|
||||
/* Stop DHCP server.
|
||||
*/
|
||||
void dhcpserver_stop(void);
|
||||
|
||||
/* Set a router address to send as an option. */
|
||||
void dhcpserver_set_router(const ip4_addr_t *router);
|
||||
|
||||
/* Set a DNS address to send as an option. */
|
||||
void dhcpserver_set_dns(const ip4_addr_t *dns);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -6,10 +6,8 @@
|
|||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include "ds1307.h"
|
||||
#include <i2c/i2c.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define ADDR 0x68
|
||||
#define RAM_SIZE 56
|
||||
|
||||
#define TIME_REG 0
|
||||
|
|
@ -40,38 +38,36 @@ static uint8_t dec2bcd(uint8_t val)
|
|||
return ((val / 10) << 4) + (val % 10);
|
||||
}
|
||||
|
||||
static uint8_t read_register(uint8_t reg)
|
||||
static uint8_t read_register(i2c_dev_t* dev, uint8_t reg)
|
||||
{
|
||||
uint8_t val;
|
||||
i2c_slave_read(ADDR, reg, &val, 1);
|
||||
i2c_slave_read(dev->bus, dev->addr, ®, &val, 1);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void update_register(uint8_t reg, uint8_t mask, uint8_t val)
|
||||
static void update_register(i2c_dev_t* dev, uint8_t reg, uint8_t mask, uint8_t val)
|
||||
{
|
||||
uint8_t buf[2];
|
||||
uint8_t buf = (read_register(dev,reg) & mask) | val;
|
||||
|
||||
buf[0] = reg;
|
||||
buf[1] = (read_register(reg) & mask) | val;
|
||||
|
||||
i2c_slave_write(ADDR, buf, 2);
|
||||
i2c_slave_write(dev->bus, dev->addr, ®, &buf, 1);
|
||||
}
|
||||
|
||||
void ds1307_start(bool start)
|
||||
void ds1307_start(i2c_dev_t* dev, bool start)
|
||||
{
|
||||
update_register(TIME_REG, CH_MASK, start ? 0 : CH_BIT);
|
||||
update_register(dev, TIME_REG, CH_MASK, start ? 0 : CH_BIT);
|
||||
}
|
||||
|
||||
bool ds1307_is_running()
|
||||
bool ds1307_is_running(i2c_dev_t* dev)
|
||||
{
|
||||
return !(read_register(TIME_REG) & CH_BIT);
|
||||
return !(read_register(dev, TIME_REG) & CH_BIT);
|
||||
}
|
||||
|
||||
void ds1307_get_time(struct tm *time)
|
||||
void ds1307_get_time(i2c_dev_t* dev, struct tm *time)
|
||||
{
|
||||
uint8_t buf[7];
|
||||
uint8_t reg = TIME_REG ;
|
||||
|
||||
i2c_slave_read(ADDR, TIME_REG, buf, 7);
|
||||
i2c_slave_read(dev->bus, dev->addr, ® , buf, 7);
|
||||
|
||||
time->tm_sec = bcd2dec(buf[0] & SECONDS_MASK);
|
||||
time->tm_min = bcd2dec(buf[1]);
|
||||
|
|
@ -89,7 +85,7 @@ void ds1307_get_time(struct tm *time)
|
|||
time->tm_year = bcd2dec(buf[6]) + 2000;
|
||||
}
|
||||
|
||||
void ds1307_set_time(const struct tm *time)
|
||||
void ds1307_set_time(i2c_dev_t* dev, const struct tm *time)
|
||||
{
|
||||
uint8_t buf[8];
|
||||
buf[0] = TIME_REG;
|
||||
|
|
@ -101,64 +97,51 @@ void ds1307_set_time(const struct tm *time)
|
|||
buf[6] = dec2bcd(time->tm_mon + 1);
|
||||
buf[7] = dec2bcd(time->tm_year - 2000);
|
||||
|
||||
i2c_slave_write(ADDR, buf, 8);
|
||||
i2c_slave_write(dev->bus, dev->addr, &buf[0], &buf[1] , 7);
|
||||
}
|
||||
|
||||
void ds1307_enable_squarewave(bool enable)
|
||||
void ds1307_enable_squarewave(i2c_dev_t* dev, bool enable)
|
||||
{
|
||||
update_register(CONTROL_REG, SQWE_MASK, enable ? SQWE_BIT : 0);
|
||||
update_register(dev, CONTROL_REG, SQWE_MASK, enable ? SQWE_BIT : 0);
|
||||
}
|
||||
|
||||
bool ds1307_is_squarewave_enabled()
|
||||
bool ds1307_is_squarewave_enabled(i2c_dev_t* dev)
|
||||
{
|
||||
return read_register(CONTROL_REG) & SQWE_BIT;
|
||||
return read_register(dev, CONTROL_REG) & SQWE_BIT;
|
||||
}
|
||||
|
||||
void ds1307_set_squarewave_freq(ds1307_squarewave_freq_t freq)
|
||||
void ds1307_set_squarewave_freq(i2c_dev_t* dev, ds1307_squarewave_freq_t freq)
|
||||
{
|
||||
update_register(CONTROL_REG, SQWEF_MASK, (uint8_t)freq);
|
||||
update_register(dev, CONTROL_REG, SQWEF_MASK, (uint8_t)freq);
|
||||
}
|
||||
|
||||
ds1307_squarewave_freq_t ds1307_get_squarewave_freq()
|
||||
ds1307_squarewave_freq_t ds1307_get_squarewave_freq(i2c_dev_t* dev)
|
||||
{
|
||||
return (ds1307_squarewave_freq_t)(read_register(CONTROL_REG) & SQWEF_MASK);
|
||||
return (ds1307_squarewave_freq_t)(read_register(dev, CONTROL_REG) & SQWEF_MASK);
|
||||
}
|
||||
|
||||
bool ds1307_get_output()
|
||||
bool ds1307_get_output(i2c_dev_t* dev)
|
||||
{
|
||||
return read_register(CONTROL_REG) & OUT_BIT;
|
||||
return read_register(dev, CONTROL_REG) & OUT_BIT;
|
||||
}
|
||||
|
||||
void ds1307_set_output(bool value)
|
||||
void ds1307_set_output(i2c_dev_t* dev, bool value)
|
||||
{
|
||||
update_register(CONTROL_REG, OUT_MASK, value ? OUT_BIT : 0);
|
||||
update_register(dev, CONTROL_REG, OUT_MASK, value ? OUT_BIT : 0);
|
||||
}
|
||||
|
||||
bool ds1307_read_ram(uint8_t offset, uint8_t *buf, uint8_t len)
|
||||
int ds1307_read_ram(i2c_dev_t* dev, uint8_t offset, uint8_t *buf, uint8_t len)
|
||||
{
|
||||
if (offset + len > RAM_SIZE) return false;
|
||||
uint8_t reg = RAM_REG + offset ;
|
||||
|
||||
return i2c_slave_read(ADDR, RAM_REG + offset, buf, len);
|
||||
return i2c_slave_read(dev->bus, dev->addr, ®, buf, len);
|
||||
}
|
||||
|
||||
bool ds1307_write_ram(uint8_t offset, uint8_t *buf, uint8_t len)
|
||||
int ds1307_write_ram(i2c_dev_t* dev, uint8_t offset, uint8_t *buf, uint8_t len)
|
||||
{
|
||||
if (offset + len > RAM_SIZE) return false;
|
||||
uint8_t reg = RAM_REG + offset ;
|
||||
|
||||
// temporary buffer on the stack is not good so copy-paste :(
|
||||
bool success = false;
|
||||
do {
|
||||
i2c_start();
|
||||
if (!i2c_write(ADDR << 1))
|
||||
break;
|
||||
if (!i2c_write(RAM_REG + offset))
|
||||
break;
|
||||
while (len--) {
|
||||
if (!i2c_write(*buf++))
|
||||
break;
|
||||
}
|
||||
i2c_stop();
|
||||
success = true;
|
||||
} while(0);
|
||||
return success;
|
||||
return i2c_slave_write(dev->bus, dev->addr, ®, buf, len);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,11 +11,13 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
#include <i2c/i2c.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define DS1307_ADDR 0x68
|
||||
/**
|
||||
* Squarewave frequency
|
||||
*/
|
||||
|
|
@ -31,80 +33,80 @@ typedef enum _ds1307_squarewave_freq_t
|
|||
* \brief Start/stop clock
|
||||
* \param start Start clock if true
|
||||
*/
|
||||
void ds1307_start(bool start);
|
||||
void ds1307_start(i2c_dev_t* dev, bool start);
|
||||
|
||||
/**
|
||||
* \brief Get current clock state
|
||||
* \return true if clock running
|
||||
*/
|
||||
bool ds1307_is_running();
|
||||
bool ds1307_is_running(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* \brief Get current time
|
||||
* \param time Pointer to the time struct to fill
|
||||
*/
|
||||
void ds1307_get_time(struct tm *time);
|
||||
void ds1307_get_time(i2c_dev_t* dev, struct tm *time);
|
||||
|
||||
/**
|
||||
* \brief Set time to RTC
|
||||
* \param time Pointer to the time struct
|
||||
*/
|
||||
void ds1307_set_time(const struct tm *time);
|
||||
void ds1307_set_time(i2c_dev_t* dev, const struct tm *time);
|
||||
|
||||
/**
|
||||
* \brief Enable or disable square-wave oscillator output
|
||||
* \param enable Enable oscillator if true
|
||||
*/
|
||||
void ds1307_enable_squarewave(bool enable);
|
||||
void ds1307_enable_squarewave(i2c_dev_t* dev, bool enable);
|
||||
|
||||
/**
|
||||
* \brief Get square-wave oscillator output
|
||||
* \return true if square-wave oscillator enabled
|
||||
*/
|
||||
bool ds1307_is_squarewave_enabled();
|
||||
bool ds1307_is_squarewave_enabled(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* \brief Set square-wave oscillator frequency
|
||||
* \param freq Frequency
|
||||
*/
|
||||
void ds1307_set_squarewave_freq(ds1307_squarewave_freq_t freq);
|
||||
void ds1307_set_squarewave_freq(i2c_dev_t* dev, ds1307_squarewave_freq_t freq);
|
||||
|
||||
/**
|
||||
* \brief Get current square-wave oscillator frequency
|
||||
* \return Frequency
|
||||
*/
|
||||
ds1307_squarewave_freq_t ds1307_get_squarewave_freq();
|
||||
ds1307_squarewave_freq_t ds1307_get_squarewave_freq(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* \brief Get current output level of the SQW/OUT pin
|
||||
* \return true if high
|
||||
*/
|
||||
bool ds1307_get_output();
|
||||
bool ds1307_get_output(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* \brief Set output level of the SQW/OUT pin
|
||||
* Set output level if square-wave output is disabled
|
||||
* \param value High level if true
|
||||
*/
|
||||
void ds1307_set_output(bool value);
|
||||
void ds1307_set_output(i2c_dev_t* dev, bool value);
|
||||
|
||||
/**
|
||||
* \brief Read RAM contents into the buffer
|
||||
* \param offset Start byte, 0..55
|
||||
* \param buf Buffer
|
||||
* \param len Bytes to read, 1..56
|
||||
* \return false if error occured
|
||||
* \return Non-zero if error occured
|
||||
*/
|
||||
bool ds1307_read_ram(uint8_t offset, uint8_t *buf, uint8_t len);
|
||||
int ds1307_read_ram(i2c_dev_t* dev, uint8_t offset, uint8_t *buf, uint8_t len);
|
||||
|
||||
/**
|
||||
* \brief Write buffer to RTC RAM
|
||||
* \param offset Start byte, 0..55
|
||||
* \param buf Buffer
|
||||
* \param len Bytes to write, 1..56
|
||||
* \return false if error occured
|
||||
* \return Non-zero if error occured
|
||||
*/
|
||||
bool ds1307_write_ram(uint8_t offset, uint8_t *buf, uint8_t len);
|
||||
int ds1307_write_ram(i2c_dev_t* dev, uint8_t offset, uint8_t *buf, uint8_t len);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -11,64 +11,61 @@
|
|||
#include "espressif/sdk_private.h"
|
||||
#include "esp8266.h"
|
||||
|
||||
#include "i2c/i2c.h"
|
||||
|
||||
/* Convert normal decimal to binary coded decimal */
|
||||
static inline uint8_t decToBcd(uint8_t dec)
|
||||
{
|
||||
return(((dec / 10) * 16) + (dec % 10));
|
||||
return (dec / 10) * 16 + dec % 10;
|
||||
}
|
||||
|
||||
/* Convert binary coded decimal to normal decimal */
|
||||
static inline uint8_t bcdToDec(uint8_t bcd)
|
||||
{
|
||||
return(((bcd / 16) * 10) + (bcd % 16));
|
||||
return (bcd / 16) * 10 + bcd % 16;
|
||||
}
|
||||
|
||||
/* Send a number of bytes to the rtc over i2c
|
||||
* returns true to indicate success
|
||||
*/
|
||||
static inline bool ds3231_send(uint8_t *data, uint8_t len)
|
||||
static inline int ds3231_send(i2c_dev_t *dev, uint8_t reg, uint8_t *data, uint8_t len)
|
||||
{
|
||||
return i2c_slave_write(DS3231_ADDR, data, len);
|
||||
return i2c_slave_write(dev->bus, dev->addr, ®, data, len);
|
||||
}
|
||||
|
||||
/* Read a number of bytes from the rtc over i2c
|
||||
* returns true to indicate success
|
||||
*/
|
||||
static inline bool ds3231_recv(uint8_t *data, uint8_t len)
|
||||
static inline int ds3231_recv(i2c_dev_t *dev, uint8_t reg, uint8_t *data, uint8_t len)
|
||||
{
|
||||
return i2c_slave_read(DS3231_ADDR, data[0], data, len);
|
||||
return i2c_slave_read(dev->bus, dev->addr, ®, data, len);
|
||||
}
|
||||
|
||||
bool ds3231_setTime(struct tm *time)
|
||||
int ds3231_setTime(i2c_dev_t *dev, struct tm *time)
|
||||
{
|
||||
uint8_t data[8];
|
||||
uint8_t data[7];
|
||||
|
||||
/* start register */
|
||||
data[0] = DS3231_ADDR_TIME;
|
||||
/* time/date data */
|
||||
data[1] = decToBcd(time->tm_sec);
|
||||
data[2] = decToBcd(time->tm_min);
|
||||
data[3] = decToBcd(time->tm_hour);
|
||||
data[4] = decToBcd(time->tm_wday + 1);
|
||||
data[5] = decToBcd(time->tm_mday);
|
||||
data[6] = decToBcd(time->tm_mon + 1);
|
||||
data[7] = decToBcd(time->tm_year - 100);
|
||||
data[0] = decToBcd(time->tm_sec);
|
||||
data[1] = decToBcd(time->tm_min);
|
||||
data[2] = decToBcd(time->tm_hour);
|
||||
/* The week data must be in the range 1 to 7, and to keep the start on the
|
||||
* same day as for tm_wday have it start at 1 on Sunday. */
|
||||
data[3] = decToBcd(time->tm_wday + 1);
|
||||
data[4] = decToBcd(time->tm_mday);
|
||||
data[5] = decToBcd(time->tm_mon + 1);
|
||||
data[6] = decToBcd(time->tm_year - 100);
|
||||
|
||||
return ds3231_send(data, 8);
|
||||
return ds3231_send(dev, DS3231_ADDR_TIME, data, 7);
|
||||
}
|
||||
|
||||
bool ds3231_setAlarm(uint8_t alarms, struct tm *time1, uint8_t option1, struct tm *time2, uint8_t option2)
|
||||
int ds3231_setAlarm(i2c_dev_t *dev, uint8_t alarms, struct tm *time1, uint8_t option1, struct tm *time2, uint8_t option2)
|
||||
{
|
||||
int i = 0;
|
||||
uint8_t data[8];
|
||||
|
||||
/* start register */
|
||||
data[i++] = (alarms == DS3231_ALARM_2 ? DS3231_ADDR_ALARM2 : DS3231_ADDR_ALARM1);
|
||||
uint8_t data[7];
|
||||
|
||||
/* alarm 1 data */
|
||||
if (alarms != DS3231_ALARM_2) {
|
||||
if (alarms != DS3231_ALARM_2)
|
||||
{
|
||||
data[i++] = (option1 >= DS3231_ALARM1_MATCH_SEC ? decToBcd(time1->tm_sec) : DS3231_ALARM_NOTSET);
|
||||
data[i++] = (option1 >= DS3231_ALARM1_MATCH_SECMIN ? decToBcd(time1->tm_min) : DS3231_ALARM_NOTSET);
|
||||
data[i++] = (option1 >= DS3231_ALARM1_MATCH_SECMINHOUR ? decToBcd(time1->tm_hour) : DS3231_ALARM_NOTSET);
|
||||
|
|
@ -77,14 +74,15 @@ bool ds3231_setAlarm(uint8_t alarms, struct tm *time1, uint8_t option1, struct t
|
|||
}
|
||||
|
||||
/* alarm 2 data */
|
||||
if (alarms != DS3231_ALARM_1) {
|
||||
if (alarms != DS3231_ALARM_1)
|
||||
{
|
||||
data[i++] = (option2 >= DS3231_ALARM2_MATCH_MIN ? decToBcd(time2->tm_min) : DS3231_ALARM_NOTSET);
|
||||
data[i++] = (option2 >= DS3231_ALARM2_MATCH_MINHOUR ? decToBcd(time2->tm_hour) : DS3231_ALARM_NOTSET);
|
||||
data[i++] = (option2 == DS3231_ALARM2_MATCH_MINHOURDAY ? (decToBcd(time2->tm_wday + 1) & DS3231_ALARM_WDAY) :
|
||||
(option2 == DS3231_ALARM2_MATCH_MINHOURDATE ? decToBcd(time2->tm_mday) : DS3231_ALARM_NOTSET));
|
||||
}
|
||||
|
||||
return ds3231_send(data, i);
|
||||
return ds3231_send(dev, (alarms == DS3231_ALARM_2 ? DS3231_ADDR_ALARM2 : DS3231_ADDR_ALARM1), data, i);
|
||||
}
|
||||
|
||||
/* Get a byte containing just the requested bits
|
||||
|
|
@ -94,15 +92,15 @@ bool ds3231_setAlarm(uint8_t alarms, struct tm *time1, uint8_t option1, struct t
|
|||
* of use a mask of 0xff to just return the whole register byte
|
||||
* returns true to indicate success
|
||||
*/
|
||||
bool ds3231_getFlag(uint8_t addr, uint8_t mask, uint8_t *flag)
|
||||
bool ds3231_getFlag(i2c_dev_t *dev, uint8_t addr, uint8_t mask, uint8_t *flag)
|
||||
{
|
||||
uint8_t data[1];
|
||||
uint8_t data;
|
||||
|
||||
/* get register */
|
||||
data[0] = addr;
|
||||
if (ds3231_send(data, 1) && ds3231_recv(data, 1)) {
|
||||
if (!ds3231_recv(dev, addr, &data, 1))
|
||||
{
|
||||
/* return only requested flag */
|
||||
*flag = (data[0] & mask);
|
||||
*flag = (data & mask);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -115,34 +113,34 @@ bool ds3231_getFlag(uint8_t addr, uint8_t mask, uint8_t *flag)
|
|||
* DS3231_SET/DS3231_CLEAR/DS3231_REPLACE
|
||||
* returns true to indicate success
|
||||
*/
|
||||
bool ds3231_setFlag(uint8_t addr, uint8_t bits, uint8_t mode)
|
||||
bool ds3231_setFlag(i2c_dev_t *dev, uint8_t addr, uint8_t bits, uint8_t mode)
|
||||
{
|
||||
uint8_t data[2];
|
||||
uint8_t data;
|
||||
|
||||
data[0] = addr;
|
||||
/* get status register */
|
||||
if (ds3231_send(data, 1) && ds3231_recv(data+1, 1)) {
|
||||
if (!ds3231_recv(dev, addr, &data, 1))
|
||||
{
|
||||
/* clear the flag */
|
||||
if (mode == DS3231_REPLACE)
|
||||
data[1] = bits;
|
||||
data = bits;
|
||||
else if (mode == DS3231_SET)
|
||||
data[1] |= bits;
|
||||
data |= bits;
|
||||
else
|
||||
data[1] &= ~bits;
|
||||
data &= ~bits;
|
||||
|
||||
if (ds3231_send(data, 2)) {
|
||||
if (!ds3231_send(dev, addr, &data, 1))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ds3231_getOscillatorStopFlag(bool *flag)
|
||||
bool ds3231_getOscillatorStopFlag(i2c_dev_t *dev, bool *flag)
|
||||
{
|
||||
uint8_t f;
|
||||
|
||||
if (ds3231_getFlag(DS3231_ADDR_STATUS, DS3231_STAT_OSCILLATOR, &f)) {
|
||||
if (ds3231_getFlag(dev, DS3231_ADDR_STATUS, DS3231_STAT_OSCILLATOR, &f))
|
||||
{
|
||||
*flag = (f ? true : false);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -150,75 +148,77 @@ bool ds3231_getOscillatorStopFlag(bool *flag)
|
|||
return false;
|
||||
}
|
||||
|
||||
inline bool ds3231_clearOscillatorStopFlag()
|
||||
inline bool ds3231_clearOscillatorStopFlag(i2c_dev_t *dev)
|
||||
{
|
||||
return ds3231_setFlag(DS3231_ADDR_STATUS, DS3231_STAT_OSCILLATOR, DS3231_CLEAR);
|
||||
return ds3231_setFlag(dev, DS3231_ADDR_STATUS, DS3231_STAT_OSCILLATOR, DS3231_CLEAR);
|
||||
}
|
||||
|
||||
inline bool ds3231_getAlarmFlags(uint8_t *alarms)
|
||||
inline bool ds3231_getAlarmFlags(i2c_dev_t *dev, uint8_t *alarms)
|
||||
{
|
||||
return ds3231_getFlag(DS3231_ADDR_STATUS, DS3231_ALARM_BOTH, alarms);
|
||||
return ds3231_getFlag(dev, DS3231_ADDR_STATUS, DS3231_ALARM_BOTH, alarms);
|
||||
}
|
||||
|
||||
inline bool ds3231_clearAlarmFlags(uint8_t alarms)
|
||||
inline bool ds3231_clearAlarmFlags(i2c_dev_t *dev, uint8_t alarms)
|
||||
{
|
||||
return ds3231_setFlag(DS3231_ADDR_STATUS, alarms, DS3231_CLEAR);
|
||||
return ds3231_setFlag(dev, DS3231_ADDR_STATUS, alarms, DS3231_CLEAR);
|
||||
}
|
||||
|
||||
inline bool ds3231_enableAlarmInts(uint8_t alarms)
|
||||
inline bool ds3231_enableAlarmInts(i2c_dev_t *dev, uint8_t alarms)
|
||||
{
|
||||
return ds3231_setFlag(DS3231_ADDR_CONTROL, DS3231_CTRL_ALARM_INTS | alarms, DS3231_SET);
|
||||
return ds3231_setFlag(dev, DS3231_ADDR_CONTROL, DS3231_CTRL_ALARM_INTS | alarms, DS3231_SET);
|
||||
}
|
||||
|
||||
inline bool ds3231_disableAlarmInts(uint8_t alarms)
|
||||
inline bool ds3231_disableAlarmInts(i2c_dev_t *dev, uint8_t alarms)
|
||||
{
|
||||
/* Just disable specific alarm(s) requested
|
||||
* does not disable alarm interrupts generally (which would enable the squarewave)
|
||||
*/
|
||||
return ds3231_setFlag(DS3231_ADDR_CONTROL, alarms, DS3231_CLEAR);
|
||||
return ds3231_setFlag(dev, DS3231_ADDR_CONTROL, alarms, DS3231_CLEAR);
|
||||
}
|
||||
|
||||
inline bool ds3231_enable32khz()
|
||||
inline bool ds3231_enable32khz(i2c_dev_t *dev)
|
||||
{
|
||||
return ds3231_setFlag(DS3231_ADDR_STATUS, DS3231_STAT_32KHZ, DS3231_SET);
|
||||
return ds3231_setFlag(dev, DS3231_ADDR_STATUS, DS3231_STAT_32KHZ, DS3231_SET);
|
||||
}
|
||||
|
||||
inline bool ds3231_disable32khz()
|
||||
inline bool ds3231_disable32khz(i2c_dev_t *dev)
|
||||
{
|
||||
return ds3231_setFlag(DS3231_ADDR_STATUS, DS3231_STAT_32KHZ, DS3231_CLEAR);
|
||||
return ds3231_setFlag(dev, DS3231_ADDR_STATUS, DS3231_STAT_32KHZ, DS3231_CLEAR);
|
||||
}
|
||||
|
||||
inline bool ds3231_enableSquarewave()
|
||||
inline bool ds3231_enableSquarewave(i2c_dev_t *dev)
|
||||
{
|
||||
return ds3231_setFlag(DS3231_ADDR_CONTROL, DS3231_CTRL_ALARM_INTS, DS3231_CLEAR);
|
||||
return ds3231_setFlag(dev, DS3231_ADDR_CONTROL, DS3231_CTRL_ALARM_INTS, DS3231_CLEAR);
|
||||
}
|
||||
|
||||
inline bool ds3231_disableSquarewave()
|
||||
inline bool ds3231_disableSquarewave(i2c_dev_t *dev)
|
||||
{
|
||||
return ds3231_setFlag(DS3231_ADDR_CONTROL, DS3231_CTRL_ALARM_INTS, DS3231_SET);
|
||||
return ds3231_setFlag(dev, DS3231_ADDR_CONTROL, DS3231_CTRL_ALARM_INTS, DS3231_SET);
|
||||
}
|
||||
|
||||
bool ds3231_setSquarewaveFreq(uint8_t freq)
|
||||
bool ds3231_setSquarewaveFreq(i2c_dev_t *dev, uint8_t freq)
|
||||
{
|
||||
uint8_t flag = 0;
|
||||
|
||||
if (ds3231_getFlag(DS3231_ADDR_CONTROL, 0xff, &flag)) {
|
||||
if (ds3231_getFlag(dev, DS3231_ADDR_CONTROL, 0xff, &flag))
|
||||
{
|
||||
/* clear current rate */
|
||||
flag &= ~DS3231_CTRL_SQWAVE_8192HZ;
|
||||
/* set new rate */
|
||||
flag |= freq;
|
||||
|
||||
return ds3231_setFlag(DS3231_ADDR_CONTROL, flag, DS3231_REPLACE);
|
||||
return ds3231_setFlag(dev, DS3231_ADDR_CONTROL, flag, DS3231_REPLACE);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ds3231_getRawTemp(int16_t *temp)
|
||||
bool ds3231_getRawTemp(i2c_dev_t *dev, int16_t *temp)
|
||||
{
|
||||
uint8_t data[2];
|
||||
|
||||
data[0] = DS3231_ADDR_TEMP;
|
||||
if (ds3231_send(data, 1) && ds3231_recv(data, 2)) {
|
||||
if (!ds3231_recv(dev, DS3231_ADDR_TEMP,data, 2))
|
||||
{
|
||||
*temp = (int16_t)(int8_t)data[0] << 2 | data[1] >> 6;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -226,11 +226,11 @@ bool ds3231_getRawTemp(int16_t *temp)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool ds3231_getTempInteger(int8_t *temp)
|
||||
bool ds3231_getTempInteger(i2c_dev_t *dev, int8_t *temp)
|
||||
{
|
||||
int16_t tInt;
|
||||
|
||||
if (ds3231_getRawTemp(&tInt)) {
|
||||
if (ds3231_getRawTemp(dev, &tInt)) {
|
||||
*temp = tInt >> 2;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -238,11 +238,11 @@ bool ds3231_getTempInteger(int8_t *temp)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool ds3231_getTempFloat(float *temp)
|
||||
bool ds3231_getTempFloat(i2c_dev_t *dev, float *temp)
|
||||
{
|
||||
int16_t tInt;
|
||||
|
||||
if (ds3231_getRawTemp(&tInt)) {
|
||||
if (ds3231_getRawTemp(dev, &tInt)) {
|
||||
*temp = tInt * 0.25;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -250,18 +250,13 @@ bool ds3231_getTempFloat(float *temp)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool ds3231_getTime(struct tm *time)
|
||||
bool ds3231_getTime(i2c_dev_t *dev, struct tm *time)
|
||||
{
|
||||
uint8_t data[7];
|
||||
|
||||
/* start register address */
|
||||
data[0] = DS3231_ADDR_TIME;
|
||||
if (!ds3231_send(data, 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* read time */
|
||||
if (!ds3231_recv(data, 7)) {
|
||||
if (ds3231_recv(dev, DS3231_ADDR_TIME, data, 7))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -287,10 +282,5 @@ bool ds3231_getTime(struct tm *time)
|
|||
//applyTZ(time);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void ds3231_Init(uint8_t scl, uint8_t sda)
|
||||
{
|
||||
i2c_init(scl, sda);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
#include "i2c/i2c.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
@ -87,7 +89,7 @@ enum {
|
|||
* I suggest using GMT and applying timezone and DST when read back
|
||||
* returns true to indicate success
|
||||
*/
|
||||
bool ds3231_setTime(struct tm *time);
|
||||
int ds3231_setTime(i2c_dev_t *dev, struct tm *time);
|
||||
|
||||
/* Set alarms
|
||||
* alarm1 works with seconds, minutes, hours and day of week/month, or fires every second
|
||||
|
|
@ -100,30 +102,30 @@ bool ds3231_setTime(struct tm *time);
|
|||
* if you want to enable interrupts for the alarms you need to do that separately
|
||||
* returns true to indicate success
|
||||
*/
|
||||
bool ds3231_setAlarm(uint8_t alarms, struct tm *time1, uint8_t option1, struct tm *time2, uint8_t option2);
|
||||
int ds3231_setAlarm(i2c_dev_t *dev, uint8_t alarms, struct tm *time1, uint8_t option1, struct tm *time2, uint8_t option2);
|
||||
|
||||
/* Check if oscillator has previously stopped, e.g. no power/battery or disabled
|
||||
* sets flag to true if there has been a stop
|
||||
* returns true to indicate success
|
||||
*/
|
||||
bool ds3231_getOscillatorStopFlag(bool *flag);
|
||||
bool ds3231_getOscillatorStopFlag(i2c_dev_t *dev, bool *flag);
|
||||
|
||||
/* Clear the oscillator stopped flag
|
||||
* returns true to indicate success
|
||||
*/
|
||||
bool ds3231_clearOscillatorStopFlag();
|
||||
bool ds3231_clearOscillatorStopFlag(i2c_dev_t *dev);
|
||||
|
||||
/* Check which alarm(s) have past
|
||||
* sets alarms to DS3231_ALARM_NONE/DS3231_ALARM_1/DS3231_ALARM_2/DS3231_ALARM_BOTH
|
||||
* returns true to indicate success
|
||||
*/
|
||||
bool ds3231_getAlarmFlags(uint8_t *alarms);
|
||||
bool ds3231_getAlarmFlags(i2c_dev_t *dev, uint8_t *alarms);
|
||||
|
||||
/* Clear alarm past flag(s)
|
||||
* pass DS3231_ALARM_1/DS3231_ALARM_2/DS3231_ALARM_BOTH
|
||||
* returns true to indicate success
|
||||
*/
|
||||
bool ds3231_clearAlarmFlags(uint8_t alarm);
|
||||
bool ds3231_clearAlarmFlags(i2c_dev_t *dev, uint8_t alarm);
|
||||
|
||||
/* enable alarm interrupts (and disables squarewave)
|
||||
* pass DS3231_ALARM_1/DS3231_ALARM_2/DS3231_ALARM_BOTH
|
||||
|
|
@ -132,61 +134,60 @@ bool ds3231_clearAlarmFlags(uint8_t alarm);
|
|||
* interrupt enabled, else it will trigger immediately
|
||||
* returns true to indicate success
|
||||
*/
|
||||
bool ds3231_enableAlarmInts(uint8_t alarms);
|
||||
bool ds3231_enableAlarmInts(i2c_dev_t *dev, uint8_t alarms);
|
||||
|
||||
/* Disable alarm interrupts (does not (re-)enable squarewave)
|
||||
* pass DS3231_ALARM_1/DS3231_ALARM_2/DS3231_ALARM_BOTH
|
||||
* returns true to indicate success
|
||||
*/
|
||||
bool ds3231_disableAlarmInts(uint8_t alarms);
|
||||
bool ds3231_disableAlarmInts(i2c_dev_t *dev, uint8_t alarms);
|
||||
|
||||
/* Enable the output of 32khz signal
|
||||
* returns true to indicate success
|
||||
*/
|
||||
bool ds3231_enable32khz();
|
||||
bool ds3231_enable32khz(i2c_dev_t *dev);
|
||||
|
||||
/* Disable the output of 32khz signal
|
||||
* returns true to indicate success
|
||||
*/
|
||||
bool ds3231_disable32khz();
|
||||
bool ds3231_disable32khz(i2c_dev_t *dev);
|
||||
|
||||
/* Enable the squarewave output (disables alarm interrupt functionality)
|
||||
* returns true to indicate success
|
||||
*/
|
||||
bool ds3231_enableSquarewave();
|
||||
bool ds3231_enableSquarewave(i2c_dev_t *dev);
|
||||
|
||||
/* Disable the squarewave output (which re-enables alarm interrupts, but individual
|
||||
* alarm interrupts also need to be enabled, if not already, before they will trigger)
|
||||
* returns true to indicate success
|
||||
*/
|
||||
bool ds3231_disableSquarewave();
|
||||
bool ds3231_disableSquarewave(i2c_dev_t *dev);
|
||||
|
||||
/* Set the frequency of the squarewave output (but does not enable it)
|
||||
* pass DS3231_SQUAREWAVE_RATE_1HZ/DS3231_SQUAREWAVE_RATE_1024HZ/DS3231_SQUAREWAVE_RATE_4096HZ/DS3231_SQUAREWAVE_RATE_8192HZ
|
||||
* returns true to indicate success
|
||||
*/
|
||||
bool ds3231_setSquarewaveFreq(uint8_t freq);
|
||||
bool ds3231_setSquarewaveFreq(i2c_dev_t *dev, uint8_t freq);
|
||||
|
||||
/* Get the raw value
|
||||
* returns true to indicate success
|
||||
*/
|
||||
bool ds3231_getRawTemp(int16_t *temp);
|
||||
bool ds3231_getRawTemp(i2c_dev_t *dev, int16_t *temp);
|
||||
|
||||
/* Get the temperature as an integer
|
||||
* returns true to indicate success
|
||||
*/
|
||||
bool ds3231_getTempInteger(int8_t *temp);
|
||||
bool ds3231_getTempInteger(i2c_dev_t *dev, int8_t *temp);
|
||||
|
||||
/* Get the temerapture as a float (in quarter degree increments)
|
||||
* returns true to indicate success
|
||||
*/
|
||||
bool ds3231_getTempFloat(float *temp);
|
||||
bool ds3231_getTempFloat(i2c_dev_t *dev, float *temp);
|
||||
|
||||
/* Get the time from the rtc, populates a supplied tm struct
|
||||
* returns true to indicate success
|
||||
*/
|
||||
bool ds3231_getTime(struct tm *time);
|
||||
void ds3231_Init(uint8_t scl, uint8_t sda);
|
||||
bool ds3231_getTime(i2c_dev_t *dev, struct tm *time);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,8 +1,8 @@
|
|||
/*----------------------------------------------------------------------------/
|
||||
/ FatFs - Generic FAT file system module R0.12b /
|
||||
/ FatFs - Generic FAT file system module R0.12c /
|
||||
/-----------------------------------------------------------------------------/
|
||||
/
|
||||
/ Copyright (C) 2016, ChaN, all right reserved.
|
||||
/ Copyright (C) 2017, ChaN, all right reserved.
|
||||
/
|
||||
/ FatFs module is an open source software. Redistribution and use of FatFs in
|
||||
/ source and binary forms, with or without modification, are permitted provided
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
|
||||
#ifndef _FATFS
|
||||
#define _FATFS 68020 /* Revision ID */
|
||||
#define _FATFS 68300 /* Revision ID */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
@ -42,13 +42,6 @@ typedef struct {
|
|||
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
|
||||
} PARTITION;
|
||||
extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
|
||||
#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */
|
||||
#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */
|
||||
|
||||
#else /* Single partition configuration */
|
||||
#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */
|
||||
#define LD2PT(vol) 0 /* Find first valid partition or in SFD */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -140,14 +133,15 @@ typedef struct {
|
|||
FATFS* fs; /* Pointer to the owner file system object */
|
||||
WORD id; /* Owner file system mount ID */
|
||||
BYTE attr; /* Object attribute */
|
||||
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:got flagmented, b2:sub-directory stretched) */
|
||||
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:flagmented in this session, b2:sub-directory stretched) */
|
||||
DWORD sclust; /* Object start cluster (0:no cluster or root directory) */
|
||||
FSIZE_t objsize; /* Object size (valid when sclust != 0) */
|
||||
#if _FS_EXFAT
|
||||
DWORD n_cont; /* Size of coutiguous part, clusters - 1 (valid when stat == 3) */
|
||||
DWORD n_cont; /* Size of first fragment, clusters - 1 (valid when stat == 3) */
|
||||
DWORD n_frag; /* Size of last fragment needs to be written (valid when not zero) */
|
||||
DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */
|
||||
DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */
|
||||
DWORD c_ofs; /* Offset in the containing directory (valid when sclust != 0) */
|
||||
DWORD c_ofs; /* Offset in the containing directory (valid when sclust != 0 and non-directory object) */
|
||||
#endif
|
||||
#if _FS_LOCK != 0
|
||||
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
|
||||
|
|
@ -163,7 +157,7 @@ typedef struct {
|
|||
BYTE flag; /* File status flags */
|
||||
BYTE err; /* Abort flag (error code) */
|
||||
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
|
||||
DWORD clust; /* Current cluster of fpter (invalid when fprt is 0) */
|
||||
DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */
|
||||
DWORD sect; /* Sector number appearing in buf[] (0:invalid) */
|
||||
#if !_FS_READONLY
|
||||
DWORD dir_sect; /* Sector number containing the directory entry */
|
||||
|
|
@ -185,7 +179,7 @@ typedef struct {
|
|||
_FDID obj; /* Object identifier */
|
||||
DWORD dptr; /* Current read/write offset */
|
||||
DWORD clust; /* Current cluster */
|
||||
DWORD sect; /* Current sector */
|
||||
DWORD sect; /* Current sector (0:Read operation has terminated) */
|
||||
BYTE* dir; /* Pointer to the directory item in the win[] */
|
||||
BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */
|
||||
#if _USE_LFN != 0
|
||||
|
|
@ -285,6 +279,7 @@ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the fil
|
|||
#define f_size(fp) ((fp)->obj.objsize)
|
||||
#define f_rewind(fp) f_lseek((fp), 0)
|
||||
#define f_rewinddir(dp) f_readdir((dp), 0)
|
||||
#define f_rmdir(path) f_unlink(path)
|
||||
|
||||
#ifndef EOF
|
||||
#define EOF (-1)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*---------------------------------------------------------------------------/
|
||||
/ FatFs - FAT file system module configuration file
|
||||
/---------------------------------------------------------------------------*/
|
||||
#define _FFCONF 68020 /* Revision ID */
|
||||
#define _FFCONF 68300 /* Revision ID */
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Function Configurations
|
||||
|
|
|
|||
|
|
@ -60,8 +60,8 @@ static void write_nibble(const hd44780_t *lcd, uint8_t b, bool rs)
|
|||
| (rs ? 1 << lcd->pins.rs : 0)
|
||||
| (lcd->backlight ? 1 << lcd->pins.bl : 0);
|
||||
|
||||
pcf8574_port_write(lcd->addr, data | (1 << lcd->pins.e));
|
||||
pcf8574_port_write(lcd->addr, data);
|
||||
pcf8574_port_write(&lcd->i2c_dev, data | (1 << lcd->pins.e));
|
||||
pcf8574_port_write(&lcd->i2c_dev, data);
|
||||
#else
|
||||
gpio_write(lcd->pins.d7, (b >> 3) & 1);
|
||||
gpio_write(lcd->pins.d6, (b >> 2) & 1);
|
||||
|
|
@ -164,7 +164,7 @@ void hd44780_set_backlight(hd44780_t *lcd, bool on)
|
|||
return;
|
||||
|
||||
#if (HD44780_I2C)
|
||||
pcf8574_gpio_write(lcd->addr, lcd->pins.bl, on);
|
||||
pcf8574_gpio_write(&lcd->i2c_dev, lcd->pins.bl, on);
|
||||
#else
|
||||
gpio_write(lcd->pins.bl, on);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -12,7 +12,10 @@
|
|||
#include <stdbool.h>
|
||||
|
||||
#ifndef HD44780_I2C
|
||||
#define HD44780_I2C 0
|
||||
#define HD44780_I2C 1
|
||||
#endif
|
||||
#if (HD44780_I2C)
|
||||
#include <i2c/i2c.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
@ -36,7 +39,9 @@ typedef enum
|
|||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t addr; //!< PCF8574 address (0b0100<A2><A1><A0>)
|
||||
#if (HD44780_I2C)
|
||||
i2c_dev_t i2c_dev; //!< PCF8574 device settings (0b0100<A2><A1><A0>)
|
||||
#endif
|
||||
struct
|
||||
{
|
||||
uint8_t rs; //!< gpio/register bit used for RS pin
|
||||
|
|
|
|||
|
|
@ -6,10 +6,8 @@
|
|||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include "hmc5883l.h"
|
||||
#include <i2c/i2c.h>
|
||||
#include <espressif/esp_common.h>
|
||||
|
||||
#define ADDR 0x1e
|
||||
|
||||
#define REG_CR_A 0x00
|
||||
#define REG_CR_B 0x01
|
||||
|
|
@ -38,6 +36,8 @@
|
|||
|
||||
#define MEASUREMENT_TIMEOUT 6000
|
||||
|
||||
#define timeout_expired(start, len) ((uint32_t)(sdk_system_get_time() - (start)) >= (len))
|
||||
|
||||
static const float gain_values [] = {
|
||||
[HMC5883L_GAIN_1370] = 0.73,
|
||||
[HMC5883L_GAIN_1090] = 0.92,
|
||||
|
|
@ -52,119 +52,120 @@ static const float gain_values [] = {
|
|||
static float current_gain;
|
||||
static hmc5883l_operating_mode_t current_mode;
|
||||
|
||||
static inline void write_register(uint8_t reg, uint8_t val)
|
||||
static inline void write_register(i2c_dev_t* dev, uint8_t reg, uint8_t val)
|
||||
{
|
||||
uint8_t buf[2] = { reg, val };
|
||||
i2c_slave_write(ADDR, buf, 2);
|
||||
i2c_slave_write(dev->bus, dev->addr, ®, &val, 1);
|
||||
}
|
||||
|
||||
static inline uint8_t read_register(uint8_t reg)
|
||||
static inline uint8_t read_register(i2c_dev_t* dev, uint8_t reg)
|
||||
{
|
||||
uint8_t res;
|
||||
i2c_slave_read(ADDR, reg, &res, 1);
|
||||
i2c_slave_read(dev->bus, dev->addr, ®, &res, 1);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline void update_register(uint8_t reg, uint8_t mask, uint8_t val)
|
||||
static inline void update_register(i2c_dev_t* dev, uint8_t reg, uint8_t mask, uint8_t val)
|
||||
{
|
||||
write_register(reg, (read_register(reg) & mask) | val);
|
||||
write_register(dev, reg, (read_register(dev, reg) & mask) | val);
|
||||
}
|
||||
|
||||
bool hmc5883l_init()
|
||||
bool hmc5883l_init(i2c_dev_t* dev)
|
||||
{
|
||||
if (hmc5883l_get_id() != HMC5883L_ID)
|
||||
if (hmc5883l_get_id(dev) != HMC5883L_ID)
|
||||
return false;
|
||||
current_gain = gain_values[hmc5883l_get_gain()];
|
||||
current_mode = hmc5883l_get_operating_mode();
|
||||
current_gain = gain_values[hmc5883l_get_gain(dev)];
|
||||
current_mode = hmc5883l_get_operating_mode(dev);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t hmc5883l_get_id()
|
||||
uint32_t hmc5883l_get_id(i2c_dev_t* dev)
|
||||
{
|
||||
uint32_t res = 0;
|
||||
i2c_slave_read(ADDR, REG_ID_A, (uint8_t *)&res, 3);
|
||||
uint8_t reg = REG_ID_A;
|
||||
i2c_slave_read(dev->bus, dev->addr, ®, (uint8_t *)&res, 3);
|
||||
return res;
|
||||
}
|
||||
|
||||
hmc5883l_operating_mode_t hmc5883l_get_operating_mode()
|
||||
hmc5883l_operating_mode_t hmc5883l_get_operating_mode(i2c_dev_t* dev)
|
||||
{
|
||||
uint8_t res = read_register(REG_MODE) & MASK_MD;
|
||||
uint8_t res = read_register(dev, REG_MODE) & MASK_MD;
|
||||
return res == 0 ? HMC5883L_MODE_CONTINUOUS : HMC5883L_MODE_SINGLE;
|
||||
}
|
||||
|
||||
void hmc5883l_set_operating_mode(hmc5883l_operating_mode_t mode)
|
||||
void hmc5883l_set_operating_mode(i2c_dev_t* dev, hmc5883l_operating_mode_t mode)
|
||||
{
|
||||
write_register(REG_MODE, mode);
|
||||
write_register(dev, REG_MODE, mode);
|
||||
current_mode = mode;
|
||||
}
|
||||
|
||||
hmc5883l_samples_averaged_t hmc5883l_get_samples_averaged()
|
||||
hmc5883l_samples_averaged_t hmc5883l_get_samples_averaged(i2c_dev_t* dev)
|
||||
{
|
||||
return (read_register(REG_CR_A) & MASK_MA) >> BIT_MA;
|
||||
return (read_register(dev, REG_CR_A) & MASK_MA) >> BIT_MA;
|
||||
}
|
||||
|
||||
void hmc5883l_set_samples_averaged(hmc5883l_samples_averaged_t samples)
|
||||
void hmc5883l_set_samples_averaged(i2c_dev_t* dev, hmc5883l_samples_averaged_t samples)
|
||||
{
|
||||
update_register(REG_CR_A, MASK_MA, samples << BIT_MA);
|
||||
update_register(dev, REG_CR_A, MASK_MA, samples << BIT_MA);
|
||||
}
|
||||
|
||||
hmc5883l_data_rate_t hmc5883l_get_data_rate()
|
||||
hmc5883l_data_rate_t hmc5883l_get_data_rate(i2c_dev_t* dev)
|
||||
{
|
||||
return (read_register(REG_CR_A) & MASK_DO) >> BIT_DO;
|
||||
return (read_register(dev, REG_CR_A) & MASK_DO) >> BIT_DO;
|
||||
}
|
||||
|
||||
void hmc5883l_set_data_rate(hmc5883l_data_rate_t rate)
|
||||
void hmc5883l_set_data_rate(i2c_dev_t* dev, hmc5883l_data_rate_t rate)
|
||||
{
|
||||
update_register(REG_CR_A, MASK_DO, rate << BIT_DO);
|
||||
update_register(dev, REG_CR_A, MASK_DO, rate << BIT_DO);
|
||||
}
|
||||
|
||||
hmc5883l_bias_t hmc5883l_get_bias()
|
||||
hmc5883l_bias_t hmc5883l_get_bias(i2c_dev_t* dev)
|
||||
{
|
||||
return read_register(REG_CR_A) & MASK_MS;
|
||||
return read_register(dev, REG_CR_A) & MASK_MS;
|
||||
}
|
||||
|
||||
void hmc5883l_set_bias(hmc5883l_bias_t bias)
|
||||
void hmc5883l_set_bias(i2c_dev_t* dev, hmc5883l_bias_t bias)
|
||||
{
|
||||
update_register(REG_CR_A, MASK_MS, bias);
|
||||
update_register(dev, REG_CR_A, MASK_MS, bias);
|
||||
}
|
||||
|
||||
hmc5883l_gain_t hmc5883l_get_gain()
|
||||
hmc5883l_gain_t hmc5883l_get_gain(i2c_dev_t* dev)
|
||||
{
|
||||
return read_register(REG_CR_B) >> BIT_GN;
|
||||
return read_register(dev, REG_CR_B) >> BIT_GN;
|
||||
}
|
||||
|
||||
void hmc5883l_set_gain(hmc5883l_gain_t gain)
|
||||
void hmc5883l_set_gain(i2c_dev_t* dev, hmc5883l_gain_t gain)
|
||||
{
|
||||
write_register(REG_CR_B, gain << BIT_GN);
|
||||
write_register(dev, REG_CR_B, gain << BIT_GN);
|
||||
current_gain = gain_values[gain];
|
||||
}
|
||||
|
||||
bool hmc5883l_data_is_locked()
|
||||
bool hmc5883l_data_is_locked(i2c_dev_t* dev)
|
||||
{
|
||||
return read_register(REG_STAT) & MASK_DL;
|
||||
return read_register(dev, REG_STAT) & MASK_DL;
|
||||
}
|
||||
|
||||
bool hmc5883l_data_is_ready()
|
||||
bool hmc5883l_data_is_ready(i2c_dev_t* dev)
|
||||
{
|
||||
return read_register(REG_STAT) & MASK_DR;
|
||||
return read_register(dev, REG_STAT) & MASK_DR;
|
||||
}
|
||||
|
||||
bool hmc5883l_get_raw_data(hmc5883l_raw_data_t *data)
|
||||
bool hmc5883l_get_raw_data(i2c_dev_t* dev, hmc5883l_raw_data_t *data)
|
||||
{
|
||||
if (current_mode == HMC5883L_MODE_SINGLE)
|
||||
{
|
||||
// overwrite mode register for measurement
|
||||
hmc5883l_set_operating_mode(current_mode);
|
||||
hmc5883l_set_operating_mode(dev, current_mode);
|
||||
// wait for data
|
||||
uint32_t timeout = sdk_system_get_time() + MEASUREMENT_TIMEOUT;
|
||||
while (!hmc5883l_data_is_ready())
|
||||
uint32_t start = sdk_system_get_time();
|
||||
while (!hmc5883l_data_is_ready(dev))
|
||||
{
|
||||
if (sdk_system_get_time() >= timeout)
|
||||
if (timeout_expired(start, MEASUREMENT_TIMEOUT))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
uint8_t buf[6];
|
||||
i2c_slave_read(ADDR, REG_DX_H, buf, 6);
|
||||
uint8_t reg = REG_DX_H;
|
||||
i2c_slave_read(dev->bus, dev->addr, ®, buf, 6);
|
||||
data->x = ((int16_t)buf[REG_DX_H - REG_DX_H] << 8) | buf[REG_DX_L - REG_DX_H];
|
||||
data->y = ((int16_t)buf[REG_DY_H - REG_DX_H] << 8) | buf[REG_DY_L - REG_DX_H];
|
||||
data->z = ((int16_t)buf[REG_DZ_H - REG_DX_H] << 8) | buf[REG_DZ_L - REG_DX_H];
|
||||
|
|
@ -178,11 +179,11 @@ void hmc5883l_raw_to_mg(const hmc5883l_raw_data_t *raw, hmc5883l_data_t *mg)
|
|||
mg->z = raw->z * current_gain;
|
||||
}
|
||||
|
||||
bool hmc5883l_get_data(hmc5883l_data_t *data)
|
||||
bool hmc5883l_get_data(i2c_dev_t* dev, hmc5883l_data_t *data)
|
||||
{
|
||||
hmc5883l_raw_data_t raw;
|
||||
|
||||
if (!hmc5883l_get_raw_data(&raw))
|
||||
if (!hmc5883l_get_raw_data(dev, &raw))
|
||||
return false;
|
||||
hmc5883l_raw_to_mg(&raw, data);
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -10,12 +10,15 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <i2c/i2c.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#define HMC5883L_ADDR 0x1e
|
||||
|
||||
#define HMC5883L_ID 0x00333448 // "H43"
|
||||
|
||||
/**
|
||||
|
|
@ -101,82 +104,82 @@ typedef struct
|
|||
* \brief Init device
|
||||
* \return false if error occured
|
||||
*/
|
||||
bool hmc5883l_init();
|
||||
bool hmc5883l_init(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* \brief Get device ID
|
||||
* Always returns 0x00333448 if IC functioning properly.
|
||||
* \return Device ID
|
||||
*/
|
||||
uint32_t hmc5883l_get_id();
|
||||
uint32_t hmc5883l_get_id(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* \brief Get operating mode
|
||||
* \return Measurement mode
|
||||
*/
|
||||
hmc5883l_operating_mode_t hmc5883l_get_operating_mode();
|
||||
hmc5883l_operating_mode_t hmc5883l_get_operating_mode(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* \brief Set operating mode
|
||||
* \param mode Measurement mode
|
||||
*/
|
||||
void hmc5883l_set_operating_mode(hmc5883l_operating_mode_t mode);
|
||||
void hmc5883l_set_operating_mode(i2c_dev_t* dev, hmc5883l_operating_mode_t mode);
|
||||
|
||||
/**
|
||||
* \brief Get number of samples averaged per measurement output
|
||||
* \return Number of samples
|
||||
*/
|
||||
hmc5883l_samples_averaged_t hmc5883l_get_samples_averaged();
|
||||
hmc5883l_samples_averaged_t hmc5883l_get_samples_averaged(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* \brief Set number of samples averaged per measurement output
|
||||
* \param samples Number of samples
|
||||
*/
|
||||
void hmc5883l_set_samples_averaged(hmc5883l_samples_averaged_t samples);
|
||||
void hmc5883l_set_samples_averaged(i2c_dev_t* dev, hmc5883l_samples_averaged_t samples);
|
||||
|
||||
/**
|
||||
* \brief Get data output rate in continuous measurement mode
|
||||
* \return Data output rate
|
||||
*/
|
||||
hmc5883l_data_rate_t hmc5883l_get_data_rate();
|
||||
hmc5883l_data_rate_t hmc5883l_get_data_rate(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* \brief Set data output rate in continuous measurement mode
|
||||
* \param rate Data output rate
|
||||
*/
|
||||
void hmc5883l_set_data_rate(hmc5883l_data_rate_t rate);
|
||||
void hmc5883l_set_data_rate(i2c_dev_t* dev, hmc5883l_data_rate_t rate);
|
||||
|
||||
/**
|
||||
* \brief Get measurement mode (bias of the axes)
|
||||
* See datasheet for self test description
|
||||
* \return Bias
|
||||
*/
|
||||
hmc5883l_bias_t hmc5883l_get_bias();
|
||||
hmc5883l_bias_t hmc5883l_get_bias(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* \brief Set measurement mode (bias of the axes)
|
||||
* See datasheet for self test description
|
||||
* \param bias Bias
|
||||
*/
|
||||
void hmc5883l_set_bias(hmc5883l_bias_t bias);
|
||||
void hmc5883l_set_bias(i2c_dev_t* dev, hmc5883l_bias_t bias);
|
||||
|
||||
/**
|
||||
* \brief Get device gain
|
||||
* \return Current gain
|
||||
*/
|
||||
hmc5883l_gain_t hmc5883l_get_gain();
|
||||
hmc5883l_gain_t hmc5883l_get_gain(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* \brief Set device gain
|
||||
* \param gain Gain
|
||||
*/
|
||||
void hmc5883l_set_gain(hmc5883l_gain_t gain);
|
||||
void hmc5883l_set_gain(i2c_dev_t* dev, hmc5883l_gain_t gain);
|
||||
|
||||
/**
|
||||
* \brief Get data state
|
||||
* \return true when data is written to all six data registers
|
||||
*/
|
||||
bool hmc5883l_data_is_ready();
|
||||
bool hmc5883l_data_is_ready(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* \brief Get lock state.
|
||||
|
|
@ -188,14 +191,14 @@ bool hmc5883l_data_is_ready();
|
|||
* 4. power is reset.
|
||||
* \return true when data registers is locked
|
||||
*/
|
||||
bool hmc5883l_data_is_locked();
|
||||
bool hmc5883l_data_is_locked(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* \brief Get raw magnetic data
|
||||
* \param data Pointer to the struct to write raw data
|
||||
* \return false if error occured in single measurement mode, always true in continuous mode
|
||||
*/
|
||||
bool hmc5883l_get_raw_data(hmc5883l_raw_data_t *data);
|
||||
bool hmc5883l_get_raw_data(i2c_dev_t* dev, hmc5883l_raw_data_t *data);
|
||||
|
||||
/**
|
||||
* \brief Convert raw magnetic data to milligausses
|
||||
|
|
@ -209,7 +212,7 @@ void hmc5883l_raw_to_mg(const hmc5883l_raw_data_t *raw, hmc5883l_data_t *mg);
|
|||
* \param data Pointer to the struct to write data
|
||||
* \return false if error occured in single measurement mode, always true in continuous mode
|
||||
*/
|
||||
bool hmc5883l_get_data(hmc5883l_data_t *data);
|
||||
bool hmc5883l_get_data(i2c_dev_t* dev, hmc5883l_data_t *data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@
|
|||
|
||||
/** Set this to 1 on platforms where strnstr is not available */
|
||||
#ifndef LWIP_HTTPD_STRNSTR_PRIVATE
|
||||
#define LWIP_HTTPD_STRNSTR_PRIVATE 1
|
||||
#define LWIP_HTTPD_STRNSTR_PRIVATE 0
|
||||
#endif
|
||||
|
||||
/** Set this to one to show error pages when parsing a request fails instead
|
||||
|
|
@ -2675,7 +2675,7 @@ http_accept(void *arg, struct tcp_pcb *pcb, err_t err)
|
|||
* Initialize the httpd with the specified local address.
|
||||
*/
|
||||
static void
|
||||
httpd_init_addr(ip_addr_t *local_addr)
|
||||
httpd_init_addr(const ip_addr_t *local_addr)
|
||||
{
|
||||
struct tcp_pcb *pcb;
|
||||
err_t err;
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ void httpd_post_data_recved(void *connection, u16_t recved_len);
|
|||
|
||||
#endif /* LWIP_HTTPD_SUPPORT_POST */
|
||||
|
||||
enum {
|
||||
typedef enum {
|
||||
WS_TEXT_MODE = 0x01,
|
||||
WS_BIN_MODE = 0x02,
|
||||
} WS_MODE;
|
||||
|
|
|
|||
|
|
@ -2,18 +2,8 @@
|
|||
|
||||
This time a driver for the excellent esp-open-rtos. This is a bit banging I2C driver based on the Wikipedia pesudo C code [1].
|
||||
|
||||
### Adding to your project
|
||||
|
||||
Add the driver to your project as a submodule rather than cloning it:
|
||||
|
||||
````
|
||||
% git submodule add https://github.com/kanflo/esp-open-rtos-driver-i2c.git i2c
|
||||
````
|
||||
The esp-open-rtos makefile-fu will make sure the driver is built.
|
||||
|
||||
### Usage
|
||||
|
||||
|
||||
````
|
||||
#include <i2c.h>
|
||||
|
||||
|
|
@ -23,18 +13,23 @@ The esp-open-rtos makefile-fu will make sure the driver is built.
|
|||
uint8_t slave_addr = 0x20;
|
||||
uint8_t reg_addr = 0x1f;
|
||||
uint8_t reg_data;
|
||||
uint8_t data[] = {reg_addr, 0xc8};
|
||||
|
||||
i2c_init(SCL_PIN, SDA_PIN);
|
||||
|
||||
// Write data to slave
|
||||
bool success = i2c_slave_write(slave_addr, data, sizeof(data));
|
||||
// Write 1 byte to slave register
|
||||
int err = i2c_slave_write(slave_addr, ®_addr, &data, 1);
|
||||
if (err != 0)
|
||||
{
|
||||
// do something with error
|
||||
}
|
||||
|
||||
// Issue write to slave, sending reg_addr, followed by reading 1 byte
|
||||
success = i2c_slave_read(slave_addr, ®_addr, reg_data, 1);
|
||||
err = i2c_slave_read(slave_addr, ®_addr, ®_data, 1);
|
||||
|
||||
````
|
||||
|
||||
For details please see `extras/i2c/i2c.h`.
|
||||
|
||||
The driver is released under the MIT license.
|
||||
|
||||
[1] https://en.wikipedia.org/wiki/I²C#Example_of_bit-banging_the_I.C2.B2C_Master_protocol
|
||||
335
extras/i2c/i2c.c
335
extras/i2c/i2c.c
|
|
@ -1,18 +1,18 @@
|
|||
/*
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2015 Johan Kanflo (github.com/kanflo)
|
||||
*
|
||||
*
|
||||
* 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
|
||||
|
|
@ -24,217 +24,306 @@
|
|||
|
||||
#include <esp8266.h>
|
||||
#include <espressif/esp_misc.h> // sdk_os_delay_us
|
||||
#include <espressif/esp_system.h>
|
||||
#include "i2c.h"
|
||||
|
||||
//#define I2C_DEBUG true
|
||||
|
||||
// I2C driver for ESP8266 written for use with esp-open-rtos
|
||||
// Based on https://en.wikipedia.org/wiki/I²C#Example_of_bit-banging_the_I.C2.B2C_Master_protocol
|
||||
|
||||
// With calling overhead, we end up at ~100kbit/s
|
||||
#define CLK_HALF_PERIOD_US (1)
|
||||
#ifdef I2C_DEBUG
|
||||
#define debug(fmt, ...) printf("%s: " fmt "\n", "I2C", ## __VA_ARGS__)
|
||||
#else
|
||||
#define debug(fmt, ...)
|
||||
#endif
|
||||
|
||||
#define CLK_STRETCH (10)
|
||||
|
||||
static bool started;
|
||||
static uint8_t g_scl_pin;
|
||||
static uint8_t g_sda_pin;
|
||||
static uint8_t freq ; // Store CPU frequency for optimisation speed in delay function ( Warning: Don't change CPU frequency during a transaction)
|
||||
static i2c_bus_description_t i2c_bus[MAX_I2C_BUS];
|
||||
|
||||
void i2c_init(uint8_t scl_pin, uint8_t sda_pin)
|
||||
inline bool i2c_status(uint8_t bus)
|
||||
{
|
||||
started = false;
|
||||
g_scl_pin = scl_pin;
|
||||
g_sda_pin = sda_pin;
|
||||
|
||||
// Just to prevent these pins floating too much if not connected.
|
||||
gpio_set_pullup(g_scl_pin, 1, 1);
|
||||
gpio_set_pullup(g_sda_pin, 1, 1);
|
||||
|
||||
gpio_enable(g_scl_pin, GPIO_OUT_OPEN_DRAIN);
|
||||
gpio_enable(g_sda_pin, GPIO_OUT_OPEN_DRAIN);
|
||||
|
||||
// I2C bus idle state.
|
||||
gpio_write(g_scl_pin, 1);
|
||||
gpio_write(g_sda_pin, 1);
|
||||
return i2c_bus[bus].started;
|
||||
}
|
||||
|
||||
static inline void i2c_delay(void)
|
||||
void i2c_init(uint8_t bus, uint8_t scl_pin, uint8_t sda_pin, i2c_freq_t freq)
|
||||
{
|
||||
sdk_os_delay_us(CLK_HALF_PERIOD_US);
|
||||
i2c_bus[bus].started = false;
|
||||
i2c_bus[bus].flag = false ;
|
||||
i2c_bus[bus].g_scl_pin = scl_pin;
|
||||
i2c_bus[bus].g_sda_pin = sda_pin;
|
||||
i2c_bus[bus].frequency = freq ;
|
||||
|
||||
// Just to prevent these pins floating too much if not connected.
|
||||
gpio_set_pullup(i2c_bus[bus].g_scl_pin, 1, 1);
|
||||
gpio_set_pullup(i2c_bus[bus].g_sda_pin, 1, 1);
|
||||
|
||||
gpio_enable(i2c_bus[bus].g_scl_pin, GPIO_OUT_OPEN_DRAIN);
|
||||
gpio_enable(i2c_bus[bus].g_sda_pin, GPIO_OUT_OPEN_DRAIN);
|
||||
|
||||
// I2C bus idle state.
|
||||
gpio_write(i2c_bus[bus].g_scl_pin, 1);
|
||||
gpio_write(i2c_bus[bus].g_sda_pin, 1);
|
||||
|
||||
// Prevent user, if frequency is high
|
||||
if (sdk_system_get_cpu_freq() == SYS_CPU_80MHZ)
|
||||
if (i2c_freq_array[i2c_bus[bus].frequency][1] == 1)
|
||||
debug("Max frequency is 320Khz at 80MHz");
|
||||
|
||||
}
|
||||
|
||||
void i2c_frequency(uint8_t bus, i2c_freq_t freq)
|
||||
{
|
||||
i2c_bus[bus].frequency = freq ;
|
||||
}
|
||||
|
||||
static inline void i2c_delay(uint8_t bus)
|
||||
{
|
||||
uint32_t delay;
|
||||
if (freq == SYS_CPU_160MHZ)
|
||||
{
|
||||
delay = i2c_freq_array[i2c_bus[bus].frequency][0];
|
||||
__asm volatile (
|
||||
"1: addi %0, %0, -1" "\n"
|
||||
"bnez %0, 1b" "\n"
|
||||
:: "a" (delay));
|
||||
}
|
||||
else
|
||||
{
|
||||
delay = i2c_freq_array[i2c_bus[bus].frequency][1];
|
||||
__asm volatile (
|
||||
"1: addi %0, %0, -1" "\n"
|
||||
"bnez %0, 1b" "\n"
|
||||
:: "a" (delay));
|
||||
}
|
||||
}
|
||||
|
||||
// Set SCL as input, allowing it to float high, and return current
|
||||
// level of line, 0 or 1
|
||||
static inline bool read_scl(void)
|
||||
static inline bool read_scl(uint8_t bus)
|
||||
{
|
||||
gpio_write(g_scl_pin, 1);
|
||||
return gpio_read(g_scl_pin); // Clock high, valid ACK
|
||||
gpio_write(i2c_bus[bus].g_scl_pin, 1);
|
||||
return gpio_read(i2c_bus[bus].g_scl_pin); // Clock high, valid ACK
|
||||
}
|
||||
|
||||
// Set SDA as input, allowing it to float high, and return current
|
||||
// level of line, 0 or 1
|
||||
static inline bool read_sda(void)
|
||||
static inline bool read_sda(uint8_t bus)
|
||||
{
|
||||
gpio_write(g_sda_pin, 1);
|
||||
gpio_write(i2c_bus[bus].g_sda_pin, 1);
|
||||
// TODO: Without this delay we get arbitration lost in i2c_stop
|
||||
i2c_delay();
|
||||
return gpio_read(g_sda_pin); // Clock high, valid ACK
|
||||
i2c_delay(bus);
|
||||
return gpio_read(i2c_bus[bus].g_sda_pin); // Clock high, valid ACK
|
||||
}
|
||||
|
||||
// Actively drive SCL signal low
|
||||
static inline void clear_scl(void)
|
||||
static inline void clear_scl(uint8_t bus)
|
||||
{
|
||||
gpio_write(g_scl_pin, 0);
|
||||
gpio_write(i2c_bus[bus].g_scl_pin, 0);
|
||||
}
|
||||
|
||||
// Actively drive SDA signal low
|
||||
static inline void clear_sda(void)
|
||||
static inline void clear_sda(uint8_t bus)
|
||||
{
|
||||
gpio_write(g_sda_pin, 0);
|
||||
gpio_write(i2c_bus[bus].g_sda_pin, 0);
|
||||
}
|
||||
|
||||
// Output start condition
|
||||
void i2c_start(void)
|
||||
void i2c_start(uint8_t bus)
|
||||
{
|
||||
uint32_t clk_stretch = CLK_STRETCH;
|
||||
if (started) { // if started, do a restart cond
|
||||
freq = sdk_system_get_cpu_freq();
|
||||
if (i2c_bus[bus].started) { // if started, do a restart cond
|
||||
// Set SDA to 1
|
||||
(void) read_sda();
|
||||
i2c_delay();
|
||||
while (read_scl() == 0 && clk_stretch--) ;
|
||||
(void) read_sda(bus);
|
||||
i2c_delay(bus);
|
||||
uint32_t clk_stretch = CLK_STRETCH;
|
||||
while (read_scl(bus) == 0 && clk_stretch--) ;
|
||||
// Repeated start setup time, minimum 4.7us
|
||||
i2c_delay();
|
||||
i2c_delay(bus);
|
||||
}
|
||||
if (read_sda() == 0) {
|
||||
printf("I2C: arbitration lost in i2c_start\n");
|
||||
i2c_bus[bus].started = true;
|
||||
if (read_sda(bus) == 0) {
|
||||
debug("arbitration lost in i2c_start from bus %u",bus);
|
||||
}
|
||||
// SCL is high, set SDA from 1 to 0.
|
||||
clear_sda();
|
||||
i2c_delay();
|
||||
clear_scl();
|
||||
started = true;
|
||||
clear_sda(bus);
|
||||
i2c_delay(bus);
|
||||
clear_scl(bus);
|
||||
}
|
||||
|
||||
// Output stop condition
|
||||
void i2c_stop(void)
|
||||
bool i2c_stop(uint8_t bus)
|
||||
{
|
||||
uint32_t clk_stretch = CLK_STRETCH;
|
||||
// Set SDA to 0
|
||||
clear_sda();
|
||||
i2c_delay();
|
||||
clear_sda(bus);
|
||||
i2c_delay(bus);
|
||||
// Clock stretching
|
||||
while (read_scl() == 0 && clk_stretch--) ;
|
||||
while (read_scl(bus) == 0 && clk_stretch--) ;
|
||||
// Stop bit setup time, minimum 4us
|
||||
i2c_delay();
|
||||
i2c_delay(bus);
|
||||
// SCL is high, set SDA from 0 to 1
|
||||
if (read_sda() == 0) {
|
||||
printf("I2C: arbitration lost in i2c_stop\n");
|
||||
if (read_sda(bus) == 0) {
|
||||
debug("arbitration lost in i2c_stop from bus %u",bus);
|
||||
}
|
||||
i2c_delay();
|
||||
started = false;
|
||||
i2c_delay(bus);
|
||||
if (!i2c_bus[bus].started) {
|
||||
debug("bus %u link was break!",bus);
|
||||
return false ; //If bus was stop in other way, the current transmission Failed
|
||||
}
|
||||
i2c_bus[bus].started = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Write a bit to I2C bus
|
||||
static void i2c_write_bit(bool bit)
|
||||
static void i2c_write_bit(uint8_t bus, bool bit)
|
||||
{
|
||||
uint32_t clk_stretch = CLK_STRETCH;
|
||||
if (bit) {
|
||||
(void) read_sda();
|
||||
(void) read_sda(bus);
|
||||
} else {
|
||||
clear_sda();
|
||||
clear_sda(bus);
|
||||
}
|
||||
i2c_delay();
|
||||
i2c_delay(bus);
|
||||
// Clock stretching
|
||||
while (read_scl() == 0 && clk_stretch--) ;
|
||||
while (read_scl(bus) == 0 && clk_stretch--) ;
|
||||
// SCL is high, now data is valid
|
||||
// If SDA is high, check that nobody else is driving SDA
|
||||
if (bit && read_sda() == 0) {
|
||||
printf("I2C: arbitration lost in i2c_write_bit\n");
|
||||
if (bit && read_sda(bus) == 0) {
|
||||
debug("arbitration lost in i2c_write_bit from bus %u",bus);
|
||||
}
|
||||
i2c_delay();
|
||||
clear_scl();
|
||||
i2c_delay(bus);
|
||||
clear_scl(bus);
|
||||
}
|
||||
|
||||
// Read a bit from I2C bus
|
||||
static bool i2c_read_bit(void)
|
||||
static bool i2c_read_bit(uint8_t bus)
|
||||
{
|
||||
uint32_t clk_stretch = CLK_STRETCH;
|
||||
bool bit;
|
||||
// Let the slave drive data
|
||||
(void) read_sda();
|
||||
i2c_delay();
|
||||
(void) read_sda(bus);
|
||||
i2c_delay(bus);
|
||||
// Clock stretching
|
||||
while (read_scl() == 0 && clk_stretch--) ;
|
||||
while (read_scl(bus) == 0 && clk_stretch--) ;
|
||||
// SCL is high, now data is valid
|
||||
bit = read_sda();
|
||||
i2c_delay();
|
||||
clear_scl();
|
||||
bit = read_sda(bus);
|
||||
i2c_delay(bus);
|
||||
clear_scl(bus);
|
||||
return bit;
|
||||
}
|
||||
|
||||
bool i2c_write(uint8_t byte)
|
||||
bool i2c_write(uint8_t bus, uint8_t byte)
|
||||
{
|
||||
bool nack;
|
||||
uint8_t bit;
|
||||
for (bit = 0; bit < 8; bit++) {
|
||||
i2c_write_bit((byte & 0x80) != 0);
|
||||
i2c_write_bit(bus,(byte & 0x80) != 0);
|
||||
byte <<= 1;
|
||||
}
|
||||
nack = i2c_read_bit();
|
||||
nack = i2c_read_bit(bus);
|
||||
return !nack;
|
||||
}
|
||||
|
||||
uint8_t i2c_read(bool ack)
|
||||
uint8_t i2c_read(uint8_t bus, bool ack)
|
||||
{
|
||||
uint8_t byte = 0;
|
||||
uint8_t bit;
|
||||
for (bit = 0; bit < 8; bit++) {
|
||||
byte = (byte << 1) | i2c_read_bit();
|
||||
byte = ((byte << 1)) | (i2c_read_bit(bus));
|
||||
}
|
||||
i2c_write_bit(ack);
|
||||
i2c_write_bit(bus,ack);
|
||||
return byte;
|
||||
}
|
||||
|
||||
bool i2c_slave_write(uint8_t slave_addr, uint8_t *data, uint8_t len)
|
||||
void i2c_force_bus(uint8_t bus, bool state)
|
||||
{
|
||||
bool success = false;
|
||||
do {
|
||||
i2c_start();
|
||||
if (!i2c_write(slave_addr << 1))
|
||||
break;
|
||||
while (len--) {
|
||||
if (!i2c_write(*data++))
|
||||
break;
|
||||
}
|
||||
i2c_stop();
|
||||
success = true;
|
||||
} while(0);
|
||||
return success;
|
||||
i2c_bus[bus].force = state ;
|
||||
}
|
||||
|
||||
bool i2c_slave_read(uint8_t slave_addr, uint8_t data, uint8_t *buf, uint32_t len)
|
||||
static int i2c_bus_test(uint8_t bus)
|
||||
{
|
||||
bool success = false;
|
||||
do {
|
||||
i2c_start();
|
||||
if (!i2c_write(slave_addr << 1)) {
|
||||
break;
|
||||
}
|
||||
i2c_write(data);
|
||||
i2c_stop();
|
||||
i2c_start();
|
||||
if (!i2c_write(slave_addr << 1 | 1)) { // Slave address + read
|
||||
break;
|
||||
}
|
||||
while(len) {
|
||||
*buf = i2c_read(len == 1);
|
||||
buf++;
|
||||
len--;
|
||||
}
|
||||
success = true;
|
||||
} while(0);
|
||||
i2c_stop();
|
||||
if (!success) {
|
||||
printf("I2C: write error\n");
|
||||
taskENTER_CRITICAL(); // To prevent task swaping after checking flag and before set it!
|
||||
bool status = i2c_bus[bus].flag ; // get current status
|
||||
if(i2c_bus[bus].force)
|
||||
{
|
||||
i2c_bus[bus].flag = true ; // force bus on
|
||||
taskEXIT_CRITICAL();
|
||||
if(status)
|
||||
i2c_stop(bus); //Bus was busy, stop it.
|
||||
}
|
||||
return success;
|
||||
else
|
||||
{
|
||||
if (status)
|
||||
{
|
||||
taskEXIT_CRITICAL();
|
||||
debug("busy");
|
||||
taskYIELD(); // If bus busy, change task to try finish last com.
|
||||
return -EBUSY ; // If bus busy, inform user
|
||||
}
|
||||
else
|
||||
{
|
||||
i2c_bus[bus].flag = true ; // Set Bus busy
|
||||
taskEXIT_CRITICAL();
|
||||
}
|
||||
}
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
int i2c_slave_write(uint8_t bus, uint8_t slave_addr, const uint8_t *data, const uint8_t *buf, uint32_t len)
|
||||
{
|
||||
if(i2c_bus_test(bus))
|
||||
return -EBUSY ;
|
||||
i2c_start(bus);
|
||||
if (!i2c_write(bus, slave_addr << 1))
|
||||
goto error;
|
||||
if(data != NULL)
|
||||
if (!i2c_write(bus,*data))
|
||||
goto error;
|
||||
while (len--) {
|
||||
if (!i2c_write(bus,*buf++))
|
||||
goto error;
|
||||
}
|
||||
if (!i2c_stop(bus))
|
||||
goto error;
|
||||
i2c_bus[bus].flag = false ; // Bus free
|
||||
return 0;
|
||||
|
||||
error:
|
||||
debug("Bus %u Write Error",bus);
|
||||
i2c_stop(bus);
|
||||
i2c_bus[bus].flag = false ; // Bus free
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
int i2c_slave_read(uint8_t bus, uint8_t slave_addr, const uint8_t *data, uint8_t *buf, uint32_t len)
|
||||
{
|
||||
if(i2c_bus_test(bus))
|
||||
return -EBUSY ;
|
||||
if(data != NULL) {
|
||||
i2c_start(bus);
|
||||
if (!i2c_write(bus,slave_addr << 1))
|
||||
goto error;
|
||||
if (!i2c_write(bus,*data))
|
||||
goto error;
|
||||
if (!i2c_stop(bus))
|
||||
goto error;
|
||||
}
|
||||
i2c_start(bus);
|
||||
if (!i2c_write(bus,slave_addr << 1 | 1)) // Slave address + read
|
||||
goto error;
|
||||
while(len) {
|
||||
*buf = i2c_read(bus,len == 1);
|
||||
buf++;
|
||||
len--;
|
||||
}
|
||||
if (!i2c_stop(bus))
|
||||
goto error;
|
||||
i2c_bus[bus].flag = false ; // Bus free
|
||||
return 0;
|
||||
|
||||
error:
|
||||
debug("Read Error");
|
||||
i2c_stop(bus);
|
||||
i2c_bus[bus].flag = false ; // Bus free
|
||||
return -EIO;
|
||||
}
|
||||
|
|
|
|||
157
extras/i2c/i2c.h
157
extras/i2c/i2c.h
|
|
@ -1,18 +1,18 @@
|
|||
/*
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2015 Johan Kanflo (github.com/kanflo)
|
||||
*
|
||||
*
|
||||
* 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
|
||||
|
|
@ -27,31 +27,148 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Init bitbanging I2C driver on given pins
|
||||
void i2c_init(uint8_t scl_pin, uint8_t sda_pin);
|
||||
|
||||
// Write a byte to I2C bus. Return true if slave acked.
|
||||
bool i2c_write(uint8_t byte);
|
||||
/*
|
||||
* Define i2c bus max number
|
||||
*/
|
||||
#define MAX_I2C_BUS 2
|
||||
|
||||
// Read a byte from I2C bus. Return true if slave acked.
|
||||
uint8_t i2c_read(bool ack);
|
||||
|
||||
// Write 'len' bytes from 'buf' to slave. Return true if slave acked.
|
||||
bool i2c_slave_write(uint8_t slave_addr, uint8_t *buf, uint8_t len);
|
||||
/*
|
||||
* following array contain value for different frequency
|
||||
* Warning : 1 is minimal, that mean at 80MHz clock, frequency max is 320kHz
|
||||
* Array format is { {160MHz, 80MHz} , {160MHz, 80MHz} , ... }
|
||||
*/
|
||||
#define NB_FREQ_AVAILABLE 4
|
||||
|
||||
// Issue a read operation and send 'data', followed by reading 'len' bytes
|
||||
// from slave into 'buf'. Return true if slave acked.
|
||||
bool i2c_slave_read(uint8_t slave_addr, uint8_t data, uint8_t *buf, uint32_t len);
|
||||
typedef enum {
|
||||
I2C_FREQ_80K = 0,
|
||||
I2C_FREQ_100K,
|
||||
I2C_FREQ_400K,
|
||||
I2C_FREQ_500K,
|
||||
} i2c_freq_t;
|
||||
|
||||
// Send start and stop conditions. Only needed when implementing protocols for
|
||||
// devices where the i2c_slave_[read|write] functions above are of no use.
|
||||
void i2c_start(void);
|
||||
void i2c_stop(void);
|
||||
const static uint8_t i2c_freq_array[NB_FREQ_AVAILABLE][2] = { {255,35}, {100,20}, {10,1}, {6,1} } ;
|
||||
|
||||
/**
|
||||
* Device descriptor
|
||||
*/
|
||||
typedef struct i2c_dev {
|
||||
uint8_t bus ;
|
||||
uint8_t addr ;
|
||||
} i2c_dev_t ;
|
||||
|
||||
/**
|
||||
* Bus settings
|
||||
*/
|
||||
typedef struct i2c_bus_description {
|
||||
uint8_t g_scl_pin; // Scl pin
|
||||
uint8_t g_sda_pin; // Sda pin
|
||||
uint8_t frequency; // frequency selection
|
||||
bool started;
|
||||
bool flag;
|
||||
bool force;
|
||||
} i2c_bus_description_t ;
|
||||
|
||||
|
||||
// I2C driver for ESP8266 written for use with esp-open-rtos
|
||||
// Based on https://en.wikipedia.org/wiki/I²C#Example_of_bit-banging_the_I.C2.B2C_Master_protocol
|
||||
// With calling overhead, we end up at ~320kbit/s
|
||||
|
||||
//Level 0 API
|
||||
|
||||
/**
|
||||
* Init bitbanging I2C driver on given pins
|
||||
* @param bus Bus i2c selection
|
||||
* @param scl_pin SCL pin for I2C
|
||||
* @param sda_pin SDA pin for I2C
|
||||
* @param freq frequency of bus (ex : I2C_FREQ_400K)
|
||||
*/
|
||||
void i2c_init(uint8_t bus, uint8_t scl_pin, uint8_t sda_pin, i2c_freq_t freq);
|
||||
|
||||
/**
|
||||
* Change bus frequency
|
||||
* @param bus Bus i2c selection
|
||||
* @param freq frequency of bus (ex : I2C_FREQ_400K)
|
||||
*/
|
||||
void i2c_frequency(uint8_t bus, i2c_freq_t freq);
|
||||
|
||||
/**
|
||||
* Write a byte to I2C bus.
|
||||
* @param bus Bus i2c selection
|
||||
* @param byte Pointer to device descriptor
|
||||
* @return true if slave acked
|
||||
*/
|
||||
bool i2c_write(uint8_t bus, uint8_t byte);
|
||||
|
||||
/**
|
||||
* Read a byte from I2C bus.
|
||||
* @param bus Bus i2c selection
|
||||
* @param ack Set Ack for slave (false: Ack // true: NoAck)
|
||||
* @return byte read from slave.
|
||||
*/
|
||||
uint8_t i2c_read(uint8_t bus, bool ack);
|
||||
|
||||
/**
|
||||
* Send start or restart condition
|
||||
* @param bus Bus i2c selection
|
||||
*/
|
||||
void i2c_start(uint8_t bus);
|
||||
|
||||
/**
|
||||
* Send stop condition
|
||||
* @param bus Bus i2c selection
|
||||
* @return false if link was broken
|
||||
*/
|
||||
bool i2c_stop(uint8_t bus);
|
||||
|
||||
/**
|
||||
* get status from I2C bus.
|
||||
* @param bus Bus i2c selection
|
||||
* @return true if busy.
|
||||
*/
|
||||
bool i2c_status(uint8_t bus);
|
||||
|
||||
//Level 1 API (Don't need functions above)
|
||||
|
||||
/**
|
||||
* This function will allow you to force a transmission I2C, cancel current transmission.
|
||||
* Warning: Use with precaution. Don't use it if you can avoid it. Usefull for priority transmission.
|
||||
* @param bus Bus i2c selection
|
||||
* @param state Force the next I2C transmission if true (Use with precaution)
|
||||
*/
|
||||
void i2c_force_bus(uint8_t bus, bool state);
|
||||
|
||||
/**
|
||||
* Write 'len' bytes from 'buf' to slave at 'data' register adress .
|
||||
* @param bus Bus i2c selection
|
||||
* @param slave_addr slave device address
|
||||
* @param data Pointer to register address to send if non-null
|
||||
* @param buf Pointer to data buffer
|
||||
* @param len Number of byte to send
|
||||
* @return Non-Zero if error occured
|
||||
*/
|
||||
int i2c_slave_write(uint8_t bus, uint8_t slave_addr, const uint8_t *data, const uint8_t *buf, uint32_t len);
|
||||
|
||||
/**
|
||||
* Issue a send operation of 'data' register adress, followed by reading 'len' bytes
|
||||
* from slave into 'buf'.
|
||||
* @param bus Bus i2c selection
|
||||
* @param slave_addr slave device address
|
||||
* @param data Pointer to register address to send if non-null
|
||||
* @param buf Pointer to data buffer
|
||||
* @param len Number of byte to read
|
||||
* @return Non-Zero if error occured
|
||||
*/
|
||||
int i2c_slave_read(uint8_t bus, uint8_t slave_addr, const uint8_t *data, uint8_t *buf, uint32_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ void sdk_rom_i2c_writeReg_Mask(uint32_t block, uint32_t host_id,
|
|||
reg_add##_lsb, indata)
|
||||
|
||||
|
||||
void i2s_dma_init(i2s_dma_isr_t isr, i2s_clock_div_t clock_div, i2s_pins_t pins)
|
||||
void i2s_dma_init(i2s_dma_isr_t isr, void *arg, i2s_clock_div_t clock_div, i2s_pins_t pins)
|
||||
{
|
||||
// reset DMA
|
||||
SET_MASK_BITS(SLC.CONF0, SLC_CONF0_RX_LINK_RESET);
|
||||
|
|
@ -83,7 +83,7 @@ void i2s_dma_init(i2s_dma_isr_t isr, i2s_clock_div_t clock_div, i2s_pins_t pins)
|
|||
SLC_RX_DESCRIPTOR_CONF_RX_EOF_MODE | SLC_RX_DESCRIPTOR_CONF_RX_FILL_MODE);
|
||||
|
||||
if (isr) {
|
||||
_xt_isr_attach(INUM_SLC, isr);
|
||||
_xt_isr_attach(INUM_SLC, isr, arg);
|
||||
SET_MASK_BITS(SLC.INT_ENABLE, SLC_INT_ENABLE_RX_EOF);
|
||||
SLC.INT_CLEAR = 0xFFFFFFFF;
|
||||
_xt_isr_unmask(1<<INUM_SLC);
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*i2s_dma_isr_t)(void);
|
||||
typedef void (*i2s_dma_isr_t)(void *);
|
||||
|
||||
typedef struct dma_descriptor {
|
||||
uint32_t blocksize:12;
|
||||
|
|
@ -61,10 +61,11 @@ typedef struct {
|
|||
* Initialize I2S and DMA subsystems.
|
||||
*
|
||||
* @param isr ISR handler. Can be NULL if interrupt handling is not needed.
|
||||
* @param arg ISR handler arg.
|
||||
* @param clock_div I2S clock configuration.
|
||||
* @param pins I2S pin configuration. Specifies which pins are enabled in I2S.
|
||||
*/
|
||||
void i2s_dma_init(i2s_dma_isr_t isr, i2s_clock_div_t clock_div, i2s_pins_t pins);
|
||||
void i2s_dma_init(i2s_dma_isr_t isr, void *arg, i2s_clock_div_t clock_div, i2s_pins_t pins);
|
||||
|
||||
/**
|
||||
* Calculate I2S dividers for the specified frequency.
|
||||
|
|
|
|||
|
|
@ -10,69 +10,40 @@
|
|||
|
||||
#include "ina3221.h"
|
||||
|
||||
//#define INA3221_DEBUG true
|
||||
|
||||
#ifdef INA3221_DEBUG
|
||||
#define debug(fmt, ...) printf("%s: " fmt "\n", "INA3221", ## __VA_ARGS__)
|
||||
#else
|
||||
#define debug(fmt, ...)
|
||||
#endif
|
||||
|
||||
static int _wireWriteRegister (uint8_t addr, uint8_t reg, uint16_t value)
|
||||
static int _wireWriteRegister (const i2c_dev_t* dev, uint8_t reg, uint16_t value)
|
||||
{
|
||||
i2c_start();
|
||||
if (!i2c_write(addr<<1)) // adress + W
|
||||
goto error;
|
||||
if (!i2c_write(reg))
|
||||
goto error;
|
||||
if (!i2c_write((value >> 8) & 0xFF))
|
||||
goto error;
|
||||
if (!i2c_write(value & 0xFF))
|
||||
goto error;
|
||||
i2c_stop();
|
||||
debug("Data write to %02X : %02X+%04X\n",addr,reg,value);
|
||||
|
||||
return 0 ;
|
||||
|
||||
error:
|
||||
debug("Error while xmitting I2C slave\n");
|
||||
i2c_stop();
|
||||
return -EIO;
|
||||
uint8_t d[2] = { 0 , 0 };
|
||||
d[1] = value & 0x00FF;
|
||||
d[0] = (value >> 8) & 0x00FF;
|
||||
debug("Data write to bus %u at %02X : %02X+%04X\n",dev->bus, dev->addr, reg, value);
|
||||
return i2c_slave_write(dev->bus, dev->addr, ®, d, sizeof(d));
|
||||
}
|
||||
|
||||
static int _wireReadRegister(uint8_t addr, uint8_t reg, uint16_t *value)
|
||||
static int _wireReadRegister(const i2c_dev_t* dev, uint8_t reg, uint16_t *value)
|
||||
{
|
||||
uint8_t tampon[2] = { 0 } ;
|
||||
|
||||
i2c_start();
|
||||
if (!i2c_write(addr<<1)) // adress + W
|
||||
goto error;
|
||||
if (!i2c_write(reg))
|
||||
goto error;
|
||||
i2c_stop();
|
||||
i2c_start(); // restart condition
|
||||
if (!i2c_write((addr<<1) | 1)) // adress + R
|
||||
goto error;
|
||||
tampon[1] = i2c_read(0);
|
||||
tampon[0] = i2c_read(1);
|
||||
i2c_stop();
|
||||
*value = tampon[1]<<8 | tampon[0] ;
|
||||
debug("Data read from %02X: %02X+%04X\n",addr,reg,*value);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
debug("Error while xmitting I2C slave\n");
|
||||
i2c_stop();
|
||||
return -EIO;
|
||||
uint8_t d[] = {0, 0};
|
||||
int error = i2c_slave_read(dev->bus, dev->addr, ®, d, sizeof(d))
|
||||
debug("Data read from bus %u at %02X: %02X+%04X\n",dev->bus, dev->addr, reg, *value);
|
||||
*value = d[1] | (d[0] << 8);
|
||||
return error;
|
||||
}
|
||||
|
||||
int ina3221_trigger(ina3221_t *dev)
|
||||
{
|
||||
return _wireWriteRegister(dev->addr, INA3221_REG_CONFIG, dev->config.config_register);
|
||||
return _wireWriteRegister(&dev->i2c_dev, INA3221_REG_CONFIG, dev->config.config_register);
|
||||
}
|
||||
|
||||
int ina3221_getStatus(ina3221_t *dev)
|
||||
{
|
||||
return _wireReadRegister(dev->addr, INA3221_REG_MASK, &dev->mask.mask_register);
|
||||
return _wireReadRegister(&dev->i2c_dev, INA3221_REG_MASK, &dev->mask.mask_register);
|
||||
}
|
||||
|
||||
int ina3221_sync(ina3221_t *dev)
|
||||
|
|
@ -80,17 +51,17 @@ int ina3221_sync(ina3221_t *dev)
|
|||
uint16_t ptr_data;
|
||||
int err = 0;
|
||||
//////////////////////// Sync config register
|
||||
if ((err = _wireReadRegister(dev->addr, INA3221_REG_CONFIG, &ptr_data))) // Read config
|
||||
if ((err = _wireReadRegister(&dev->i2c_dev, INA3221_REG_CONFIG, &ptr_data))) // Read config
|
||||
return err;
|
||||
if( ptr_data != dev->config.config_register) {
|
||||
if ((err = _wireWriteRegister(dev->addr, INA3221_REG_CONFIG, dev->config.config_register))) // Update config
|
||||
if ((err = _wireWriteRegister(&dev->i2c_dev, INA3221_REG_CONFIG, dev->config.config_register))) // Update config
|
||||
return err;
|
||||
}
|
||||
//////////////////////// Sync mask register config
|
||||
if ((err = _wireReadRegister(dev->addr, INA3221_REG_MASK, &ptr_data))) // Read mask
|
||||
if ((err = _wireReadRegister(&dev->i2c_dev, INA3221_REG_MASK, &ptr_data))) // Read mask
|
||||
return err;
|
||||
if( (ptr_data & INA3221_MASK_CONFIG) != (dev->mask.mask_register & INA3221_MASK_CONFIG)) {
|
||||
if ((err = _wireWriteRegister(dev->addr, INA3221_REG_MASK, dev->mask.mask_register & INA3221_MASK_CONFIG))) // Update config
|
||||
if ((err = _wireWriteRegister(&dev->i2c_dev, INA3221_REG_MASK, dev->mask.mask_register & INA3221_MASK_CONFIG))) // Update config
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -101,7 +72,7 @@ int ina3221_setting(ina3221_t *dev ,bool mode, bool bus, bool shunt)
|
|||
dev->config.mode = mode;
|
||||
dev->config.ebus = bus;
|
||||
dev->config.esht = shunt;
|
||||
return _wireWriteRegister(dev->addr, INA3221_REG_CONFIG, dev->config.config_register);
|
||||
return _wireWriteRegister(&dev->i2c_dev, INA3221_REG_CONFIG, dev->config.config_register);
|
||||
}
|
||||
|
||||
int ina3221_enableChannel(ina3221_t *dev ,bool ch1, bool ch2, bool ch3)
|
||||
|
|
@ -109,7 +80,7 @@ int ina3221_enableChannel(ina3221_t *dev ,bool ch1, bool ch2, bool ch3)
|
|||
dev->config.ch1 = ch1;
|
||||
dev->config.ch2 = ch2;
|
||||
dev->config.ch3 = ch3;
|
||||
return _wireWriteRegister(dev->addr, INA3221_REG_CONFIG, dev->config.config_register);
|
||||
return _wireWriteRegister(&dev->i2c_dev, INA3221_REG_CONFIG, dev->config.config_register);
|
||||
}
|
||||
|
||||
int ina3221_enableChannelSum(ina3221_t *dev ,bool ch1, bool ch2, bool ch3)
|
||||
|
|
@ -117,32 +88,32 @@ int ina3221_enableChannelSum(ina3221_t *dev ,bool ch1, bool ch2, bool ch3)
|
|||
dev->mask.scc1 = ch1;
|
||||
dev->mask.scc2 = ch2;
|
||||
dev->mask.scc3 = ch3;
|
||||
return _wireWriteRegister(dev->addr, INA3221_REG_MASK, dev->mask.mask_register & INA3221_MASK_CONFIG);
|
||||
return _wireWriteRegister(&dev->i2c_dev, INA3221_REG_MASK, dev->mask.mask_register & INA3221_MASK_CONFIG);
|
||||
}
|
||||
|
||||
int ina3221_enableLatchPin(ina3221_t *dev ,bool warning, bool critical)
|
||||
{
|
||||
dev->mask.wen = warning;
|
||||
dev->mask.cen = critical;
|
||||
return _wireWriteRegister(dev->addr, INA3221_REG_MASK, dev->mask.mask_register & INA3221_MASK_CONFIG);
|
||||
return _wireWriteRegister(&dev->i2c_dev, INA3221_REG_MASK, dev->mask.mask_register & INA3221_MASK_CONFIG);
|
||||
}
|
||||
|
||||
int ina3221_setAverage(ina3221_t *dev, ina3221_avg_t avg)
|
||||
{
|
||||
dev->config.avg = avg;
|
||||
return _wireWriteRegister(dev->addr, INA3221_REG_CONFIG, dev->config.config_register);
|
||||
return _wireWriteRegister(&dev->i2c_dev, INA3221_REG_CONFIG, dev->config.config_register);
|
||||
}
|
||||
|
||||
int ina3221_setBusConversionTime(ina3221_t *dev,ina3221_ct_t ct)
|
||||
{
|
||||
dev->config.vbus = ct;
|
||||
return _wireWriteRegister(dev->addr, INA3221_REG_CONFIG, dev->config.config_register);
|
||||
return _wireWriteRegister(&dev->i2c_dev, INA3221_REG_CONFIG, dev->config.config_register);
|
||||
}
|
||||
|
||||
int ina3221_setShuntConversionTime(ina3221_t *dev,ina3221_ct_t ct)
|
||||
{
|
||||
dev->config.vsht = ct;
|
||||
return _wireWriteRegister(dev->addr, INA3221_REG_CONFIG, dev->config.config_register);
|
||||
return _wireWriteRegister(&dev->i2c_dev, INA3221_REG_CONFIG, dev->config.config_register);
|
||||
}
|
||||
|
||||
int ina3221_reset(ina3221_t *dev)
|
||||
|
|
@ -150,14 +121,14 @@ int ina3221_reset(ina3221_t *dev)
|
|||
dev->config.config_register = INA3221_DEFAULT_CONFIG ; //dev reset
|
||||
dev->mask.mask_register = INA3221_DEFAULT_CONFIG ; //dev reset
|
||||
dev->config.rst = 1 ;
|
||||
return _wireWriteRegister(dev->addr, INA3221_REG_CONFIG, dev->config.config_register); // send reset to device
|
||||
return _wireWriteRegister(&dev->i2c_dev, INA3221_REG_CONFIG, dev->config.config_register); // send reset to device
|
||||
}
|
||||
|
||||
int ina3221_getBusVoltage(ina3221_t *dev, ina3221_channel_t channel, float *voltage)
|
||||
{
|
||||
int16_t raw_value;
|
||||
int err = 0;
|
||||
if ((err = _wireReadRegister(dev->addr,INA3221_REG_BUSVOLTAGE_1+channel*2, (uint16_t*)&raw_value)))
|
||||
if ((err = _wireReadRegister(&dev->i2c_dev,INA3221_REG_BUSVOLTAGE_1+channel*2, (uint16_t*)&raw_value)))
|
||||
return err;
|
||||
*voltage = raw_value*0.001 ; //V 8mV step
|
||||
return 0;
|
||||
|
|
@ -167,12 +138,12 @@ int ina3221_getShuntValue(ina3221_t *dev, ina3221_channel_t channel, float *volt
|
|||
{
|
||||
int16_t raw_value;
|
||||
int err = 0;
|
||||
if ((err = _wireReadRegister(dev->addr,INA3221_REG_SHUNTVOLTAGE_1+channel*2, (uint16_t*)&raw_value)))
|
||||
if ((err = _wireReadRegister(&dev->i2c_dev,INA3221_REG_SHUNTVOLTAGE_1+channel*2, (uint16_t*)&raw_value)))
|
||||
return err;
|
||||
*voltage = raw_value*0.005; //mV 40uV step
|
||||
if(!dev->shunt[channel])
|
||||
{
|
||||
debug("No shunt configured for channel %u. Dev:%X\n",channel+1, dev->addr);
|
||||
debug("No shunt configured for channel %u. Dev:%u:%X\n",channel+1, dev->bus, dev->addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
*current = (*voltage*1000.0)/dev->shunt[channel] ; //mA
|
||||
|
|
@ -183,7 +154,7 @@ int ina3221_getSumShuntValue(ina3221_t *dev, float *voltage)
|
|||
{
|
||||
int16_t raw_value;
|
||||
int err = 0;
|
||||
if ((err = _wireReadRegister(dev->addr,INA3221_REG_SHUNT_VOLTAGE_SUM, (uint16_t*)&raw_value)))
|
||||
if ((err = _wireReadRegister(&dev->i2c_dev,INA3221_REG_SHUNT_VOLTAGE_SUM, (uint16_t*)&raw_value)))
|
||||
return err;
|
||||
*voltage = raw_value*0.02; //uV 40uV step
|
||||
return 0;
|
||||
|
|
@ -192,39 +163,39 @@ int ina3221_getSumShuntValue(ina3221_t *dev, float *voltage)
|
|||
int ina3221_setCriticalAlert(ina3221_t *dev, ina3221_channel_t channel, float current)
|
||||
{
|
||||
int16_t raw_value = current*dev->shunt[channel]*0.2; // format
|
||||
return _wireWriteRegister(dev->addr,INA3221_REG_CRITICAL_ALERT_1+channel*2, *(uint16_t*)&raw_value);
|
||||
return _wireWriteRegister(&dev->i2c_dev,INA3221_REG_CRITICAL_ALERT_1+channel*2, *(uint16_t*)&raw_value);
|
||||
}
|
||||
|
||||
int ina3221_setWarningAlert(ina3221_t *dev, ina3221_channel_t channel, float current)
|
||||
{
|
||||
int16_t raw_value = current*dev->shunt[channel]*0.2 ; // format
|
||||
return _wireWriteRegister(dev->addr,INA3221_REG_WARNING_ALERT_1+channel*2, *(uint16_t*)&raw_value);
|
||||
return _wireWriteRegister(&dev->i2c_dev,INA3221_REG_WARNING_ALERT_1+channel*2, *(uint16_t*)&raw_value);
|
||||
}
|
||||
|
||||
int ina3221_setSumWarningAlert(ina3221_t *dev, float voltage)
|
||||
{
|
||||
int16_t raw_value = voltage*50.0 ; // format
|
||||
return _wireWriteRegister(dev->addr,INA3221_REG_SHUNT_VOLTAGE_SUM_LIMIT, *(uint16_t*)&raw_value);
|
||||
return _wireWriteRegister(&dev->i2c_dev,INA3221_REG_SHUNT_VOLTAGE_SUM_LIMIT, *(uint16_t*)&raw_value);
|
||||
}
|
||||
|
||||
int ina3221_setPowerValidUpperLimit(ina3221_t *dev, float voltage)
|
||||
{
|
||||
if(!dev->config.ebus)
|
||||
{
|
||||
debug("Bus not enable. Dev:%X\n", dev->addr);
|
||||
debug("Bus not enable. Dev:%u:%X\n", dev->bus, dev->addr);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
int16_t raw_value = voltage*1000.0; //format
|
||||
return _wireWriteRegister(dev->addr,INA3221_REG_VALID_POWER_UPPER_LIMIT, *(uint16_t*)&raw_value);
|
||||
return _wireWriteRegister(&dev->i2c_dev,INA3221_REG_VALID_POWER_UPPER_LIMIT, *(uint16_t*)&raw_value);
|
||||
}
|
||||
|
||||
int ina3221_setPowerValidLowerLimit(ina3221_t *dev, float voltage)
|
||||
{
|
||||
if(!dev->config.ebus)
|
||||
{
|
||||
debug("Bus not enable. Dev:%X\n", dev->addr);
|
||||
debug("Bus not enable. Dev:%u:%X\n", dev->bus, dev->addr);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
int16_t raw_value = voltage*1000.0; // round and format
|
||||
return _wireWriteRegister(dev->addr,INA3221_REG_VALID_POWER_LOWER_LIMIT, *(uint16_t*)&raw_value);
|
||||
return _wireWriteRegister(&dev->i2c_dev,INA3221_REG_VALID_POWER_LOWER_LIMIT, *(uint16_t*)&raw_value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
@ -130,7 +132,7 @@ typedef union
|
|||
* Device description
|
||||
*/
|
||||
typedef struct {
|
||||
const uint8_t addr; // ina3221 I2C address
|
||||
const i2c_dev_t i2c_dev; // ina3221 I2C address
|
||||
const uint16_t shunt[BUS_NUMBER]; //Memory of shunt value (mOhm)
|
||||
ina3221_config_t config; //Memory of ina3221 config
|
||||
ina3221_mask_t mask; //Memory of mask_config
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@
|
|||
*
|
||||
* \brief Configuration options (set of defines)
|
||||
*
|
||||
* This set of compile-time options may be used to enable
|
||||
* or disable features selectively, and reduce the global
|
||||
* memory footprint.
|
||||
*
|
||||
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
|
|
@ -21,11 +25,6 @@
|
|||
* This file is part of mbed TLS (https://tls.mbed.org)
|
||||
*/
|
||||
|
||||
/*
|
||||
* This set of compile-time options may be used to enable
|
||||
* or disable features selectively, and reduce the global
|
||||
* memory footprint.
|
||||
*/
|
||||
#ifndef MBEDTLS_CONFIG_H
|
||||
#define MBEDTLS_CONFIG_H
|
||||
|
||||
|
|
@ -72,6 +71,10 @@
|
|||
* The time does not need to be correct, only time differences are used,
|
||||
* by contrast with MBEDTLS_HAVE_TIME_DATE
|
||||
*
|
||||
* Defining MBEDTLS_HAVE_TIME allows you to specify MBEDTLS_PLATFORM_TIME_ALT,
|
||||
* MBEDTLS_PLATFORM_TIME_MACRO, MBEDTLS_PLATFORM_TIME_TYPE_MACRO and
|
||||
* MBEDTLS_PLATFORM_STD_TIME.
|
||||
*
|
||||
* Comment if your system does not support time functions
|
||||
*/
|
||||
//#define MBEDTLS_HAVE_TIME
|
||||
|
|
@ -132,10 +135,10 @@
|
|||
//#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_PLATFORM_XXX_ALT
|
||||
* \def MBEDTLS_PLATFORM_EXIT_ALT
|
||||
*
|
||||
* Uncomment a macro to let mbed TLS support the function in the platform
|
||||
* abstraction layer.
|
||||
* MBEDTLS_PLATFORM_XXX_ALT: Uncomment a macro to let mbed TLS support the
|
||||
* function in the platform abstraction layer.
|
||||
*
|
||||
* Example: In case you uncomment MBEDTLS_PLATFORM_PRINTF_ALT, mbed TLS will
|
||||
* provide a function "mbedtls_platform_set_printf()" that allows you to set an
|
||||
|
|
@ -149,13 +152,17 @@
|
|||
* \warning MBEDTLS_PLATFORM_XXX_ALT cannot be defined at the same time as
|
||||
* MBEDTLS_PLATFORM_XXX_MACRO!
|
||||
*
|
||||
* Requires: MBEDTLS_PLATFORM_TIME_ALT requires MBEDTLS_HAVE_TIME
|
||||
*
|
||||
* Uncomment a macro to enable alternate implementation of specific base
|
||||
* platform function
|
||||
*/
|
||||
//#define MBEDTLS_PLATFORM_EXIT_ALT
|
||||
//#define MBEDTLS_PLATFORM_TIME_ALT
|
||||
//#define MBEDTLS_PLATFORM_FPRINTF_ALT
|
||||
//#define MBEDTLS_PLATFORM_PRINTF_ALT
|
||||
//#define MBEDTLS_PLATFORM_SNPRINTF_ALT
|
||||
//#define MBEDTLS_PLATFORM_NV_SEED_ALT
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_DEPRECATED_WARNING
|
||||
|
|
@ -208,19 +215,19 @@
|
|||
//#define MBEDTLS_TIMING_ALT
|
||||
|
||||
/**
|
||||
* \def MBEDTLS__MODULE_NAME__ALT
|
||||
* \def MBEDTLS_AES_ALT
|
||||
*
|
||||
* Uncomment a macro to let mbed TLS use your alternate core implementation of
|
||||
* a symmetric crypto or hash module (e.g. platform specific assembly
|
||||
* optimized implementations). Keep in mind that the function prototypes
|
||||
* should remain the same.
|
||||
* MBEDTLS__MODULE_NAME__ALT: Uncomment a macro to let mbed TLS use your
|
||||
* alternate core implementation of a symmetric crypto, an arithmetic or hash
|
||||
* module (e.g. platform specific assembly optimized implementations). Keep
|
||||
* in mind that the function prototypes should remain the same.
|
||||
*
|
||||
* This replaces the whole module. If you only want to replace one of the
|
||||
* functions, use one of the MBEDTLS__FUNCTION_NAME__ALT flags.
|
||||
*
|
||||
* Example: In case you uncomment MBEDTLS_AES_ALT, mbed TLS will no longer
|
||||
* provide the "struct mbedtls_aes_context" definition and omit the base function
|
||||
* declarations and implementations. "aes_alt.h" will be included from
|
||||
* provide the "struct mbedtls_aes_context" definition and omit the base
|
||||
* function declarations and implementations. "aes_alt.h" will be included from
|
||||
* "aes.h" to include the new function definitions.
|
||||
*
|
||||
* Uncomment a macro to enable alternate implementation of the corresponding
|
||||
|
|
@ -239,13 +246,23 @@
|
|||
//#define MBEDTLS_SHA1_ALT
|
||||
//#define MBEDTLS_SHA256_ALT
|
||||
//#define MBEDTLS_SHA512_ALT
|
||||
/*
|
||||
* When replacing the elliptic curve module, pleace consider, that it is
|
||||
* implemented with two .c files:
|
||||
* - ecp.c
|
||||
* - ecp_curves.c
|
||||
* You can replace them very much like all the other MBEDTLS__MODULE_NAME__ALT
|
||||
* macros as described above. The only difference is that you have to make sure
|
||||
* that you provide functionality for both .c files.
|
||||
*/
|
||||
//#define MBEDTLS_ECP_ALT
|
||||
|
||||
/**
|
||||
* \def MBEDTLS__FUNCTION_NAME__ALT
|
||||
* \def MBEDTLS_MD2_PROCESS_ALT
|
||||
*
|
||||
* Uncomment a macro to let mbed TLS use you alternate core implementation of
|
||||
* symmetric crypto or hash function. Keep in mind that function prototypes
|
||||
* should remain the same.
|
||||
* MBEDTLS__FUNCTION_NAME__ALT: Uncomment a macro to let mbed TLS use you
|
||||
* alternate core implementation of symmetric crypto or hash function. Keep in
|
||||
* mind that function prototypes should remain the same.
|
||||
*
|
||||
* This replaces only one function. The header file from mbed TLS is still
|
||||
* used, in contrast to the MBEDTLS__MODULE_NAME__ALT flags.
|
||||
|
|
@ -278,6 +295,76 @@
|
|||
//#define MBEDTLS_AES_ENCRYPT_ALT
|
||||
//#define MBEDTLS_AES_DECRYPT_ALT
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_ECP_INTERNAL_ALT
|
||||
*
|
||||
* Expose a part of the internal interface of the Elliptic Curve Point module.
|
||||
*
|
||||
* MBEDTLS_ECP__FUNCTION_NAME__ALT: Uncomment a macro to let mbed TLS use your
|
||||
* alternative core implementation of elliptic curve arithmetic. Keep in mind
|
||||
* that function prototypes should remain the same.
|
||||
*
|
||||
* This partially replaces one function. The header file from mbed TLS is still
|
||||
* used, in contrast to the MBEDTLS_ECP_ALT flag. The original implementation
|
||||
* is still present and it is used for group structures not supported by the
|
||||
* alternative.
|
||||
*
|
||||
* Any of these options become available by defining MBEDTLS_ECP_INTERNAL_ALT
|
||||
* and implementing the following functions:
|
||||
* unsigned char mbedtls_internal_ecp_grp_capable(
|
||||
* const mbedtls_ecp_group *grp )
|
||||
* int mbedtls_internal_ecp_init( const mbedtls_ecp_group *grp )
|
||||
* void mbedtls_internal_ecp_deinit( const mbedtls_ecp_group *grp )
|
||||
* The mbedtls_internal_ecp_grp_capable function should return 1 if the
|
||||
* replacement functions implement arithmetic for the given group and 0
|
||||
* otherwise.
|
||||
* The functions mbedtls_internal_ecp_init and mbedtls_internal_ecp_deinit are
|
||||
* called before and after each point operation and provide an opportunity to
|
||||
* implement optimized set up and tear down instructions.
|
||||
*
|
||||
* Example: In case you uncomment MBEDTLS_ECP_INTERNAL_ALT and
|
||||
* MBEDTLS_ECP_DOUBLE_JAC_ALT, mbed TLS will still provide the ecp_double_jac
|
||||
* function, but will use your mbedtls_internal_ecp_double_jac if the group is
|
||||
* supported (your mbedtls_internal_ecp_grp_capable function returns 1 when
|
||||
* receives it as an argument). If the group is not supported then the original
|
||||
* implementation is used. The other functions and the definition of
|
||||
* mbedtls_ecp_group and mbedtls_ecp_point will not change, so your
|
||||
* implementation of mbedtls_internal_ecp_double_jac and
|
||||
* mbedtls_internal_ecp_grp_capable must be compatible with this definition.
|
||||
*
|
||||
* Uncomment a macro to enable alternate implementation of the corresponding
|
||||
* function.
|
||||
*/
|
||||
/* Required for all the functions in this section */
|
||||
//#define MBEDTLS_ECP_INTERNAL_ALT
|
||||
/* Support for Weierstrass curves with Jacobi representation */
|
||||
//#define MBEDTLS_ECP_RANDOMIZE_JAC_ALT
|
||||
//#define MBEDTLS_ECP_ADD_MIXED_ALT
|
||||
//#define MBEDTLS_ECP_DOUBLE_JAC_ALT
|
||||
//#define MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT
|
||||
//#define MBEDTLS_ECP_NORMALIZE_JAC_ALT
|
||||
/* Support for curves with Montgomery arithmetic */
|
||||
//#define MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT
|
||||
//#define MBEDTLS_ECP_RANDOMIZE_MXZ_ALT
|
||||
//#define MBEDTLS_ECP_NORMALIZE_MXZ_ALT
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_TEST_NULL_ENTROPY
|
||||
*
|
||||
* Enables testing and use of mbed TLS without any configured entropy sources.
|
||||
* This permits use of the library on platforms before an entropy source has
|
||||
* been integrated (see for example the MBEDTLS_ENTROPY_HARDWARE_ALT or the
|
||||
* MBEDTLS_ENTROPY_NV_SEED switches).
|
||||
*
|
||||
* WARNING! This switch MUST be disabled in production builds, and is suitable
|
||||
* only for development.
|
||||
* Enabling the switch negates any security provided by the library.
|
||||
*
|
||||
* Requires MBEDTLS_ENTROPY_C, MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
|
||||
*
|
||||
*/
|
||||
//#define MBEDTLS_TEST_NULL_ENTROPY
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_ENTROPY_HARDWARE_ALT
|
||||
*
|
||||
|
|
@ -365,10 +452,11 @@
|
|||
//#define MBEDTLS_CIPHER_NULL_CIPHER
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_CIPHER_PADDING_XXX
|
||||
* \def MBEDTLS_CIPHER_PADDING_PKCS7
|
||||
*
|
||||
* Uncomment or comment macros to add support for specific padding modes
|
||||
* in the cipher layer with cipher modes that support padding (e.g. CBC)
|
||||
* MBEDTLS_CIPHER_PADDING_XXX: Uncomment or comment macros to add support for
|
||||
* specific padding modes in the cipher layer with cipher modes that support
|
||||
* padding (e.g. CBC)
|
||||
*
|
||||
* If you disable all padding modes, only full blocks can be used with CBC.
|
||||
*
|
||||
|
|
@ -408,10 +496,10 @@
|
|||
#define MBEDTLS_REMOVE_ARC4_CIPHERSUITES
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_ECP_XXXX_ENABLED
|
||||
* \def MBEDTLS_ECP_DP_SECP192R1_ENABLED
|
||||
*
|
||||
* Enables specific curves within the Elliptic Curve module.
|
||||
* By default all supported curves are enabled.
|
||||
* MBEDTLS_ECP_XXXX_ENABLED: Enables specific curves within the Elliptic Curve
|
||||
* module. By default all supported curves are enabled.
|
||||
*
|
||||
* Comment macros to disable the curve and functions for it
|
||||
*/
|
||||
|
|
@ -695,6 +783,25 @@
|
|||
*/
|
||||
#define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED
|
||||
*
|
||||
* Enable the ECJPAKE based ciphersuite modes in SSL / TLS.
|
||||
*
|
||||
* \warning This is currently experimental. EC J-PAKE support is based on the
|
||||
* Thread v1.0.0 specification; incompatible changes to the specification
|
||||
* might still happen. For this reason, this is disabled by default.
|
||||
*
|
||||
* Requires: MBEDTLS_ECJPAKE_C
|
||||
* MBEDTLS_SHA256_C
|
||||
* MBEDTLS_ECP_DP_SECP256R1_ENABLED
|
||||
*
|
||||
* This enables the following ciphersuites (if other requisites are
|
||||
* enabled as well):
|
||||
* MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8
|
||||
*/
|
||||
//#define MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_PK_PARSE_EC_EXTENDED
|
||||
*
|
||||
|
|
@ -780,6 +887,34 @@
|
|||
*/
|
||||
#define MBEDTLS_ENTROPY_FORCE_SHA256
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_ENTROPY_NV_SEED
|
||||
*
|
||||
* Enable the non-volatile (NV) seed file-based entropy source.
|
||||
* (Also enables the NV seed read/write functions in the platform layer)
|
||||
*
|
||||
* This is crucial (if not required) on systems that do not have a
|
||||
* cryptographic entropy source (in hardware or kernel) available.
|
||||
*
|
||||
* Requires: MBEDTLS_ENTROPY_C, MBEDTLS_PLATFORM_C
|
||||
*
|
||||
* \note The read/write functions that are used by the entropy source are
|
||||
* determined in the platform layer, and can be modified at runtime and/or
|
||||
* compile-time depending on the flags (MBEDTLS_PLATFORM_NV_SEED_*) used.
|
||||
*
|
||||
* \note If you use the default implementation functions that read a seedfile
|
||||
* with regular fopen(), please make sure you make a seedfile with the
|
||||
* proper name (defined in MBEDTLS_PLATFORM_STD_NV_SEED_FILE) and at
|
||||
* least MBEDTLS_ENTROPY_BLOCK_SIZE bytes in size that can be read from
|
||||
* and written to or you will get an entropy source error! The default
|
||||
* implementation will only use the first MBEDTLS_ENTROPY_BLOCK_SIZE
|
||||
* bytes from the file.
|
||||
*
|
||||
* \note The entropy collector will write to the seed file before entropy is
|
||||
* given to an external source, to update it.
|
||||
*/
|
||||
//#define MBEDTLS_ENTROPY_NV_SEED
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_MEMORY_DEBUG
|
||||
*
|
||||
|
|
@ -869,18 +1004,6 @@
|
|||
*/
|
||||
#define MBEDTLS_SHA256_SMALLER
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_SSL_AEAD_RANDOM_IV
|
||||
*
|
||||
* Generate a random IV rather than using the record sequence number as a
|
||||
* nonce for ciphersuites using and AEAD algorithm (GCM or CCM).
|
||||
*
|
||||
* Using the sequence number is generally recommended.
|
||||
*
|
||||
* Uncomment this macro to always use random IVs with AEAD ciphersuites.
|
||||
*/
|
||||
//#define MBEDTLS_SSL_AEAD_RANDOM_IV
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_SSL_ALL_ALERT_MESSAGES
|
||||
*
|
||||
|
|
@ -1040,7 +1163,7 @@
|
|||
*
|
||||
* Comment this macro to disable support for SSL 3.0
|
||||
*/
|
||||
#define MBEDTLS_SSL_PROTO_SSL3
|
||||
//#define MBEDTLS_SSL_PROTO_SSL3
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_SSL_PROTO_TLS1
|
||||
|
|
@ -1135,6 +1258,22 @@
|
|||
*/
|
||||
#define MBEDTLS_SSL_DTLS_HELLO_VERIFY
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE
|
||||
*
|
||||
* Enable server-side support for clients that reconnect from the same port.
|
||||
*
|
||||
* Some clients unexpectedly close the connection and try to reconnect using the
|
||||
* same source port. This needs special support from the server to handle the
|
||||
* new connection securely, as described in section 4.2.8 of RFC 6347. This
|
||||
* flag enables that support.
|
||||
*
|
||||
* Requires: MBEDTLS_SSL_DTLS_HELLO_VERIFY
|
||||
*
|
||||
* Comment this to disable support for clients reusing the source port.
|
||||
*/
|
||||
#define MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_SSL_DTLS_BADMAC_LIMIT
|
||||
*
|
||||
|
|
@ -1160,6 +1299,16 @@
|
|||
*/
|
||||
#define MBEDTLS_SSL_SESSION_TICKETS
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_SSL_EXPORT_KEYS
|
||||
*
|
||||
* Enable support for exporting key block and master secret.
|
||||
* This is required for certain users of TLS, e.g. EAP-TLS.
|
||||
*
|
||||
* Comment this macro to disable support for key export
|
||||
*/
|
||||
#define MBEDTLS_SSL_EXPORT_KEYS
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_SSL_SERVER_NAME_INDICATION
|
||||
*
|
||||
|
|
@ -1231,6 +1380,8 @@
|
|||
* If set, the X509 parser will not break-off when parsing an X509 certificate
|
||||
* and encountering an unknown critical extension.
|
||||
*
|
||||
* \warning Depending on your PKI use, enabling this can be a security risk!
|
||||
*
|
||||
* Uncomment to prevent an error.
|
||||
*/
|
||||
//#define MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION
|
||||
|
|
@ -1438,7 +1589,7 @@
|
|||
* library/pkwrite.c
|
||||
* library/x509_create.c
|
||||
* library/x509write_crt.c
|
||||
* library/mbedtls_x509write_csr.c
|
||||
* library/x509write_csr.c
|
||||
*/
|
||||
#define MBEDTLS_ASN1_WRITE_C
|
||||
|
||||
|
|
@ -1572,6 +1723,19 @@
|
|||
*/
|
||||
#define MBEDTLS_CIPHER_C
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_CMAC_C
|
||||
*
|
||||
* Enable the CMAC (Cipher-based Message Authentication Code) mode for block
|
||||
* ciphers.
|
||||
*
|
||||
* Module: library/cmac.c
|
||||
*
|
||||
* Requires: MBEDTLS_AES_C or MBEDTLS_DES_C
|
||||
*
|
||||
*/
|
||||
//#define MBEDTLS_CMAC_C
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_CTR_DRBG_C
|
||||
*
|
||||
|
|
@ -1671,6 +1835,25 @@
|
|||
*/
|
||||
#define MBEDTLS_ECDSA_C
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_ECJPAKE_C
|
||||
*
|
||||
* Enable the elliptic curve J-PAKE library.
|
||||
*
|
||||
* \warning This is currently experimental. EC J-PAKE support is based on the
|
||||
* Thread v1.0.0 specification; incompatible changes to the specification
|
||||
* might still happen. For this reason, this is disabled by default.
|
||||
*
|
||||
* Module: library/ecjpake.c
|
||||
* Caller:
|
||||
*
|
||||
* This module is used by the following key exchanges:
|
||||
* ECJPAKE
|
||||
*
|
||||
* Requires: MBEDTLS_ECP_C, MBEDTLS_MD_C
|
||||
*/
|
||||
//#define MBEDTLS_ECJPAKE_C
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_ECP_C
|
||||
*
|
||||
|
|
@ -1679,6 +1862,7 @@
|
|||
* Module: library/ecp.c
|
||||
* Caller: library/ecdh.c
|
||||
* library/ecdsa.c
|
||||
* library/ecjpake.c
|
||||
*
|
||||
* Requires: MBEDTLS_BIGNUM_C and at least one MBEDTLS_ECP_DP_XXX_ENABLED
|
||||
*/
|
||||
|
|
@ -1766,7 +1950,7 @@
|
|||
*
|
||||
* Enable the generic message digest layer.
|
||||
*
|
||||
* Module: library/mbedtls_md.c
|
||||
* Module: library/md.c
|
||||
* Caller:
|
||||
*
|
||||
* Uncomment to enable generic message digest wrappers.
|
||||
|
|
@ -1778,7 +1962,7 @@
|
|||
*
|
||||
* Enable the MD2 hash algorithm.
|
||||
*
|
||||
* Module: library/mbedtls_md2.c
|
||||
* Module: library/md2.c
|
||||
* Caller:
|
||||
*
|
||||
* Uncomment to enable support for (rare) MD2-signed X.509 certs.
|
||||
|
|
@ -1790,7 +1974,7 @@
|
|||
*
|
||||
* Enable the MD4 hash algorithm.
|
||||
*
|
||||
* Module: library/mbedtls_md4.c
|
||||
* Module: library/md4.c
|
||||
* Caller:
|
||||
*
|
||||
* Uncomment to enable support for (rare) MD4-signed X.509 certs.
|
||||
|
|
@ -1802,8 +1986,8 @@
|
|||
*
|
||||
* Enable the MD5 hash algorithm.
|
||||
*
|
||||
* Module: library/mbedtls_md5.c
|
||||
* Caller: library/mbedtls_md.c
|
||||
* Module: library/md5.c
|
||||
* Caller: library/md.c
|
||||
* library/pem.c
|
||||
* library/ssl_tls.c
|
||||
*
|
||||
|
|
@ -1831,11 +2015,19 @@
|
|||
/**
|
||||
* \def MBEDTLS_NET_C
|
||||
*
|
||||
* Enable the TCP/IP networking routines.
|
||||
* Enable the TCP and UDP over IPv6/IPv4 networking routines.
|
||||
*
|
||||
* Module: library/net.c
|
||||
* \note This module only works on POSIX/Unix (including Linux, BSD and OS X)
|
||||
* and Windows. For other platforms, you'll want to disable it, and write your
|
||||
* own networking callbacks to be passed to \c mbedtls_ssl_set_bio().
|
||||
*
|
||||
* This module provides TCP/IP networking routines.
|
||||
* \note See also our Knowledge Base article about porting to a new
|
||||
* environment:
|
||||
* https://tls.mbed.org/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS
|
||||
*
|
||||
* Module: library/net_sockets.c
|
||||
*
|
||||
* This module provides networking routines.
|
||||
*/
|
||||
#define MBEDTLS_NET_C
|
||||
|
||||
|
|
@ -1852,11 +2044,11 @@
|
|||
* library/rsa.c
|
||||
* library/x509.c
|
||||
* library/x509_create.c
|
||||
* library/mbedtls_x509_crl.c
|
||||
* library/mbedtls_x509_crt.c
|
||||
* library/mbedtls_x509_csr.c
|
||||
* library/x509_crl.c
|
||||
* library/x509_crt.c
|
||||
* library/x509_csr.c
|
||||
* library/x509write_crt.c
|
||||
* library/mbedtls_x509write_csr.c
|
||||
* library/x509write_csr.c
|
||||
*
|
||||
* This modules translates between OIDs and internal values.
|
||||
*/
|
||||
|
|
@ -1884,9 +2076,9 @@
|
|||
* Module: library/pem.c
|
||||
* Caller: library/dhm.c
|
||||
* library/pkparse.c
|
||||
* library/mbedtls_x509_crl.c
|
||||
* library/mbedtls_x509_crt.c
|
||||
* library/mbedtls_x509_csr.c
|
||||
* library/x509_crl.c
|
||||
* library/x509_crt.c
|
||||
* library/x509_csr.c
|
||||
*
|
||||
* Requires: MBEDTLS_BASE64_C
|
||||
*
|
||||
|
|
@ -1902,7 +2094,7 @@
|
|||
* Module: library/pem.c
|
||||
* Caller: library/pkwrite.c
|
||||
* library/x509write_crt.c
|
||||
* library/mbedtls_x509write_csr.c
|
||||
* library/x509write_csr.c
|
||||
*
|
||||
* Requires: MBEDTLS_BASE64_C
|
||||
*
|
||||
|
|
@ -1932,8 +2124,8 @@
|
|||
* Enable the generic public (asymetric) key parser.
|
||||
*
|
||||
* Module: library/pkparse.c
|
||||
* Caller: library/mbedtls_x509_crt.c
|
||||
* library/mbedtls_x509_csr.c
|
||||
* Caller: library/x509_crt.c
|
||||
* library/x509_csr.c
|
||||
*
|
||||
* Requires: MBEDTLS_PK_C
|
||||
*
|
||||
|
|
@ -2024,8 +2216,8 @@
|
|||
*
|
||||
* Enable the RIPEMD-160 hash algorithm.
|
||||
*
|
||||
* Module: library/mbedtls_ripemd160.c
|
||||
* Caller: library/mbedtls_md.c
|
||||
* Module: library/ripemd160.c
|
||||
* Caller: library/md.c
|
||||
*
|
||||
*/
|
||||
#define MBEDTLS_RIPEMD160_C
|
||||
|
|
@ -2053,14 +2245,15 @@
|
|||
*
|
||||
* Enable the SHA1 cryptographic hash algorithm.
|
||||
*
|
||||
* Module: library/mbedtls_sha1.c
|
||||
* Caller: library/mbedtls_md.c
|
||||
* Module: library/sha1.c
|
||||
* Caller: library/md.c
|
||||
* library/ssl_cli.c
|
||||
* library/ssl_srv.c
|
||||
* library/ssl_tls.c
|
||||
* library/x509write_crt.c
|
||||
*
|
||||
* This module is required for SSL/TLS and SHA1-signed certificates.
|
||||
* This module is required for SSL/TLS up to version 1.1, for TLS 1.2
|
||||
* depending on the handshake parameters, and for SHA1-signed certificates.
|
||||
*/
|
||||
#define MBEDTLS_SHA1_C
|
||||
|
||||
|
|
@ -2069,9 +2262,9 @@
|
|||
*
|
||||
* Enable the SHA-224 and SHA-256 cryptographic hash algorithms.
|
||||
*
|
||||
* Module: library/mbedtls_sha256.c
|
||||
* Module: library/sha256.c
|
||||
* Caller: library/entropy.c
|
||||
* library/mbedtls_md.c
|
||||
* library/md.c
|
||||
* library/ssl_cli.c
|
||||
* library/ssl_srv.c
|
||||
* library/ssl_tls.c
|
||||
|
|
@ -2086,9 +2279,9 @@
|
|||
*
|
||||
* Enable the SHA-384 and SHA-512 cryptographic hash algorithms.
|
||||
*
|
||||
* Module: library/mbedtls_sha512.c
|
||||
* Module: library/sha512.c
|
||||
* Caller: library/entropy.c
|
||||
* library/mbedtls_md.c
|
||||
* library/md.c
|
||||
* library/ssl_cli.c
|
||||
* library/ssl_srv.c
|
||||
*
|
||||
|
|
@ -2181,7 +2374,8 @@
|
|||
* By default mbed TLS assumes it is used in a non-threaded environment or that
|
||||
* contexts are not shared between threads. If you do intend to use contexts
|
||||
* between threads, you will need to enable this layer to prevent race
|
||||
* conditions.
|
||||
* conditions. See also our Knowledge Base article about threading:
|
||||
* https://tls.mbed.org/kb/development/thread-safety-and-multi-threading
|
||||
*
|
||||
* Module: library/threading.c
|
||||
*
|
||||
|
|
@ -2198,7 +2392,18 @@
|
|||
/**
|
||||
* \def MBEDTLS_TIMING_C
|
||||
*
|
||||
* Enable the portable timing interface.
|
||||
* Enable the semi-portable timing interface.
|
||||
*
|
||||
* \note The provided implementation only works on POSIX/Unix (including Linux,
|
||||
* BSD and OS X) and Windows. On other platforms, you can either disable that
|
||||
* module and provide your own implementations of the callbacks needed by
|
||||
* \c mbedtls_ssl_set_timer_cb() for DTLS, or leave it enabled and provide
|
||||
* your own implementation of the whole module by setting
|
||||
* \c MBEDTLS_TIMING_ALT in the current file.
|
||||
*
|
||||
* \note See also our Knowledge Base article about porting to a new
|
||||
* environment:
|
||||
* https://tls.mbed.org/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS
|
||||
*
|
||||
* Module: library/timing.c
|
||||
* Caller: library/havege.c
|
||||
|
|
@ -2224,9 +2429,9 @@
|
|||
* Enable X.509 core for using certificates.
|
||||
*
|
||||
* Module: library/x509.c
|
||||
* Caller: library/mbedtls_x509_crl.c
|
||||
* library/mbedtls_x509_crt.c
|
||||
* library/mbedtls_x509_csr.c
|
||||
* Caller: library/x509_crl.c
|
||||
* library/x509_crt.c
|
||||
* library/x509_csr.c
|
||||
*
|
||||
* Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_BIGNUM_C, MBEDTLS_OID_C,
|
||||
* MBEDTLS_PK_PARSE_C
|
||||
|
|
@ -2240,7 +2445,7 @@
|
|||
*
|
||||
* Enable X.509 certificate parsing.
|
||||
*
|
||||
* Module: library/mbedtls_x509_crt.c
|
||||
* Module: library/x509_crt.c
|
||||
* Caller: library/ssl_cli.c
|
||||
* library/ssl_srv.c
|
||||
* library/ssl_tls.c
|
||||
|
|
@ -2256,8 +2461,8 @@
|
|||
*
|
||||
* Enable X.509 CRL parsing.
|
||||
*
|
||||
* Module: library/mbedtls_x509_crl.c
|
||||
* Caller: library/mbedtls_x509_crt.c
|
||||
* Module: library/x509_crl.c
|
||||
* Caller: library/x509_crt.c
|
||||
*
|
||||
* Requires: MBEDTLS_X509_USE_C
|
||||
*
|
||||
|
|
@ -2270,7 +2475,7 @@
|
|||
*
|
||||
* Enable X.509 Certificate Signing Request (CSR) parsing.
|
||||
*
|
||||
* Module: library/mbedtls_x509_csr.c
|
||||
* Module: library/x509_csr.c
|
||||
* Caller: library/x509_crt_write.c
|
||||
*
|
||||
* Requires: MBEDTLS_X509_USE_C
|
||||
|
|
@ -2347,12 +2552,12 @@
|
|||
|
||||
/* MPI / BIGNUM options */
|
||||
#define MBEDTLS_MPI_WINDOW_SIZE 1 /**< Maximum windows size used. */
|
||||
#define MBEDTLS_MPI_MAX_SIZE 512 /**< Maximum number of bytes for usable MPIs. */
|
||||
#define MBEDTLS_MPI_MAX_SIZE 512 /**< Maximum number of bytes for usable MPIs. */
|
||||
|
||||
/* CTR_DRBG options */
|
||||
//#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 48 /**< Amount of entropy used per seed by default (48 with SHA-512, 32 with SHA-256) */
|
||||
/* this is normally 10x higher, but reseeding seems quite inexpensive on esp8266 */
|
||||
#define MBEDTLS_CTR_DRBG_RESEED_INTERVAL 1000 /**< Interval before reseed is performed by default */
|
||||
#define MBEDTLS_CTR_DRBG_RESEED_INTERVAL 1000 /**< Interval before reseed is performed by default */
|
||||
//#define MBEDTLS_CTR_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */
|
||||
//#define MBEDTLS_CTR_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */
|
||||
//#define MBEDTLS_CTR_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */
|
||||
|
|
@ -2371,6 +2576,7 @@
|
|||
/* Entropy options */
|
||||
//#define MBEDTLS_ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */
|
||||
//#define MBEDTLS_ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */
|
||||
//#define MBEDTLS_ENTROPY_MIN_HARDWARE 32 /**< Default minimum number of bytes required for the hardware entropy source mbedtls_hardware_poll() before entropy is released */
|
||||
|
||||
/* Memory buffer allocator options */
|
||||
//#define MBEDTLS_MEMORY_ALIGN_MULTIPLE 4 /**< Align on multiples of this value */
|
||||
|
|
@ -2380,27 +2586,37 @@
|
|||
//#define MBEDTLS_PLATFORM_STD_CALLOC calloc /**< Default allocator to use, can be undefined */
|
||||
//#define MBEDTLS_PLATFORM_STD_FREE free /**< Default free to use, can be undefined */
|
||||
//#define MBEDTLS_PLATFORM_STD_EXIT exit /**< Default exit to use, can be undefined */
|
||||
//#define MBEDTLS_PLATFORM_STD_TIME time /**< Default time to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */
|
||||
//#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< Default fprintf to use, can be undefined */
|
||||
//#define MBEDTLS_PLATFORM_STD_PRINTF printf /**< Default printf to use, can be undefined */
|
||||
/* Note: your snprintf must correclty zero-terminate the buffer! */
|
||||
//#define MBEDTLS_PLATFORM_STD_SNPRINTF snprintf /**< Default snprintf to use, can be undefined */
|
||||
//#define MBEDTLS_PLATFORM_STD_EXIT_SUCCESS 0 /**< Default exit value to use, can be undefined */
|
||||
//#define MBEDTLS_PLATFORM_STD_EXIT_FAILURE 1 /**< Default exit value to use, can be undefined */
|
||||
//#define MBEDTLS_PLATFORM_STD_NV_SEED_READ mbedtls_platform_std_nv_seed_read /**< Default nv_seed_read function to use, can be undefined */
|
||||
//#define MBEDTLS_PLATFORM_STD_NV_SEED_WRITE mbedtls_platform_std_nv_seed_write /**< Default nv_seed_write function to use, can be undefined */
|
||||
//#define MBEDTLS_PLATFORM_STD_NV_SEED_FILE "seedfile" /**< Seed file to read/write with default implementation */
|
||||
|
||||
/* To Use Function Macros MBEDTLS_PLATFORM_C must be enabled */
|
||||
/* MBEDTLS_PLATFORM_XXX_MACRO and MBEDTLS_PLATFORM_XXX_ALT cannot both be defined */
|
||||
//#define MBEDTLS_PLATFORM_CALLOC_MACRO calloc /**< Default allocator macro to use, can be undefined */
|
||||
//#define MBEDTLS_PLATFORM_FREE_MACRO free /**< Default free macro to use, can be undefined */
|
||||
//#define MBEDTLS_PLATFORM_EXIT_MACRO exit /**< Default exit macro to use, can be undefined */
|
||||
//#define MBEDTLS_PLATFORM_TIME_MACRO time /**< Default time macro to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */
|
||||
//#define MBEDTLS_PLATFORM_TIME_TYPE_MACRO time_t /**< Default time macro to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */
|
||||
//#define MBEDTLS_PLATFORM_FPRINTF_MACRO fprintf /**< Default fprintf macro to use, can be undefined */
|
||||
//#define MBEDTLS_PLATFORM_PRINTF_MACRO printf /**< Default printf macro to use, can be undefined */
|
||||
/* Note: your snprintf must correclty zero-terminate the buffer! */
|
||||
//#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf /**< Default snprintf macro to use, can be undefined */
|
||||
//#define MBEDTLS_PLATFORM_NV_SEED_READ_MACRO mbedtls_platform_std_nv_seed_read /**< Default nv_seed_read function to use, can be undefined */
|
||||
//#define MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO mbedtls_platform_std_nv_seed_write /**< Default nv_seed_write function to use, can be undefined */
|
||||
|
||||
/* SSL Cache options */
|
||||
//#define MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT 86400 /**< 1 day */
|
||||
//#define MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /**< Maximum entries in cache */
|
||||
|
||||
/* SSL options */
|
||||
#define MBEDTLS_SSL_MAX_CONTENT_LEN 4096 /**< Maxium fragment length in bytes, determines the size of each of the two internal I/O buffers */
|
||||
#define MBEDTLS_SSL_MAX_CONTENT_LEN 4096 /**< Maxium fragment length in bytes, determines the size of each of the two internal I/O buffers */
|
||||
//#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */
|
||||
//#define MBEDTLS_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */
|
||||
//#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */
|
||||
|
|
@ -2421,11 +2637,35 @@
|
|||
|
||||
/* X509 options */
|
||||
//#define MBEDTLS_X509_MAX_INTERMEDIATE_CA 8 /**< Maximum number of intermediate CAs in a verification chain. */
|
||||
//#define MBEDTLS_X509_MAX_FILE_PATH_LEN 512 /**< Maximum length of a path/filename string in bytes including the null terminator character ('\0'). */
|
||||
|
||||
/* \} name SECTION: Module configuration options */
|
||||
/**
|
||||
* Allow SHA-1 in the default TLS configuration for certificate signing.
|
||||
* Without this build-time option, SHA-1 support must be activated explicitly
|
||||
* through mbedtls_ssl_conf_cert_profile. Turning on this option is not
|
||||
* recommended because of it is possible to generte SHA-1 collisions, however
|
||||
* this may be safe for legacy infrastructure where additional controls apply.
|
||||
*/
|
||||
// #define MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES
|
||||
|
||||
#if defined(TARGET_LIKE_MBED)
|
||||
#include "mbedtls/target_config.h"
|
||||
/**
|
||||
* Allow SHA-1 in the default TLS configuration for TLS 1.2 handshake
|
||||
* signature and ciphersuite selection. Without this build-time option, SHA-1
|
||||
* support must be activated explicitly through mbedtls_ssl_conf_sig_hashes.
|
||||
* The use of SHA-1 in TLS <= 1.1 and in HMAC-SHA-1 is always allowed by
|
||||
* default. At the time of writing, there is no practical attack on the use
|
||||
* of SHA-1 in handshake signatures, hence this option is turned on by default
|
||||
* for compatibility with existing peers.
|
||||
*/
|
||||
#define MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_KEY_EXCHANGE
|
||||
|
||||
/* \} name SECTION: Customisation configuration options */
|
||||
|
||||
/* Target and application specific configurations */
|
||||
//#define YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE "mbedtls/target_config.h"
|
||||
|
||||
#if defined(TARGET_LIKE_MBED) && defined(YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE)
|
||||
#include YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 0a0c22e0efcf2f8f71d7e16712f80b8f77326f72
|
||||
Subproject commit f2a597fa3dd1c7b15e0fee62f6932b253295803d
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
#if defined(MBEDTLS_NET_C)
|
||||
|
||||
#include "mbedtls/net.h"
|
||||
#include "mbedtls/net_sockets.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -6,66 +6,59 @@
|
|||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include "mcp4725.h"
|
||||
#include <i2c/i2c.h>
|
||||
|
||||
#define CMD_DAC 0x40
|
||||
#define CMD_EEPROM 0x60
|
||||
#define BIT_READY 0x80
|
||||
|
||||
static void read_data(uint8_t addr, uint8_t *buf, uint8_t size)
|
||||
static void read_data(i2c_dev_t* dev, uint8_t *buf, uint8_t size)
|
||||
{
|
||||
i2c_start();
|
||||
i2c_write(addr << 1 | 1);
|
||||
while (size--)
|
||||
*(buf++) = i2c_read(!size);
|
||||
i2c_stop();
|
||||
i2c_slave_read(dev->bus, dev->addr , NULL, buf, size);
|
||||
}
|
||||
|
||||
bool mcp4725_eeprom_busy(uint8_t addr)
|
||||
bool mcp4725_eeprom_busy(i2c_dev_t* dev)
|
||||
{
|
||||
uint8_t res;
|
||||
read_data(addr, &res, 1);
|
||||
read_data(dev, &res, 1);
|
||||
|
||||
return !(res & BIT_READY);
|
||||
}
|
||||
|
||||
mcp4725_power_mode_t mcp4725_get_power_mode(uint8_t addr, bool eeprom)
|
||||
mcp4725_power_mode_t mcp4725_get_power_mode(i2c_dev_t* dev, bool eeprom)
|
||||
{
|
||||
uint8_t buf[4];
|
||||
read_data(addr, buf, eeprom ? 4 : 1);
|
||||
read_data(dev, buf, eeprom ? 4 : 1);
|
||||
|
||||
return (eeprom ? buf[3] >> 5 : buf[0] >> 1) & 0x03;
|
||||
}
|
||||
|
||||
void mcp4725_set_power_mode(uint8_t addr, mcp4725_power_mode_t mode, bool eeprom)
|
||||
void mcp4725_set_power_mode(i2c_dev_t* dev, mcp4725_power_mode_t mode, bool eeprom)
|
||||
{
|
||||
uint16_t value = mcp4725_get_raw_output(addr, eeprom);
|
||||
uint16_t value = mcp4725_get_raw_output(dev, eeprom);
|
||||
uint8_t data[] = {
|
||||
(eeprom ? CMD_EEPROM : CMD_DAC) | ((uint8_t)mode << 1),
|
||||
value >> 4,
|
||||
value << 4
|
||||
};
|
||||
i2c_slave_write(addr, data, 3);
|
||||
i2c_slave_write(dev->bus, dev->addr, &data[0], &data[1], 2);
|
||||
}
|
||||
|
||||
uint16_t mcp4725_get_raw_output(uint8_t addr, bool eeprom)
|
||||
uint16_t mcp4725_get_raw_output(i2c_dev_t* dev, bool eeprom)
|
||||
{
|
||||
uint8_t buf[5];
|
||||
read_data(addr, buf, eeprom ? 5 : 3);
|
||||
read_data(dev, buf, eeprom ? 5 : 3);
|
||||
|
||||
return eeprom
|
||||
? ((uint16_t)(buf[3] & 0x0f) << 8) | buf[4]
|
||||
: ((uint16_t)buf[0] << 4) | (buf[1] >> 4);
|
||||
}
|
||||
|
||||
void mcp4725_set_raw_output(uint8_t addr, uint16_t value, bool eeprom)
|
||||
void mcp4725_set_raw_output(i2c_dev_t* dev, uint16_t value, bool eeprom)
|
||||
{
|
||||
uint8_t data[] = {
|
||||
(eeprom ? CMD_EEPROM : CMD_DAC),
|
||||
value >> 4,
|
||||
value << 4
|
||||
};
|
||||
i2c_slave_write(addr, data, 3);
|
||||
i2c_slave_write(dev->bus, dev->addr, &data[0], &data[1], 2);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <i2c/i2c.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
|
|
@ -41,7 +42,7 @@ typedef enum
|
|||
* @param addr Device address
|
||||
* @return true when EEPROM is busy
|
||||
*/
|
||||
bool mcp4725_eeprom_busy(uint8_t addr);
|
||||
bool mcp4725_eeprom_busy(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* Get power mode
|
||||
|
|
@ -49,7 +50,7 @@ bool mcp4725_eeprom_busy(uint8_t addr);
|
|||
* @param eeprom Read power mode from EEPROM if true
|
||||
* @return Power mode
|
||||
*/
|
||||
mcp4725_power_mode_t mcp4725_get_power_mode(uint8_t addr, bool eeprom);
|
||||
mcp4725_power_mode_t mcp4725_get_power_mode(i2c_dev_t* dev, bool eeprom);
|
||||
|
||||
/**
|
||||
* Set power mode
|
||||
|
|
@ -57,7 +58,7 @@ mcp4725_power_mode_t mcp4725_get_power_mode(uint8_t addr, bool eeprom);
|
|||
* @param mode Power mode
|
||||
* @param eeprom Store mode to device EEPROM if true
|
||||
*/
|
||||
void mcp4725_set_power_mode(uint8_t addr, mcp4725_power_mode_t mode, bool eeprom);
|
||||
void mcp4725_set_power_mode(i2c_dev_t* dev, mcp4725_power_mode_t mode, bool eeprom);
|
||||
|
||||
/**
|
||||
* Get current DAC value
|
||||
|
|
@ -65,7 +66,7 @@ void mcp4725_set_power_mode(uint8_t addr, mcp4725_power_mode_t mode, bool eeprom
|
|||
* @param eeprom Read value from device EEPROM if true
|
||||
* @return Raw output value, 0..4095
|
||||
*/
|
||||
uint16_t mcp4725_get_raw_output(uint8_t addr, bool eeprom);
|
||||
uint16_t mcp4725_get_raw_output(i2c_dev_t* dev, bool eeprom);
|
||||
|
||||
/**
|
||||
* Set DAC output value
|
||||
|
|
@ -73,7 +74,7 @@ uint16_t mcp4725_get_raw_output(uint8_t addr, bool eeprom);
|
|||
* @param value Raw output value, 0..4095
|
||||
* @param eeprom Store value to device EEPROM if true
|
||||
*/
|
||||
void mcp4725_set_raw_output(uint8_t addr, uint16_t value, bool eeprom);
|
||||
void mcp4725_set_raw_output(i2c_dev_t* dev, uint16_t value, bool eeprom);
|
||||
|
||||
/**
|
||||
* Get current DAC output voltage
|
||||
|
|
@ -82,9 +83,9 @@ void mcp4725_set_raw_output(uint8_t addr, uint16_t value, bool eeprom);
|
|||
* @param eeprom Read voltage from device EEPROM if true
|
||||
* @return Current output voltage, volts
|
||||
*/
|
||||
inline float mcp4725_get_voltage(uint8_t addr, float vdd, bool eeprom)
|
||||
inline float mcp4725_get_voltage(i2c_dev_t* dev, float vdd, bool eeprom)
|
||||
{
|
||||
return vdd / MCP4725_MAX_VALUE * mcp4725_get_raw_output(addr, eeprom);
|
||||
return vdd / MCP4725_MAX_VALUE * mcp4725_get_raw_output(dev, eeprom);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -94,9 +95,9 @@ inline float mcp4725_get_voltage(uint8_t addr, float vdd, bool eeprom)
|
|||
* @param value Output value, volts
|
||||
* @param eeprom Store value to device EEPROM if true
|
||||
*/
|
||||
inline void mcp4725_set_voltage(uint8_t addr, float vdd, float value, bool eeprom)
|
||||
inline void mcp4725_set_voltage(i2c_dev_t* dev, float vdd, float value, bool eeprom)
|
||||
{
|
||||
mcp4725_set_raw_output(addr, MCP4725_MAX_VALUE / vdd * value, eeprom);
|
||||
mcp4725_set_raw_output(dev, MCP4725_MAX_VALUE / vdd * value, eeprom);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
9
extras/mdnsresponder/component.mk
Normal file
9
extras/mdnsresponder/component.mk
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# Component makefile for extras/mdnsresponder
|
||||
|
||||
INC_DIRS += $(mdnsresponder_ROOT)
|
||||
|
||||
# args for passing into compile rule generation
|
||||
mdnsresponder_INC_DIR = $(mdnsresponder_ROOT)
|
||||
mdnsresponder_SRC_DIR = $(mdnsresponder_ROOT)
|
||||
|
||||
$(eval $(call component_compile_rules,mdnsresponder))
|
||||
797
extras/mdnsresponder/mdnsresponder.c
Normal file
797
extras/mdnsresponder/mdnsresponder.c
Normal file
|
|
@ -0,0 +1,797 @@
|
|||
/*
|
||||
* Basic multicast DNS responder
|
||||
*
|
||||
* Advertises the IP address, port, and characteristics of a service to other devices using multicast DNS on the same LAN,
|
||||
* so they can find devices with addresses dynamically allocated by DHCP. See avahi, Bonjour, etc
|
||||
* See RFC6762, RFC6763
|
||||
*
|
||||
* This sample code is in the public domain.
|
||||
*
|
||||
* by M J A Hamel 2016
|
||||
*/
|
||||
|
||||
|
||||
#include <espressif/esp_common.h>
|
||||
#include <espressif/esp_wifi.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
|
||||
#include <lwip/err.h>
|
||||
#include <lwip/sockets.h>
|
||||
#include <lwip/sys.h>
|
||||
#include <lwip/netdb.h>
|
||||
#include <lwip/dns.h>
|
||||
#include <lwip/udp.h>
|
||||
#include <lwip/igmp.h>
|
||||
#include <lwip/netif.h>
|
||||
|
||||
#include "mdnsresponder.h"
|
||||
|
||||
#define qDebugLog // Log activity generally
|
||||
#define qLogIncoming // Log all arriving multicast packets
|
||||
#define qLogAllTraffic // Log and decode all mDNS packets
|
||||
|
||||
#define kMDNSStackSize 800
|
||||
|
||||
#define DNS_MULTICAST_ADDRESS "224.0.0.251" // RFC 6762
|
||||
#define DNS_MDNS_PORT 5353 // RFC 6762
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/bpstruct.h"
|
||||
#endif
|
||||
|
||||
PACK_STRUCT_BEGIN
|
||||
/** DNS message header */
|
||||
struct mdns_hdr {
|
||||
PACK_STRUCT_FIELD(u16_t id);
|
||||
PACK_STRUCT_FIELD(u8_t flags1);
|
||||
PACK_STRUCT_FIELD(u8_t flags2);
|
||||
PACK_STRUCT_FIELD(u16_t numquestions);
|
||||
PACK_STRUCT_FIELD(u16_t numanswers);
|
||||
PACK_STRUCT_FIELD(u16_t numauthrr);
|
||||
PACK_STRUCT_FIELD(u16_t numextrarr);
|
||||
}PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
|
||||
#define SIZEOF_DNS_HDR 12
|
||||
|
||||
PACK_STRUCT_BEGIN
|
||||
/** MDNS query message structure */
|
||||
struct mdns_query {
|
||||
/* MDNS query record starts with either a domain name or a pointer
|
||||
to a name already present somewhere in the packet. */
|
||||
PACK_STRUCT_FIELD(u16_t type);
|
||||
PACK_STRUCT_FIELD(u16_t class);
|
||||
}PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
|
||||
#define SIZEOF_DNS_QUERY 4
|
||||
|
||||
PACK_STRUCT_BEGIN
|
||||
/** MDNS answer message structure */
|
||||
struct mdns_answer {
|
||||
/* MDNS answer record starts with either a domain name or a pointer
|
||||
to a name already present somewhere in the packet. */
|
||||
PACK_STRUCT_FIELD(u16_t type);
|
||||
PACK_STRUCT_FIELD(u16_t class);
|
||||
PACK_STRUCT_FIELD(u32_t ttl);
|
||||
PACK_STRUCT_FIELD(u16_t len);
|
||||
}PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#define SIZEOF_DNS_ANSWER 10
|
||||
|
||||
PACK_STRUCT_BEGIN
|
||||
struct mdns_rr_srv {
|
||||
/* RR SRV */
|
||||
PACK_STRUCT_FIELD(u16_t prio);
|
||||
PACK_STRUCT_FIELD(u16_t weight);
|
||||
PACK_STRUCT_FIELD(u16_t port);
|
||||
}PACK_STRUCT_STRUCT;
|
||||
PACK_STRUCT_END
|
||||
#define SIZEOF_DNS_RR_SRV 6
|
||||
|
||||
|
||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||
# include "arch/epstruct.h"
|
||||
#endif
|
||||
|
||||
#define vTaskDelayMs(ms) vTaskDelay((ms)/portTICK_PERIOD_MS)
|
||||
#define UNUSED_ARG(x) (void)x
|
||||
#define kDummyDataSize 8 // arbitrary, dynamically resized
|
||||
#define kMaxNameSize 64
|
||||
#define kMaxQStr 128 // max incoming question key handled
|
||||
|
||||
typedef struct mdns_rsrc {
|
||||
struct mdns_rsrc* rNext;
|
||||
u16_t rType;
|
||||
u32_t rTTL;
|
||||
u16_t rKeySize;
|
||||
u16_t rDataSize;
|
||||
char rData[kDummyDataSize]; // Key, as C str with . seperators, followed by data in network-ready form
|
||||
// at rData[rKeySize]
|
||||
} mdns_rsrc;
|
||||
|
||||
static struct udp_pcb* gMDNS_pcb = NULL;
|
||||
static ip_addr_t gMulticastAddr; // == DNS_MULTICAST_ADDRESS
|
||||
static mdns_rsrc* gDictP = NULL; // RR database, linked list
|
||||
|
||||
//---------------------- Debug/logging utilities -------------------------
|
||||
|
||||
#ifdef qDebugLog
|
||||
|
||||
// DNS field TYPE used for "Resource Records", some additions
|
||||
#define DNS_RRTYPE_AAAA 28 /* IPv6 host address */
|
||||
#define DNS_RRTYPE_SRV 33 /* Service record */
|
||||
#define DNS_RRTYPE_OPT 41 /* EDNS0 OPT record */
|
||||
#define DNS_RRTYPE_NSEC 47 /* NSEC record */
|
||||
#define DNS_RRTYPE_TSIG 250 /* Transaction Signature */
|
||||
#define DNS_RRTYPE_ANY 255 /* Not a DNS type, but a DNS query type, meaning "all types"*/
|
||||
|
||||
// DNS field CLASS used for "Resource Records"
|
||||
#define DNS_RRCLASS_ANY 255 /* Any class (q) */
|
||||
|
||||
#define DNS_FLAG1_RESP 0x80
|
||||
#define DNS_FLAG1_OPMASK 0x78
|
||||
#define DNS_FLAG1_AUTH 0x04
|
||||
#define DNS_FLAG1_TRUNC 0x02
|
||||
#define DNS_FLAG1_RD 0x01
|
||||
#define DNS_FLAG2_RA 0x80
|
||||
#define DNS_FLAG2_RESMASK 0x0F
|
||||
|
||||
static char qstr[12];
|
||||
|
||||
static char* mdns_qrtype(uint16_t typ)
|
||||
{
|
||||
switch(typ) {
|
||||
case DNS_RRTYPE_A : return ("A");
|
||||
case DNS_RRTYPE_NS : return ("NS");
|
||||
case DNS_RRTYPE_PTR : return ("PTR");
|
||||
case DNS_RRTYPE_TXT : return ("TXT ");
|
||||
case DNS_RRTYPE_AAAA : return ("AAAA");
|
||||
case DNS_RRTYPE_SRV : return ("SRV ");
|
||||
case DNS_RRTYPE_NSEC : return ("NSEC ");
|
||||
case DNS_RRTYPE_ANY : return ("ANY");
|
||||
}
|
||||
sprintf(qstr,"type %d",typ);
|
||||
return qstr;
|
||||
}
|
||||
|
||||
#ifdef qLogAllTraffic
|
||||
|
||||
static void mdns_printhex(u8_t* p, int n)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<n; i++) {
|
||||
printf("%02X ",*p++);
|
||||
if ((i % 32) == 31) printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void mdns_print_pstr(u8_t* p)
|
||||
{
|
||||
int i, n;
|
||||
char* cp;
|
||||
|
||||
n = *p++;
|
||||
cp = (char*)p;
|
||||
for (i=0; i<n; i++) putchar(*cp++);
|
||||
}
|
||||
|
||||
static char cstr[16];
|
||||
|
||||
static char* mdns_qclass(uint16_t cls)
|
||||
{
|
||||
switch(cls) {
|
||||
case DNS_RRCLASS_IN : return ("In");
|
||||
case DNS_RRCLASS_ANY : return ("ANY");
|
||||
}
|
||||
sprintf(cstr,"class %d",cls);
|
||||
return cstr;
|
||||
}
|
||||
|
||||
static u8_t* mdns_print_name(u8_t* p, struct mdns_hdr* hp)
|
||||
// Sequence of Pascal strings, terminated by zero-length string
|
||||
// Handles compression, returns ptr to next item
|
||||
{
|
||||
char* cp = (char*)p;
|
||||
int i, n;
|
||||
|
||||
do {
|
||||
n = *cp++;
|
||||
if ((n & 0xC0) == 0xC0) {
|
||||
n = (n & 0x3F) << 8;
|
||||
n |= (u8_t)*cp++;
|
||||
mdns_print_name( (u8_t*)hp + n ,hp );
|
||||
n = 0;
|
||||
} else if (n & 0xC0) {
|
||||
printf("<label $%X?>",n);
|
||||
n = 0;
|
||||
} else {
|
||||
for (i=0; i<n; i++)
|
||||
putchar(*cp++);
|
||||
if (n!=0) putchar('.');
|
||||
}
|
||||
} while (n>0);
|
||||
return (u8_t*)cp;
|
||||
}
|
||||
|
||||
|
||||
static u8_t* mdns_print_header(struct mdns_hdr* hdr)
|
||||
{
|
||||
if (hdr->flags1 & DNS_FLAG1_RESP) {
|
||||
printf("Response, ID $%X %s ", htons(hdr->id), (hdr->flags1 & DNS_FLAG1_AUTH) ? "Auth " : "Non-auth ");
|
||||
if (hdr->flags2 & DNS_FLAG2_RA) printf("RA ");
|
||||
if ((hdr->flags2 & DNS_FLAG2_RESMASK)==0) printf("noerr");
|
||||
else printf("err %d", hdr->flags2 & DNS_FLAG2_RESMASK);
|
||||
} else {
|
||||
printf("Query, ID $%X op %d", htons(hdr->id), (hdr->flags1>>4) & 0x7 );
|
||||
}
|
||||
if (hdr->flags1 & DNS_FLAG1_RD) printf("RD ");
|
||||
if (hdr->flags1 & DNS_FLAG1_TRUNC) printf("[TRUNC] ");
|
||||
|
||||
printf(": %d questions", htons(hdr->numquestions) );
|
||||
if (hdr->numanswers != 0)
|
||||
printf(", %d answers",htons(hdr->numanswers));
|
||||
if (hdr->numauthrr != 0)
|
||||
printf(", %d auth RR",htons(hdr->numauthrr));
|
||||
if (hdr->numextrarr != 0)
|
||||
printf(", %d extra RR",htons(hdr->numextrarr));
|
||||
putchar('\n');
|
||||
return (u8_t*)hdr + SIZEOF_DNS_HDR;
|
||||
}
|
||||
|
||||
static u8_t* mdns_print_query(u8_t* p)
|
||||
// Copy needed because it may be misaligned
|
||||
{
|
||||
struct mdns_query q;
|
||||
uint16_t c;
|
||||
|
||||
memcpy(&q,p,SIZEOF_DNS_QUERY);
|
||||
c = htons(q.class);
|
||||
printf(" %s %s", mdns_qrtype(htons(q.type)), mdns_qclass(c & 0x7FFF) );
|
||||
if (c & 0x8000) printf(" unicast-req");
|
||||
printf("\n");
|
||||
return p + SIZEOF_DNS_QUERY;
|
||||
}
|
||||
|
||||
static u8_t* mdns_print_answer(u8_t* p, struct mdns_hdr* hp)
|
||||
// Copy needed because it may be misaligned
|
||||
{
|
||||
struct mdns_answer ans;
|
||||
u16_t rrlen, atype, rrClass;;
|
||||
|
||||
memcpy(&ans,p,SIZEOF_DNS_ANSWER);
|
||||
atype = htons(ans.type);
|
||||
rrlen = htons(ans.len);
|
||||
rrClass = htons(ans.class);
|
||||
printf(" %s %s TTL %d ", mdns_qrtype(atype), mdns_qclass(rrClass & 0x7FFF), htonl(ans.ttl));
|
||||
if (rrClass & 0x8000)
|
||||
printf("cache-flush ");
|
||||
if (rrlen > 0) {
|
||||
u8_t* rp = p + SIZEOF_DNS_ANSWER;
|
||||
if (atype==DNS_RRTYPE_A && rrlen==4) {
|
||||
printf("%d.%d.%d.%d\n",rp[0],rp[1],rp[2],rp[3]);
|
||||
} else if (atype==DNS_RRTYPE_PTR) {
|
||||
mdns_print_name(rp, hp);
|
||||
printf("\n");
|
||||
} else if (atype==DNS_RRTYPE_TXT) {
|
||||
mdns_print_pstr(rp);
|
||||
printf("\n");
|
||||
} else if (atype==DNS_RRTYPE_SRV && rrlen > SIZEOF_DNS_RR_SRV) {
|
||||
struct mdns_rr_srv srvRR;
|
||||
memcpy(&srvRR,rp,SIZEOF_DNS_RR_SRV);
|
||||
printf("prio %d, weight %d, port %d, target ", srvRR.prio, srvRR.weight, srvRR.port);
|
||||
mdns_print_name(rp + SIZEOF_DNS_RR_SRV, hp);
|
||||
printf("\n");
|
||||
} else {
|
||||
printf("%db:",rrlen);
|
||||
mdns_printhex(rp,rrlen);
|
||||
}
|
||||
} else
|
||||
printf("\n");
|
||||
return p + SIZEOF_DNS_ANSWER + rrlen;
|
||||
}
|
||||
|
||||
static int mdns_print_msg(u8_t* msgP, int msgLen)
|
||||
{
|
||||
int i;
|
||||
u8_t* tp;
|
||||
u8_t* limP = msgP + msgLen;
|
||||
struct mdns_hdr* hdr;
|
||||
|
||||
hdr = (struct mdns_hdr*) msgP;
|
||||
tp = mdns_print_header(hdr);
|
||||
for (i=0; i<htons(hdr->numquestions); i++) {
|
||||
printf(" Q%d: ",i+1);
|
||||
tp = mdns_print_name(tp,hdr);
|
||||
tp = mdns_print_query(tp);
|
||||
if (tp > limP) return 0;
|
||||
}
|
||||
|
||||
for (i=0; i<htons(hdr->numanswers); i++) {
|
||||
printf(" A%d: ",i+1);
|
||||
tp = mdns_print_name(tp,hdr);
|
||||
tp = mdns_print_answer(tp,hdr);
|
||||
if (tp > limP) return 0;
|
||||
}
|
||||
|
||||
for (i=0; i<htons(hdr->numauthrr); i++) {
|
||||
printf(" AuRR%d: ",i+1);
|
||||
tp = mdns_print_name(tp,hdr);
|
||||
tp = mdns_print_answer(tp,hdr);
|
||||
if (tp > limP) return 0;
|
||||
}
|
||||
|
||||
for (i=0; i<htons(hdr->numextrarr); i++) {
|
||||
printf(" ExRR%d: ",i+1);
|
||||
tp = mdns_print_name(tp,hdr);
|
||||
tp = mdns_print_answer(tp,hdr);
|
||||
if (tp > limP) return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // qDebugLog
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
static u8_t* mdns_labels2str(u8_t* hdrP, u8_t* p, char* qStr)
|
||||
// Convert a DNS domain name label sequence into C string with . seperators
|
||||
// Handles compression
|
||||
{
|
||||
int i, n;
|
||||
|
||||
do {
|
||||
n = *p++;
|
||||
if ((n & 0xC0) == 0xC0) {
|
||||
n = (n & 0x3F) << 8;
|
||||
n |= (u8_t)*p++;
|
||||
mdns_labels2str( hdrP, hdrP + n, qStr);
|
||||
return p;
|
||||
} else if (n & 0xC0) {
|
||||
printf(">>> mdns_labels2str,label $%X?",n);
|
||||
return p;
|
||||
} else {
|
||||
for (i=0; i<n; i++)
|
||||
*qStr++ = *p++;
|
||||
if (n==0) *qStr++ = 0;
|
||||
else *qStr++ = '.';
|
||||
}
|
||||
} while (n>0);
|
||||
return p;
|
||||
}
|
||||
|
||||
static int mdns_str2labels(const char* name, u8_t* lseq, int max)
|
||||
// Encode a <string>.<string>.<string> as a sequence of labels, return length
|
||||
{
|
||||
int i,n,sdx,idx = 0;
|
||||
int lc = 0;
|
||||
|
||||
do {
|
||||
sdx = idx;
|
||||
while (name[idx] != '.' && name[idx] != 0) idx++;
|
||||
n = idx-sdx;
|
||||
*lseq++ = n;
|
||||
lc++;
|
||||
if (lc+n > max) {
|
||||
printf(">>> mdns_str2labels: oversize (%d)\n",lc+n);
|
||||
return 0;
|
||||
}
|
||||
for (i=0; i<n; i++)
|
||||
*lseq++ = name[sdx+i];
|
||||
lc += n;
|
||||
if (name[idx]=='.')
|
||||
idx++;
|
||||
} while (n>0);
|
||||
return lc;
|
||||
}
|
||||
|
||||
static u8_t* mdns_get_question(u8_t* hdrP, u8_t* qp, char* qStr, uint16_t* qClass, uint16_t* qType, u8_t* qUnicast)
|
||||
// Unpack a DNS question RR at qp, return pointer to next RR
|
||||
{
|
||||
struct mdns_query qr;
|
||||
uint16_t cls;
|
||||
|
||||
qp = mdns_labels2str(hdrP, qp, qStr);
|
||||
memcpy(&qr,qp,SIZEOF_DNS_QUERY);
|
||||
*qType = htons(qr.type);
|
||||
cls = htons(qr.class);
|
||||
*qUnicast = cls>>15;
|
||||
*qClass = cls & 0x7FFF;
|
||||
return qp + SIZEOF_DNS_QUERY;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
static void mdns_add_response(const char* vKey, u16_t vType, u32_t ttl, const void* dataP, u16_t vDataSize)
|
||||
// Add a record to the RR database list
|
||||
{
|
||||
mdns_rsrc* rsrcP;
|
||||
int keyLen, recSize;
|
||||
|
||||
keyLen = strlen(vKey) + 1;
|
||||
recSize = sizeof(mdns_rsrc) - kDummyDataSize + keyLen + vDataSize;
|
||||
rsrcP = (mdns_rsrc*)malloc(recSize);
|
||||
if (rsrcP==NULL)
|
||||
printf(">>> mdns_add_response: couldn't alloc %d\n",recSize);
|
||||
else {
|
||||
rsrcP->rType = vType;
|
||||
rsrcP->rTTL = ttl;
|
||||
rsrcP->rKeySize = keyLen;
|
||||
rsrcP->rDataSize = vDataSize;
|
||||
memcpy(rsrcP->rData, vKey, keyLen);
|
||||
memcpy(&rsrcP->rData[keyLen], dataP, vDataSize);
|
||||
rsrcP->rNext = gDictP;
|
||||
gDictP = rsrcP;
|
||||
#ifdef qDebugLog
|
||||
printf("mDNS added RR '%s' %s, %d bytes\n", vKey, mdns_qrtype(vType), vDataSize);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void mdns_add_PTR(const char* rKey, u32_t ttl, const char* nmStr)
|
||||
{
|
||||
int nl;
|
||||
u8_t lBuff[kMaxNameSize];
|
||||
|
||||
nl = mdns_str2labels(nmStr,lBuff,sizeof(lBuff));
|
||||
if (nl>0)
|
||||
mdns_add_response(rKey, DNS_RRTYPE_PTR, ttl, lBuff, nl);
|
||||
}
|
||||
|
||||
void mdns_add_SRV(const char* rKey, u32_t ttl, u16_t rPort, const char* targName)
|
||||
{
|
||||
typedef struct SrvRec {
|
||||
struct mdns_rr_srv srvRR;
|
||||
u8_t lBuff[kMaxNameSize];
|
||||
} __attribute__((packed)) SrvRec;
|
||||
|
||||
int nl;
|
||||
SrvRec temp;
|
||||
|
||||
temp.srvRR.prio = 0;
|
||||
temp.srvRR.weight = 0;
|
||||
temp.srvRR.port = htons(rPort);
|
||||
nl = mdns_str2labels(targName,temp.lBuff,sizeof(temp.lBuff));
|
||||
if (nl>0)
|
||||
mdns_add_response(rKey, DNS_RRTYPE_SRV, ttl, &temp, SIZEOF_DNS_RR_SRV + nl);
|
||||
}
|
||||
|
||||
void mdns_add_TXT(const char* rKey, u32_t ttl, const char* txStr)
|
||||
// Single TXT str, can be concatenated
|
||||
{
|
||||
char pstr[256];
|
||||
u16_t n = strlen(txStr);
|
||||
if (n > 255)
|
||||
printf(">>> mdns_add_TXT oversize (%d)\n",n);
|
||||
else {
|
||||
pstr[0] = n;
|
||||
memcpy(&pstr[1],txStr,n);
|
||||
mdns_add_response(rKey, DNS_RRTYPE_TXT, ttl, txStr, n+1);
|
||||
}
|
||||
}
|
||||
|
||||
void mdns_add_A(const char* rKey, u32_t ttl, struct ip_addr addr)
|
||||
{
|
||||
mdns_add_response(rKey, DNS_RRTYPE_A, ttl, &addr, sizeof(addr));
|
||||
}
|
||||
|
||||
void mdns_add_facility( const char* instanceName, // Friendly name, need not be unique
|
||||
const char* serviceName, // Must be _name
|
||||
const char* addText, // Must be <key>=<value>
|
||||
mdns_flags flags, // TCP or UDP
|
||||
u16_t onPort, // port number
|
||||
u32_t ttl // seconds
|
||||
)
|
||||
{
|
||||
char key[64];
|
||||
char fullName[128];
|
||||
char devName[96];
|
||||
struct ip_info ipInfo;
|
||||
|
||||
#ifdef qDebugLog
|
||||
printf("\nmDNS advertising instance %s protocol %s text %s on port %d %s TTL %d secs\n",
|
||||
instanceName,serviceName,addText,onPort,(flags & mdns_UDP) ? "UDP" : "TCP", ttl);
|
||||
#endif
|
||||
|
||||
snprintf(key,sizeof(key),"%s.%s.local.",serviceName,(flags & mdns_UDP) ? "_udp" :"_tcp");
|
||||
snprintf(fullName,sizeof(fullName),"%s.%s",instanceName,key);
|
||||
snprintf(devName,sizeof(devName),"%s.local.",instanceName);
|
||||
|
||||
if (!sdk_wifi_get_ip_info(STATION_IF,&ipInfo))
|
||||
ipInfo.ip.addr = IPADDR_NONE;
|
||||
|
||||
// Order has significance for extraRR feature
|
||||
mdns_add_TXT(fullName,ttl,addText);
|
||||
mdns_add_A(devName,ttl,ipInfo.ip);
|
||||
mdns_add_SRV(fullName,ttl,onPort,devName);
|
||||
mdns_add_PTR(key,ttl,fullName);
|
||||
|
||||
// Optional, makes us browsable
|
||||
if (flags & mdns_Browsable)
|
||||
mdns_add_PTR("_services._dns-sd._udp.local.",ttl,key);
|
||||
|
||||
}
|
||||
|
||||
static void mdns_update_ipaddr(struct ip_info* ipInfo)
|
||||
// IP address has been defined/changed: update any A records with the new IP
|
||||
{
|
||||
mdns_rsrc* rp = gDictP;
|
||||
while (rp != NULL) {
|
||||
if (rp->rType==DNS_RRTYPE_A) {
|
||||
#ifdef qDebugLog
|
||||
printf("Updating A record for '%s' to %d.%d.%d.%d\n", rp->rData,
|
||||
ip4_addr1(&ipInfo->ip), ip4_addr2(&ipInfo->ip), ip4_addr3(&ipInfo->ip), ip4_addr4(&ipInfo->ip));
|
||||
#endif
|
||||
memcpy(&rp->rData[rp->rKeySize], &ipInfo->ip, sizeof(ip_addr_t));
|
||||
}
|
||||
rp = rp->rNext;
|
||||
}
|
||||
}
|
||||
|
||||
static mdns_rsrc* mdns_match(const char* qstr, u16_t qType)
|
||||
{
|
||||
mdns_rsrc* rp = gDictP;
|
||||
while (rp != NULL) {
|
||||
if (rp->rType==qType || qType==DNS_RRTYPE_ANY) {
|
||||
if (strcasecmp(rp->rData,qstr)==0) {
|
||||
#ifdef qDebugLog
|
||||
printf(" - matched '%s' %s\n",qstr,mdns_qrtype(rp->rType));
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
rp = rp->rNext;
|
||||
}
|
||||
return rp;
|
||||
}
|
||||
|
||||
static int mdns_add_to_answer(mdns_rsrc* rsrcP, u8_t* resp, int respLen)
|
||||
// Create answer RR and append to resp[respLen], return new length
|
||||
{
|
||||
// Key is stored as C str, convert to labels
|
||||
respLen += mdns_str2labels(rsrcP->rData, &resp[respLen], DNS_MSG_SIZE-respLen);
|
||||
|
||||
// Answer fields: may be misaligned, so build and memcpy
|
||||
struct mdns_answer ans;
|
||||
ans.type = htons(rsrcP->rType);
|
||||
ans.class = htons(DNS_RRCLASS_IN);
|
||||
ans.ttl = htonl(rsrcP->rTTL);
|
||||
ans.len = htons(rsrcP->rDataSize);
|
||||
memcpy(&resp[respLen], &ans, SIZEOF_DNS_ANSWER);
|
||||
respLen += SIZEOF_DNS_ANSWER;
|
||||
|
||||
// Data for this key
|
||||
memcpy(&resp[respLen], &rsrcP->rData[rsrcP->rKeySize], rsrcP->rDataSize);
|
||||
respLen += rsrcP->rDataSize;
|
||||
|
||||
return respLen;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
static void mdns_send_mcast(u8_t* msgP, int nBytes)
|
||||
// Send UDP to multicast address
|
||||
{
|
||||
struct pbuf* p;
|
||||
err_t err;
|
||||
|
||||
p = pbuf_alloc(PBUF_TRANSPORT, nBytes, PBUF_RAM);
|
||||
if (p) {
|
||||
memcpy(p->payload, msgP, nBytes);
|
||||
err = udp_sendto(gMDNS_pcb, p, &gMulticastAddr, DNS_MDNS_PORT);
|
||||
if (err==ERR_OK) {
|
||||
#ifdef qDebugLog
|
||||
printf(" - responded with %d bytes err %d\n",nBytes,err);
|
||||
#endif
|
||||
} else
|
||||
printf(">>> mdns_send failed %d\n",err);
|
||||
pbuf_free(p);
|
||||
} else
|
||||
printf(">>> mdns_send: alloc failed[%d]\n",nBytes);
|
||||
}
|
||||
|
||||
static void mdns_reply(struct mdns_hdr* hdrP)
|
||||
// Message has passed tests, may want to send an answer
|
||||
{
|
||||
int i, nquestions, respLen;
|
||||
struct mdns_hdr* rHdr;
|
||||
mdns_rsrc* extra;
|
||||
u8_t* qBase = (u8_t*)hdrP;
|
||||
u8_t* qp;
|
||||
u8_t* mdns_response;
|
||||
|
||||
mdns_response = malloc(DNS_MSG_SIZE);
|
||||
if (mdns_response==NULL) {
|
||||
printf(">>> mdns_reply could not alloc %d\n",DNS_MSG_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
// Build response header
|
||||
rHdr = (struct mdns_hdr*) mdns_response;
|
||||
rHdr->id = hdrP->id;
|
||||
rHdr->flags1 = DNS_FLAG1_RESP + DNS_FLAG1_AUTH;
|
||||
rHdr->flags2 = 0;
|
||||
rHdr->numquestions = 0;
|
||||
rHdr->numanswers = 0;
|
||||
rHdr->numauthrr = 0;
|
||||
rHdr->numextrarr = 0;
|
||||
respLen = SIZEOF_DNS_HDR;
|
||||
|
||||
extra = NULL;
|
||||
qp = qBase + SIZEOF_DNS_HDR;
|
||||
nquestions = htons(hdrP->numquestions);
|
||||
|
||||
for (i=0; i<nquestions; i++) {
|
||||
char qStr[kMaxQStr];
|
||||
u16_t qClass, qType;
|
||||
u8_t qUnicast;
|
||||
mdns_rsrc* rsrcP;
|
||||
|
||||
qp = mdns_get_question(qBase, qp, qStr, &qClass, &qType, &qUnicast);
|
||||
if (qClass==DNS_RRCLASS_IN || qClass==DNS_RRCLASS_ANY) {
|
||||
rsrcP = mdns_match(qStr,qType);
|
||||
if (rsrcP) {
|
||||
respLen = mdns_add_to_answer(rsrcP, mdns_response, respLen);
|
||||
rHdr->numanswers = htons( htons(rHdr->numanswers) + 1 );
|
||||
// Extra RR logic: if SRV follows PTR, or A follows SRV, volunteer it in extraRR
|
||||
// Not required, but could do more here, see RFC6763 s12
|
||||
if (qType==DNS_RRTYPE_PTR) {
|
||||
if (rsrcP->rNext && rsrcP->rNext->rType==DNS_RRTYPE_SRV)
|
||||
extra = rsrcP->rNext;
|
||||
} else if (qType==DNS_RRTYPE_SRV) {
|
||||
if (rsrcP->rNext && rsrcP->rNext->rType==DNS_RRTYPE_A)
|
||||
extra = rsrcP->rNext;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // for nQuestions
|
||||
|
||||
if (respLen > SIZEOF_DNS_HDR) {
|
||||
if (extra) {
|
||||
respLen = mdns_add_to_answer(extra, mdns_response, respLen);
|
||||
rHdr->numextrarr = htons( htons(rHdr->numextrarr) + 1 );
|
||||
}
|
||||
mdns_send_mcast(mdns_response,respLen);
|
||||
}
|
||||
free(mdns_response);
|
||||
}
|
||||
|
||||
static void mdns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
|
||||
// Callback from udp_recv
|
||||
{
|
||||
UNUSED_ARG(pcb);
|
||||
UNUSED_ARG(port);
|
||||
|
||||
u8_t* mdns_payload;
|
||||
int plen;
|
||||
|
||||
// Sanity checks on size
|
||||
plen = p->tot_len;
|
||||
if (plen > DNS_MSG_SIZE) {
|
||||
printf(">>> mdns_recv: pbuf too big\n");
|
||||
} else if (plen < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + 1 + SIZEOF_DNS_ANSWER + 1)) {
|
||||
printf(">>> mdns_recv: pbuf too small\n");
|
||||
} else {
|
||||
#ifdef qLogIncoming
|
||||
printf("\n\nmDNS got %d bytes from %d.%d.%d.%d\n",plen, ip4_addr1(addr), ip4_addr2(addr), ip4_addr3(addr), ip4_addr4(addr));
|
||||
#endif
|
||||
mdns_payload = malloc(plen);
|
||||
if (!mdns_payload)
|
||||
printf(">>> mdns_recv, could not alloc %d\n",plen);
|
||||
else {
|
||||
if (pbuf_copy_partial(p, mdns_payload, plen, 0) == plen) {
|
||||
struct mdns_hdr* hdrP = (struct mdns_hdr*) mdns_payload;
|
||||
|
||||
#ifdef qLogAllTraffic
|
||||
mdns_print_msg(mdns_payload, plen);
|
||||
#endif
|
||||
|
||||
if ( (hdrP->flags1 & (DNS_FLAG1_RESP + DNS_FLAG1_OPMASK + DNS_FLAG1_TRUNC) ) == 0
|
||||
&& hdrP->numquestions > 0 )
|
||||
mdns_reply(hdrP);
|
||||
}
|
||||
free(mdns_payload);
|
||||
}
|
||||
}
|
||||
pbuf_free(p);
|
||||
}
|
||||
|
||||
static void mdns_start()
|
||||
// If we are in station mode and have an IP address, start a multicast UDP receive
|
||||
{
|
||||
struct ip_info ipInfo;
|
||||
err_t err;
|
||||
|
||||
if (sdk_wifi_get_opmode() != STATION_MODE) {
|
||||
printf(">>> mDNS_start: wifi opmode not station\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sdk_wifi_get_ip_info(STATION_IF,&ipInfo)) {
|
||||
printf(">>> mDNS_start: no IP addr\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mdns_update_ipaddr(&ipInfo);
|
||||
|
||||
// Start IGMP on the netif for our interface: this isn't done for us
|
||||
struct netif* nfp = netif_list;
|
||||
while (nfp!=NULL) {
|
||||
if ( ip_addr_cmp(&ipInfo.ip, &(nfp->ip_addr)) ) {
|
||||
if (!(nfp->flags & NETIF_FLAG_IGMP)) {
|
||||
nfp->flags |= NETIF_FLAG_IGMP;
|
||||
err = igmp_start(nfp);
|
||||
if (err != ERR_OK) {
|
||||
printf(">>> mDNS_start: igmp_start on %c%c failed %d\n",nfp->name[0], nfp->name[1],err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
nfp = nfp->next;
|
||||
}
|
||||
|
||||
gMDNS_pcb = udp_new();
|
||||
if (!gMDNS_pcb) {
|
||||
printf(">>> mDNS_start: udp_new failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((err=igmp_joingroup(&ipInfo.ip, &gMulticastAddr)) != ERR_OK) {
|
||||
printf(">>> mDNS_start: igmp_join failed %d\n",err);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((err=udp_bind(gMDNS_pcb, IP_ADDR_ANY, DNS_MDNS_PORT)) != ERR_OK) {
|
||||
printf(">>> mDNS_start: udp_bind failed %d\n",err);
|
||||
return;
|
||||
}
|
||||
|
||||
udp_recv(gMDNS_pcb, mdns_recv, NULL);
|
||||
}
|
||||
|
||||
static void mdns_close()
|
||||
{
|
||||
udp_remove(gMDNS_pcb);
|
||||
gMDNS_pcb = NULL;
|
||||
#ifdef qDebugLog
|
||||
printf("Closing mDNS\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void mdns_task(void *pvParameters)
|
||||
{
|
||||
uint8_t hasIP = 0;
|
||||
uint8_t status;
|
||||
UNUSED_ARG(pvParameters);
|
||||
|
||||
ipaddr_aton(DNS_MULTICAST_ADDRESS, &gMulticastAddr);
|
||||
// Wait until we have joined AP and are assigned an IP
|
||||
while (1) {
|
||||
status = (sdk_wifi_station_get_connect_status() == STATION_GOT_IP);
|
||||
if (status != hasIP) {
|
||||
if (status) mdns_start();
|
||||
else mdns_close();
|
||||
hasIP = status;
|
||||
}
|
||||
vTaskDelayMs(status ? 1000 : 100);
|
||||
}
|
||||
}
|
||||
|
||||
void mdns_init()
|
||||
{
|
||||
#if LWIP_IGMP
|
||||
xTaskCreate(mdns_task, "MDNS", kMDNSStackSize, NULL, 2, NULL);
|
||||
#else
|
||||
#error "LWIP_IGMP needs to be defined in lwipopts.h"
|
||||
#endif
|
||||
}
|
||||
52
extras/mdnsresponder/mdnsresponder.h
Normal file
52
extras/mdnsresponder/mdnsresponder.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
#ifndef __MDNSRESPONDER_H__
|
||||
#define __MDNSRESPONDER_H__
|
||||
|
||||
/*
|
||||
* Basic multicast DNS responder
|
||||
*
|
||||
* Advertises the IP address, port, and characteristics of a service to other devices using multicast DNS on the same LAN,
|
||||
* so they can find devices with addresses dynamically allocated by DHCP. See avahi, Bonjour, etc
|
||||
* See RFC6762, RFC6763
|
||||
*
|
||||
* This sample code is in the public domain.
|
||||
*
|
||||
* by M J A Hamel 2016
|
||||
*/
|
||||
|
||||
|
||||
// Starts the mDNS responder task, call first
|
||||
void mdns_init();
|
||||
|
||||
// Build and advertise an appropriate linked set of PTR/TXT/SRV/A records for the parameters provided
|
||||
// This is a simple canned way to build a set of records for a single service that will
|
||||
// be advertised whenever the device is given an IP address by WiFi
|
||||
|
||||
typedef enum {
|
||||
mdns_TCP,
|
||||
mdns_UDP,
|
||||
mdns_Browsable // see RFC6763:11 - adds a standard record that lets browsers find the service without needing to know its name
|
||||
} mdns_flags;
|
||||
|
||||
void mdns_add_facility( const char* instanceName, // Short user-friendly instance name, should NOT include serial number/MAC/etc
|
||||
const char* serviceName, // Must be registered, _name, (see RFC6335 5.1 & 5.2)
|
||||
const char* addText, // Should be <key>=<value>, or "" if unused (see RFC6763 6.3)
|
||||
mdns_flags flags, // TCP or UDP plus browsable
|
||||
u16_t onPort, // port number
|
||||
u32_t ttl // time-to-live, seconds
|
||||
);
|
||||
|
||||
|
||||
// Low-level RR builders for rolling your own
|
||||
void mdns_add_PTR(const char* rKey, u32_t ttl, const char* nameStr);
|
||||
void mdns_add_SRV(const char* rKey, u32_t ttl, u16_t rPort, const char* targname);
|
||||
void mdns_add_TXT(const char* rKey, u32_t ttl, const char* txtStr);
|
||||
void mdns_add_A (const char* rKey, u32_t ttl, struct ip_addr addr);
|
||||
|
||||
/* Sample usage, advertising a secure web service
|
||||
|
||||
mdns_init();
|
||||
mdns_add_facility("Fluffy", "_https", "Zoom=1", mdns_TCP+mdns_Browsable, 443, 600);
|
||||
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
|
@ -8,7 +8,6 @@
|
|||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#include "ms561101ba03.h"
|
||||
#include <i2c/i2c.h>
|
||||
#include <espressif/esp_common.h>
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
|
@ -26,60 +25,67 @@
|
|||
*/
|
||||
#define CONVERSION_TIME 20 / portTICK_PERIOD_MS // milliseconds
|
||||
|
||||
static inline bool reset(uint8_t addr)
|
||||
static inline int reset(i2c_dev_t* i2c_dev)
|
||||
{
|
||||
uint8_t buf[1] = { RESET };
|
||||
return i2c_slave_write(addr, buf, 1);
|
||||
return i2c_slave_write(i2c_dev->bus, i2c_dev->addr, NULL, buf, 1);
|
||||
}
|
||||
|
||||
static inline bool read_prom(ms561101ba03_t *dev)
|
||||
{
|
||||
uint8_t tmp[2] = { 0, 0 };
|
||||
uint8_t reg = 0xA2 ;
|
||||
|
||||
if (!i2c_slave_read(dev->addr, 0xA2, tmp, 2))
|
||||
if (i2c_slave_read(dev->i2c_dev.bus, dev->i2c_dev.addr, ®, tmp, 2))
|
||||
return false;
|
||||
dev->config_data.sens = tmp[0] << 8 | tmp[1];
|
||||
|
||||
if (!i2c_slave_read(dev->addr, 0xA4, tmp, 2))
|
||||
reg = 0xA4 ;
|
||||
if (i2c_slave_read(dev->i2c_dev.bus, dev->i2c_dev.addr, ®, tmp, 2))
|
||||
return false;
|
||||
dev->config_data.off = tmp[0] << 8 | tmp[1];
|
||||
|
||||
if (!i2c_slave_read(dev->addr, 0xA6, tmp, 2))
|
||||
reg = 0xA6 ;
|
||||
if (i2c_slave_read(dev->i2c_dev.bus, dev->i2c_dev.addr, ®, tmp, 2))
|
||||
return false;
|
||||
dev->config_data.tcs = tmp[0] << 8 | tmp[1];
|
||||
|
||||
if (!i2c_slave_read(dev->addr, 0xA8, tmp, 2))
|
||||
reg = 0xA8 ;
|
||||
if (i2c_slave_read(dev->i2c_dev.bus, dev->i2c_dev.addr, ®, tmp, 2))
|
||||
return false;
|
||||
dev->config_data.tco = tmp[0] << 8 | tmp[1];
|
||||
|
||||
if (!i2c_slave_read(dev->addr, 0xAA, tmp, 2))
|
||||
reg = 0xAA ;
|
||||
if (i2c_slave_read(dev->i2c_dev.bus, dev->i2c_dev.addr, ®, tmp, 2))
|
||||
return false;
|
||||
dev->config_data.t_ref = tmp[0] << 8 | tmp[1];
|
||||
|
||||
if (!i2c_slave_read(dev->addr, 0xAC, tmp, 2))
|
||||
reg = 0xAC ;
|
||||
if (i2c_slave_read(dev->i2c_dev.bus, dev->i2c_dev.addr, ®, tmp, 2))
|
||||
return false;
|
||||
dev->config_data.tempsens = tmp[0] << 8 | tmp[1];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool start_pressure_conversion(ms561101ba03_t *dev) //D1
|
||||
static inline int start_pressure_conversion(ms561101ba03_t *dev) //D1
|
||||
{
|
||||
uint8_t buf = CONVERT_D1 + dev->osr;
|
||||
return i2c_slave_write(dev->addr, &buf, 1);
|
||||
return i2c_slave_write(dev->i2c_dev.bus, dev->i2c_dev.addr, NULL, &buf, 1);
|
||||
}
|
||||
|
||||
static inline bool start_temperature_conversion(ms561101ba03_t *dev) //D2
|
||||
static inline int start_temperature_conversion(ms561101ba03_t *dev) //D2
|
||||
{
|
||||
uint8_t buf = CONVERT_D2 + dev->osr;
|
||||
return i2c_slave_write(dev->addr, &buf, 1);
|
||||
return i2c_slave_write(dev->i2c_dev.bus, dev->i2c_dev.addr, NULL, &buf, 1);
|
||||
}
|
||||
|
||||
static inline bool read_adc(uint8_t addr, uint32_t *result)
|
||||
static inline bool read_adc(i2c_dev_t* i2c_dev, uint32_t *result)
|
||||
{
|
||||
*result = 0;
|
||||
uint8_t tmp[3];
|
||||
if (!i2c_slave_read(addr, 0x00, tmp, 3))
|
||||
uint8_t reg = 0x00 ;
|
||||
if (i2c_slave_read(i2c_dev->bus, i2c_dev->addr, ®, tmp, 3))
|
||||
return false;
|
||||
|
||||
*result = (tmp[0] << 16) | (tmp[1] << 8) | tmp[2];
|
||||
|
|
@ -132,12 +138,12 @@ static inline int32_t calc_p(uint32_t digital_pressure, int64_t sens, int64_t of
|
|||
|
||||
static inline bool get_raw_temperature(ms561101ba03_t *dev, uint32_t *result)
|
||||
{
|
||||
if (!start_temperature_conversion(dev))
|
||||
if (start_temperature_conversion(dev))
|
||||
return false;
|
||||
|
||||
vTaskDelay(CONVERSION_TIME);
|
||||
|
||||
if (!read_adc(dev->addr, result))
|
||||
if (!read_adc(&dev->i2c_dev, result))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
|
@ -145,12 +151,12 @@ static inline bool get_raw_temperature(ms561101ba03_t *dev, uint32_t *result)
|
|||
|
||||
static inline bool get_raw_pressure(ms561101ba03_t *dev, uint32_t *result)
|
||||
{
|
||||
if (!start_pressure_conversion(dev))
|
||||
if (start_pressure_conversion(dev))
|
||||
return false;
|
||||
|
||||
vTaskDelay(CONVERSION_TIME);
|
||||
|
||||
if (!read_adc(dev->addr, result))
|
||||
if (!read_adc(&dev->i2c_dev, result))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
|
@ -209,7 +215,7 @@ bool ms561101ba03_get_sensor_data(ms561101ba03_t *dev)
|
|||
bool ms561101ba03_init(ms561101ba03_t *dev)
|
||||
{
|
||||
// First of all we need to reset the chip
|
||||
if (!reset(dev->addr))
|
||||
if (reset(&dev->i2c_dev))
|
||||
return false;
|
||||
// Wait a bit for the device to reset
|
||||
vTaskDelay(CONVERSION_TIME);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <i2c/i2c.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
|
|
@ -60,7 +61,7 @@ typedef struct
|
|||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t addr; //!< I2C address
|
||||
i2c_dev_t i2c_dev; //!< I2C device settings
|
||||
ms561101ba03_osr_t osr; //!< Oversampling setting
|
||||
ms561101ba03_config_data_t config_data; //!< Device configuration, filled upon initalize
|
||||
ms561101ba03_result_t result; //!< Result, filled upon co
|
||||
|
|
|
|||
|
|
@ -424,6 +424,8 @@ int mqtt_subscribe(mqtt_client_t* c, const char* topic, enum mqtt_qos qos, mqtt
|
|||
if (rc != 0x80)
|
||||
{
|
||||
int i;
|
||||
|
||||
rc = MQTT_FAILURE;
|
||||
for (i = 0; i < MQTT_MAX_MESSAGE_HANDLERS; ++i)
|
||||
{
|
||||
if (c->messageHandlers[i].topicFilter == 0)
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ char mqtt_timer_expired(mqtt_timer_t* timer)
|
|||
{
|
||||
TickType_t now = xTaskGetTickCount();
|
||||
int32_t left = timer->end_time - now;
|
||||
return (left < 0);
|
||||
return (left <= 0);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ int mqtt_timer_left_ms(mqtt_timer_t* timer)
|
|||
{
|
||||
TickType_t now = xTaskGetTickCount();
|
||||
int32_t left = timer->end_time - now;
|
||||
return (left < 0) ? 0 : left / portTICK_PERIOD_MS;
|
||||
return (left < 0) ? 0 : left * portTICK_PERIOD_MS;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -72,9 +72,8 @@ int mqtt_esp_read(mqtt_network_t* n, unsigned char* buffer, int len, int timeou
|
|||
int rcvd = 0;
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(n->my_socket, &fdset);
|
||||
// It seems tv_sec actually means FreeRTOS tick
|
||||
tv.tv_sec = timeout_ms / portTICK_PERIOD_MS;
|
||||
tv.tv_usec = 0;
|
||||
tv.tv_sec = timeout_ms / 1000;
|
||||
tv.tv_usec = (timeout_ms % 1000) * 1000;
|
||||
rc = select(n->my_socket + 1, &fdset, 0, 0, &tv);
|
||||
if ((rc > 0) && (FD_ISSET(n->my_socket, &fdset)))
|
||||
{
|
||||
|
|
@ -97,9 +96,8 @@ int mqtt_esp_write(mqtt_network_t* n, unsigned char* buffer, int len, int timeo
|
|||
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(n->my_socket, &fdset);
|
||||
// It seems tv_sec actually means FreeRTOS tick
|
||||
tv.tv_sec = timeout_ms / portTICK_PERIOD_MS;
|
||||
tv.tv_usec = 0;
|
||||
tv.tv_sec = timeout_ms / 1000;
|
||||
tv.tv_usec = (timeout_ms % 1000) * 1000;
|
||||
rc = select(n->my_socket + 1, 0, &fdset, 0, &tv);
|
||||
if ((rc > 0) && (FD_ISSET(n->my_socket, &fdset)))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
*/
|
||||
#include "pca9685.h"
|
||||
|
||||
#include <i2c/i2c.h>
|
||||
#include <espressif/esp_common.h>
|
||||
|
||||
#define REG_MODE1 0x00
|
||||
|
|
@ -59,33 +58,32 @@ inline static uint32_t round_div(uint32_t x, uint32_t y)
|
|||
return (x + y / 2) / y;
|
||||
}
|
||||
|
||||
inline static void write_reg(uint8_t addr, uint8_t reg, uint8_t val)
|
||||
inline static void write_reg(i2c_dev_t* dev, uint8_t reg, uint8_t val)
|
||||
{
|
||||
uint8_t data[2] = { reg, val };
|
||||
if (!i2c_slave_write(addr, data, 2))
|
||||
debug("Could not write 0x%02x to 0x%02x, addr = 0x%02x", reg, val, addr);
|
||||
if (i2c_slave_write(dev->bus, dev->addr, ®, &val, 1))
|
||||
debug("Could not write 0x%02x to 0x%02x, bus %u, addr = 0x%02x", reg, val, dev->bus, dev->addr);
|
||||
}
|
||||
|
||||
inline static uint8_t read_reg(uint8_t addr, uint8_t reg)
|
||||
inline static uint8_t read_reg(i2c_dev_t* dev, uint8_t reg)
|
||||
{
|
||||
uint8_t res = 0;
|
||||
if (!i2c_slave_read(addr, reg, &res, 1))
|
||||
debug("Could not read from 0x%02x, addr = 0x%02x", reg, addr);
|
||||
if (i2c_slave_read(dev->bus, dev->addr, ®, &res, 1))
|
||||
debug("Could not read from 0x%02x, bus %u, addr = 0x%02x", reg, dev->bus, dev->addr);
|
||||
return res;
|
||||
}
|
||||
|
||||
inline static void update_reg(uint8_t addr, uint8_t reg, uint8_t mask, uint8_t val)
|
||||
inline static void update_reg(i2c_dev_t* dev, uint8_t reg, uint8_t mask, uint8_t val)
|
||||
{
|
||||
write_reg(addr, reg, (read_reg(addr, reg) & ~mask) | val);
|
||||
write_reg(dev, reg, (read_reg(dev, reg) & ~mask) | val);
|
||||
}
|
||||
|
||||
void pca9685_init(uint8_t addr)
|
||||
void pca9685_init(i2c_dev_t* dev)
|
||||
{
|
||||
// Enable autoincrement
|
||||
update_reg(addr, REG_MODE1, MODE1_AI, MODE1_AI);
|
||||
update_reg(dev, REG_MODE1, MODE1_AI, MODE1_AI);
|
||||
}
|
||||
|
||||
bool pca9685_set_subaddr(uint8_t addr, uint8_t num, uint8_t subaddr, bool enable)
|
||||
bool pca9685_set_subaddr(i2c_dev_t* dev, uint8_t num, uint8_t subaddr, bool enable)
|
||||
{
|
||||
if (num > MAX_SUBADDR)
|
||||
{
|
||||
|
|
@ -93,63 +91,63 @@ bool pca9685_set_subaddr(uint8_t addr, uint8_t num, uint8_t subaddr, bool enable
|
|||
return false;
|
||||
}
|
||||
|
||||
write_reg(addr, REG_SUBADR1 + num, subaddr << 1);
|
||||
write_reg(dev, REG_SUBADR1 + num, subaddr << 1);
|
||||
|
||||
uint8_t mask = 1 << (MODE1_SUB_BIT - num);
|
||||
update_reg(addr, REG_MODE1, mask, enable ? mask : 0);
|
||||
update_reg(dev, REG_MODE1, mask, enable ? mask : 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pca9685_is_sleeping(uint8_t addr)
|
||||
bool pca9685_is_sleeping(i2c_dev_t* dev)
|
||||
{
|
||||
return (read_reg(addr, REG_MODE1) & MODE1_SLEEP) != 0;
|
||||
return (read_reg(dev, REG_MODE1) & MODE1_SLEEP) != 0;
|
||||
}
|
||||
|
||||
void pca9685_sleep(uint8_t addr, bool sleep)
|
||||
void pca9685_sleep(i2c_dev_t* dev, bool sleep)
|
||||
{
|
||||
update_reg(addr, REG_MODE1, MODE1_SLEEP, sleep ? MODE1_SLEEP : 0);
|
||||
update_reg(dev, REG_MODE1, MODE1_SLEEP, sleep ? MODE1_SLEEP : 0);
|
||||
if (!sleep)
|
||||
sdk_os_delay_us(WAKEUP_DELAY_US);
|
||||
}
|
||||
|
||||
void pca9685_restart(uint8_t addr)
|
||||
void pca9685_restart(i2c_dev_t* dev)
|
||||
{
|
||||
uint8_t mode = read_reg(addr, REG_MODE1);
|
||||
uint8_t mode = read_reg(dev, REG_MODE1);
|
||||
if (mode & MODE1_RESTART)
|
||||
{
|
||||
write_reg(addr, REG_MODE1, mode & ~MODE1_SLEEP);
|
||||
write_reg(dev, REG_MODE1, mode & ~MODE1_SLEEP);
|
||||
sdk_os_delay_us(WAKEUP_DELAY_US);
|
||||
}
|
||||
write_reg(addr, REG_MODE1, (mode & ~MODE1_SLEEP) | MODE1_RESTART);
|
||||
write_reg(dev, REG_MODE1, (mode & ~MODE1_SLEEP) | MODE1_RESTART);
|
||||
}
|
||||
|
||||
bool pca9685_is_output_inverted(uint8_t addr)
|
||||
bool pca9685_is_output_inverted(i2c_dev_t* dev)
|
||||
{
|
||||
return (read_reg(addr, REG_MODE2) & MODE2_INVRT) != 0;
|
||||
return (read_reg(dev, REG_MODE2) & MODE2_INVRT) != 0;
|
||||
}
|
||||
|
||||
void pca9685_set_output_inverted(uint8_t addr, bool inverted)
|
||||
void pca9685_set_output_inverted(i2c_dev_t* dev, bool inverted)
|
||||
{
|
||||
update_reg(addr, REG_MODE2, MODE2_INVRT, inverted ? MODE2_INVRT : 0);
|
||||
update_reg(dev, REG_MODE2, MODE2_INVRT, inverted ? MODE2_INVRT : 0);
|
||||
}
|
||||
|
||||
bool pca9685_get_output_open_drain(uint8_t addr)
|
||||
bool pca9685_get_output_open_drain(i2c_dev_t* dev)
|
||||
{
|
||||
return (read_reg(addr, REG_MODE2) & MODE2_OUTDRV) == 0;
|
||||
return (read_reg(dev, REG_MODE2) & MODE2_OUTDRV) == 0;
|
||||
}
|
||||
|
||||
void pca9685_set_output_open_drain(uint8_t addr, bool open_drain)
|
||||
void pca9685_set_output_open_drain(i2c_dev_t* dev, bool open_drain)
|
||||
{
|
||||
update_reg(addr, REG_MODE2, MODE2_OUTDRV, open_drain ? 0 : MODE2_OUTDRV);
|
||||
update_reg(dev, REG_MODE2, MODE2_OUTDRV, open_drain ? 0 : MODE2_OUTDRV);
|
||||
}
|
||||
|
||||
uint8_t pca9685_get_prescaler(uint8_t addr)
|
||||
uint8_t pca9685_get_prescaler(i2c_dev_t* dev)
|
||||
{
|
||||
return read_reg(addr, REG_PRE_SCALE);
|
||||
return read_reg(dev, REG_PRE_SCALE);
|
||||
}
|
||||
|
||||
bool pca9685_set_prescaler(uint8_t addr, uint8_t prescaler)
|
||||
bool pca9685_set_prescaler(i2c_dev_t* dev, uint8_t prescaler)
|
||||
{
|
||||
if (prescaler < MIN_PRESCALER)
|
||||
{
|
||||
|
|
@ -157,18 +155,18 @@ bool pca9685_set_prescaler(uint8_t addr, uint8_t prescaler)
|
|||
return false;
|
||||
}
|
||||
|
||||
pca9685_sleep(addr, true);
|
||||
write_reg(addr, REG_PRE_SCALE, prescaler);
|
||||
pca9685_sleep(addr, false);
|
||||
pca9685_sleep(dev, true);
|
||||
write_reg(dev, REG_PRE_SCALE, prescaler);
|
||||
pca9685_sleep(dev, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t pca9685_get_pwm_frequency(uint8_t addr)
|
||||
uint16_t pca9685_get_pwm_frequency(i2c_dev_t* dev)
|
||||
{
|
||||
return INTERNAL_FREQ / ((uint32_t)4096 * (read_reg(addr, REG_PRE_SCALE) + 1));
|
||||
return INTERNAL_FREQ / ((uint32_t)4096 * (read_reg(dev, REG_PRE_SCALE) + 1));
|
||||
}
|
||||
|
||||
bool pca9685_set_pwm_frequency(uint8_t addr, uint16_t freq)
|
||||
bool pca9685_set_pwm_frequency(i2c_dev_t* dev, uint16_t freq)
|
||||
{
|
||||
uint16_t prescaler = round_div(INTERNAL_FREQ, (uint32_t)4096 * freq) - 1;
|
||||
if (prescaler < MIN_PRESCALER || prescaler > MAX_PRESCALER)
|
||||
|
|
@ -177,32 +175,32 @@ bool pca9685_set_pwm_frequency(uint8_t addr, uint16_t freq)
|
|||
return false;
|
||||
}
|
||||
|
||||
return pca9685_set_prescaler(addr, prescaler);
|
||||
return pca9685_set_prescaler(dev, prescaler);
|
||||
}
|
||||
|
||||
void pca9685_set_pwm_value(uint8_t addr, uint8_t channel, uint16_t val)
|
||||
void pca9685_set_pwm_value(i2c_dev_t* dev, uint8_t channel, uint16_t val)
|
||||
{
|
||||
uint8_t reg = channel > MAX_CHANNEL ? REG_ALL_LED : REG_LED_N(channel);
|
||||
|
||||
if (val == 0)
|
||||
{
|
||||
// Full off
|
||||
write_reg(addr, reg + OFFS_REG_LED_OFF, LED_FULL_ON_OFF);
|
||||
write_reg(dev, reg + OFFS_REG_LED_OFF, LED_FULL_ON_OFF);
|
||||
}
|
||||
else if (val < 4096)
|
||||
{
|
||||
// Normal
|
||||
uint8_t buf[5] = { reg, 0, 0, val, val >> 8 };
|
||||
i2c_slave_write(addr, buf, 5);
|
||||
uint8_t buf[4] = { 0, 0, val, val >> 8 };
|
||||
i2c_slave_write(dev->bus, dev->addr, ®, buf, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Full on
|
||||
write_reg(addr, reg + OFFS_REG_LED_ON, LED_FULL_ON_OFF);
|
||||
write_reg(dev, reg + OFFS_REG_LED_ON, LED_FULL_ON_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
bool pca9685_set_pwm_values(uint8_t addr, uint8_t first_ch, uint8_t channels, const uint16_t *values)
|
||||
bool pca9685_set_pwm_values(i2c_dev_t* dev, uint8_t first_ch, uint8_t channels, const uint16_t *values)
|
||||
{
|
||||
if (channels == 0 || first_ch + channels - 1 > MAX_CHANNEL)
|
||||
{
|
||||
|
|
@ -211,7 +209,7 @@ bool pca9685_set_pwm_values(uint8_t addr, uint8_t first_ch, uint8_t channels, co
|
|||
}
|
||||
|
||||
for (uint8_t i = 0; i < channels; i ++)
|
||||
pca9685_set_pwm_value(addr, first_ch + i, values [i]);
|
||||
pca9685_set_pwm_value(dev, first_ch + i, values [i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <i2c/i2c.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
|
|
@ -22,7 +23,7 @@ extern "C"
|
|||
* Init device
|
||||
* @param addr Device address
|
||||
*/
|
||||
void pca9685_init(uint8_t addr);
|
||||
void pca9685_init(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* Setup device subaddress (see section 7.3.6 if the datasheet)
|
||||
|
|
@ -32,62 +33,62 @@ void pca9685_init(uint8_t addr);
|
|||
* @param enable True to enable subaddress, false to disable
|
||||
* @return False if error occured
|
||||
*/
|
||||
bool pca9685_set_subaddr(uint8_t addr, uint8_t num, uint8_t subaddr, bool enable);
|
||||
bool pca9685_set_subaddr(i2c_dev_t* dev, uint8_t num, uint8_t subaddr, bool enable);
|
||||
|
||||
/**
|
||||
* Restart device (see section 7.3.1.1 of the datasheet)
|
||||
* @param addr Device address
|
||||
*/
|
||||
void pca9685_restart(uint8_t addr);
|
||||
void pca9685_restart(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* Check if device is in sleep mode
|
||||
* @param addr Device address
|
||||
* @return True if device is sleeping
|
||||
*/
|
||||
bool pca9685_is_sleeping(uint8_t addr);
|
||||
bool pca9685_is_sleeping(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* Switch device to low-power mode or wake it up.
|
||||
* @param addr Device address
|
||||
* @param sleep True for sleep mode, false for wake up
|
||||
*/
|
||||
void pca9685_sleep(uint8_t addr, bool sleep);
|
||||
void pca9685_sleep(i2c_dev_t* dev, bool sleep);
|
||||
|
||||
/**
|
||||
* Get logic inversion of the outputs
|
||||
* @param addr Device address
|
||||
* @return True if outputs are inverted, false otherwise
|
||||
*/
|
||||
bool pca9685_is_output_inverted(uint8_t addr);
|
||||
bool pca9685_is_output_inverted(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* Logically invert outputs (see section 7.7 of the datasheet)
|
||||
* @param addr Device address
|
||||
* @param inverted True for inverted outputs
|
||||
*/
|
||||
void pca9685_set_output_inverted(uint8_t addr, bool inverted);
|
||||
void pca9685_set_output_inverted(i2c_dev_t* dev, bool inverted);
|
||||
|
||||
/**
|
||||
* Get outputs mode
|
||||
* @param addr Device address
|
||||
* @return True if outputs are in open drain mode
|
||||
*/
|
||||
bool pca9685_get_output_open_drain(uint8_t addr);
|
||||
bool pca9685_get_output_open_drain(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* Set outputs mode
|
||||
* @param addr Device address
|
||||
* @param open_drain True to set open drain mode, false to normal mode
|
||||
*/
|
||||
void pca9685_set_output_open_drain(uint8_t addr, bool open_drain);
|
||||
void pca9685_set_output_open_drain(i2c_dev_t* dev, bool open_drain);
|
||||
|
||||
/**
|
||||
* Get current PWM frequency prescaler.
|
||||
* @param addr Device address
|
||||
* @return Frequency prescaler
|
||||
*/
|
||||
uint8_t pca9685_get_prescaler(uint8_t addr);
|
||||
uint8_t pca9685_get_prescaler(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* Set PWM frequency prescaler.
|
||||
|
|
@ -95,14 +96,14 @@ uint8_t pca9685_get_prescaler(uint8_t addr);
|
|||
* @param prescaler Prescaler value
|
||||
* @return False if error occured
|
||||
*/
|
||||
bool pca9685_set_prescaler(uint8_t addr, uint8_t prescaler);
|
||||
bool pca9685_set_prescaler(i2c_dev_t* dev, uint8_t prescaler);
|
||||
|
||||
/**
|
||||
* Get current PWM frequency
|
||||
* @param addr Device address
|
||||
* @return PWM frequency, Hz
|
||||
*/
|
||||
uint16_t pca9685_get_pwm_frequency(uint8_t addr);
|
||||
uint16_t pca9685_get_pwm_frequency(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* Set PWM frequency
|
||||
|
|
@ -110,7 +111,7 @@ uint16_t pca9685_get_pwm_frequency(uint8_t addr);
|
|||
* @param freq PWM frequency, Hz
|
||||
* @return False if error occured
|
||||
*/
|
||||
bool pca9685_set_pwm_frequency(uint8_t addr, uint16_t freq);
|
||||
bool pca9685_set_pwm_frequency(i2c_dev_t* dev, uint16_t freq);
|
||||
|
||||
/**
|
||||
* Set PWM value on output channel
|
||||
|
|
@ -118,7 +119,7 @@ bool pca9685_set_pwm_frequency(uint8_t addr, uint16_t freq);
|
|||
* @param channel Channel number, 0..15 or >15 for all channels
|
||||
* @param val PWM value, 0..4096
|
||||
*/
|
||||
void pca9685_set_pwm_value(uint8_t addr, uint8_t channel, uint16_t val);
|
||||
void pca9685_set_pwm_value(i2c_dev_t* dev, uint8_t channel, uint16_t val);
|
||||
|
||||
/**
|
||||
* Set PWM values on output channels
|
||||
|
|
@ -128,7 +129,7 @@ void pca9685_set_pwm_value(uint8_t addr, uint8_t channel, uint16_t val);
|
|||
* @param values Array of the channel values, each 0..4096
|
||||
* @return False if error occured
|
||||
*/
|
||||
bool pca9685_set_pwm_values(uint8_t addr, uint8_t first_ch, uint8_t channels, const uint16_t *values);
|
||||
bool pca9685_set_pwm_values(i2c_dev_t* dev, uint8_t first_ch, uint8_t channels, const uint16_t *values);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,54 +1,46 @@
|
|||
#include "pcf8574.h"
|
||||
#include <i2c/i2c.h>
|
||||
|
||||
uint8_t pcf8574_port_read(uint8_t addr)
|
||||
uint8_t pcf8574_port_read(i2c_dev_t* dev)
|
||||
{
|
||||
i2c_start();
|
||||
uint8_t res = i2c_write((addr << 1) | 1) ? i2c_read(1) : 0;
|
||||
i2c_stop();
|
||||
uint8_t res;
|
||||
if (i2c_slave_read(dev->bus, dev->addr, NULL, &res, 1))
|
||||
return 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t pcf8574_port_read_buf(uint8_t addr, void *buf, size_t len)
|
||||
size_t pcf8574_port_read_buf(i2c_dev_t* dev, void *buf, size_t len)
|
||||
{
|
||||
if (!len || !buf) return 0;
|
||||
uint8_t *_buf = (uint8_t *)buf;
|
||||
|
||||
i2c_start();
|
||||
if (!i2c_write((addr << 1) | 1)) return 0;
|
||||
for (size_t i = 0; i < len; i++)
|
||||
*_buf++ = i2c_read(i == len - 1);
|
||||
i2c_stop();
|
||||
if (i2c_slave_read(dev->bus, dev->addr, NULL, _buf, len))
|
||||
return 0;
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t pcf8574_port_write_buf(uint8_t addr, void *buf, size_t len)
|
||||
size_t pcf8574_port_write_buf(const i2c_dev_t* dev, void *buf, size_t len)
|
||||
{
|
||||
if (!len || !buf) return 0;
|
||||
uint8_t *_buf = (uint8_t *)buf;
|
||||
|
||||
i2c_start();
|
||||
if (!i2c_write(addr << 1)) return 0;
|
||||
for (size_t i = 0; i < len; i++)
|
||||
i2c_write(*_buf++);
|
||||
if (i2c_slave_write(dev->bus, dev->addr, NULL, _buf, len))
|
||||
return 0;
|
||||
return len;
|
||||
}
|
||||
|
||||
void pcf8574_port_write(uint8_t addr, uint8_t value)
|
||||
void pcf8574_port_write(const i2c_dev_t* dev, uint8_t value)
|
||||
{
|
||||
i2c_start();
|
||||
if (i2c_write(addr << 1)) i2c_write(value);
|
||||
i2c_stop();
|
||||
i2c_slave_write(dev->bus, dev->addr, NULL, &value, 1);
|
||||
}
|
||||
|
||||
bool pcf8574_gpio_read(uint8_t addr, uint8_t num)
|
||||
bool pcf8574_gpio_read(i2c_dev_t* dev, uint8_t num)
|
||||
{
|
||||
return (bool)((pcf8574_port_read(addr) >> num) & 1);
|
||||
return (bool)((pcf8574_port_read(dev) >> num) & 1);
|
||||
}
|
||||
|
||||
void pcf8574_gpio_write(uint8_t addr, uint8_t num, bool value)
|
||||
void pcf8574_gpio_write(i2c_dev_t* dev, uint8_t num, bool value)
|
||||
{
|
||||
uint8_t bit = (uint8_t)value << num;
|
||||
uint8_t mask = ~(1 << num);
|
||||
pcf8574_port_write (addr, (pcf8574_port_read(addr) & mask) | bit);
|
||||
pcf8574_port_write (dev, (pcf8574_port_read(dev) & mask) | bit);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <i2c/i2c.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
|
|
@ -19,7 +20,7 @@ extern "C"
|
|||
* \param addr I2C register address (0b0100<A2><A1><A0> for PCF8574)
|
||||
* \return 8-bit GPIO port value
|
||||
*/
|
||||
uint8_t pcf8574_port_read(uint8_t addr);
|
||||
uint8_t pcf8574_port_read(i2c_dev_t* dev);
|
||||
|
||||
/**
|
||||
* \brief Continiously read GPIO port values to buffer
|
||||
|
|
@ -28,14 +29,14 @@ uint8_t pcf8574_port_read(uint8_t addr);
|
|||
* @param len Buffer length
|
||||
* @return Number of bytes read
|
||||
*/
|
||||
size_t pcf8574_port_read_buf(uint8_t addr, void *buf, size_t len);
|
||||
size_t pcf8574_port_read_buf(i2c_dev_t* dev, void *buf, size_t len);
|
||||
|
||||
/**
|
||||
* \brief Write value to GPIO port
|
||||
* \param addr I2C register address (0b0100<A2><A1><A0> for PCF8574)
|
||||
* \param value GPIO port value
|
||||
*/
|
||||
void pcf8574_port_write(uint8_t addr, uint8_t value);
|
||||
void pcf8574_port_write(const i2c_dev_t* dev, uint8_t value);
|
||||
|
||||
/**
|
||||
* \brief Continiously write GPIO values to GPIO port
|
||||
|
|
@ -44,7 +45,7 @@ void pcf8574_port_write(uint8_t addr, uint8_t value);
|
|||
* @param len Buffer length
|
||||
* @return Number of bytes written
|
||||
*/
|
||||
size_t pcf8574_port_write_buf(uint8_t addr, void *buf, size_t len);
|
||||
size_t pcf8574_port_write_buf(const i2c_dev_t* dev, void *buf, size_t len);
|
||||
|
||||
/**
|
||||
* \brief Read input value of a GPIO pin
|
||||
|
|
@ -52,7 +53,7 @@ size_t pcf8574_port_write_buf(uint8_t addr, void *buf, size_t len);
|
|||
* \param num pin number (0..7)
|
||||
* \return GPIO pin value
|
||||
*/
|
||||
bool pcf8574_gpio_read(uint8_t addr, uint8_t num);
|
||||
bool pcf8574_gpio_read(i2c_dev_t* dev, uint8_t num);
|
||||
|
||||
/**
|
||||
* \brief Set GPIO pin output
|
||||
|
|
@ -62,7 +63,7 @@ bool pcf8574_gpio_read(uint8_t addr, uint8_t num);
|
|||
* \param num pin number (0..7)
|
||||
* \param value true for high level
|
||||
*/
|
||||
void pcf8574_gpio_write(uint8_t addr, uint8_t num, bool value);
|
||||
void pcf8574_gpio_write(i2c_dev_t* dev, uint8_t num, bool value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
6
extras/pcf8591/component.mk
Normal file
6
extras/pcf8591/component.mk
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# Component makefile for extras/pcf8591
|
||||
|
||||
INC_DIRS += $(pcf8591_ROOT)..
|
||||
pcf8591_SRC_DIR = $(pcf8591_ROOT)
|
||||
|
||||
$(eval $(call component_compile_rules,pcf8591))
|
||||
20
extras/pcf8591/pcf8591.c
Normal file
20
extras/pcf8591/pcf8591.c
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "pcf8591.h"
|
||||
|
||||
/**
|
||||
* CAUTION: PLEASE SET LOW FREQUENCY
|
||||
*/
|
||||
|
||||
#define PCF8591_CTRL_REG_READ 0x03
|
||||
|
||||
uint8_t pcf8591_read(i2c_dev_t* dev, uint8_t analog_pin)
|
||||
{
|
||||
uint8_t res = 0;
|
||||
uint8_t control_reg = PCF8591_CTRL_REG_READ & analog_pin;
|
||||
|
||||
i2c_slave_read(dev->bus, dev->addr, &control_reg, &res, 1);
|
||||
|
||||
return res;
|
||||
}
|
||||
44
extras/pcf8591/pcf8591.h
Normal file
44
extras/pcf8591/pcf8591.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Driver for 8-bit analog-to-digital conversion and
|
||||
* an 8-bit digital-to-analog conversion PCF8591
|
||||
*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2017 Pham Ngoc Thanh <pnt239@gmail.com>
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
#ifndef _EXTRAS_PCF8591_H_
|
||||
#define _EXTRAS_PCF8591_H_
|
||||
|
||||
#include <i2c/i2c.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* CAUTION: PLEASE SET I2C_FREQUENCY_400K IS 'false' IN 'i2c.h' FILE
|
||||
*/
|
||||
|
||||
#define PCF8591_DEFAULT_ADDRESS 0x48
|
||||
|
||||
void pcf8591_init(void); //FIXME : library incomplete ?
|
||||
|
||||
/**
|
||||
* Read input value of an analog pin.
|
||||
* @param[in] addr Pointer to device
|
||||
* @param[in] analog_pin pin number:
|
||||
* 0 - AIN0
|
||||
* 1 - AIN1
|
||||
* 2 - AIN2
|
||||
* 3 - AIN3
|
||||
* @return analog value
|
||||
*/
|
||||
uint8_t pcf8591_read(i2c_dev_t* dev, uint8_t analog_pin);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _EXTRAS_PCF8591_H_ */
|
||||
|
|
@ -29,7 +29,7 @@ typedef struct pwmInfoDefinition
|
|||
uint8_t running;
|
||||
|
||||
uint16_t freq;
|
||||
uint16_t dutyCicle;
|
||||
uint16_t dutyCycle;
|
||||
|
||||
/* private */
|
||||
uint32_t _maxLoad;
|
||||
|
|
@ -43,7 +43,7 @@ typedef struct pwmInfoDefinition
|
|||
|
||||
static PWMInfo pwmInfo;
|
||||
|
||||
static void frc1_interrupt_handler(void)
|
||||
static void frc1_interrupt_handler(void *arg)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
bool out = true;
|
||||
|
|
@ -66,7 +66,7 @@ static void frc1_interrupt_handler(void)
|
|||
pwmInfo._step = step;
|
||||
}
|
||||
|
||||
void pwm_init(uint8_t npins, uint8_t* pins)
|
||||
void pwm_init(uint8_t npins, const uint8_t* pins)
|
||||
{
|
||||
/* Assert number of pins is correct */
|
||||
if (npins > MAX_PWM_PINS)
|
||||
|
|
@ -97,7 +97,7 @@ void pwm_init(uint8_t npins, uint8_t* pins)
|
|||
pwm_stop();
|
||||
|
||||
/* set up ISRs */
|
||||
_xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler);
|
||||
_xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler, NULL);
|
||||
|
||||
/* Flag not running */
|
||||
pwmInfo.running = 0;
|
||||
|
|
@ -127,10 +127,10 @@ void pwm_set_duty(uint16_t duty)
|
|||
{
|
||||
bool output;
|
||||
|
||||
pwmInfo.dutyCicle = duty;
|
||||
pwmInfo.dutyCycle = duty;
|
||||
if (duty > 0 && duty < UINT16_MAX) {
|
||||
pwm_restart();
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
// 0% and 100% duty cycle are special cases: constant output.
|
||||
|
|
@ -139,7 +139,7 @@ void pwm_set_duty(uint16_t duty)
|
|||
output = (duty == UINT16_MAX);
|
||||
for (uint8_t i = 0; i < pwmInfo.usedPins; ++i)
|
||||
{
|
||||
gpio_write(pwmInfo.pins[i].pin, output);
|
||||
gpio_write(pwmInfo.pins[i].pin, output);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -154,7 +154,7 @@ void pwm_restart()
|
|||
|
||||
void pwm_start()
|
||||
{
|
||||
pwmInfo._onLoad = pwmInfo.dutyCicle * pwmInfo._maxLoad / UINT16_MAX;
|
||||
pwmInfo._onLoad = pwmInfo.dutyCycle * pwmInfo._maxLoad / UINT16_MAX;
|
||||
pwmInfo._offLoad = pwmInfo._maxLoad - pwmInfo._onLoad;
|
||||
pwmInfo._step = PERIOD_ON;
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
void pwm_init(uint8_t npins, uint8_t* pins);
|
||||
void pwm_init(uint8_t npins, const uint8_t* pins);
|
||||
void pwm_set_freq(uint16_t freq);
|
||||
void pwm_set_duty(uint16_t duty);
|
||||
|
||||
|
|
|
|||
|
|
@ -141,6 +141,8 @@ static uint16_t crc_ccitt(const uint8_t *data, size_t n)
|
|||
#define spi_skip_word() do { spi_read_byte(); spi_read_byte(); } while(0)
|
||||
#define spi_skip_dword() do { spi_read_byte(); spi_read_byte(); spi_read_byte(); spi_read_byte(); } while(0)
|
||||
|
||||
#define timeout_expired(start, len) ((uint32_t)(sdk_system_get_time() - (start)) >= (len))
|
||||
|
||||
inline static uint16_t spi_write_word(uint16_t word)
|
||||
{
|
||||
return (spi_transfer_8(BUS, word >> 8) << 8) | spi_transfer_8(BUS, word);
|
||||
|
|
@ -154,9 +156,10 @@ inline static void spi_read_bytes(uint8_t *dst, size_t size)
|
|||
|
||||
static bool wait()
|
||||
{
|
||||
uint32_t stop = sdk_system_get_time() + IO_TIMEOUT_US;
|
||||
|
||||
uint32_t start = sdk_system_get_time();
|
||||
while (spi_read_byte() != 0xff)
|
||||
if (sdk_system_get_time() >= stop)
|
||||
if (timeout_expired(start, IO_TIMEOUT_US))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -208,11 +211,11 @@ inline static sdio_error_t set_error(sdio_card_t *card, sdio_error_t err)
|
|||
|
||||
static sdio_error_t read_data(sdio_card_t *card, uint8_t *dst, size_t size)
|
||||
{
|
||||
uint32_t timeout = sdk_system_get_time() + IO_TIMEOUT_US;
|
||||
uint32_t start = sdk_system_get_time();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (sdk_system_get_time() >= timeout)
|
||||
if (timeout_expired(start, IO_TIMEOUT_US))
|
||||
return set_error(card, SDIO_ERR_TIMEOUT);
|
||||
|
||||
uint8_t b = spi_read_byte();
|
||||
|
|
@ -269,7 +272,7 @@ sdio_error_t sdio_init(sdio_card_t *card, uint8_t cs_pin, uint32_t high_freq_div
|
|||
spi_set_settings(BUS, &s);
|
||||
gpio_enable(card->cs_pin, GPIO_OUTPUT);
|
||||
|
||||
uint32_t timeout = sdk_system_get_time() + INIT_TIMEOUT_US;
|
||||
uint32_t start = sdk_system_get_time();
|
||||
|
||||
spi_cs_low(card);
|
||||
spi_cs_high(card);
|
||||
|
|
@ -279,7 +282,7 @@ sdio_error_t sdio_init(sdio_card_t *card, uint8_t cs_pin, uint32_t high_freq_div
|
|||
// Set card to the SPI idle mode
|
||||
while (command(card, CMD0, 0) != BV(R1_IDLE_STATE))
|
||||
{
|
||||
if (sdk_system_get_time() >= timeout)
|
||||
if (timeout_expired(start, INIT_TIMEOUT_US))
|
||||
return set_error(card, SDIO_ERR_TIMEOUT);
|
||||
}
|
||||
|
||||
|
|
@ -300,7 +303,7 @@ sdio_error_t sdio_init(sdio_card_t *card, uint8_t cs_pin, uint32_t high_freq_div
|
|||
break;
|
||||
}
|
||||
|
||||
if (sdk_system_get_time() >= timeout)
|
||||
if (timeout_expired(start, INIT_TIMEOUT_US))
|
||||
return set_error(card, SDIO_ERR_TIMEOUT);
|
||||
}
|
||||
|
||||
|
|
@ -311,13 +314,13 @@ sdio_error_t sdio_init(sdio_card_t *card, uint8_t cs_pin, uint32_t high_freq_div
|
|||
{
|
||||
card->type = SDIO_TYPE_MMC;
|
||||
while (command(card, CMD1, 0))
|
||||
if (sdk_system_get_time() >= timeout)
|
||||
if (timeout_expired(start, INIT_TIMEOUT_US))
|
||||
return set_error(card, SDIO_ERR_TIMEOUT);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (app_command(card, ACMD41, 0))
|
||||
if (sdk_system_get_time() >= timeout)
|
||||
if (timeout_expired(start, INIT_TIMEOUT_US))
|
||||
return set_error(card, SDIO_ERR_TIMEOUT);
|
||||
}
|
||||
|
||||
|
|
@ -328,7 +331,7 @@ sdio_error_t sdio_init(sdio_card_t *card, uint8_t cs_pin, uint32_t high_freq_div
|
|||
{
|
||||
// SD2 or SDHC
|
||||
while (app_command(card, ACMD41, BV(30)) != 0)
|
||||
if (sdk_system_get_time() >= timeout)
|
||||
if (timeout_expired(start, INIT_TIMEOUT_US))
|
||||
return set_error(card, SDIO_ERR_TIMEOUT);
|
||||
}
|
||||
// read OCR
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
|
||||
#include "sntp.h"
|
||||
|
||||
#include "lwip/timers.h"
|
||||
#include "lwip/timeouts.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
|
|
@ -136,12 +136,12 @@
|
|||
#define SNTP_STARTUP_DELAY 0
|
||||
#endif
|
||||
|
||||
/** SNTP receive timeout - in milliseconds
|
||||
/** SNTP receive timeout - in seconds
|
||||
* Also used as retry timeout - this shouldn't be too low.
|
||||
* Default is 3 seconds.
|
||||
*/
|
||||
#ifndef SNTP_RECV_TIMEOUT
|
||||
#define SNTP_RECV_TIMEOUT 3000
|
||||
#define SNTP_RECV_TIMEOUT 3
|
||||
#endif
|
||||
|
||||
/** SNTP update delay - in milliseconds
|
||||
|
|
@ -384,8 +384,8 @@ sntp_request(void *arg)
|
|||
/* bind to local address */
|
||||
if (lwip_bind(sock, (struct sockaddr *)&local, sizeof(local)) == 0) {
|
||||
/* set recv timeout */
|
||||
timeout = SNTP_RECV_TIMEOUT;
|
||||
lwip_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
|
||||
const struct timeval timeout = { SNTP_RECV_TIMEOUT, 0 };
|
||||
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
|
||||
/* prepare SNTP request */
|
||||
sntp_initialize_request(&sntpmsg);
|
||||
|
|
@ -511,7 +511,7 @@ sntp_try_next_server(void* arg)
|
|||
|
||||
/** UDP recv callback for the sntp pcb */
|
||||
static void
|
||||
sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
|
||||
sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
|
||||
{
|
||||
u8_t mode;
|
||||
u8_t stratum;
|
||||
|
|
@ -597,7 +597,7 @@ sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, ip_addr_t *addr, u16_t
|
|||
* @param server_addr resolved IP address of the SNTP server
|
||||
*/
|
||||
static void
|
||||
sntp_send_request(ip_addr_t *server_addr)
|
||||
sntp_send_request(const ip_addr_t *server_addr)
|
||||
{
|
||||
struct pbuf* p;
|
||||
p = pbuf_alloc(PBUF_TRANSPORT, SNTP_MSG_LEN, PBUF_RAM);
|
||||
|
|
@ -611,7 +611,7 @@ sntp_send_request(ip_addr_t *server_addr)
|
|||
pbuf_free(p);
|
||||
|
||||
/* set up receive timeout: try next server or retry on timeout */
|
||||
sys_timeout((u32_t)SNTP_RECV_TIMEOUT, sntp_try_next_server, NULL);
|
||||
sys_timeout((u32_t)SNTP_RECV_TIMEOUT * 1000, sntp_try_next_server, NULL);
|
||||
#if SNTP_CHECK_RESPONSE >= 1
|
||||
/* save server address to verify it in sntp_recv */
|
||||
ip_addr_set(&sntp_last_server_address, server_addr);
|
||||
|
|
@ -629,7 +629,7 @@ sntp_send_request(ip_addr_t *server_addr)
|
|||
* DNS found callback when using DNS names as server address.
|
||||
*/
|
||||
static void
|
||||
sntp_dns_found(const char* hostname, ip_addr_t *ipaddr, void *arg)
|
||||
sntp_dns_found(const char* hostname, const ip_addr_t *ipaddr, void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(hostname);
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
|
|
@ -730,10 +730,8 @@ int sntp_set_servers(char *server_url[], int num_servers)
|
|||
|
||||
/* Allocate memory and copy servers */
|
||||
for (i = 0; i < num_servers; i++) {
|
||||
sntp_server_addresses[i] = malloc(strlen(server_url[i]));
|
||||
if (sntp_server_addresses[i]) {
|
||||
strcpy(sntp_server_addresses[i], server_url[i]);
|
||||
} else {
|
||||
sntp_server_addresses[i] = strdup(server_url[i]);
|
||||
if (!sntp_server_addresses[i]) {
|
||||
sntp_num_servers = i;
|
||||
return -2;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ void sntp_update_rtc(time_t t, uint32_t us) {
|
|||
// DEBUG: Compute and print drift
|
||||
int64_t sntp_current = sntp_base + TIMER_COUNT - tim_ref;
|
||||
int64_t sntp_correct = (((uint64_t)us + (uint64_t)t * 1000000U)<<12) / cal;
|
||||
printf("\nRTC Adjust: drift = %ld ticks, cal = %d\n", (time_t)(sntp_correct - sntp_current), cal);
|
||||
printf("\nRTC Adjust: drift = %lld ticks, cal = %d\n", (time_t)(sntp_correct - sntp_current), (uint32_t)cal);
|
||||
|
||||
tim_ref = TIMER_COUNT;
|
||||
cal = sdk_system_rtc_clock_cali_proc();
|
||||
|
|
|
|||
23
extras/softuart/LICENSE
Normal file
23
extras/softuart/LICENSE
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (C) 2016 Bernhard Guillon <Bernhard.Guillon@web.de>
|
||||
Copyright (c) 2015 plieningerweb
|
||||
|
||||
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.
|
||||
|
||||
10
extras/softuart/component.mk
Normal file
10
extras/softuart/component.mk
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# Component makefile for extras/softuart
|
||||
|
||||
# expected anyone using this driver includes it as 'softuart/softuart.h'
|
||||
INC_DIRS += $(softuart_ROOT)..
|
||||
|
||||
# args for passing into compile rule generation
|
||||
softuart_SRC_DIR = $(softuart_ROOT)
|
||||
|
||||
$(eval $(call component_compile_rules,softuart))
|
||||
|
||||
270
extras/softuart/softuart.c
Normal file
270
extras/softuart/softuart.c
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
/*
|
||||
* Softuart
|
||||
*
|
||||
* Copyright (C) 2017 Ruslan V. Uss <unclerus@gmail.com>
|
||||
* Copyright (C) 2016 Bernhard Guillon <Bernhard.Guillon@web.de>
|
||||
*
|
||||
* This code is based on Softuart from here [1] and reworked to
|
||||
* fit into esp-open-rtos.
|
||||
*
|
||||
* it fits my needs to read the GY-GPS6MV2 module with 9600 8n1
|
||||
*
|
||||
* Original Copyright:
|
||||
* Copyright (c) 2015 plieningerweb
|
||||
*
|
||||
* MIT Licensed as described in the file LICENSE
|
||||
*
|
||||
* 1 https://github.com/plieningerweb/esp8266-software-uart
|
||||
*/
|
||||
|
||||
#include "softuart.h"
|
||||
#include <stdint.h>
|
||||
#include <esp/gpio.h>
|
||||
#include <espressif/esp_common.h>
|
||||
#include <stdio.h>
|
||||
|
||||
//#define SOFTUART_DEBUG
|
||||
|
||||
#ifdef SOFTUART_DEBUG
|
||||
#define debug(fmt, ...) printf("%s: " fmt "\n", "SOFTUART", ## __VA_ARGS__)
|
||||
#else
|
||||
#define debug(fmt, ...)
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char receive_buffer[SOFTUART_MAX_RX_BUFF];
|
||||
uint8_t receive_buffer_tail;
|
||||
uint8_t receive_buffer_head;
|
||||
uint8_t buffer_overflow;
|
||||
} softuart_buffer_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t rx_pin, tx_pin;
|
||||
uint32_t baudrate;
|
||||
volatile softuart_buffer_t buffer;
|
||||
uint16_t bit_time;
|
||||
} softuart_t;
|
||||
|
||||
static softuart_t uarts[SOFTUART_MAX_UARTS] = { { 0 } };
|
||||
|
||||
inline static int8_t find_uart_by_rx(uint8_t rx_pin)
|
||||
{
|
||||
for (uint8_t i = 0; i < SOFTUART_MAX_UARTS; i++)
|
||||
if (uarts[i].baudrate && uarts[i].rx_pin == rx_pin) return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// GPIO interrupt handler
|
||||
static void handle_rx(uint8_t gpio_num)
|
||||
{
|
||||
// find uart
|
||||
int8_t uart_no = find_uart_by_rx(gpio_num);
|
||||
if (uart_no < 0) return;
|
||||
|
||||
softuart_t *uart = uarts + uart_no;
|
||||
|
||||
// Disable interrupt
|
||||
gpio_set_interrupt(gpio_num, GPIO_INTTYPE_NONE, handle_rx);
|
||||
|
||||
// Wait till start bit is half over so we can sample the next one in the center
|
||||
sdk_os_delay_us(uart->bit_time / 2);
|
||||
|
||||
// Now sample bits
|
||||
uint8_t d = 0;
|
||||
uint32_t start_time = 0x7FFFFFFF & sdk_system_get_time();
|
||||
|
||||
for (uint8_t i = 0; i < 8; i++)
|
||||
{
|
||||
while ((0x7FFFFFFF & sdk_system_get_time()) < (start_time + (uart->bit_time * (i + 1))))
|
||||
{
|
||||
// If system timer overflow, escape from while loop
|
||||
if ((0x7FFFFFFF & sdk_system_get_time()) < start_time)
|
||||
break;
|
||||
}
|
||||
// Shift d to the right
|
||||
d >>= 1;
|
||||
|
||||
// Read bit
|
||||
if (gpio_read(uart->rx_pin))
|
||||
{
|
||||
// If high, set msb of 8bit to 1
|
||||
d |= 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
// Store byte in buffer
|
||||
// If buffer full, set the overflow flag and return
|
||||
uint8_t next = (uart->buffer.receive_buffer_tail + 1) % SOFTUART_MAX_RX_BUFF;
|
||||
if (next != uart->buffer.receive_buffer_head)
|
||||
{
|
||||
// save new data in buffer: tail points to where byte goes
|
||||
uart->buffer.receive_buffer[uart->buffer.receive_buffer_tail] = d; // save new byte
|
||||
uart->buffer.receive_buffer_tail = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
uart->buffer.buffer_overflow = 1;
|
||||
}
|
||||
|
||||
// Wait for stop bit
|
||||
sdk_os_delay_us(uart->bit_time);
|
||||
|
||||
// Done, reenable interrupt
|
||||
gpio_set_interrupt(uart->rx_pin, GPIO_INTTYPE_EDGE_NEG, handle_rx);
|
||||
}
|
||||
|
||||
static bool check_uart_no(uint8_t uart_no)
|
||||
{
|
||||
if (uart_no >= SOFTUART_MAX_UARTS)
|
||||
{
|
||||
debug("Invalid uart number %d, %d max", uart_no, SOFTUART_MAX_UARTS);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool check_uart_enabled(uint8_t uart_no)
|
||||
{
|
||||
if (!uarts[uart_no].baudrate)
|
||||
{
|
||||
debug("Uart %d is disabled", uart_no);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// Public
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool softuart_open(uint8_t uart_no, uint32_t baudrate, uint8_t rx_pin, uint8_t tx_pin)
|
||||
{
|
||||
// do some checks
|
||||
if (!check_uart_no(uart_no)) return false;
|
||||
if (baudrate == 0)
|
||||
{
|
||||
debug("Invalid baudrate");
|
||||
return false;
|
||||
}
|
||||
for (uint8_t i = 0; i < SOFTUART_MAX_UARTS; i++)
|
||||
if (uarts[i].baudrate && i != uart_no
|
||||
&& (uarts[i].rx_pin == rx_pin || uarts[i].tx_pin == tx_pin || uarts[i].rx_pin == tx_pin || uarts[i].tx_pin == rx_pin))
|
||||
{
|
||||
debug("Cannot share pins between uarts");
|
||||
return false;
|
||||
}
|
||||
|
||||
softuart_close(uart_no);
|
||||
|
||||
softuart_t *uart = uarts + uart_no;
|
||||
|
||||
uart->baudrate = baudrate;
|
||||
uart->rx_pin = rx_pin;
|
||||
uart->tx_pin = tx_pin;
|
||||
|
||||
// Calculate bit_time
|
||||
uart->bit_time = (1000000 / baudrate);
|
||||
if (((100000000 / baudrate) - (100 * uart->bit_time)) > 50) uart->bit_time++;
|
||||
|
||||
// Setup Rx
|
||||
gpio_enable(rx_pin, GPIO_INPUT);
|
||||
gpio_set_pullup(rx_pin, true, false);
|
||||
|
||||
// Setup Tx
|
||||
gpio_enable(tx_pin, GPIO_OUTPUT);
|
||||
gpio_set_pullup(tx_pin, true, false);
|
||||
gpio_write(tx_pin, 1);
|
||||
|
||||
// Setup the interrupt handler to get the start bit
|
||||
gpio_set_interrupt(rx_pin, GPIO_INTTYPE_EDGE_NEG, handle_rx);
|
||||
|
||||
sdk_os_delay_us(1000); // TODO: not sure if it really needed
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool softuart_close(uint8_t uart_no)
|
||||
{
|
||||
if (!check_uart_no(uart_no)) return false;
|
||||
softuart_t *uart = uarts + uart_no;
|
||||
|
||||
if (!uart->baudrate) return true;
|
||||
|
||||
// Remove interrupt
|
||||
gpio_set_interrupt(uart->rx_pin, GPIO_INTTYPE_NONE, NULL);
|
||||
// Mark as unused
|
||||
uart->baudrate = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool softuart_put(uint8_t uart_no, char c)
|
||||
{
|
||||
if (!check_uart_no(uart_no)) return false;
|
||||
if (!check_uart_enabled(uart_no)) return false;
|
||||
softuart_t *uart = uarts + uart_no;
|
||||
|
||||
uint32_t start_time = 0x7FFFFFFF & sdk_system_get_time();
|
||||
gpio_write(uart->tx_pin, 0);
|
||||
|
||||
for (uint8_t i = 0; i <= 8; i++)
|
||||
{
|
||||
while ((0x7FFFFFFF & sdk_system_get_time()) < (start_time + (uart->bit_time * (i + 1))))
|
||||
{
|
||||
if ((0x7FFFFFFF & sdk_system_get_time()) < start_time)
|
||||
break;
|
||||
}
|
||||
gpio_write(uart->tx_pin, c & (1 << i));
|
||||
}
|
||||
|
||||
while ((0x7FFFFFFF & sdk_system_get_time()) < (start_time + (uart->bit_time * 9)))
|
||||
{
|
||||
if ((0x7FFFFFFF & sdk_system_get_time()) < start_time)
|
||||
break;
|
||||
}
|
||||
gpio_write(uart->tx_pin, 1);
|
||||
sdk_os_delay_us(uart->bit_time * 6);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool softuart_puts(uint8_t uart_no, const char *s)
|
||||
{
|
||||
while (*s)
|
||||
{
|
||||
if (!softuart_put(uart_no, *s++))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool softuart_available(uint8_t uart_no)
|
||||
{
|
||||
if (!check_uart_no(uart_no)) return false;
|
||||
if (!check_uart_enabled(uart_no)) return false;
|
||||
softuart_t *uart = uarts + uart_no;
|
||||
|
||||
return (uart->buffer.receive_buffer_tail + SOFTUART_MAX_RX_BUFF - uart->buffer.receive_buffer_head) % SOFTUART_MAX_RX_BUFF;
|
||||
}
|
||||
|
||||
uint8_t softuart_read(uint8_t uart_no)
|
||||
{
|
||||
if (!check_uart_no(uart_no)) return 0;
|
||||
if (!check_uart_enabled(uart_no)) return 0;
|
||||
softuart_t *uart = uarts + uart_no;
|
||||
|
||||
// Empty buffer?
|
||||
if (uart->buffer.receive_buffer_head == uart->buffer.receive_buffer_tail) return 0;
|
||||
|
||||
// Read from "head"
|
||||
uint8_t d = uart->buffer.receive_buffer[uart->buffer.receive_buffer_head]; // grab next byte
|
||||
uart->buffer.receive_buffer_head = (uart->buffer.receive_buffer_head + 1) % SOFTUART_MAX_RX_BUFF;
|
||||
return d;
|
||||
}
|
||||
|
||||
93
extras/softuart/softuart.h
Normal file
93
extras/softuart/softuart.h
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Softuart for esp-open-rtos
|
||||
*
|
||||
* Copyright (C) 2017 Ruslan V. Uss <unclerus@gmail.com>
|
||||
* Copyright (C) 2016 Bernhard Guillon <Bernhard.Guillon@web.de>
|
||||
*
|
||||
* This code is based on Softuart from here [1] and reworked to
|
||||
* fit into esp-open-rtos. For now only the RX part is ported.
|
||||
* Also the configuration of the pin is for now hardcoded.
|
||||
*
|
||||
* it fits my needs to read the GY-GPS6MV2 module with 9600 8n1
|
||||
*
|
||||
* Original Copyright:
|
||||
* Copyright (c) 2015 plieningerweb
|
||||
*
|
||||
* MIT Licensed as described in the file LICENSE
|
||||
*
|
||||
* 1 https://github.com/plieningerweb/esp8266-software-uart
|
||||
*/
|
||||
#ifndef SOFTUART_H_
|
||||
#define SOFTUART_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#ifndef SOFTUART_MAX_UARTS
|
||||
#define SOFTUART_MAX_UARTS 2
|
||||
#endif
|
||||
|
||||
#ifndef SOFTUART_MAX_RX_BUFF
|
||||
#define SOFTUART_MAX_RX_BUFF 64 //!< Must be power of two: 2, 4, 8, 16 etc.
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initialize software uart and setup interrupt handler
|
||||
* @param uart_no Software uart index, 0..SOFTUART_MAX_UARTS
|
||||
* @param baudrate Baudrate, e.g. 9600, 19200, etc
|
||||
* @param rx_pin GPIO pin number for RX
|
||||
* @param tx_pin GPIO pin number for TX
|
||||
* @return true if no errors occured otherwise false
|
||||
*/
|
||||
bool softuart_open(uint8_t uart_no, uint32_t baudrate, uint8_t rx_pin, uint8_t tx_pin);
|
||||
|
||||
/**
|
||||
* Deinitialize software uart
|
||||
* @param uart_no Software uart index, 0..SOFTUART_MAX_UARTS
|
||||
* @return true if no errors occured otherwise false
|
||||
*/
|
||||
bool softuart_close(uint8_t uart_no);
|
||||
|
||||
/**
|
||||
* Put char to software uart
|
||||
* @param uart_no Software uart index, 0..SOFTUART_MAX_UARTS
|
||||
* @param c Char
|
||||
* @return true if no errors occured otherwise false
|
||||
*/
|
||||
bool softuart_put(uint8_t uart_no, char c);
|
||||
|
||||
/**
|
||||
* Put string to software uart
|
||||
* @param uart_no Software uart index, 0..SOFTUART_MAX_UARTS
|
||||
* @param s Null-terminated string
|
||||
* @return true if no errors occured otherwise false
|
||||
*/
|
||||
bool softuart_puts(uint8_t uart_no, const char *s);
|
||||
|
||||
/**
|
||||
* Check if data is available
|
||||
* @param uart_no Software uart index, 0..SOFTUART_MAX_UARTS
|
||||
* @return true if data is available otherwise false
|
||||
*/
|
||||
bool softuart_available(uint8_t uart_no);
|
||||
|
||||
/**
|
||||
* Read current byte from internal buffer if available.
|
||||
*
|
||||
* NOTE: This call is non blocking.
|
||||
* NOTE: You have to check softuart_available() first.
|
||||
* @param uart_no Software uart index, 0..SOFTUART_MAX_UARTS
|
||||
* @return current byte if available otherwise 0
|
||||
*/
|
||||
uint8_t softuart_read(uint8_t uart_no);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SOFTUART_H_ */
|
||||
|
|
@ -7,11 +7,10 @@
|
|||
*/
|
||||
#include "esp_spiffs.h"
|
||||
#include "spiffs.h"
|
||||
#include <espressif/spi_flash.h>
|
||||
#include <spiflash.h>
|
||||
#include <stdbool.h>
|
||||
#include <esp/uart.h>
|
||||
#include <fcntl.h>
|
||||
#include "esp_spiffs_flash.h"
|
||||
|
||||
spiffs fs;
|
||||
|
||||
|
|
@ -34,7 +33,7 @@ static fs_buf_t cache_buf = {0};
|
|||
|
||||
static s32_t esp_spiffs_read(u32_t addr, u32_t size, u8_t *dst)
|
||||
{
|
||||
if (esp_spiffs_flash_read(addr, dst, size) == ESP_SPIFFS_FLASH_ERROR) {
|
||||
if (!spiflash_read(addr, dst, size)) {
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
|
|
@ -43,7 +42,7 @@ static s32_t esp_spiffs_read(u32_t addr, u32_t size, u8_t *dst)
|
|||
|
||||
static s32_t esp_spiffs_write(u32_t addr, u32_t size, u8_t *src)
|
||||
{
|
||||
if (esp_spiffs_flash_write(addr, src, size) == ESP_SPIFFS_FLASH_ERROR) {
|
||||
if (!spiflash_write(addr, src, size)) {
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
|
|
@ -52,11 +51,10 @@ static s32_t esp_spiffs_write(u32_t addr, u32_t size, u8_t *src)
|
|||
|
||||
static s32_t esp_spiffs_erase(u32_t addr, u32_t size)
|
||||
{
|
||||
uint32_t sectors = size / SPI_FLASH_SEC_SIZE;
|
||||
uint32_t sectors = size / SPI_FLASH_SECTOR_SIZE;
|
||||
|
||||
for (uint32_t i = 0; i < sectors; i++) {
|
||||
if (esp_spiffs_flash_erase_sector(addr + (SPI_FLASH_SEC_SIZE * i))
|
||||
== ESP_SPIFFS_FLASH_ERROR) {
|
||||
if (!spiflash_erase_sector(addr + (SPI_FLASH_SECTOR_SIZE * i))) {
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,273 +0,0 @@
|
|||
/**
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016 sheinz (https://github.com/sheinz)
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include "esp_spiffs_flash.h"
|
||||
#include "flashchip.h"
|
||||
#include "espressif/spi_flash.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "esp/rom.h"
|
||||
#include "esp/spi_regs.h"
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Note about Wait_SPI_Idle.
|
||||
*
|
||||
* Each write/erase flash operation sets BUSY bit in flash status register.
|
||||
* If attempt to access flash while BUSY bit is set operation will fail.
|
||||
* Function Wait_SPI_Idle loops until this bit is not cleared.
|
||||
*
|
||||
* The approach in the following code is that each write function that is
|
||||
* accessible from the outside should leave flash in Idle state.
|
||||
* The read operations doesn't set BUSY bit in a flash. So they do not wait.
|
||||
* They relay that previous operation is completely finished.
|
||||
*
|
||||
* This approach is different from ESP8266 bootrom where Wait_SPI_Idle is
|
||||
* called where it needed and not.
|
||||
*/
|
||||
|
||||
#define SPI_WRITE_MAX_SIZE 64
|
||||
|
||||
// 64 bytes read causes hang
|
||||
// http://bbs.espressif.com/viewtopic.php?f=6&t=2439
|
||||
#define SPI_READ_MAX_SIZE 60
|
||||
|
||||
|
||||
/**
|
||||
* Copy unaligned data to 4-byte aligned destination buffer.
|
||||
*
|
||||
* @param words Number of 4-byte words to write.
|
||||
*
|
||||
* @see unaligned_memcpy.S
|
||||
*/
|
||||
void memcpy_unaligned_src(volatile uint32_t *dst, uint8_t *src, uint8_t words);
|
||||
|
||||
/**
|
||||
* Copy 4-byte aligned source data to unaligned destination buffer.
|
||||
*
|
||||
* @param bytes Number of byte to copy to dst.
|
||||
*
|
||||
* @see unaligned_memcpy.S
|
||||
*/
|
||||
void memcpy_unaligned_dst(uint8_t *dst, volatile uint32_t *src, uint8_t bytes);
|
||||
|
||||
|
||||
/**
|
||||
* Low level SPI flash write. Write block of data up to 64 bytes.
|
||||
*/
|
||||
static inline void IRAM spi_write_data(sdk_flashchip_t *chip, uint32_t addr,
|
||||
uint8_t *buf, uint32_t size)
|
||||
{
|
||||
uint32_t words = size >> 2;
|
||||
if (size & 0b11) {
|
||||
words++;
|
||||
}
|
||||
|
||||
Wait_SPI_Idle(chip); // wait for previous write to finish
|
||||
|
||||
SPI(0).ADDR = (addr & 0x00FFFFFF) | (size << 24);
|
||||
|
||||
memcpy_unaligned_src(SPI(0).W, buf, words);
|
||||
|
||||
SPI_write_enable(chip);
|
||||
|
||||
SPI(0).CMD = SPI_CMD_PP;
|
||||
while (SPI(0).CMD) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a page of flash. Data block should not cross page boundary.
|
||||
*/
|
||||
static uint32_t IRAM spi_write_page(sdk_flashchip_t *flashchip, uint32_t dest_addr,
|
||||
uint8_t *buf, uint32_t size)
|
||||
{
|
||||
// check if block to write doesn't cross page boundary
|
||||
if (flashchip->page_size < size + (dest_addr % flashchip->page_size)) {
|
||||
return ESP_SPIFFS_FLASH_ERROR;
|
||||
}
|
||||
|
||||
if (size < 1) {
|
||||
return ESP_SPIFFS_FLASH_OK;
|
||||
}
|
||||
|
||||
while (size >= SPI_WRITE_MAX_SIZE) {
|
||||
spi_write_data(flashchip, dest_addr, buf, SPI_WRITE_MAX_SIZE);
|
||||
|
||||
size -= SPI_WRITE_MAX_SIZE;
|
||||
dest_addr += SPI_WRITE_MAX_SIZE;
|
||||
buf += SPI_WRITE_MAX_SIZE;
|
||||
|
||||
if (size < 1) {
|
||||
return ESP_SPIFFS_FLASH_OK;
|
||||
}
|
||||
}
|
||||
|
||||
spi_write_data(flashchip, dest_addr, buf, size);
|
||||
|
||||
return ESP_SPIFFS_FLASH_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split block of data into pages and write pages.
|
||||
*/
|
||||
static uint32_t IRAM spi_write(uint32_t addr, uint8_t *dst, uint32_t size)
|
||||
{
|
||||
if (sdk_flashchip.chip_size < (addr + size)) {
|
||||
return ESP_SPIFFS_FLASH_ERROR;
|
||||
}
|
||||
|
||||
uint32_t write_bytes_to_page = sdk_flashchip.page_size -
|
||||
(addr % sdk_flashchip.page_size); // TODO: place for optimization
|
||||
|
||||
if (size < write_bytes_to_page) {
|
||||
if (spi_write_page(&sdk_flashchip, addr, dst, size)) {
|
||||
return ESP_SPIFFS_FLASH_ERROR;
|
||||
}
|
||||
} else {
|
||||
if (spi_write_page(&sdk_flashchip, addr, dst, write_bytes_to_page)) {
|
||||
return ESP_SPIFFS_FLASH_ERROR;
|
||||
}
|
||||
|
||||
uint32_t offset = write_bytes_to_page;
|
||||
uint32_t pages_to_write = (size - offset) / sdk_flashchip.page_size;
|
||||
for (uint8_t i = 0; i != pages_to_write; i++) {
|
||||
if (spi_write_page(&sdk_flashchip, addr + offset,
|
||||
dst + offset, sdk_flashchip.page_size)) {
|
||||
return ESP_SPIFFS_FLASH_ERROR;
|
||||
}
|
||||
offset += sdk_flashchip.page_size;
|
||||
}
|
||||
|
||||
if (spi_write_page(&sdk_flashchip, addr + offset,
|
||||
dst + offset, size - offset)) {
|
||||
return ESP_SPIFFS_FLASH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_SPIFFS_FLASH_OK;
|
||||
}
|
||||
|
||||
uint32_t IRAM esp_spiffs_flash_write(uint32_t addr, uint8_t *buf, uint32_t size)
|
||||
{
|
||||
uint32_t result = ESP_SPIFFS_FLASH_ERROR;
|
||||
|
||||
if (buf) {
|
||||
vPortEnterCritical();
|
||||
Cache_Read_Disable();
|
||||
|
||||
result = spi_write(addr, buf, size);
|
||||
|
||||
// make sure all write operations is finished before exiting
|
||||
Wait_SPI_Idle(&sdk_flashchip);
|
||||
|
||||
Cache_Read_Enable(0, 0, 1);
|
||||
vPortExitCritical();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read SPI flash up to 64 bytes.
|
||||
*/
|
||||
static inline void IRAM read_block(sdk_flashchip_t *chip, uint32_t addr,
|
||||
uint8_t *buf, uint32_t size)
|
||||
{
|
||||
SPI(0).ADDR = (addr & 0x00FFFFFF) | (size << 24);
|
||||
SPI(0).CMD = SPI_CMD_READ;
|
||||
|
||||
while (SPI(0).CMD) {};
|
||||
|
||||
memcpy_unaligned_dst(buf, SPI(0).W, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read SPI flash data. Data region doesn't need to be page aligned.
|
||||
*/
|
||||
static inline uint32_t IRAM read_data(sdk_flashchip_t *flashchip, uint32_t addr,
|
||||
uint8_t *dst, uint32_t size)
|
||||
{
|
||||
if (size < 1) {
|
||||
return ESP_SPIFFS_FLASH_OK;
|
||||
}
|
||||
|
||||
if ((addr + size) > flashchip->chip_size) {
|
||||
return ESP_SPIFFS_FLASH_ERROR;
|
||||
}
|
||||
|
||||
while (size >= SPI_READ_MAX_SIZE) {
|
||||
read_block(flashchip, addr, dst, SPI_READ_MAX_SIZE);
|
||||
dst += SPI_READ_MAX_SIZE;
|
||||
size -= SPI_READ_MAX_SIZE;
|
||||
addr += SPI_READ_MAX_SIZE;
|
||||
}
|
||||
|
||||
if (size > 0) {
|
||||
read_block(flashchip, addr, dst, size);
|
||||
}
|
||||
|
||||
return ESP_SPIFFS_FLASH_OK;
|
||||
}
|
||||
|
||||
uint32_t IRAM esp_spiffs_flash_read(uint32_t dest_addr, uint8_t *buf, uint32_t size)
|
||||
{
|
||||
uint32_t result = ESP_SPIFFS_FLASH_ERROR;
|
||||
|
||||
if (buf) {
|
||||
vPortEnterCritical();
|
||||
Cache_Read_Disable();
|
||||
|
||||
result = read_data(&sdk_flashchip, dest_addr, buf, size);
|
||||
|
||||
Cache_Read_Enable(0, 0, 1);
|
||||
vPortExitCritical();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t IRAM esp_spiffs_flash_erase_sector(uint32_t addr)
|
||||
{
|
||||
if ((addr + sdk_flashchip.sector_size) > sdk_flashchip.chip_size) {
|
||||
return ESP_SPIFFS_FLASH_ERROR;
|
||||
}
|
||||
|
||||
if (addr & 0xFFF) {
|
||||
return ESP_SPIFFS_FLASH_ERROR;
|
||||
}
|
||||
|
||||
vPortEnterCritical();
|
||||
Cache_Read_Disable();
|
||||
|
||||
SPI_write_enable(&sdk_flashchip);
|
||||
|
||||
SPI(0).ADDR = addr & 0x00FFFFFF;
|
||||
SPI(0).CMD = SPI_CMD_SE;
|
||||
while (SPI(0).CMD) {};
|
||||
|
||||
Wait_SPI_Idle(&sdk_flashchip);
|
||||
|
||||
Cache_Read_Enable(0, 0, 1);
|
||||
vPortExitCritical();
|
||||
|
||||
return ESP_SPIFFS_FLASH_OK;
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
/**
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016 sheinz (https://github.com/sheinz)
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef __ESP_SPIFFS_FLASH_H__
|
||||
#define __ESP_SPIFFS_FLASH_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "common_macros.h"
|
||||
|
||||
#define ESP_SPIFFS_FLASH_OK 0
|
||||
#define ESP_SPIFFS_FLASH_ERROR 1
|
||||
|
||||
/**
|
||||
* Read data from SPI flash.
|
||||
*
|
||||
* @param addr Address to read from. Can be not aligned.
|
||||
* @param buf Buffer to read to. Doesn't have to be aligned.
|
||||
* @param size Size of data to read. Buffer size must be >= than data size.
|
||||
*
|
||||
* @return ESP_SPIFFS_FLASH_OK or ESP_SPIFFS_FLASH_ERROR
|
||||
*/
|
||||
uint32_t IRAM esp_spiffs_flash_read(uint32_t addr, uint8_t *buf, uint32_t size);
|
||||
|
||||
/**
|
||||
* Write data to SPI flash.
|
||||
*
|
||||
* @param addr Address to write to. Can be not aligned.
|
||||
* @param buf Buffer of data to write to flash. Doesn't have to be aligned.
|
||||
* @param size Size of data to write. Buffer size must be >= than data size.
|
||||
*
|
||||
* @return ESP_SPIFFS_FLASH_OK or ESP_SPIFFS_FLASH_ERROR
|
||||
*/
|
||||
uint32_t IRAM esp_spiffs_flash_write(uint32_t addr, uint8_t *buf, uint32_t size);
|
||||
|
||||
/**
|
||||
* Erase a sector.
|
||||
*
|
||||
* @param addr Address of sector to erase. Must be sector aligned.
|
||||
*
|
||||
* @return ESP_SPIFFS_FLASH_OK or ESP_SPIFFS_FLASH_ERROR
|
||||
*/
|
||||
uint32_t IRAM esp_spiffs_flash_erase_sector(uint32_t addr);
|
||||
|
||||
#endif // __ESP_SPIFFS_FLASH_H__
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
/**
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016 sheinz (https://github.com/sheinz)
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
.text
|
||||
.section .iram1.text, "x"
|
||||
.literal_position
|
||||
|
||||
/**
|
||||
* Copy unaligned data to 4-byte aligned buffer.
|
||||
*/
|
||||
.align 4
|
||||
.global memcpy_unaligned_src
|
||||
.type memcpy_unaligned_src, @function
|
||||
memcpy_unaligned_src:
|
||||
/* a2: dst, a3: src, a4: size */
|
||||
ssa8l a3
|
||||
srli a3, a3, 2
|
||||
slli a3, a3, 2
|
||||
beqz a4, u_src_end
|
||||
l32i a6, a3, 0
|
||||
u_src_loop:
|
||||
l32i a7, a3, 4
|
||||
src a8, a7, a6
|
||||
memw
|
||||
s32i a8, a2, 0
|
||||
mov a6, a7
|
||||
addi a3, a3, 4
|
||||
addi a2, a2, 4
|
||||
addi a4, a4, -1
|
||||
bnez a4, u_src_loop
|
||||
u_src_end:
|
||||
movi a2, 0
|
||||
ret.n
|
||||
|
||||
|
||||
/**
|
||||
* Copy data from 4-byte aligned source to unaligned destination buffer.
|
||||
*/
|
||||
.align 4
|
||||
.global memcpy_unaligned_dst
|
||||
.type memcpy_unaligned_dst, @function
|
||||
memcpy_unaligned_dst:
|
||||
/* a2: dst, a3: src, a4: size */
|
||||
beqz.n a4, u_dst_end
|
||||
extui a5, a4, 0, 2
|
||||
beqz.n a5, aligned_dst_loop
|
||||
u_dst_loop:
|
||||
/* Load data word */
|
||||
memw
|
||||
l32i.n a5, a3, 0
|
||||
|
||||
/* Save byte number 0 */
|
||||
s8i a5, a2, 0
|
||||
addi.n a4, a4, -1
|
||||
beqz a4, u_dst_end
|
||||
addi.n a2, a2, 1
|
||||
|
||||
/* Shift and save byte number 1 */
|
||||
srli a5, a5, 8
|
||||
s8i a5, a2, 0
|
||||
addi.n a4, a4, -1
|
||||
beqz a4, u_dst_end
|
||||
addi.n a2, a2, 1
|
||||
|
||||
/* Shift and save byte number 2 */
|
||||
srli a5, a5, 8
|
||||
s8i a5, a2, 0
|
||||
addi.n a4, a4, -1
|
||||
beqz a4, u_dst_end
|
||||
addi.n a2, a2, 1
|
||||
|
||||
/* Shift and save byte number 3 */
|
||||
srli a5, a5, 8
|
||||
s8i a5, a2, 0
|
||||
addi.n a4, a4, -1
|
||||
addi.n a2, a2, 1
|
||||
|
||||
/* Next word */
|
||||
addi.n a3, a3, 4
|
||||
bnez.n a4, u_dst_loop
|
||||
ret.n
|
||||
aligned_dst_loop:
|
||||
memw
|
||||
l32i a5, a3, 0
|
||||
s32i a5, a2, 0
|
||||
addi.n a3, a3, 4
|
||||
addi.n a2, a2, 4
|
||||
addi.n a4, a4, -4
|
||||
bnez.n a4, aligned_dst_loop
|
||||
u_dst_end: ret.n
|
||||
|
||||
|
|
@ -11,9 +11,6 @@
|
|||
*/
|
||||
#include "ssd1306.h"
|
||||
#include <stdio.h>
|
||||
#if (SSD1306_I2C_SUPPORT)
|
||||
#include <i2c/i2c.h>
|
||||
#endif
|
||||
#if (SSD1306_SPI4_SUPPORT) || (SSD1306_SPI3_SUPPORT)
|
||||
#include <esp/spi.h>
|
||||
#endif
|
||||
|
|
@ -88,10 +85,18 @@
|
|||
#define abs(x) ((x)<0 ? -(x) : (x))
|
||||
#define swap(x, y) do { typeof(x) temp##x##y = x; x = y; y = temp##x##y; } while (0)
|
||||
|
||||
|
||||
#if (SSD1306_I2C_SUPPORT)
|
||||
static int inline i2c_send(const ssd1306_t *dev, uint8_t reg, uint8_t* data, uint8_t len)
|
||||
{
|
||||
return i2c_slave_write(dev->i2c_dev.bus, dev->i2c_dev.addr , ®, data, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Issue a command to SSD1306 device
|
||||
* I2C proto format:
|
||||
* |S|Slave Address|W|ACK|0x00|Command|Ack|P|
|
||||
*
|
||||
*
|
||||
* in case of two-bytes command here will be Data byte
|
||||
* right after the command byte.
|
||||
*/
|
||||
|
|
@ -101,23 +106,7 @@ int ssd1306_command(const ssd1306_t *dev, uint8_t cmd)
|
|||
switch (dev->protocol) {
|
||||
#if (SSD1306_I2C_SUPPORT)
|
||||
case SSD1306_PROTO_I2C:
|
||||
i2c_start();
|
||||
if (!i2c_write(dev->addr << 1)) {
|
||||
debug("Error while xmitting I2C slave address\n");
|
||||
i2c_stop();
|
||||
return -EIO;
|
||||
}
|
||||
if (!i2c_write(0x00)) {
|
||||
debug("Error while xmitting transmission type\n");
|
||||
i2c_stop();
|
||||
return -EIO;
|
||||
}
|
||||
if (!i2c_write(cmd)) {
|
||||
debug("Error while xmitting command: 0x%02X\n", cmd);
|
||||
i2c_stop();
|
||||
return -EIO;
|
||||
}
|
||||
i2c_stop();
|
||||
return i2c_send(dev, 0x00, &cmd, 1);
|
||||
break;
|
||||
#endif
|
||||
#if (SSD1306_SPI4_SUPPORT)
|
||||
|
|
@ -247,7 +236,9 @@ int ssd1306_load_frame_buffer(const ssd1306_t *dev, uint8_t buf[])
|
|||
{
|
||||
uint16_t i;
|
||||
uint8_t j;
|
||||
|
||||
#if (SSD1306_I2C_SUPPORT)
|
||||
uint8_t tab[16] = { 0 } ;
|
||||
#endif
|
||||
size_t len = dev->width * dev->height / 8;
|
||||
if(dev->screen == SSD1306_SCREEN)
|
||||
{
|
||||
|
|
@ -258,31 +249,11 @@ int ssd1306_load_frame_buffer(const ssd1306_t *dev, uint8_t buf[])
|
|||
switch (dev->protocol) {
|
||||
#if (SSD1306_I2C_SUPPORT)
|
||||
case SSD1306_PROTO_I2C:
|
||||
for (i = 0; i < len; i++) {
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
if(dev->screen == SH1106_SCREEN && i%dev->width == 0) sh1106_go_coordinate(dev,0,i/dev->width);
|
||||
i2c_start();
|
||||
if (!i2c_write(dev->addr << 1)) {
|
||||
debug("Error while xmitting I2C slave address\n");
|
||||
i2c_stop();
|
||||
return -EIO;
|
||||
}
|
||||
if (!i2c_write(0x40)) {
|
||||
debug("Error while xmitting transmission type\n");
|
||||
i2c_stop();
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
for (j = 0; j < 16; j++) {
|
||||
if (!i2c_write(buf ? buf[i] : 0)) {
|
||||
debug("Error while writing to GDDRAM\n");
|
||||
i2c_stop();
|
||||
return -EIO;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
i--;
|
||||
i2c_stop();
|
||||
taskYIELD();
|
||||
i2c_send(dev, 0x40, buf ? &buf[i] : tab, 16);
|
||||
i+=15 ;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
|
@ -319,9 +290,19 @@ int ssd1306_load_frame_buffer(const ssd1306_t *dev, uint8_t buf[])
|
|||
{
|
||||
spi_set_command(SPI_BUS,1,1); // data mode
|
||||
if (buf)
|
||||
spi_transfer(SPI_BUS, buf, NULL, len, SPI_8BIT);
|
||||
{
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
spi_transfer(SPI_BUS, &buf[i], NULL, 1, SPI_8BIT);
|
||||
}
|
||||
}
|
||||
else
|
||||
spi_repeat_send_8(SPI_BUS,0,len);
|
||||
{
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
spi_transfer_8(SPI_BUS, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
// shifted
|
||||
#if (SSD1306_I2C_SUPPORT)
|
||||
#include <i2c/i2c.h>
|
||||
#define SSD1306_I2C_ADDR_0 (0x3C)
|
||||
#define SSD1306_I2C_ADDR_1 (0x3D)
|
||||
#endif
|
||||
|
|
@ -67,7 +68,7 @@ typedef struct
|
|||
ssd1306_screen_t screen ;
|
||||
union {
|
||||
#if (SSD1306_I2C_SUPPORT)
|
||||
uint8_t addr ; //!< I2C address, used by SSD1306_PROTO_I2C
|
||||
i2c_dev_t i2c_dev; //!< I2C devuce descriptor, used by SSD1306_PROTO_I2C
|
||||
#endif
|
||||
uint8_t cs_pin ; //!< Chip Select GPIO pin, used by SSD1306_PROTO_SPI3, SSD1306_PROTO_SPI4
|
||||
} ;
|
||||
|
|
@ -192,14 +193,6 @@ int ssd1306_set_display_offset(const ssd1306_t *dev, uint8_t offset);
|
|||
*/
|
||||
int sh1106_set_charge_pump_voltage(const ssd1306_t *dev, sh1106_voltage_t select);
|
||||
|
||||
/**
|
||||
* Select charge pump voltage. See value in datasheet.
|
||||
* @param dev Pointer to device descriptor
|
||||
* @param select Select charge pump voltage value
|
||||
* @return Non-zero if error occured
|
||||
*/
|
||||
int sh1106_set_charge_pump_voltage(const ssd1306_t *dev, sh1106_voltage_t select);
|
||||
|
||||
/**
|
||||
* Enable or disable the charge pump. See application note in datasheet.
|
||||
* @param dev Pointer to device descriptor
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ static SemaphoreHandle_t uart0_sem = NULL;
|
|||
static bool inited = false;
|
||||
static void uart0_rx_init(void);
|
||||
|
||||
IRAM void uart0_rx_handler(void)
|
||||
IRAM void uart0_rx_handler(void *arg)
|
||||
{
|
||||
// TODO: Handle UART1, see reg 0x3ff20020, bit2, bit0 represents uart1 and uart0 respectively
|
||||
if (!UART(UART0).INT_STATUS & UART_INT_STATUS_RXFIFO_FULL) {
|
||||
|
|
@ -97,7 +97,7 @@ static void uart0_rx_init(void)
|
|||
int trig_lvl = 1;
|
||||
uart0_sem = xSemaphoreCreateCounting(UART0_RX_SIZE, 0);
|
||||
|
||||
_xt_isr_attach(INUM_UART, uart0_rx_handler);
|
||||
_xt_isr_attach(INUM_UART, uart0_rx_handler, NULL);
|
||||
_xt_isr_unmask(1 << INUM_UART);
|
||||
|
||||
// reset the rx fifo
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include "FreeRTOS.h"
|
||||
#include "i2c/i2c.h"
|
||||
#include "task.h"
|
||||
#include "tsl2561.h"
|
||||
|
||||
|
|
@ -96,32 +95,32 @@
|
|||
#define B8C 0x0000 // 0.000 * 2^LUX_SCALE
|
||||
#define M8C 0x0000 // 0.000 * 2^LUX_SCALE
|
||||
|
||||
static bool write_register(uint8_t i2c_addr, uint8_t reg, uint8_t value)
|
||||
static int write_register(i2c_dev_t* i2c_dev, uint8_t reg, uint8_t value)
|
||||
{
|
||||
uint8_t data[2];
|
||||
data[0] = TSL2561_REG_COMMAND | reg;
|
||||
data[1] = value;
|
||||
return i2c_slave_write(i2c_addr, data, 2);
|
||||
reg = TSL2561_REG_COMMAND | reg;
|
||||
return i2c_slave_write(i2c_dev->bus, i2c_dev->addr, ®, &value, 1);
|
||||
}
|
||||
|
||||
static uint8_t read_register(uint8_t i2c_addr, uint8_t reg)
|
||||
static uint8_t read_register(i2c_dev_t* i2c_dev, uint8_t reg)
|
||||
{
|
||||
uint8_t data[1];
|
||||
reg = TSL2561_REG_COMMAND | reg;
|
||||
|
||||
if (!i2c_slave_read(i2c_addr, TSL2561_REG_COMMAND | reg, data, 1))
|
||||
if (i2c_slave_read(i2c_dev->bus, i2c_dev->addr, ®, data, 1))
|
||||
{
|
||||
printf("Error in tsl261 read_register\n");
|
||||
printf("Error in tsl2561 read_register\n");
|
||||
}
|
||||
|
||||
return data[0];
|
||||
}
|
||||
|
||||
static uint16_t read_register_16(uint8_t i2c_addr, uint8_t low_register_addr)
|
||||
static uint16_t read_register_16(i2c_dev_t* i2c_dev, uint8_t low_register_addr)
|
||||
{
|
||||
uint16_t value = 0;
|
||||
uint8_t data[2];
|
||||
low_register_addr = TSL2561_REG_COMMAND | TSL2561_READ_WORD | low_register_addr;
|
||||
|
||||
if (!i2c_slave_read(i2c_addr, TSL2561_REG_COMMAND | TSL2561_READ_WORD | low_register_addr, data, 2))
|
||||
if (i2c_slave_read(i2c_dev->bus, i2c_dev->addr, &low_register_addr, data, 2))
|
||||
{
|
||||
printf("Error with i2c_slave_read in read_register_16\n");
|
||||
}
|
||||
|
|
@ -131,24 +130,24 @@ static uint16_t read_register_16(uint8_t i2c_addr, uint8_t low_register_addr)
|
|||
return value;
|
||||
}
|
||||
|
||||
static bool enable(uint8_t i2c_addr)
|
||||
static int enable(i2c_dev_t* i2c_dev)
|
||||
{
|
||||
return write_register(i2c_addr, TSL2561_REG_CONTROL, TSL2561_ON);
|
||||
return write_register(i2c_dev, TSL2561_REG_CONTROL, TSL2561_ON);
|
||||
}
|
||||
|
||||
static bool disable(uint8_t i2c_addr)
|
||||
static int disable(i2c_dev_t* i2c_dev)
|
||||
{
|
||||
return write_register(i2c_addr, TSL2561_REG_CONTROL, TSL2561_OFF);
|
||||
return write_register(i2c_dev, TSL2561_REG_CONTROL, TSL2561_OFF);
|
||||
}
|
||||
|
||||
void tsl2561_init(tsl2561_t *device)
|
||||
{
|
||||
if (!enable(device->i2c_addr))
|
||||
if (enable(&device->i2c_dev))
|
||||
{
|
||||
printf("Error initializing tsl2561\n");
|
||||
}
|
||||
|
||||
uint8_t control_reg = (read_register(device->i2c_addr, TSL2561_REG_CONTROL) & TSL2561_ON);
|
||||
uint8_t control_reg = (read_register(&device->i2c_dev, TSL2561_REG_CONTROL) & TSL2561_ON);
|
||||
|
||||
if (control_reg != TSL2561_ON)
|
||||
{
|
||||
|
|
@ -156,39 +155,39 @@ void tsl2561_init(tsl2561_t *device)
|
|||
}
|
||||
|
||||
// Fetch the package type
|
||||
uint8_t part_reg = read_register(device->i2c_addr, TSL2561_REG_PART_ID);
|
||||
uint8_t part_reg = read_register(&device->i2c_dev, TSL2561_REG_PART_ID);
|
||||
uint8_t package = part_reg >> 6;
|
||||
device->package_type = package;
|
||||
|
||||
// Fetch the gain and integration time
|
||||
uint8_t timing_register = read_register(device->i2c_addr, TSL2561_REG_TIMING);
|
||||
uint8_t timing_register = read_register(&device->i2c_dev, TSL2561_REG_TIMING);
|
||||
device->gain = timing_register & 0x10;
|
||||
device->integration_time = timing_register & 0x03;
|
||||
|
||||
disable(device->i2c_addr);
|
||||
disable(&device->i2c_dev);
|
||||
}
|
||||
|
||||
void tsl2561_set_integration_time(tsl2561_t *device, tsl2561_integration_time_t integration_time_id)
|
||||
{
|
||||
enable(device->i2c_addr);
|
||||
write_register(device->i2c_addr, TSL2561_REG_TIMING, integration_time_id | device->gain);
|
||||
disable(device->i2c_addr);
|
||||
enable(&device->i2c_dev);
|
||||
write_register(&device->i2c_dev, TSL2561_REG_TIMING, integration_time_id | device->gain);
|
||||
disable(&device->i2c_dev);
|
||||
|
||||
device->integration_time = integration_time_id;
|
||||
}
|
||||
|
||||
void tsl2561_set_gain(tsl2561_t *device, tsl2561_gain_t gain)
|
||||
{
|
||||
enable(device->i2c_addr);
|
||||
write_register(device->i2c_addr, TSL2561_REG_TIMING, gain | device->integration_time);
|
||||
disable(device->i2c_addr);
|
||||
enable(&device->i2c_dev);
|
||||
write_register(&device->i2c_dev, TSL2561_REG_TIMING, gain | device->integration_time);
|
||||
disable(&device->i2c_dev);
|
||||
|
||||
device->gain = gain;
|
||||
}
|
||||
|
||||
static void get_channel_data(tsl2561_t *device, uint16_t *channel0, uint16_t *channel1)
|
||||
{
|
||||
enable(device->i2c_addr);
|
||||
enable(&device->i2c_dev);
|
||||
|
||||
// Since we just enabled the chip, we need to sleep
|
||||
// for the chip's integration time so it can gather a reading
|
||||
|
|
@ -205,10 +204,10 @@ static void get_channel_data(tsl2561_t *device, uint16_t *channel0, uint16_t *ch
|
|||
break;
|
||||
}
|
||||
|
||||
*channel0 = read_register_16(device->i2c_addr, TSL2561_REG_CHANNEL_0_LOW);
|
||||
*channel1 = read_register_16(device->i2c_addr, TSL2561_REG_CHANNEL_1_LOW);
|
||||
*channel0 = read_register_16(&device->i2c_dev, TSL2561_REG_CHANNEL_0_LOW);
|
||||
*channel1 = read_register_16(&device->i2c_dev, TSL2561_REG_CHANNEL_1_LOW);
|
||||
|
||||
disable(device->i2c_addr);
|
||||
disable(&device->i2c_dev);
|
||||
}
|
||||
|
||||
bool tsl2561_read_lux(tsl2561_t *device, uint32_t *lux)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <i2c/i2c.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
@ -38,7 +39,7 @@ typedef enum
|
|||
} tsl2561_gain_t;
|
||||
|
||||
typedef struct {
|
||||
tsl2561_i2c_addr_t i2c_addr;
|
||||
i2c_dev_t i2c_dev;
|
||||
uint8_t integration_time;
|
||||
uint8_t gain;
|
||||
uint8_t package_type;
|
||||
|
|
|
|||
9
extras/tsl4531/component.mk
Normal file
9
extras/tsl4531/component.mk
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# Component makefile for extras/tsl4531
|
||||
|
||||
# Include the TSL4531 driver as "tsl4531/tsl4531.h"
|
||||
INC_DIRS += $(tsl4531_ROOT)..
|
||||
|
||||
# args for passing into compile rule generation
|
||||
tsl4531_SRC_DIR = $(tsl4531_ROOT)
|
||||
|
||||
$(eval $(call component_compile_rules,tsl4531))
|
||||
165
extras/tsl4531/tsl4531.c
Normal file
165
extras/tsl4531/tsl4531.c
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2017 Brian Schwind (https://github.com/bschwind)
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "tsl4531.h"
|
||||
|
||||
// Registers
|
||||
#define TSL4531_REG_COMMAND 0x80
|
||||
#define TSL4531_REG_CONTROL 0x00
|
||||
#define TSL4531_REG_CONFIG 0x01
|
||||
#define TSL4531_REG_DATA_LOW 0x04
|
||||
#define TSL4531_REG_DATA_HIGH 0x05
|
||||
#define TSL4531_REG_DEVICE_ID 0x0A
|
||||
|
||||
// TSL4531 Misc Values
|
||||
#define TSL4531_ON 0x03
|
||||
#define TSL4531_OFF 0x00
|
||||
|
||||
// Integration times in milliseconds
|
||||
#define TSL4531_INTEGRATION_TIME_100MS 120
|
||||
#define TSL4531_INTEGRATION_TIME_200MS 240
|
||||
#define TSL4531_INTEGRATION_TIME_400MS 480 // Default
|
||||
|
||||
static int write_register(i2c_dev_t* i2c_dev, uint8_t reg, uint8_t value)
|
||||
{
|
||||
reg = TSL4531_REG_COMMAND | reg;
|
||||
return i2c_slave_write(i2c_dev->bus, i2c_dev->addr, ®, &value, 1);
|
||||
}
|
||||
|
||||
static uint8_t read_register(i2c_dev_t* i2c_dev, uint8_t reg)
|
||||
{
|
||||
uint8_t data[1];
|
||||
reg = TSL4531_REG_COMMAND | reg;
|
||||
|
||||
if (i2c_slave_read(i2c_dev->bus, i2c_dev->addr, ®, data, 1))
|
||||
{
|
||||
printf("Error in tsl4531 read_register\n");
|
||||
}
|
||||
|
||||
return data[0];
|
||||
}
|
||||
|
||||
static uint16_t read_register_16(i2c_dev_t* i2c_dev, uint8_t low_register_addr)
|
||||
{
|
||||
uint16_t value = 0;
|
||||
uint8_t data[2];
|
||||
low_register_addr = TSL4531_REG_COMMAND | low_register_addr;
|
||||
|
||||
if (i2c_slave_read(i2c_dev->bus, i2c_dev->addr, &low_register_addr, data, 2))
|
||||
{
|
||||
printf("Error with i2c_slave_read in read_register_16\n");
|
||||
}
|
||||
|
||||
value = ((uint16_t)data[1] << 8) | (data[0]);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static int enable(tsl4531_t *device)
|
||||
{
|
||||
return write_register(&device->i2c_dev, TSL4531_REG_CONTROL, TSL4531_ON);
|
||||
}
|
||||
|
||||
static int disable(tsl4531_t *device)
|
||||
{
|
||||
return write_register(&device->i2c_dev, TSL4531_REG_CONTROL, TSL4531_OFF);
|
||||
}
|
||||
|
||||
void tsl4531_init(tsl4531_t *device)
|
||||
{
|
||||
if (enable(device))
|
||||
{
|
||||
printf("Error initializing tsl4531, the enable write failed\n");
|
||||
}
|
||||
|
||||
uint8_t control_reg = read_register(&device->i2c_dev, TSL4531_REG_CONTROL);
|
||||
|
||||
if (control_reg != TSL4531_ON) {
|
||||
printf("Error initializing tsl4531, control register wasn't set to ON\n");
|
||||
}
|
||||
|
||||
uint8_t idRegister = read_register(&device->i2c_dev, TSL4531_REG_DEVICE_ID);
|
||||
uint8_t id = (idRegister & 0xF0) >> 4;
|
||||
|
||||
if (id == TSL4531_PART_TSL45317) {
|
||||
device->part_id = TSL4531_PART_TSL45317;
|
||||
} else if (id == TSL4531_PART_TSL45313) {
|
||||
device->part_id = TSL4531_PART_TSL45313;
|
||||
} else if (id == TSL4531_PART_TSL45315) {
|
||||
device->part_id = TSL4531_PART_TSL45315;
|
||||
} else if (id == TSL4531_PART_TSL45311) {
|
||||
device->part_id = TSL4531_PART_TSL45311;
|
||||
} else {
|
||||
printf("Unknown part id for TSL4531 sensor: %u\n", id);
|
||||
}
|
||||
|
||||
disable(device);
|
||||
}
|
||||
|
||||
void tsl4531_set_integration_time(tsl4531_t *device, tsl4531_integration_time_t integration_time_id)
|
||||
{
|
||||
uint8_t power_save_bit = device->skip_power_save ? 0x08 : 0x00;
|
||||
uint8_t integration_time_bits = 0x03 & integration_time_id;
|
||||
uint8_t new_config_reg = power_save_bit | integration_time_bits;
|
||||
|
||||
enable(device);
|
||||
write_register(&device->i2c_dev, TSL4531_REG_CONFIG, new_config_reg);
|
||||
disable(device);
|
||||
|
||||
device->integration_time_id = integration_time_id;
|
||||
}
|
||||
|
||||
void tsl4531_set_power_save_skip(tsl4531_t *device, bool skip_power_save)
|
||||
{
|
||||
uint8_t power_save_bit = skip_power_save ? 0x08 : 0x00;
|
||||
uint8_t integration_time_bits = 0x03 & device->integration_time_id;
|
||||
uint8_t new_config_reg = power_save_bit | integration_time_bits;
|
||||
|
||||
enable(device);
|
||||
write_register(&device->i2c_dev, TSL4531_REG_CONFIG, new_config_reg);
|
||||
disable(device);
|
||||
|
||||
device->skip_power_save = skip_power_save;
|
||||
}
|
||||
|
||||
bool tsl4531_read_lux(tsl4531_t *device, uint16_t *lux)
|
||||
{
|
||||
bool success = true;
|
||||
uint16_t multiplier = 1;
|
||||
|
||||
enable(device);
|
||||
|
||||
switch (device->integration_time_id)
|
||||
{
|
||||
case TSL4531_INTEGRATION_100MS:
|
||||
multiplier = 4;
|
||||
vTaskDelay(TSL4531_INTEGRATION_TIME_100MS / portTICK_PERIOD_MS);
|
||||
break;
|
||||
case TSL4531_INTEGRATION_200MS:
|
||||
multiplier = 2;
|
||||
vTaskDelay(TSL4531_INTEGRATION_TIME_200MS / portTICK_PERIOD_MS);
|
||||
break;
|
||||
case TSL4531_INTEGRATION_400MS:
|
||||
multiplier = 1;
|
||||
vTaskDelay(TSL4531_INTEGRATION_TIME_400MS / portTICK_PERIOD_MS);
|
||||
break;
|
||||
default:
|
||||
multiplier = 1;
|
||||
vTaskDelay(TSL4531_INTEGRATION_TIME_400MS / portTICK_PERIOD_MS);
|
||||
break;
|
||||
}
|
||||
|
||||
uint16_t lux_data = read_register_16(&device->i2c_dev, TSL4531_REG_DATA_LOW);
|
||||
|
||||
disable(device);
|
||||
|
||||
*lux = multiplier * lux_data;
|
||||
|
||||
return success;
|
||||
}
|
||||
57
extras/tsl4531/tsl4531.h
Normal file
57
extras/tsl4531/tsl4531.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Part of esp-open-rtos
|
||||
* Copyright (C) 2017 Brian Schwind (https://github.com/bschwind)
|
||||
* BSD Licensed as described in the file LICENSE
|
||||
*/
|
||||
|
||||
#ifndef __TSL4531_H__
|
||||
#define __TSL4531_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <i2c/i2c.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// I2C Addresses
|
||||
typedef enum
|
||||
{
|
||||
TSL4531_I2C_ADDR = 0x29
|
||||
} tsl4531_i2c_addr_t;
|
||||
|
||||
// Integration time IDs
|
||||
typedef enum
|
||||
{
|
||||
TSL4531_INTEGRATION_100MS = 0x02,
|
||||
TSL4531_INTEGRATION_200MS = 0x01,
|
||||
TSL4531_INTEGRATION_400MS = 0x00 // Default
|
||||
} tsl4531_integration_time_t;
|
||||
|
||||
// Part IDs
|
||||
typedef enum
|
||||
{
|
||||
TSL4531_PART_TSL45317 = 0x08,
|
||||
TSL4531_PART_TSL45313 = 0x09,
|
||||
TSL4531_PART_TSL45315 = 0x0A,
|
||||
TSL4531_PART_TSL45311 = 0x0B
|
||||
} tsl4531_part_id_t;
|
||||
|
||||
typedef struct {
|
||||
i2c_dev_t i2c_dev;
|
||||
uint8_t integration_time_id;
|
||||
bool skip_power_save;
|
||||
tsl4531_part_id_t part_id;
|
||||
} tsl4531_t;
|
||||
|
||||
void tsl4531_init(tsl4531_t *device);
|
||||
void tsl4531_set_integration_time(tsl4531_t *device, tsl4531_integration_time_t integration_time_id);
|
||||
void tsl4531_set_power_save_skip(tsl4531_t *device, bool skip_power_save);
|
||||
bool tsl4531_read_lux(tsl4531_t *device, uint16_t *lux);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __TSL4531_H__
|
||||
|
|
@ -15,6 +15,8 @@
|
|||
#define PING_TIMEOUT 6000
|
||||
#define ROUNDTRIP 58
|
||||
|
||||
#define timeout_expired(start, len) ((uint32_t)(sdk_system_get_time() - (start)) >= (len))
|
||||
|
||||
void ultrasoinc_init(const ultrasonic_sensor_t *dev)
|
||||
{
|
||||
gpio_enable(dev->trigger_pin, GPIO_OUTPUT);
|
||||
|
|
@ -36,21 +38,21 @@ int32_t ultrasoinc_measure_cm(const ultrasonic_sensor_t *dev, uint32_t max_dista
|
|||
return ULTRASONIC_ERROR_PING;
|
||||
|
||||
// Wait for echo
|
||||
uint32_t timeout = sdk_system_get_time() + PING_TIMEOUT;
|
||||
uint32_t start = sdk_system_get_time();
|
||||
while (!gpio_read(dev->echo_pin))
|
||||
{
|
||||
if (sdk_system_get_time() >= timeout)
|
||||
if (timeout_expired(start, PING_TIMEOUT))
|
||||
return ULTRASONIC_ERROR_PING_TIMEOUT;
|
||||
}
|
||||
|
||||
// got echo, measuring
|
||||
uint32_t echo_start = sdk_system_get_time();
|
||||
uint32_t time = echo_start;
|
||||
timeout = echo_start + max_distance * ROUNDTRIP;
|
||||
uint32_t meas_timeout = echo_start + max_distance * ROUNDTRIP;
|
||||
while (gpio_read(dev->echo_pin))
|
||||
{
|
||||
time = sdk_system_get_time();
|
||||
if (time >= timeout)
|
||||
if (timeout_expired(echo_start, meas_timeout))
|
||||
return ULTRASONIC_ERROR_ECHO_TIMEOUT;
|
||||
}
|
||||
|
||||
|
|
|
|||
10
extras/wificfg/component.mk
Normal file
10
extras/wificfg/component.mk
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# Component makefile for extras/wificfg
|
||||
|
||||
# Expected anyone using wificfg includes it as 'wificfg/wificfg.h'
|
||||
INC_DIRS += $(wificfg_ROOT)..
|
||||
|
||||
# args for passing into compile rule generation
|
||||
wificfg_INC_DIR =
|
||||
wificfg_SRC_DIR = $(wificfg_ROOT)
|
||||
|
||||
$(eval $(call component_compile_rules,wificfg))
|
||||
30
extras/wificfg/content/challenge.html
Normal file
30
extras/wificfg/content/challenge.html
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
"<!DOCTYPE html><html lang=\"en\">"
|
||||
"<head>"
|
||||
"<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">"
|
||||
"<script src=\"/script.js\"></script>"
|
||||
"<title>",
|
||||
"</title>"
|
||||
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
|
||||
"</head>"
|
||||
"<body>"
|
||||
"<ul class=\"topnav\" id=\"myTopnav\">"
|
||||
"<li><a href=\"/\">Home</a></li>"
|
||||
"<li class=\"active\"><a href=\"/wificfg/\">WiFi Config</a></li>"
|
||||
"<li><a href=\"/wificfg/sta.html\">WiFi Station</a></li>"
|
||||
"<li><a href=\"/wificfg/ap.html\">WiFi Access Point</a></li>"
|
||||
"<li class=\"icon\">"
|
||||
"<a href=\"javascript:void(0);\" onclick=\"myFunction()\">☰</a>"
|
||||
"</li>"
|
||||
"</ul>"
|
||||
"<form action=\"/challenge.html\" method=\"post\">"
|
||||
"<fieldset>"
|
||||
"<legend>Unlock the configuration interface</legend>"
|
||||
"<dl class=\"dlh\">"
|
||||
"<dt><label for=\"pw\">Password</label></dt>"
|
||||
"<dd><input id=\"pw\" type=\"text\" maxlength=\"32\" name=\"cfg_password\" "
|
||||
"placeholder=\"unlock-password\" value=\"\"></dd>"
|
||||
"</dl>"
|
||||
"<center><input type=\"submit\" value=\"Unlock\"></center>"
|
||||
"</fieldset>"
|
||||
"</form>"
|
||||
"</body></html>"
|
||||
11
extras/wificfg/content/favicon.ico
Normal file
11
extras/wificfg/content/favicon.ico
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
"HTTP/1.1 200 \r\n"
|
||||
"Content-Type: image/svg+xml\r\n"
|
||||
"Cache-Control: max-age=900\r\n"
|
||||
"Transfer-Encoding: chunked\r\n"
|
||||
"Connection: close\r\n"
|
||||
"\r\n",
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"
|
||||
"<svg xmlns:svg=\"http://www.w3.org/2000/svg\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 48 48\" version=\"1.1\">"
|
||||
"<defs><linearGradient id=\"g1\" y2=\"248.63\" gradientUnits=\"userSpaceOnUse\" x2=\"153\" gradientTransform=\"matrix(.20068 0 0 .20068 -54.336 -1.0508)\" y1=\"15.424\" x1=\"99.777\"><stop style=\"stop-color:#0088FF\" offset=\"0\"/><stop style=\"stop-color:#b2dbff\" offset=\"1\"/></linearGradient></defs>"
|
||||
"<path style=\"stroke-linejoin:round;color:#000000;stroke:#aaaaaa;stroke-linecap:round;fill:url(#g1)\" d=\"m22.7 0.94747c-0.474 0.03238-0.934 0.10563-1.398 0.15883h-0.032l-1.112 6.068c-1.812 0.4127-3.517 1.1132-5.051 2.065l-4.988-3.59c-1.3485 1.0468-2.5754 2.2677-3.6536 3.59l3.4628 5.0517c-1.0514 1.606-1.842 3.441-2.2874 5.369v0.031l-6.0361 0.953c-0.1104 0.902-0.1589 1.833-0.1589 2.764 0 0.762 0.021 1.514 0.0953 2.256l6.0362 1.08c0.4293 2.096 1.2448 4.054 2.3827 5.782l-3.5899 4.924c1.0281 1.277 2.2151 2.439 3.4946 3.463l5.0833-3.494c1.776 1.133 3.759 1.928 5.909 2.319l0.953 6.004c0.677 0.062 1.372 0.064 2.065 0.064 0.979 0 1.914-0.037 2.859-0.159l1.144-6.132c2.041-0.507 3.958-1.389 5.623-2.573l4.893 3.558c1.268-1.079 2.429-2.32 3.431-3.653l-3.558-5.147c0.963-1.664 1.631-3.5 1.969-5.464l6.005-0.953c0.052-0.627 0.063-1.234 0.063-1.875 0-1.112-0.129-2.203-0.286-3.272l-6.099-1.112c-0.478-1.765-1.263-3.412-2.256-4.892l3.59-4.9245c-1.113-1.3608-2.382-2.618-3.781-3.6852l-5.178 3.5581c-1.488-0.8802-3.09-1.5556-4.829-1.9379l-0.953-6.0362c-0.868-0.102-1.742-0.15883-2.637-0.15883-0.242 0-0.491-0.00761-0.731 0-0.117 0.00371-0.232-0.00681-0.349 0-0.032 0.00184-0.064-0.00216-0.095 0zm0.826 15.44c0.116-0.006 0.231 0 0.349 0 3.761 0 6.83 3.07 6.83 6.831 0 3.76-3.069 6.798-6.83 6.798s-6.799-3.038-6.799-6.798c0-3.643 2.852-6.648 6.45-6.831z\"/>"
|
||||
"</svg>"
|
||||
8
extras/wificfg/content/script.js
Normal file
8
extras/wificfg/content/script.js
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
"HTTP/1.1 200 \r\n"
|
||||
"Content-Type: text/javascript\r\n"
|
||||
"Cache-Control: max-age=900\r\n"
|
||||
"Transfer-Encoding: chunked\r\n"
|
||||
"Connection: close\r\n"
|
||||
"\r\n",
|
||||
"function myFunction() { var x = document.getElementById(\"myTopnav\");"
|
||||
"if (x.className === \"topnav\") { x.className += \" responsive\"; } else { x.className = \"topnav\"; } }"
|
||||
19
extras/wificfg/content/style.css
Normal file
19
extras/wificfg/content/style.css
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
"HTTP/1.1 200 \r\n"
|
||||
"Content-Type: text/css\r\n"
|
||||
"Cache-Control: max-age=900\r\n"
|
||||
"Transfer-Encoding: chunked\r\n"
|
||||
"\r\n",
|
||||
".dlh dd,h1{font-weight:300}.dlh{font-size:0;text-align:center}"
|
||||
".dlh dd,.dlh dt{width:48%;width:calc(50% - 10px);margin:8px 0;display:inline-block;font-size:16px;vertical-align:middle}"
|
||||
".dlh dt{text-align:right;padding-right:10px}"
|
||||
".dlh dd{font-size:18px;text-align:left;padding-left:10px}"
|
||||
"ul.topnav{list-style-type:none;margin:0;padding:0;overflow:hidden;background-color:#bbb}"
|
||||
"ul.topnav li{float:left}"
|
||||
"ul.topnav li a{display:inline-block;color:#444;text-align:center;padding:14px 16px;text-decoration:none;transition:.3s;font-size:17px}"
|
||||
"ul.topnav li a:hover{background-color:#ddd}ul.topnav li.icon{display:none}"
|
||||
"@media screen and (max-width:680px){ul.topnav li:not(.active){display:none}ul.topnav li.icon{float:right;display:inline-block}ul.topnav.responsive{position:relative}ul.topnav.responsive li.icon{position:absolute;right:0;top:0}ul.topnav.responsive li{float:none;display:inline}ul.topnav.responsive li a{display:block;text-align:left}}"
|
||||
"html{min-height:100%}"
|
||||
"body{background:#d0e4f7;background:-moz-linear-gradient(top, #d0e4f7 0%, #73b1e7 24%, #0a77d5 50%, #539fe1 79%, #87bcea 100%);background:-webkit-linear-gradient(top, #d0e4f7 0%,#73b1e7 24%,#0a77d5 50%,#539fe1 79%,#87bcea 100%);background:linear-gradient(to bottom, #d0e4f7 0%,#73b1e7 24%,#0a77d5 50%,#539fe1 79%,#87bcea 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#d0e4f7', endColorstr='#87bcea',GradientType=0)}"
|
||||
"body{font-family:helvetica,arial,sans-serif;font-size:16px}"
|
||||
"h1{font-size:26px}"
|
||||
"p{font-size:14px}"
|
||||
18
extras/wificfg/content/tasks.html
Normal file
18
extras/wificfg/content/tasks.html
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
"<!DOCTYPE html><html lang=\"en\">"
|
||||
"<head>"
|
||||
"<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">"
|
||||
"<script src=\"/script.js\"></script>"
|
||||
"<title>",
|
||||
"</title>"
|
||||
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
|
||||
"</head>"
|
||||
"<body>"
|
||||
"<ul class=\"topnav\" id=\"myTopnav\">"
|
||||
"<li><a href=\"/\">Home</a></li>"
|
||||
"<li><a href=\"/wificfg/\">WiFi Config</a></li>"
|
||||
"<li class=\"active\"><a href=\"/tasks.html\">Tasks</a></li>"
|
||||
"<li class=\"icon\">"
|
||||
"<a href=\"javascript:void(0);\" onclick=\"myFunction()\">☰</a>"
|
||||
"</li>"
|
||||
"</ul>",
|
||||
"</body></html>"
|
||||
90
extras/wificfg/content/wificfg/ap.html
Normal file
90
extras/wificfg/content/wificfg/ap.html
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
"<!DOCTYPE html><html lang=\"en\">"
|
||||
"<head>"
|
||||
"<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">"
|
||||
"<script src=\"/script.js\"></script>"
|
||||
"<title>",
|
||||
"</title>"
|
||||
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
|
||||
"</head>"
|
||||
"<body>"
|
||||
"<ul class=\"topnav\" id=\"myTopnav\">"
|
||||
"<li><a href=\"/\">Home</a></li>"
|
||||
"<li><a href=\"/wificfg/\">WiFi Config</a></li>"
|
||||
"<li><a href=\"/wificfg/sta.html\">WiFi Station</a></li>"
|
||||
"<li class=\"active\"><a href=\"/wificfg/ap.html\">WiFi Access Point</a></li>"
|
||||
"<li class=\"icon\">"
|
||||
"<a href=\"javascript:void(0);\" onclick=\"myFunction()\">☰</a>"
|
||||
"</li>"
|
||||
"</ul>"
|
||||
"<form action=\"/wificfg/ap.html\" method=\"post\">"
|
||||
"<fieldset>"
|
||||
"<legend>WiFi Access Point configuration</legend>"
|
||||
"<dl class=\"dlh\">"
|
||||
"<dt><label for=\"enable\">Enable AP mode</label></dt>"
|
||||
"<dd><input id=\"enable\" type=\"checkbox\" name=\"ap_enable\" value=\"1\" ",
|
||||
" /></dd>"
|
||||
"<dt><label for=\"disable_if_sta\">Auto disable if station connection</label></dt>"
|
||||
"<dd><input id=\"hidden\" type=\"checkbox\" name=\"ap_disable_if_sta\" value=\"1\" ",
|
||||
" /></dd>"
|
||||
"<dt><label for=\"disabled_restarts\">Disabled restarts</label></dt>"
|
||||
"<dd><input id=\"disabled_restarts\" type=\"number\" size=\"2\" min=\"0\" step=\"1\" "
|
||||
"name=\"ap_disabled_restarts\" placeholder=\"0\" value=\"",
|
||||
"\"/></dd>"
|
||||
"<dt><label for=\"ssid\">SSID</label></dt>"
|
||||
"<dd><input id=\"ssid\" type=\"text\" minlength=\"1\" maxlength=\"31\" name=\"ap_ssid\" "
|
||||
"placeholder=\"my access point\" value=\"",
|
||||
"\"></dd>"
|
||||
"<dt><label for=\"ap\">Password</label></dt>"
|
||||
"<dd><input id=\"ap\" type=\"text\" minlength=\"8\" maxlength=\"63\" name=\"ap_password\" "
|
||||
"placeholder=\"password\" value=\"",
|
||||
"\"></dd>"
|
||||
"<dt><label for=\"hidden\">SSID Hidden</label></dt>"
|
||||
"<dd><input id=\"hidden\" type=\"checkbox\" name=\"ap_ssid_hidden\" value=\"1\" ",
|
||||
" /></dd>"
|
||||
"<dt><label for=\"ch\">Channel</label></dt>"
|
||||
"<dd><input id=\"ch\" type=\"number\" size=\"2\" min=\"1\" max=\"14\" step=\"1\" "
|
||||
"name=\"ap_channel\" placeholder=\"6\" value=\"",
|
||||
"\"></dd>"
|
||||
"<dt><label for=\"am\">Authentication Mode</label></dt>"
|
||||
"<dd><select id=\"am\" name=\"ap_authmode\">"
|
||||
"<option value=\"0\"",
|
||||
">Open</option>"
|
||||
"<option value=\"1\"",
|
||||
">WEP</option>"
|
||||
"<option value=\"2\"",
|
||||
">WPA_PSK</option>"
|
||||
"<option value=\"3\"",
|
||||
">WPA2_PSK</option>"
|
||||
"<option value=\"4\"",
|
||||
">WPA_WPA2_PSK</option></select></dd>"
|
||||
"<dt><label for=\"mc\">Max connections</label></dt>"
|
||||
"<dd><input id=\"mc\" type=\"number\" size=\"2\" min=\"1\" max=\"8\" step=\"1\" "
|
||||
"name=\"ap_max_conn\" placeholder=\"3\" value=\"",
|
||||
"\"></dd>"
|
||||
"<dt><label for=\"bi\">Beacon interval</label></dt>"
|
||||
"<dd><input id=\"bi\" type=\"number\" size=\"6\" min=\"0\" max=\"10000\" step=\"1\" "
|
||||
"name=\"ap_beacon_interval\" placeholder=\"100\" value=\"",
|
||||
"\"></dd>"
|
||||
"<dt><label for=\"ip\">IP Address</label></dt>"
|
||||
"<dd><input id=\"ip\" type=\"text\" maxlength=\"15\" size=\"15\" "
|
||||
"pattern=\"(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*){3}\" "
|
||||
"name=\"ap_ip_addr\" placeholder=\"192.168.4.1\" value=\"",
|
||||
"\"></dd>"
|
||||
"<dt><label for=\"nm\">Netmask</label></dt>"
|
||||
"<dd><input id=\"nm\" type=\"text\" maxlength=\"15\" size=\"15\" "
|
||||
"pattern=\"(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*){3}\" "
|
||||
"name=\"ap_netmask\" placeholder=\"255.255.255.0\" value=\"",
|
||||
"\"></dd>"
|
||||
"<dt><label for=\"dhcp\">DHCP Server Max Leases</label></dt>"
|
||||
"<dd><input id=\"dhcp\" type=\"number\" size=\"2\" min=\"0\" max=\"16\" step=\"1\" "
|
||||
"name=\"ap_dhcp_leases\" placeholder=\"4\" value=\"",
|
||||
"\"></dd>"
|
||||
"<dt><label for=\"dns_en\">DNS enabled</label></dt>"
|
||||
"<dd><input id=\"dns_en\" type=\"checkbox\" name=\"ap_dns\" value=\"1\" ",
|
||||
" /></dd>"
|
||||
"</dl>"
|
||||
"<center><input type=\"reset\"> <input type=\"submit\" value=\"Save\"></center>"
|
||||
"</fieldset>"
|
||||
"<input type=\"hidden\" name=\"done\">"
|
||||
"</form>"
|
||||
"</body></html>"
|
||||
52
extras/wificfg/content/wificfg/index.html
Normal file
52
extras/wificfg/content/wificfg/index.html
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
"<!DOCTYPE html><html lang=\"en\">"
|
||||
"<head>"
|
||||
"<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">"
|
||||
"<script src=\"/script.js\"></script>"
|
||||
"<title>",
|
||||
"</title>"
|
||||
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
|
||||
"</head>"
|
||||
"<body>"
|
||||
"<ul class=\"topnav\" id=\"myTopnav\">"
|
||||
"<li><a href=\"/\">Home</a></li>"
|
||||
"<li class=\"active\"><a href=\"/wificfg/\">WiFi Config</a></li>"
|
||||
"<li><a href=\"/wificfg/sta.html\">WiFi Station</a></li>"
|
||||
"<li><a href=\"/wificfg/ap.html\">WiFi Access Point</a></li>"
|
||||
"<li class=\"icon\">"
|
||||
"<a href=\"javascript:void(0);\" onclick=\"myFunction()\">☰</a>"
|
||||
"</li>"
|
||||
"</ul>"
|
||||
"<h1>WiFi Status</h1>"
|
||||
"<dl class=\"dlh\">",
|
||||
"</dl>"
|
||||
"<br>"
|
||||
"<form action=\"/wificfg/\" method=\"post\" onsubmit=\"return confirm('Are you sure you want to lock the configuration interface, and have you noted the password?');\">"
|
||||
"<fieldset>"
|
||||
"<legend>Lock the configuration interface</legend>"
|
||||
"<p>These WiFi configuration pages can be disabled for security on a shared network. If a password is supplied then they can be unlocked. Warning: if no password is supplied then it will not be possible to unlock these pages via this interface.</p>"
|
||||
"<dl class=\"dlh\">"
|
||||
"<dt><label for=\"pw\">Password</label></dt>"
|
||||
"<dd><input id=\"pw\" type=\"text\" maxlength=\"32\" name=\"cfg_password\" "
|
||||
"placeholder=\"unlock-password\" value=\"",
|
||||
"\"></dd>"
|
||||
"</dl>"
|
||||
"<input type=\"hidden\" name=\"cfg_enable\" value=\"0\">"
|
||||
"<center><input type=\"submit\" value=\"Lock\"></center>"
|
||||
"</fieldset>"
|
||||
"</form>"
|
||||
"<form action=\"/wificfg/restart.html\" method=\"post\" onsubmit=\"return confirm('Are you sure you want to restart the device?');\">"
|
||||
"<fieldset>"
|
||||
"<legend>Restart device</legend>"
|
||||
"<p>A restart is necessary for some changes to take effect.</p>"
|
||||
"<center><button>Restart</button></center>"
|
||||
"</fieldset></form>"
|
||||
"<form action=\"/wificfg/erase.html\" method=\"post\" onsubmit=\"return confirm('Are you sure you want to erase the configuration?');\">"
|
||||
"<fieldset>"
|
||||
"<legend>Erase configuration</legend>"
|
||||
"<p>Erases the device configuration stored in the flash memory and restarts the device. "
|
||||
"This might be useful to clear stored passwords and private configuration information."
|
||||
"</p>"
|
||||
"<center><button>Erase Configuration</button></center>"
|
||||
"</fieldset>"
|
||||
"</form>",
|
||||
"</body></html>"
|
||||
68
extras/wificfg/content/wificfg/sta.html
Normal file
68
extras/wificfg/content/wificfg/sta.html
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
"<!DOCTYPE html><html lang=\"en\">"
|
||||
"<head>"
|
||||
"<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">"
|
||||
"<script src=\"/script.js\"></script>"
|
||||
"<title>",
|
||||
"</title>"
|
||||
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
|
||||
"</head>"
|
||||
"<body>"
|
||||
"<ul class=\"topnav\" id=\"myTopnav\">"
|
||||
"<li><a href=\"/\">Home</a></li>"
|
||||
"<li><a href=\"/wificfg/\">WiFi Config</a></li>"
|
||||
"<li class=\"active\"><a href=\"/wificfg/sta.html\">WiFi Station</a></li>"
|
||||
"<li><a href=\"/wificfg/ap.html\">WiFi Access Point</a></li>"
|
||||
"<li class=\"icon\">"
|
||||
"<a href=\"javascript:void(0);\" onclick=\"myFunction()\">☰</a>"
|
||||
"</li>"
|
||||
"</ul>"
|
||||
"<form action=\"/wificfg/sta.html\" method=\"post\">"
|
||||
"<fieldset>"
|
||||
"<legend>WiFi Station configuration</legend>"
|
||||
"<dl class=\"dlh\">"
|
||||
"<dt><label for=\"enable\">Enable Station mode</label></dt>"
|
||||
"<dd><input id=\"enable\" type=\"checkbox\" name=\"sta_enable\" value=\"1\" ",
|
||||
" /></dd>"
|
||||
"<dt><label for=\"disabled_restarts\">Disabled restarts</label></dt>"
|
||||
"<dd><input id=\"disabled_restarts\" type=\"number\" size=\"2\" min=\"0\" step=\"1\" "
|
||||
"name=\"sta_disabled_restarts\" placeholder=\"0\" value=\"",
|
||||
"\" /></dd>"
|
||||
"<dt><label for=\"ssid\">SSID</label></dt>"
|
||||
"<dd><input id=\"ssid\" minlength=\"1\" maxlength=\"31\" type=\"text\" name=\"sta_ssid\" "
|
||||
"placeholder=\"my access point\" value=\"",
|
||||
"\"></dd>"
|
||||
"<dt><label for=\"pw\">Password</label></dt>"
|
||||
"<dd><input id=\"pw\" type=\"text\" minlength=\"8\" maxlength=\"63\" name=\"sta_password\" "
|
||||
"placeholder=\"password\" value=\"",
|
||||
"\"></dd>"
|
||||
"<dt><label for=\"hostname\">Hostname</label></dt>"
|
||||
"<dd><input id=\"hostname\" type=\"text\" maxlength=\"63\" name=\"hostname\" "
|
||||
"placeholder=\"device-hostname\" value=\"",
|
||||
"\"></dd>"
|
||||
"<dt><label for=\"dhcp\">Enable DHCP</label></dt>"
|
||||
"<dd><input id=\"dhcp\" type=\"radio\" name=\"sta_dhcp\" value=\"1\" ",
|
||||
" /></dd>"
|
||||
"<dt><label for=\"static\">Disable DHCP (static address below)</label></dt>"
|
||||
"<dd><input id=\"static\" type=\"radio\" name=\"sta_dhcp\" value=\"0\" ",
|
||||
" /></dd>"
|
||||
"<dt><label for=\"ip\">Static IP Address</label></dt>"
|
||||
"<dd><input id=\"ip\" type=\"text\" maxlength=\"15\" size=\"15\" "
|
||||
"pattern=\"(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*){3}\" "
|
||||
"name=\"sta_ip_addr\" placeholder=\"192.168.1.50\" value=\"",
|
||||
"\"></dd>"
|
||||
"<dt><label for=\"nm\">Static Netmask</label></dt>"
|
||||
"<dd><input id=\"nm\" type=\"text\" maxlength=\"15\" size=\"15\" "
|
||||
"pattern=\"(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*){3}\" "
|
||||
"name=\"sta_netmask\" placeholder=\"255.255.255.0\" value=\"",
|
||||
"\"></dd>"
|
||||
"<dt><label for=\"gw\">Static Gateway</label></dt>"
|
||||
"<dd><input id=\"gw\" type=\"text\" maxlength=\"15\" size=\"15\" "
|
||||
"pattern=\"(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*){3}\" "
|
||||
"name=\"sta_gateway\" placeholder=\"192.168.1.1\" value=\"",
|
||||
"\"></dd>"
|
||||
"</dl>"
|
||||
"<center><input type=\"reset\"> <input type=\"submit\" value=\"Save\"></center>"
|
||||
"</fieldset>"
|
||||
"<input type=\"hidden\" name=\"done\">"
|
||||
"</form>"
|
||||
"</body></html>"
|
||||
2022
extras/wificfg/wificfg.c
Normal file
2022
extras/wificfg/wificfg.c
Normal file
File diff suppressed because it is too large
Load diff
137
extras/wificfg/wificfg.h
Normal file
137
extras/wificfg/wificfg.h
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* WiFi configuration via a simple web server.
|
||||
*
|
||||
* Copyright (C) 2016 OurAirQuality.org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0, January 2004 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/
|
||||
*
|
||||
* 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 CONTRIBUTORS 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 WITH THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __WIFICFG_H__
|
||||
#define __WIFICFG_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Printf format used to initialize a default AP ssid. It is passed the last
|
||||
* three bytes of the mac address. This may be NULL to not default the ssid,
|
||||
* but the AP network will not run without a ssid.
|
||||
*/
|
||||
extern char *wificfg_default_ssid;
|
||||
|
||||
/*
|
||||
* A default password for the AP interface. This may be NULL to not default the
|
||||
* password, but the AP network will not run without a password. The minimum
|
||||
* length is 8 characters.
|
||||
*/
|
||||
extern char *wificfg_default_password;
|
||||
|
||||
/*
|
||||
* A default hostname printf format string. This may be NULL to not default the
|
||||
* hostname.
|
||||
*/
|
||||
extern char *wificfg_default_hostname;
|
||||
|
||||
/*
|
||||
* The web server parses the http method string in these enums. The ANY method
|
||||
* is only use for dispatch. The method enum is passed to the handler functions.
|
||||
*/
|
||||
typedef enum {
|
||||
HTTP_METHOD_GET,
|
||||
HTTP_METHOD_POST,
|
||||
HTTP_METHOD_HEAD,
|
||||
HTTP_METHOD_OTHER,
|
||||
HTTP_METHOD_ANY,
|
||||
} wificfg_method;
|
||||
|
||||
/*
|
||||
* The web server parses these content-type header values. This is passed to the
|
||||
* dispatch function.
|
||||
*/
|
||||
typedef enum {
|
||||
HTTP_CONTENT_TYPE_WWW_FORM_URLENCODED,
|
||||
HTTP_CONTENT_TYPE_OTHER
|
||||
} wificfg_content_type;
|
||||
|
||||
/*
|
||||
* The function signature for the http server request handler functions.
|
||||
*
|
||||
* The buffer, with its length, is usable by the handler.
|
||||
*/
|
||||
typedef int (* wificfg_handler)(int s, wificfg_method method,
|
||||
uint32_t content_length,
|
||||
wificfg_content_type content_type,
|
||||
char *buf, size_t len);
|
||||
|
||||
typedef struct {
|
||||
const char *path;
|
||||
wificfg_method method;
|
||||
wificfg_handler handler;
|
||||
bool secure;
|
||||
} wificfg_dispatch;
|
||||
|
||||
|
||||
/*
|
||||
* Start the Wifi Configuration http server task. The IP port number
|
||||
* and a path dispatch list are needed. The dispatch list can not be
|
||||
* stack allocated as it is passed to another task.
|
||||
*/
|
||||
void wificfg_init(uint32_t port, const wificfg_dispatch *dispatch);
|
||||
|
||||
/*
|
||||
* Support for reading a form name or value from the socket. The name or value
|
||||
* is truncated to the buffer length. The number of characters read is limited
|
||||
* to the remainder which is updated. The 'valp' flag is set if a value follows.
|
||||
*/
|
||||
int wificfg_form_name_value(int s, bool *valp, size_t *rem, char *buf, size_t len);
|
||||
|
||||
/* Support for form url-encoding decoder. */
|
||||
void wificfg_form_url_decode(char *string);
|
||||
|
||||
/* Support for html-escaping of form values. */
|
||||
void wificfg_html_escape(char *string, char *buf, size_t len);
|
||||
|
||||
/* Support for writing a string in a response. */
|
||||
int wificfg_write_string(int s, const char *str);
|
||||
|
||||
/* Support for writing a string in a response, with chunk transfer encoding.
|
||||
* An optional buffer may be supplied to use to construct a chunk with the
|
||||
* header and trailer, reducing the number of write() calls, and the str may be
|
||||
* at the start of this buffer.
|
||||
*/
|
||||
int wificfg_write_string_chunk(int s, const char *str, char *buf, size_t len);
|
||||
|
||||
/* Write a chunk transfer encoding end marker. */
|
||||
int wificfg_write_chunk_end(int s);
|
||||
|
||||
/* Write a chunk offset 4 bytes into the buffer. */
|
||||
int wificfg_write_buffer_chunk(int s, char *buf);
|
||||
|
||||
/* Write a html title meta data, using the hostname or AP SSI. */
|
||||
int wificfg_write_html_title(int s, char *buf, size_t len, const char *str);
|
||||
|
||||
/* Callback to notify the wificfg logic that a station connection has been
|
||||
* successfully established. It might use this to disable the AP interface after
|
||||
* a restart.
|
||||
*/
|
||||
void wificfg_got_sta_connect(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __WIFICFG_H__
|
||||
|
|
@ -60,7 +60,7 @@ volatile uint32_t dma_isr_counter = 0;
|
|||
|
||||
static volatile bool i2s_dma_processing = false;
|
||||
|
||||
static void dma_isr_handler(void)
|
||||
static void dma_isr_handler(void *arg)
|
||||
{
|
||||
if (i2s_dma_is_eof_interrupt()) {
|
||||
#ifdef WS2812_I2S_DEBUG
|
||||
|
|
@ -145,7 +145,7 @@ void ws2812_i2s_init(uint32_t pixels_number)
|
|||
debug("i2s clock dividers, bclk=%d, clkm=%d\n",
|
||||
clock_div.bclk_div, clock_div.clkm_div);
|
||||
|
||||
i2s_dma_init(dma_isr_handler, clock_div, i2s_pins);
|
||||
i2s_dma_init(dma_isr_handler, NULL, clock_div, i2s_pins);
|
||||
}
|
||||
|
||||
const IRAM_DATA int16_t bitpatterns[16] =
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue