mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	add zephyr
This commit is contained in:
		
							
								
								
									
										187
									
								
								esphome/ble/ble_interface.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								esphome/ble/ble_interface.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,187 @@ | ||||
| from bleak import BleakClient, BleakScanner | ||||
| from bleak.backends.characteristic import BleakGATTCharacteristic | ||||
| from ble_serial.bluetooth.constants import ble_chars | ||||
| import logging | ||||
| import asyncio | ||||
| from typing import Optional | ||||
|  | ||||
|  | ||||
| class BLE_interface: | ||||
|     def __init__(self, adapter: str, service: str): | ||||
|         self._send_queue = asyncio.Queue() | ||||
|  | ||||
|         self.scan_args = dict(adapter=adapter) | ||||
|         if service: | ||||
|             self.scan_args["service_uuids"] = [service] | ||||
|  | ||||
|     async def connect(self, addr_str: str, addr_type: str, timeout: float): | ||||
|         if addr_str: | ||||
|             device = await BleakScanner.find_device_by_address( | ||||
|                 addr_str, timeout=timeout, **self.scan_args | ||||
|             ) | ||||
|         else: | ||||
|             logging.warning( | ||||
|                 "Picking first device with matching service, " | ||||
|                 "consider passing a specific device address, especially if there could be multiple devices" | ||||
|             ) | ||||
|             device = await BleakScanner.find_device_by_filter( | ||||
|                 lambda dev, ad: True, timeout=timeout, **self.scan_args | ||||
|             ) | ||||
|  | ||||
|         assert device, "No matching device found!" | ||||
|  | ||||
|         # address_type used only in Windows .NET currently | ||||
|         self.dev = BleakClient( | ||||
|             device, | ||||
|             address_type=addr_type, | ||||
|             timeout=timeout, | ||||
|             disconnected_callback=self.handle_disconnect, | ||||
|         ) | ||||
|  | ||||
|         logging.info(f"Trying to connect with {device}") | ||||
|         await self.dev.connect() | ||||
|         logging.info(f"Device {self.dev.address} connected") | ||||
|  | ||||
|     async def setup_chars(self, write_uuid: str, read_uuid: str, mode: str): | ||||
|         self.read_enabled = "r" in mode | ||||
|         self.write_enabled = "w" in mode | ||||
|  | ||||
|         if self.write_enabled: | ||||
|             self.write_char = self.find_char( | ||||
|                 write_uuid, ["write", "write-without-response"] | ||||
|             ) | ||||
|         else: | ||||
|             logging.info("Writing disabled, skipping write UUID detection") | ||||
|  | ||||
|         if self.read_enabled: | ||||
|             self.read_char = self.find_char(read_uuid, ["notify", "indicate"]) | ||||
|             await self.dev.start_notify(self.read_char, self.handle_notify) | ||||
|         else: | ||||
|             logging.info("Reading disabled, skipping read UUID detection") | ||||
|  | ||||
|     def find_char( | ||||
|         self, uuid: Optional[str], req_props: [str] | ||||
|     ) -> BleakGATTCharacteristic: | ||||
|         name = req_props[0] | ||||
|  | ||||
|         # Use user supplied UUID first, otherwise try included list | ||||
|         if uuid: | ||||
|             uuid_candidates = [uuid] | ||||
|         else: | ||||
|             uuid_candidates = ble_chars | ||||
|             logging.debug(f"No {name} uuid specified, trying builtin list") | ||||
|  | ||||
|         results = [] | ||||
|         for srv in self.dev.services: | ||||
|             for c in srv.characteristics: | ||||
|                 if c.uuid in uuid_candidates: | ||||
|                     results.append(c) | ||||
|  | ||||
|         if uuid: | ||||
|             assert ( | ||||
|                 len(results) > 0 | ||||
|             ), f"No characteristic with specified {name} UUID {uuid} found!" | ||||
|         else: | ||||
|             assert ( | ||||
|                 len(results) > 0 | ||||
|             ), f"""No characteristic in builtin {name} list {uuid_candidates} found! | ||||
|                     Please specify one with {'-w/--write-uuid' if name == 'write' else '-r/--read-uuid'}, see also --help""" | ||||
|  | ||||
|         res_str = "\n".join(f"\t{c} {c.properties}" for c in results) | ||||
|         logging.debug(f"Characteristic candidates for {name}: \n{res_str}") | ||||
|  | ||||
|         # Check if there is a intersection of permission flags | ||||
|         results[:] = [c for c in results if set(c.properties) & set(req_props)] | ||||
|  | ||||
|         assert len(results) > 0, f"No characteristic with {req_props} property found!" | ||||
|  | ||||
|         assert ( | ||||
|             len(results) == 1 | ||||
|         ), f"Multiple matching {name} characteristics found, please specify one" | ||||
|  | ||||
|         # must be valid here | ||||
|         found = results[0] | ||||
|         logging.info(f"Found {name} characteristic {found.uuid} (H. {found.handle})") | ||||
|         return found | ||||
|  | ||||
|     def set_receiver(self, callback): | ||||
|         self._cb = callback | ||||
|         logging.info("Receiver set up") | ||||
|  | ||||
|     async def send_loop(self): | ||||
|         assert hasattr(self, "_cb"), "Callback must be set before receive loop!" | ||||
|         while True: | ||||
|             data = await self._send_queue.get() | ||||
|             if data is None: | ||||
|                 break  # Let future end on shutdown | ||||
|             if not self.write_enabled: | ||||
|                 logging.warning(f"Ignoring unexpected write data: {data}") | ||||
|                 continue | ||||
|             logging.debug(f"Sending {data}") | ||||
|             await self.dev.write_gatt_char(self.write_char, data) | ||||
|  | ||||
|     def stop_loop(self): | ||||
|         logging.info("Stopping Bluetooth event loop") | ||||
|         self._send_queue.put_nowait(None) | ||||
|  | ||||
|     async def disconnect(self): | ||||
|         if hasattr(self, "dev") and self.dev.is_connected: | ||||
|             if hasattr(self, "read_char"): | ||||
|                 await self.dev.stop_notify(self.read_char) | ||||
|             await self.dev.disconnect() | ||||
|             logging.info("Bluetooth disconnected") | ||||
|  | ||||
|     def queue_send(self, data: bytes): | ||||
|         self._send_queue.put_nowait(data) | ||||
|  | ||||
|     def handle_notify(self, handle: int, data: bytes): | ||||
|         logging.debug(f"Received notify from {handle}: {data}") | ||||
|         if not self.read_enabled: | ||||
|             logging.warning(f"Read unexpected data, dropping: {data}") | ||||
|             return | ||||
|         self._cb(data) | ||||
|  | ||||
|     def handle_disconnect(self, client: BleakClient): | ||||
|         logging.warning(f"Device {client.address} disconnected") | ||||
|         self.stop_loop() | ||||
|  | ||||
|  | ||||
| def receive_callback(value: bytes): | ||||
|     print("Received:", value) | ||||
|  | ||||
|  | ||||
| async def hello_sender(ble: BLE_interface): | ||||
|     while True: | ||||
|         await asyncio.sleep(1 / 100) | ||||
|         # print("Sending...") | ||||
|         ble.queue_send( | ||||
|             b"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n" | ||||
|         ) | ||||
|         # ble.queue_send(b"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n") | ||||
|         # ble.queue_send(b"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n") | ||||
|  | ||||
|  | ||||
| async def main(): | ||||
|     # None uses default/autodetection, insert values if needed | ||||
|     ADAPTER = "hci0" | ||||
|     SERVICE_UUID = "6ba1b218-15a8-461f-9fa8-5dcae273eafd" | ||||
|     WRITE_UUID = "f75c76d2-129e-4dad-a1dd-7866124401e7" | ||||
|     # READ_UUID = '2c55e69e-4993-11ed-b878-0242ac120002' | ||||
|     READ_UUID = "ed9da18c-a800-4f66-a670-aa7547e34453" | ||||
|     DEVICE = "EF:45:95:65:46:FD" | ||||
|  | ||||
|     ble = BLE_interface(ADAPTER, SERVICE_UUID) | ||||
|     ble.set_receiver(receive_callback) | ||||
|  | ||||
|     try: | ||||
|         await ble.connect(DEVICE, "public", 10.0) | ||||
|         await ble.setup_chars(WRITE_UUID, READ_UUID, "rw") | ||||
|  | ||||
|         await asyncio.gather(ble.send_loop(), hello_sender(ble)) | ||||
|     finally: | ||||
|         await ble.disconnect() | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     logging.basicConfig(level=logging.INFO) | ||||
|     asyncio.run(main()) | ||||
							
								
								
									
										53
									
								
								esphome/components/ipsp/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								esphome/components/ipsp/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     CONF_ID, | ||||
