Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve code generation. #76

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ name: CI

on:
push:
branches:
- master
pull_request:
schedule:
- cron: '50 4 * * *'
Expand Down
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,6 @@ anyhow = "1"
strum = { version = "0.23", features = ["derive"], optional = true }
regex = "1.5"
bindgen = "0.59"

[patch.crates-io]
ring = { git = "https://github.com/gear-tech/ring.git", branch = "v0.16.20-fix-nightly" }
36 changes: 26 additions & 10 deletions build/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ use std::env;
use std::iter::once;
use std::path::PathBuf;

use ::bindgen::callbacks::{IntKind, ParseCallbacks};
use ::bindgen::{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would that affect esp-idf-hal and esp-idf-svc? Would these continue to compile just fine after these changes, or do we need a PR for each of those to fix any compilation errors?

Also: why do we want Rust enums?

Copy link
Contributor Author

@reitermarkus reitermarkus Mar 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would that affect esp-idf-hal and esp-idf-svc?

I guess there will need to be some changes to those crates. I can have a look at that of course.

Also: why do we want Rust enums?

They are more ergonomic to use and the compiler will check if all variants are handled.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would that affect esp-idf-hal and esp-idf-svc?

I guess there will need to be some changes to those crates. I can have a look at that of course.

Would appreciate that. :)

Also: why do we want Rust enums?

They are more ergonomic to use and the compiler will check if all variants are handled.

I think I tried this once, but then for some reason abandoned it. Perhaps once you try to adjust esp-idf-svc and esp-idf-hal to work with the new enum-based constants, the problem (if there was a real one) will resurface itself.

callbacks::{IntKind, ParseCallbacks},
EnumVariation,
};
use anyhow::*;
use common::*;
use embuild::utils::OsStrExt;
Expand All @@ -29,16 +32,24 @@ struct BindgenCallbacks;
impl ParseCallbacks for BindgenCallbacks {
fn int_macro(&self, name: &str, _value: i64) -> Option<IntKind> {
// Make sure the ESP_ERR_*, ESP_OK and ESP_FAIL macros are all i32.
const PREFIX: &str = "ESP_";
const SUFFIX: &str = "ERR_";
const SUFFIX_SPECIAL: [&str; 2] = ["OK", "FAIL"];
if let Some(name) = name.strip_prefix("ESP_") {
if name == "OK" || name == "FAIL" || name.starts_with("ERR_") {
return Some(IntKind::I32);
}
}

let name = name.strip_prefix(PREFIX)?;
if name.starts_with(SUFFIX) || SUFFIX_SPECIAL.iter().any(|&s| name == s) {
Some(IntKind::I32)
} else {
None
None
}

fn add_derives(&self, name: &str) -> Vec<String> {
let mut derives = vec![];

// Make sure log levels can be compared.
if name == "esp_log_level_t" {
derives.push("PartialOrd".into());
}

derives
}
}

Expand Down Expand Up @@ -93,8 +104,13 @@ fn main() -> anyhow::Result<()> {
.bindgen
.builder()?
.parse_callbacks(Box::new(BindgenCallbacks))
.ctypes_prefix("c_types")
.ctypes_prefix("crate::c_types")
.header(header_file.try_to_str()?)
.default_enum_style(EnumVariation::NewType { is_bitfield: false })
.constified_enum_module("flags")
.constified_enum_module("http_errno")
.bitfield_enum(r"esp_netif_flags(_t)?")
.no_default("wifi_init_config_t")
.blocklist_function("strtold")
.blocklist_function("_strtold_r")
.blocklist_function("v.*printf")
Expand Down
36 changes: 36 additions & 0 deletions src/defaults.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use crate::bindings::*;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would we want to do this here and not in esp-idf-svc?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You cannot implement Default in another crate, so it needs to be defined here.

Copy link
Collaborator

@ivmarkov ivmarkov Mar 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No I mean given that we have a type-safe wrapper for Wifi already, why would you need these defaults here? Or do you plan on implementing another set of type-safe wrappers besides esp-idf-svc? I would be supper happy if you could help us improve esp-idf-svc instead. :)

One more point: we have discussed with Espressif, that the best possible solution is to have ESP-IDF expose C functions that implement these defaults and that we can consume - in addition to their C macros available today that we cannot consume. Timelines unclear though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have implemented a different wrapper in one of my projects which used my own bindgen crate before these crates existed. This would enable me to switch to this crate. Also, this could still be used in esp-idf-svc which currently does the same thing as in this Default implementation.

I would be supper happy if you could help us improve esp-idf-svc instead. :)

