feat: init software

This commit is contained in:
sinavir 2024-12-03 22:08:03 +01:00
parent 777d0fb9ff
commit 16dbabc8c0
No known key found for this signature in database
11 changed files with 446 additions and 0 deletions

5
.gitignore vendored
View file

@ -52,6 +52,11 @@ Module.symvers
Mkfile.old
dkms.conf
/build
/main/build
/sdkconfig.old
# ---> Nix
# Ignore build outputs from performing a nix-build or `nix build` command
result

7
CMakeLists.txt Normal file
View file

@ -0,0 +1,7 @@
# 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)
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
idf_build_set_property(MINIMAL_BUILD ON)
project(simple)

View file

@ -1,2 +1,20 @@
# hackens-devant
Déploiement:
```
nix-shell
# Choisir le SSID/Password à cette étape dans Example Connection Configuration.
# On peut aussi choisir les GPIO dans Example Configuration (TODO changer ce nom)
idf.py menuconfig
idf.py build
# Il faut avoir le ESP connecté à cette étape
idf.py flash
```
## Requêtes possibles
- `GET /status`
- `POST /0` (resp `/1`) avec en donnée `1` ou `0` pour changer l'état du pin `0` (resp. `1`)

9
main/CMakeLists.txt Normal file
View file

@ -0,0 +1,9 @@
set(requires esp-tls nvs_flash esp_netif esp_http_server esp_wifi esp_eth esp_driver_gpio)
idf_build_get_property(target IDF_TARGET)
if(${target} STREQUAL "linux")
list(APPEND requires esp_stubs protocol_examples_common)
endif()
idf_component_register(SRCS "main.c"
INCLUDE_DIRS "."
PRIV_REQUIRES ${requires})

20
main/Kconfig.projbuild Normal file
View file

@ -0,0 +1,20 @@
menu "Example Configuration"
orsource "$IDF_PATH/examples/common_components/env_caps/$IDF_TARGET/Kconfig.env_caps"
config GPIO_OUTPUT_0
int "GPIO output pin 0"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 8 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32H2 || IDF_TARGET_ESP32C5 || IDF_TARGET_ESP32C61
default 18
help
GPIO pin number to be used as GPIO_OUTPUT_IO_0.
config GPIO_OUTPUT_1
int "GPIO output pin 1"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 9 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32H2 || IDF_TARGET_ESP32C5 || IDF_TARGET_ESP32C61
default 19
help
GPIO pin number to be used as GPIO_OUTPUT_IO_1.
endmenu

7
main/idf_component.yml Normal file
View file

@ -0,0 +1,7 @@
dependencies:
protocol_examples_common:
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
esp_stubs:
path: ${IDF_PATH}/examples/protocols/linux_stubs/esp_stubs
rules:
- if: "target in [linux]"

263
main/main.c Normal file
View file

