Adicionar primeiro
This commit is contained in:
23
components/peripherals/CMakeLists.txt
Executable file
23
components/peripherals/CMakeLists.txt
Executable file
@@ -0,0 +1,23 @@
|
||||
set(srcs
|
||||
"src/adc.c"
|
||||
"src/adc121s021_dma.c"
|
||||
"src/peripherals.c"
|
||||
"src/led.c"
|
||||
"src/buzzer.c"
|
||||
"src/pilot.c"
|
||||
"src/proximity.c"
|
||||
"src/ac_relay.c"
|
||||
"src/energy_meter.c"
|
||||
"src/socket_lock.c"
|
||||
"src/rcm.c"
|
||||
"src/aux_io.c"
|
||||
"src/onewire.c"
|
||||
"src/ds18x20.c"
|
||||
"src/temp_sensor.c"
|
||||
"src/ntc_sensor.c"
|
||||
)
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS "include"
|
||||
PRIV_REQUIRES nvs_flash driver esp_adc esp_timer
|
||||
REQUIRES config evse api meter ntc_driver)
|
||||
25
components/peripherals/include/ac_relay.h
Executable file
25
components/peripherals/include/ac_relay.h
Executable file
@@ -0,0 +1,25 @@
|
||||
#ifndef AC_RELAY_H_
|
||||
#define AC_RELAY_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* @brief Inicializa o relé de corrente alternada.
|
||||
*/
|
||||
void ac_relay_init(void);
|
||||
|
||||
/**
|
||||
* @brief Define o estado do relé de corrente alternada.
|
||||
*
|
||||
* @param state true para ligar, false para desligar.
|
||||
*/
|
||||
void ac_relay_set_state(bool state);
|
||||
|
||||
/**
|
||||
* @brief Retorna o estado atual do relé de corrente alternada.
|
||||
*
|
||||
* @return true se estiver ligado, false se desligado.
|
||||
*/
|
||||
bool ac_relay_get_state(void);
|
||||
|
||||
#endif /* AC_RELAY_H_ */
|
||||
14
components/peripherals/include/adc.h
Executable file
14
components/peripherals/include/adc.h
Executable file
@@ -0,0 +1,14 @@
|
||||
#ifndef ADC_H_
|
||||
#define ADC_H_
|
||||
|
||||
#include "esp_adc/adc_oneshot.h"
|
||||
#include "esp_adc/adc_cali.h"
|
||||
#include "esp_adc/adc_cali_scheme.h"
|
||||
|
||||
extern adc_oneshot_unit_handle_t adc_handle;
|
||||
|
||||
extern adc_cali_handle_t adc_cali_handle;
|
||||
|
||||
void adc_init(void);
|
||||
|
||||
#endif /* ADC_H_ */
|
||||
12
components/peripherals/include/adc121s021_dma.h
Executable file
12
components/peripherals/include/adc121s021_dma.h
Executable file
@@ -0,0 +1,12 @@
|
||||
#ifndef ADC_DMA_H_
|
||||
#define ADC_DMA_H_
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void adc121s021_dma_init(void);
|
||||
bool adc121s021_dma_get_sample(uint16_t *sample);
|
||||
|
||||
|
||||
#endif /* ADC_DMA_h_ */
|
||||
39
components/peripherals/include/aux_io.h
Executable file
39
components/peripherals/include/aux_io.h
Executable file
@@ -0,0 +1,39 @@
|
||||
#ifndef AUX_IO_H_
|
||||
#define AUX_IO_H_
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
/**
|
||||
* @brief Initialize aux
|
||||
*
|
||||
*/
|
||||
void aux_init(void);
|
||||
|
||||
/**
|
||||
* @brief Read digital input
|
||||
*
|
||||
* @param name
|
||||
* @param value
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t aux_read(const char *name, bool *value);
|
||||
|
||||
/**
|
||||
* @brief Write digial output
|
||||
*
|
||||
* @param name
|
||||
* @param value
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t aux_write(const char *name, bool value);
|
||||
|
||||
/**
|
||||
* @brief Read analog input
|
||||
*
|
||||
* @param name
|
||||
* @param value
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t aux_analog_read(const char *name, int *value);
|
||||
|
||||
#endif /* AUX_IO_H_ */
|
||||
22
components/peripherals/include/buzzer.h
Executable file
22
components/peripherals/include/buzzer.h
Executable file
@@ -0,0 +1,22 @@
|
||||
#ifndef BUZZER_H_
|
||||
#define BUZZER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief Inicializa o buzzer e inicia monitoramento automático do estado EVSE.
|
||||
*/
|
||||
void buzzer_init(void);
|
||||
|
||||
/**
|
||||
* @brief Liga e desliga o buzzer manualmente (uso interno ou testes).
|
||||
*/
|
||||
void buzzer_on(void);
|
||||
void buzzer_off(void);
|
||||
|
||||
/**
|
||||
* @brief Ativa o buzzer por um período fixo (em milissegundos).
|
||||
*/
|
||||
void buzzer_beep_ms(uint16_t ms);
|
||||
|
||||
#endif /* BUZZER_H_ */
|
||||
179
components/peripherals/include/energy_meter.h
Executable file
179
components/peripherals/include/energy_meter.h
Executable file
@@ -0,0 +1,179 @@
|
||||
#ifndef ENERGY_METER_H_
|
||||
#define ENERGY_METER_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
/**
|
||||
* @brief Grid energy meter model
|
||||
*
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ENERGY_METER_NONE,
|
||||
ENERGY_METER_ORNO_515,
|
||||
ENERGY_METER_ORNO_517,
|
||||
} meter_model_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize energy meter
|
||||
*
|
||||
*/
|
||||
void energy_meter_init(void);
|
||||
|
||||
/**
|
||||
* @brief Get state of energy meter
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
bool meter_get_state(void);
|
||||
|
||||
/**
|
||||
* @brief Get mode of energy meter, stored in NVS
|
||||
*
|
||||
* @return meter_model_t
|
||||
*/
|
||||
meter_model_t meter_get_model(void);
|
||||
|
||||
/**
|
||||
* @brief Set mode of energy meter, stored in NVS
|
||||
*
|
||||
* @param mode
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t meter_set_model(meter_model_t mode);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Start energy meter session, if not started
|
||||
*
|
||||
*/
|
||||
void energy_meter_start_session(void);
|
||||
|
||||
/**
|
||||
* @brief Stop energy meter session, if not stopped
|
||||
*
|
||||
*/
|
||||
void energy_meter_stop_session(void);
|
||||
|
||||
/**
|
||||
* @brief Process energy meter
|
||||
*
|
||||
* @param charging
|
||||
* @param charging_current
|
||||
*/
|
||||
void energy_meter_process(bool charging, uint16_t charging_current);
|
||||
|
||||
/**
|
||||
* @brief Get session actual power
|
||||
*
|
||||
* @return Power in W
|
||||
*/
|
||||
uint32_t energy_meter_get_power(void);
|
||||
|
||||
/**
|
||||
* @brief Get session time
|
||||
*
|
||||
* @return Time in s
|
||||
*/
|
||||
uint32_t energy_meter_get_session_time(void);
|
||||
|
||||
/**
|
||||
* @brief Get charging time
|
||||
*
|
||||
* @return Time in s
|
||||
*/
|
||||
uint32_t energy_meter_get_charging_time(void);
|
||||
|
||||
/**
|
||||
* @brief Get session consumption
|
||||
*
|
||||
* @return Consumption in Wh
|
||||
*/
|
||||
uint32_t energy_meter_get_consumption(void);
|
||||
|
||||
/**
|
||||
* @brief After energy_meter_process, get current measured voltage
|
||||
*
|
||||
* @param voltage Output array of 3 items, values in V
|
||||
*/
|
||||
void energy_meter_get_voltage(float *voltage);
|
||||
|
||||
/**
|
||||
* @brief Cet current measured voltage on L1
|
||||
*
|
||||
* @return Voltage in V
|
||||
*/
|
||||
float energy_meter_get_l1_voltage(void);
|
||||
|
||||
/**
|
||||
* @brief Cet current measured voltage on L2
|
||||
*
|
||||
* @return Voltage in V
|
||||
*/
|
||||
float energy_meter_get_l2_voltage(void);
|
||||
|
||||
/**
|
||||
* @brief Cet current measured voltage on L3
|
||||
*
|
||||
* @return Voltage in V
|
||||
*/
|
||||
float energy_meter_get_l3_voltage(void);
|
||||
|
||||
/**
|
||||
* @brief After energy_meter_process, get current measured current
|
||||
*
|
||||
* @param voltage Output array of 3 items, values in A
|
||||
*/
|
||||
void energy_meter_get_current(float *current);
|
||||
|
||||
/**
|
||||
* @brief Cet current measured current on L1
|
||||
*
|
||||
* @return Voltage in V
|
||||
*/
|
||||
float energy_meter_get_l1_current(void);
|
||||
|
||||
/**
|
||||
* @brief Cet current measured current on L2
|
||||
*
|
||||
* @return Voltage in V
|
||||
*/
|
||||
float energy_meter_get_l2_current(void);
|
||||
|
||||
/**
|
||||
* @brief Cet current measured current on L3
|
||||
*
|
||||
* @return Voltage in V
|
||||
*/
|
||||
float energy_meter_get_l3_current(void);
|
||||
|
||||
/**
|
||||
* @brief Serialize to string
|
||||
*
|
||||
* @param mode
|
||||
* @return const char*
|
||||
*/
|
||||
const char *meter_model_to_str(meter_model_t mode);
|
||||
|
||||
/**
|
||||
* @brief Parse from string
|
||||
*
|
||||
* @param str
|
||||
* @return meter_model_t
|
||||
*/
|
||||
meter_model_t meter_str_to_model(const char *str);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Serialize to string
|
||||
*
|
||||
* @param mode
|
||||
* @return const char*
|
||||
*/
|
||||
const char *meter_state_to_str(bool state);
|
||||
|
||||
|
||||
#endif /* ENERGY_METER_H_ */
|
||||
53
components/peripherals/include/led.h
Executable file
53
components/peripherals/include/led.h
Executable file
@@ -0,0 +1,53 @@
|
||||
#ifndef LED_H_
|
||||
#define LED_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* @brief Identificadores dos LEDs disponíveis no hardware
|
||||
*/
|
||||
typedef enum {
|
||||
LED_ID_STOP,
|
||||
LED_ID_CHARGING,
|
||||
LED_ID_ERROR,
|
||||
LED_ID_MAX
|
||||
} led_id_t;
|
||||
|
||||
/**
|
||||
* @brief Padrões de comportamento possíveis para os LEDs
|
||||
*/
|
||||
typedef enum {
|
||||
LED_PATTERN_OFF, ///< LED sempre desligado
|
||||
LED_PATTERN_ON, ///< LED sempre ligado
|
||||
LED_PATTERN_BLINK, ///< Pisca com ciclo padrão (500ms on / 500ms off)
|
||||
LED_PATTERN_BLINK_FAST, ///< Pisca rápido (200ms / 200ms)
|
||||
LED_PATTERN_BLINK_SLOW, ///< Pisca lento (300ms / 1700ms)
|
||||
LED_PATTERN_CHARGING_EFFECT ///< Efeito visual para carregamento (2s on / 1s off)
|
||||
} led_pattern_t;
|
||||
|
||||
/**
|
||||
* @brief Inicializa os LEDs com base na configuração da placa
|
||||
* Deve ser chamada uma única vez na inicialização do sistema.
|
||||
*/
|
||||
void led_init(void);
|
||||
|
||||
/**
|
||||
* @brief Define diretamente o tempo ligado/desligado de um LED.
|
||||
* Pode ser usado para padrões personalizados.
|
||||
*
|
||||
* @param led_id Identificador do LED (ver enum led_id_t)
|
||||
* @param ontime Tempo ligado em milissegundos
|
||||
* @param offtime Tempo desligado em milissegundos
|
||||
*/
|
||||
void led_set_state(led_id_t led_id, uint16_t ontime, uint16_t offtime);
|
||||
|
||||
/**
|
||||
* @brief Aplica um dos padrões de piscar definidos ao LED
|
||||
*
|
||||
* @param led_id Identificador do LED (ver enum led_id_t)
|
||||
* @param pattern Padrão desejado (ver enum led_pattern_t)
|
||||
*/
|
||||
void led_apply_pattern(led_id_t led_id, led_pattern_t pattern);
|
||||
|
||||
#endif /* LED_H_ */
|
||||
83
components/peripherals/include/lm75a.h
Normal file
83
components/peripherals/include/lm75a.h
Normal file
@@ -0,0 +1,83 @@
|
||||
#ifndef LM75A_H
|
||||
#define LM75A_H
|
||||
|
||||
#include "esp_err.h" // Para o uso de tipos de erro do ESP-IDF, caso esteja utilizando.
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Inicializa o sensor LM75A.
|
||||
*
|
||||
* Configura o sensor para leitura e define os pinos de comunicação.
|
||||
*/
|
||||
esp_err_t lm75a_init(void);
|
||||
|
||||
/**
|
||||
* @brief Desinicializa o sensor LM75A.
|
||||
*
|
||||
* Libera os recursos usados pelo sensor.
|
||||
*/
|
||||
esp_err_t lm75a_deinit(void);
|
||||
|
||||
/**
|
||||
* @brief Lê a temperatura do LM75A.
|
||||
*
|
||||
* @param show Se for 1, a temperatura será exibida em algum tipo de log ou interface.
|
||||
* Se for 0, o valor é apenas retornado sem exibição.
|
||||
* @return A temperatura lida em graus Celsius.
|
||||
*/
|
||||
float lm75a_read_temperature(int show);
|
||||
|
||||
/**
|
||||
* @brief Define o valor do limite de temperatura (T_OS) para o sensor LM75A.
|
||||
*
|
||||
* @param tos O limite de temperatura de sobrecarga (T_OS) em graus Celsius.
|
||||
* @return ESP_OK em caso de sucesso ou código de erro se falhar.
|
||||
*/
|
||||
esp_err_t lm75a_set_tos(int tos);
|
||||
|
||||
/**
|
||||
* @brief Define o valor do limite de temperatura de histerese (T_HYS) para o sensor LM75A.
|
||||
*
|
||||
* @param thys O limite de histerese de temperatura (T_HYS) em graus Celsius.
|
||||
* @return ESP_OK em caso de sucesso ou código de erro se falhar.
|
||||
*/
|
||||
esp_err_t lm75a_set_thys(int thys);
|
||||
|
||||
/**
|
||||
* @brief Obtém o limite de temperatura de sobrecarga (T_OS) do sensor LM75A.
|
||||
*
|
||||
* @return O valor atual de T_OS em graus Celsius.
|
||||
*/
|
||||
int lm75a_get_tos(void);
|
||||
|
||||
/**
|
||||
* @brief Obtém o limite de temperatura de histerese (T_HYS) do sensor LM75A.
|
||||
*
|
||||
* @return O valor atual de T_HYS em graus Celsius.
|
||||
*/
|
||||
int lm75a_get_thys(void);
|
||||
|
||||
/**
|
||||
* @brief Habilita ou desabilita a interrupção do LM75A.
|
||||
*
|
||||
* @param en 1 para habilitar a interrupção, 0 para desabilitar.
|
||||
* @return ESP_OK em caso de sucesso ou código de erro se falhar.
|
||||
*/
|
||||
esp_err_t lm75a_set_int(int en);
|
||||
|
||||
/**
|
||||
* @brief Obtém o estado do pino OS (Overtemperature Shutdown) do LM75A.
|
||||
*
|
||||
* @return 1 se o pino OS estiver ativo (indica que a temperatura de sobrecarga foi atingida),
|
||||
* 0 caso contrário.
|
||||
*/
|
||||
int lm75a_get_osio(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LM75A_H */
|
||||
17
components/peripherals/include/ntc_sensor.h
Executable file
17
components/peripherals/include/ntc_sensor.h
Executable file
@@ -0,0 +1,17 @@
|
||||
#ifndef NTC_SENSOR_H_
|
||||
#define NTC_SENSOR_H_
|
||||
|
||||
/**
|
||||
* @brief Initialize ntc senso
|
||||
*
|
||||
*/
|
||||
void ntc_sensor_init(void);
|
||||
|
||||
/**
|
||||
* @brief Return temperature after temp_sensor_measure
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
float ntc_temp_sensor(void);
|
||||
|
||||
#endif /* NTC_SENSOR_H_ */
|
||||
6
components/peripherals/include/peripherals.h
Executable file
6
components/peripherals/include/peripherals.h
Executable file
@@ -0,0 +1,6 @@
|
||||
#ifndef PERIPHERALS_H
|
||||
#define PERIPHERALS_H
|
||||
|
||||
void peripherals_init(void);
|
||||
|
||||
#endif /* PERIPHERALS_H */
|
||||
69
components/peripherals/include/pilot.h
Executable file
69
components/peripherals/include/pilot.h
Executable file
@@ -0,0 +1,69 @@
|
||||
#ifndef PILOT_H_
|
||||
#define PILOT_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief Níveis categóricos de tensão no sinal CP (Control Pilot)
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
PILOT_VOLTAGE_12, ///< Estado A: +12V
|
||||
PILOT_VOLTAGE_9, ///< Estado B: +9V
|
||||
PILOT_VOLTAGE_6, ///< Estado C: +6V
|
||||
PILOT_VOLTAGE_3, ///< Estado D: +3V
|
||||
PILOT_VOLTAGE_1 ///< Estado E/F: abaixo de 3V
|
||||
} pilot_voltage_t;
|
||||
|
||||
/**
|
||||
* @brief Inicializa o driver do sinal Pilot
|
||||
*/
|
||||
void pilot_init(void);
|
||||
|
||||
/**
|
||||
* @brief Define o nível do Pilot: +12V ou -12V
|
||||
*
|
||||
* @param level true = +12V, false = -12V
|
||||
*/
|
||||
void pilot_set_level(bool level);
|
||||
|
||||
/**
|
||||
* @brief Ativa o PWM do Pilot com corrente limitada
|
||||
*
|
||||
* @param amps Corrente em décimos de ampère (ex: 160 = 16A)
|
||||
*/
|
||||
void pilot_set_amps(uint16_t amps);
|
||||
|
||||
/**
|
||||
* @brief Mede o nível de tensão do Pilot e detecta -12V
|
||||
*
|
||||
* @param up_voltage Valor categórico da tensão positiva
|
||||
* @param down_voltage_n12 true se o nível negativo atingir -12V
|
||||
*/
|
||||
void pilot_measure(pilot_voltage_t *up_voltage, bool *down_voltage_n12);
|
||||
|
||||
/**
|
||||
* @brief Retorna o estado lógico atual do Pilot (nível alto = +12V)
|
||||
*
|
||||
* @return true se nível atual for +12V, false se for -12V
|
||||
*/
|
||||
bool pilot_get_state(void);
|
||||
|
||||
/**
|
||||
* @brief Cache interno opcional dos níveis de tensão reais do Pilot
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t high_mv; ///< Pico positivo medido (mV)
|
||||
uint16_t low_mv; ///< Pico negativo medido (mV)
|
||||
} pilot_voltage_cache_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PILOT_H_ */
|
||||
19
components/peripherals/include/proximity.h
Executable file
19
components/peripherals/include/proximity.h
Executable file
@@ -0,0 +1,19 @@
|
||||
#ifndef PROXIMITY_H_
|
||||
#define PROXIMITY_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief Initialize proximity check
|
||||
*
|
||||
*/
|
||||
void proximity_init(void);
|
||||
|
||||
/**
|
||||
* @brief Return measured value of max current on PP
|
||||
*
|
||||
* @return current in A
|
||||
*/
|
||||
uint8_t proximity_get_max_current(void);
|
||||
|
||||
#endif /* PROXIMITY_H_ */
|
||||
28
components/peripherals/include/rcm.h
Executable file
28
components/peripherals/include/rcm.h
Executable file
@@ -0,0 +1,28 @@
|
||||
#ifndef RCM_H_
|
||||
#define RCM_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* @brief Initialize residual current monitor
|
||||
*
|
||||
*/
|
||||
void rcm_init(void);
|
||||
|
||||
/**
|
||||
* @brief Test residual current monitor
|
||||
*
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool rcm_test(void);
|
||||
|
||||
/**
|
||||
* @brief Residual current monitor was detected leakage
|
||||
*
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool rcm_is_triggered(void);
|
||||
|
||||
#endif /* RCM_H_ */
|
||||
94
components/peripherals/include/socket_lock.h
Executable file
94
components/peripherals/include/socket_lock.h
Executable file
@@ -0,0 +1,94 @@
|
||||
#ifndef SOCKED_LOCK_H_
|
||||
#define SOCKED_LOCK_H_
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SOCKED_LOCK_STATUS_IDLE,
|
||||
SOCKED_LOCK_STATUS_OPERATING,
|
||||
SOCKED_LOCK_STATUS_LOCKING_FAIL,
|
||||
SOCKED_LOCK_STATUS_UNLOCKING_FAIL
|
||||
} socket_lock_status_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize socket lock
|
||||
*
|
||||
*/
|
||||
void socket_lock_init(void);
|
||||
|
||||
/**
|
||||
* @brief Get socket lock detection on high, stored in NVS
|
||||
*
|
||||
* @return true when locked has zero resistance
|
||||
* @return false when unlocked has zero resistance
|
||||
*/
|
||||
bool socket_lock_is_detection_high(void);
|
||||
|
||||
/**
|
||||
* @brief Set socket lock detection on high, stored in NVS
|
||||
*
|
||||
* @param detection_high
|
||||
*/
|
||||
void socket_lock_set_detection_high(bool detection_high);
|
||||
|
||||
/**
|
||||
* @brief Get socket lock operating time
|
||||
*
|
||||
* @return time in ms
|
||||
*/
|
||||
uint16_t socket_lock_get_operating_time(void);
|
||||
|
||||
/**
|
||||
* @brief Set socket lock operating time
|
||||
*
|
||||
* @param operating_time - time in ms
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t socket_lock_set_operating_time(uint16_t operating_time);
|
||||
|
||||
/**
|
||||
* @brief Get socket lock retry count
|
||||
*
|
||||
* @return retry count
|
||||
*/
|
||||
uint8_t socket_lock_get_retry_count(void);
|
||||
|
||||
/**
|
||||
* @brief Set socket lock retry count
|
||||
*
|
||||
* @param retry_count
|
||||
*/
|
||||
void socket_lock_set_retry_count(uint8_t retry_count);
|
||||
|
||||
/**
|
||||
* @brief Get socket lock break time
|
||||
*
|
||||
* @return time in ms
|
||||
*/
|
||||
uint16_t socket_lock_get_break_time(void);
|
||||
|
||||
/**
|
||||
* @brief Set socket lock break time
|
||||
*
|
||||
* @param break_time
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t socket_lock_set_break_time(uint16_t break_time);
|
||||
|
||||
/**
|
||||
* @brief Set socke lock to locked / unlocked state
|
||||
*
|
||||
* @param locked
|
||||
*/
|
||||
void socket_lock_set_locked(bool locked);
|
||||
|
||||
/**
|
||||
* @brief Get socket lock status
|
||||
*
|
||||
* @return socket_lock_status_t
|
||||
*/
|
||||
socket_lock_status_t socket_lock_get_status(void);
|
||||
|
||||
|
||||
#endif /* SOCKED_LOCK_H_ */
|
||||
41
components/peripherals/include/temp_sensor.h
Normal file
41
components/peripherals/include/temp_sensor.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef TEMP_SENSOR_H_
|
||||
#define TEMP_SENSOR_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
/**
|
||||
* @brief Initialize DS18S20 temperature sensor bus
|
||||
*
|
||||
*/
|
||||
void temp_sensor_init(void);
|
||||
|
||||
/**
|
||||
* @brief Get found sensor count
|
||||
*
|
||||
* @return uint8_t
|
||||
*/
|
||||
uint8_t temp_sensor_get_count(void);
|
||||
|
||||
/**
|
||||
* @brief Return lowest temperature after temp_sensor_measure
|
||||
*
|
||||
* @return int16_t
|
||||
*/
|
||||
int16_t temp_sensor_get_low(void);
|
||||
|
||||
/**
|
||||
* @brief Return highest temperature after temp_sensor_measure
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int temp_sensor_get_high(void);
|
||||
|
||||
/**
|
||||
* @brief Return temperature sensor error
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
bool temp_sensor_is_error(void);
|
||||
|
||||
#endif /* TEMP_SENSOR_H_ */
|
||||
59
components/peripherals/src/ac_relay.c
Executable file
59
components/peripherals/src/ac_relay.c
Executable file
@@ -0,0 +1,59 @@
|
||||
#include "esp_log.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
#include "ac_relay.h"
|
||||
#include "board_config.h"
|
||||
|
||||
static const char* TAG = "ac_relay";
|
||||
|
||||
/**
|
||||
* @brief Initialize the AC relay GPIO.
|
||||
*
|
||||
* Configures the specified GPIO pin as an output and sets its initial state to OFF (low).
|
||||
*/
|
||||
void ac_relay_init(void)
|
||||
{
|
||||
gpio_config_t conf = {
|
||||
.pin_bit_mask = BIT64(board_config.ac_relay_gpio),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE, ///< Disabled unless required
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
|
||||
esp_err_t ret = gpio_config(&conf);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to configure GPIO (error: %s)", esp_err_to_name(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
gpio_set_level(board_config.ac_relay_gpio, false); ///< Ensure relay starts OFF
|
||||
ESP_LOGI(TAG, "AC relay initialized. Pin: %d", board_config.ac_relay_gpio);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the state of the AC relay.
|
||||
*
|
||||
* @param state True to turn the relay ON, False to turn it OFF.
|
||||
*/
|
||||
void ac_relay_set_state(bool state)
|
||||
{
|
||||
ESP_LOGI(TAG, "Setting AC relay state: Pin: %d, State: %d", board_config.ac_relay_gpio, state);
|
||||
|
||||
esp_err_t ret = gpio_set_level(board_config.ac_relay_gpio, state);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set GPIO level (error: %s)", esp_err_to_name(ret));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the current state of the AC relay.
|
||||
*
|
||||
* @return true if the relay is ON, false if OFF.
|
||||
*/
|
||||
bool ac_relay_get_state(void)
|
||||
{
|
||||
int level = gpio_get_level(board_config.ac_relay_gpio);
|
||||
ESP_LOGD(TAG, "Current AC relay state: Pin: %d, State: %d", board_config.ac_relay_gpio, level);
|
||||
return level;
|
||||
}
|
||||
54
components/peripherals/src/adc.c
Executable file
54
components/peripherals/src/adc.c
Executable file
@@ -0,0 +1,54 @@
|
||||
#include "adc.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
const static char* TAG = "adc";
|
||||
|
||||
adc_oneshot_unit_handle_t adc_handle;
|
||||
|
||||
adc_cali_handle_t adc_cali_handle;
|
||||
|
||||
void adc_init(void)
|
||||
{
|
||||
adc_oneshot_unit_init_cfg_t conf = {
|
||||
.unit_id = ADC_UNIT_1
|
||||
};
|
||||
ESP_ERROR_CHECK(adc_oneshot_new_unit(&conf, &adc_handle));
|
||||
|
||||
bool calibrated = false;
|
||||
|
||||
#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
|
||||
if (!calibrated) {
|
||||
ESP_LOGI(TAG, "Calibration scheme version is %s", "Curve Fitting");
|
||||
adc_cali_curve_fitting_config_t cali_config = {
|
||||
.unit_id = ADC_UNIT_1,
|
||||
.atten = ADC_ATTEN_DB_12,
|
||||
.bitwidth = ADC_BITWIDTH_DEFAULT,
|
||||
};
|
||||
if (adc_cali_create_scheme_curve_fitting(&cali_config, &adc_cali_handle) == ESP_OK) {
|
||||
calibrated = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
|
||||
if (!calibrated) {
|
||||
ESP_LOGI(TAG, "Calibration scheme version is %s", "Line Fitting");
|
||||
adc_cali_line_fitting_config_t cali_config = {
|
||||
.unit_id = ADC_UNIT_1,
|
||||
.atten = ADC_ATTEN_DB_12,
|
||||
.bitwidth = ADC_BITWIDTH_DEFAULT,
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
.default_vref = 1100
|
||||
#endif
|
||||
};
|
||||
if (adc_cali_create_scheme_line_fitting(&cali_config, &adc_cali_handle) == ESP_OK) {
|
||||
calibrated = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!calibrated) {
|
||||
ESP_LOGE(TAG, "No calibration scheme");
|
||||
ESP_ERROR_CHECK(ESP_FAIL);
|
||||
}
|
||||
}
|
||||
66
components/peripherals/src/adc121s021_dma.c
Executable file
66
components/peripherals/src/adc121s021_dma.c
Executable file
@@ -0,0 +1,66 @@
|
||||
#include "driver/spi_master.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "adc121s021_dma.h"
|
||||
|
||||
#define TAG "adc_dma"
|
||||
|
||||
#define PIN_NUM_MOSI 23
|
||||
#define PIN_NUM_MISO 19
|
||||
#define PIN_NUM_CLK 18
|
||||
#define PIN_NUM_CS 5
|
||||
|
||||
#define SPI_HOST_USED SPI2_HOST
|
||||
#define SAMPLE_SIZE_BYTES 2
|
||||
#define ADC_BITS 12
|
||||
|
||||
static spi_device_handle_t adc_spi;
|
||||
|
||||
void adc121s021_dma_init(void)
|
||||
{
|
||||
spi_bus_config_t buscfg = {
|
||||
.mosi_io_num = PIN_NUM_MOSI,
|
||||
.miso_io_num = PIN_NUM_MISO,
|
||||
.sclk_io_num = PIN_NUM_CLK,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
.max_transfer_sz = SAMPLE_SIZE_BYTES,
|
||||
};
|
||||
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.clock_speed_hz = 6000000, // 6 MHz
|
||||
.mode = 0,
|
||||
.spics_io_num = PIN_NUM_CS,
|
||||
.queue_size = 2,
|
||||
.flags = SPI_DEVICE_NO_DUMMY,
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI_HOST_USED, &buscfg, SPI_DMA_CH_AUTO));
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(SPI_HOST_USED, &devcfg, &adc_spi));
|
||||
}
|
||||
|
||||
bool adc121s021_dma_get_sample(uint16_t *sample)
|
||||
{
|
||||
uint8_t tx_buffer[2] = {0x00, 0x00}; // Dummy TX
|
||||
uint8_t rx_buffer[2] = {0};
|
||||
|
||||
spi_transaction_t t = {
|
||||
.length = 16, // 16 bits
|
||||
.tx_buffer = tx_buffer,
|
||||
.rx_buffer = rx_buffer,
|
||||
.flags = 0
|
||||
};
|
||||
|
||||
esp_err_t err = spi_device_transmit(adc_spi, &t);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "SPI transmit error: %s", esp_err_to_name(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extrai os 12 bits significativos da resposta do ADC121S021
|
||||
*sample = ((rx_buffer[0] << 8) | rx_buffer[1]) & 0x0FFF;
|
||||
|
||||
return true;
|
||||
}
|
||||
174
components/peripherals/src/aux_io.c
Executable file
174
components/peripherals/src/aux_io.c
Executable file
@@ -0,0 +1,174 @@
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "nvs.h"
|
||||
|
||||
#include "aux_io.h"
|
||||
#include "board_config.h"
|
||||
#include "adc.h"
|
||||
|
||||
#define MAX_AUX_IN 4
|
||||
#define MAX_AUX_OUT 4
|
||||
#define MAX_AUX_AIN 4
|
||||
|
||||
//static const char* TAG = "aux";
|
||||
|
||||
static int aux_in_count = 0;
|
||||
static int aux_out_count = 0;
|
||||
static int aux_ain_count = 0;
|
||||
|
||||
static struct aux_gpio_s
|
||||
{
|
||||
gpio_num_t gpio;
|
||||
const char* name;
|
||||
} aux_in[MAX_AUX_IN], aux_out[MAX_AUX_OUT];
|
||||
|
||||
static struct aux_adc_s
|
||||
{
|
||||
adc_channel_t adc;
|
||||
const char* name;
|
||||
} aux_ain[MAX_AUX_AIN];
|
||||
|
||||
|
||||
void aux_init(void)
|
||||
{
|
||||
// IN
|
||||
|
||||
gpio_config_t io_conf = {
|
||||
.mode = GPIO_MODE_INPUT,
|
||||
.pull_up_en = GPIO_PULLDOWN_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
.pin_bit_mask = 0
|
||||
};
|
||||
|
||||
if (board_config.aux_in_1) {
|
||||
aux_in[aux_in_count].gpio = board_config.aux_in_1_gpio;
|
||||
aux_in[aux_in_count].name = board_config.aux_in_1_name;
|
||||
io_conf.pin_bit_mask |= BIT64(board_config.aux_in_1_gpio);
|
||||
aux_in_count++;
|
||||
}
|
||||
|
||||
if (board_config.aux_in_2) {
|
||||
aux_in[aux_in_count].gpio = board_config.aux_in_2_gpio;
|
||||
aux_in[aux_in_count].name = board_config.aux_in_2_name;
|
||||
io_conf.pin_bit_mask |= BIT64(board_config.aux_in_2_gpio);
|
||||
aux_in_count++;
|
||||
}
|
||||
|
||||
if (board_config.aux_in_3) {
|
||||
aux_in[aux_in_count].gpio = board_config.aux_in_3_gpio;
|
||||
aux_in[aux_in_count].name = board_config.aux_in_3_name;
|
||||
io_conf.pin_bit_mask |= BIT64(board_config.aux_in_3_gpio);
|
||||
aux_in_count++;
|
||||
}
|
||||
|
||||
if (board_config.aux_in_4) {
|
||||
aux_in[aux_in_count].gpio = board_config.aux_in_4_gpio;
|
||||
aux_in[aux_in_count].name = board_config.aux_in_4_name;
|
||||
io_conf.pin_bit_mask |= BIT64(board_config.aux_in_4_gpio);
|
||||
aux_in_count++;
|
||||
}
|
||||
|
||||
if (io_conf.pin_bit_mask > 0) {
|
||||
ESP_ERROR_CHECK(gpio_config(&io_conf));
|
||||
}
|
||||
|
||||
// OUT
|
||||
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = 0;
|
||||
|
||||
if (board_config.aux_out_1) {
|
||||
aux_out[aux_out_count].gpio = board_config.aux_out_1_gpio;
|
||||
aux_out[aux_out_count].name = board_config.aux_out_1_name;
|
||||
io_conf.pin_bit_mask |= BIT64(board_config.aux_out_1_gpio);
|
||||
aux_out_count++;
|
||||
}
|
||||
|
||||
if (board_config.aux_out_2) {
|
||||
aux_out[aux_out_count].gpio = board_config.aux_out_2_gpio;
|
||||
aux_out[aux_out_count].name = board_config.aux_out_2_name;
|
||||
io_conf.pin_bit_mask |= BIT64(board_config.aux_out_2_gpio);
|
||||
aux_out_count++;
|
||||
}
|
||||
|
||||
if (board_config.aux_out_3) {
|
||||
aux_out[aux_out_count].gpio = board_config.aux_out_3_gpio;
|
||||
aux_out[aux_out_count].name = board_config.aux_out_3_name;
|
||||
io_conf.pin_bit_mask |= BIT64(board_config.aux_out_3_gpio);
|
||||
aux_out_count++;
|
||||
}
|
||||
|
||||
if (board_config.aux_out_4) {
|
||||
aux_out[aux_out_count].gpio = board_config.aux_out_4_gpio;
|
||||
aux_out[aux_out_count].name = board_config.aux_out_4_name;
|
||||
io_conf.pin_bit_mask |= BIT64(board_config.aux_out_4_gpio);
|
||||
aux_out_count++;
|
||||
}
|
||||
|
||||
if (io_conf.pin_bit_mask > 0) {
|
||||
ESP_ERROR_CHECK(gpio_config(&io_conf));
|
||||
}
|
||||
|
||||
// AIN
|
||||
|
||||
adc_oneshot_chan_cfg_t config = {
|
||||
.bitwidth = ADC_BITWIDTH_DEFAULT,
|
||||
.atten = ADC_ATTEN_DB_12
|
||||
};
|
||||
|
||||
if (board_config.aux_ain_1) {
|
||||
aux_ain[aux_ain_count].adc = board_config.aux_ain_1_adc_channel;
|
||||
aux_ain[aux_ain_count].name = board_config.aux_out_1_name;
|
||||
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc_handle, board_config.aux_ain_1_adc_channel, &config));
|
||||
aux_ain_count++;
|
||||
}
|
||||
|
||||
if (board_config.aux_ain_2) {
|
||||
aux_ain[aux_ain_count].adc = board_config.aux_ain_2_adc_channel;
|
||||
aux_ain[aux_ain_count].name = board_config.aux_out_2_name;
|
||||
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc_handle, board_config.aux_ain_2_adc_channel, &config));
|
||||
aux_ain_count++;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t aux_read(const char* name, bool* value)
|
||||
{
|
||||
for (int i = 0; i < aux_in_count; i++) {
|
||||
if (strcmp(aux_in[i].name, name) == 0) {
|
||||
*value = gpio_get_level(aux_in[i].gpio) == 1;
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
esp_err_t aux_write(const char* name, bool value)
|
||||
{
|
||||
for (int i = 0; i < aux_out_count; i++) {
|
||||
if (strcmp(aux_out[i].name, name) == 0) {
|
||||
return gpio_set_level(aux_out[i].gpio, value);
|
||||
}
|
||||
}
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
esp_err_t aux_analog_read(const char* name, int* value)
|
||||
{
|
||||
for (int i = 0; i < aux_ain_count; i++) {
|
||||
if (strcmp(aux_ain[i].name, name) == 0) {
|
||||
int raw = 0;
|
||||
esp_err_t ret = adc_oneshot_read(adc_handle, aux_ain[i].adc, &raw);
|
||||
if (ret == ESP_OK) {
|
||||
return adc_cali_raw_to_voltage(adc_cali_handle, raw, value);
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
163
components/peripherals/src/buzzer.c
Executable file
163
components/peripherals/src/buzzer.c
Executable file
@@ -0,0 +1,163 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "board_config.h"
|
||||
#include "buzzer.h"
|
||||
#include "evse_api.h"
|
||||
|
||||
static gpio_num_t buzzer_gpio = GPIO_NUM_NC;
|
||||
static evse_state_t last_buzzer_state = -1;
|
||||
static QueueHandle_t buzzer_queue = NULL;
|
||||
|
||||
void buzzer_on(void) {
|
||||
if (buzzer_gpio != GPIO_NUM_NC)
|
||||
gpio_set_level(buzzer_gpio, 1);
|
||||
}
|
||||
|
||||
void buzzer_off(void) {
|
||||
if (buzzer_gpio != GPIO_NUM_NC)
|
||||
gpio_set_level(buzzer_gpio, 0);
|
||||
}
|
||||
|
||||
// ----------------------
|
||||
// Padrões de Buzzer
|
||||
// ----------------------
|
||||
|
||||
typedef struct {
|
||||
uint16_t on_ms;
|
||||
uint16_t off_ms;
|
||||
} buzzer_pattern_step_t;
|
||||
|
||||
typedef enum {
|
||||
BUZZER_PATTERN_NONE = 0,
|
||||
BUZZER_PATTERN_PLUGGED,
|
||||
BUZZER_PATTERN_UNPLUGGED,
|
||||
BUZZER_PATTERN_CHARGING,
|
||||
} buzzer_pattern_id_t;
|
||||
|
||||
static const buzzer_pattern_step_t pattern_plugged[] = {
|
||||
{100, 100}, {200, 0}
|
||||
};
|
||||
|
||||
static const buzzer_pattern_step_t pattern_unplugged[] = {
|
||||
{150, 150}, {150, 150}, {150, 0}
|
||||
};
|
||||
|
||||
static const buzzer_pattern_step_t pattern_charging[] = {
|
||||
{80, 150}, {100, 120}, {120, 100}, {140, 0}
|
||||
};
|
||||
|
||||
// ----------------------
|
||||
// Executor de padrões
|
||||
// ----------------------
|
||||
|
||||
static void buzzer_execute_pattern(buzzer_pattern_id_t pattern_id) {
|
||||
const buzzer_pattern_step_t *pattern = NULL;
|
||||
size_t length = 0;
|
||||
|
||||
switch (pattern_id) {
|
||||
case BUZZER_PATTERN_PLUGGED:
|
||||
pattern = pattern_plugged;
|
||||
length = sizeof(pattern_plugged) / sizeof(pattern_plugged[0]);
|
||||
break;
|
||||
case BUZZER_PATTERN_UNPLUGGED:
|
||||
pattern = pattern_unplugged;
|
||||
length = sizeof(pattern_unplugged) / sizeof(pattern_unplugged[0]);
|
||||
break;
|
||||
case BUZZER_PATTERN_CHARGING:
|
||||
pattern = pattern_charging;
|
||||
length = sizeof(pattern_charging) / sizeof(pattern_charging[0]);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
buzzer_on();
|
||||
vTaskDelay(pdMS_TO_TICKS(pattern[i].on_ms));
|
||||
buzzer_off();
|
||||
if (pattern[i].off_ms > 0)
|
||||
vTaskDelay(pdMS_TO_TICKS(pattern[i].off_ms));
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------
|
||||
// Task que toca o buzzer
|
||||
// ----------------------
|
||||
|
||||
static void buzzer_worker_task(void *arg) {
|
||||
buzzer_pattern_id_t pattern_id;
|
||||
|
||||
while (true) {
|
||||
if (xQueueReceive(buzzer_queue, &pattern_id, portMAX_DELAY)) {
|
||||
buzzer_execute_pattern(pattern_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------
|
||||
// Task de monitoramento
|
||||
// ----------------------
|
||||
|
||||
static void buzzer_monitor_task(void *arg) {
|
||||
while (true) {
|
||||
evse_state_t current = evse_get_state();
|
||||
|
||||
if (current != last_buzzer_state) {
|
||||
buzzer_pattern_id_t pattern_id = BUZZER_PATTERN_NONE;
|
||||
|
||||
switch (current) {
|
||||
case EVSE_STATE_A:
|
||||
if (last_buzzer_state != EVSE_STATE_A)
|
||||
pattern_id = BUZZER_PATTERN_UNPLUGGED;
|
||||
break;
|
||||
case EVSE_STATE_B1:
|
||||
case EVSE_STATE_B2:
|
||||
if (last_buzzer_state != EVSE_STATE_B1 && last_buzzer_state != EVSE_STATE_B2)
|
||||
pattern_id = BUZZER_PATTERN_PLUGGED;
|
||||
break;
|
||||
case EVSE_STATE_C2:
|
||||
case EVSE_STATE_D2:
|
||||
if (last_buzzer_state != EVSE_STATE_C2 && last_buzzer_state != EVSE_STATE_D2)
|
||||
pattern_id = BUZZER_PATTERN_CHARGING;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (pattern_id != BUZZER_PATTERN_NONE) {
|
||||
xQueueSend(buzzer_queue, &pattern_id, 0); // Não bloqueia
|
||||
}
|
||||
|
||||
last_buzzer_state = current;
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------
|
||||
// Inicialização
|
||||
// ----------------------
|
||||
|
||||
void buzzer_init(void) {
|
||||
if (board_config.buzzer) {
|
||||
buzzer_gpio = board_config.buzzer_gpio;
|
||||
|
||||
gpio_config_t io_conf = {
|
||||
.pin_bit_mask = BIT64(buzzer_gpio),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_down_en = GPIO_PULLDOWN_ENABLE,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE
|
||||
};
|
||||
gpio_config(&io_conf);
|
||||
gpio_set_level(buzzer_gpio, 0);
|
||||
}
|
||||
|
||||
buzzer_queue = xQueueCreate(4, sizeof(buzzer_pattern_id_t));
|
||||
|
||||
xTaskCreate(buzzer_monitor_task, "buzzer_monitor", 2048, NULL, 5, NULL);
|
||||
xTaskCreate(buzzer_worker_task, "buzzer_worker", 2048, NULL, 5, NULL);
|
||||
}
|
||||
265
components/peripherals/src/ds18x20.c
Executable file
265
components/peripherals/src/ds18x20.c
Executable file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Grzegorz Hetman <ghetman@gmail.com>
|
||||
* Copyright (c) 2016 Alex Stewart <foogod@gmail.com>
|
||||
* Copyright (c) 2018 Ruslan V. Uss <unclerus@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the names of itscontributors
|
||||
* may be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#include <math.h>
|
||||
#include <esp_log.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include "ds18x20.h"
|
||||
|
||||
#define ds18x20_WRITE_SCRATCHPAD 0x4E
|
||||
#define ds18x20_READ_SCRATCHPAD 0xBE
|
||||
#define ds18x20_COPY_SCRATCHPAD 0x48
|
||||
#define ds18x20_READ_EEPROM 0xB8
|
||||
#define ds18x20_READ_PWRSUPPLY 0xB4
|
||||
#define ds18x20_SEARCHROM 0xF0
|
||||
#define ds18x20_SKIP_ROM 0xCC
|
||||
#define ds18x20_READROM 0x33
|
||||
#define ds18x20_MATCHROM 0x55
|
||||
#define ds18x20_ALARMSEARCH 0xEC
|
||||
#define ds18x20_CONVERT_T 0x44
|
||||
|
||||
#define CHECK(x) do { esp_err_t __; if ((__ = x) != ESP_OK) return __; } while (0)
|
||||
#define CHECK_ARG(VAL) do { if (!(VAL)) return ESP_ERR_INVALID_ARG; } while (0)
|
||||
|
||||
static portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
static const char* TAG = "ds18x20";
|
||||
|
||||
esp_err_t ds18x20_measure(gpio_num_t pin, ds18x20_addr_t addr, bool wait)
|
||||
{
|
||||
if (!onewire_reset(pin))
|
||||
return ESP_ERR_INVALID_RESPONSE;
|
||||
|
||||
if (addr == DS18X20_ANY)
|
||||
onewire_skip_rom(pin);
|
||||
else
|
||||
onewire_select(pin, addr);
|
||||
|
||||
portENTER_CRITICAL(&mux);
|
||||
onewire_write(pin, ds18x20_CONVERT_T);
|
||||
// For parasitic devices, power must be applied within 10us after issuing
|
||||
// the convert command.
|
||||
onewire_power(pin);
|
||||
portEXIT_CRITICAL(&mux);
|
||||
|
||||
if (wait){
|
||||
vTaskDelay(pdMS_TO_TICKS(750));
|
||||
onewire_depower(pin);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ds18x20_read_scratchpad(gpio_num_t pin, ds18x20_addr_t addr, uint8_t* buffer)
|
||||
{
|
||||
CHECK_ARG(buffer);
|
||||
|
||||
uint8_t crc;
|
||||
uint8_t expected_crc;
|
||||
|
||||
if (!onewire_reset(pin))
|
||||
return ESP_ERR_INVALID_RESPONSE;
|
||||
|
||||
if (addr == DS18X20_ANY)
|
||||
onewire_skip_rom(pin);
|
||||
else
|
||||
onewire_select(pin, addr);
|
||||
onewire_write(pin, ds18x20_READ_SCRATCHPAD);
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
buffer[i] = onewire_read(pin);
|
||||
crc = onewire_read(pin);
|
||||
|
||||
expected_crc = onewire_crc8(buffer, 8);
|
||||
if (crc != expected_crc)
|
||||
{
|
||||
ESP_LOGE(TAG, "CRC check failed reading scratchpad: %02x %02x %02x %02x %02x %02x %02x %02x : %02x (expected %02x)", buffer[0], buffer[1],
|
||||
buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7], crc, expected_crc);
|
||||
return ESP_ERR_INVALID_CRC;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ds18x20_write_scratchpad(gpio_num_t pin, ds18x20_addr_t addr, uint8_t* buffer)
|
||||
{
|
||||
CHECK_ARG(buffer);
|
||||
|
||||
if (!onewire_reset(pin))
|
||||
return ESP_ERR_INVALID_RESPONSE;
|
||||
|
||||
if (addr == DS18X20_ANY)
|
||||
onewire_skip_rom(pin);
|
||||
else
|
||||
onewire_select(pin, addr);
|
||||
onewire_write(pin, ds18x20_WRITE_SCRATCHPAD);
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
onewire_write(pin, buffer[i]);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ds18x20_copy_scratchpad(gpio_num_t pin, ds18x20_addr_t addr)
|
||||
{
|
||||
if (!onewire_reset(pin))
|
||||
return ESP_ERR_INVALID_RESPONSE;
|
||||
|
||||
if (addr == DS18X20_ANY)
|
||||
onewire_skip_rom(pin);
|
||||
else
|
||||
onewire_select(pin, addr);
|
||||
|
||||
portENTER_CRITICAL(&mux);
|
||||
onewire_write(pin, ds18x20_COPY_SCRATCHPAD);
|
||||
// For parasitic devices, power must be applied within 10us after issuing
|
||||
// the convert command.
|
||||
onewire_power(pin);
|
||||
portEXIT_CRITICAL(&mux);
|
||||
|
||||
// And then it needs to keep that power up for 10ms.
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
onewire_depower(pin);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ds18b20_read_temperature(gpio_num_t pin, ds18x20_addr_t addr, int16_t* temperature)
|
||||
{
|
||||
CHECK_ARG(temperature);
|
||||
|
||||
uint8_t scratchpad[8];
|
||||
int16_t temp;
|
||||
|
||||
CHECK(ds18x20_read_scratchpad(pin, addr, scratchpad));
|
||||
|
||||
temp = scratchpad[1] << 8 | scratchpad[0];
|
||||
|
||||
*temperature = ((int16_t)temp * 625.0) / 100;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ds18s20_read_temperature(gpio_num_t pin, ds18x20_addr_t addr, int16_t* temperature)
|
||||
{
|
||||
CHECK_ARG(temperature);
|
||||
|
||||
uint8_t scratchpad[8];
|
||||
int16_t temp;
|
||||
|
||||
CHECK(ds18x20_read_scratchpad(pin, addr, scratchpad));
|
||||
|
||||
temp = scratchpad[1] << 8 | scratchpad[0];
|
||||
temp = ((temp & 0xfffe) << 3) + (16 - scratchpad[6]) - 4;
|
||||
|
||||
*temperature = (temp * 625) / 100 - 25;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ds18x20_read_temperature(gpio_num_t pin, ds18x20_addr_t addr, int16_t* temperature)
|
||||
{
|
||||
if ((uint8_t)addr == DS18B20_FAMILY_ID) {
|
||||
return ds18b20_read_temperature(pin, addr, temperature);
|
||||
} else {
|
||||
return ds18s20_read_temperature(pin, addr, temperature);
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t ds18b20_measure_and_read(gpio_num_t pin, ds18x20_addr_t addr, int16_t* temperature)
|
||||
{
|
||||
CHECK_ARG(temperature);
|
||||
|
||||
CHECK(ds18x20_measure(pin, addr, true));
|
||||
return ds18b20_read_temperature(pin, addr, temperature);
|
||||
}
|
||||
|
||||
esp_err_t ds18s20_measure_and_read(gpio_num_t pin, ds18x20_addr_t addr, int16_t* temperature)
|
||||
{
|
||||
CHECK_ARG(temperature);
|
||||
|
||||
CHECK(ds18x20_measure(pin, addr, true));
|
||||
return ds18s20_read_temperature(pin, addr, temperature);
|
||||
}
|
||||
|
||||
esp_err_t ds18x20_measure_and_read(gpio_num_t pin, ds18x20_addr_t addr, int16_t* temperature)
|
||||
{
|
||||
CHECK_ARG(temperature);
|
||||
|
||||
CHECK(ds18x20_measure(pin, addr, true));
|
||||
return ds18x20_read_temperature(pin, addr, temperature);
|
||||
}
|
||||
|
||||
esp_err_t ds18x20_measure_and_read_multi(gpio_num_t pin, ds18x20_addr_t* addr_list, size_t addr_count, int16_t* result_list)
|
||||
{
|
||||
CHECK_ARG(result_list && addr_count);
|
||||
|
||||
CHECK(ds18x20_measure(pin, DS18X20_ANY, true));
|
||||
|
||||
return ds18x20_read_temp_multi(pin, addr_list, addr_count, result_list);
|
||||
}
|
||||
|
||||
esp_err_t ds18x20_scan_devices(gpio_num_t pin, ds18x20_addr_t* addr_list, size_t addr_count, size_t* found)
|
||||
{
|
||||
CHECK_ARG(addr_list && addr_count);
|
||||
|
||||
onewire_search_t search;
|
||||
onewire_addr_t addr;
|
||||
|
||||
*found = 0;
|
||||
onewire_search_start(&search);
|
||||
while ((addr = onewire_search_next(&search, pin)) != ONEWIRE_NONE)
|
||||
{
|
||||
uint8_t family_id = (uint8_t)addr;
|
||||
if (family_id == DS18B20_FAMILY_ID || family_id == DS18S20_FAMILY_ID)
|
||||
{
|
||||
if (*found < addr_count)
|
||||
addr_list[*found] = addr;
|
||||
*found += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ds18x20_read_temp_multi(gpio_num_t pin, ds18x20_addr_t* addr_list, size_t addr_count, int16_t* result_list)
|
||||
{
|
||||
CHECK_ARG(result_list);
|
||||
|
||||
esp_err_t res = ESP_OK;
|
||||
for (size_t i = 0; i < addr_count; i++)
|
||||
{
|
||||
esp_err_t tmp = ds18x20_read_temperature(pin, addr_list[i], &result_list[i]);
|
||||
if (tmp != ESP_OK)
|
||||
res = tmp;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
254
components/peripherals/src/ds18x20.h
Executable file
254
components/peripherals/src/ds18x20.h
Executable file
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Grzegorz Hetman <ghetman@gmail.com>
|
||||
* Copyright (c) 2016 Alex Stewart <foogod@gmail.com>
|
||||
* Copyright (c) 2018 Ruslan V. Uss <unclerus@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the names of itscontributors
|
||||
* may be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _DS18X20_H
|
||||
#define _DS18X20_H
|
||||
|
||||
#include <esp_err.h>
|
||||
#include "onewire.h"
|
||||
|
||||
typedef onewire_addr_t ds18x20_addr_t;
|
||||
|
||||
/** An address value which can be used to indicate "any device on the bus" */
|
||||
#define DS18X20_ANY ONEWIRE_NONE
|
||||
|
||||
/** Family ID (lower address byte) of DS18B20 sensors */
|
||||
#define DS18B20_FAMILY_ID 0x28
|
||||
|
||||
/** Family ID (lower address byte) of DS18S20 sensors */
|
||||
#define DS18S20_FAMILY_ID 0x10
|
||||
|
||||
/**
|
||||
* @brief Find the addresses of all ds18x20 devices on the bus.
|
||||
*
|
||||
* Scans the bus for all devices and places their addresses in the supplied
|
||||
* array. If there are more than `addr_count` devices on the bus, only the
|
||||
* first `addr_count` are recorded.
|
||||
*
|
||||
* @param pin The GPIO pin connected to the ds18x20 bus
|
||||
* @param addr_list A pointer to an array of ::ds18x20_addr_t values.
|
||||
* This will be populated with the addresses of the found
|
||||
* devices.
|
||||
* @param addr_count Number of slots in the `addr_list` array. At most this
|
||||
* many addresses will be returned.
|
||||
* @param found The number of devices found. Note that this may be less
|
||||
* than, equal to, or more than `addr_count`, depending on
|
||||
* how many ds18x20 devices are attached to the bus.
|
||||
*
|
||||
* @returns `ESP_OK` if the command was successfully issued
|
||||
*/
|
||||
esp_err_t ds18x20_scan_devices(gpio_num_t pin, ds18x20_addr_t *addr_list, size_t addr_count, size_t *found);
|
||||
|
||||
/**
|
||||
* @brief Tell one or more sensors to perform a temperature measurement and
|
||||
* conversion (CONVERT_T) operation.
|
||||
*
|
||||
* This operation can take up to 750ms to complete.
|
||||
*
|
||||
* If `wait=true`, this routine will automatically drive the pin high for the
|
||||
* necessary 750ms after issuing the command to ensure parasitically-powered
|
||||
* devices have enough power to perform the conversion operation (for
|
||||
* non-parasitically-powered devices, this is not necessary but does not
|
||||
* hurt). If `wait=false`, this routine will drive the pin high, but will
|
||||
* then return immediately. It is up to the caller to wait the requisite time
|
||||
* and then depower the bus using onewire_depower() or by issuing another
|
||||
* command once conversion is done.
|
||||
*
|
||||
* @param pin The GPIO pin connected to the ds18x20 device
|
||||
* @param addr The 64-bit address of the device on the bus. This can be set
|
||||
* to ::DS18X20_ANY to send the command to all devices on the bus
|
||||
* at the same time.
|
||||
* @param wait Whether to wait for the necessary 750ms for the ds18x20 to
|
||||
* finish performing the conversion before returning to the
|
||||
* caller (You will normally want to do this).
|
||||
*
|
||||
* @returns `ESP_OK` if the command was successfully issued
|
||||
*/
|
||||
esp_err_t ds18x20_measure(gpio_num_t pin, ds18x20_addr_t addr, bool wait);
|
||||
|
||||
/**
|
||||
* @brief Read the value from the last CONVERT_T operation.
|
||||
*
|
||||
* This should be called after ds18x20_measure() to fetch the result of the
|
||||
* temperature measurement.
|
||||
*
|
||||
* @param pin The GPIO pin connected to the ds18x20 device
|
||||
* @param addr The 64-bit address of the device to read. This can be set
|
||||
* to ::DS18X20_ANY to read any device on the bus (but note
|
||||
* that this will only work if there is exactly one device
|
||||
* connected, or they will corrupt each others' transmissions)
|
||||
* @param temperature The temperature in degrees Celsius
|
||||
*
|
||||
* @returns `ESP_OK` if the command was successfully issued
|
||||
*/
|
||||
esp_err_t ds18x20_read_temperature(gpio_num_t pin, ds18x20_addr_t addr, int16_t *temperature);
|
||||
|
||||
/**
|
||||
* @brief Read the value from the last CONVERT_T operation (ds18b20 version).
|
||||
*
|
||||
* This should be called after ds18x20_measure() to fetch the result of the
|
||||
* temperature measurement.
|
||||
*
|
||||
* @param pin The GPIO pin connected to the ds18x20 device
|
||||
* @param addr The 64-bit address of the device to read. This can be set
|
||||
* to ::DS18X20_ANY to read any device on the bus (but note
|
||||
* that this will only work if there is exactly one device
|
||||
* connected, or they will corrupt each others' transmissions)
|
||||
* @param temperature The temperature in degrees Celsius
|
||||
*
|
||||
* @returns `ESP_OK` if the command was successfully issued
|
||||
*/
|
||||
esp_err_t ds18b20_read_temperature(gpio_num_t pin, ds18x20_addr_t addr, int16_t *temperature);
|
||||
|
||||
/**
|
||||
* @brief Read the value from the last CONVERT_T operation (ds18s20 version).
|
||||
*
|
||||
* This should be called after ds18x20_measure() to fetch the result of the
|
||||
* temperature measurement.
|
||||
*
|
||||
* @param pin The GPIO pin connected to the ds18x20 device
|
||||
* @param addr The 64-bit address of the device to read. This can be set
|
||||
* to ::DS18X20_ANY to read any device on the bus (but note
|
||||
* that this will only work if there is exactly one device
|
||||
* connected, or they will corrupt each others' transmissions)
|
||||
* @param temperature The temperature in degrees Celsius
|
||||
*
|
||||
* @returns `ESP_OK` if the command was successfully issued
|
||||
*/
|
||||
esp_err_t ds18s20_read_temperature(gpio_num_t pin, ds18x20_addr_t addr, int16_t *temperature);
|
||||
|
||||
/**
|
||||
* @brief Read the value from the last CONVERT_T operation for multiple devices.
|
||||
*
|
||||
* This should be called after ds18x20_measure() to fetch the result of the
|
||||
* temperature measurement.
|
||||
*
|
||||
* @param pin The GPIO pin connected to the ds18x20 bus
|
||||
* @param addr_list A list of addresses for devices to read.
|
||||
* @param addr_count The number of entries in `addr_list`.
|
||||
* @param result_list An array of int16_ts to hold the returned temperature
|
||||
* values. It should have at least `addr_count` entries.
|
||||
*
|
||||
* @returns `ESP_OK` if all temperatures were fetched successfully
|
||||
*/
|
||||
esp_err_t ds18x20_read_temp_multi(gpio_num_t pin, ds18x20_addr_t *addr_list, size_t addr_count, int16_t *result_list);
|
||||
|
||||
/** Perform a ds18x20_measure() followed by ds18s20_read_temperature()
|
||||
*
|
||||
* @param pin The GPIO pin connected to the ds18s20 device
|
||||
* @param addr The 64-bit address of the device to read. This can be set
|
||||
* to ::DS18X20_ANY to read any device on the bus (but note
|
||||
* that this will only work if there is exactly one device
|
||||
* connected, or they will corrupt each others' transmissions)
|
||||
* @param temperature The temperature in degrees Celsius
|
||||
*/
|
||||
esp_err_t ds18s20_measure_and_read(gpio_num_t pin, ds18x20_addr_t addr, int16_t *temperature);
|
||||
|
||||
/** Perform a ds18x20_measure() followed by ds18b20_read_temperature()
|
||||
*
|
||||
* @param pin The GPIO pin connected to the ds18x20 device
|
||||
* @param addr The 64-bit address of the device to read. This can be set
|
||||
* to ::DS18X20_ANY to read any device on the bus (but note
|
||||
* that this will only work if there is exactly one device
|
||||
* connected, or they will corrupt each others' transmissions)
|
||||
* @param temperature The temperature in degrees Celsius
|
||||
*/
|
||||
esp_err_t ds18b20_measure_and_read(gpio_num_t pin, ds18x20_addr_t addr, int16_t *temperature);
|
||||
|
||||
/** Perform a ds18x20_measure() followed by ds18x20_read_temperature()
|
||||
*
|
||||
* @param pin The GPIO pin connected to the ds18x20 device
|
||||
* @param addr The 64-bit address of the device to read. This can be set
|
||||
* to ::DS18X20_ANY to read any device on the bus (but note
|
||||
* that this will only work if there is exactly one device
|
||||
* connected, or they will corrupt each others' transmissions)
|
||||
* @param temperature The temperature in degrees Celsius
|
||||
*/
|
||||
esp_err_t ds18x20_measure_and_read(gpio_num_t pin, ds18x20_addr_t addr, int16_t *temperature);
|
||||
|
||||
/**
|
||||
* @brief Perform a ds18x20_measure() followed by ds18x20_read_temp_multi()
|
||||
*
|
||||
* @param pin The GPIO pin connected to the ds18x20 bus
|
||||
* @param addr_list A list of addresses for devices to read.
|
||||
* @param addr_count The number of entries in `addr_list`.
|
||||
* @param result_list An array of int16_ts to hold the returned temperature
|
||||
* values. It should have at least `addr_count` entries.
|
||||
*
|
||||
* @returns `ESP_OK` if all temperatures were fetched successfully
|
||||
*/
|
||||
esp_err_t ds18x20_measure_and_read_multi(gpio_num_t pin, ds18x20_addr_t *addr_list, size_t addr_count, int16_t *result_list);
|
||||
|
||||
/**
|
||||
* @brief Read the scratchpad data for a particular ds18x20 device.
|
||||
*
|
||||
* This is not generally necessary to do directly. It is done automatically
|
||||
* as part of ds18x20_read_temperature().
|
||||
*
|
||||
* @param pin The GPIO pin connected to the ds18x20 device
|
||||
* @param addr The 64-bit address of the device to read. This can be set
|
||||
* to ::DS18X20_ANY to read any device on the bus (but note
|
||||
* that this will only work if there is exactly one device
|
||||
* connected, or they will corrupt each others' transmissions)
|
||||
* @param buffer An 8-byte buffer to hold the read data.
|
||||
*
|
||||
* @returns `ESP_OK` if the command was successfully issued
|
||||
*/
|
||||
esp_err_t ds18x20_read_scratchpad(gpio_num_t pin, ds18x20_addr_t addr, uint8_t *buffer);
|
||||
|
||||
/**
|
||||
* @brief Write the scratchpad data for a particular ds18x20 device.
|
||||
*
|
||||
* @param pin The GPIO pin connected to the ds18x20 device
|
||||
* @param addr The 64-bit address of the device to write. This can be set
|
||||
* to ::DS18X20_ANY to read any device on the bus (but note
|
||||
* that this will only work if there is exactly one device
|
||||
* connected, or they will corrupt each others' transmissions)
|
||||
* @param buffer An 3-byte buffer to hold the data to write
|
||||
*
|
||||
* @returns `ESP_OK` if the command was successfully issued
|
||||
*/
|
||||
esp_err_t ds18x20_write_scratchpad(gpio_num_t pin, ds18x20_addr_t addr, uint8_t *buffer);
|
||||
|
||||
/**
|
||||
* @brief Issue the copy scratchpad command, copying current scratchpad to
|
||||
* EEPROM.
|
||||
*
|
||||
* @param pin The GPIO pin connected to the ds18x20 device
|
||||
* @param addr The 64-bit address of the device to command. This can be set
|
||||
* to ::DS18X20_ANY to read any device on the bus (but note
|
||||
* that this will only work if there is exactly one device
|
||||
* connected, or they will corrupt each others' transmissions)
|
||||
*
|
||||
* @returns `ESP_OK` if the command was successfully issued
|
||||
*/
|
||||
esp_err_t ds18x20_copy_scratchpad(gpio_num_t pin, ds18x20_addr_t addr);
|
||||
|
||||
|
||||
#endif /* _DS18X20_H */
|
||||
233
components/peripherals/src/energy_meter.c
Executable file
233
components/peripherals/src/energy_meter.c
Executable file
@@ -0,0 +1,233 @@
|
||||
#include <memory.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h> // <- Necessário para bool
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_timer.h"
|
||||
#include "nvs.h"
|
||||
|
||||
#include "energy_meter.h"
|
||||
#include "meter.h"
|
||||
#include "serial_mdb.h"
|
||||
|
||||
#define NVS_NAMESPACE "evse_emeter"
|
||||
#define NVS_MODEL "model"
|
||||
#define NVS_STATE "state"
|
||||
|
||||
static const char *TAG = "energy_meter";
|
||||
|
||||
static nvs_handle nvs;
|
||||
|
||||
static bool state = false;
|
||||
static meter_model_t model = ENERGY_METER_NONE;
|
||||
|
||||
static uint16_t power = 0;
|
||||
static bool has_session = false;
|
||||
static int64_t start_time = 0;
|
||||
static uint32_t charging_time = 0; // ms
|
||||
static uint32_t consumption = 0; // Ws
|
||||
static float cur[3] = {0, 0, 0};
|
||||
static float vlt[3] = {0, 0, 0};
|
||||
static int64_t prev_time = 0;
|
||||
|
||||
static void set_calc_power(float p, uint32_t delta_ms)
|
||||
{
|
||||
consumption += roundf((p * delta_ms) / 1000.0f);
|
||||
power = roundf(p);
|
||||
}
|
||||
|
||||
void energy_meter_init(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "energy_meter_init");
|
||||
ESP_ERROR_CHECK(nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs));
|
||||
|
||||
uint8_t u8 = ENERGY_METER_NONE;
|
||||
nvs_get_u8(nvs, NVS_MODEL, &u8);
|
||||
model = u8;
|
||||
}
|
||||
|
||||
bool meter_get_state(void)
|
||||
{
|
||||
return serial_mdb_get_meter_state();
|
||||
}
|
||||
|
||||
esp_err_t meter_set_state(bool _state)
|
||||
{
|
||||
state = _state;
|
||||
nvs_set_u8(nvs, NVS_STATE, state);
|
||||
nvs_commit(nvs);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
meter_model_t meter_get_model(void)
|
||||
{
|
||||
return model;
|
||||
}
|
||||
|
||||
esp_err_t meter_set_model(meter_model_t _model)
|
||||
{
|
||||
ESP_LOGI(TAG, "meter_set_model");
|
||||
|
||||
if (_model < 0 || _model > ENERGY_METER_ORNO_517) {
|
||||
ESP_LOGE(TAG, "Model out of range");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
model = _model;
|
||||
nvs_set_u8(nvs, NVS_MODEL, model);
|
||||
nvs_commit(nvs);
|
||||
serial_mdb_set_model(model != ENERGY_METER_NONE);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void energy_meter_start_session(void)
|
||||
{
|
||||
if (!has_session) {
|
||||
ESP_LOGI(TAG, "Start session");
|
||||
start_time = esp_timer_get_time();
|
||||
has_session = true;
|
||||
//meter_start();
|
||||
}
|
||||
}
|
||||
|
||||
void energy_meter_stop_session(void)
|
||||
{
|
||||
if (has_session) {
|
||||
ESP_LOGI(TAG, "Stop session");
|
||||
start_time = 0;
|
||||
consumption = 0;
|
||||
charging_time = 0;
|
||||
has_session = false;
|
||||
//meter_stop();
|
||||
}
|
||||
}
|
||||
|
||||
void energy_meter_process(bool charging, uint16_t charging_current)
|
||||
{
|
||||
int64_t now = esp_timer_get_time();
|
||||
uint32_t delta_ms = (now - prev_time) / 1000;
|
||||
|
||||
if (charging && meter_is_running()) {
|
||||
MeterData data = meter_getData();
|
||||
|
||||
vlt[0] = data.vrmsA;
|
||||
vlt[1] = data.vrmsB;
|
||||
vlt[2] = data.vrmsC;
|
||||
|
||||
cur[0] = data.irmsA;
|
||||
cur[1] = data.irmsB;
|
||||
cur[2] = data.irmsC;
|
||||
|
||||
uint32_t total_power = data.wattA + data.wattB + data.wattC;
|
||||
|
||||
set_calc_power((float)total_power, delta_ms);
|
||||
charging_time += delta_ms;
|
||||
} else {
|
||||
vlt[0] = vlt[1] = vlt[2] = 0;
|
||||
cur[0] = cur[1] = cur[2] = 0;
|
||||
power = 0;
|
||||
}
|
||||
|
||||
prev_time = now;
|
||||
}
|
||||
|
||||
uint32_t energy_meter_get_power(void)
|
||||
{
|
||||
return power;
|
||||
}
|
||||
|
||||
uint32_t energy_meter_get_session_time(void)
|
||||
{
|
||||
return has_session ? (esp_timer_get_time() - start_time) / 1000000 : 0;
|
||||
}
|
||||
|
||||
uint32_t energy_meter_get_charging_time(void)
|
||||
{
|
||||
return charging_time / 1000;
|
||||
}
|
||||
|
||||
uint32_t energy_meter_get_consumption(void)
|
||||
{
|
||||
return consumption / 3600;
|
||||
}
|
||||
|
||||
void energy_meter_get_voltage(float *voltage)
|
||||
{
|
||||
memcpy(voltage, vlt, sizeof(vlt));
|
||||
}
|
||||
|
||||
float energy_meter_get_l1_voltage(void)
|
||||
{
|
||||
return vlt[0];
|
||||
}
|
||||
|
||||
float energy_meter_get_l2_voltage(void)
|
||||
{
|
||||
return vlt[1];
|
||||
}
|
||||
|
||||
float energy_meter_get_l3_voltage(void)
|
||||
{
|
||||
return vlt[2];
|
||||
}
|
||||
|
||||
void energy_meter_get_current(float *current)
|
||||
{
|
||||
memcpy(current, cur, sizeof(cur));
|
||||
}
|
||||
|
||||
float energy_meter_get_l1_current(void)
|
||||
{
|
||||
return cur[0];
|
||||
}
|
||||
|
||||
float energy_meter_get_l2_current(void)
|
||||
{
|
||||
return cur[1];
|
||||
}
|
||||
|
||||
float energy_meter_get_l3_current(void)
|
||||
{
|
||||
return cur[2];
|
||||
}
|
||||
|
||||
|
||||
const char *meter_state_to_str(bool state)
|
||||
{
|
||||
return state == true ? "CONNECTED" : "NOT CONNECTED";
|
||||
}
|
||||
|
||||
const char *meter_model_to_str(meter_model_t mode)
|
||||
{
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case ENERGY_METER_NONE:
|
||||
return "NONE";
|
||||
case ENERGY_METER_ORNO_515:
|
||||
return "OR-WE-515";
|
||||
case ENERGY_METER_ORNO_517:
|
||||
return "OR-WE-517";
|
||||
default:
|
||||
return "NONE";
|
||||
}
|
||||
}
|
||||
|
||||
meter_model_t meter_str_to_model(const char *str)
|
||||
{
|
||||
if (!strcmp(str, "NONE"))
|
||||
{
|
||||
return ENERGY_METER_NONE;
|
||||
}
|
||||
if (!strcmp(str, "OR-WE-515"))
|
||||
{
|
||||
return ENERGY_METER_ORNO_515;
|
||||
}
|
||||
if (!strcmp(str, "OR-WE-517"))
|
||||
{
|
||||
return ENERGY_METER_ORNO_517;
|
||||
}
|
||||
|
||||
return ENERGY_METER_NONE;
|
||||
}
|
||||
245
components/peripherals/src/led.c
Executable file
245
components/peripherals/src/led.c
Executable file
@@ -0,0 +1,245 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "led.h"
|
||||
#include "board_config.h"
|
||||
#include "evse_error.h"
|
||||
#include "evse_api.h"
|
||||
|
||||
#define LED_UPDATE_INTERVAL_MS 100
|
||||
#define BLOCK_TIME pdMS_TO_TICKS(10)
|
||||
|
||||
static const char *TAG = "led";
|
||||
|
||||
typedef struct {
|
||||
gpio_num_t gpio;
|
||||
bool on : 1;
|
||||
uint16_t ontime;
|
||||
uint16_t offtime;
|
||||
TimerHandle_t timer;
|
||||
led_pattern_t pattern;
|
||||
uint8_t blink_count;
|
||||
} led_t;
|
||||
|
||||
static led_t leds[LED_ID_MAX] = {0};
|
||||
static TimerHandle_t led_update_timer = NULL;
|
||||
static evse_state_t led_state = -1;
|
||||
|
||||
// ----------------------------
|
||||
// Funções Internas
|
||||
// ----------------------------
|
||||
|
||||
static void led_update_timer_callback(TimerHandle_t xTimer);
|
||||
static void led_update(void);
|
||||
static void led_apply_by_state(evse_state_t state);
|
||||
|
||||
static inline void led_gpio_write(gpio_num_t gpio, bool level) {
|
||||
if (gpio != GPIO_NUM_NC)
|
||||
gpio_set_level(gpio, level);
|
||||
}
|
||||
|
||||
static void led_timer_callback(TimerHandle_t xTimer)
|
||||
{
|
||||
led_t *led = (led_t *)pvTimerGetTimerID(xTimer);
|
||||
led->on = !led->on;
|
||||
led_gpio_write(led->gpio, led->on);
|
||||
uint32_t next_time = led->on ? led->ontime : led->offtime;
|
||||
|
||||
xTimerChangePeriod(led->timer, pdMS_TO_TICKS(next_time), BLOCK_TIME);
|
||||
}
|
||||
|
||||
// ----------------------------
|
||||
// Inicialização
|
||||
// ----------------------------
|
||||
|
||||
void led_init(void)
|
||||
{
|
||||
gpio_config_t io_conf = {
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_ENABLE,
|
||||
.pin_bit_mask = 0
|
||||
};
|
||||
|
||||
for (int i = 0; i < LED_ID_MAX; i++) {
|
||||
leds[i].gpio = GPIO_NUM_NC;
|
||||
}
|
||||
|
||||
if (board_config.led_stop) {
|
||||
leds[LED_ID_STOP].gpio = board_config.led_stop_gpio;
|
||||
io_conf.pin_bit_mask |= BIT64(board_config.led_stop_gpio);
|
||||
}
|
||||
|
||||
if (board_config.led_charging) {
|
||||
leds[LED_ID_CHARGING].gpio = board_config.led_charging_gpio;
|
||||
io_conf.pin_bit_mask |= BIT64(board_config.led_charging_gpio);
|
||||
}
|
||||
|
||||
if (board_config.led_error) {
|
||||
leds[LED_ID_ERROR].gpio = board_config.led_error_gpio;
|
||||
io_conf.pin_bit_mask |= BIT64(board_config.led_error_gpio);
|
||||
}
|
||||
|
||||
if (io_conf.pin_bit_mask != 0) {
|
||||
ESP_ERROR_CHECK(gpio_config(&io_conf));
|
||||
}
|
||||
|
||||
if (!led_update_timer) {
|
||||
led_update_timer = xTimerCreate("led_update_timer",
|
||||
pdMS_TO_TICKS(LED_UPDATE_INTERVAL_MS),
|
||||
pdTRUE, NULL,
|
||||
led_update_timer_callback);
|
||||
if (led_update_timer) {
|
||||
xTimerStart(led_update_timer, BLOCK_TIME);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to create LED update timer");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------
|
||||
// API Pública
|
||||
// ----------------------------
|
||||
|
||||
void led_set_state(led_id_t led_id, uint16_t ontime, uint16_t offtime)
|
||||
{
|
||||
if (led_id >= LED_ID_MAX) return;
|
||||
|
||||
led_t *led = &leds[led_id];
|
||||
if (led->gpio == GPIO_NUM_NC) return;
|
||||
|
||||
// Evita reconfiguração idêntica
|
||||
if (led->ontime == ontime && led->offtime == offtime)
|
||||
return;
|
||||
|
||||
if (led->timer) {
|
||||
xTimerStop(led->timer, BLOCK_TIME);
|
||||
}
|
||||
|
||||
led->ontime = ontime;
|
||||
led->offtime = offtime;
|
||||
|
||||
if (ontime == 0) {
|
||||
led->on = false;
|
||||
led_gpio_write(led->gpio, 0);
|
||||
} else if (offtime == 0) {
|
||||
led->on = true;
|
||||
led_gpio_write(led->gpio, 1);
|
||||
} else {
|
||||
led->on = true;
|
||||
led_gpio_write(led->gpio, 1);
|
||||
|
||||
if (!led->timer) {
|
||||
led->timer = xTimerCreate("led_timer", pdMS_TO_TICKS(ontime),
|
||||
pdFALSE, (void *)led, led_timer_callback);
|
||||
}
|
||||
|
||||
if (led->timer) {
|
||||
xTimerStart(led->timer, BLOCK_TIME);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void led_apply_pattern(led_id_t id, led_pattern_t pattern)
|
||||
{
|
||||
if (id >= LED_ID_MAX) return;
|
||||
|
||||
led_t *led = &leds[id];
|
||||
if (led->gpio == GPIO_NUM_NC) return;
|
||||
|
||||
if (led->pattern == pattern) return;
|
||||
|
||||
if (led->timer) {
|
||||
xTimerStop(led->timer, BLOCK_TIME);
|
||||
}
|
||||
|
||||
led->pattern = pattern;
|
||||
led->blink_count = 0;
|
||||
|
||||
switch (pattern) {
|
||||
case LED_PATTERN_OFF:
|
||||
led_set_state(id, 0, 0);
|
||||
break;
|
||||
case LED_PATTERN_ON:
|
||||
led_set_state(id, 1, 0);
|
||||
break;
|
||||
case LED_PATTERN_BLINK:
|
||||
led_set_state(id, 500, 500);
|
||||
break;
|
||||
case LED_PATTERN_BLINK_FAST:
|
||||
led_set_state(id, 200, 200);
|
||||
break;
|
||||
case LED_PATTERN_BLINK_SLOW:
|
||||
led_set_state(id, 300, 1700);
|
||||
break;
|
||||
case LED_PATTERN_CHARGING_EFFECT:
|
||||
led_set_state(id, 2000, 1000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------
|
||||
// Controle por Estado
|
||||
// ----------------------------
|
||||
|
||||
static void led_apply_by_state(evse_state_t state)
|
||||
{
|
||||
// Reset todos
|
||||
led_apply_pattern(LED_ID_STOP, LED_PATTERN_OFF);
|
||||
led_apply_pattern(LED_ID_CHARGING, LED_PATTERN_OFF);
|
||||
led_apply_pattern(LED_ID_ERROR, LED_PATTERN_OFF);
|
||||
|
||||
switch (state) {
|
||||
case EVSE_STATE_A:
|
||||
led_apply_pattern(LED_ID_STOP, LED_PATTERN_ON);
|
||||
break;
|
||||
case EVSE_STATE_B1:
|
||||
case EVSE_STATE_B2:
|
||||
case EVSE_STATE_C1:
|
||||
led_apply_pattern(LED_ID_CHARGING, LED_PATTERN_ON);
|
||||
break;
|
||||
case EVSE_STATE_C2:
|
||||
led_apply_pattern(LED_ID_CHARGING, LED_PATTERN_CHARGING_EFFECT);
|
||||
break;
|
||||
case EVSE_STATE_D1:
|
||||
case EVSE_STATE_D2:
|
||||
led_apply_pattern(LED_ID_CHARGING, LED_PATTERN_BLINK_FAST);
|
||||
break;
|
||||
case EVSE_STATE_E:
|
||||
case EVSE_STATE_F:
|
||||
led_apply_pattern(LED_ID_ERROR, LED_PATTERN_BLINK_FAST);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------
|
||||
// Timer Update
|
||||
// ----------------------------
|
||||
|
||||
static void led_update(void)
|
||||
{
|
||||
if (evse_error_is_active()) {
|
||||
led_apply_pattern(LED_ID_ERROR, LED_PATTERN_BLINK_FAST);
|
||||
led_apply_pattern(LED_ID_STOP, LED_PATTERN_OFF);
|
||||
led_apply_pattern(LED_ID_CHARGING, LED_PATTERN_OFF);
|
||||
return;
|
||||
}
|
||||
|
||||
evse_state_t current = evse_get_state();
|
||||
|
||||
if (current != led_state) {
|
||||
led_state = current;
|
||||
led_apply_by_state(current);
|
||||
}
|
||||
}
|
||||
|
||||
static void led_update_timer_callback(TimerHandle_t xTimer)
|
||||
{
|
||||
(void)xTimer;
|
||||
led_update();
|
||||
}
|
||||
308
components/peripherals/src/lm75a.c
Normal file
308
components/peripherals/src/lm75a.c
Normal file
@@ -0,0 +1,308 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/i2c_master.h"
|
||||
|
||||
#define I2C_MASTER_NUM I2C_NUM_1
|
||||
#define I2C_MASTER_SCL_IO GPIO_NUM_22 // CONFIG_EXAMPLE_I2C_SCL /*!< gpio number for I2C master clock */
|
||||
#define I2C_MASTER_SDA_IO GPIO_NUM_21 // CONFIG_EXAMPLE_I2C_SDA /*!< gpio number for I2C master data */
|
||||
#define I2C_MASTER_FREQ_HZ 100000 // CONFIG_I2C_TRANS_SPEED /*!< I2C master clock frequency */
|
||||
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master do not need buffer */
|
||||
#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master do not need buffer */
|
||||
#define LM75A_SLAVE_ADDR 0x48 // CONFIG_LM75A_SLAVE_ADDR /*!< LM75A slave address, you can set any 7bit value */
|
||||
#define ACK_VAL 0x0 /*!< I2C ack value */
|
||||
#define NACK_VAL 0x1 /*!< I2C nack value */
|
||||
#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */
|
||||
#define READ_BIT I2C_MASTER_READ /*!< I2C master read */
|
||||
#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
|
||||
#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */
|
||||
|
||||
/*
|
||||
#define GPIO_INPUT_IO_0 CONFIG_LM75A_OS_PIN
|
||||
#define GPIO_OUTPUT_IO_0 CONFIG_LM75A_VCC_PIN
|
||||
#define GPIO_OUTPUT_PIN_SEL (1ULL << GPIO_OUTPUT_IO_0)
|
||||
#define GPIO_INPUT_PIN_SEL (1ULL << GPIO_INPUT_IO_0)
|
||||
#define ESP_INTR_FLAG_DEFAULT 0
|
||||
*/
|
||||
|
||||
// static xQueueHandle gpio_evt_queue = NULL;
|
||||
// static int gpio_int_task_enable = 0;
|
||||
// static TaskHandle_t gpio_int_task_handle = NULL;
|
||||
|
||||
/**
|
||||
* @brief test code to read esp-i2c-slave
|
||||
* We need to fill the buffer of esp slave device, then master can read them out.
|
||||
*
|
||||
* _______________________________________________________________________________________
|
||||
* | start | slave_addr + rd_bit +ack | read n-1 bytes + ack | read 1 byte + nack | stop |
|
||||
* --------|--------------------------|----------------------|--------------------|------|
|
||||
*
|
||||
*/
|
||||
static esp_err_t i2c_master_read_slave(i2c_port_t i2c_num, uint8_t *data_rd, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
return ESP_OK;
|
||||
}
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (LM75A_SLAVE_ADDR << 1) | READ_BIT, ACK_CHECK_EN);
|
||||
if (size > 1)
|
||||
{
|
||||
i2c_master_read(cmd, data_rd, size - 1, ACK_VAL);
|
||||
}
|
||||
i2c_master_read_byte(cmd, data_rd + size - 1, NACK_VAL);
|
||||
i2c_master_stop(cmd);
|
||||
esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_PERIOD_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test code to write esp-i2c-slave
|
||||
* Master device write data to slave(both esp32),
|
||||
* the data will be stored in slave buffer.
|
||||
* We can read them out from slave buffer.
|
||||
*
|
||||
* ___________________________________________________________________
|
||||
* | start | slave_addr + wr_bit + ack | write n bytes + ack | stop |
|
||||
* --------|---------------------------|----------------------|------|
|
||||
*
|
||||
*/
|
||||
static esp_err_t i2c_master_write_slave(i2c_port_t i2c_num, uint8_t *data_wr, size_t size)
|
||||
{
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (LM75A_SLAVE_ADDR << 1) | WRITE_BIT, ACK_CHECK_EN);
|
||||
i2c_master_write(cmd, data_wr, size, ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_PERIOD_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief i2c master initialization
|
||||
*/
|
||||
static void i2c_master_init()
|
||||
{
|
||||
int i2c_master_port = I2C_MASTER_NUM;
|
||||
i2c_config_t conf;
|
||||
conf.mode = I2C_MODE_MASTER;
|
||||
conf.sda_io_num = I2C_MASTER_SDA_IO;
|
||||
conf.sda_pullup_en = GPIO_PULLUP_DISABLE;
|
||||
conf.scl_io_num = I2C_MASTER_SCL_IO;
|
||||
conf.scl_pullup_en = GPIO_PULLUP_DISABLE;
|
||||
conf.master.clk_speed = I2C_MASTER_FREQ_HZ;
|
||||
conf.clk_flags = 0;
|
||||
|
||||
i2c_param_config(i2c_master_port, &conf);
|
||||
i2c_driver_install(i2c_master_port, conf.mode,
|
||||
I2C_MASTER_RX_BUF_DISABLE,
|
||||
I2C_MASTER_TX_BUF_DISABLE, 0);
|
||||
}
|
||||
|
||||
int lm75a_read_temperature(int show)
|
||||
{
|
||||
uint8_t buf[2];
|
||||
float tmp;
|
||||
buf[0] = 0;
|
||||
i2c_master_write_slave(I2C_MASTER_NUM, buf, 1);
|
||||
i2c_master_read_slave(I2C_MASTER_NUM, buf, 2);
|
||||
tmp = buf[0];
|
||||
if (buf[1] & 128)
|
||||
tmp += 0.5;
|
||||
if (show)
|
||||
printf("lm75a_read_temperature=%.1f\n", tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
static void IRAM_ATTR gpio_isr_handler(void *arg)
|
||||
{
|
||||
uint32_t gpio_num = (uint32_t)arg;
|
||||
xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
|
||||
}
|
||||
|
||||
static void gpio_int_task(void *arg)
|
||||
{
|
||||
uint32_t io_num;
|
||||
gpio_int_task_enable = 1;
|
||||
while (gpio_int_task_enable)
|
||||
{
|
||||
if (xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY))
|
||||
{
|
||||
|
||||
// read temperature to clean int;
|
||||
if (io_num == GPIO_INPUT_IO_0)
|
||||
{
|
||||
printf("GPIO[%d] intr, val: %d\n\n", io_num, gpio_get_level(io_num));
|
||||
lm75a_read_temperature(0); // read to clean interrupt.
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("quit gpio_int_task\n");
|
||||
if (gpio_evt_queue)
|
||||
{
|
||||
vQueueDelete(gpio_evt_queue);
|
||||
gpio_evt_queue = NULL;
|
||||
}
|
||||
gpio_int_task_handle = NULL;
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void init_os_gpio()
|
||||
{
|
||||
printf("init_os_gpio!\n");
|
||||
|
||||
if (gpio_evt_queue == NULL)
|
||||
gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));
|
||||
|
||||
if (gpio_int_task_handle == NULL)
|
||||
{
|
||||
xTaskCreate(gpio_int_task, "gpio_int_task", 2048, NULL, 10, &gpio_int_task_handle);
|
||||
// install gpio isr service
|
||||
gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
|
||||
// hook isr handler for specific gpio pin again
|
||||
gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void *)GPIO_INPUT_IO_0);
|
||||
}
|
||||
}
|
||||
|
||||
static void deinit_os_gpio()
|
||||
{
|
||||
printf("deinit_os_gpio!\n");
|
||||
|
||||
if (gpio_int_task_handle)
|
||||
{
|
||||
gpio_isr_handler_remove(GPIO_INPUT_IO_0);
|
||||
gpio_uninstall_isr_service();
|
||||
gpio_int_task_enable = 0;
|
||||
int io = 0;
|
||||
xQueueSend(gpio_evt_queue, &io, 0); // send a fake signal to quit task.
|
||||
}
|
||||
}
|
||||
|
||||
static void lm75a_vcc_enable()
|
||||
{
|
||||
gpio_config_t io_conf;
|
||||
// enable output for vcc
|
||||
io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL;
|
||||
io_conf.pull_down_en = 0;
|
||||
io_conf.pull_up_en = 0;
|
||||
gpio_config(&io_conf);
|
||||
|
||||
// enable input for interrupt
|
||||
io_conf.intr_type = GPIO_PIN_INTR_NEGEDGE; // GPIO_PIN_INTR_ANYEDGE;
|
||||
io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
|
||||
io_conf.mode = GPIO_MODE_INPUT;
|
||||
io_conf.pull_up_en = 1;
|
||||
gpio_set_pull_mode(GPIO_INPUT_IO_0, GPIO_FLOATING);
|
||||
gpio_config(&io_conf);
|
||||
gpio_set_level(GPIO_OUTPUT_IO_0, 1);
|
||||
}
|
||||
|
||||
static void lm75a_vcc_disable()
|
||||
{
|
||||
gpio_set_level(GPIO_OUTPUT_IO_0, 0);
|
||||
}
|
||||
*/
|
||||
|
||||
void lm75a_init()
|
||||
{
|
||||
// lm75a_vcc_enable();
|
||||
i2c_master_init();
|
||||
}
|
||||
|
||||
void lm75a_deinit()
|
||||
{
|
||||
// deinit_os_gpio();
|
||||
i2c_driver_delete(I2C_MASTER_NUM);
|
||||
// lm75a_vcc_disable();
|
||||
}
|
||||
|
||||
void lm75a_set_tos(int tos)
|
||||
{
|
||||
uint8_t buf[4];
|
||||
printf("lm75a_set_tos: %d\n", tos);
|
||||
// set Tos:
|
||||
buf[0] = 0x3;
|
||||
buf[1] = (tos & 0xff);
|
||||
buf[2] = 0;
|
||||
i2c_master_write_slave(I2C_MASTER_NUM, buf, 3);
|
||||
}
|
||||
|
||||
void lm75a_set_thys(int thys)
|
||||
{
|
||||
uint8_t buf[4];
|
||||
printf("lm75a_set_thys: %d\n", thys);
|
||||
// set Thyst:
|
||||
buf[0] = 0x2;
|
||||
buf[1] = (thys & 0xff);
|
||||
buf[2] = 0;
|
||||
i2c_master_write_slave(I2C_MASTER_NUM, buf, 3);
|
||||
}
|
||||
|
||||
void lm75a_get_tos()
|
||||
{
|
||||
uint8_t buf[4];
|
||||
float tmp;
|
||||
buf[0] = 0x3;
|
||||
i2c_master_write_slave(I2C_MASTER_NUM, buf, 1);
|
||||
i2c_master_read_slave(I2C_MASTER_NUM, buf, 2);
|
||||
tmp = buf[0];
|
||||
if (buf[1] & 128)
|
||||
tmp += 0.5;
|
||||
|
||||
printf("lm75a_get_tos: %.1f\n", tmp);
|
||||
}
|
||||
|
||||
void lm75a_get_thys()
|
||||
{
|
||||
uint8_t buf[4];
|
||||
float tmp;
|
||||
buf[0] = 0x2;
|
||||
i2c_master_write_slave(I2C_MASTER_NUM, buf, 1);
|
||||
i2c_master_read_slave(I2C_MASTER_NUM, buf, 2);
|
||||
tmp = buf[0];
|
||||
if (buf[1] & 128)
|
||||
tmp += 0.5;
|
||||
|
||||
printf("lm75a_get_thys: %.1f\n", tmp);
|
||||
}
|
||||
|
||||
void lm75a_set_int(int en)
|
||||
{
|
||||
uint8_t buf[2];
|
||||
|
||||
en = !!en;
|
||||
if (en)
|
||||
{
|
||||
printf("lm75a_set_int: %d\n", en);
|
||||
buf[0] = 0x1;
|
||||
buf[1] = (1 << 1); // D1 set to 1;
|
||||
i2c_master_write_slave(I2C_MASTER_NUM, buf, 2);
|
||||
i2c_master_read_slave(I2C_MASTER_NUM, buf, 2); // do one time read to clean interrupt before enter interrupt mode.
|
||||
// gpio_set_intr_type(GPIO_INPUT_IO_0, GPIO_INTR_NEGEDGE);
|
||||
// init_os_gpio();
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("lm75a_set_int: %d\n", en);
|
||||
// deinit_os_gpio();
|
||||
buf[0] = 0x1;
|
||||
buf[1] = 0;
|
||||
i2c_master_write_slave(I2C_MASTER_NUM, buf, 2);
|
||||
i2c_master_read_slave(I2C_MASTER_NUM, buf, 2); // do one time read to clean interrupt before enter interrupt mode.
|
||||
}
|
||||
}
|
||||
|
||||
void lm75a_get_osio()
|
||||
{
|
||||
// printf("os_io: %d\n", gpio_get_level(GPIO_INPUT_IO_0));
|
||||
}
|
||||
63
components/peripherals/src/ntc_sensor.c
Executable file
63
components/peripherals/src/ntc_sensor.c
Executable file
@@ -0,0 +1,63 @@
|
||||
#include <sys/param.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "ntc_sensor.h"
|
||||
#include "ntc_driver.h"
|
||||
|
||||
#include "adc.h"
|
||||
|
||||
static const char *TAG = "temp_sensor";
|
||||
|
||||
#define MEASURE_PERIOD 15000 // 10s
|
||||
|
||||
static float temp = 0.0;
|
||||
|
||||
static ntc_device_handle_t ntc = NULL;
|
||||
|
||||
static portMUX_TYPE temp_mux = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
static void ntc_sensor_task_func(void *param) {
|
||||
float t;
|
||||
while (true) {
|
||||
if (ntc_dev_get_temperature(ntc, &t) == ESP_OK) {
|
||||
portENTER_CRITICAL(&temp_mux);
|
||||
temp = t;
|
||||
portEXIT_CRITICAL(&temp_mux);
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(MEASURE_PERIOD));
|
||||
}
|
||||
}
|
||||
|
||||
float ntc_temp_sensor(void) {
|
||||
float t;
|
||||
portENTER_CRITICAL(&temp_mux);
|
||||
t = temp;
|
||||
portEXIT_CRITICAL(&temp_mux);
|
||||
return t;
|
||||
}
|
||||
|
||||
void ntc_sensor_init(void)
|
||||
{
|
||||
|
||||
ESP_LOGI(TAG, "ntc_sensor_init");
|
||||
|
||||
// Select the NTC sensor and initialize the hardware parameters
|
||||
ntc_config_t ntc_config = {
|
||||
.b_value = 3950,
|
||||
.r25_ohm = 10000,
|
||||
.fixed_ohm = 4700,
|
||||
.vdd_mv = 3300,
|
||||
.circuit_mode = CIRCUIT_MODE_NTC_GND,
|
||||
.atten = ADC_ATTEN_DB_12,
|
||||
.channel = ADC_CHANNEL_0,
|
||||
.unit = ADC_UNIT_1};
|
||||
|
||||
// Create the NTC Driver and Init ADC
|
||||
// ntc_device_handle_t ntc = NULL;
|
||||
// adc_oneshot_unit_handle_t adc_handle = NULL;
|
||||
ESP_ERROR_CHECK(ntc_dev_create(&ntc_config, &ntc, &adc_handle));
|
||||
ESP_ERROR_CHECK(ntc_dev_get_adc_handle(ntc, &adc_handle));
|
||||
|
||||
xTaskCreate(ntc_sensor_task_func, "ntc_sensor_task", 5 * 1024, NULL, 5, NULL);
|
||||
}
|
||||
498
components/peripherals/src/onewire.c
Executable file
498
components/peripherals/src/onewire.c
Executable file
@@ -0,0 +1,498 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 zeroday nodemcu.com
|
||||
*
|
||||
* 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.
|
||||
* -------------------------------------------------------------------------------
|
||||
* Portions copyright (C) 2000 Dallas Semiconductor Corporation, under the
|
||||
* following additional terms:
|
||||
*
|
||||
* Except as contained in this notice, the name of Dallas Semiconductor
|
||||
* shall not be used except as stated in the Dallas Semiconductor
|
||||
* Branding Policy.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include "rom/ets_sys.h"
|
||||
|
||||
#include "onewire.h"
|
||||
|
||||
#define ONEWIRE_SELECT_ROM 0x55
|
||||
#define ONEWIRE_SKIP_ROM 0xcc
|
||||
#define ONEWIRE_SEARCH 0xf0
|
||||
#define ONEWIRE_CRC8_TABLE
|
||||
|
||||
static portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
// Waits up to `max_wait` microseconds for the specified pin to go high.
|
||||
// Returns true if successful, false if the bus never comes high (likely
|
||||
// shorted).
|
||||
static inline bool _onewire_wait_for_bus(gpio_num_t pin, int max_wait)
|
||||
{
|
||||
bool state;
|
||||
for (int i = 0; i < ((max_wait + 4) / 5); i++) {
|
||||
if (gpio_get_level(pin))
|
||||
break;
|
||||
ets_delay_us(5);
|
||||
}
|
||||
state = gpio_get_level(pin);
|
||||
// Wait an extra 1us to make sure the devices have an adequate recovery
|
||||
// time before we drive things low again.
|
||||
ets_delay_us(1);
|
||||
return state;
|
||||
}
|
||||
|
||||
static void setup_pin(gpio_num_t pin, bool open_drain)
|
||||
{
|
||||
gpio_set_direction(pin, open_drain ? GPIO_MODE_INPUT_OUTPUT_OD : GPIO_MODE_OUTPUT);
|
||||
// gpio_set_pull_mode(pin, GPIO_PULLUP_ONLY);
|
||||
}
|
||||
|
||||
// Perform the onewire reset function. We will wait up to 250uS for
|
||||
// the bus to come high, if it doesn't then it is broken or shorted
|
||||
// and we return false;
|
||||
//
|
||||
// Returns true if a device asserted a presence pulse, false otherwise.
|
||||
//
|
||||
bool onewire_reset(gpio_num_t pin)
|
||||
{
|
||||
setup_pin(pin, true);
|
||||
|
||||
gpio_set_level(pin, 1);
|
||||
// wait until the wire is high... just in case
|
||||
if (!_onewire_wait_for_bus(pin, 250))
|
||||
return false;
|
||||
|
||||
gpio_set_level(pin, 0);
|
||||
ets_delay_us(480);
|
||||
|
||||
portENTER_CRITICAL(&mux);
|
||||
gpio_set_level(pin, 1); // allow it to float
|
||||
ets_delay_us(70);
|
||||
bool r = !gpio_get_level(pin);
|
||||
portEXIT_CRITICAL(&mux);
|
||||
|
||||
// Wait for all devices to finish pulling the bus low before returning
|
||||
if (!_onewire_wait_for_bus(pin, 410))
|
||||
return false;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static bool _onewire_write_bit(gpio_num_t pin, bool v)
|
||||
{
|
||||
if (!_onewire_wait_for_bus(pin, 10))
|
||||
return false;
|
||||
|
||||
portENTER_CRITICAL(&mux);
|
||||
if (v) {
|
||||
gpio_set_level(pin, 0); // drive output low
|
||||
ets_delay_us(10);
|
||||
gpio_set_level(pin, 1); // allow output high
|
||||
ets_delay_us(55);
|
||||
} else {
|
||||
gpio_set_level(pin, 0); // drive output low
|
||||
ets_delay_us(65);
|
||||
gpio_set_level(pin, 1); // allow output high
|
||||
}
|
||||
ets_delay_us(1);
|
||||
portEXIT_CRITICAL(&mux);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int _onewire_read_bit(gpio_num_t pin)
|
||||
{
|
||||
if (!_onewire_wait_for_bus(pin, 10))
|
||||
return -1;
|
||||
|
||||
portENTER_CRITICAL(&mux);
|
||||
gpio_set_level(pin, 0);
|
||||
ets_delay_us(2);
|
||||
gpio_set_level(pin, 1); // let pin float, pull up will raise
|
||||
ets_delay_us(11);
|
||||
int r = gpio_get_level(pin); // Must sample within 15us of start
|
||||
ets_delay_us(48);
|
||||
portEXIT_CRITICAL(&mux);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
// Write a byte. The writing code uses open-drain mode and expects the pullup
|
||||
// resistor to pull the line high when not driven low. If you need strong
|
||||
// power after the write (e.g. DS18B20 in parasite power mode) then call
|
||||
// onewire_power() after this is complete to actively drive the line high.
|
||||
//
|
||||
bool onewire_write(gpio_num_t pin, uint8_t v)
|
||||
{
|
||||
for (uint8_t bitMask = 0x01; bitMask; bitMask <<= 1)
|
||||
if (!_onewire_write_bit(pin, (bitMask & v)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool onewire_write_bytes(gpio_num_t pin, const uint8_t* buf, size_t count)
|
||||
{
|
||||
for (size_t i = 0; i < count; i++)
|
||||
if (!onewire_write(pin, buf[i]))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read a byte
|
||||
//
|
||||
int onewire_read(gpio_num_t pin)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
for (uint8_t bitMask = 0x01; bitMask; bitMask <<= 1) {
|
||||
int bit = _onewire_read_bit(pin);
|
||||
if (bit < 0)
|
||||
return -1;
|
||||
else if (bit)
|
||||
r |= bitMask;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
bool onewire_read_bytes(gpio_num_t pin, uint8_t* buf, size_t count)
|
||||
{
|
||||
size_t i;
|
||||
int b;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
b = onewire_read(pin);
|
||||
if (b < 0)
|
||||
return false;
|
||||
buf[i] = b;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool onewire_select(gpio_num_t pin, onewire_addr_t addr)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
if (!onewire_write(pin, ONEWIRE_SELECT_ROM))
|
||||
return false;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (!onewire_write(pin, addr & 0xff))
|
||||
return false;
|
||||
addr >>= 8;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool onewire_skip_rom(gpio_num_t pin)
|
||||
{
|
||||
return onewire_write(pin, ONEWIRE_SKIP_ROM);
|
||||
}
|
||||
|
||||
bool onewire_power(gpio_num_t pin)
|
||||
{
|
||||
// Make sure the bus is not being held low before driving it high, or we
|
||||
// may end up shorting ourselves out.
|
||||
if (!_onewire_wait_for_bus(pin, 10))
|
||||
return false;
|
||||
|
||||
setup_pin(pin, false);
|
||||
gpio_set_level(pin, 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void onewire_depower(gpio_num_t pin)
|
||||
{
|
||||
setup_pin(pin, true);
|
||||
}
|
||||
|
||||
void onewire_search_start(onewire_search_t* search)
|
||||
{
|
||||
// reset the search state
|
||||
memset(search, 0, sizeof(*search));
|
||||
}
|
||||
|
||||
void onewire_search_prefix(onewire_search_t* search, uint8_t family_code)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
search->rom_no[0] = family_code;
|
||||
for (i = 1; i < 8; i++) {
|
||||
search->rom_no[i] = 0;
|
||||
}
|
||||
search->last_discrepancy = 64;
|
||||
search->last_device_found = false;
|
||||
}
|
||||
|
||||
// Perform a search. If the next device has been successfully enumerated, its
|
||||
// ROM address will be returned. If there are no devices, no further
|
||||
// devices, or something horrible happens in the middle of the
|
||||
// enumeration then ONEWIRE_NONE is returned. Use OneWire::reset_search() to
|
||||
// start over.
|
||||
//
|
||||
// --- Replaced by the one from the Dallas Semiconductor web site ---
|
||||
//--------------------------------------------------------------------------
|
||||
// Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing
|
||||
// search state.
|
||||
// Return 1 : device found, ROM number in ROM_NO buffer
|
||||
// 0 : device not found, end of search
|
||||
//
|
||||
onewire_addr_t onewire_search_next(onewire_search_t* search, gpio_num_t pin)
|
||||
{
|
||||
//TODO: add more checking for read/write errors
|
||||
uint8_t id_bit_number;
|
||||
uint8_t last_zero, search_result;
|
||||
int rom_byte_number;
|
||||
int8_t id_bit, cmp_id_bit;
|
||||
onewire_addr_t addr;
|
||||
unsigned char rom_byte_mask;
|
||||
bool search_direction;
|
||||
|
||||
// initialize for search
|
||||
id_bit_number = 1;
|
||||
last_zero = 0;
|
||||
rom_byte_number = 0;
|
||||
rom_byte_mask = 1;
|
||||
search_result = 0;
|
||||
|
||||
// if the last call was not the last one
|
||||
if (!search->last_device_found) {
|
||||
// 1-Wire reset
|
||||
if (!onewire_reset(pin)) {
|
||||
// reset the search
|
||||
search->last_discrepancy = 0;
|
||||
search->last_device_found = false;
|
||||
return ONEWIRE_NONE;
|
||||
}
|
||||
|
||||
// issue the search command
|
||||
onewire_write(pin, ONEWIRE_SEARCH);
|
||||
|
||||
// loop to do the search
|
||||
do {
|
||||
// read a bit and its complement
|
||||
id_bit = _onewire_read_bit(pin);
|
||||
cmp_id_bit = _onewire_read_bit(pin);
|
||||
|
||||
if ((id_bit == 1) && (cmp_id_bit == 1))
|
||||
break;
|
||||
else {
|
||||
// all devices coupled have 0 or 1
|
||||
if (id_bit != cmp_id_bit)
|
||||
search_direction = id_bit; // bit write value for search
|
||||
else {
|
||||
// if this discrepancy if before the Last Discrepancy
|
||||
// on a previous next then pick the same as last time
|
||||
if (id_bit_number < search->last_discrepancy)
|
||||
search_direction = ((search->rom_no[rom_byte_number] & rom_byte_mask) > 0);
|
||||
else
|
||||
// if equal to last pick 1, if not then pick 0
|
||||
search_direction = (id_bit_number == search->last_discrepancy);
|
||||
|
||||
// if 0 was picked then record its position in LastZero
|
||||
if (!search_direction)
|
||||
last_zero = id_bit_number;
|
||||
}
|
||||
|
||||
// set or clear the bit in the ROM byte rom_byte_number
|
||||
// with mask rom_byte_mask
|
||||
if (search_direction)
|
||||
search->rom_no[rom_byte_number] |= rom_byte_mask;
|
||||
else
|
||||
search->rom_no[rom_byte_number] &= ~rom_byte_mask;
|
||||
|
||||
// serial number search direction write bit
|
||||
_onewire_write_bit(pin, search_direction);
|
||||
|
||||
// increment the byte counter id_bit_number
|
||||
// and shift the mask rom_byte_mask
|
||||
id_bit_number++;
|
||||
rom_byte_mask <<= 1;
|
||||
|
||||
// if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask
|
||||
if (rom_byte_mask == 0) {
|
||||
rom_byte_number++;
|
||||
rom_byte_mask = 1;
|
||||
}
|
||||
}
|
||||
} while (rom_byte_number < 8); // loop until through all ROM bytes 0-7
|
||||
|
||||
// if the search was successful then
|
||||
if (!(id_bit_number < 65)) {
|
||||
// search successful so set last_discrepancy,last_device_found,search_result
|
||||
search->last_discrepancy = last_zero;
|
||||
|
||||
// check for last device
|
||||
if (search->last_discrepancy == 0)
|
||||
search->last_device_found = true;
|
||||
|
||||
search_result = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// if no device found then reset counters so next 'search' will be like a first
|
||||
if (!search_result || !search->rom_no[0]) {
|
||||
search->last_discrepancy = 0;
|
||||
search->last_device_found = false;
|
||||
return ONEWIRE_NONE;
|
||||
} else {
|
||||
addr = 0;
|
||||
for (rom_byte_number = 7; rom_byte_number >= 0; rom_byte_number--) {
|
||||
addr = (addr << 8) | search->rom_no[rom_byte_number];
|
||||
}
|
||||
//printf("Ok I found something at %08x%08x...\n", (uint32_t)(addr >> 32), (uint32_t)addr);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
// The 1-Wire CRC scheme is described in Maxim Application Note 27:
|
||||
// "Understanding and Using Cyclic Redundancy Checks with Maxim iButton Products"
|
||||
//
|
||||
|
||||
#ifdef ONEWIRE_CRC8_TABLE
|
||||
// This table comes from Dallas sample code where it is freely reusable,
|
||||
// though Copyright (c) 2000 Dallas Semiconductor Corporation
|
||||
static const uint8_t dscrc_table[] = {
|
||||
0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,
|
||||
157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220,
|
||||
35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98,
|
||||
190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255,
|
||||
70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7,
|
||||
219, 133, 103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154,
|
||||
101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36,
|
||||
248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185,
|
||||
140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205,
|
||||
17, 79, 173, 243, 112, 46, 204, 146, 211, 141, 111, 49, 178, 236, 14, 80,
|
||||
175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238,
|
||||
50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115,
|
||||
202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139,
|
||||
87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22,
|
||||
233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168,
|
||||
116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53
|
||||
};
|
||||
|
||||
//
|
||||
// Compute a Dallas Semiconductor 8 bit CRC. These show up in the ROM
|
||||
// and the registers. (note: this might better be done without to
|
||||
// table, it would probably be smaller and certainly fast enough
|
||||
// compared to all those delayMicrosecond() calls. But I got
|
||||
// confused, so I use this table from the examples.)
|
||||
//
|
||||
uint8_t onewire_crc8(const uint8_t* data, uint8_t len)
|
||||
{
|
||||
uint8_t crc = 0;
|
||||
|
||||
while (len--)
|
||||
crc = dscrc_table[crc ^ *data++];
|
||||
|
||||
return crc;
|
||||
}
|
||||
#else
|
||||
//
|
||||
// Compute a Dallas Semiconductor 8 bit CRC directly.
|
||||
// this is much slower, but much smaller, than the lookup table.
|
||||
//
|
||||
uint8_t onewire_crc8(const uint8_t* data, uint8_t len)
|
||||
{
|
||||
uint8_t crc = 0;
|
||||
|
||||
while (len--)
|
||||
{
|
||||
uint8_t inbyte = *data++;
|
||||
for (int i = 8; i; i--)
|
||||
{
|
||||
uint8_t mix = (crc ^ inbyte) & 0x01;
|
||||
crc >>= 1;
|
||||
if (mix)
|
||||
crc ^= 0x8C;
|
||||
inbyte >>= 1;
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
#endif /* ONEWIRE_CRC8_TABLE */
|
||||
|
||||
// Compute the 1-Wire CRC16 and compare it against the received CRC.
|
||||
// Example usage (reading a DS2408):
|
||||
// // Put everything in a buffer so we can compute the CRC easily.
|
||||
// uint8_t buf[13];
|
||||
// buf[0] = 0xF0; // Read PIO Registers
|
||||
// buf[1] = 0x88; // LSB address
|
||||
// buf[2] = 0x00; // MSB address
|
||||
// WriteBytes(net, buf, 3); // Write 3 cmd bytes
|
||||
// ReadBytes(net, buf+3, 10); // Read 6 data bytes, 2 0xFF, 2 CRC16
|
||||
// if (!CheckCRC16(buf, 11, &buf[11])) {
|
||||
// // Handle error.
|
||||
// }
|
||||
//
|
||||
// @param input - Array of bytes to checksum.
|
||||
// @param len - How many bytes to use.
|
||||
// @param inverted_crc - The two CRC16 bytes in the received data.
|
||||
// This should just point into the received data,
|
||||
// *not* at a 16-bit integer.
|
||||
// @param crc - The crc starting value (optional)
|
||||
// @return 1, iff the CRC matches.
|
||||
bool onewire_check_crc16(const uint8_t* input, size_t len, const uint8_t* inverted_crc, uint16_t crc_iv)
|
||||
{
|
||||
uint16_t crc = ~onewire_crc16(input, len, crc_iv);
|
||||
return (crc & 0xFF) == inverted_crc[0] && (crc >> 8) == inverted_crc[1];
|
||||
}
|
||||
|
||||
// Compute a Dallas Semiconductor 16 bit CRC. This is required to check
|
||||
// the integrity of data received from many 1-Wire devices. Note that the
|
||||
// CRC computed here is *not* what you'll get from the 1-Wire network,
|
||||
// for two reasons:
|
||||
// 1) The CRC is transmitted bitwise inverted.
|
||||
// 2) Depending on the endian-ness of your processor, the binary
|
||||
// representation of the two-byte return value may have a different
|
||||
// byte order than the two bytes you get from 1-Wire.
|
||||
// @param input - Array of bytes to checksum.
|
||||
// @param len - How many bytes to use.
|
||||
// @param crc - The crc starting value (optional)
|
||||
// @return The CRC16, as defined by Dallas Semiconductor.
|
||||
uint16_t onewire_crc16(const uint8_t* input, size_t len, uint16_t crc_iv)
|
||||
{
|
||||
uint16_t crc = crc_iv;
|
||||
static const uint8_t oddparity[16] = { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 };
|
||||
|
||||
uint16_t i;
|
||||
for (i = 0; i < len; i++) {
|
||||
// Even though we're just copying a byte from the input,
|
||||
// we'll be doing 16-bit computation with it.
|
||||
uint16_t cdata = input[i];
|
||||
cdata = (cdata ^ crc) & 0xff;
|
||||
crc >>= 8;
|
||||
|
||||
if (oddparity[cdata & 0x0F] ^ oddparity[cdata >> 4])
|
||||
crc ^= 0xC001;
|
||||
|
||||
cdata <<= 6;
|
||||
crc ^= cdata;
|
||||
cdata <<= 1;
|
||||
crc ^= cdata;
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
277
components/peripherals/src/onewire.h
Executable file
277
components/peripherals/src/onewire.h
Executable file
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 zeroday nodemcu.com
|
||||
*
|
||||
* 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.
|
||||
* -------------------------------------------------------------------------------
|
||||
* Portions copyright (C) 2000 Dallas Semiconductor Corporation, under the
|
||||
* following additional terms:
|
||||
*
|
||||
* Except as contained in this notice, the name of Dallas Semiconductor
|
||||
* shall not be used except as stated in the Dallas Semiconductor
|
||||
* Branding Policy.
|
||||
*/
|
||||
|
||||
#ifndef ONEWIRE_H_
|
||||
#define ONEWIRE_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "driver/gpio.h"
|
||||
|
||||
/**
|
||||
* Type used to hold all 1-Wire device ROM addresses (64-bit)
|
||||
*/
|
||||
typedef uint64_t onewire_addr_t;
|
||||
|
||||
/**
|
||||
* Structure to contain the current state for onewire_search_next(), etc
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t rom_no[8];
|
||||
uint8_t last_discrepancy;
|
||||
bool last_device_found;
|
||||
} onewire_search_t;
|
||||
|
||||
/**
|
||||
* ::ONEWIRE_NONE is an invalid ROM address that will never occur in a device
|
||||
* (CRC mismatch), and so can be useful as an indicator for "no-such-device",
|
||||
* etc.
|
||||
*/
|
||||
#define ONEWIRE_NONE ((onewire_addr_t)(0xffffffffffffffffLL))
|
||||
|
||||
/**
|
||||
* @brief Perform a 1-Wire reset cycle.
|
||||
*
|
||||
* @param pin The GPIO pin connected to the 1-Wire bus.
|
||||
*
|
||||
* @return `true` if at least one device responds with a presence pulse,
|
||||
* `false` if no devices were detected (or the bus is shorted, etc)
|
||||
*/
|
||||
bool onewire_reset(gpio_num_t pin);
|
||||
|
||||
/**
|
||||
* @brief Issue a 1-Wire "ROM select" command to select a particular device.
|
||||
*
|
||||
* It is necessary to call ::onewire_reset() before calling this function.
|
||||
*
|
||||
* @param pin The GPIO pin connected to the 1-Wire bus.
|
||||
* @param addr The ROM address of the device to select
|
||||
*
|
||||
* @return `true` if the "ROM select" command could be successfully issued,
|
||||
* `false` if there was an error.
|
||||
*/
|
||||
bool onewire_select(gpio_num_t pin, const onewire_addr_t addr);
|
||||
|
||||
/**
|
||||
* @brief Issue a 1-Wire "skip ROM" command to select *all* devices on the bus.
|
||||
*
|
||||
* It is necessary to call ::onewire_reset() before calling this function.
|
||||
*
|
||||
* @param pin The GPIO pin connected to the 1-Wire bus.
|
||||
*
|
||||
* @return `true` if the "skip ROM" command could be successfully issued,
|
||||
* `false` if there was an error.
|
||||
*/
|
||||
bool onewire_skip_rom(gpio_num_t pin);
|
||||
|
||||
/**
|
||||
* @brief Write a byte on the onewire bus.
|
||||
*
|
||||
* The writing code uses open-drain mode and expects the pullup resistor to
|
||||
* pull the line high when not driven low. If you need strong power after the
|
||||
* write (e.g. DS18B20 in parasite power mode) then call ::onewire_power()
|
||||
* after this is complete to actively drive the line high.
|
||||
*
|
||||
* @param pin The GPIO pin connected to the 1-Wire bus.
|
||||
* @param v The byte value to write
|
||||
*
|
||||
* @return `true` if successful, `false` on error.
|
||||
*/
|
||||
bool onewire_write(gpio_num_t pin, uint8_t v);
|
||||
|
||||
/**
|
||||
* @brief Write multiple bytes on the 1-Wire bus.
|
||||
*
|
||||
* See ::onewire_write() for more info.
|
||||
*
|
||||
* @param pin The GPIO pin connected to the 1-Wire bus.
|
||||
* @param buf A pointer to the buffer of bytes to be written
|
||||
* @param count Number of bytes to write
|
||||
*
|
||||
* @return `true` if all bytes written successfully, `false` on error.
|
||||
*/
|
||||
bool onewire_write_bytes(gpio_num_t pin, const uint8_t *buf, size_t count);
|
||||
|
||||
/**
|
||||
* @brief Read a byte from a 1-Wire device.
|
||||
*
|
||||
* @param pin The GPIO pin connected to the 1-Wire bus.
|
||||
*
|
||||
* @return the read byte on success, negative value on error.
|
||||
*/
|
||||
int onewire_read(gpio_num_t pin);
|
||||
|
||||
/**
|
||||
* @brief Read multiple bytes from a 1-Wire device.
|
||||
*
|
||||
* @param pin The GPIO pin connected to the 1-Wire bus.
|
||||
* @param[out] buf A pointer to the buffer to contain the read bytes
|
||||
* @param count Number of bytes to read
|
||||
*
|
||||
* @return `true` on success, `false` on error.
|
||||
*/
|
||||
bool onewire_read_bytes(gpio_num_t pin, uint8_t *buf, size_t count);
|
||||
|
||||
/**
|
||||
* @brief Actively drive the bus high to provide extra power for certain
|
||||
* operations of parasitically-powered devices.
|
||||
*
|
||||
* For parasitically-powered devices which need more power than can be
|
||||
* provided via the normal pull-up resistor, it may be necessary for some
|
||||
* operations to drive the bus actively high. This function can be used to
|
||||
* perform that operation.
|
||||
*
|
||||
* The bus can be depowered once it is no longer needed by calling
|
||||
* ::onewire_depower(), or it will be depowered automatically the next time
|
||||
* ::onewire_reset() is called to start another command.
|
||||
*
|
||||
* @note Make sure the device(s) you are powering will not pull more current
|
||||
* than the ESP32/ESP8266 is able to supply via its GPIO pins (this is
|
||||
* especially important when multiple devices are on the same bus and
|
||||
* they are all performing a power-intensive operation at the same time
|
||||
* (i.e. multiple DS18B20 sensors, which have all been given a
|
||||
* "convert T" operation by using ::onewire_skip_rom())).
|
||||
*
|
||||
* @note This routine will check to make sure that the bus is already high
|
||||
* before driving it, to make sure it doesn't attempt to drive it high
|
||||
* while something else is pulling it low (which could cause a reset or
|
||||
* damage the ESP32/ESP8266).
|
||||
*
|
||||
* @param pin The GPIO pin connected to the 1-Wire bus.
|
||||
*
|
||||
* @return `true` on success, `false` on error.
|
||||
*/
|
||||
bool onewire_power(gpio_num_t pin);
|
||||
|
||||
/**
|
||||
* @brief Stop forcing power onto the bus.
|
||||
*
|
||||
* You only need to do this if you previously called ::onewire_power() to drive
|
||||
* the bus high and now want to allow it to float instead. Note that
|
||||
* onewire_reset() will also automatically depower the bus first, so you do
|
||||
* not need to call this first if you just want to start a new operation.
|
||||
*
|
||||
* @param pin The GPIO pin connected to the 1-Wire bus.
|
||||
*/
|
||||
void onewire_depower(gpio_num_t pin);
|
||||
|
||||
/**
|
||||
* @brief Clear the search state so that it will start from the beginning on
|
||||
* the next call to ::onewire_search_next().
|
||||
*
|
||||
* @param[out] search The onewire_search_t structure to reset.
|
||||
*/
|
||||
void onewire_search_start(onewire_search_t *search);
|
||||
|
||||
/**
|
||||
* @brief Setup the search to search for devices with the specified
|
||||
* "family code".
|
||||
*
|
||||
* @param[out] search The onewire_search_t structure to update.
|
||||
* @param family_code The "family code" to search for.
|
||||
*/
|
||||
void onewire_search_prefix(onewire_search_t *search, uint8_t family_code);
|
||||
|
||||
/**
|
||||
* @brief Search for the next device on the bus.
|
||||
*
|
||||
* The order of returned device addresses is deterministic. You will always
|
||||
* get the same devices in the same order.
|
||||
*
|
||||
* @note It might be a good idea to check the CRC to make sure you didn't get
|
||||
* garbage.
|
||||
*
|
||||
* @return the address of the next device on the bus, or ::ONEWIRE_NONE if
|
||||
* there is no next address. ::ONEWIRE_NONE might also mean that
|
||||
* the bus is shorted, there are no devices, or you have already
|
||||
* retrieved all of them.
|
||||
*/
|
||||
onewire_addr_t onewire_search_next(onewire_search_t *search, gpio_num_t pin);
|
||||
|
||||
/**
|
||||
* @brief Compute a Dallas Semiconductor 8 bit CRC.
|
||||
*
|
||||
* These are used in the ROM address and scratchpad registers to verify the
|
||||
* transmitted data is correct.
|
||||
*/
|
||||
uint8_t onewire_crc8(const uint8_t *data, uint8_t len);
|
||||
|
||||
/**
|
||||
* @brief Compute the 1-Wire CRC16 and compare it against the received CRC.
|
||||
*
|
||||
* Example usage (reading a DS2408):
|
||||
* @code{.c}
|
||||
* // Put everything in a buffer so we can compute the CRC easily.
|
||||
* uint8_t buf[13];
|
||||
* buf[0] = 0xF0; // Read PIO Registers
|
||||
* buf[1] = 0x88; // LSB address
|
||||
* buf[2] = 0x00; // MSB address
|
||||
* onewire_write_bytes(pin, buf, 3); // Write 3 cmd bytes
|
||||
* onewire_read_bytes(pin, buf+3, 10); // Read 6 data bytes, 2 0xFF, 2 CRC16
|
||||
* if (!onewire_check_crc16(buf, 11, &buf[11])) {
|
||||
* // TODO: Handle error.
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @param input Array of bytes to checksum.
|
||||
* @param len Number of bytes in `input`
|
||||
* @param inverted_crc The two CRC16 bytes in the received data.
|
||||
* This should just point into the received data,
|
||||
* *not* at a 16-bit integer.
|
||||
* @param crc_iv The crc starting value (optional)
|
||||
*
|
||||
* @return `true` if the CRC matches, `false` otherwise.
|
||||
*/
|
||||
bool onewire_check_crc16(const uint8_t* input, size_t len, const uint8_t* inverted_crc, uint16_t crc_iv);
|
||||
|
||||
/**
|
||||
* @brief Compute a Dallas Semiconductor 16 bit CRC.
|
||||
*
|
||||
* This is required to check the integrity of data received from many 1-Wire
|
||||
* devices. Note that the CRC computed here is *not* what you'll get from the
|
||||
* 1-Wire network, for two reasons:
|
||||
*
|
||||
* 1. The CRC is transmitted bitwise inverted.
|
||||
* 2. Depending on the endian-ness of your processor, the binary
|
||||
* representation of the two-byte return value may have a different
|
||||
* byte order than the two bytes you get from 1-Wire.
|
||||
*
|
||||
* @param input Array of bytes to checksum.
|
||||
* @param len How many bytes are in `input`.
|
||||
* @param crc_iv The crc starting value (optional)
|
||||
*
|
||||
* @return the CRC16, as defined by Dallas Semiconductor.
|
||||
*/
|
||||
uint16_t onewire_crc16(const uint8_t* input, size_t len, uint16_t crc_iv);
|
||||
|
||||
|
||||
#endif /* ONEWIRE_H_ */
|
||||
27
components/peripherals/src/peripherals.c
Executable file
27
components/peripherals/src/peripherals.c
Executable file
@@ -0,0 +1,27 @@
|
||||
#include "peripherals.h"
|
||||
#include "adc.h"
|
||||
#include "led.h"
|
||||
#include "buzzer.h"
|
||||
#include "pilot.h"
|
||||
#include "proximity.h"
|
||||
#include "ac_relay.h"
|
||||
#include "socket_lock.h"
|
||||
#include "rcm.h"
|
||||
#include "energy_meter.h"
|
||||
#include "aux_io.h"
|
||||
#include "ntc_sensor.h"
|
||||
|
||||
void peripherals_init(void)
|
||||
{
|
||||
ac_relay_init();
|
||||
led_init();
|
||||
buzzer_init();
|
||||
adc_init();
|
||||
pilot_init();
|
||||
proximity_init();
|
||||
// socket_lock_init();
|
||||
// rcm_init();
|
||||
energy_meter_init();
|
||||
// aux_init();
|
||||
ntc_sensor_init();
|
||||
}
|
||||
186
components/peripherals/src/pilot.c
Executable file
186
components/peripherals/src/pilot.c
Executable file
@@ -0,0 +1,186 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "driver/ledc.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_rom_sys.h"
|
||||
|
||||
#include "pilot.h"
|
||||
#include "adc.h"
|
||||
#include "board_config.h"
|
||||
|
||||
#define PILOT_PWM_TIMER LEDC_TIMER_0
|
||||
#define PILOT_PWM_CHANNEL LEDC_CHANNEL_0
|
||||
#define PILOT_PWM_SPEED_MODE LEDC_LOW_SPEED_MODE
|
||||
#define PILOT_PWM_DUTY_RES LEDC_TIMER_10_BIT
|
||||
#define PILOT_PWM_MAX_DUTY 1023
|
||||
|
||||
#define NUM_PILOT_SAMPLES 100
|
||||
#define MAX_SAMPLE_ATTEMPTS 1000
|
||||
#define PILOT_EXTREME_PERCENT 10 // 15% superior e inferior
|
||||
|
||||
static const char *TAG = "pilot";
|
||||
static pilot_voltage_cache_t last_voltage = {0, 0};
|
||||
|
||||
static inline uint16_t adc_to_mv(uint16_t x) {
|
||||
return (uint16_t)(((uint32_t)(x) * 3300U) / 4095U);
|
||||
}
|
||||
|
||||
void pilot_init(void)
|
||||
{
|
||||
ledc_timer_config_t ledc_timer = {
|
||||
.speed_mode = PILOT_PWM_SPEED_MODE,
|
||||
.timer_num = PILOT_PWM_TIMER,
|
||||
.duty_resolution = PILOT_PWM_DUTY_RES,
|
||||
.freq_hz = 1000,
|
||||
.clk_cfg = LEDC_AUTO_CLK
|
||||
};
|
||||
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
|
||||
|
||||
ledc_channel_config_t ledc_channel = {
|
||||
.speed_mode = PILOT_PWM_SPEED_MODE,
|
||||
.channel = PILOT_PWM_CHANNEL,
|
||||
.timer_sel = PILOT_PWM_TIMER,
|
||||
.intr_type = LEDC_INTR_DISABLE,
|
||||
.gpio_num = board_config.pilot_pwm_gpio,
|
||||
.duty = 0,
|
||||
.hpoint = 0
|
||||
};
|
||||
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
|
||||
ESP_ERROR_CHECK(ledc_stop(PILOT_PWM_SPEED_MODE, PILOT_PWM_CHANNEL, 0));
|
||||
|
||||
ESP_ERROR_CHECK(ledc_fade_func_install(0));
|
||||
|
||||
adc_oneshot_chan_cfg_t config = {
|
||||
.bitwidth = ADC_BITWIDTH_DEFAULT,
|
||||
.atten = ADC_ATTEN_DB_12,
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc_handle, board_config.pilot_adc_channel, &config));
|
||||
}
|
||||
|
||||
void pilot_set_level(bool level)
|
||||
{
|
||||
ESP_LOGI(TAG, "Set level %d", level);
|
||||
ledc_stop(PILOT_PWM_SPEED_MODE, PILOT_PWM_CHANNEL, level ? 1 : 0);
|
||||
}
|
||||
|
||||
void pilot_set_amps(uint16_t amps)
|
||||
{
|
||||
ESP_LOGI(TAG, "Set amps %d", amps);
|
||||
|
||||
if (amps < 60 || amps > 800) {
|
||||
ESP_LOGE(TAG, "Invalid ampere value: %d A*10", amps);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t duty;
|
||||
if (amps <= 510) {
|
||||
duty = (PILOT_PWM_MAX_DUTY * amps) / 600;
|
||||
} else {
|
||||
duty = ((PILOT_PWM_MAX_DUTY * amps) / 2500) + (64 * (PILOT_PWM_MAX_DUTY / 100));
|
||||
}
|
||||
|
||||
if (duty > PILOT_PWM_MAX_DUTY)
|
||||
duty = PILOT_PWM_MAX_DUTY;
|
||||
|
||||
ESP_LOGI(TAG, "Set amp %dA*10 -> duty %lu/%d", amps, duty, PILOT_PWM_MAX_DUTY);
|
||||
ledc_set_duty(PILOT_PWM_SPEED_MODE, PILOT_PWM_CHANNEL, duty);
|
||||
ledc_update_duty(PILOT_PWM_SPEED_MODE, PILOT_PWM_CHANNEL);
|
||||
}
|
||||
|
||||
static int compare_u16(const void *a, const void *b) {
|
||||
return (*(uint16_t *)a - *(uint16_t *)b);
|
||||
}
|
||||
|
||||
static uint16_t select_low_median_qsort(uint16_t *src, int n, int percent) {
|
||||
int k = (n * percent) / 100;
|
||||
if (k == 0) k = 1;
|
||||
|
||||
uint16_t *copy = alloca(n * sizeof(uint16_t));
|
||||
memcpy(copy, src, n * sizeof(uint16_t));
|
||||
|
||||
qsort(copy, n, sizeof(uint16_t), compare_u16);
|
||||
return copy[k / 2];
|
||||
}
|
||||
|
||||
static uint16_t select_high_median_qsort(uint16_t *src, int n, int percent) {
|
||||
int k = (n * percent) / 100;
|
||||
if (k == 0) k = 1;
|
||||
|
||||
uint16_t *copy = alloca(n * sizeof(uint16_t));
|
||||
memcpy(copy, src, n * sizeof(uint16_t));
|
||||
|
||||
qsort(copy, n, sizeof(uint16_t), compare_u16);
|
||||
return copy[n - k + (k / 2)];
|
||||
}
|
||||
|
||||
void pilot_measure(pilot_voltage_t *up_voltage, bool *down_voltage_n12)
|
||||
{
|
||||
ESP_LOGD(TAG, "pilot_measure");
|
||||
|
||||
uint16_t samples[NUM_PILOT_SAMPLES];
|
||||
int collected = 0, attempts = 0;
|
||||
uint16_t sample;
|
||||
|
||||
while (collected < NUM_PILOT_SAMPLES && attempts < MAX_SAMPLE_ATTEMPTS) {
|
||||
if (adc_oneshot_read(adc_handle, board_config.pilot_adc_channel, &sample) == ESP_OK) {
|
||||
samples[collected++] = sample;
|
||||
esp_rom_delay_us(10);
|
||||
} else {
|
||||
esp_rom_delay_us(100);
|
||||
attempts++;
|
||||
}
|
||||
}
|
||||
|
||||
if (collected < NUM_PILOT_SAMPLES) {
|
||||
ESP_LOGW(TAG, "Timeout on sample read (%d/%d)", collected, NUM_PILOT_SAMPLES);
|
||||
*up_voltage = PILOT_VOLTAGE_1;
|
||||
*down_voltage_n12 = false;
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t high_raw = select_high_median_qsort(samples, collected, PILOT_EXTREME_PERCENT);
|
||||
uint16_t low_raw = select_low_median_qsort(samples, collected, PILOT_EXTREME_PERCENT);
|
||||
|
||||
int high_mv = 0;
|
||||
int low_mv = 0;
|
||||
|
||||
if (adc_cali_raw_to_voltage(adc_cali_handle, high_raw, &high_mv) != ESP_OK ||
|
||||
adc_cali_raw_to_voltage(adc_cali_handle, low_raw, &low_mv) != ESP_OK) {
|
||||
ESP_LOGW(TAG, "ADC calibration failed");
|
||||
*up_voltage = PILOT_VOLTAGE_1;
|
||||
*down_voltage_n12 = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (high_mv >= board_config.pilot_down_threshold_12)
|
||||
*up_voltage = PILOT_VOLTAGE_12;
|
||||
else if (high_mv >= board_config.pilot_down_threshold_9)
|
||||
*up_voltage = PILOT_VOLTAGE_9;
|
||||
else if (high_mv >= board_config.pilot_down_threshold_6)
|
||||
*up_voltage = PILOT_VOLTAGE_6;
|
||||
else if (high_mv >= board_config.pilot_down_threshold_3)
|
||||
*up_voltage = PILOT_VOLTAGE_3;
|
||||
else
|
||||
*up_voltage = PILOT_VOLTAGE_1;
|
||||
|
||||
*down_voltage_n12 = (low_mv <= board_config.pilot_down_threshold_n12);
|
||||
|
||||
ESP_LOGD(TAG, "Final: up_voltage=%d, down_voltage_n12=%d", *up_voltage, *down_voltage_n12);
|
||||
}
|
||||
|
||||
bool pilot_get_state(void)
|
||||
{
|
||||
pilot_voltage_t voltage;
|
||||
bool is_n12v;
|
||||
|
||||
pilot_measure(&voltage, &is_n12v);
|
||||
|
||||
// Considera que "estado alto" significa pelo menos 12V (standby ou pronto)
|
||||
return voltage == PILOT_VOLTAGE_12;
|
||||
}
|
||||
64
components/peripherals/src/proximity.c
Executable file
64
components/peripherals/src/proximity.c
Executable file
@@ -0,0 +1,64 @@
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "proximity.h"
|
||||
#include "board_config.h"
|
||||
#include "adc.h"
|
||||
|
||||
static const char *TAG = "proximity";
|
||||
|
||||
void proximity_init(void)
|
||||
{
|
||||
if (board_config.proximity)
|
||||
{
|
||||
adc_oneshot_chan_cfg_t config = {
|
||||
.bitwidth = ADC_BITWIDTH_DEFAULT,
|
||||
.atten = ADC_ATTEN_DB_12};
|
||||
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc_handle, board_config.proximity_adc_channel, &config));
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t proximity_get_max_current(void)
|
||||
{
|
||||
int voltage;
|
||||
adc_oneshot_read(adc_handle, board_config.proximity_adc_channel, &voltage);
|
||||
adc_cali_raw_to_voltage(adc_cali_handle, voltage, &voltage);
|
||||
|
||||
ESP_LOGI(TAG, "Measured: %dmV", voltage);
|
||||
|
||||
uint8_t current;
|
||||
|
||||
if (voltage >= board_config.proximity_down_threshold_8)
|
||||
{
|
||||
current = 8;
|
||||
}
|
||||
else if (voltage >= board_config.proximity_down_threshold_10)
|
||||
{
|
||||
current = 10;
|
||||
}
|
||||
|
||||
else if (voltage >= board_config.proximity_down_threshold_13)
|
||||
{
|
||||
current = 13;
|
||||
}
|
||||
else if (voltage >= board_config.proximity_down_threshold_20)
|
||||
{
|
||||
current = 20;
|
||||
}
|
||||
|
||||
else if (voltage >= board_config.proximity_down_threshold_25)
|
||||
{
|
||||
current = 25;
|
||||
}
|
||||
else if (voltage >= board_config.proximity_down_threshold_32)
|
||||
{
|
||||
current = 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
current = 32;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Max current: %dA", current);
|
||||
|
||||
return current;
|
||||
}
|
||||
76
components/peripherals/src/rcm.c
Executable file
76
components/peripherals/src/rcm.c
Executable file
@@ -0,0 +1,76 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "rcm.h"
|
||||
#include "board_config.h"
|
||||
#include "evse_api.h"
|
||||
|
||||
// static bool do_test = false;
|
||||
|
||||
// static bool triggered = false;
|
||||
|
||||
// static bool test_triggered = false;
|
||||
|
||||
// static void IRAM_ATTR rcm_isr_handler(void* arg)
|
||||
// {
|
||||
// if (!do_test) {
|
||||
// triggered = true;
|
||||
// } else {
|
||||
// test_triggered = true;
|
||||
// }
|
||||
// }
|
||||
|
||||
void rcm_init(void)
|
||||
{
|
||||
if (board_config.rcm) {
|
||||
gpio_config_t io_conf = {};
|
||||
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = BIT64(board_config.rcm_test_gpio);
|
||||
ESP_ERROR_CHECK(gpio_config(&io_conf));
|
||||
|
||||
io_conf.mode = GPIO_MODE_INPUT;
|
||||
// io_conf.intr_type = GPIO_INTR_POSEDGE;
|
||||
io_conf.pin_bit_mask = BIT64(board_config.rcm_gpio);
|
||||
ESP_ERROR_CHECK(gpio_config(&io_conf));
|
||||
//ESP_ERROR_CHECK(gpio_isr_handler_add(board_config.rcm_gpio, rcm_isr_handler, NULL));
|
||||
}
|
||||
}
|
||||
|
||||
bool rcm_test(void)
|
||||
{
|
||||
// do_test = true;
|
||||
// test_triggered = false;
|
||||
|
||||
// gpio_set_level(board_config.rcm_test_gpio, 1);
|
||||
// vTaskDelay(pdMS_TO_TICKS(100));
|
||||
// gpio_set_level(board_config.rcm_test_gpio, 0);
|
||||
|
||||
// do_test = false;
|
||||
|
||||
// return test_triggered;
|
||||
|
||||
gpio_set_level(board_config.rcm_test_gpio, 1);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
bool success = gpio_get_level(board_config.rcm_gpio) == 1;
|
||||
gpio_set_level(board_config.rcm_test_gpio, 0);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool rcm_is_triggered(void)
|
||||
{
|
||||
// bool _triggered = triggered;
|
||||
// if (gpio_get_level(board_config.rcm_gpio) == 0) {
|
||||
// triggered = false;
|
||||
// }
|
||||
// return _triggered;
|
||||
if (gpio_get_level(board_config.rcm_gpio) == 1) {
|
||||
vTaskDelay(pdMS_TO_TICKS(1));
|
||||
return gpio_get_level(board_config.rcm_gpio) == 1;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
227
components/peripherals/src/socket_lock.c
Executable file
227
components/peripherals/src/socket_lock.c
Executable file
@@ -0,0 +1,227 @@
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "nvs.h"
|
||||
|
||||
#include "socket_lock.h"
|
||||
#include "board_config.h"
|
||||
|
||||
#define NVS_NAMESPACE "socket_lock"
|
||||
#define NVS_OPERATING_TIME "op_time"
|
||||
#define NVS_BREAK_TIME "break_time"
|
||||
#define NVS_RETRY_COUNT "retry_count"
|
||||
#define NVS_DETECTION_HIGH "detect_hi"
|
||||
|
||||
#define OPERATING_TIME_MIN 100
|
||||
#define OPERATING_TIME_MAX 1000
|
||||
#define LOCK_DELAY 500
|
||||
|
||||
#define LOCK_BIT BIT0
|
||||
#define UNLOCK_BIT BIT1
|
||||
#define REPEAT_LOCK_BIT BIT2
|
||||
#define REPEAT_UNLOCK_BIT BIT3
|
||||
|
||||
static const char* TAG = "socket_lock";
|
||||
|
||||
static nvs_handle_t nvs;
|
||||
|
||||
static uint16_t operating_time = 300;
|
||||
|
||||
static uint16_t break_time = 1000;
|
||||
|
||||
static bool detection_high;
|
||||
|
||||
static uint8_t retry_count = 5;
|
||||
|
||||
static socket_lock_status_t status;
|
||||
|
||||
static TaskHandle_t socket_lock_task;
|
||||
|
||||
static bool is_locked(void)
|
||||
{
|
||||
gpio_set_level(board_config.socket_lock_a_gpio, 1);
|
||||
gpio_set_level(board_config.socket_lock_b_gpio, 1);
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(board_config.socket_lock_detection_delay));
|
||||
|
||||
return gpio_get_level(board_config.socket_lock_detection_gpio) == detection_high;
|
||||
}
|
||||
|
||||
static void socket_lock_task_func(void* param)
|
||||
{
|
||||
uint32_t notification;
|
||||
|
||||
TickType_t previous_tick = 0;
|
||||
uint8_t attempt = 0;
|
||||
|
||||
while (true) {
|
||||
if (xTaskNotifyWait(0x00, 0xff, ¬ification, portMAX_DELAY)) {
|
||||
if (notification & (LOCK_BIT | UNLOCK_BIT)) {
|
||||
attempt = retry_count;
|
||||
}
|
||||
|
||||
if (notification & (UNLOCK_BIT | REPEAT_UNLOCK_BIT)) {
|
||||
gpio_set_level(board_config.socket_lock_a_gpio, 0);
|
||||
gpio_set_level(board_config.socket_lock_b_gpio, 1);
|
||||
vTaskDelay(pdMS_TO_TICKS(operating_time));
|
||||
|
||||
if (!is_locked()) {
|
||||
ESP_LOGI(TAG, "Unlock OK");
|
||||
status = SOCKED_LOCK_STATUS_IDLE;
|
||||
} else {
|
||||
if (attempt > 1) {
|
||||
ESP_LOGW(TAG, "Not unlocked yet, repeating...");
|
||||
attempt--;
|
||||
xTaskNotify(socket_lock_task, REPEAT_UNLOCK_BIT, eSetBits);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Not unlocked");
|
||||
status = SOCKED_LOCK_STATUS_UNLOCKING_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
gpio_set_level(board_config.socket_lock_a_gpio, 0);
|
||||
gpio_set_level(board_config.socket_lock_b_gpio, 0);
|
||||
} else if (notification & (LOCK_BIT | REPEAT_LOCK_BIT)) {
|
||||
if (notification & LOCK_BIT) {
|
||||
vTaskDelay(pdMS_TO_TICKS(LOCK_DELAY)); //delay before first lock attempt
|
||||
}
|
||||
gpio_set_level(board_config.socket_lock_a_gpio, 1);
|
||||
gpio_set_level(board_config.socket_lock_b_gpio, 0);
|
||||
vTaskDelay(pdMS_TO_TICKS(operating_time));
|
||||
|
||||
if (is_locked()) {
|
||||
ESP_LOGI(TAG, "Lock OK");
|
||||
status = SOCKED_LOCK_STATUS_IDLE;
|
||||
} else {
|
||||
if (attempt > 1) {
|
||||
ESP_LOGW(TAG, "Not locked yet, repeating...");
|
||||
attempt--;
|
||||
xTaskNotify(socket_lock_task, REPEAT_LOCK_BIT, eSetBits);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Not locked");
|
||||
status = SOCKED_LOCK_STATUS_LOCKING_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
gpio_set_level(board_config.socket_lock_a_gpio, 0);
|
||||
gpio_set_level(board_config.socket_lock_b_gpio, 0);
|
||||
}
|
||||
|
||||
TickType_t delay_tick = xTaskGetTickCount() - previous_tick;
|
||||
if (delay_tick < pdMS_TO_TICKS(break_time)) {
|
||||
vTaskDelay(pdMS_TO_TICKS(break_time) - delay_tick);
|
||||
}
|
||||
previous_tick = xTaskGetTickCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void socket_lock_init(void)
|
||||
{
|
||||
if (board_config.socket_lock) {
|
||||
ESP_ERROR_CHECK(nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs));
|
||||
|
||||
nvs_get_u16(nvs, NVS_OPERATING_TIME, &operating_time);
|
||||
|
||||
nvs_get_u16(nvs, NVS_BREAK_TIME, &break_time);
|
||||
|
||||
nvs_get_u8(nvs, NVS_RETRY_COUNT, &retry_count);
|
||||
|
||||
uint8_t u8;
|
||||
if (nvs_get_u8(nvs, NVS_DETECTION_HIGH, &u8) == ESP_OK) {
|
||||
detection_high = u8;
|
||||
}
|
||||
|
||||
gpio_config_t io_conf = {};
|
||||
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = BIT64(board_config.socket_lock_a_gpio) | BIT64(board_config.socket_lock_b_gpio);
|
||||
ESP_ERROR_CHECK(gpio_config(&io_conf));
|
||||
|
||||
io_conf.mode = GPIO_MODE_INPUT;
|
||||
io_conf.pin_bit_mask = BIT64(board_config.socket_lock_detection_gpio);
|
||||
ESP_ERROR_CHECK(gpio_config(&io_conf));
|
||||
|
||||
xTaskCreate(socket_lock_task_func, "socket_lock_task", 2 * 1024, NULL, 10, &socket_lock_task);
|
||||
}
|
||||
}
|
||||
|
||||
bool socket_lock_is_detection_high(void)
|
||||
{
|
||||
return detection_high;
|
||||
}
|
||||
|
||||
void socket_lock_set_detection_high(bool _detection_high)
|
||||
{
|
||||
detection_high = _detection_high;
|
||||
|
||||
nvs_set_u8(nvs, NVS_DETECTION_HIGH, detection_high);
|
||||
nvs_commit(nvs);
|
||||
}
|
||||
|
||||
uint16_t socket_lock_get_operating_time(void)
|
||||
{
|
||||
return operating_time;
|
||||
}
|
||||
|
||||
esp_err_t socket_lock_set_operating_time(uint16_t _operating_time)
|
||||
{
|
||||
if (_operating_time < OPERATING_TIME_MIN || _operating_time > OPERATING_TIME_MAX) {
|
||||
ESP_LOGE(TAG, "Operating time out of range");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
operating_time = _operating_time;
|
||||
nvs_set_u16(nvs, NVS_OPERATING_TIME, operating_time);
|
||||
nvs_commit(nvs);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
uint8_t socket_lock_get_retry_count(void)
|
||||
{
|
||||
return retry_count;
|
||||
}
|
||||
|
||||
void socket_lock_set_retry_count(uint8_t _retry_count)
|
||||
{
|
||||
retry_count = _retry_count;
|
||||
nvs_set_u8(nvs, NVS_RETRY_COUNT, retry_count);
|
||||
nvs_commit(nvs);
|
||||
}
|
||||
|
||||
uint16_t socket_lock_get_break_time(void)
|
||||
{
|
||||
return break_time;
|
||||
}
|
||||
|
||||
esp_err_t socket_lock_set_break_time(uint16_t _break_time)
|
||||
{
|
||||
if (_break_time < board_config.socket_lock_min_break_time) {
|
||||
ESP_LOGE(TAG, "Operating time out of range");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
break_time = _break_time;
|
||||
nvs_set_u16(nvs, NVS_BREAK_TIME, break_time);
|
||||
nvs_commit(nvs);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void socket_lock_set_locked(bool locked)
|
||||
{
|
||||
ESP_LOGI(TAG, "Set locked %d", locked);
|
||||
|
||||
xTaskNotify(socket_lock_task, locked ? LOCK_BIT : UNLOCK_BIT, eSetBits);
|
||||
status = SOCKED_LOCK_STATUS_OPERATING;
|
||||
}
|
||||
|
||||
socket_lock_status_t socket_lock_get_status(void)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
62
components/peripherals/src/temp_sensor.c
Normal file
62
components/peripherals/src/temp_sensor.c
Normal file
@@ -0,0 +1,62 @@
|
||||
#include <sys/param.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
#include "temp_sensor.h"
|
||||
#include "lm75a.h"
|
||||
|
||||
#define MAX_SENSORS 5
|
||||
#define MEASURE_PERIOD 10000 // 10s
|
||||
#define MEASURE_ERR_THRESHOLD 3
|
||||
|
||||
static const char *TAG = "temp_sensor";
|
||||
|
||||
static uint8_t sensor_count = 0;
|
||||
|
||||
static int16_t low_temp = 0;
|
||||
|
||||
static int high_temp = 0;
|
||||
|
||||
static uint8_t measure_err_count = 0;
|
||||
|
||||
static void temp_sensor_task_func(void *param)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
high_temp = lm75a_read_temperature(0);
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(MEASURE_PERIOD));
|
||||
}
|
||||
}
|
||||
|
||||
void temp_sensor_init(void)
|
||||
{
|
||||
|
||||
ESP_LOGW(TAG, "temp_sensor_init");
|
||||
|
||||
lm75a_init();
|
||||
|
||||
xTaskCreate(temp_sensor_task_func, "temp_sensor_task", 5 * 1024, NULL, 5, NULL);
|
||||
}
|
||||
|
||||
uint8_t temp_sensor_get_count(void)
|
||||
{
|
||||
return sensor_count;
|
||||
}
|
||||
|
||||
int16_t temp_sensor_get_low(void)
|
||||
{
|
||||
return low_temp;
|
||||
}
|
||||
|
||||
int temp_sensor_get_high(void)
|
||||
{
|
||||
return high_temp;
|
||||
}
|
||||
|
||||
bool temp_sensor_is_error(void)
|
||||
{
|
||||
return sensor_count == 0 || measure_err_count > MEASURE_ERR_THRESHOLD;
|
||||
}
|
||||
Reference in New Issue
Block a user