| ) | ||||
| from esphome.components.nrf52 import add_zephyr_prj_conf_option | ||||
|  | ||||
| ipsp_ns = cg.esphome_ns.namespace("ipsp") | ||||
| Network = ipsp_ns.class_("Network", cg.Component) | ||||
|  | ||||
| CONFIG_SCHEMA = cv.All( | ||||
|     cv.Schema( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(Network), | ||||
|         } | ||||
|     ).extend(cv.COMPONENT_SCHEMA), | ||||
|     cv.only_with_zephyr, | ||||
| ) | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     await cg.register_component(var, config) | ||||
|     add_zephyr_prj_conf_option("CONFIG_BT", True) | ||||
|     add_zephyr_prj_conf_option("CONFIG_BT_SMP", True) | ||||
|     add_zephyr_prj_conf_option("CONFIG_BT_PERIPHERAL", True) | ||||
|     add_zephyr_prj_conf_option("CONFIG_BT_CENTRAL", True) | ||||
|     add_zephyr_prj_conf_option("CONFIG_BT_L2CAP_DYNAMIC_CHANNEL", True) | ||||
|     add_zephyr_prj_conf_option("CONFIG_BT_DEVICE_NAME", "Test IPSP node")  # TODO | ||||
|     add_zephyr_prj_conf_option("CONFIG_NETWORKING", True) | ||||
|     add_zephyr_prj_conf_option("CONFIG_NET_IPV6", True) | ||||
|     add_zephyr_prj_conf_option("CONFIG_NET_IPV4", False) | ||||
|     add_zephyr_prj_conf_option("CONFIG_NET_UDP", False) | ||||
|     add_zephyr_prj_conf_option("CONFIG_NET_TCP", True) | ||||
|     add_zephyr_prj_conf_option("CONFIG_TEST_RANDOM_GENERATOR", True) | ||||
|     add_zephyr_prj_conf_option("CONFIG_NET_L2_BT", True) | ||||
|     add_zephyr_prj_conf_option("CONFIG_INIT_STACKS", True) | ||||
|     add_zephyr_prj_conf_option("CONFIG_NET_PKT_RX_COUNT", 10) | ||||
|     add_zephyr_prj_conf_option("CONFIG_NET_PKT_TX_COUNT", 10) | ||||
|     add_zephyr_prj_conf_option("CONFIG_NET_BUF_RX_COUNT", 20) | ||||
|     add_zephyr_prj_conf_option("CONFIG_NET_BUF_TX_COUNT", 20) | ||||
|     add_zephyr_prj_conf_option("CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT", 3) | ||||
|     add_zephyr_prj_conf_option("CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT", 4) | ||||
|     add_zephyr_prj_conf_option("CONFIG_NET_MAX_CONTEXTS", 6) | ||||
|  | ||||
|     add_zephyr_prj_conf_option("CONFIG_NET_CONFIG_AUTO_INIT", True) | ||||
|     add_zephyr_prj_conf_option("CONFIG_NET_CONFIG_SETTINGS", True) | ||||
|     add_zephyr_prj_conf_option("CONFIG_NET_CONFIG_MY_IPV6_ADDR", "2001:db8::1") | ||||
|     add_zephyr_prj_conf_option("CONFIG_NET_CONFIG_PEER_IPV6_ADDR", "2001:db8::2") | ||||
|     add_zephyr_prj_conf_option("CONFIG_NET_CONFIG_BT_NODE", True) | ||||
|     if True: | ||||
|         add_zephyr_prj_conf_option("CONFIG_LOG", True) | ||||
|         add_zephyr_prj_conf_option("CONFIG_NET_LOG", True) | ||||
							
								
								
									
										31
									
								
								esphome/components/ipsp/network.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								esphome/components/ipsp/network.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| #include "network.h" | ||||