@ -0,0 +1,263 @@
/* Simple HTTP Server Example
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.
*/
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <esp_log.h>
#include <stdatomic.h>
#include <nvs_flash.h>
#include <sys/param.h>
#include "esp_netif.h"
#include "protocol_examples_common.h"
#include "protocol_examples_utils.h"
#include "esp_tls_crypto.h"
#include <esp_http_server.h>
#include "esp_event.h"
#include "esp_netif.h"
#include "esp_tls.h"
#include "esp_check.h"
#include "driver/gpio.h"
#if !CONFIG_IDF_TARGET_LINUX
#include <esp_wifi.h>
#include <esp_system.h>
#include "nvs_flash.h"
#include "esp_eth.h"
#endif // !CONFIG_IDF_TARGET_LINUX
#define EXAMPLE_HTTP_QUERY_KEY_MAX_LEN (64)
// GPIO pin definition. Use menu config to choose GPIO
#define GPIO_OUTPUT_IO_0 CONFIG_GPIO_OUTPUT_0
#define GPIO_OUTPUT_IO_1 CONFIG_GPIO_OUTPUT_1
#define GPIO_OUTPUT_PIN_SEL ((1ULL<<GPIO_OUTPUT_IO_0) | (1ULL<<GPIO_OUTPUT_IO_1))
/* A simple example that demonstrates how to create GET and POST
* handlers for the web server.
*/
static const char *TAG = "devant";
static atomic_bool status_one = false;
static atomic_bool status_two = false;
/* An HTTP GET handler */
static esp_err_t status_get_handler(httpd_req_t *req)
{
/* Send response with custom headers and body set as the
* string passed in user context*/
char buf[3];
sprintf(buf, "%d%d", status_one, status_two);
httpd_resp_send(req, buf, 2);
return ESP_OK;
}
static const httpd_uri_t status = {
.uri = "/status",
.method = HTTP_GET,
.handler = status_get_handler,
};
/* An HTTP POST handler */
static esp_err_t post_one_handler(httpd_req_t *req)
{
char buf[1];
int ret, remaining = req->content_len;
while (remaining > 0) {
/* Read the data for the request */
if ((ret = httpd_req_recv(req, buf,
MIN(remaining, sizeof(buf)))) <= 0) {
if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
/* Retry receiving if timeout occurred */
continue;
}
return ESP_FAIL;
}
bool set = false;
if (buf[0] == '1') {
status_one = true;
set = true;
} else if (buf[0] == '0') {
status_one = false;
set = true;
};
if (set) {
ESP_LOGI(TAG, "RECEIVED DATA");
gpio_set_level(GPIO_OUTPUT_IO_0, status_one);
httpd_resp_send(req, NULL, 0); // TODO check simplification
return ESP_OK;
};
remaining -= ret;
}
// Return 400 if found no info for status
httpd_resp_set_status(req, HTTPD_400);
httpd_resp_send(req, NULL, 0);
return ESP_OK;
}
static const httpd_uri_t post_one = {
.uri = "/0",
.method = HTTP_POST,
.handler = post_one_handler,
.user_ctx = NULL
};
/* An HTTP POST handler */
static esp_err_t post_two_handler(httpd_req_t *req)
{
char buf[1];
int ret, remaining = req->content_len;
while (remaining > 0) {
/* Read the data for the request */
if ((ret = httpd_req_recv(req, buf,
MIN(remaining, sizeof(buf)))) <= 0) {
if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
/* Retry receiving if timeout occurred */
continue;
}
return ESP_FAIL;
}
bool set = false;
if (buf[0] == '1') {
status_two = true;
set = true;
} else if (buf[0] == '0') {
status_two = false;
set = true;
};
if (set) {
ESP_LOGI(TAG, "RECEIVED DATA");
gpio_set_level(GPIO_OUTPUT_IO_1, status_two);
httpd_resp_send(req, NULL, 0); // TODO check simplification
return ESP_OK;
};
remaining -= ret;
}
// Return 400 if found no info for status
httpd_resp_set_status(req, HTTPD_400);
httpd_resp_send(req, NULL, 0);
return ESP_OK;
}
static const httpd_uri_t post_two = {
.uri = "/1",
.method = HTTP_POST,
.handler = post_two_handler,
.user_ctx = NULL
};
static httpd_handle_t start_webserver(void)
{
httpd_handle_t server = NULL;
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.lru_purge_enable = true;
// Start the httpd server
ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port);
if (httpd_start(&server, &config) == ESP_OK) {
// Set URI handlers
ESP_LOGI(TAG, "Registering URI handlers");
httpd_register_uri_handler(server, &status);
httpd_register_uri_handler(server, &post_one);
httpd_register_uri_handler(server, &post_two);
return server;
}
ESP_LOGI(TAG, "Error starting server!");
return NULL;
}
static esp_err_t stop_webserver(httpd_handle_t server)
{
// Stop the httpd server
return httpd_stop(server);
}
static void disconnect_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
httpd_handle_t* server = (httpd_handle_t*) arg;
if (*server) {
ESP_LOGI(TAG, "Stopping webserver");
if (stop_webserver(*server) == ESP_OK) {
*server = NULL;
} else {
ESP_LOGE(TAG, "Failed to stop http server");
}
}
}
static void connect_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
httpd_handle_t* server = (httpd_handle_t*) arg;
if (*server == NULL) {
ESP_LOGI(TAG, "Starting webserver");
*server = start_webserver();
}
}
void app_main(void)
{
static httpd_handle_t server = NULL;
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
//zero-initialize the config structure.
gpio_config_t io_conf = {};
//disable interrupt
io_conf.intr_type = GPIO_INTR_DISABLE;
//set as output mode
io_conf.mode = GPIO_MODE_OUTPUT;
//bit mask of the pins that you want to set,e.g.GPIO18/19
io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL;
//disable pull-down mode
io_conf.pull_down_en = 0;
//disable pull-up mode
io_conf.pull_up_en = 0;
//configure GPIO with the given settings
gpio_config(&io_conf);
gpio_set_level(GPIO_OUTPUT_IO_0, 0);
gpio_set_level(GPIO_OUTPUT_IO_1, 0);
printf("Minimum free heap size: %"PRIu32" bytes\n", esp_get_minimum_free_heap_size());
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
/* Register event handlers to stop the server when Wi-Fi or Ethernet is disconnected,
* and re-start it upon connection.
*/
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &connect_handler, &server));
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &disconnect_handler, &server));
/* Start the server for the first time */
server = start_webserver();
while (server) {
sleep(5);
}
}

