Added GPIOs

This commit is contained in:
Martin Ger
2017-03-22 22:57:56 +01:00
parent c49bd02b76
commit ae98d4cdb8
7 changed files with 603 additions and 29 deletions

View File

@@ -33,7 +33,7 @@ ESPPORT ?= /dev/ttyUSB0
TARGET = app
# which modules (subdirectories) of the project to include in compiling
MODULES = driver user mqtt
MODULES = driver user mqtt easygpio
EXTRA_INCDIR = $(BUILD_AREA)/esp-open-sdk/esp-open-lwip/include include
#EXTRA_INCDIR = include

343
easygpio/easygpio.c Normal file
View File

@@ -0,0 +1,343 @@
/*
* easygpio.c
*
* Copyright (c) 2015, eadf (https://github.com/eadf)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Redis nor the names of its contributors 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 OWNER 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 "easygpio.h"
#include "gpio.h"
#include "osapi.h"
#include "ets_sys.h"
#define EASYGPIO_USE_GPIO_INPUT_GET
static void ICACHE_FLASH_ATTR
gpio16_output_conf(void) {
WRITE_PERI_REG(PAD_XPD_DCDC_CONF,
(READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbcUL) | 0x1UL); // mux configuration for XPD_DCDC to output rtc_gpio0
WRITE_PERI_REG(RTC_GPIO_CONF,
(READ_PERI_REG(RTC_GPIO_CONF) & 0xfffffffeUL) | 0x0UL); //mux configuration for out enable
WRITE_PERI_REG(RTC_GPIO_ENABLE,
(READ_PERI_REG(RTC_GPIO_ENABLE) & 0xfffffffeUL) | 0x1UL); //out enable
}
static void ICACHE_FLASH_ATTR
gpio16_input_conf(void) {
WRITE_PERI_REG(PAD_XPD_DCDC_CONF,
(READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbcUL) | 0x1UL); // mux configuration for XPD_DCDC and rtc_gpio0 connection
WRITE_PERI_REG(RTC_GPIO_CONF,
(READ_PERI_REG(RTC_GPIO_CONF) & 0xfffffffeUL) | 0x0UL); //mux configuration for out enable
WRITE_PERI_REG(RTC_GPIO_ENABLE,
READ_PERI_REG(RTC_GPIO_ENABLE) & 0xfffffffeUL); //out disable
}
/**
* Returns the number of active pins in the gpioMask.
*/
uint8_t ICACHE_FLASH_ATTR
easygpio_countBits(uint32_t gpioMask) {
uint8_t i=0;
uint8_t numberOfPins=0;
for (i=0; i<32; i++){
numberOfPins += (gpioMask & BIT(i))?1:0;
}
return numberOfPins;
}
/**
* Returns the gpio name and func for a specific pin.
*/
bool ICACHE_FLASH_ATTR
easygpio_getGPIONameFunc(uint8_t gpio_pin, uint32_t *gpio_name, uint8_t *gpio_func) {
if (gpio_pin == 6 || gpio_pin == 7 || gpio_pin == 8 || gpio_pin == 11 || gpio_pin >= 17) {
os_printf("easygpio_getGPIONameFunc Error: There is no GPIO%d, check your code\n", gpio_pin);
return false;
}
if (gpio_pin == 16) {
os_printf("easygpio_getGPIONameFunc Error: GPIO16 does not have gpio_name and gpio_func\n");
return false;
}
switch ( gpio_pin ) {
case 0:
*gpio_func = FUNC_GPIO0;
*gpio_name = PERIPHS_IO_MUX_GPIO0_U;
return true;
case 1:
*gpio_func = FUNC_GPIO1;
*gpio_name = PERIPHS_IO_MUX_U0TXD_U;
return true;
case 2:
*gpio_func = FUNC_GPIO2;
*gpio_name = PERIPHS_IO_MUX_GPIO2_U;
return true;
case 3:
*gpio_func = FUNC_GPIO3;
*gpio_name = PERIPHS_IO_MUX_U0RXD_U;
return true;
case 4:
*gpio_func = FUNC_GPIO4;
*gpio_name = PERIPHS_IO_MUX_GPIO4_U;
return true;
case 5:
*gpio_func = FUNC_GPIO5;
*gpio_name = PERIPHS_IO_MUX_GPIO5_U;
return true;
case 9:
*gpio_func = FUNC_GPIO9;
*gpio_name = PERIPHS_IO_MUX_SD_DATA2_U;
return true;
case 10:
*gpio_func = FUNC_GPIO10;
*gpio_name = PERIPHS_IO_MUX_SD_DATA3_U;
return true;
case 12:
*gpio_func = FUNC_GPIO12;
*gpio_name = PERIPHS_IO_MUX_MTDI_U;
return true;
case 13:
*gpio_func = FUNC_GPIO13;
*gpio_name = PERIPHS_IO_MUX_MTCK_U;
return true;
case 14:
*gpio_func = FUNC_GPIO14;
*gpio_name = PERIPHS_IO_MUX_MTMS_U;
return true;
case 15:
*gpio_func = FUNC_GPIO15;
*gpio_name = PERIPHS_IO_MUX_MTDO_U;
return true;
default:
return false;
}
return true;
}
/**
* Sets the pull up registers for a pin.
*/
static void ICACHE_FLASH_ATTR
easygpio_setupPullsByName(uint32_t gpio_name, EasyGPIO_PullStatus pullStatus) {
if (EASYGPIO_PULLUP == pullStatus) {
PIN_PULLUP_EN(gpio_name);
} else {
PIN_PULLUP_DIS(gpio_name);
}
}
/**
* Sets the pull registers for a pin.
*/
bool ICACHE_FLASH_ATTR
easygpio_pullMode(uint8_t gpio_pin, EasyGPIO_PullStatus pullStatus) {
uint32_t gpio_name;
uint8_t gpio_func;
if (!easygpio_getGPIONameFunc(gpio_pin, &gpio_name, &gpio_func) ) {
return false;
}
easygpio_setupPullsByName(gpio_name, pullStatus);
return true;
}
/**
* Sets the 'gpio_pin' pin as a GPIO and sets the pull register for that pin.
* 'pullStatus' has no effect on output pins or GPIO16
*/
bool ICACHE_FLASH_ATTR
easygpio_pinMode(uint8_t gpio_pin, EasyGPIO_PullStatus pullStatus, EasyGPIO_PinMode pinMode) {
uint32_t gpio_name;
uint8_t gpio_func;
if (16==gpio_pin) {
// ignoring pull status on GPIO16 for now
if (EASYGPIO_OUTPUT == pinMode) {
gpio16_output_conf();
} else {
gpio16_input_conf();
}
return true;
} else if (!easygpio_getGPIONameFunc(gpio_pin, &gpio_name, &gpio_func) ) {
return false;
}
PIN_FUNC_SELECT(gpio_name, gpio_func);
easygpio_setupPullsByName(gpio_name, pullStatus);
if (EASYGPIO_OUTPUT != pinMode) {
GPIO_DIS_OUTPUT(GPIO_ID_PIN(gpio_pin));
} else {
// must enable the pin or else the WRITE_PERI_REG won't work
gpio_output_set(0, 0, BIT(GPIO_ID_PIN(gpio_pin)),0);
}
return true;
}
/**
* Sets the 'gpio_pin' pin as a GPIO and sets the interrupt to trigger on that pin.
* The 'interruptArg' is the function argument that will be sent to your interruptHandler
*/
bool ICACHE_FLASH_ATTR
easygpio_attachInterrupt(uint8_t gpio_pin, EasyGPIO_PullStatus pullStatus, void (*interruptHandler)(void *arg), void *interruptArg) {
uint32_t gpio_name;
uint8_t gpio_func;
if (gpio_pin == 16) {
os_printf("easygpio_setupInterrupt Error: GPIO16 does not have interrupts\n");
return false;
}
if (!easygpio_getGPIONameFunc(gpio_pin, &gpio_name, &gpio_func) ) {
return false;
}
ETS_GPIO_INTR_ATTACH(interruptHandler, interruptArg);
ETS_GPIO_INTR_DISABLE();
PIN_FUNC_SELECT(gpio_name, gpio_func);
easygpio_setupPullsByName(gpio_name, pullStatus);
// disable output
GPIO_DIS_OUTPUT(gpio_pin);
gpio_register_set(GPIO_PIN_ADDR(gpio_pin), GPIO_PIN_INT_TYPE_SET(GPIO_PIN_INTR_DISABLE)
| GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_DISABLE)
| GPIO_PIN_SOURCE_SET(GPIO_AS_PIN_SOURCE));
//clear gpio14 status
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(gpio_pin));
ETS_GPIO_INTR_ENABLE();
return true;
}
/**
* Detach the interrupt handler from the 'gpio_pin' pin.
*/
bool ICACHE_FLASH_ATTR
easygpio_detachInterrupt(uint8_t gpio_pin) {
if (gpio_pin == 16) {
os_printf("easygpio_setupInterrupt Error: GPIO16 does not have interrupts\n");
return false;
}
// Don't know how to detach interrupt, yet.
// Quick and dirty fix - just disable the interrupt
gpio_pin_intr_state_set(GPIO_ID_PIN(gpio_pin), GPIO_PIN_INTR_DISABLE);
return true;
}
/**
* Uniform way of setting GPIO output value. Handles GPIO 0-16.
*
* You can not rely on that this function will switch the gpio to an output like GPIO_OUTPUT_SET does.
* Use easygpio_outputEnable() to change an input gpio to output mode.
*/
void
easygpio_outputSet(uint8_t gpio_pin, uint8_t value) {
if (16==gpio_pin) {
WRITE_PERI_REG(RTC_GPIO_OUT,
(READ_PERI_REG(RTC_GPIO_OUT) & 0xfffffffeUL) | (0x1UL & value));
} else {
#ifdef EASYGPIO_USE_GPIO_OUTPUT_SET
GPIO_OUTPUT_SET(GPIO_ID_PIN(gpio_pin), value);
#else
if (value&1){
WRITE_PERI_REG( PERIPHS_GPIO_BASEADDR, READ_PERI_REG(PERIPHS_GPIO_BASEADDR) | BIT(gpio_pin));
} else {
WRITE_PERI_REG( PERIPHS_GPIO_BASEADDR, READ_PERI_REG(PERIPHS_GPIO_BASEADDR) & ~BIT(gpio_pin));
}
#endif
}
}
/**
* Uniform way of getting GPIO input value. Handles GPIO 0-16.
* The pin must be initiated with easygpio_pinMode() so that the pin mux is setup as a gpio in the first place.
* If you know that you won't be using GPIO16 then you'd better off by just using GPIO_INPUT_GET().
*/
uint8_t
easygpio_inputGet(uint8_t gpio_pin) {
if (16==gpio_pin) {
return (READ_PERI_REG(RTC_GPIO_IN_DATA) & 1UL);
} else {
#ifdef EASYGPIO_USE_GPIO_INPUT_GET
return GPIO_INPUT_GET(GPIO_ID_PIN(gpio_pin));
#else
// this does *not* work, maybe GPIO_IN_ADDRESS is the wrong address
return ((GPIO_REG_READ(GPIO_IN_ADDRESS) > gpio_pin) & 1UL);
#endif
}
}
/**
* Uniform way of turning an output GPIO pin into input mode. Handles GPIO 0-16.
* The pin must be initiated with easygpio_pinMode() so that the pin mux is setup as a gpio in the first place.
* This function does the same thing as GPIO_DIS_OUTPUT, but works on GPIO16 too.
*/
void easygpio_outputDisable(uint8_t gpio_pin) {
if (16==gpio_pin) {
WRITE_PERI_REG(RTC_GPIO_ENABLE,
READ_PERI_REG(RTC_GPIO_ENABLE) & 0xfffffffeUL); //out disable
} else {
GPIO_DIS_OUTPUT(GPIO_ID_PIN(gpio_pin));
}
}
/**
* Uniform way of turning an input GPIO pin into output mode. Handles GPIO 0-16.
* The pin must be initiated with easygpio_pinMode() so that the pin mux is setup as a gpio in the first place.
*
* This function:
* - should only be used to convert a input pin into an output pin.
* - is a little bit slower than easygpio_outputSet() so you should use that
* function to just change output value.
* - does the same thing as GPIO_OUTPUT_SET, but works on GPIO16 too.
*/
void easygpio_outputEnable(uint8_t gpio_pin, uint8_t value) {
if (16==gpio_pin) {
// write the value before flipping to output
// - so we don't flash previous value for a few ns.
WRITE_PERI_REG(RTC_GPIO_OUT,
(READ_PERI_REG(RTC_GPIO_OUT) & 0xfffffffeUL) | (0x1UL & value));
WRITE_PERI_REG(RTC_GPIO_ENABLE,
(READ_PERI_REG(RTC_GPIO_ENABLE) & 0xfffffffeUL) | 0x1UL); //out enable
} else {
GPIO_OUTPUT_SET(GPIO_ID_PIN(gpio_pin), value);
}
}

