Skip to content

Commit 99802e7

Browse files
[Refactor] Error Handling, C++ Wrapper, and Pybind11 Bindings (#2)
* Refactored C ectool functions to return error codes instead of printing or exiting. * Added standard error codes (e.g. `EC_ERR_INIT`, `EC_ERR_READMEM`). * Introduced a C++ `ECController` class to wrap the C API, throwing C++ exceptions with clear error messages. * Exposed `ECController` to Python using pybind11 bindings. * Updated CMake to support the new C++ and pybind11 build flow.
1 parent 5dfcd32 commit 99802e7

File tree

9 files changed

+212
-183
lines changed

9 files changed

+212
-183
lines changed

pyectool/__init__.py

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,9 @@
11
from __future__ import annotations
22

3-
from .libectool_py import (
4-
__doc__,
5-
__version__,
6-
ascii_mode,
7-
auto_fan_control,
8-
get_max_non_battery_temperature,
9-
get_max_temperature,
10-
init,
11-
is_on_ac,
12-
release,
13-
set_fan_duty,
14-
)
3+
from .libectool_py import __doc__, __version__, ECController
154

165
__all__ = [
176
"__doc__",
187
"__version__",
19-
"ascii_mode",
20-
"auto_fan_control",
21-
"get_max_non_battery_temperature",
22-
"get_max_temperature",
23-
"init",
24-
"is_on_ac",
25-
"release",
26-
"set_fan_duty",
8+
"ECController",
279
]

pyectool/__init__.pyi

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@ from __future__ import annotations
33
__doc__: str
44
__version__: str
55

6-
def init() -> None: ...
7-
def release() -> None: ...
8-
def is_on_ac() -> bool: ...
9-
def auto_fan_control() -> None: ...
10-
def set_fan_duty(duty: int) -> None: ...
11-
def get_max_temperature() -> float: ...
12-
def get_max_non_battery_temperature() -> float: ...
13-
14-
ascii_mode: bool
6+
class ECController:
7+
def __init__(self) -> None: ...
8+
def is_on_ac(self) -> bool: ...
9+
def auto_fan_control(self) -> None: ...
10+
def set_fan_duty(self, duty: int) -> None: ...
11+
def get_max_temperature(self) -> float: ...
12+
def get_max_non_battery_temperature(self) -> float: ...

src/bindings/CMakeLists.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# Create the Python module
2-
python_add_library(libectool_py MODULE libectool_py.cc WITH_SOABI)
2+
python_add_library(libectool_py MODULE PyECController.cc ECController.cc
3+
WITH_SOABI)
34

45
# Link against required libraries
56
target_link_libraries(libectool_py PRIVATE pybind11::headers libectool)
6-
target_include_directories(libectool_py PUBLIC ../include)
7+
target_include_directories(libectool_py PRIVATE . ../include)
78
target_compile_definitions(libectool_py PUBLIC VERSION_INFO=${PROJECT_VERSION})

src/bindings/ECController.cc

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#include "ECController.h"
2+
#include "libectool.h"
3+
4+
void ECController::handle_error(int code, const std::string &msg) {
5+
if (code == 0) return;
6+
7+
std::string reason;
8+
switch (code) {
9+
case EC_ERR_INIT: reason = "EC initialization failed"; break;
10+
case EC_ERR_READMEM: reason = "EC memory read failed"; break;
11+
case EC_ERR_EC_COMMAND: reason = "EC command failed"; break;
12+
case EC_ERR_INVALID_PARAM: reason = "Invalid parameter"; break;
13+
default: reason = "Unknown error"; break;
14+
}
15+
16+
throw std::runtime_error(msg + " (" + reason + ", code " + std::to_string(code) + ")");
17+
}
18+
19+
20+
bool ECController::is_on_ac() {
21+
int ac;
22+
int ret = ec_is_on_ac(&ac);
23+
handle_error(ret, "Failed to read AC status");
24+
return ac;
25+
}
26+
27+
void ECController::auto_fan_control() {
28+
int ret = ec_auto_fan_control();
29+
handle_error(ret, "Failed to enable auto fan control");
30+
}
31+
32+
void ECController::set_fan_duty(int duty) {
33+
int ret = ec_set_fan_duty(duty);
34+
handle_error(ret, "Failed to set fan duty");
35+
}
36+
37+
float ECController::get_max_temperature() {
38+
float t;
39+
int ret = ec_get_max_temperature(&t);
40+
handle_error(ret, "Failed to get max temperature");
41+
return t;
42+
}
43+
44+
float ECController::get_max_non_battery_temperature() {
45+
float t;
46+
int ret = ec_get_max_non_battery_temperature(&t);
47+
handle_error(ret, "Failed to get non-battery temperature");
48+
return t;
49+
}

src/bindings/ECController.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#pragma once
2+
#include <stdexcept>
3+
#include <string>
4+
5+
class ECController {
6+
public:
7+
bool is_on_ac();
8+
void auto_fan_control();
9+
void set_fan_duty(int duty);
10+
float get_max_temperature();
11+
float get_max_non_battery_temperature();
12+
13+
private:
14+
void handle_error(int code, const std::string &msg);
15+
};

src/bindings/PyECController.cc

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#include <pybind11/pybind11.h>
2+
#include "ECController.h"
3+
4+
#define STRINGIFY(x) #x
5+
#define MACRO_STRINGIFY(x) STRINGIFY(x)
6+
7+
namespace py = pybind11;
8+
9+
PYBIND11_MODULE(libectool_py, m) {
10+
m.doc() = "Python bindings for ectool";
11+
12+
py::class_<ECController>(m, "ECController")
13+
.def(py::init<>())
14+
.def("is_on_ac", &ECController::is_on_ac, "Check if on AC power")
15+
.def("auto_fan_control", &ECController::auto_fan_control, "Enable automatic fan control")
16+
.def("set_fan_duty", &ECController::set_fan_duty,
17+
"Set fan duty cycle (0-100)", py::arg("duty"))
18+
.def("get_max_temperature", &ECController::get_max_temperature,
19+
"Get max temperature")
20+
.def("get_max_non_battery_temperature",
21+
&ECController::get_max_non_battery_temperature,
22+
"Get max non-battery temperature");
23+
24+
#ifdef VERSION_INFO
25+
m.attr("__version__") = MACRO_STRINGIFY(VERSION_INFO);
26+
#else
27+
m.attr("__version__") = "dev";
28+
#endif
29+
}

src/bindings/libectool_py.cc

Lines changed: 0 additions & 31 deletions
This file was deleted.

0 commit comments

Comments
 (0)