commit
091a6a89f3
21 changed files with 5538 additions and 0 deletions
@ -0,0 +1,6 @@ |
|||||
|
.cache |
||||
|
build |
||||
|
main/build |
||||
|
main/Kconfig.projbuild |
||||
|
sdkconfig |
||||
|
sdkconfig.old |
@ -0,0 +1,6 @@ |
|||||
|
# The following lines of boilerplate have to be in your project's CMakeLists |
||||
|
# in this exact order for cmake to work correctly |
||||
|
cmake_minimum_required(VERSION 3.16) |
||||
|
|
||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake) |
||||
|
project(plant_water) |
@ -0,0 +1,90 @@ |
|||||
|
# Example: GPIO |
||||
|
|
||||
|
(See the README.md file in the upper level 'examples' directory for more information about examples.) |
||||
|
|
||||
|
This test code shows how to configure GPIO and how to use it with interruption. |
||||
|
|
||||
|
## GPIO functions: |
||||
|
|
||||
|
| GPIO | Direction | Configuration | |
||||
|
| ---------------------------- | --------- | ------------------------------------------------------ | |
||||
|
| CONFIG_GPIO_OUTPUT_0 | output | | |
||||
|
| CONFIG_GPIO_OUTPUT_1 | output | | |
||||
|
| CONFIG_GPIO_INPUT_0 | input | pulled up, interrupt from rising edge and falling edge | |
||||
|
| CONFIG_GPIO_INPUT_1 | input | pulled up, interrupt from rising edge | |
||||
|
|
||||
|
## Test: |
||||
|
1. Connect CONFIG_GPIO_OUTPUT_0 with CONFIG_GPIO_INPUT_0 |
||||
|
2. Connect CONFIG_GPIO_OUTPUT_1 with CONFIG_GPIO_INPUT_1 |
||||
|
3. Generate pulses on CONFIG_GPIO_OUTPUT_0/1, that triggers interrupt on CONFIG_GPIO_INPUT_0/1 |
||||
|
|
||||
|
**Note:** The following pin assignments are used by default, you can change them by `idf.py menuconfig` > `Example Configuration`. |
||||
|
|
||||
|
| | CONFIG_GPIO_OUTPUT_0 | CONFIG_GPIO_OUTPUT_1 | CONFIG_GPIO_INPUT_0 | CONFIG_GPIO_INPUT_1 | |
||||
|
| --------------- | -------------------- | -------------------- | ------------------- | ------------------- | |
||||
|
| ESP32-C2/ESP32H2| 8 | 9 | 4 | 5 | |
||||
|
| All other chips | 18 | 19 | 4 | 5 | |
||||
|
|
||||
|
## How to use example |
||||
|
|
||||
|
Before project configuration and build, be sure to set the correct chip target using `idf.py set-target <chip_name>`. |
||||
|
|
||||
|
### Hardware Required |
||||
|
|
||||
|
* A development board with any Espressif SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.) |
||||
|
* A USB cable for Power supply and programming |
||||
|
* Some jumper wires to connect GPIOs. |
||||
|
|
||||
|
### Configure the project |
||||
|
|
||||
|
### Build and Flash |
||||
|
|
||||
|
Build the project and flash it to the board, then run the monitor tool to view the serial output: |
||||
|
|
||||
|
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project. |
||||
|
|
||||
|
(To exit the serial monitor, type ``Ctrl-]``.) |
||||
|
|
||||
|
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects. |
||||
|
|
||||
|
## Example Output |
||||
|
|
||||
|
As you run the example, you will see the following log: |
||||
|
|
||||
|
``` |
||||
|
I (317) gpio: GPIO[18]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 |
||||
|
I (327) gpio: GPIO[19]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 |
||||
|
I (337) gpio: GPIO[4]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:1 |
||||
|
I (347) gpio: GPIO[5]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:1 |
||||
|
Minimum free heap size: 289892 bytes |
||||
|
cnt: 0 |
||||
|
cnt: 1 |
||||
|
GPIO[4] intr, val: 1 |
||||
|
GPIO[5] intr, val: 1 |
||||
|
cnt: 2 |
||||
|
GPIO[4] intr, val: 0 |
||||
|
cnt: 3 |
||||
|
GPIO[4] intr, val: 1 |
||||
|
GPIO[5] intr, val: 1 |
||||
|
cnt: 4 |
||||
|
GPIO[4] intr, val: 0 |
||||
|
cnt: 5 |
||||
|
GPIO[4] intr, val: 1 |
||||
|
GPIO[5] intr, val: 1 |
||||
|
cnt: 6 |
||||
|
GPIO[4] intr, val: 0 |
||||
|
cnt: 7 |
||||
|
GPIO[4] intr, val: 1 |
||||
|
GPIO[5] intr, val: 1 |
||||
|
cnt: 8 |
||||
|
GPIO[4] intr, val: 0 |
||||
|
cnt: 9 |
||||
|
GPIO[4] intr, val: 1 |
||||
|
GPIO[5] intr, val: 1 |
||||
|
cnt: 10 |
||||
|
... |
||||
|
``` |
||||
|
|
||||
|
## Troubleshooting |
||||
|
|
||||
|
For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. |
@ -0,0 +1,2 @@ |
|||||
|
idf_component_register(SRCS "cjson.c" |
||||
|
INCLUDE_DIRS "include") |
File diff suppressed because it is too large
@ -0,0 +1,4 @@ |
|||||
|
#
|
||||
|
# Component makefile.
|
||||
|
#
|
||||
|
COMPONENT_ADD_INCLUDEDIRS := . |
@ -0,0 +1,300 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), to deal |
||||
|
in the Software without restriction, including without limitation the rights |
||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
|
copies of the Software, and to permit persons to whom the Software is |
||||
|
furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included in |
||||
|
all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
||||
|
THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef cJSON__h |
||||
|
#define cJSON__h |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" |
||||
|
{ |
||||
|
#endif |
||||
|
|
||||
|
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) |
||||
|
#define __WINDOWS__ |
||||
|
#endif |
||||
|
|
||||
|
#ifdef __WINDOWS__ |
||||
|
|
||||
|
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
|
||||
|
|
||||
|
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols |
||||
|
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) |
||||
|
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol |
||||
|
|
||||
|
For *nix builds that support visibility attribute, you can define similar behavior by |
||||
|
|
||||
|
setting default visibility to hidden by adding |
||||
|
-fvisibility=hidden (for gcc) |
||||
|
or |
||||
|
-xldscope=hidden (for sun cc) |
||||
|
to CFLAGS |
||||
|
|
||||
|
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does |
||||
|
|
||||
|
*/ |
||||
|
|
||||
|
#define CJSON_CDECL __cdecl |
||||
|
#define CJSON_STDCALL __stdcall |
||||
|
|
||||
|
/* export symbols by default, this is necessary for copy pasting the C and header file */ |
||||
|
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) |
||||
|
#define CJSON_EXPORT_SYMBOLS |
||||
|
#endif |
||||
|
|
||||
|
#if defined(CJSON_HIDE_SYMBOLS) |
||||
|
#define CJSON_PUBLIC(type) type CJSON_STDCALL |
||||
|
#elif defined(CJSON_EXPORT_SYMBOLS) |
||||
|
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL |
||||
|
#elif defined(CJSON_IMPORT_SYMBOLS) |
||||
|
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL |
||||
|
#endif |
||||
|
#else /* !__WINDOWS__ */ |
||||
|
#define CJSON_CDECL |
||||
|
#define CJSON_STDCALL |
||||
|
|
||||
|
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) |
||||
|
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type |
||||
|
#else |
||||
|
#define CJSON_PUBLIC(type) type |
||||
|
#endif |
||||
|
#endif |
||||
|
|
||||
|
/* project version */ |
||||
|
#define CJSON_VERSION_MAJOR 1 |
||||
|
#define CJSON_VERSION_MINOR 7 |
||||
|
#define CJSON_VERSION_PATCH 15 |
||||
|
|
||||
|
#include <stddef.h> |
||||
|
|
||||
|
/* cJSON Types: */ |
||||
|
#define cJSON_Invalid (0) |
||||
|
#define cJSON_False (1 << 0) |
||||
|
#define cJSON_True (1 << 1) |
||||
|
#define cJSON_NULL (1 << 2) |
||||
|
#define cJSON_Number (1 << 3) |
||||
|
#define cJSON_String (1 << 4) |
||||
|
#define cJSON_Array (1 << 5) |
||||
|
#define cJSON_Object (1 << 6) |
||||
|
#define cJSON_Raw (1 << 7) /* raw json */ |
||||
|
|
||||
|
#define cJSON_IsReference 256 |
||||
|
#define cJSON_StringIsConst 512 |
||||
|
|
||||
|
/* The cJSON structure: */ |
||||
|
typedef struct cJSON |
||||
|
{ |
||||
|
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ |
||||
|
struct cJSON *next; |
||||
|
struct cJSON *prev; |
||||
|
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ |
||||
|
struct cJSON *child; |
||||
|
|
||||
|
/* The type of the item, as above. */ |
||||
|
int type; |
||||
|
|
||||
|
/* The item's string, if type==cJSON_String and type == cJSON_Raw */ |
||||
|
char *valuestring; |
||||
|
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ |
||||
|
int valueint; |
||||
|
/* The item's number, if type==cJSON_Number */ |
||||
|
double valuedouble; |
||||
|
|
||||
|
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ |
||||
|
char *string; |
||||
|
} cJSON; |
||||
|
|
||||
|
typedef struct cJSON_Hooks |
||||
|
{ |
||||
|
/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ |
||||
|
void *(CJSON_CDECL *malloc_fn)(size_t sz); |
||||
|
void (CJSON_CDECL *free_fn)(void *ptr); |
||||
|
} cJSON_Hooks; |
||||
|
|
||||
|
typedef int cJSON_bool; |
||||
|
|
||||
|
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
|
||||
|
* This is to prevent stack overflows. */ |
||||
|
#ifndef CJSON_NESTING_LIMIT |
||||
|
#define CJSON_NESTING_LIMIT 1000 |
||||
|
#endif |
||||
|
|
||||
|
/* returns the version of cJSON as a string */ |
||||
|
CJSON_PUBLIC(const char*) cJSON_Version(void); |
||||
|
|
||||
|
/* Supply malloc, realloc and free functions to cJSON */ |
||||
|
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); |
||||
|
|
||||
|
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ |
||||
|
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length); |
||||
|
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ |
||||
|
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated); |
||||
|
|
||||
|
/* Render a cJSON entity to text for transfer/storage. */ |
||||
|
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); |
||||
|
/* Render a cJSON entity to text for transfer/storage without any formatting. */ |
||||
|
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); |
||||
|
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ |
||||
|
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); |
||||
|
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ |
||||
|
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ |
||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); |
||||
|
/* Delete a cJSON entity and all subentities. */ |
||||
|
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item); |
||||
|
|
||||
|
/* Returns the number of items in an array (or object). */ |
||||
|
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); |
||||
|
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); |
||||
|
/* Get item "string" from object. Case insensitive. */ |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); |
||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); |
||||
|
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ |
||||
|
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); |
||||
|
|
||||
|
/* Check item type and return its value */ |
||||
|
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item); |
||||
|
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item); |
||||
|
|
||||
|
/* These functions check the type of an item */ |
||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); |
||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); |
||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); |
||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); |
||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); |
||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); |
||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); |
||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); |
||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); |
||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); |
||||
|
|
||||
|
/* These calls create a cJSON item of the appropriate type. */ |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); |
||||
|
/* raw json */ |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); |
||||
|
|
||||
|
/* Create a string where valuestring references a string so
|
||||
|
* it will not be freed by cJSON_Delete */ |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); |
||||
|
/* Create an object/array that only references it's elements so
|
||||
|
* they will not be freed by cJSON_Delete */ |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); |
||||
|
|
||||
|
/* These utilities create an Array of count items.
|
||||
|
* The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/ |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count); |
||||
|
|
||||
|
/* Append item to the specified array/object. */ |
||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item); |
||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); |
||||
|
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
|
||||
|
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before |
||||
|
* writing to `item->string` */ |
||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); |
||||
|
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ |
||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); |
||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); |
||||
|
|
||||
|
/* Remove/Detach items from Arrays/Objects. */ |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); |
||||
|
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); |
||||
|
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); |
||||
|
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); |
||||
|
|
||||
|
/* Update array items. */ |
||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ |
||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); |
||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); |
||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); |
||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); |
||||
|
|
||||
|
/* Duplicate a cJSON item */ |
||||
|
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); |
||||
|
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
|
||||
|
* need to be released. With recurse!=0, it will duplicate any children connected to the item. |
||||
|
* The item->next and ->prev pointers are always zero on return from Duplicate. */ |
||||
|
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
|
||||
|
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ |
||||
|
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); |
||||
|
|
||||
|
/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
|
||||
|
* The input pointer json cannot point to a read-only address area, such as a string constant, |
||||
|
* but should point to a readable and writable address area. */ |
||||
|
CJSON_PUBLIC(void) cJSON_Minify(char *json); |
||||
|
|
||||
|
/* Helper functions for creating and adding items to an object at the same time.
|
||||
|
* They return the added item or NULL on failure. */ |
||||
|
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); |
||||
|
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); |
||||
|
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); |
||||
|
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); |
||||
|
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); |
||||
|
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); |
||||
|
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); |
||||
|
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); |
||||
|
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name); |
||||
|
|
||||
|
/* When assigning an integer value, it needs to be propagated to valuedouble too. */ |
||||
|
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) |
||||
|
/* helper for the cJSON_SetNumberValue macro */ |
||||
|
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); |
||||
|
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) |
||||
|
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */ |
||||
|
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring); |
||||
|
|
||||
|
/* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/ |
||||
|
#define cJSON_SetBoolValue(object, boolValue) ( \ |
||||
|
(object != NULL && ((object)->type & (cJSON_False|cJSON_True))) ? \ |
||||
|
(object)->type=((object)->type &(~(cJSON_False|cJSON_True)))|((boolValue)?cJSON_True:cJSON_False) : \ |
||||
|
cJSON_Invalid\ |
||||
|
) |
||||
|
|
||||
|
/* Macro for iterating over an array or object */ |
||||
|
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) |
||||
|
|
||||
|
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ |
||||
|
CJSON_PUBLIC(void *) cJSON_malloc(size_t size); |
||||
|
CJSON_PUBLIC(void) cJSON_free(void *object); |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#endif |
@ -0,0 +1,3 @@ |
|||||
|
idf_component_register(SRCS "esp8266_wrapper.c" |
||||
|
INCLUDE_DIRS "include" |
||||
|
REQUIRES "driver") |
@ -0,0 +1,4 @@ |
|||||
|
#
|
||||
|
# Component makefile.
|
||||
|
#
|
||||
|
COMPONENT_ADD_INCLUDEDIRS := . |
@ -0,0 +1,193 @@ |
|||||
|
/**
|
||||
|
* Wrapper module for source code compatibility with esp-open-rtos. |
||||
|
*/ |
||||
|
|
||||
|
#ifdef ESP_PLATFORM // ESP32 (ESP-IDF)
|
||||
|
|
||||
|
#include <sys/time.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
#include "driver/spi_master.h" |
||||
|
#include "driver/spi_common.h" |
||||
|
|
||||
|
#include "driver/i2c.h" |
||||
|
#include "driver/gpio.h" |
||||
|
|
||||
|
#include "esp8266_wrapper.h" |
||||
|
|
||||
|
// esp-open-rtos SDK function wrapper
|
||||
|
|
||||
|
uint32_t sdk_system_get_time () { |
||||
|
struct timeval time; |
||||
|
gettimeofday(&time,0); |
||||
|
return (uint32_t) (time.tv_sec*(long int)1e6 + time.tv_usec); |
||||
|
} |
||||
|
|
||||
|
bool gpio_isr_service_installed = false; |
||||
|
bool auto_pull_up = false; |
||||
|
bool auto_pull_down = true; |
||||
|
|
||||
|
esp_err_t gpio_set_interrupt(gpio_num_t gpio, |
||||
|
gpio_int_type_t type, |
||||
|
gpio_interrupt_handler_t handler) |
||||
|
{ |
||||
|
if (!gpio_isr_service_installed) |
||||
|
gpio_isr_service_installed = (gpio_install_isr_service(0) == ESP_OK); |
||||
|
|
||||
|
gpio_config_t gpio_cfg = { |
||||
|
.pin_bit_mask = ((uint64_t)(((uint64_t)1)<< gpio)), |
||||
|
.mode = GPIO_MODE_INPUT, |
||||
|
.pull_up_en = auto_pull_up, |
||||
|
.pull_down_en = auto_pull_down, |
||||
|
.intr_type = type |
||||
|
}; |
||||
|
gpio_config(&gpio_cfg); |
||||
|
|
||||
|
// set interrupt handler
|
||||
|
gpio_isr_handler_add(gpio, (gpio_isr_t)handler, (void*)gpio); |
||||
|
|
||||
|
return ESP_OK; |
||||
|
} |
||||
|
|
||||
|
void gpio_enable (gpio_num_t gpio, const gpio_mode_t mode) |
||||
|
{ |
||||
|
gpio_config_t gpio_cfg = { |
||||
|
.pin_bit_mask = ((uint64_t)(((uint64_t)1)<< gpio)), |
||||
|
.mode = mode, |
||||
|
.pull_up_en = auto_pull_up, |
||||
|
.pull_down_en = auto_pull_down, |
||||
|
}; |
||||
|
gpio_config(&gpio_cfg); |
||||
|
} |
||||
|
|
||||
|
// esp-open-rtos I2C interface wrapper
|
||||
|
|
||||
|
#define I2C_ACK_VAL 0x0 |
||||
|
#define I2C_NACK_VAL 0x1 |
||||
|
|
||||
|
void i2c_init (int bus, gpio_num_t scl, gpio_num_t sda, uint32_t freq) |
||||
|
{ |
||||
|
i2c_config_t conf = {0}; |
||||
|
conf.mode = I2C_MODE_MASTER; |
||||
|
conf.sda_io_num = sda; |
||||
|
conf.scl_io_num = scl; |
||||
|
conf.sda_pullup_en = GPIO_PULLUP_ENABLE; |
||||
|
conf.scl_pullup_en = GPIO_PULLUP_ENABLE; |
||||
|
conf.master.clk_speed = freq; |
||||
|
conf.clk_flags = 0; |
||||
|
i2c_param_config(bus, &conf); |
||||
|
i2c_driver_install(bus, I2C_MODE_MASTER, 0, 0, 0); |
||||
|
} |
||||
|
|
||||
|
int i2c_slave_write (uint8_t bus, uint8_t addr, const uint8_t *reg, |
||||
|
uint8_t *data, uint32_t len) |
||||
|
{ |
||||
|
i2c_cmd_handle_t cmd = i2c_cmd_link_create(); |
||||
|
i2c_master_start(cmd); |
||||
|
i2c_master_write_byte(cmd, addr << 1 | I2C_MASTER_WRITE, true); |
||||
|
if (reg) |
||||
|
i2c_master_write_byte(cmd, *reg, true); |
||||
|
if (data) |
||||
|
i2c_master_write(cmd, data, len, true); |
||||
|
i2c_master_stop(cmd); |
||||
|
esp_err_t err = i2c_master_cmd_begin(bus, cmd, 1000 / portTICK_PERIOD_MS); |
||||
|
i2c_cmd_link_delete(cmd); |
||||
|
|
||||
|
return err; |
||||
|
} |
||||
|
|
||||
|
int i2c_slave_read (uint8_t bus, uint8_t addr, const uint8_t *reg, |
||||
|
uint8_t *data, uint32_t len) |
||||
|
{ |
||||
|
if (len == 0) return true; |
||||
|
|
||||
|
i2c_cmd_handle_t cmd = i2c_cmd_link_create(); |
||||
|
if (reg) |
||||
|
{ |
||||
|
i2c_master_start(cmd); |
||||
|
i2c_master_write_byte(cmd, ( addr << 1 ) | I2C_MASTER_WRITE, true); |
||||
|
i2c_master_write_byte(cmd, *reg, true); |
||||
|
if (!data) |
||||
|
i2c_master_stop(cmd); |
||||
|
} |
||||
|
if (data) |
||||
|
{ |
||||
|
i2c_master_start(cmd); |
||||
|
i2c_master_write_byte(cmd, ( addr << 1 ) | I2C_MASTER_READ, true); |
||||
|
if (len > 1) i2c_master_read(cmd, data, len-1, I2C_ACK_VAL); |
||||
|
i2c_master_read_byte(cmd, data + len-1, I2C_NACK_VAL); |
||||
|
i2c_master_stop(cmd); |
||||
|
} |
||||
|
esp_err_t err = i2c_master_cmd_begin(bus, cmd, 1000 / portTICK_PERIOD_MS); |
||||
|
i2c_cmd_link_delete(cmd); |
||||
|
|
||||
|
return err; |
||||
|
} |
||||
|
|
||||
|
// esp-open-rtos SPI interface wrapper
|
||||
|
|
||||
|
#define SPI_MAX_BUS 3 // ESP32 features three SPIs (SPI_HOST, HSPI_HOST and VSPI_HOST)
|
||||
|
#define SPI_MAX_CS 34 // GPIO 33 is the last port that can be used as output
|
||||
|
|
||||
|
spi_device_handle_t spi_handles[SPI_MAX_CS] = { 0 }; |
||||
|
|
||||
|
bool spi_bus_init (spi_host_device_t host, uint8_t sclk , uint8_t miso, uint8_t mosi) |
||||
|
{ |
||||
|
spi_bus_config_t spi_bus_cfg = { |
||||
|
.miso_io_num=miso, |
||||
|
.mosi_io_num=mosi, |
||||
|
.sclk_io_num=sclk, |
||||
|
.quadwp_io_num=-1, |
||||
|
.quadhd_io_num=-1 |
||||
|
}; |
||||
|
return (spi_bus_initialize(host, &spi_bus_cfg, 1) == ESP_OK); |
||||
|
} |
||||
|
|
||||
|
bool spi_device_init (uint8_t bus, uint8_t cs) |
||||
|
{ |
||||
|
if (bus >= SPI_MAX_BUS || cs >= SPI_MAX_CS) |
||||
|
return false; |
||||
|
|
||||
|
if ((spi_handles[cs] = malloc (sizeof(spi_device_handle_t))) == 0) |
||||
|
return false; |
||||
|
|
||||
|
spi_device_interface_config_t dev_cfg = { |
||||
|
.clock_speed_hz = 1e6, // 1 MHz clock
|
||||
|
.mode = 0, // SPI mode 0
|
||||
|
.spics_io_num = cs, // CS GPIO
|
||||
|
.queue_size = 1, |
||||
|
.flags = 0, // no flags set
|
||||
|
.command_bits = 0, // no command bits used
|
||||
|
.address_bits = 0, // register address is first byte in MOSI
|
||||
|
.dummy_bits = 0 // no dummy bits used
|
||||
|
}; |
||||
|
|
||||
|
if (spi_bus_add_device(bus, &dev_cfg, &(spi_handles[cs])) != ESP_OK) |
||||
|
{ |
||||
|
free (spi_handles[cs]); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
size_t spi_transfer_pf (uint8_t bus, uint8_t cs, const uint8_t *mosi, uint8_t *miso, uint16_t len) |
||||
|
{ |
||||
|
spi_transaction_t spi_trans; |
||||
|
|
||||
|
if (cs >= SPI_MAX_CS) |
||||
|
return 0; |
||||
|
|
||||
|
memset(&spi_trans, 0, sizeof(spi_trans)); // zero out spi_trans;
|
||||
|
spi_trans.tx_buffer = mosi; |
||||
|
spi_trans.rx_buffer = miso; |
||||
|
spi_trans.length=len*8; |
||||
|
|
||||
|
if (spi_device_transmit(spi_handles[cs], &spi_trans) != ESP_OK) |
||||
|
return 0; |
||||
|
|
||||
|
return len; |
||||
|
} |
||||
|
|
||||
|
#endif // ESP32 (ESP-IDF)
|
||||
|
|
@ -0,0 +1,108 @@ |
|||||
|
/*
|
||||
|
* Wrapper module for source code compatibility with esp-open-rtos. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef __ESP8266_WRAPPER_H__ |
||||
|
#define __ESP8266_WRAPPER_H__ |
||||
|
|
||||
|
#ifdef ESP_PLATFORM // ESP32 (ESP-IDF)
|
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
#include "driver/gpio.h" |
||||
|
#include "freertos/FreeRTOS.h" |
||||
|
#include "freertos/task.h" |
||||
|
#include "freertos/queue.h" |
||||
|
|
||||
|
#include "driver/uart.h" |
||||
|
#include "driver/spi_common.h" |
||||
|
|
||||
|
/*
|
||||
|
* esp-open-rtos SDK function wrapper |
||||
|
*/ |
||||
|
|
||||
|
uint32_t sdk_system_get_time (); |
||||
|
|
||||
|
#define uart_set_baud(p,r) uart_set_baudrate (p,r) |
||||
|
|
||||
|
#define IRAM IRAM_ATTR |
||||
|
|
||||
|
#define GPIO_INTTYPE_NONE GPIO_INTR_DISABLE |
||||
|
#define GPIO_INTTYPE_EDGE_POS GPIO_INTR_POSEDGE |
||||
|
#define GPIO_INTTYPE_EDGE_NEG GPIO_INTR_NEGEDGE |
||||
|
#define GPIO_INTTYPE_EDGE_ANY GPIO_INTR_ANYEDGE |
||||
|
#define GPIO_INTTYPE_LEVEL_LOW GPIO_INTR_LOW_LEVEL |
||||
|
#define GPIO_INTTYPE_LEVEL_HIGH GPIO_INTR_HIGH_LEVEL |
||||
|
|
||||
|
// Set it true, if isr_service is already installed anywhere else or should
|
||||
|
// not be installed, otherwise, *gpio_set_interrupt* install it when it is
|
||||
|
// called first time.
|
||||
|
extern bool gpio_isr_service_installed; |
||||
|
|
||||
|
// pull-up, pull-down configuration used for next call of *gpio_set_interrupt*
|
||||
|
extern bool auto_pull_up; // default false;
|
||||
|
extern bool auto_pull_down; // default true;
|
||||
|
|
||||
|
// ISR handler type compatible to the ESP8266
|
||||
|
typedef void (*gpio_interrupt_handler_t)(uint8_t gpio); |
||||
|
|
||||
|
// GPIO set interrupt function compatible to ESP8266
|
||||
|
esp_err_t gpio_set_interrupt(gpio_num_t gpio, |
||||
|
gpio_int_type_t type, |
||||
|
gpio_interrupt_handler_t handler); |
||||
|
|
||||
|
// GPIO enable function compatible to esp-open-rtos
|
||||
|
#define GPIO_INPUT GPIO_MODE_INPUT |
||||
|
#define GPIO_OUTPUT GPIO_MODE_OUTPUT |
||||
|
#define GPIO_OUT_OPEN_DRAIN GPIO_MODE_OUTPUT_OD |
||||
|
|
||||
|
void gpio_enable (gpio_num_t gpio, const gpio_mode_t mode); |
||||
|
|
||||
|
/*
|
||||
|
* esp-open-rtos I2C interface wrapper |
||||
|
*/ |
||||
|
|
||||
|
#define I2C_FREQ_80K 80000 |
||||
|
#define I2C_FREQ_100K 100000 |
||||
|
#define I2C_FREQ_400K 400000 |
||||
|
#define I2C_FREQ_500K 500000 |
||||
|
#define I2C_FREQ_600K 600000 |
||||
|
#define I2C_FREQ_800K 800000 |
||||
|
#define I2C_FREQ_1000K 1000000 |
||||
|
#define I2C_FREQ_1300K 1300000 |
||||
|
|
||||
|
#define i2c_set_clock_stretch(bus,cs) // not needed on ESP32
|
||||
|
|
||||
|
void i2c_init (int bus, gpio_num_t scl, gpio_num_t sda, uint32_t freq); |
||||
|
|
||||
|
int i2c_slave_write (uint8_t bus, uint8_t addr, const uint8_t *reg, |
||||
|
uint8_t *data, uint32_t len); |
||||
|
|
||||
|
int i2c_slave_read (uint8_t bus, uint8_t addr, const uint8_t *reg, |
||||
|
uint8_t *data, uint32_t len); |
||||
|
|
||||
|
/*
|
||||
|
* esp-open-rtos SPI interface wrapper |
||||
|
*/ |
||||
|
|
||||
|
bool spi_bus_init (spi_host_device_t host, |
||||
|
uint8_t sclk , uint8_t miso, uint8_t mosi); |
||||
|
|
||||
|
bool spi_device_init (uint8_t bus, uint8_t cs); |
||||
|
|
||||
|
size_t spi_transfer_pf(uint8_t bus, uint8_t cs, |
||||
|
const uint8_t *mosi, uint8_t *miso, uint16_t len); |
||||
|
|
||||
|
/*
|
||||
|
* freertos api wrapper |
||||
|
*/ |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#endif // ESP_PLATFORM
|
||||
|
|
||||
|
#endif // __ESP8266_WRAPPER_H__
|
@ -0,0 +1,3 @@ |
|||||
|
idf_component_register(SRCS "sht3x.c" |
||||
|
INCLUDE_DIRS "include" |
||||
|
REQUIRES "esp8266_wrapper") |
@ -0,0 +1,4 @@ |
|||||
|
#
|
||||
|
# Component makefile.
|
||||
|
#
|
||||
|
COMPONENT_ADD_INCLUDEDIRS := . |
@ -0,0 +1,280 @@ |
|||||
|
/*
|
||||
|
* Driver for Sensirion SHT3x digital temperature and humidity sensor |
||||
|
* connected to I2C |
||||
|
* |
||||
|
* This driver is for the usage with the ESP8266 and FreeRTOS (esp-open-rtos) |
||||
|
* [https://github.com/SuperHouse/esp-open-rtos]. It is also working with ESP32
|
||||
|
* and ESP-IDF [https://github.com/espressif/esp-idf.git] as well as Linux
|
||||
|
* based systems using a wrapper library for ESP8266 functions. |
||||
|
* |
||||
|
* ---------------------------------------------------------------- |
||||
|
* |
||||
|
* The BSD License (3-clause license) |
||||
|
* |
||||
|
* Copyright (c) 2017 Gunar Schorcht (https://github.com/gschorcht)
|
||||
|
* All rights reserved. |
||||
|
* |
||||
|
* 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 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 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 __SHT3x_H__ |
||||
|
#define __SHT3x_H__ |
||||
|
|
||||
|
// Uncomment to enable debug output
|
||||
|
// #define SHT3x_DEBUG_LEVEL_1 // only error messages
|
||||
|
// #define SHT3x_DEBUG_LEVEL_2 // error and debug messages
|
||||
|
|
||||
|
#include "stdint.h" |
||||
|
#include "stdbool.h" |
||||
|
|
||||
|
#include "sht3x_platform.h" |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
// definition of possible I2C slave addresses
|
||||
|
#define SHT3x_ADDR_1 0x44 // ADDR pin connected to GND/VSS (default)
|
||||
|
#define SHT3x_ADDR_2 0x45 // ADDR pin connected to VDD
|
||||
|
|
||||
|
// definition of error codes
|
||||
|
#define SHT3x_OK 0 |
||||
|
#define SHT3x_NOK -1 |
||||
|
|
||||
|
#define SHT3x_I2C_ERROR_MASK 0x000f |
||||
|
#define SHT3x_DRV_ERROR_MASK 0xfff0 |
||||
|
|
||||
|
// error codes for I2C interface ORed with SHT3x error codes
|
||||
|
#define SHT3x_I2C_READ_FAILED 1 |
||||
|
#define SHT3x_I2C_SEND_CMD_FAILED 2 |
||||
|
#define SHT3x_I2C_BUSY 3 |
||||
|
|
||||
|
// SHT3x driver error codes OR ed with error codes for I2C interface
|
||||
|
#define SHT3x_MEAS_NOT_STARTED (1 << 8) |
||||
|
#define SHT3x_MEAS_ALREADY_RUNNING (2 << 8) |
||||
|
#define SHT3x_MEAS_STILL_RUNNING (3 << 8) |
||||
|
#define SHT3x_READ_RAW_DATA_FAILED (4 << 8) |
||||
|
|
||||
|
#define SHT3x_SEND_MEAS_CMD_FAILED (5 << 8) |
||||
|
#define SHT3x_SEND_RESET_CMD_FAILED (6 << 8) |
||||
|
#define SHT3x_SEND_STATUS_CMD_FAILED (7 << 8) |
||||
|
#define SHT3x_SEND_FETCH_CMD_FAILED (8 << 8) |
||||
|
|
||||
|
#define SHT3x_WRONG_CRC_TEMPERATURE (9 << 8) |
||||
|
#define SHT3x_WRONG_CRC_HUMIDITY (10 << 8) |
||||
|
|
||||
|
#define SHT3x_RAW_DATA_SIZE 6 |
||||
|
|
||||
|
/**
|
||||
|
* @brief raw data type |
||||
|
*/ |
||||
|
typedef uint8_t sht3x_raw_data_t [SHT3x_RAW_DATA_SIZE]; |
||||
|
|
||||
|
|
||||
|
/**
|
||||
|
* @brief possible measurement modes |
||||
|
*/ |
||||
|
typedef enum { |
||||
|
sht3x_single_shot = 0, // one single measurement
|
||||
|
sht3x_periodic_05mps, // periodic with 0.5 measurements per second (mps)
|
||||
|
sht3x_periodic_1mps, // periodic with 1 measurements per second (mps)
|
||||
|
sht3x_periodic_2mps, // periodic with 2 measurements per second (mps)
|
||||
|
sht3x_periodic_4mps, // periodic with 4 measurements per second (mps)
|
||||
|
sht3x_periodic_10mps // periodic with 10 measurements per second (mps)
|
||||
|
} sht3x_mode_t; |
||||
|
|
||||
|
|
||||
|
/**
|
||||
|
* @brief possible repeatability modes |
||||
|
*/ |
||||
|
typedef enum { |
||||
|
sht3x_high = 0, |
||||
|
sht3x_medium, |
||||
|
sht3x_low |
||||
|
} sht3x_repeat_t; |
||||
|
|
||||
|
/**
|
||||
|
* @brief SHT3x sensor device data structure type |
||||
|
*/ |
||||
|
typedef struct { |
||||
|
|
||||
|
uint32_t error_code; // combined error codes
|
||||
|
|
||||
|
uint8_t bus; // I2C bus at which sensor is connected
|
||||
|
uint8_t addr; // I2C slave address of the sensor
|
||||
|
|
||||
|
sht3x_mode_t mode; // used measurement mode
|
||||
|
sht3x_repeat_t repeatability; // used repeatability
|
||||
|
|
||||
|
bool meas_started; // indicates whether measurement started
|
||||
|
uint32_t meas_start_time; // measurement start time in us
|
||||
|
bool meas_first; // first measurement in periodic mode
|
||||
|
|
||||
|
} sht3x_sensor_t; |
||||
|
|
||||
|
|
||||
|
/**
|
||||
|
* @brief Initialize a SHT3x sensor |
||||
|
* |
||||
|
* The function creates a data structure describing the sensor and |
||||
|
* initializes the sensor device. |
||||
|
* |
||||
|
* @param bus I2C bus at which the sensor is connected |
||||
|
* @param addr I2C slave address of the sensor |
||||
|
* @return pointer to sensor data structure, or NULL on error |
||||
|
*/ |
||||
|
sht3x_sensor_t* sht3x_init_sensor (uint8_t bus, uint8_t addr); |
||||
|
|
||||
|
|
||||
|
/**
|
||||
|
* @brief High level measurement function |
||||
|
* |
||||
|
* For convenience this function comprises all three steps to perform |
||||
|
* one measurement in only one function: |
||||
|
* |
||||
|
* 1. Starts a measurement in single shot mode with high reliability |
||||
|
* 2. Waits using *vTaskDelay* until measurement results are available |
||||
|
* 3. Returns the results in kind of floating point sensor values |
||||
|
* |
||||
|
* This function is the easiest way to use the sensor. It is most suitable |
||||
|
* for users that don't want to have the control on sensor details. |
||||
|
* |
||||
|
* Please note: The function delays the calling task up to 30 ms to wait for |
||||
|
* the the measurement results. This might lead to problems when the function |
||||
|
* is called from a software timer callback function. |
||||
|
* |
||||
|
* @param dev pointer to sensor device data structure |
||||
|
* @param temperature returns temperature in degree Celsius |
||||
|
* @param humidity returns humidity in percent |
||||
|
* @return true on success, false on error |
||||
|
*/ |
||||
|
bool sht3x_measure (sht3x_sensor_t* dev, float* temperature, float* humidity); |
||||
|
|
||||
|
|
||||
|
/**
|
||||
|
* @brief Start the measurement in single shot or periodic mode |
||||
|
* |
||||
|
* The function starts the measurement either in *single shot mode* |
||||
|
* (exactly one measurement) or *periodic mode* (periodic measurements) |
||||
|
* with given repeatabilty. |
||||
|
* |
||||
|
* In the *single shot mode*, this function has to be called for each |
||||
|
* measurement. The measurement duration has to be waited every time |
||||
|
* before the results can be fetched. |
||||
|
* |
||||
|
* In the *periodic mode*, this function has to be called only once. Also |
||||
|
* the measurement duration has to be waited only once until the first |
||||
|
* results are available. After this first measurement, the sensor then |
||||
|
* automatically performs all subsequent measurements. The rate of periodic |
||||
|
* measurements can be 10, 4, 2, 1 or 0.5 measurements per second (mps). |
||||
|
* |
||||
|
* Please note: Due to inaccuracies in timing of the sensor, the user task |
||||
|
* should fetch the results at a lower rate. The rate of the periodic |
||||
|
* measurements is defined by the parameter *mode*. |
||||
|
* |
||||
|
* @param dev pointer to sensor device data structure |
||||
|
* @param mode measurement mode, see type *sht3x_mode_t* |
||||
|
* @param repeat repeatability, see type *sht3x_repeat_t* |
||||
|
* @return true on success, false on error |
||||
|
*/ |
||||
|
bool sht3x_start_measurement (sht3x_sensor_t* dev, sht3x_mode_t mode, |
||||
|
sht3x_repeat_t repeat); |
||||
|
|
||||
|
/**
|
||||
|
* @brief Get the duration of a measurement in RTOS ticks. |
||||
|
* |
||||
|
* The function returns the duration in RTOS ticks required by the sensor to |
||||
|
* perform a measurement for the given repeatability. Once a measurement is |
||||
|
* started with function *sht3x_start_measurement* the user task can use this |
||||
|
* duration in RTOS ticks directly to wait with function *vTaskDelay* until |
||||
|
* the measurement results can be fetched. |
||||
|
* |
||||
|
* Please note: The duration only depends on repeatability level. Therefore, |
||||
|
* it can be considered as constant for a repeatibility. |
||||
|
* |
||||
|
* @param repeat repeatability, see type *sht3x_repeat_t* |
||||
|
* @return measurement duration given in RTOS ticks |
||||
|
*/ |
||||
|
uint8_t sht3x_get_measurement_duration (sht3x_repeat_t repeat); |
||||
|
|
||||
|
|
||||
|
/**
|
||||
|
* @brief Read measurement results from sensor as raw data |
||||
|
* |
||||
|
* The function read measurement results from the sensor, checks the CRC |
||||
|
* checksum and stores them in the byte array as following. |
||||
|
* |
||||
|
* data[0] = Temperature MSB |
||||
|
* data[1] = Temperature LSB |
||||
|
* data[2] = Temperature CRC |
||||
|
* data[3] = Pressure MSB |
||||
|
* data[4] = Pressure LSB |
||||
|
* data[2] = Pressure CRC |
||||
|
* |
||||
|
* In case that there are no new data that can be read, the function fails. |
||||
|
* |
||||
|
* @param dev pointer to sensor device data structure |
||||
|
* @param raw_data byte array in which raw data are stored |
||||
|
* @return true on success, false on error |
||||
|
*/ |
||||
|
bool sht3x_get_raw_data(sht3x_sensor_t* dev, sht3x_raw_data_t raw_data); |
||||
|
|
||||
|
|
||||
|
/**
|
||||
|
* @brief Computes sensor values from raw data |
||||
|
* |
||||
|
* @param raw_data byte array that contains raw data |
||||
|
* @param temperature returns temperature in degree Celsius |
||||
|
* @param humidity returns humidity in percent |
||||
|
* @return true on success, false on error |
||||
|
*/ |
||||
|
bool sht3x_compute_values (sht3x_raw_data_t raw_data, |
||||
|
float* temperature, float* humidity); |
||||
|
|
||||
|
|
||||
|
/**
|
||||
|
* @brief Get measurement results in form of sensor values |
||||
|
* |
||||
|
* The function combines function *sht3x_read_raw_data* and function |
||||
|
* *sht3x_compute_values* to get the measurement results. |
||||
|
* |
||||
|
* In case that there are no results that can be read, the function fails. |
||||
|
* |
||||
|
* @param dev pointer to sensor device data structure |
||||
|
* @param temperature returns temperature in degree Celsius |
||||
|
* @param humidity returns humidity in percent |
||||
|
* @return true on success, false on error |
||||
|
*/ |
||||
|
bool sht3x_get_results (sht3x_sensor_t* dev, |
||||
|
float* temperature, float* humidity); |
||||
|
|
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#endif /* __SHT3x_H__ */ |
@ -0,0 +1,58 @@ |
|||||
|
/*
|
||||
|
* Driver for AMS CCS811 digital gas sensor connected to I2C. |
||||
|
* |
||||
|
* This driver is for the usage with the ESP8266 and FreeRTOS (esp-open-rtos) |
||||
|
* [https://github.com/SuperHouse/esp-open-rtos]. It is also working with ESP32
|
||||
|
* and ESP-IDF [https://github.com/espressif/esp-idf.git] as well as Linux
|
||||
|
* based systems using a wrapper library for ESP8266 functions. |
||||
|
* |
||||
|
* --------------------------------------------------------------------------- |
||||
|
* |
||||
|
* The BSD License (3-clause license) |
||||
|
* |
||||
|
* Copyright (c) 2017 Gunar Schorcht (https://github.com/gschorcht)
|
||||
|
* All rights reserved. |
||||
|
* |
||||
|
* 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 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 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. |
||||
|
*/ |
||||
|
|
||||
|
/**
|
||||
|
* Platform file: platform specific definitions, includes and functions |
||||
|
*/ |
||||
|
|
||||
|
#ifndef __CCS811_PLATFORM_H__ |
||||
|
#define __CCS811_PLATFORM_H__ |
||||
|
|
||||
|
#ifdef ESP_PLATFORM // ESP32 (ESP-IDF)
|
||||
|
|
||||
|
// platform specific includes
|
||||
|
#include "esp8266_wrapper.h" |
||||
|
#include <errno.h> |
||||
|
|
||||
|
#endif // ESP_PLATFORM
|
||||
|
|
||||
|
#endif // __CCS811_PLATFORM_H__
|
@ -0,0 +1,450 @@ |
|||||
|
/*
|
||||
|
* Driver for Sensirion SHT3x digital temperature and humidity sensor |
||||
|
* connected to I2C |
||||
|
* |
||||
|
* This driver is for the usage with the ESP8266 and FreeRTOS (esp-open-rtos) |
||||
|
* [https://github.com/SuperHouse/esp-open-rtos]. It is also working with ESP32
|
||||
|
* and ESP-IDF [https://github.com/espressif/esp-idf.git] as well as Linux
|
||||
|
* based systems using a wrapper library for ESP8266 functions. |
||||
|
* |
||||
|
* ---------------------------------------------------------------- |
||||
|
* |
||||
|
* The BSD License (3-clause license) |
||||
|
* |
||||
|
* Copyright (c) 2017 Gunar Schorcht (https://github.com/gschorcht)
|
||||
|
* All rights reserved. |
||||
|
* |
||||
|
* 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 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 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 <string.h> |
||||
|
#include <stdlib.h> |
||||
|
|
||||
|
#include "sht3x.h" |
||||
|
|
||||
|
#define SHT3x_STATUS_CMD 0xF32D |
||||
|
#define SHT3x_CLEAR_STATUS_CMD 0x3041 |
||||
|
#define SHT3x_RESET_CMD 0x30A2 |
||||
|
#define SHT3x_FETCH_DATA_CMD 0xE000 |
||||
|
#define SHT3x_HEATER_OFF_CMD 0x3066 |
||||
|
|
||||
|
const uint16_t SHT3x_MEASURE_CMD[6][3] = { |
||||
|
{0x2400,0x240b,0x2416}, // [SINGLE_SHOT][H,M,L] without clock stretching
|
||||
|
{0x2032,0x2024,0x202f}, // [PERIODIC_05][H,M,L]
|
||||
|
{0x2130,0x2126,0x212d}, // [PERIODIC_1 ][H,M,L]
|
||||
|
{0x2236,0x2220,0x222b}, // [PERIODIC_2 ][H,M,L]
|
||||
|
{0x2234,0x2322,0x2329}, // [PERIODIC_4 ][H,M,L]
|
||||
|
{0x2737,0x2721,0x272a} }; // [PERIODIC_10][H,M,L]
|
||||
|
|
||||
|
// due to the fact that ticks can be smaller than portTICK_PERIOD_MS, one and
|
||||
|
// a half tick period added to the duration to be sure that waiting time for
|
||||
|
// the results is long enough
|
||||
|
#define TIME_TO_TICKS(ms) (1 + ((ms) + (portTICK_PERIOD_MS-1) + portTICK_PERIOD_MS/2 ) / portTICK_PERIOD_MS) |
||||
|
|
||||
|
#define SHT3x_MEAS_DURATION_REP_HIGH 15 |
||||
|
#define SHT3x_MEAS_DURATION_REP_MEDIUM 6 |
||||
|
#define SHT3x_MEAS_DURATION_REP_LOW 4 |
||||
|
|
||||
|
// measurement durations in us
|
||||
|
const uint16_t SHT3x_MEAS_DURATION_US[3] = { SHT3x_MEAS_DURATION_REP_HIGH * 1000, |
||||
|
SHT3x_MEAS_DURATION_REP_MEDIUM * 1000, |
||||
|
SHT3x_MEAS_DURATION_REP_LOW * 1000 }; |
||||
|
|
||||
|
// measurement durations in RTOS ticks
|
||||
|
const uint8_t SHT3x_MEAS_DURATION_TICKS[3] = { TIME_TO_TICKS(SHT3x_MEAS_DURATION_REP_HIGH), |
||||
|
TIME_TO_TICKS(SHT3x_MEAS_DURATION_REP_MEDIUM), |
||||
|
TIME_TO_TICKS(SHT3x_MEAS_DURATION_REP_LOW) }; |
||||
|
|
||||
|
#if defined(SHT3x_DEBUG_LEVEL_2) |
||||
|
#define debug(s, f, ...) printf("%s %s: " s "\n", "SHT3x", f, ## __VA_ARGS__) |
||||
|
#define debug_dev(s, f, d, ...) printf("%s %s: bus %d, addr %02x - " s "\n", "SHT3x", f, d->bus, d->addr, ## __VA_ARGS__) |
||||
|
#else |
||||
|
#define debug(s, f, ...) |
||||
|
#define debug_dev(s, f, d, ...) |
||||
|
#endif |
||||
|
|
||||
|
#if defined(SHT3x_DEBUG_LEVEL_1) || defined(SHT3x_DEBUG_LEVEL_2) |
||||
|
#define error(s, f, ...) printf("%s %s: " s "\n", "SHT3x", f, ## __VA_ARGS__) |
||||
|
#define error_dev(s, f, d, ...) printf("%s %s: bus %d, addr %02x - " s "\n", "SHT3x", f, d->bus, d->addr, ## __VA_ARGS__) |
||||
|
#else |
||||
|
#define error(s, f, ...) |
||||
|
#define error_dev(s, f, d, ...) |
||||
|
#endif |
||||
|
|
||||
|
/** Forward declaration of function for internal use */ |
||||
|
|
||||
|
static bool sht3x_is_measuring (sht3x_sensor_t*); |
||||
|
static bool sht3x_send_command (sht3x_sensor_t*, uint16_t); |
||||
|
static bool sht3x_read_data (sht3x_sensor_t*, uint8_t*, uint32_t); |
||||
|
static bool sht3x_get_status (sht3x_sensor_t*, uint16_t*); |
||||
|
static bool sht3x_reset (sht3x_sensor_t*); |
||||
|
|
||||
|
static uint8_t crc8 (uint8_t data[], int len); |
||||
|
|
||||
|
/** ------------------------------------------------ */ |
||||
|
|
||||
|
bool sht3x_init_driver() |
||||
|
{ |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
sht3x_sensor_t* sht3x_init_sensor(uint8_t bus, uint8_t addr) |
||||
|
{ |
||||
|
sht3x_sensor_t* dev; |
||||
|
|
||||
|
if ((dev = malloc (sizeof(sht3x_sensor_t))) == NULL) { |
||||
|
printf("Failed to allocate memory\n"); |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
// inititalize sensor data structure
|
||||
|
dev->bus = bus; |
||||
|
dev->addr = addr; |
||||
|
dev->mode = sht3x_single_shot; |
||||
|
dev->meas_start_time = 0; |
||||
|
dev->meas_started = false; |
||||
|
dev->meas_first = false; |
||||
|
|
||||
|
uint16_t status; |
||||
|
|
||||
|
// try to reset the sensor
|
||||
|
if (!sht3x_reset(dev)) |
||||
|
{ |
||||
|
printf("could not reset the sensor\n"); |
||||
|
} |
||||
|
|
||||
|
// check again the status after clear status command
|
||||
|
if (!sht3x_get_status(dev, &status)) |
||||
|
{ |
||||
|
printf("could not get sensor status\n"); |
||||
|
free(dev); |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
printf("sensor initialized\n"); |
||||
|
return dev; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
bool sht3x_measure (sht3x_sensor_t* dev, float* temperature, float* humidity) |
||||
|
{ |
||||
|
if (!dev || (!temperature && !humidity)) return false; |
||||
|
|
||||
|
if (!sht3x_start_measurement (dev, sht3x_single_shot, sht3x_high)) { |
||||
|
printf("Could not start measurement\n"); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
vTaskDelay (SHT3x_MEAS_DURATION_TICKS[sht3x_high]); |
||||
|
|
||||
|
sht3x_raw_data_t raw_data; |
||||
|
|
||||
|
if (!sht3x_get_raw_data (dev, raw_data)) { |
||||
|
printf("Could not get raw data\n"); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
return sht3x_compute_values (raw_data, temperature, humidity); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
bool sht3x_start_measurement (sht3x_sensor_t* dev, sht3x_mode_t mode, sht3x_repeat_t repeat) |
||||
|
{ |
||||
|
if (!dev) return false; |
||||
|
|
||||
|
dev->error_code = SHT3x_OK; |
||||
|
dev->mode = mode; |
||||
|
dev->repeatability = repeat; |
||||
|
|
||||
|
// start measurement according to selected mode and return an duration estimate
|
||||
|
if (!sht3x_send_command(dev, SHT3x_MEASURE_CMD[mode][repeat])) |
||||
|
{ |
||||
|
error_dev ("could not send start measurment command", __FUNCTION__, dev); |
||||
|
dev->error_code |= SHT3x_SEND_MEAS_CMD_FAILED; |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
dev->meas_start_time = sdk_system_get_time (); |
||||
|
printf("start time = %d\n", dev->meas_start_time); |
||||
|
dev->meas_started = true; |
||||
|
dev->meas_first = true; |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
uint8_t sht3x_get_measurement_duration (sht3x_repeat_t repeat) |
||||
|
{ |
||||
|
return SHT3x_MEAS_DURATION_TICKS[repeat]; // in RTOS ticks
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
bool sht3x_get_raw_data(sht3x_sensor_t* dev, sht3x_raw_data_t raw_data) |
||||
|
{ |
||||
|
if (!dev || !raw_data) { |
||||
|
printf("dev = %p, raw_data = %p\n", dev, raw_data); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
dev->error_code = SHT3x_OK; |
||||
|
|
||||
|
if (!dev->meas_started) |
||||
|
{ |
||||
|
printf ("measurement is not started\n"); |
||||
|
dev->error_code = SHT3x_MEAS_NOT_STARTED; |
||||
|
return sht3x_is_measuring (dev); |
||||
|
} |
||||
|
|
||||
|
if (sht3x_is_measuring(dev)) |
||||
|
{ |
||||
|
printf("measurement is still running\n"); |
||||
|
dev->error_code = SHT3x_MEAS_STILL_RUNNING; |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// send fetch command in any periodic mode (mode > 0) before read raw data
|
||||
|
if (dev->mode && !sht3x_send_command(dev, SHT3x_FETCH_DATA_CMD)) |
||||
|
{ |
||||
|
printf ("send fetch command failed\n"); |
||||
|
dev->error_code |= SHT3x_SEND_FETCH_CMD_FAILED; |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// read raw data
|
||||
|
if (!sht3x_read_data(dev, raw_data, sizeof(sht3x_raw_data_t))) |
||||
|
{ |
||||
|
printf("read raw data failed\n"); |
||||
|
dev->error_code |= SHT3x_READ_RAW_DATA_FAILED; |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// reset first measurement flag
|
||||
|
dev->meas_first = false; |
||||
|
|
||||
|
// reset measurement started flag in single shot mode
|
||||
|
if (dev->mode == sht3x_single_shot) |
||||
|
dev->meas_started = false; |
||||
|
|
||||
|
// check temperature crc
|
||||
|
if (crc8(raw_data,2) != raw_data[2]) |
||||
|
{ |
||||
|
printf("CRC check for temperature data failed\n"); |
||||
|
dev->error_code |= SHT3x_WRONG_CRC_TEMPERATURE; |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// check humidity crc
|
||||
|
if (crc8(raw_data+3,2) != raw_data[5]) |
||||
|
{ |
||||
|
printf ("CRC check for humidity data failed\n"); |
||||
|
dev->error_code |= SHT3x_WRONG_CRC_HUMIDITY; |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
bool sht3x_compute_values (sht3x_raw_data_t raw_data, float* temperature, float* humidity) |
||||
|
{ |
||||
|
if (!raw_data) { |
||||
|
printf("raw_data was falsey\n"); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (temperature) |
||||
|
*temperature = ((((raw_data[0] * 256.0) + raw_data[1]) * 175) / 65535.0) - 45; |
||||
|
|
||||
|
if (humidity) |
||||
|
*humidity = ((((raw_data[3] * 256.0) + raw_data[4]) * 100) / 65535.0); |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
bool sht3x_get_results (sht3x_sensor_t* dev, float* temperature, float* humidity) |
||||
|
{ |
||||
|
if (!dev || (!temperature && !humidity)) return false; |
||||
|
|
||||
|
sht3x_raw_data_t raw_data; |
||||
|
|
||||
|
if (!sht3x_get_raw_data (dev, raw_data)) |
||||
|
return false; |
||||
|
|
||||
|
return sht3x_compute_values (raw_data, temperature, humidity); |
||||
|
} |
||||
|
|
||||
|
/* Functions for internal use only */ |
||||
|
|
||||
|
static bool sht3x_is_measuring (sht3x_sensor_t* dev) |
||||
|
{ |
||||
|
if (!dev) return false; |
||||
|
|
||||
|
dev->error_code = SHT3x_OK; |
||||
|
|
||||
|
// not running if measurement is not started at all or
|
||||
|
// it is not the first measurement in periodic mode
|
||||
|
if (!dev->meas_started || !dev->meas_first) |
||||
|
return false; |
||||
|
|
||||
|
// not running if time elapsed is greater than duration
|
||||
|
printf("start time = %d\n", dev->meas_start_time); |
||||
|
printf("current time = %d\n", sdk_system_get_time()); |
||||
|
printf("difference = %d\n", sdk_system_get_time() - dev->meas_start_time); |
||||
|
uint32_t elapsed = sdk_system_get_time() - dev->meas_start_time; |
||||
|
|
||||
|
return elapsed < SHT3x_MEAS_DURATION_US[dev->repeatability]; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
static bool sht3x_send_command(sht3x_sensor_t* dev, uint16_t cmd) |
||||
|
{ |
||||
|
if (!dev) { |
||||
|
printf("dev was falsey in sht3x_send_command\n"); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
uint8_t data[2] = { cmd >> 8, cmd & 0xff }; |
||||
|
|
||||
|
printf("send command MSB=%02x LSB=%02x\n", data[0], data[1]); |
||||
|
|
||||
|
int err = i2c_slave_write(dev->bus, dev->addr, 0, data, 2); |
||||
|
|
||||
|
if (err) |
||||
|
{ |
||||
|
dev->error_code |= (err == -EBUSY) ? SHT3x_I2C_BUSY : SHT3x_I2C_SEND_CMD_FAILED; |
||||
|
printf ("i2c error %d on write command %02x\n", err, cmd); |
||||
|
printf("err = %d\n", err); |
||||
|
printf("busy = %d\n", -EBUSY); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
static bool sht3x_read_data(sht3x_sensor_t* dev, uint8_t *data, uint32_t len) |
||||
|
{ |
||||
|
if (!dev) return false; |
||||
|
int err = i2c_slave_read(dev->bus, dev->addr, 0, data, len); |
||||
|
|
||||
|
if (err) |
||||
|
{ |
||||
|
dev->error_code |= (err == -EBUSY) ? SHT3x_I2C_BUSY : SHT3x_I2C_READ_FAILED; |
||||
|
error_dev ("error %d on read %d byte", __FUNCTION__, dev, err, len); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
# ifdef SHT3x_DEBUG_LEVEL_2 |
||||
|
printf("SHT3x %s: bus %d, addr %02x - read following bytes: ", |
||||
|
__FUNCTION__, dev->bus, dev->addr); |
||||
|
for (int i=0; i < len; i++) |
||||
|
printf("%02x ", data[i]); |
||||
|
printf("\n"); |
||||
|
# endif // ifdef SHT3x_DEBUG_LEVEL_2
|
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
static bool sht3x_reset (sht3x_sensor_t* dev) |
||||
|
{ |
||||
|
if (!dev) { |
||||
|
printf("dev was falsey\n"); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
printf("soft-reset triggered\n"); |
||||
|
|
||||
|
dev->error_code = SHT3x_OK; |
||||
|
|
||||
|
// send reset command
|
||||
|
if (!sht3x_send_command(dev, SHT3x_RESET_CMD)) |
||||
|
{ |
||||
|
printf("Got error code from sht3x_send_command\n"); |
||||
|
dev->error_code |= SHT3x_SEND_RESET_CMD_FAILED; |
||||
|
return false; |
||||
|
} |
||||
|
// wait for small amount of time needed (according to datasheet 0.5ms)
|
||||
|
vTaskDelay (100 / portTICK_PERIOD_MS); |
||||
|
|
||||
|
uint16_t status; |
||||
|
|
||||
|
// check the status after reset
|
||||
|
if (!sht3x_get_status(dev, &status)) { |
||||
|
printf("Failed to get status from sensor\n"); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
static bool sht3x_get_status (sht3x_sensor_t* dev, uint16_t* status) |
||||
|
{ |
||||
|
if (!dev || !status) return false; |
||||
|
|
||||
|
dev->error_code = SHT3x_OK; |
||||
|
|
||||
|
uint8_t data[3]; |
||||
|
|
||||
|
if (!sht3x_send_command(dev, SHT3x_STATUS_CMD) || !sht3x_read_data(dev, data, 3)) |
||||
|
{ |
||||
|
dev->error_code |= SHT3x_SEND_STATUS_CMD_FAILED; |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
*status = data[0] << 8 | data[1]; |
||||
|
debug_dev ("status=%02x", __FUNCTION__, dev, *status); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
const uint8_t g_polynom = 0x31; |
||||
|
|
||||
|
static uint8_t crc8 (uint8_t data[], int len) |
||||
|
{ |
||||
|
// initialization value
|
||||
|
uint8_t crc = 0xff; |
||||
|
|
||||
|
// iterate over all bytes
|
||||
|
for (int i=0; i < len; i++) |
||||
|
{ |
||||
|
crc ^= data[i]; |
||||
|
|
||||
|
for (int i = 0; i < 8; i++) |
||||
|
{ |
||||
|
bool xor = crc & 0x80; |
||||
|
crc = crc << 1; |
||||
|
crc = xor ? crc ^ g_polynom : crc; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return crc; |
||||
|
} |
||||
|
|
||||
|
|
@ -0,0 +1,20 @@ |
|||||
|
#!/usr/bin/env python |
||||
|
|
||||
|
from __future__ import division, print_function, unicode_literals |
||||
|
|
||||
|
import ttfw_idf |
||||
|
|
||||
|
|
||||
|
@ttfw_idf.idf_example_test(env_tag='Example_TWAI1', target=['esp32', 'esp32s2'], ci_target=['esp32']) |
||||
|
def test_examples_gpio(env, extra_data): |
||||
|
app_name = 'gpio' |
||||
|
dut = env.get_dut(app_name, 'examples/peripherals/gpio/generic_gpio') |
||||
|
dut.start_app() |
||||
|
res = dut.expect(ttfw_idf.MINIMUM_FREE_HEAP_SIZE_RE) |
||||
|
if not res: |
||||
|
raise ValueError('Maximum heap size info not found') |
||||
|
ttfw_idf.print_heap_size(app_name, dut.app.config_name, dut.TARGET, res[0]) |
||||
|
|
||||
|
|
||||
|
if __name__ == '__main__': |
||||
|
test_examples_gpio() |
@ -0,0 +1,3 @@ |
|||||
|
idf_component_register(SRCS "plant_water.c" |
||||
|
INCLUDE_DIRS "." |
||||
|
REQUIRES "esp_http_server" "nvs_flash" "esp_http_client" "esp_eth" "driver" "esp8266_wrapper" "sht3x" "cjson") |
@ -0,0 +1,731 @@ |
|||||
|
#include "./plant_water.h" |
||||
|
#include "sht3x.h" |
||||
|
#include "cjson.h" |
||||
|
|
||||
|
#define I2C_BUS 0 |
||||
|
#define I2C_SCL_PIN 22 |
||||
|
#define I2C_SDA_PIN 21 |
||||
|
|
||||
|
#define HTTPD_RESP_SIZE 100 |
||||
|
#define MAX_CRON_SPECS 5 |
||||
|
|
||||
|
static const char *TAG = "pump"; |
||||
|
static sht3x_sensor_t* sensor; |
||||
|
|
||||
|
static void set_pump(int pump_num, int state) { |
||||
|
// Set duty to 100%
|
||||
|
ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, pump_num, state == 1 ? LEDC_DUTY: 0)); |
||||
|
// Update duty to apply the new value
|
||||
|
ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, pump_num)); |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
pump_one_on() { |
||||
|
set_pump(0, 1); |
||||
|
set_pump(1, 0); |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
pump_two_on() { |
||||
|
set_pump(0, 0); |
||||
|
set_pump(1, 1); |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
pumps_off() { |
||||
|
set_pump(0, 0); |
||||
|
set_pump(1, 0); |
||||
|
} |
||||
|
|
||||
|
typedef enum { |
||||
|
PUMP_ON = 1, |
||||
|
PUMP_OFF = 2, |
||||
|
} event_type; |
||||
|
|
||||
|
struct event_t { |
||||
|
event_type pump_1; |
||||
|
event_type pump_2; |
||||
|
int pump_delay; |
||||
|
}; |
||||
|
|
||||
|
struct cron_t { |
||||
|
int pump_num; |
||||
|
int state; |
||||
|
int pump_on_time; |
||||
|
int hour; |
||||
|
int minute; |
||||
|
int last_ran_day; // day of the month it last ran
|
||||
|
int last_ran_minute; // minute it last ran
|
||||
|
int last_ran_hour; // hour it last ran
|
||||
|
}; |
||||
|
|
||||
|
static struct cron_t cron_specs[MAX_CRON_SPECS]; |
||||
|
|
||||
|
static TickType_t |
||||
|
make_delay(int seconds) { |
||||
|
return (1000*seconds) / portTICK_PERIOD_MS; |
||||
|
} |
||||
|
|
||||
|
// Timer type definitions
|
||||
|
const TickType_t PUMP_TIMER_DELAY = (1000*60) / portTICK_PERIOD_MS; |
||||
|
const TickType_t PUMP_CB_PERIOD = (1000*10) / portTICK_PERIOD_MS; |
||||
|
|
||||
|
TimerHandle_t pumpTimer = 0; // Timer for toggling the pumps on/off
|
||||
|
StaticTimer_t pumpTimerBuffer; // Memory backing for the timer, allocated statically
|
||||
|
|
||||
|
// Queue type definitions
|
||||
|
uint8_t queueStorage[PUMP_EV_NUM*sizeof (struct event_t)]; // byte array for queue memory
|
||||
|
static StaticQueue_t pumpEvents; |
||||
|
QueueHandle_t pumpEventsHandle; |
||||
|
|
||||
|
uint8_t timerQueueStorage[PUMP_EV_NUM*sizeof (struct cron_t)]; // byte array for queue memory
|
||||
|
static StaticQueue_t timerEvents; |
||||
|
QueueHandle_t timerEventsHandle; |
||||
|
|
||||
|
// Task type definitions
|
||||
|
|
||||
|
StaticTask_t xTaskBuffer; |
||||
|
StackType_t xStack[TASK_STACK_SIZE]; |
||||
|
|
||||
|
void |
||||
|
pumpRunnerTaskFunction(void *params) { |
||||
|
struct event_t pumpMessage; |
||||
|
|
||||
|
printf("Task started\n"); |
||||
|
|
||||
|
configASSERT( ( uint32_t ) params == 1UL ); |
||||
|
|
||||
|
while (1) { |
||||
|
vTaskDelay(2000 / portTICK_PERIOD_MS); |
||||
|
|
||||
|
if (pumpEventsHandle != NULL) { |
||||
|
// The queue exists and is created
|
||||
|
if (xQueueReceive(pumpEventsHandle, &pumpMessage, (TickType_t)PUMP_TIMER_DELAY) == pdPASS) { |
||||
|
printf("got a message, pump_1 = %u, pump_2 = %u, PUMP_ON = %u, PUMP_OFF = %u\n", pumpMessage.pump_1, pumpMessage.pump_2, PUMP_ON, PUMP_OFF); |
||||
|
if (pumpMessage.pump_1 == PUMP_ON) { |
||||
|
pump_one_on(); |
||||
|
} |
||||
|
if (pumpMessage.pump_2 == PUMP_ON) { |
||||
|
pump_two_on(); |
||||
|
} |
||||
|
vTaskDelay(pumpMessage.pump_delay); |
||||
|
pumps_off(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
createPumpRunnerTask(void) { |
||||
|
xTaskCreateStatic(pumpRunnerTaskFunction, |
||||
|
"pumpt", |
||||
|
TASK_STACK_SIZE, |
||||
|
(void*)1, |
||||
|
tskIDLE_PRIORITY + 2, |
||||
|
xStack, |
||||
|
&xTaskBuffer); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void |
||||
|
runPumps(int delay1, int delay2) { |
||||
|
struct event_t message; |
||||
|
message.pump_1 = PUMP_ON; |
||||
|
message.pump_2 = PUMP_OFF; |
||||
|
message.pump_delay = make_delay(delay1); |
||||
|
|
||||
|
xQueueSend(pumpEventsHandle, (void*)&message, (TickType_t)0); |
||||
|
|
||||
|
message.pump_2 = PUMP_ON; |
||||
|
message.pump_1 = PUMP_OFF; |
||||
|
message.pump_delay = make_delay(delay2); |
||||
|
|
||||
|
xQueueSend(pumpEventsHandle, (void*)&message, (TickType_t)0); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
pumpTimerCb(TimerHandle_t pumpTimer) { |
||||
|
time_t now; |
||||
|
struct tm timeinfo; |
||||
|
time(&now); |
||||
|
localtime_r(&now, &timeinfo); |
||||
|
struct cron_t pump_timer_config; |
||||
|
static int next_cron_spec = 0; |
||||
|
|
||||
|
if (timerEventsHandle != NULL) { |
||||
|
if (xQueueReceive(timerEventsHandle, &pump_timer_config, (TickType_t)0) == pdPASS) { |
||||
|
printf("Got a new cron spec\n"); |
||||
|
cron_specs[next_cron_spec] = pump_timer_config; |
||||
|
next_cron_spec = (next_cron_spec + 1) % MAX_CRON_SPECS; |
||||
|
printf("new: hour = %d, minute = %d\n", pump_timer_config.hour, pump_timer_config.minute); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// check current number of cron specs, remove oldest one and replace if none left
|
||||
|
// loop over them and check time and execute commands
|
||||
|
for (int i = 0; i < MAX_CRON_SPECS; i++) { |
||||
|
//printf("to match: hour = %d, minute = %d\n", cron_specs[i].hour, cron_specs[i].minute);
|
||||
|
//printf("current: hour = %d, minute = %d\n", timeinfo.tm_hour, timeinfo.tm_min);
|
||||
|
if (timeinfo.tm_hour == cron_specs[i].hour && (timeinfo.tm_min == cron_specs[i].minute)) { |
||||
|
if (cron_specs[i].last_ran_day == timeinfo.tm_mday) { |
||||
|
// it already ran today, skip it
|
||||
|
continue; |
||||
|
} |
||||
|
printf("running, hour = %d, minute = %d\n", cron_specs[i].hour, cron_specs[i].minute); |
||||
|
// refactor this bit...
|
||||
|
struct event_t message = {0}; |
||||
|
switch (cron_specs[i].pump_num) { |
||||
|
case 0: |
||||
|
message.pump_1 = PUMP_ON; |
||||
|
message.pump_2 = PUMP_OFF; |
||||
|
break; |
||||
|
case 1: |
||||
|
message.pump_2 = PUMP_ON; |
||||
|
message.pump_1 = PUMP_OFF; |
||||
|
break; |
||||
|
} |
||||
|
message.pump_delay = make_delay(cron_specs[i].pump_on_time); |
||||
|
xQueueSend(pumpEventsHandle, (void*)&message, (TickType_t)0); |
||||
|
|
||||
|
cron_specs[i].last_ran_day = timeinfo.tm_mday; |
||||
|
cron_specs[i].last_ran_hour = timeinfo.tm_hour; |
||||
|
cron_specs[i].last_ran_minute = timeinfo.tm_min; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
esp_err_t |
||||
|
get_sensor_data(httpd_req_t *req) { |
||||
|
time_t now; |
||||
|
struct tm timeinfo; |
||||
|
time(&now); |
||||
|
localtime_r(&now, &timeinfo); |
||||
|
|
||||
|
float temperature; |
||||
|
float humidity; |
||||
|
|
||||
|
char resp[HTTPD_RESP_SIZE] = {0}; |
||||
|
|
||||
|
cJSON *resp_object_j = cJSON_CreateObject(); |
||||
|
|
||||
|
if (sht3x_measure(sensor, &temperature, &humidity)) { |
||||
|
cJSON_AddNumberToObject(resp_object_j, "temperature", (double)temperature); |
||||
|
cJSON_AddNumberToObject(resp_object_j, "humidity", (double)humidity); |
||||
|
} |
||||
|
|
||||
|
cJSON_AddNumberToObject(resp_object_j, "hour", (double)timeinfo.tm_hour); |
||||
|
cJSON_AddNumberToObject(resp_object_j, "minute", (double)timeinfo.tm_min); |
||||
|
|
||||
|
cJSON_PrintPreallocated(resp_object_j, resp, HTTPD_RESP_SIZE, false); |
||||
|
|
||||
|
if (resp_object_j != NULL) { cJSON_Delete(resp_object_j); } |
||||
|
|
||||
|
httpd_resp_set_type(req, "application/json"); |
||||
|
httpd_resp_set_status(req, HTTPD_200); |
||||
|
httpd_resp_send(req, resp, HTTPD_RESP_USE_STRLEN); |
||||
|
|
||||
|
return ESP_OK; |
||||
|
} |
||||
|
|
||||
|
esp_err_t |
||||
|
pumps_on_handler(httpd_req_t *req) { |
||||
|
printf("pumps_on_handler executed\n"); |
||||
|
// TODO stream
|
||||
|
char req_body[HTTPD_RESP_SIZE+1] = {0}; |
||||
|
char resp[HTTPD_RESP_SIZE] = {0}; |
||||
|
|
||||
|
size_t body_size = MIN(req->content_len, (sizeof(req_body)-1)); |
||||
|
|
||||
|
// Receive body and do error handling
|
||||
|
int ret = httpd_req_recv(req, req_body, body_size); |
||||
|
|
||||
|
// if ret == 0 then no data
|
||||
|
if (ret < 0) { |
||||
|
if (ret == HTTPD_SOCK_ERR_TIMEOUT) { |
||||
|
httpd_resp_send_408(req); |
||||
|
} |
||||
|
return ESP_FAIL; |
||||
|
} |
||||
|
|
||||
|
cJSON *json = cJSON_ParseWithLength(req_body, HTTPD_RESP_SIZE); |
||||
|
|
||||
|
cJSON *pump_one_time_j = NULL; |
||||
|
cJSON *pump_two_time_j = NULL; |
||||
|
|
||||
|
if (json != NULL) { |
||||
|
printf("%s\n", cJSON_Print(json)); |
||||
|
if (cJSON_IsObject(json)) { |
||||
|
pump_one_time_j = cJSON_GetObjectItemCaseSensitive(json, "pump_1"); |
||||
|
pump_two_time_j = cJSON_GetObjectItemCaseSensitive(json, "pump_2"); |
||||
|
if (cJSON_IsNumber(pump_one_time_j) && cJSON_IsNumber(pump_two_time_j)) { |
||||
|
if (pump_one_time_j->valueint > 0 && pump_two_time_j->valueint > 0) { |
||||
|
printf("Running pumps: p1 = %d, p2 = %d\n", pump_one_time_j->valueint, pump_two_time_j->valueint); |
||||
|
runPumps(pump_one_time_j->valueint, pump_two_time_j->valueint); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
httpd_resp_send(req, resp, HTTPD_RESP_USE_STRLEN); |
||||
|
|
||||
|
if (json != NULL) { cJSON_Delete(json); } |
||||
|
return ESP_OK; |
||||
|
} |
||||
|
|
||||
|
/* URI handler structure for GET /uri */ |
||||
|
httpd_uri_t uri_get = { |
||||
|
.uri = "/sensor", |
||||
|
.method = HTTP_GET, |
||||
|
.handler = get_sensor_data, |
||||
|
.user_ctx = NULL |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
/* URI handler structure for POST /pumps_on */ |
||||
|
httpd_uri_t pumps_on = { |
||||
|
.uri = "/pumps_on", |
||||
|
.method = HTTP_POST, |
||||
|
.handler = pumps_on_handler, |
||||
|
.user_ctx = NULL |
||||
|
}; |
||||
|
|
||||
|
esp_err_t |
||||
|
add_cron_handler(httpd_req_t *req) { |
||||
|
printf("add_cron_handler executed\n"); |
||||
|
// TODO stream
|
||||
|
char req_body[HTTPD_RESP_SIZE+1] = {0}; |
||||
|
char resp[HTTPD_RESP_SIZE] = {0}; |
||||
|
|
||||
|
size_t body_size = MIN(req->content_len, (sizeof(req_body)-1)); |
||||
|
|
||||
|
// Receive body and do error handling
|
||||
|
int ret = httpd_req_recv(req, req_body, body_size); |
||||
|
|
||||
|
// if ret == 0 then no data
|
||||
|
if (ret < 0) { |
||||
|
if (ret == HTTPD_SOCK_ERR_TIMEOUT) { |
||||
|
httpd_resp_send_408(req); |
||||
|
} |
||||
|
return ESP_FAIL; |
||||
|
} |
||||
|
|
||||
|
cJSON *json = cJSON_ParseWithLength(req_body, HTTPD_RESP_SIZE); |
||||
|
|
||||
|
cJSON *pump_num; |
||||
|
cJSON *state; |
||||
|
cJSON *pump_on_time; // time it will be on for
|
||||
|
cJSON *hour; // hour to trigger in
|
||||
|
cJSON *minute; // minute on the hour to trigger on
|
||||
|
|
||||
|
struct cron_t cron_spec = {0}; |
||||
|
|
||||
|
if (json != NULL) { |
||||
|
printf("%s\n", cJSON_Print(json)); |
||||
|
if (cJSON_IsObject(json)) { |
||||
|
pump_num = cJSON_GetObjectItemCaseSensitive(json, "pump_num"); |
||||
|
state = cJSON_GetObjectItemCaseSensitive(json, "state"); |
||||
|
pump_on_time = cJSON_GetObjectItemCaseSensitive(json, "pump_on_time"); |
||||
|
hour = cJSON_GetObjectItemCaseSensitive(json, "hour"); |
||||
|
minute = cJSON_GetObjectItemCaseSensitive(json, "minute"); |
||||
|
|
||||
|
if (cJSON_IsNumber(pump_num) && |
||||
|
cJSON_IsNumber(state) && |
||||
|
cJSON_IsNumber(pump_on_time) && |
||||
|
cJSON_IsNumber(hour) && |
||||
|
cJSON_IsNumber(minute)) { |
||||
|
printf("Creating cron spec\n"); |
||||
|
cron_spec.pump_num = pump_num->valueint; |
||||
|
cron_spec.state = state->valueint; |
||||
|
cron_spec.pump_on_time = pump_on_time->valueint; |
||||
|
cron_spec.hour = hour->valueint; |
||||
|
cron_spec.minute = minute->valueint; |
||||
|
cron_spec.last_ran_day = -1; |
||||
|
cron_spec.last_ran_hour = -1; |
||||
|
cron_spec.last_ran_minute = -1; |
||||
|
printf("Parsed: hour = %d, minute = %d\n", cron_spec.hour, cron_spec.minute); |
||||
|
xQueueSend(timerEventsHandle, (void*)&cron_spec, (TickType_t)0); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
httpd_resp_send(req, resp, HTTPD_RESP_USE_STRLEN); |
||||
|
|
||||
|
if (json != NULL) { cJSON_Delete(json); } |
||||
|
return ESP_OK; |
||||
|
} |
||||
|
|
||||
|
/* URI handler structure for POST /add_cron */ |
||||
|
httpd_uri_t add_cron = { |
||||
|
.uri = "/add_cron", |
||||
|
.method = HTTP_POST, |
||||
|
.handler = add_cron_handler, |
||||
|
.user_ctx = NULL |
||||
|
}; |
||||
|
|
||||
|
/* Function for starting the webserver */ |
||||
|
httpd_handle_t |
||||
|
start_webserver(void) { |
||||
|
/* Generate default configuration */ |
||||
|
httpd_config_t config = HTTPD_DEFAULT_CONFIG(); |
||||
|
|
||||
|
/* Empty handle to esp_http_server */ |
||||
|
httpd_handle_t server = NULL; |
||||
|
|
||||
|
/* Start the httpd server */ |
||||
|
if (httpd_start(&server, &config) == ESP_OK) { |
||||
|
/* Register URI handlers */ |
||||
|
httpd_register_uri_handler(server, &uri_get); |
||||
|
httpd_register_uri_handler(server, &pumps_on); |
||||
|
httpd_register_uri_handler(server, &add_cron); |
||||
|
} |
||||
|
/* If server failed to start, handle will be NULL */ |
||||
|
ESP_LOGI(TAG, "webserver started"); |
||||
|
return server; |
||||
|
} |
||||
|
|
||||
|
static SemaphoreHandle_t s_semph_get_ip_addrs; |
||||
|
|
||||
|
/* tear down connection, release resources */ |
||||
|
static void |
||||
|
stop(void) { |
||||
|
#if CONFIG_EXAMPLE_CONNECT_WIFI |
||||
|
wifi_stop(); |
||||
|
s_active_interfaces--; |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
esp_err_t |
||||
|
wifi_disconnect(void) { |
||||
|
if (s_semph_get_ip_addrs == NULL) { |
||||
|
return ESP_ERR_INVALID_STATE; |
||||
|
} |
||||
|
vSemaphoreDelete(s_semph_get_ip_addrs); |
||||
|
s_semph_get_ip_addrs = NULL; |
||||
|
stop(); |
||||
|
ESP_ERROR_CHECK(esp_unregister_shutdown_handler(&stop)); |
||||
|
return ESP_OK; |
||||
|
} |
||||
|
#ifndef INET6_ADDRSTRLEN |
||||
|
#define INET6_ADDRSTRLEN 48 |
||||
|
#endif |
||||
|
|
||||
|
/* Variable holding number of times ESP32 restarted since first boot.
|
||||
|
* It is placed into RTC memory using RTC_DATA_ATTR and |
||||
|
* maintains its value when ESP32 wakes from deep sleep. |
||||
|
*/ |
||||
|
RTC_DATA_ATTR static int boot_count = 0; |
||||
|
|
||||
|
static void obtain_time(void); |
||||
|
static void initialize_sntp(void); |
||||
|
|
||||
|
void wifi_init_sta(void); |
||||
|
|
||||
|
void |
||||
|
time_sync_notification_cb(struct timeval *tv) { |
||||
|
ESP_LOGI(TAG, "Notification of a time synchronization event"); |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
obtain_time(void) { |
||||
|
/**
|
||||
|
* NTP server address could be aquired via DHCP, |
||||
|
* see following menuconfig options: |
||||
|
* 'LWIP_DHCP_GET_NTP_SRV' - enable STNP over DHCP |
||||
|
* 'LWIP_SNTP_DEBUG' - enable debugging messages |
||||
|
* |
||||
|
*/ |
||||
|
|
||||
|
wifi_init_sta(); |
||||
|
initialize_sntp(); |
||||
|
|
||||
|
// wait for time to be set
|
||||
|
time_t now = 0; |
||||
|
struct tm timeinfo = { 0 }; |
||||
|
int retry = 0; |
||||
|
const int retry_count = 15; |
||||
|
while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET && ++retry < retry_count) { |
||||
|
ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count); |
||||
|
vTaskDelay(2000 / portTICK_PERIOD_MS); |
||||
|
} |
||||
|
time(&now); |
||||
|
localtime_r(&now, &timeinfo);\ |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
initialize_sntp(void) { |
||||
|
ESP_LOGI(TAG, "Initializing SNTP"); |
||||
|
sntp_setoperatingmode(SNTP_OPMODE_POLL); |
||||
|
|
||||
|
/*
|
||||
|
* If 'NTP over DHCP' is enabled, we set dynamic pool address |
||||
|
* as a 'secondary' server. It will act as a fallback server in case that address |
||||
|
* provided via NTP over DHCP is not accessible |
||||
|
*/ |
||||
|
#if LWIP_DHCP_GET_NTP_SRV && SNTP_MAX_SERVERS > 1 |
||||
|
sntp_setservername(1, "pool.ntp.org"); |
||||
|
|
||||
|
#if LWIP_IPV6 && SNTP_MAX_SERVERS > 2 // statically assigned IPv6 address is also possible
|
||||
|
ip_addr_t ip6; |
||||
|
if (ipaddr_aton("2a01:3f7::1", &ip6)) { // ipv6 ntp source "ntp.netnod.se"
|
||||
|
sntp_setserver(2, &ip6); |
||||
|
} |
||||
|
#endif /* LWIP_IPV6 */ |
||||
|
|
||||
|
#else /* LWIP_DHCP_GET_NTP_SRV && (SNTP_MAX_SERVERS > 1) */ |
||||
|
// otherwise, use DNS address from a pool
|
||||
|
sntp_setservername(0, "pool.ntp.org"); |
||||
|
#endif |
||||
|
|
||||
|
sntp_set_time_sync_notification_cb(time_sync_notification_cb); |
||||
|
|
||||
|
sntp_init(); |
||||
|
|
||||
|
ESP_LOGI(TAG, "List of configured NTP servers:"); |
||||
|
|
||||
|
for (uint8_t i = 0; i < SNTP_MAX_SERVERS; ++i){ |
||||
|
if (sntp_getservername(i)){ |
||||
|
ESP_LOGI(TAG, "server %d: %s", i, sntp_getservername(i)); |
||||
|
} else { |
||||
|
// we have either IPv4 or IPv6 address, let's print it
|
||||
|
char buff[INET6_ADDRSTRLEN]; |
||||
|
ip_addr_t const *ip = sntp_getserver(i); |
||||
|
if (ipaddr_ntoa_r(ip, buff, INET6_ADDRSTRLEN) != NULL) |
||||
|
ESP_LOGI(TAG, "server %d: %s", i, buff); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* FreeRTOS event group to signal when we are connected*/ |
||||
|
static EventGroupHandle_t s_wifi_event_group; |
||||
|
static int s_retry_num = 0; |
||||
|
|
||||
|
static void |
||||
|
event_handler(void *arg, |
||||
|
esp_event_base_t event_base, |
||||
|
int32_t event_id, |
||||
|
void *event_data) { |
||||
|
|
||||
|
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { |
||||
|
esp_wifi_connect(); |
||||
|
} |
||||
|
else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { |
||||
|
if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) { |
||||
|
esp_wifi_connect(); |
||||
|
s_retry_num++; |
||||
|
ESP_LOGI(TAG, "retry to connect to the AP"); |
||||
|
} |
||||
|
else { |
||||
|
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); |
||||
|
} |
||||
|
ESP_LOGI(TAG,"connect to the AP fail"); |
||||
|
} |
||||
|
else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { |
||||
|
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; |
||||
|
ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip)); |
||||
|
s_retry_num = 0; |
||||
|
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
wifi_init_sta(void) { |
||||
|
s_wifi_event_group = xEventGroupCreate(); |
||||
|
|
||||
|
ESP_ERROR_CHECK(nvs_flash_init()); |
||||
|
ESP_ERROR_CHECK(esp_netif_init()); |
||||
|
ESP_ERROR_CHECK(esp_event_loop_create_default()); |
||||
|
|
||||
|
#ifdef LWIP_DHCP_GET_NTP_SRV |
||||
|
sntp_servermode_dhcp(1); // accept NTP offers from DHCP server, if any
|
||||
|
#endif |
||||
|
|
||||
|
esp_netif_create_default_wifi_sta(); |
||||
|
|
||||
|
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); |
||||
|
ESP_ERROR_CHECK(esp_wifi_init(&cfg)); |
||||
|
|
||||
|
esp_event_handler_instance_t instance_any_id; |
||||
|
esp_event_handler_instance_t instance_got_ip; |
||||
|
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, |
||||
|
ESP_EVENT_ANY_ID, |
||||
|
&event_handler, |
||||
|
NULL, |
||||
|
&instance_any_id)); |
||||
|
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, |
||||
|
IP_EVENT_STA_GOT_IP, |
||||
|
&event_handler, |
||||
|
NULL, |
||||
|
&instance_got_ip)); |
||||
|
|
||||
|
wifi_config_t wifi_config = { |
||||
|
.sta = { |
||||
|
.ssid = EXAMPLE_ESP_WIFI_SSID, |
||||
|
.password = EXAMPLE_ESP_WIFI_PASS, |
||||
|
/* Setting a password implies station will connect to all security modes including WEP/WPA.
|
||||
|
* However these modes are deprecated and not advisable to be used. Incase your Access point |
||||
|
* doesn't support WPA2, these mode can be enabled by commenting below line */ |
||||
|
.threshold.authmode = ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD, |
||||
|
}, |
||||
|
}; |
||||
|
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); |
||||
|
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) ); |
||||
|
ESP_ERROR_CHECK(esp_wifi_start() ); |
||||
|
|
||||
|
ESP_LOGI(TAG, "wifi_init_sta finished."); |
||||
|
|
||||
|
/* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
|
||||
|
* number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */ |
||||
|
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, |
||||
|
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, |
||||
|
pdFALSE, |
||||
|
pdFALSE, |
||||
|
portMAX_DELAY); |
||||
|
|
||||
|
/* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
|
||||
|
* happened. */ |
||||
|
if (bits & WIFI_CONNECTED_BIT) { |
||||
|
ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", |
||||
|
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS); |
||||
|
|
||||
|
httpd_handle_t server; |
||||
|
printf("Trying to start webserver\n"); |
||||
|
server = start_webserver(); |
||||
|
|
||||
|
} |
||||
|
else if (bits & WIFI_FAIL_BIT) { |
||||
|
ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", |
||||
|
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS); |
||||
|
} |
||||
|
else { |
||||
|
ESP_LOGE(TAG, "UNEXPECTED EVENT"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
ledc_init(int gpio_num, |
||||
|
int ledc_channel_num, |
||||
|
int ledc_timer_num) { |
||||
|
// Prepare and then apply the LEDC PWM timer configuration
|
||||
|
ledc_timer_config_t ledc_timer = { |
||||
|
.speed_mode = LEDC_MODE, |
||||
|
.timer_num = ledc_timer_num, |
||||
|
.duty_resolution = LEDC_DUTY_RES, |
||||
|
.freq_hz = LEDC_FREQUENCY, // Set output frequency at 5 kHz
|
||||
|
.clk_cfg = LEDC_AUTO_CLK |
||||
|
}; |
||||
|
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer)); |
||||
|
|
||||
|
// Prepare and then apply the LEDC PWM channel configuration
|
||||
|
ledc_channel_config_t ledc_channel = { |
||||
|
.speed_mode = LEDC_MODE, |
||||
|
.channel = ledc_channel_num, |
||||
|
.timer_sel = ledc_timer_num, |
||||
|
.intr_type = LEDC_INTR_DISABLE, |
||||
|
.gpio_num = gpio_num, |
||||
|
.duty = 0, // Set duty to 0%
|
||||
|
.hpoint = 0 |
||||
|
}; |
||||
|
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel)); |
||||
|
} |
||||
|
|
||||
|
void user_task (void *pvParameters) |
||||
|
{ |
||||
|
float temperature; |
||||
|
float humidity; |
||||
|
|
||||
|
TickType_t last_wakeup = xTaskGetTickCount(); |
||||
|
|
||||
|
while (1) |
||||
|
{ |
||||
|
// perform one measurement and do something with the results
|
||||
|
if (sht3x_measure (sensor, &temperature, &humidity)) |
||||
|
printf("%.3f SHT3x Sensor: %.2f °C, %.2f %%\n", |
||||
|
(double)sdk_system_get_time()*1e-3, temperature, humidity); |
||||
|
|
||||
|
// wait until 5 seconds are over
|
||||
|
vTaskDelayUntil(&last_wakeup, 5000 / portTICK_PERIOD_MS); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* -- main program ------------------------------------------------- */ |
||||
|
|
||||
|
void user_init(void) |
||||
|
{ |
||||
|
// Set UART Parameter.
|
||||
|
uart_set_baud(0, 115200); |
||||
|
// Give the UART some time to settle
|
||||
|
vTaskDelay(1); |
||||
|
|
||||
|
// Init I2C bus interfaces at which SHT3x sensors are connected
|
||||
|
// (different busses are possible).
|
||||
|
i2c_init(I2C_BUS, I2C_SCL_PIN, I2C_SDA_PIN, I2C_FREQ_100K); |
||||
|
|
||||
|
// Create the sensors, multiple sensors are possible.
|
||||
|
if ((sensor = sht3x_init_sensor (I2C_BUS, SHT3x_ADDR_1))) |
||||
|
{ |
||||
|
// Create a user task that uses the sensors.
|
||||
|
xTaskCreate(user_task, "user_task", TASK_STACK_SIZE, NULL, 2, 0); |
||||
|
} |
||||
|
|
||||
|
// That's it.
|
||||
|
} |
||||
|
|
||||
|
void |
||||
|
app_main(void) { |
||||
|
++boot_count; |
||||
|
ESP_LOGI(TAG, "Boot count: %d", boot_count); |
||||
|
|
||||
|
time_t now; |
||||
|
struct tm timeinfo; |
||||
|
time(&now); |
||||
|
localtime_r(&now, &timeinfo); |
||||
|
|
||||
|
// Is time set? If not, tm_year will be (1970 - 1900).
|
||||
|
if (timeinfo.tm_year < (2016 - 1900)) { |
||||
|
ESP_LOGI(TAG, "Time is not set yet. Connecting to WiFi and getting time over NTP."); |
||||
|
obtain_time(); |
||||
|
// update 'now' variable with current time
|
||||
|
time(&now); |
||||
|
} |
||||
|
|
||||
|
char strftime_buf[64]; |
||||
|
|
||||
|
// Set timezone to Eastern Standard Time and print local time
|
||||
|
setenv("TZ", "EST5EDT,M3.2.0/2,M11.1.0", 1); |
||||
|
tzset(); |
||||
|
localtime_r(&now, &timeinfo); |
||||
|
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo); |
||||
|
ESP_LOGI(TAG, "The current date/time in New York is: %s", strftime_buf); |
||||
|
|
||||
|
if (sntp_get_sync_mode() == SNTP_SYNC_MODE_SMOOTH) { |
||||
|
struct timeval outdelta; |
||||
|
while (sntp_get_sync_status() == SNTP_SYNC_STATUS_IN_PROGRESS) { |
||||
|
adjtime(NULL, &outdelta); |
||||
|
ESP_LOGI(TAG, "Waiting for adjusting time ... outdelta = %jd sec: %li ms: %li us", |
||||
|
(intmax_t)outdelta.tv_sec, |
||||
|
outdelta.tv_usec/1000, |
||||
|
outdelta.tv_usec%1000); |
||||
|
vTaskDelay(2000 / portTICK_PERIOD_MS); |
||||
|
} |
||||
|
} |
||||
|
pumpEventsHandle = xQueueCreateStatic(PUMP_EV_NUM, sizeof (struct event_t), queueStorage, &pumpEvents); |
||||
|
timerEventsHandle = xQueueCreateStatic(PUMP_EV_NUM, sizeof (struct cron_t), timerQueueStorage, &timerEvents); |
||||
|
|
||||
|
configASSERT(pumpEventsHandle); |
||||
|
configASSERT(timerEventsHandle); |
||||
|
|
||||
|
pumpTimer = xTimerCreateStatic("pump timer", PUMP_CB_PERIOD, pdTRUE, (void*)0, pumpTimerCb, &pumpTimerBuffer); |
||||
|
xTimerStart(pumpTimer, 0); |
||||
|
|
||||
|
// Pump stuff
|
||||
|
// Set the LEDC peripheral configuration
|
||||
|
ledc_init(18, 0, 0); |
||||
|
ledc_init(19, 1, 1); |
||||
|
|
||||
|
i2c_init(I2C_BUS, I2C_SCL_PIN, I2C_SDA_PIN, I2C_FREQ_100K); |
||||
|
|
||||
|
// Create the sensors, multiple sensors are possible.
|
||||
|
sensor = sht3x_init_sensor(I2C_BUS, SHT3x_ADDR_1); |
||||
|
|
||||
|
createPumpRunnerTask(); |
||||
|
} |
@ -0,0 +1,61 @@ |
|||||
|
#include "driver/ledc.h" |
||||
|
#include "esp_attr.h" |
||||
|
#include "esp_err.h" |
||||
|
#include "esp_eth.h" |
||||
|
#include "esp_event.h" |
||||
|
#include "esp_http_client.h" |
||||
|
#include "esp_log.h" |
||||
|
#include "esp_netif.h" |
||||
|
#include "esp_sleep.h" |
||||
|
#include "esp_sntp.h" |
||||
|
#include "esp_system.h" |
||||
|
#include "esp_wifi.h" |
||||
|
#include "freertos/FreeRTOS.h" |
||||
|
#include "freertos/FreeRTOSConfig.h" |
||||
|
#include "freertos/event_groups.h" |
||||
|
#include "freertos/task.h" |
||||
|
#include "freertos/timers.h" |
||||
|
#include "freertos/queue.h" |
||||
|
#include "nvs_flash.h" |
||||
|
#include "protocol_examples_common.h" |
||||
|
#include "sdkconfig.h" |
||||
|
#include <esp_event.h> |
||||
|
#include <esp_http_server.h> |
||||
|
#include <esp_log.h> |
||||
|
#include <esp_system.h> |
||||
|
#include <esp_wifi.h> |
||||
|
#include <nvs_flash.h> |
||||
|
#include <stdio.h> |
||||
|
#include <string.h> |
||||
|
#include <sys/param.h> |
||||
|
#include <sys/time.h> |
||||
|
#include <time.h> |
||||
|
#include "driver/spi_common.h" |
||||
|
#include "driver/uart.h" |
||||
|
|
||||
|
#define LEDC_TIMER_0 0 |
||||
|
#define LEDC_TIMER_1 1 |
||||
|
#define LEDC_MODE LEDC_LOW_SPEED_MODE |
||||
|
#define LEDC_OUTPUT_IO_1 (18) // Define the output GPIO
|
||||
|
#define LEDC_OUTPUT_IO_2 (19) // Define the output GPIO
|
||||
|
#define LEDC_CHANNEL_1 0 |
||||
|
#define LEDC_CHANNEL_2 1 |
||||
|
#define LEDC_DUTY_RES LEDC_TIMER_13_BIT // Set duty resolution to 13 bits
|
||||
|
#define LEDC_DUTY (8191) // Set duty to 100%. ((2 ** 13) - 1) * 50% = 4095
|
||||
|
#define LEDC_FREQUENCY (5000) // Frequency in Hertz. Set frequency at 5 kHz
|
||||
|
|
||||
|
#define EXAMPLE_ESP_WIFI_SSID CONFIG_SSID |
||||
|
#define EXAMPLE_ESP_WIFI_PASS CONFIG_PASSWORD |
||||
|
#define EXAMPLE_ESP_MAXIMUM_RETRY 10 |
||||
|
|
||||
|
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_PSK |
||||
|
|
||||
|
#define PUMP_EV_NUM 5 |
||||
|
|
||||
|
/* The event group allows multiple bits for each event, but we only care about two events:
|
||||
|
* - we are connected to the AP with an IP |
||||
|
* - we failed to connect after the maximum amount of retries */ |
||||
|
#define WIFI_CONNECTED_BIT BIT0 |
||||
|
#define WIFI_FAIL_BIT BIT1 |
||||
|
|
||||
|
#define TASK_STACK_SIZE 4000 |
@ -0,0 +1,93 @@ |
|||||
|
/* Common functions for protocol examples, to establish Wi-Fi or Ethernet connection.
|
||||
|
|
||||
|
This example code is in the Public Domain (or CC0 licensed, at your option.) |
||||
|
|
||||
|
Unless required by applicable law or agreed to in writing, this |
||||
|
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR |
||||
|
CONDITIONS OF ANY KIND, either express or implied. |
||||
|
*/ |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
#include "esp_err.h" |
||||
|
#include "esp_netif.h" |
||||
|
#include "esp_eth.h" |
||||
|
|
||||
|
#ifdef CONFIG_EXAMPLE_CONNECT_ETHERNET |
||||
|
#define EXAMPLE_INTERFACE get_example_netif() |
||||
|
#endif |
||||
|
|
||||
|
#ifdef CONFIG_EXAMPLE_CONNECT_WIFI |
||||
|
#define EXAMPLE_INTERFACE get_example_netif() |
||||
|
#endif |
||||
|
|
||||
|
#if !defined (CONFIG_EXAMPLE_CONNECT_ETHERNET) && !defined (CONFIG_EXAMPLE_CONNECT_WIFI) |
||||
|
// This is useful for some tests which do not need a network connection
|
||||
|
#define EXAMPLE_INTERFACE NULL |
||||
|
#endif |
||||
|
|
||||
|
/**
|
||||
|
* @brief Configure Wi-Fi or Ethernet, connect, wait for IP |
||||
|
* |
||||
|
* This all-in-one helper function is used in protocols examples to |
||||
|
* reduce the amount of boilerplate in the example. |
||||
|
* |
||||
|
* It is not intended to be used in real world applications. |
||||
|
* See examples under examples/wifi/getting_started/ and examples/ethernet/ |
||||
|
* for more complete Wi-Fi or Ethernet initialization code. |
||||
|
* |
||||
|
* Read "Establishing Wi-Fi or Ethernet Connection" section in |
||||
|
* examples/protocols/README.md for more information about this function. |
||||
|
* |
||||
|
* @return ESP_OK on successful connection |
||||
|
*/ |
||||
|
esp_err_t example_connect(void); |
||||
|
|
||||
|
/**
|
||||
|
* Counterpart to example_connect, de-initializes Wi-Fi or Ethernet |
||||
|
*/ |
||||
|
esp_err_t example_disconnect(void); |
||||
|
|
||||
|
/**
|
||||
|
* @brief Configure stdin and stdout to use blocking I/O |
||||
|
* |
||||
|
* This helper function is used in ASIO examples. It wraps installing the |
||||
|
* UART driver and configuring VFS layer to use UART driver for console I/O. |
||||
|
*/ |
||||
|
esp_err_t example_configure_stdin_stdout(void); |
||||
|
|
||||
|
/**
|
||||
|
* @brief Returns esp-netif pointer created by example_connect() |
||||
|
* |
||||
|
* @note If multiple interfaces active at once, this API return NULL |
||||
|
* In that case the get_example_netif_from_desc() should be used |
||||
|
* to get esp-netif pointer based on interface description |
||||
|
*/ |
||||
|
esp_netif_t *get_example_netif(void); |
||||
|
|
||||
|
/**
|
||||
|
* @brief Returns esp-netif pointer created by example_connect() described by |
||||
|
* the supplied desc field |
||||
|
* |
||||
|
* @param desc Textual interface of created network interface, for example "sta" |
||||
|
* indicate default WiFi station, "eth" default Ethernet interface. |
||||
|
* |
||||
|
*/ |
||||
|
esp_netif_t *get_example_netif_from_desc(const char *desc); |
||||
|
|
||||
|
#ifdef CONFIG_EXAMPLE_CONNECT_ETHERNET |
||||
|
/**
|
||||
|
* @brief Get the example Ethernet driver handle |
||||
|
* |
||||
|
* @return esp_eth_handle_t |
||||
|
*/ |
||||
|
esp_eth_handle_t get_example_eth_handle(void); |
||||
|
#endif // CONFIG_EXAMPLE_CONNECT_ETHERNET
|
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
Loading…
Reference in new issue