80
npins/default.nix Normal file
View file

@ -0,0 +1,80 @@
# Generated by npins. Do not modify; will be overwritten regularly
let
data = builtins.fromJSON (builtins.readFile ./sources.json);
version = data.version;
mkSource =
spec:
assert spec ? type;
let
path =
if spec.type == "Git" then
mkGitSource spec
else if spec.type == "GitRelease" then
mkGitSource spec
else if spec.type == "PyPi" then
mkPyPiSource spec
else if spec.type == "Channel" then
mkChannelSource spec
else
builtins.throw "Unknown source type ${spec.type}";
in
spec // { outPath = path; };
mkGitSource =
{
repository,
revision,
url ? null,
hash,
branch ? null,
...
}:
assert repository ? type;
# At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository
# In the latter case, there we will always be an url to the tarball
if url != null then
(builtins.fetchTarball {
inherit url;
sha256 = hash; # FIXME: check nix version & use SRI hashes
})
else
assert repository.type == "Git";
let
urlToName =
url: rev:
let
matched = builtins.match "^.*/([^/]*)(\\.git)?$" repository.url;
short = builtins.substring 0 7 rev;
appendShort = if (builtins.match "[a-f0-9]*" rev) != null then "-${short}" else "";
in
"${if matched == null then "source" else builtins.head matched}${appendShort}";
name = urlToName repository.url revision;
in
builtins.fetchGit {
url = repository.url;
rev = revision;
inherit name;
# hash = hash;
};
mkPyPiSource =
{ url, hash, ... }:
builtins.fetchurl {
inherit url;
sha256 = hash;
};
mkChannelSource =
{ url, hash, ... }:
builtins.fetchTarball {
inherit url;
sha256 = hash;
};
in
if version == 3 then
builtins.mapAttrs (_: mkSource) data.pins
else
throw "Unsupported format version ${toString version} in sources.json. Try running `npins upgrade`"

22
npins/sources.json Normal file
View file

@ -0,0 +1,22 @@
{
"pins": {
"nixpkgs": {
"type": "Channel",
"name": "nixpkgs-unstable",
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-25.05pre715208.2c15aa59df00/nixexprs.tar.xz",
"hash": "1grhv1ryj80261zf0k92jqpvlwbna2r2r2a48as4fgcihv8sn076"
},
"nixpkgs-esp-dev": {
"type": "Git",
"repository": {
"type": "Git",
"url": "https://github.com/mirrexagon/nixpkgs-esp-dev.git"
},
"branch": "master",
"revision": "31ee58005f43e93a6264e3667c9bf5c31b368733",
"url": null,
"hash": "1pzbv8ywa1k3w8kivz9sglbswv1mjj1l5jxnrnmk81i5wxc4vg2w"
}
},
"version": 3
}

2
sdkconfig.defaults Normal file
View file

@ -0,0 +1,2 @@
CONFIG_GPIO_OUTPUT_0=0
CONFIG_GPIO_OUTPUT_1=1

13
shell.nix Normal file
View file

@ -0,0 +1,13 @@
{
sources ? import ./npins,
overlay ? import (sources.nixpkgs-esp-dev + /overlay.nix),
pkgs ? import sources.nixpkgs { overlays = [ overlay ]; },
}:
pkgs.mkShell {
name = "hackes-devant";
buildInputs = with pkgs; [
esp-idf-esp32c3
];
}