P-Com库的开发笔记

P-Communicate的设计思路草稿

Posted by moment on August 18, 2026

前言

大概7月末我萌生了写一个通用通信库的念头,打算照着CPP的类的形式,在C上实现一些多态,但是实际动起手来反而感觉十分生疏,可能是码量太少了的缘故。因此边写边做笔记,避免思路混乱。

基本类型

所有的P-com类都是从一个结构体衍生出来的:

struct p_com_base {
    const p_com_backend_t *backend;   /* 指向具体后端表 —— 与实现唯一的耦合点 */
    p_com_type_t           type;
    uint8_t               ref_count; /* 引用计数(255个绝对够了) */
    void                  *priv;      /* 具体后端私有数据(可不用) */
};

其中,backend指向的是一个虚表,其中储存了可能需要的方法函数指针。由于虚表存在自己的一套继承关系,这里先撇开不谈。 然后又由于:

typedef struct {
    P_ERR (*init)  (void *self, void *arg);
    P_ERR (*deinit)(void *self);
} p_com_backend_t;

这里规定了最基本的p_com_backend_t类型,因此我们可以认为,p_com_base的第一个(和第二个)元素都是

P_ERR (*init)  (void *self, void *arg);
P_ERR (*deinit)(void *self);

这是我们的核心: 在C中,只要第一个元素是一致的,我们就能在多种结构体中互相强制转换。所以我们后续的其他子类结构体,只需要符合第一个元素是init(当然第二个是deinit更好),就能实现”多态”和”继承”。

  • 什么是多态? 同一种类型,在不同参数情况下可以表现出不同的行为
  • 什么是继承? 子类型可以获取父类的特征,减少重复代码

我们在这里引入这些的目的,就是为了使用一套尽可能通用的init/deinit框架,使得所有的类型都可以用一个函数进行初始化,不用为了每个类型单独写一个初始化函数。 不过,值得注意的是,我们这里只规定了类长什么样,有什么静态的内容。而动态的“方法”,我们还没有做规定,他们是存在虚函数表中的。 这样,我们拥有了一个可以规范其他类长什么的基类之后,我们就可以开始着手把需求分解成类了。 作为一个通信库,我们肯定要涉及多种通信方式,可能是SPI,可能是UART,可能是CAN,可能是网口或者USB等等。他们的共同点就是都有一个数据输入/输出,都在某条总线上,都可能存在多个设备,我们使用的时候肯定遵循某种协议。因此,我们可以把类分成总线类,协议类,和设备类。 总线上,经常需要一些总线操作,因此我们总线需要一个虚函数表,对总线进行一些操作。 设备上,我们肯定要直接获取数据什么的,要和HAL打交道,因此有个函数表也是比较好的。 协议类,我们也可以搞一个,这样就可以让协议更自由。 那么我们就用了三个主类,以及他们对应的操作虚函数表(backend)

最后,我们需要一个文件来解决中断问题。这个应该与总线层相结合

虚函数表类型

OOP-DOD优化

某天晚上我觉得这样做出来的东西太平庸了,嵌入式框架多如牛毛,我的优点在哪?于是我想到了DOD(面向数据编程)的优化,据此开发了一套OOP转DOD的数据结构。