| #include <zephyr/net/net_if.h> | ||||
|  | ||||
|  | ||||
| /* Define my IP address where to expect messages */ | ||||
| #define MY_IP6ADDR { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, \ | ||||
| 			 0, 0, 0, 0, 0, 0, 0, 0x1 } } } | ||||
|  | ||||
| static struct in6_addr in6addr_my = MY_IP6ADDR; | ||||
|  | ||||
| namespace esphome { | ||||
| namespace ipsp { | ||||
|  | ||||
| void Network::setup() { | ||||
| 	if (net_addr_pton(AF_INET6, | ||||
| 			  CONFIG_NET_CONFIG_MY_IPV6_ADDR, | ||||
| 			  &in6addr_my) < 0) { | ||||
| 		// LOG_ERR("Invalid IPv6 address %s", | ||||
| 		// 	CONFIG_NET_CONFIG_MY_IPV6_ADDR); | ||||
| 	} | ||||
|  | ||||
| 	do { | ||||
| 		struct net_if_addr *ifaddr; | ||||
|  | ||||
| 		ifaddr = net_if_ipv6_addr_add(net_if_get_default(), | ||||
| 					      &in6addr_my, NET_ADDR_MANUAL, 0); | ||||
| 	} while (0); | ||||
| } | ||||
|  | ||||
| }  // namespace shell | ||||
| }  // namespace esphome | ||||
							
								
								
									
										10
									
								
								esphome/components/ipsp/network.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								esphome/components/ipsp/network.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| #pragma once | ||||