I will try to have a more detailed look at the esp-idf-svc crate. I think my approach is a more high level API so it could potentially depend on the esp-idf-svc crate.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok so I'm all for switching to Rust enums if you can make it work in esp idf svc and esp idf hal. As for the default method, in light of the above idea of having it centralized in ESP IDF and consumable via CAPI call, perhaps we should wait with it a bit?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way, EspWifi is pretty high level if you put aside the fact that it is mostly async (for which there are good reasons and you can workaround that). Not sure how much higher level you can get?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps we should wait with it a bit?

I don't think it makes a difference. default can easily be changed to use the CAPI call once it is available.

Not sure how much higher level you can get?

I'm also not sure. As I said, I implemented my wrapper before these crates existed, so I have also not yet reviewed in detail how EspWifi is implemented.


impl Default for wifi_init_config_t {
fn default() -> Self {
Self {
event_handler: Some(esp_event_send_internal),
osi_funcs: unsafe { &mut g_wifi_osi_funcs },
wpa_crypto_funcs: unsafe { g_wifi_default_wpa_crypto_funcs },
static_rx_buf_num: CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM as _,
dynamic_rx_buf_num: CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM as _,
tx_buf_type: CONFIG_ESP32_WIFI_TX_BUFFER_TYPE as _,
static_tx_buf_num: WIFI_STATIC_TX_BUFFER_NUM as _,
dynamic_tx_buf_num: WIFI_DYNAMIC_TX_BUFFER_NUM as _,
cache_tx_buf_num: WIFI_CACHE_TX_BUFFER_NUM as _,
csi_enable: WIFI_CSI_ENABLED as _,
ampdu_rx_enable: WIFI_AMPDU_RX_ENABLED as _,
ampdu_tx_enable: WIFI_AMPDU_TX_ENABLED as _,
amsdu_tx_enable: WIFI_AMSDU_TX_ENABLED as _,
nvs_enable: WIFI_NVS_ENABLED as _,
nano_enable: WIFI_NANO_FORMAT_ENABLED as _,
rx_ba_win: WIFI_DEFAULT_RX_BA_WIN as _,
wifi_task_core_id: WIFI_TASK_CORE_ID as _,
beacon_max_len: WIFI_SOFTAP_BEACON_MAX_LEN as _,
mgmt_sbuf_num: WIFI_MGMT_SBUF_NUM as _,
feature_caps: unsafe { g_wifi_feature_caps },
sta_disconnected_pm: WIFI_STA_DISCONNECTED_PM_ENABLED != 0,
magic: WIFI_INIT_CONFIG_MAGIC as _,
}
}
}

impl Default for esp_log_level_t {
fn default() -> Self {
esp_log_level_t(CONFIG_LOG_DEFAULT_LEVEL)
}
}
6 changes: 3 additions & 3 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,21 +62,21 @@ impl fmt::Display for EspError {

#[macro_export]
macro_rules! esp {
($err:expr) => {{
($err:expr $(,)?) => {{
esp_idf_sys::EspError::convert($err as esp_idf_sys::esp_err_t)
}};
}

#[macro_export]
macro_rules! esp_result {
($err:expr, $value:expr) => {{
($err:expr, $value:expr $(,)?) => {{
esp_idf_sys::EspError::check_and_return($err as esp_idf_sys::esp_err_t, $value)
}};
}

#[macro_export]
macro_rules! esp_nofail {
($err:expr) => {{
($err:expr $(,)?) => {{
if let Some(error) = esp_idf_sys::EspError::from($err as esp_idf_sys::esp_err_t) {
error.panic();
}
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
)]

pub use bindings::*;
pub use defaults::*;
pub use error::*;
pub use patches::PatchesRef;

mod alloc;
mod defaults;
mod error;
mod panic;
mod patches;
Expand Down Expand Up @@ -71,7 +73,5 @@ pub mod c_types {
#[allow(non_snake_case)]
#[allow(improper_ctypes)] // TODO: For now, as 5.0 spits out tons of these
mod bindings {
use super::c_types;

include!(env!("EMBUILD_GENERATED_BINDINGS_FILE"));
}