114
easygpio/easygpio.h Normal file
View File

@@ -0,0 +1,114 @@
/*
* easygpio.h
*
* Copyright (c) 2015, eadf (https://github.com/eadf)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Redis nor the names of its contributors 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 OWNER 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 EASYGPIO_INCLUDE_EASYGPIO_EASYGPIO_H_
#define EASYGPIO_INCLUDE_EASYGPIO_EASYGPIO_H_
#include "c_types.h"
typedef enum {
EASYGPIO_INPUT=0,
EASYGPIO_OUTPUT=1
} EasyGPIO_PinMode;
typedef enum {
EASYGPIO_PULLUP=3,
EASYGPIO_NOPULL=4
} EasyGPIO_PullStatus;
/**
* Returns the gpio name and func for a specific pin.
*/
bool easygpio_getGPIONameFunc(uint8_t gpio_pin, uint32_t *gpio_name, uint8_t *gpio_func);
/**
* Sets the 'gpio_pin' pin as a GPIO and sets the interrupt to trigger on that pin.
* The 'interruptArg' is the function argument that will be sent to your interruptHandler
* (this way you can several interrupts with one interruptHandler)
*/
bool easygpio_attachInterrupt(uint8_t gpio_pin, EasyGPIO_PullStatus pullStatus, void (*interruptHandler)(void *arg), void *interruptArg);
/**
* Deatach the interrupt handler from the 'gpio_pin' pin.
*/
bool easygpio_detachInterrupt(uint8_t gpio_pin);
/**
* Returns the number of active pins in the gpioMask.
*/
uint8_t easygpio_countBits(uint32_t gpioMask);
/**
* Sets the 'gpio_pin' pin as a GPIO and enables/disables the pull-up on that pin.
* 'pullStatus' has no effect on output pins or GPIO16
*/
bool easygpio_pinMode(uint8_t gpio_pin, EasyGPIO_PullStatus pullStatus, EasyGPIO_PinMode pinMode);
/**
* Enable or disable the internal pull up for a pin.
*/
bool easygpio_pullMode(uint8_t gpio_pin, EasyGPIO_PullStatus pullStatus);
/**
* Uniform way of getting GPIO input value. Handles GPIO 0-16.
* The pin must be initiated with easygpio_pinMode() so that the pin mux is setup as a gpio in the first place.
* If you know that you won't be using GPIO16 then you'd better off by just using GPIO_INPUT_GET().
*/
uint8_t easygpio_inputGet(uint8_t gpio_pin);
/**
* Uniform way of setting GPIO output value. Handles GPIO 0-16.
*
* You can not rely on that this function will switch the gpio to an output like GPIO_OUTPUT_SET does.
* Use easygpio_outputEnable() to change an input gpio to output mode.
*/
void easygpio_outputSet(uint8_t gpio_pin, uint8_t value);
/**
* Uniform way of turning an output GPIO pin into input mode. Handles GPIO 0-16.
* The pin must be initiated with easygpio_pinMode() so that the pin mux is setup as a gpio in the first place.
* This function does the same thing as GPIO_DIS_OUTPUT, but works on GPIO16 too.
*/
void easygpio_outputDisable(uint8_t gpio_pin);
/**
* Uniform way of turning an input GPIO pin into output mode. Handles GPIO 0-16.
* The pin must be initiated with easygpio_pinMode() so that the pin mux is setup as a gpio in the first place.
*
* This function:
* - should only be used to convert a input pin into an output pin.
* - is a little bit slower than easygpio_outputSet() so you should use that
* function to just change output value.
* - does the same thing as GPIO_OUTPUT_SET, but works on GPIO16 too.
*/
void easygpio_outputEnable(uint8_t gpio_pin, uint8_t value);
#endif /* EASYGPIO_INCLUDE_EASYGPIO_EASYGPIO_H_ */