| #include "esphome/core/component.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace ipsp { | ||||
| class Network : public Component { | ||||
| 	void setup() override; | ||||
| }; | ||||
| } | ||||
| } | ||||
| @@ -27,8 +27,10 @@ | ||||
| #include "esphome/core/log.h" | ||||
|  | ||||
| #ifdef USE_NRF52 | ||||
| #ifdef USE_ARDUINO | ||||
| #include <Adafruit_TinyUSB.h> // for Serial | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| namespace esphome { | ||||
| namespace logger { | ||||
| @@ -64,12 +66,16 @@ void Logger::write_header_(int level, const char *tag, int line) { | ||||
|  | ||||
|   const char *color = LOG_LEVEL_COLORS[level]; | ||||
|   const char *letter = LOG_LEVEL_LETTERS[level]; | ||||
| #ifdef USE_ARDUINO | ||||
|   void *current_task = xTaskGetCurrentTaskHandle(); | ||||
|   if (current_task == main_task) { | ||||
| #endif | ||||
|     this->printf_to_buffer_("%s[%s][%s:%03u]: ", color, letter, tag, line); | ||||
| #ifdef USE_ARDUINO | ||||
|   } else { | ||||
|     this->printf_to_buffer_("%s[%s][%s:%03u]%s[%s]%s: ", color, letter, tag, line, ESPHOME_LOG_BOLD(ESPHOME_LOG_COLOR_RED), pcTaskGetName(current_task), color); | ||||
|   } | ||||
| #endif | ||||
| } | ||||
|  | ||||
| void HOT Logger::log_vprintf_(int level, const char *tag, int line, const char *format, va_list args) {  // NOLINT | ||||
| @@ -230,7 +236,9 @@ void HOT Logger::log_message_(int level, const char *tag, int offset) { | ||||
| Logger::Logger(uint32_t baud_rate, size_t tx_buffer_size) : baud_rate_(baud_rate), tx_buffer_size_(tx_buffer_size) { | ||||
|   // add 1 to buffer size for null terminator | ||||
|   this->tx_buffer_ = new char[this->tx_buffer_size_ + 1];  // NOLINT | ||||
| #ifdef USE_ARDUINO | ||||
|   this->main_task = xTaskGetCurrentTaskHandle(); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| #ifndef USE_LIBRETINY | ||||
|   | ||||
| @@ -3,34 +3,47 @@ import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     CONF_BOARD, | ||||
|     CONF_FRAMEWORK, | ||||
|     KEY_CORE, | ||||
|     KEY_TARGET_FRAMEWORK, | ||||
|     KEY_TARGET_PLATFORM, | ||||
|     PLATFORM_NRF52, | ||||
|     CONF_TYPE, | ||||
|     CONF_FRAMEWORK, | ||||
| ) | ||||
| from esphome.core import CORE, coroutine_with_priority | ||||
| from esphome.helpers import ( | ||||
|     write_file_if_changed, | ||||
| ) | ||||
| from typing import Union | ||||
|  | ||||
| # force import gpio to register pin schema | ||||
| from .gpio import nrf52_pin_to_code  # noqa | ||||
|  | ||||
| AUTO_LOAD = ["nrf52_nrfx"] | ||||
| # def AUTO_LOAD(): | ||||
| #     # if CORE.using_arduino: | ||||
| #         return ["nrf52_nrfx"] | ||||
| #     # return [] | ||||
|  | ||||
| KEY_NRF52 = "nrf52" | ||||
|  | ||||
|  | ||||
| def set_core_data(config): | ||||
|     CORE.data[KEY_NRF52] = {} | ||||
|     CORE.data[KEY_NRF52][KEY_PRJ_CONF_OPTIONS] = {} | ||||
|     CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] = PLATFORM_NRF52 | ||||
|     CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK] = "arduino" | ||||
|     CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK] = config[CONF_FRAMEWORK][CONF_TYPE] | ||||
|     return config | ||||
|  | ||||
|  | ||||
| # https://github.com/platformio/platform-nordicnrf52/releases | ||||
| ARDUINO_PLATFORM_VERSION = cv.Version(10, 3, 0) | ||||
| NORDICNRF52_PLATFORM_VERSION = cv.Version(10, 3, 0) | ||||
|  | ||||
|  | ||||
| def _arduino_check_versions(value): | ||||
| def _platform_check_versions(value): | ||||
|     value = value.copy() | ||||
|     value[CONF_PLATFORM_VERSION] = value.get( | ||||
|         CONF_PLATFORM_VERSION, _parse_platform_version(str(ARDUINO_PLATFORM_VERSION)) | ||||
|         CONF_PLATFORM_VERSION, | ||||
|         _parse_platform_version(str(NORDICNRF52_PLATFORM_VERSION)), | ||||
|     ) | ||||
|     return value | ||||
|  | ||||
| @@ -46,20 +59,32 @@ def _parse_platform_version(value): | ||||
|  | ||||
| CONF_PLATFORM_VERSION = "platform_version" | ||||
|  | ||||
| ARDUINO_FRAMEWORK_SCHEMA = cv.All( | ||||
| PLATFORM_FRAMEWORK_SCHEMA = cv.All( | ||||
|     cv.Schema( | ||||
|         { | ||||
|             cv.Optional(CONF_PLATFORM_VERSION): _parse_platform_version, | ||||
|         } | ||||
|     ), | ||||
|     _arduino_check_versions, | ||||
|     _platform_check_versions, | ||||
| ) | ||||
|  | ||||
| FRAMEWORK_ZEPHYR = "zephyr" | ||||
| FRAMEWORK_ARDUINO = "arduino" | ||||
| FRAMEWORK_SCHEMA = cv.typed_schema( | ||||
|     { | ||||
|         FRAMEWORK_ZEPHYR: PLATFORM_FRAMEWORK_SCHEMA, | ||||
|         FRAMEWORK_ARDUINO: PLATFORM_FRAMEWORK_SCHEMA, | ||||
|     }, | ||||
|     lower=True, | ||||
|     space="-", | ||||
|     default_type=FRAMEWORK_ARDUINO, | ||||
| ) | ||||
|  | ||||
| CONFIG_SCHEMA = cv.All( | ||||
|     cv.Schema( | ||||
|         { | ||||
|             cv.Required(CONF_BOARD): cv.string_strict, | ||||
|             cv.Optional(CONF_FRAMEWORK, default={}): ARDUINO_FRAMEWORK_SCHEMA, | ||||
|             cv.Optional(CONF_FRAMEWORK, default={}): FRAMEWORK_SCHEMA, | ||||
|         } | ||||
|     ), | ||||
|     set_core_data, | ||||
| @@ -68,31 +93,94 @@ CONFIG_SCHEMA = cv.All( | ||||
| nrf52_ns = cg.esphome_ns.namespace("nrf52") | ||||
|  | ||||
|  | ||||
| PrjConfValueType = Union[bool, str, int] | ||||
| KEY_PRJ_CONF_OPTIONS = "prj_conf_options" | ||||
|  | ||||
|  | ||||
| def add_zephyr_prj_conf_option(name: str, value: PrjConfValueType): | ||||
|     """Set an zephyr prj conf value.""" | ||||
|     if not CORE.using_zephyr: | ||||
|         raise ValueError("Not an zephyr project") | ||||
|     if name in CORE.data[KEY_NRF52][KEY_PRJ_CONF_OPTIONS]: | ||||
|         old_value = CORE.data[KEY_NRF52][KEY_PRJ_CONF_OPTIONS][name] | ||||
|         if old_value != value: | ||||
|             raise ValueError( | ||||
|                 f"{name} alread set with value {old_value}, new value {value}" | ||||
|             ) | ||||
|     CORE.data[KEY_NRF52][KEY_PRJ_CONF_OPTIONS][name] = value | ||||
|  | ||||
|  | ||||
| @coroutine_with_priority(1000) | ||||
| async def to_code(config): | ||||
|     cg.add(nrf52_ns.setup_preferences()) | ||||
|     if config[CONF_BOARD] == "nrf52840": | ||||
|         # it has most generic GPIO mapping | ||||
|         config[CONF_BOARD] = "nrf52840_dk_adafruit" | ||||
|         if CORE.using_zephyr: | ||||
|             # this board works with https://github.com/adafruit/Adafruit_nRF52_Bootloader | ||||
|             config[CONF_BOARD] = "adafruit_itsybitsy_nrf52840" | ||||
|         elif CORE.using_arduino: | ||||
|             # it has most generic GPIO mapping | ||||
|             config[CONF_BOARD] = "nrf52840_dk_adafruit" | ||||
|     cg.add_platformio_option("board", config[CONF_BOARD]) | ||||
|     cg.add_build_flag("-DUSE_NRF52") | ||||
|     cg.add_define("ESPHOME_BOARD", config[CONF_BOARD]) | ||||
|     cg.add_define("ESPHOME_VARIANT", "nrf52840") | ||||
|     conf = config[CONF_FRAMEWORK] | ||||
|     cg.add_platformio_option("framework", "arduino") | ||||
|     cg.add_build_flag("-DUSE_ARDUINO") | ||||
|     cg.add_platformio_option(CONF_FRAMEWORK, conf[CONF_TYPE]) | ||||
|     cg.add_platformio_option("platform", conf[CONF_PLATFORM_VERSION]) | ||||
|     # make sure that firmware.zip is created | ||||
|     # for Adafruit_nRF52_Bootloader | ||||
|     cg.add_platformio_option("board_upload.protocol", "nrfutil") | ||||
|     cg.add_platformio_option("board_upload.use_1200bps_touch", "true") | ||||
|     cg.add_platformio_option("board_upload.require_upload_port", "true") | ||||
|     cg.add_platformio_option("board_upload.wait_for_upload_port", "true") | ||||
|     # watchdog | ||||
|     cg.add_build_flag("-DNRFX_WDT_ENABLED=1") | ||||
|     cg.add_build_flag("-DNRFX_WDT0_ENABLED=1") | ||||
|     cg.add_build_flag("-DNRFX_WDT_CONFIG_NO_IRQ=1") | ||||
|     # prevent setting up GPIO PINs | ||||
|     cg.add_platformio_option("board_build.variant", "nrf52840") | ||||
|     cg.add_platformio_option( | ||||
|         "board_build.variants_dir", os.path.dirname(os.path.realpath(__file__)) | ||||
|     ) | ||||
|     if CORE.using_arduino: | ||||
|         cg.add_build_flag("-DUSE_ARDUINO") | ||||
|         # watchdog | ||||
|         cg.add_build_flag("-DNRFX_WDT_ENABLED=1") | ||||
|         cg.add_build_flag("-DNRFX_WDT0_ENABLED=1") | ||||
|         cg.add_build_flag("-DNRFX_WDT_CONFIG_NO_IRQ=1") | ||||
|         # prevent setting up GPIO PINs | ||||
|         cg.add_platformio_option("board_build.variant", "nrf52840") | ||||
|         cg.add_platformio_option( | ||||
|             "board_build.variants_dir", os.path.dirname(os.path.realpath(__file__)) | ||||
|         ) | ||||
|     elif CORE.using_zephyr: | ||||
|         cg.add_build_flag("-DUSE_ZEPHYR") | ||||
|         cg.add_platformio_option( | ||||
|             "platform_packages", ["framework-zephyr@~2.30400.230914"] | ||||
|         ) | ||||
|         # cpp support | ||||
|         add_zephyr_prj_conf_option("CONFIG_NEWLIB_LIBC", False) | ||||
|         add_zephyr_prj_conf_option("CONFIG_NEWLIB_LIBC_NANO", True) | ||||
|         add_zephyr_prj_conf_option("CONFIG_NEWLIB_LIBC_FLOAT_PRINTF", True) | ||||
|         add_zephyr_prj_conf_option("CONFIG_CPLUSPLUS", True) | ||||
|         add_zephyr_prj_conf_option("CONFIG_LIB_CPLUSPLUS", True) | ||||
|         # watchdog | ||||
|         add_zephyr_prj_conf_option("CONFIG_WATCHDOG", True) | ||||
|         add_zephyr_prj_conf_option("CONFIG_WDT_DISABLE_AT_BOOT", False) | ||||
|     else: | ||||
|         raise NotImplementedError | ||||
|  | ||||
|  | ||||
| def _format_prj_conf_val(value: PrjConfValueType) -> str: | ||||
|     if isinstance(value, bool): | ||||
|         return "y" if value else "n" | ||||
|     if isinstance(value, int): | ||||
|         return str(value) | ||||
|     if isinstance(value, str): | ||||
|         return f'"{value}"' | ||||
|     raise ValueError | ||||
|  | ||||
|  | ||||
| # Called by writer.py | ||||
| def copy_files(): | ||||
|     if CORE.using_zephyr: | ||||
|         want_opts = CORE.data[KEY_NRF52][KEY_PRJ_CONF_OPTIONS] | ||||
|         contents = ( | ||||
|             "\n".join( | ||||
|                 f"{name}={_format_prj_conf_val(value)}" | ||||
|                 for name, value in sorted(want_opts.items()) | ||||
|             ) | ||||
|             + "\n" | ||||
|         ) | ||||
|         write_file_if_changed(CORE.relative_build_path("zephyr/prj.conf"), contents) | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| #pragma once | ||||
| #include <cstdint> | ||||
|  | ||||
| namespace esphome { | ||||
|  | ||||
|   | ||||
| @@ -1,11 +1,10 @@ | ||||
| #ifdef USE_NRF52 | ||||
| 
 | ||||
| #ifdef USE_ARDUINO | ||||
| #include <Arduino.h> | ||||
| #include "Adafruit_nRFCrypto.h" | ||||
| #include "nrfx_wdt.h" | ||||
| 
 | ||||
| namespace esphome { | ||||
| 
 | ||||
| void yield() { ::yield(); } | ||||
| uint32_t millis() { return ::millis(); } | ||||
| void delay(uint32_t ms) { ::delay(ms); } | ||||
| @@ -58,7 +57,7 @@ void nrf52GetMacAddr(uint8_t *mac) | ||||
|     mac[1] = src[4]; | ||||
|     mac[0] = src[5] | 0xc0; // MSB high two bits get set elsewhere in the bluetooth stack
 | ||||
| } | ||||
| 
 | ||||
| }  // namespace esphome
 | ||||
| 
 | ||||
| #endif | ||||
| #endif  // USE_RP2040
 | ||||
							
								
								
									
										45
									
								
								esphome/components/nrf52/core_zephyr.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								esphome/components/nrf52/core_zephyr.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| #ifdef USE_NRF52 | ||||
| #ifdef USE_ZEPHYR | ||||
|  | ||||
| #include <zephyr/kernel.h> | ||||
|  | ||||
| namespace esphome { | ||||
| void yield() { ::k_yield(); } | ||||
| uint32_t millis() { return ::k_ticks_to_ms_floor32(k_uptime_ticks()); } | ||||
| void delay(uint32_t ms) { ::k_msleep(ms); } | ||||
| uint32_t micros() { return ::k_ticks_to_us_floor32(k_uptime_ticks()); } | ||||
|  | ||||
| void arch_init() { | ||||
|     // TODO | ||||
| } | ||||
| void arch_feed_wdt() { | ||||
|     // TODO | ||||
| } | ||||
|  | ||||
| void nrf52GetMacAddr(uint8_t *mac) | ||||
| { | ||||
|     const uint8_t *src = (const uint8_t *)NRF_FICR->DEVICEADDR; | ||||
|     mac[5] = src[0]; | ||||
|     mac[4] = src[1]; | ||||
|     mac[3] = src[2]; | ||||
|     mac[2] = src[3]; | ||||
|     mac[1] = src[4]; | ||||
|     mac[0] = src[5] | 0xc0; // MSB high two bits get set elsewhere in the bluetooth stack | ||||
| } | ||||
|  | ||||
| }  // namespace esphome | ||||
|  | ||||
| void setup(); | ||||
| void loop(); | ||||
|  | ||||
| int main(){ | ||||
|     setup(); | ||||
|     while(1) { | ||||
|         loop(); | ||||
|         esphome::yield(); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| #endif | ||||
| #endif  // USE_RP2040 | ||||
| @@ -1,10 +1,10 @@ | ||||
| #pragma once | ||||
|  | ||||
| #ifdef USE_NRF52 | ||||
|  | ||||
| #include <Arduino.h> | ||||
| #include "esphome/core/hal.h" | ||||
|  | ||||
| #ifdef USE_ZEPHYR | ||||
| struct device; | ||||
| #endif | ||||
| namespace esphome { | ||||
| namespace nrf52 { | ||||
|  | ||||
| @@ -14,7 +14,7 @@ class NRF52GPIOPin : public InternalGPIOPin { | ||||
|   void set_inverted(bool inverted) { inverted_ = inverted; } | ||||
|   void set_flags(gpio::Flags flags) { flags_ = flags; } | ||||
|  | ||||
|   void setup() override { pin_mode(flags_); } | ||||
|   void setup() override; | ||||
|   void pin_mode(gpio::Flags flags) override; | ||||
|   bool digital_read() override; | ||||
|   void digital_write(bool value) override; | ||||
| @@ -30,6 +30,9 @@ class NRF52GPIOPin : public InternalGPIOPin { | ||||
|   uint8_t pin_; | ||||
|   bool inverted_; | ||||
|   gpio::Flags flags_; | ||||
| #ifdef USE_ZEPHYR | ||||
|   const device * gpio_ = nullptr; | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| }  // namespace nrf52 | ||||
|   | ||||
| @@ -1,9 +1,11 @@ | ||||
| #ifdef USE_NRF52 | ||||
| #ifdef USE_ARDUINO | ||||
| 
 | ||||
| #include "gpio.h" | ||||
| #include "esphome/core/log.h" | ||||
| #include <functional> | ||||
| #include <vector> | ||||
| #include "Arduino.h" | ||||
| 
 | ||||
| namespace esphome { | ||||
| namespace nrf52 { | ||||
| @@ -77,6 +79,9 @@ void NRF52GPIOPin::attach_interrupt(void (*func)(void *), void *arg, gpio::Inter | ||||
|   irq_arg = arg; | ||||
|   attachInterrupt(pin_, pin_irq, mode); | ||||
| } | ||||
| 
 | ||||
| void NRF52GPIOPin::setup() { pin_mode(flags_); } | ||||
| 
 | ||||
| void NRF52GPIOPin::pin_mode(gpio::Flags flags) { | ||||
|   pinMode(pin_, flags_to_mode(flags, pin_));  // NOLINT
 | ||||
| } | ||||
| @@ -109,4 +114,5 @@ bool IRAM_ATTR ISRInternalGPIOPin::digital_read() { | ||||
| 
 | ||||
| }  // namespace esphome
 | ||||
| 
 | ||||
| #endif | ||||
| #endif  // USE_NRF52
 | ||||
							
								
								
									
										143
									
								
								esphome/components/nrf52/gpio_zephyr.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								esphome/components/nrf52/gpio_zephyr.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,143 @@ | ||||
| #ifdef USE_NRF52 | ||||
| #ifdef USE_ZEPHYR | ||||
|  | ||||
| #include "gpio.h" | ||||
| #include "esphome/core/log.h" | ||||
| // #include <functional> | ||||
| // #include <vector> | ||||
| // #include <device.h> | ||||
| #include <zephyr/drivers/gpio.h> | ||||
|  | ||||
| namespace esphome { | ||||
| namespace nrf52 { | ||||
|  | ||||
| static const char *const TAG = "nrf52"; | ||||
|  | ||||
| static int flags_to_mode(gpio::Flags flags, uint8_t pin) { | ||||
|   if (flags == gpio::FLAG_INPUT) {  // NOLINT(bugprone-branch-clone) | ||||
|     return GPIO_INPUT; | ||||
|   } else if (flags == gpio::FLAG_OUTPUT) { | ||||
|     return GPIO_OUTPUT; | ||||
|   } else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLUP)) { | ||||
|     return GPIO_INPUT | GPIO_PULL_UP; | ||||
|   } else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLDOWN)) { | ||||
|     return GPIO_INPUT | GPIO_PULL_DOWN; | ||||
|   } else if (flags == (gpio::FLAG_OUTPUT | gpio::FLAG_OPEN_DRAIN)) { | ||||
|       return GPIO_OUTPUT | GPIO_OPEN_DRAIN; | ||||
|   } else { | ||||
|     return GPIO_DISCONNECTED; | ||||
|   } | ||||
| } | ||||
|  | ||||
| struct ISRPinArg { | ||||
|   uint8_t pin; | ||||
|   bool inverted; | ||||
| }; | ||||
|  | ||||
| //TODO implement | ||||
| //TODO test | ||||
| // void (*irq_cb)(void *); | ||||
| // void* irq_arg; | ||||
| // static void pin_irq(void){ | ||||
| //   irq_cb(irq_arg); | ||||
| // } | ||||
|  | ||||
| ISRInternalGPIOPin NRF52GPIOPin::to_isr() const { | ||||
|   auto *arg = new ISRPinArg{};  // NOLINT(cppcoreguidelines-owning-memory) | ||||
|   arg->pin = pin_; | ||||
|   arg->inverted = inverted_; | ||||
|   return ISRInternalGPIOPin((void *) arg); | ||||
| } | ||||
|  | ||||
| void NRF52GPIOPin::attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const { | ||||
|   // uint32_t mode = ISR_DEFERRED; | ||||
|   // switch (type) { | ||||
|   //   case gpio::INTERRUPT_RISING_EDGE: | ||||
|   //     mode |= inverted_ ? FALLING : RISING; | ||||
|   //     break; | ||||
|   //   case gpio::INTERRUPT_FALLING_EDGE: | ||||
|   //     mode |= inverted_ ? RISING : FALLING; | ||||
|   //     break; | ||||
|   //   case gpio::INTERRUPT_ANY_EDGE: | ||||
|   //     mode |= CHANGE; | ||||
|   //     break; | ||||
|   //   default: | ||||
|   //     return; | ||||
|   // } | ||||
|  | ||||
|   // irq_cb = func; | ||||
|   // irq_arg = arg; | ||||
|   // attachInterrupt(pin_, pin_irq, mode); | ||||
| } | ||||
|  | ||||
| void NRF52GPIOPin::setup() { | ||||
|   const struct device * gpio = nullptr; | ||||
|   if(pin_ < 32) { | ||||
| #define GPIO0 DT_NODELABEL(gpio0) | ||||
| #if DT_NODE_HAS_STATUS(GPIO0, okay) | ||||
|   gpio = DEVICE_DT_GET(GPIO0); | ||||
| #else | ||||
| #error "gpio0 is disabled" | ||||
| #endif | ||||
|   } else { | ||||
| #define GPIO1 DT_NODELABEL(gpio1) | ||||
| #if DT_NODE_HAS_STATUS(GPIO1, okay) | ||||
|   gpio = DEVICE_DT_GET(GPIO1); | ||||
| #else | ||||
| #error "gpio1 is disabled" | ||||
| #endif | ||||
|   } | ||||
|   //TODO why no ready?? | ||||
|   // if (!device_is_ready(gpio)) { | ||||
|     gpio_ = gpio; | ||||
|   // } else { | ||||
|   //   ESP_LOGE(TAG, "gpio %u is not ready.", pin_); | ||||
|   // } | ||||
|   gpio_ = gpio; | ||||
|   pin_mode(flags_);  | ||||
| } | ||||
|  | ||||
| void NRF52GPIOPin::pin_mode(gpio::Flags flags) { | ||||
|   if(nullptr == gpio_) { | ||||
|     return; | ||||
|   } | ||||
|   gpio_pin_configure(gpio_, pin_, flags_to_mode(flags, pin_)); | ||||
| } | ||||
|  | ||||
| std::string NRF52GPIOPin::dump_summary() const { | ||||
|   char buffer[32]; | ||||
|   snprintf(buffer, sizeof(buffer), "GPIO%u", pin_); | ||||
|   return buffer; | ||||
| } | ||||
|  | ||||
| bool NRF52GPIOPin::digital_read() { | ||||
|   if(nullptr == gpio_) { | ||||
|     //TODO invert ?? | ||||
|     return false; | ||||
|   } | ||||
|   return bool(gpio_pin_get(gpio_, pin_)) != inverted_;  // NOLINT | ||||
| } | ||||
| void NRF52GPIOPin::digital_write(bool value) { | ||||
|   if(nullptr == gpio_) { | ||||
|     return; | ||||
|   } | ||||
|   gpio_pin_set(gpio_, pin_, value != inverted_ ? 1 : 0); | ||||
| } | ||||
| void NRF52GPIOPin::detach_interrupt() const { | ||||
|   //  detachInterrupt(pin_);  | ||||
| } | ||||
|  | ||||
| }  // namespace nrf52 | ||||
|  | ||||
| // using namespace nrf52; | ||||
|  | ||||
| // TODO seems to not work??? | ||||
| // bool IRAM_ATTR ISRInternalGPIOPin::digital_read() { | ||||
|   // auto *arg = reinterpret_cast<nrf52::ISRPinArg *>(arg_); | ||||
|   // return bool(digitalRead(arg->pin)) != arg->inverted;  // NOLINT | ||||
| // } | ||||
|  | ||||
| }  // namespace esphome | ||||
|  | ||||
| #endif | ||||
| #endif  // USE_NRF52 | ||||
							
								
								
									
										31
									
								
								esphome/components/shell/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								esphome/components/shell/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     CONF_ID, | ||||
| ) | ||||
| from esphome.components.nrf52 import add_zephyr_prj_conf_option | ||||
|  | ||||
| shell_ns = cg.esphome_ns.namespace("shell") | ||||
| Shell = shell_ns.class_("Shell", cg.Component) | ||||
|  | ||||
| CONFIG_SCHEMA = cv.All( | ||||
|     cv.Schema( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(Shell), | ||||
|         } | ||||
|     ).extend(cv.COMPONENT_SCHEMA), | ||||
|     cv.only_with_zephyr, | ||||
| ) | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     await cg.register_component(var, config) | ||||
|     add_zephyr_prj_conf_option("CONFIG_SHELL", True) | ||||
|     add_zephyr_prj_conf_option("CONFIG_SHELL_BACKENDS", True) | ||||
|     add_zephyr_prj_conf_option("CONFIG_SHELL_BACKEND_SERIAL", True) | ||||
|     add_zephyr_prj_conf_option("CONFIG_NET_SHELL_DYN_CMD_COMPLETION", True) | ||||
|     add_zephyr_prj_conf_option("CONFIG_NET_SHELL", True) | ||||
|     add_zephyr_prj_conf_option("CONFIG_GPIO_SHELL", True) | ||||
|     # add_zephyr_prj_conf_option("CONFIG_ADC_SHELL", True) | ||||
|     add_zephyr_prj_conf_option("CONFIG_NET_L2_BT_SHELL", True) | ||||
							
								
								
									
										21
									
								
								esphome/components/shell/shell.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								esphome/components/shell/shell.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| #include "shell.h" | ||||
| #include <zephyr/usb/usb_device.h> | ||||
|  | ||||
| struct device; | ||||
|  | ||||
| namespace esphome { | ||||
| namespace shell { | ||||
|  | ||||
| void Shell::setup() { | ||||
| #if DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_shell_uart), zephyr_cdc_acm_uart) | ||||
| 	const device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_shell_uart)); | ||||
| 	if (!device_is_ready(dev) || usb_enable(NULL)) { | ||||
| 		return; | ||||
| 	} | ||||
| #else | ||||
| #error "shell is not set in device tree" | ||||
| #endif | ||||
| } | ||||
|  | ||||
| }  // namespace shell | ||||
| }  // namespace esphome | ||||
							
								
								
									
										10
									
								
								esphome/components/shell/shell.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								esphome/components/shell/shell.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| #pragma once | ||||
| #include "esphome/core/component.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace shell { | ||||
| class Shell : public Component { | ||||
| 	void setup() override; | ||||
| }; | ||||
| } | ||||
| } | ||||
| @@ -599,6 +599,7 @@ only_on_rp2040 = only_on(PLATFORM_RP2040) | ||||
| only_on_nrf52 = only_on(PLATFORM_NRF52) | ||||
| only_with_arduino = only_with_framework("arduino") | ||||
| only_with_esp_idf = only_with_framework("esp-idf") | ||||
| only_with_zephyr = only_with_framework("zephyr") | ||||
|  | ||||
|  | ||||
| # Adapted from: | ||||
|   | ||||
| @@ -676,6 +676,10 @@ class EsphomeCore: | ||||
|     def using_esp_idf(self): | ||||
|         return self.target_framework == "esp-idf" | ||||
|  | ||||
|     @property | ||||
|     def using_zephyr(self): | ||||
|         return self.target_framework == "zephyr" | ||||
|  | ||||
|     def add_job(self, func, *args, **kwargs): | ||||
|         self.event_loop.add_job(func, *args, **kwargs) | ||||
|  | ||||
|   | ||||
| @@ -10,6 +10,7 @@ | ||||
| #include <cstdarg> | ||||
| #include <cstdio> | ||||
| #include <cstring> | ||||
| #include <strings.h> | ||||
|  | ||||
| #if defined(USE_ESP8266) | ||||
| #include <osapi.h> | ||||
| @@ -48,7 +49,9 @@ | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_NRF52 | ||||
| #ifdef USE_ARDUINO | ||||
| #include "Adafruit_nRFCrypto.h" | ||||
| #endif | ||||
| #include "esphome/components/nrf52/core.h" | ||||
| #endif | ||||
|  | ||||
| @@ -246,7 +249,11 @@ bool random_bytes(uint8_t *data, size_t len) { | ||||
|   fclose(fp); | ||||
|   return true; | ||||
| #elif defined(USE_NRF52) | ||||
| #ifdef USE_ARDUINO | ||||
|   return nRFCrypto.Random.generate(data, len); | ||||
| #elif USE_ZEPHYR | ||||
| //TODO | ||||
| #endif | ||||
| #else | ||||
| #error "No random source available for this configuration." | ||||
| #endif | ||||
| @@ -518,13 +525,14 @@ void hsv_to_rgb(int hue, float saturation, float value, float &red, float &green | ||||
| } | ||||
|  | ||||
| // System APIs | ||||
| #if defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_HOST) | ||||
| #if defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_HOST) || defined(USE_NRF52) | ||||
| // ESP8266 doesn't have mutexes, but that shouldn't be an issue as it's single-core and non-preemptive OS. | ||||
| Mutex::Mutex() {} | ||||
| void Mutex::lock() {} | ||||
| bool Mutex::try_lock() { return true; } | ||||
| void Mutex::unlock() {} | ||||
| #elif defined(USE_ESP32) || defined(USE_LIBRETINY) || defined(USE_NRF52) | ||||
| //TODO | ||||
| #elif defined(USE_ESP32) || defined(USE_LIBRETINY) /*|| defined(USE_NRF52)*/ | ||||
| Mutex::Mutex() { handle_ = xSemaphoreCreateMutex(); } | ||||
| void Mutex::lock() { xSemaphoreTake(this->handle_, portMAX_DELAY); } | ||||
| bool Mutex::try_lock() { return xSemaphoreTake(this->handle_, 0) == pdTRUE; } | ||||
|   | ||||
| @@ -21,8 +21,10 @@ | ||||
| #include <FreeRTOS.h> | ||||
| #include <semphr.h> | ||||
| #elif defined(USE_NRF52) | ||||
| #ifdef USE_ARDUINO | ||||
| #include <Arduino.h> | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #define HOT __attribute__((hot)) | ||||
| #define ESPDEPRECATED(msg, when) __attribute__((deprecated(msg))) | ||||
| @@ -548,7 +550,8 @@ class Mutex { | ||||
|   Mutex &operator=(const Mutex &) = delete; | ||||
|  | ||||
|  private: | ||||
| #if defined(USE_ESP32) || defined(USE_LIBRETINY) || defined(USE_NRF52) | ||||
| //TODO | ||||
| #if defined(USE_ESP32) || defined(USE_LIBRETINY) /*|| defined(USE_NRF52)*/ | ||||
|   SemaphoreHandle_t handle_; | ||||
| #endif | ||||
| }; | ||||
|   | ||||
| @@ -310,6 +310,10 @@ def copy_src_tree(): | ||||
|                 CORE.relative_src_path("esphome.h"), | ||||
|                 ESPHOME_H_FORMAT.format(include_s + '\n#include "pio_includes.h"'), | ||||
|             ) | ||||
|     elif CORE.is_nrf52: | ||||
|         from esphome.components.nrf52 import copy_files | ||||
|  | ||||
|         copy_files() | ||||
|  | ||||
|  | ||||
| def generate_defines_h(): | ||||
|   | ||||
		Reference in New Issue
	
	Block a user