具有多种消息类型的嵌入式RTOS生产者和使用者

时间:2018-07-23 14:27:35

标签: c multithreading embedded freertos rtos

许多RTOS消息传递示例显示了生产者生成的内容与int32一样简单,并且消费者正在读取它。这很简单,因为您总是知道从队列(或其他消息传递缓冲区)中出来的类型以及大小。

考虑使用RTOS线程从GPS读取数据的情况。 GPS可能包含许多类型的消息。您无法保证消息何时到达,消息的顺序或消息的大小。每条消息都有许多字段,每条消息都可以表示为一个结构。

这个GPS处理生产者RTOS线程理想地将数据流解析进来,然后将数据传递出去,以便消费者线程可以轻松读取GPS数据。

假设FreeRTOS或CMSIS RTOS。如何最好地建立这种安排?将使用哪些原语?从根本上讲,我正在寻找一种干净的方法,可以将几种不同类型的不同大小的结构从生产者线程中传递出来,并在使用者中读取它们。

2 个答案:

答案 0 :(得分:4)

FreeRTOS文档与QueueSet一起讨论了该问题。 (请参阅“使用队列集的替代方法”一节中的https://www.freertos.org/Pend-on-multiple-rtos-objects.html)。 基本上,这个想法是要有一个枚举来标识缓冲区中不同类型的消息。

对于您的缓冲区类型,可以结合使用枚举和结构体联合。

count

然后您可以区分以下消息:

struct A {uint32_t foo;};
struct B {uint8_t bar;};
enum T {AType, BType};

struct GenericMessage{
    T type;
    union{
        struct A a;
        struct B b;
    };
};

答案 1 :(得分:3)

您可能会考虑使用指向消息的指针队列,而不是使用消息本身队列。这样,不管消息是什么,队列中的每个项目都是固定大小(指针大小)。

该技术确实需要仔细的资源管理,以确保在接收者处理完消息之前,不对消息进行修改,删除或重用。您需要一个allocate-enqueue-dequeue-deallocate机制。

例如,给定:

enum eMessageType
{ AType, 
  BType
};

struct GenericMessage
{
    eMessageType type;
    char payload[0] ; // Note GCC zero-length array extension
};

struct A { struct GenericMessage, 
           uint32_t foo;
         };

struct B { struct GenericMessage,
           uint8_t bar;
         };

然后,发件人可能会有类似(伪代码)的内容:

 struct A* messageA = allocateMessageA( AType, 0x12345678 ) ;     
 struct B* messageB = allocateMessageB{ BType, 0x12 } ;

 sendGeneric( genericQ, messageA ) ;     
 sendGeneric( genericQ, messageB ) ;

和接收方:

 struct GenericMessage* message_ptr = receiveGeneric( genericQ ) ;
 switch( message_ptr->type )
 {
    case AType:
    {
        struct A* = (struct A*)message_ptr ;
        uint32_t payload = message_ptr->payload ;
        ...
        deallocateMessageA( message_ptr ) ;
    }
    break;

    case BType:
    {
        struct B* = (struct B*)message_ptr ;
        uint8_t payload = message_ptr->payload ;
        ...
        deallocateMessageB( message_ptr ) ;
    }
}  

我尚未定义的分配/取消分配功能的详细信息。一种简单的方法是使用固定块内存池。如果您的RTOS不提供这些,一种简单的实现是在池中有指向消息的指针队列,每种消息类型一个队列/池。要进行分配,只需将消息从队列中取出来从相关消息池中获取指针,然后通过将指针返回到队列来进行分配。

请注意,某些RTOS允许直接发送可变长度的消息-例如,在embOS中,您可以为队列分配内存池,并在发送而不是在创建队列时指定长度。但是,接收者必须能够接收最大可能的消息。