View File

@@ -39,6 +39,8 @@ uint8_t mac[6];
os_sprintf(config->mqtt_id,"%s_%2x%2x%2x", MQTT_ID, mac[3], mac[4], mac[5]);
os_sprintf(config->mqtt_prefix,"%s/%s/system", MQTT_PREFIX, config->mqtt_id);
os_sprintf(config->mqtt_command_topic,"%s/%s/%s", MQTT_PREFIX, config->mqtt_id, "command");
os_sprintf(config->mqtt_gpio_out_topic,"%s/%s/%s", MQTT_PREFIX, config->mqtt_id, "switch");
config->gpio_out_status = 0;
config->mqtt_interval = MQTT_REPORT_INTERVAL;
config->mqtt_topic_mask = 0xffff;

View File

@@ -50,6 +50,8 @@ typedef struct
uint8_t mqtt_id[32]; // MQTT clientId
uint8_t mqtt_prefix[64]; // Topic-prefix
uint8_t mqtt_command_topic[64]; // Topic on which commands are received, "none" if not subscibed
uint8_t mqtt_gpio_out_topic[64]; // Topic on which the status of the gpio_out pin can be set
bool gpio_out_status; // Initial status of the gpio_out pin
uint32_t mqtt_interval; // Interval in secs for status messages, 0 means no messages
uint16_t mqtt_topic_mask;// Mask for active topics

