Merge remote-tracking branch 'upstream/master'

This commit is contained in:
BruceHsu 2017-10-03 01:35:25 +08:00
commit 56ba21c081
299 changed files with 16208 additions and 13185 deletions

181
extras/ad770x/ad770x.c Normal file
View 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
View 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_ */

View 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))

View file

@ -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, &reg, (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, &reg, 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);
}

View file

@ -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
View 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
View 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_ */

View 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))

View file

@ -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, &reg, 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, &reg, &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, &reg, 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, &reg, &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, &current_command, portMAX_DELAY) == pdTRUE) {
if (xQueueReceive(bmp180_rx_queue[dev->bus], &current_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);
}

View file

@ -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

View file

@ -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;
}

View file

@ -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;

View file

@ -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];

View file

@ -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

View file

@ -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, &reg, &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, &reg, &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, &reg , 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, &reg, 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, &reg, buf, len);
}

View file

@ -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

View file

@ -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, &reg, 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, &reg, 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);
}

View file

@ -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

View file

@ -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)

View file

@ -1,7 +1,7 @@
/*---------------------------------------------------------------------------/
/ FatFs - FAT file system module configuration file
/---------------------------------------------------------------------------*/
#define _FFCONF 68020 /* Revision ID */
#define _FFCONF 68300 /* Revision ID */
/*---------------------------------------------------------------------------/
/ Function Configurations

View file

@ -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

View file

@ -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

View file

@ -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, &reg, &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, &reg, &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, &reg, (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, &reg, 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;

View file

@ -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
}

View file

@ -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;

View file

@ -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;

View file

@ -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, &reg_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, &reg_addr, reg_data, 1);
err = i2c_slave_read(slave_addr, &reg_addr, &reg_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

View file

@ -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;
}

View file

@ -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
}

View file

@ -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);

View file

@ -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.

View file

@ -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, &reg, 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, &reg, 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);
}

View file

@ -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

View file

@ -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

View file

@ -29,7 +29,7 @@
#if defined(MBEDTLS_NET_C)
#include "mbedtls/net.h"
#include "mbedtls/net_sockets.h"
#include <string.h>

View file

@ -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);
}

View file

@ -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

View 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))

View 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
}

View 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

View file

@ -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, &reg, 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, &reg, 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, &reg, 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, &reg, 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, &reg, 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, &reg, 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, &reg, 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);

View file

@ -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

View file

@ -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)

View file

@ -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)))
{

View file

@ -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, &reg, &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, &reg, &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, &reg, 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;
}

View file

@ -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
}

View file

@ -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);
}

View file

@ -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
}

View 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
View 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
View 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_ */

View file

@ -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;

View file

@ -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);

View file

@ -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

View file

@ -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;
}

View file

@ -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
View 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.

View 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
View 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;
}

View 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_ */

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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__

View file

@ -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

View file

@ -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 , &reg, 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
{

View file

@ -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

View file

@ -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

View file

@ -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, &reg, &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, &reg, 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)

View file

@ -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;

View 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
View 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, &reg, &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, &reg, 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
View 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__

View file

@ -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;
}

View 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))

View 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()\">&#9776;</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>"

View 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>"

View 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\"; } }"

View 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}"

View 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()\">&#9776;</a>"
"</li>"
"</ul>",
"</body></html>"

View 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()\">&#9776;</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\">&nbsp;<input type=\"submit\" value=\"Save\"></center>"
"</fieldset>"
"<input type=\"hidden\" name=\"done\">"
"</form>"
"</body></html>"

View 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()\">&#9776;</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>"

View 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()\">&#9776;</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\">&nbsp;<input type=\"submit\" value=\"Save\"></center>"
"</fieldset>"
"<input type=\"hidden\" name=\"done\">"
"</form>"
"</body></html>"

2022
extras/wificfg/wificfg.c Normal file

File diff suppressed because it is too large Load diff

137
extras/wificfg/wificfg.h Normal file
View 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__

View file

@ -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] =