1.strongswan:MEDTH宏
#ifdef __cplusplus #define TEMPORARY decltype #else #define TEMPORARY __typeof__ #endif /** * Method declaration/definition macro, providing private and public interface. * * Defines a method name with this as first parameter and a return value ret, * and an alias for this method with a _ prefix, having the this argument * safely casted to the public interface iface. * _name is provided a function pointer, but will get optimized out by GCC. */ #define METHOD(iface, name, ret, this, ...) \ \ static ret name( \ union {iface *_public; this; } \ __attribute__((transparent_union)), \ ##__VA_ARGS__); \ \ static TEMPORARY(name) *_##name = (TEMPORARY(name) *)name; \ \ static ret name(this, ##__VA_ARGS__)
其中关于 typeof 和 METHOD 自行搜索学习
这里带入扩展一下
#define METHOD(iface, name, ret, this, ...) METHOD(blink2_public_t, run, void, blink2_private_t *self, const int tick) // // 将私有和公共联合 static void run( union {blink2_public_t *_public; self;} __attribute__((transparent_union)), // 关键 ##__VA_ARGS__); // 该联合类型的函数指针,调用时用这个,##是连接符,_##name => _run static __typeof__(run) *_##name = (__typeof__(name) *)name; // 函数体 static void run(self, ##__VA_ARGS__) { }
2.使用
blink.h
#ifndef BLINK2_H #define BLINK2_H #ifdef __cplusplus #define TEMPORARY decltype #else #define TEMPORARY __typeof__ #endif /** * Method declaration/definition macro, providing private and public interface. * * Defines a method name with this as first parameter and a return value ret, * and an alias for this method with a _ prefix, having the this argument * safely casted to the public interface iface. * _name is provided a function pointer, but will get optimized out by GCC. */ #define METHOD(iface, name, ret, this, ...) \ \ static ret name( \ union {iface *_public; this; } \ __attribute__((transparent_union)), \ ##__VA_ARGS__); \ \ static TEMPORARY(name) *_##name = (TEMPORARY(name) *)name; \ \ static ret name(this, ##__VA_ARGS__) typedef struct blink2_public blink2_public_t; struct blink2_public { void (*run)(blink2_public_t *self, const int tick); }; blink2_public_t *blink2_create(void (*hw_init)(void), void (*on)(void), void (*off)(void), const int on_time, const int off_time); #endif
blink.c
#include <stdio.h> #include "blink2.h" typedef struct blink2_private blink2_private_t; struct blink2_private { blink2_public_t pub; int on_time; int off_time; int tick; int tick_count; void (*on)(void); void (*off)(void); }; METHOD(blink2_public_t, run, void, blink2_private_t *self, const int tick) { if (self->tick != tick) { self->tick = tick; self->tick_count++; } if (self->tick_count < self->on_time) { self->on(); } else if (self->tick_count < (self->on_time + self->off_time)) { self->off(); } else { self->tick_count = 0; } } blink2_public_t *blink2_create(void (*hw_init)(void), void (*on)(void), void (*off)(void), const int on_time, const int off_time) { assert(hw_init); assert(on); assert(off); blink2_private_t *priv = malloc(sizeof(blink2_private_t)); assert(priv); priv->on_time = on_time; priv->off_time = off_time; priv->on = on; priv->off = off; priv->pub.run = _run; hw_init(); return &(priv->pub); }
main.c
#include <stdio.h> #include "driver/gpio.h" #include "esp_timer.h" #include "blink.h" #include "blink2.h" #define D4_PIN GPIO_NUM_12 #define D5_PIN GPIO_NUM_13 blink2_public_t *blink2; void blink2_hw_init(void) { gpio_reset_pin(D5_PIN); gpio_set_direction(D5_PIN, GPIO_MODE_OUTPUT); } void blink2_on(void) { gpio_set_level(D5_PIN, 1); } void blink2_off(void) { gpio_set_level(D5_PIN, 0); } static void periodic_timer_callback(void* arg); void app_main(void) { blink_init(D4_PIN); blink2 = blink2_create(blink2_hw_init, blink2_on, blink2_off, 500, 500); const esp_timer_create_args_t periodic_timer_args = { .callback = &periodic_timer_callback, .name = "periodic" }; esp_timer_handle_t periodic_timer; ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &periodic_timer)); ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_timer, 1000)); // 1000us while (1) { blink(D4_PIN); } } static void periodic_timer_callback(void* arg) { int64_t time_since_boot = esp_timer_get_time(); blink2->run(blink2, time_since_boot); }
- 这么做是想 blink2 实现公私分离,缺点就是 debug 时(在 keil 中)没法直接查看私有部分。
其中esp的定时器参考:高分辨率定时器(ESP 定时器) - ESP32-C3 - — ESP-IDF 编程指南 latest 文档 (espressif.com)https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32c3/api-reference/system/esp_timer.htmlesp的定时器github:esp-idf/examples/system/esp_timer/main/esp_timer_example_main.c at b3f7e2c8a4d354df8ef8558ea7caddc07283a57b · espressif/esp-idf · GitHub