View File

@@ -1,7 +1,7 @@
#ifndef _USER_CONFIG_
#define _USER_CONFIG_
typedef enum {SIG_DO_NOTHING=0, SIG_START_SERVER=1, SIG_SEND_DATA, SIG_UART0, SIG_CONSOLE_RX, SIG_CONSOLE_TX, SIG_PACKET } USER_SIGNALS;
typedef enum {SIG_DO_NOTHING=0, SIG_START_SERVER=1, SIG_SEND_DATA, SIG_UART0, SIG_CONSOLE_RX, SIG_CONSOLE_TX, SIG_PACKET, SIG_GPIO_INT } USER_SIGNALS;
#define WIFI_SSID "ssid"
#define WIFI_PASSWORD "password"
@@ -19,15 +19,9 @@ typedef enum {SIG_DO_NOTHING=0, SIG_START_SERVER=1, SIG_SEND_DATA, SIG_UART0, SI
#define MAX_CON_CMD_SIZE 80
//
// Define this if you have a status LED connected to GPIO LED_NO
// Define this if you have a status LED connected to a GPIO pin
//
#define STATUS_LED 1
#define LED_NO 2
// Select the GPIO init function according to your selected GPIO
//#define SET_LED_GPIO PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_GPIO1)
#define SET_LED_GPIO PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2)
//#define SET_LED_GPIO PIN_FUNC_SELECT (PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO4)
#define STATUS_LED_GIPO 13
//
// Define this to support the "scan" command for AP search
@@ -38,7 +32,7 @@ typedef enum {SIG_DO_NOTHING=0, SIG_START_SERVER=1, SIG_SEND_DATA, SIG_UART0, SI
// Define this to support the "sleep" command for power management and deep sleep
// Requires a connection of GPIO16 and RST (probably not availabe on ESP01 modules)
//
#define ALLOW_SLEEP 1
//#define ALLOW_SLEEP 1
//
// Define this if you want to have access to the config console via TCP.
@@ -78,4 +72,10 @@ typedef enum {SIG_DO_NOTHING=0, SIG_START_SERVER=1, SIG_SEND_DATA, SIG_UART0, SI
#define MQTT_ID "ESPRouter"
#define MQTT_REPORT_INTERVAL 15 /*seconds*/
// Define this if you want to get messages about GPIO pin status changes
#define USER_GPIO_IN 0
// Define this if you want to set an output signal
#define USER_GPIO_OUT 12
#endif

View File

@@ -21,10 +21,16 @@
#include "config_flash.h"
#include "sys_time.h"
#include "easygpio.h"
#ifdef REMOTE_MONITORING
#include "pcap.h"
#endif
#ifdef MQTT_CLIENT
#include "mqtt.h"
#endif
uint32_t readvdd33(void);
uint32_t Vdd;
@@ -59,7 +65,6 @@ void ICACHE_FLASH_ATTR user_set_softap_wifi_config(void);
void ICACHE_FLASH_ATTR user_set_softap_ip_config(void);
#ifdef MQTT_CLIENT
#include "mqtt.h"
#define MQTT_TOPIC_RESPONSE 0x0001
#define MQTT_TOPIC_IP 0x0002
@@ -75,6 +80,8 @@ void ICACHE_FLASH_ATTR user_set_softap_ip_config(void);
#define MQTT_TOPIC_BPSIN 0x0800
#define MQTT_TOPIC_BPSOUT 0x1000
#define MQTT_TOPIC_NOSTATIONS 0x2000
#define MQTT_TOPIC_GPIOIN 0x4000
#define MQTT_TOPIC_GPIOOUT 0x8000
MQTT_Client mqttClient;
bool mqtt_enabled;
@@ -111,6 +118,11 @@ uint8_t ip_str[16];
if (os_strcmp(config.mqtt_command_topic, "none") != 0) {
MQTT_Subscribe(client, config.mqtt_command_topic, 0);
}
#ifdef USER_GPIO_OUT
if (os_strcmp(config.mqtt_command_topic, "none") != 0) {
MQTT_Subscribe(client, config.mqtt_gpio_out_topic, 0);
}
#endif
}
static void ICACHE_FLASH_ATTR mqttDisconnectedCb(uint32_t *args)
@@ -136,6 +148,17 @@ static void ICACHE_FLASH_ATTR mqttDataCb(uint32_t *args, const char* topic, uint
system_os_post(0, SIG_CONSOLE_RX, 0);
return;
}
#ifdef USER_GPIO_OUT
if (topic_len == os_strlen(config.mqtt_gpio_out_topic) && os_strncmp(topic, config.mqtt_gpio_out_topic, topic_len) == 0) {
if (data_len > 0 && data[0] == '0')
config.gpio_out_status = 0;
else
config.gpio_out_status = 1;
easygpio_outputSet(USER_GPIO_OUT, config.gpio_out_status);
mqtt_publish_int(MQTT_TOPIC_GPIOOUT, "GpioOut", "%d", (uint32_t)config.gpio_out_status);
return;
#endif
}
}
#endif /* MQTT_CLIENT */
@@ -291,8 +314,8 @@ err_t ICACHE_FLASH_ATTR my_input_ap (struct pbuf *p, struct netif *inp) {
Bytes_in += p->tot_len;
Packets_in++;
#ifdef STATUS_LED
GPIO_OUTPUT_SET (LED_NO, 1);
#ifdef STATUS_LED_GIPO
GPIO_OUTPUT_SET (STATUS_LED_GIPO, 1);
#endif
#ifdef REMOTE_MONITORING
@@ -318,8 +341,8 @@ err_t ICACHE_FLASH_ATTR my_output_ap (struct netif *outp, struct pbuf *p) {
Bytes_out += p->tot_len;
Packets_out++;
#ifdef STATUS_LED
GPIO_OUTPUT_SET (LED_NO, 0);
#ifdef STATUS_LED_GIPO
GPIO_OUTPUT_SET (STATUS_LED_GIPO, 0);
#endif
#ifdef REMOTE_MONITORING
@@ -578,6 +601,10 @@ void ICACHE_FLASH_ATTR console_handle_command(struct espconn *pespconn)
os_sprintf(response, "System uptime: %d:%02d:%02d\r\nPower supply: %d.%03d V\r\n",
time/3600, (time%3600)/60, time%60, Vdd/1000, Vdd%1000);
ringbuf_memcpy_into(console_tx_buffer, response, os_strlen(response));
#ifdef USER_GPIO_OUT
os_sprintf(response, "GPIO output status: %d\r\n", config.gpio_out_status);
ringbuf_memcpy_into(console_tx_buffer, response, os_strlen(response));
#endif
os_sprintf(response, "%d KiB in (%d packets)\r\n%d KiB out (%d packets)\r\n",
(uint32_t)(Bytes_in/1024), Packets_in,
(uint32_t)(Bytes_out/1024), Packets_out);
@@ -611,8 +638,8 @@ void ICACHE_FLASH_ATTR console_handle_command(struct espconn *pespconn)
os_sprintf(response, "MQTT host: %s\r\nMQTT port: %d\r\nMQTT user: %s\r\nMQTT password: %s\r\n",
config.mqtt_host, config.mqtt_port, config.mqtt_user, config.locked?"***":(char*)config.mqtt_password);
ringbuf_memcpy_into(console_tx_buffer, response, os_strlen(response));
os_sprintf(response, "MQTT id: %s\r\nMQTT prefix: %s\r\nMQTT command topic: %s\r\nMQTT interval: %d s\r\nMQTT mask: %04x\r\n",
config.mqtt_id, config.mqtt_prefix, config.mqtt_command_topic, config.mqtt_interval, config.mqtt_topic_mask);
os_sprintf(response, "MQTT id: %s\r\nMQTT prefix: %s\r\nMQTT command topic: %s\r\nMQTT gpio_out topic: %s\r\nMQTT interval: %d s\r\nMQTT mask: %04x\r\n",
config.mqtt_id, config.mqtt_prefix, config.mqtt_command_topic, config.mqtt_gpio_out_topic, config.mqtt_interval, config.mqtt_topic_mask);
ringbuf_memcpy_into(console_tx_buffer, response, os_strlen(response));
goto command_handled_2;
@@ -1018,7 +1045,27 @@ void ICACHE_FLASH_ATTR console_handle_command(struct espconn *pespconn)
os_sprintf(response, "MQTT topic mask set to %4x\r\n", val);
goto command_handled;
}
#ifdef USER_GPIO_OUT
if (strcmp(tokens[1], "mqtt_gpio_out_topic") == 0)
{
os_strncpy(config.mqtt_gpio_out_topic, tokens[2], 64);
config.mqtt_gpio_out_topic[63] = 0;
os_sprintf(response, "MQTT gpio_out topic set\r\n");
goto command_handled;
}
#endif
#endif /* MQTT_CLIENT */
#ifdef USER_GPIO_OUT
if (strcmp(tokens[1], "gpio_out") == 0)
{
config.gpio_out_status = atoi(tokens[2]);
easygpio_outputSet(USER_GPIO_OUT, config.gpio_out_status);
mqtt_publish_int(MQTT_TOPIC_GPIOOUT, "GpioOut", "%d", (uint32_t)config.gpio_out_status);
os_sprintf(response, "GPIO out set to %d\r\n", config.gpio_out_status);
goto command_handled;
}
#endif
}
}
@@ -1093,8 +1140,8 @@ uint64_t t_new;
uint32_t t_diff;
toggle = !toggle;
#ifdef STATUS_LED
GPIO_OUTPUT_SET (LED_NO, toggle && connected);
#ifdef STATUS_LED_GIPO
GPIO_OUTPUT_SET (STATUS_LED_GIPO, toggle && connected);
#endif
// Power measurement
// Measure Vdd every second, sliding mean over the last 16 secs
@@ -1129,6 +1176,9 @@ uint32_t t_diff;
mqtt_publish_int(MQTT_TOPIC_NOSTATIONS, "NoStations", "%d", config.ap_on?wifi_softap_get_station_num():0);
mqtt_publish_int(MQTT_TOPIC_BPSIN, "Bpsin", "%d", (uint32_t)(Bytes_in-Bytes_in_last)/t_diff);
mqtt_publish_int(MQTT_TOPIC_BPSOUT, "Bpsout", "%d", (uint32_t)(Bytes_out-Bytes_out_last)/t_diff);
#ifdef USER_GPIO_OUT
mqtt_publish_int(MQTT_TOPIC_GPIOOUT, "GpioOut", "%d", (uint32_t)config.gpio_out_status);
#endif
t_old = t_new;
Bytes_in_last = Bytes_in;
@@ -1179,6 +1229,16 @@ static void ICACHE_FLASH_ATTR user_procTask(os_event_t *events)
break;
#endif
*/
#ifdef MQTT_CLIENT
#ifdef USER_GPIO_IN
case SIG_GPIO_INT:
{
mqtt_publish_int(MQTT_TOPIC_GPIOIN, "GpioIn", "%d", (uint32_t)events->par);
//os_printf("GPIO %d %d\r\n", (uint32_t)events->par, easygpio_inputGet(USER_GPIO_IN));
}
break;
#endif
#endif
case SIG_DO_NOTHING:
default:
// Intentionally ignoring other signals
@@ -1346,6 +1406,44 @@ void ICACHE_FLASH_ATTR user_set_station_config(void)
wifi_station_set_auto_connect(config.auto_connect != 0);
}
#ifdef MQTT_CLIENT
#ifdef USER_GPIO_IN
static os_timer_t inttimer;
void ICACHE_FLASH_ATTR int_timer_func(void *arg){
mqtt_publish_int(MQTT_TOPIC_GPIOIN, "GpioIn", "%d", easygpio_inputGet(USER_GPIO_IN));
//os_printf("GPIO %d %d\r\n", (uint32_t)arg, easygpio_inputGet(USER_GPIO_IN));
// Reactivate interrupts for GPIO
gpio_pin_intr_state_set(GPIO_ID_PIN(USER_GPIO_IN), GPIO_PIN_INTR_ANYEDGE);
}
// Interrupt handler - this function will be executed on any edge of USER_GPIO_IN
LOCAL void gpio_intr_handler(void *dummy)
{
uint32 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
if (gpio_status & BIT(USER_GPIO_IN)) {
// Disable interrupt for GPIO
gpio_pin_intr_state_set(GPIO_ID_PIN(USER_GPIO_IN), GPIO_PIN_INTR_DISABLE);
// Post it to the main task
//system_os_post(0, SIG_GPIO_INT, (ETSParam) easygpio_inputGet(USER_GPIO_IN));
// Clear interrupt status for GPIO
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & BIT(USER_GPIO_IN));
// Start the timer
os_timer_setfn(&inttimer, int_timer_func, easygpio_inputGet(USER_GPIO_IN));
os_timer_arm(&inttimer, 50, 0);
// Reactivate interrupts foR GPIO
//gpio_pin_intr_state_set(GPIO_ID_PIN(USER_GPIO_IN), GPIO_PIN_INTR_ANYEDGE);
}
}
#endif /* USER_GPIO_IN */
#endif /* MQTT_CLIENT */
void ICACHE_FLASH_ATTR user_init()
{
@@ -1365,14 +1463,7 @@ void ICACHE_FLASH_ATTR user_init()
os_printf("\r\n\r\nWiFi Repeater V1.3 starting\r\n");
#ifdef STATUS_LED
// Config GPIO pin as output
if (LED_NO == 1) system_set_os_print(0);
SET_LED_GPIO;
GPIO_OUTPUT_SET (LED_NO, 0);
#endif
// Load WiFi-config
// Load config
if (config_load(&config)== 0) {
// valid config in FLASH, can read portmap table
blob_load(0, (uint32_t *)ip_portmap_table, sizeof(struct portmap_table) * IP_PORTMAP_MAX);
@@ -1382,6 +1473,28 @@ void ICACHE_FLASH_ATTR user_init()
blob_zero(0, sizeof(struct portmap_table) * IP_PORTMAP_MAX);
}
#ifdef STATUS_LED_GIPO
// Config GPIO pin as output
#if (STATUS_LED_GIPO == 1)
// Disable output if serial pin is used as status LED
system_set_os_print(0);
#endif
easygpio_pinMode(STATUS_LED_GIPO, EASYGPIO_NOPULL, EASYGPIO_OUTPUT);
GPIO_OUTPUT_SET (STATUS_LED_GIPO, 0);
#endif
#ifdef MQTT_CLIENT
#ifdef USER_GPIO_IN
easygpio_pinMode(USER_GPIO_IN, EASYGPIO_PULLUP, EASYGPIO_INPUT);
easygpio_attachInterrupt(USER_GPIO_IN, EASYGPIO_PULLUP, gpio_intr_handler, NULL);
gpio_pin_intr_state_set(GPIO_ID_PIN(USER_GPIO_IN), GPIO_PIN_INTR_ANYEDGE);
#endif
#endif
#ifdef USER_GPIO_OUT
easygpio_pinMode(USER_GPIO_OUT, EASYGPIO_NOPULL, EASYGPIO_OUTPUT);
easygpio_outputSet(USER_GPIO_OUT, config.gpio_out_status);
#endif
// Configure the AP and start it, if required
if (config.ap_on) {
@@ -1450,6 +1563,6 @@ void ICACHE_FLASH_ATTR user_init()
system_update_cpu_freq(config.clock_speed);
//Start task
system_os_task(user_procTask, user_procTaskPrio,user_procTaskQueue, user_procTaskQueueLen);
system_os_task(user_procTask, user_procTaskPrio, user_procTaskQueue, user_procTaskQueueLen);
}