管道:介绍和基本服务

管道:介绍和基本服务

Pipes: introduction and basic services

与邮箱或队列相比,它们提供了在任务之间传递简单消息的更灵活的方式。             

使用管道             

在Nucleus SE中,管道是在构建时配置的。一个应用程序最多可以配置16个管道。如果未配置管道,则应用程序中不会包含与管道相关的数据结构或服务调用代码。             

管道仅仅是一组存储位置,每个存储位置都足够大,足以容纳一个用户定义字节长度的数据项,对这些数据项的访问是受控制的,以便可以由多个任务安全地使用它。任务可以重复写入管道,直到所有位置都已满。任务可以从管道中读取,数据通常以先进先出(FIFO)的方式接收。尝试发送到完整管道或从空管道读取可能会导致错误或任务挂起,具体取决于在API调用和Nucleus SE配置中选择的选项。             

管道和队列             

Nucleus SE还支持队列,管道和队列之间的主要区别是消息大小。队列携带由单个ADDR组成的消息,这些地址通常是指针。管道承载任意字节长的消息;应用程序中每个管道的大小是固定的,并在配置时设置。              

配置管道             

管道数量             

与Nucleus SE的大多数方面一样,管道的配置主要由nuse_config.h中的#define语句控制。键设置是NUSE_PIPE_NUMBER,它确定为应用程序配置了多少个管道。默认设置为0(即没有管道正在使用),您可以将其设置为最大16的任何值。错误的值将导致编译时错误,该错误由nuse_config_check.h中的测试生成(此错误包含在nuse_config.c中,因此使用此模块进行编译),从而导致编译一个#错误语句。             

选择非零值是管道的“主启用”。这将导致一些数据结构被相应地定义和调整大小,在下一篇文章中会有更多内容。它还激活API启用设置。             

API启用             

Nucleus SE中的每个API函数(服务调用)在nuse_config.h中都有一个启用的#define符号。对于管道,包括:

NUSE_PIPE_SEND 
NUSE_PIPE_RECEIVE 
NUSE_PIPE_JAM 
NUSE_PIPE_RESET 
NUSE_PIPE_INFORMATION 
NUSE_PIPE_COUNT

默认情况下,所有这些都设置为FALSE,从而禁用每个服务调用并禁止包含任何实现代码。要为应用程序配置管道,需要选择要使用的API调用,并将其启用符号设置为TRUE。             

下面是从默认nuse_config.h文件中提取的内容。

#define NUSE_PIPE_NUMBER    0  /* Number of pipes in the 
                                   system – 0-16 */ 
                                /* Service call enablers */ 
#define NUSE_PIPE_SEND         FALSE  
#define NUSE_PIPE_RECEIVE      FALSE 
#define NUSE_PIPE_JAM          FALSE 
#define NUSE_PIPE_RESET        FALSE 
#define NUSE_PIPE_INFORMATION  FALSE 
#define NUSE_PIPE_COUNT        FALSE

如果启用了管道API函数而未配置管道(除非始终允许使用NUSE_pipe_Count()),则会导致编译时错误。如果您的代码使用尚未启用的API调用,则会导致链接时间错误,因为应用程序中不会包含任何实现代码。             

管道服务电话             

Nucleus RTOS支持10个与管道相关的服务调用,它们提供以下功能:             

向管道发送消息。由Nucleus SE中的NUSE_Pipe_Send()实现。             

从管道接收消息。由Nucleus SE中的NUSE_Pipe_Receive()实现。             

在管道前面发个信息。由Nucleus SE中的NUSE_Pipe_Jam()实现。             

将管道恢复到未使用状态,不暂停任何任务(重置)。由Nucleus SE中的NUSE_Pipe_Reset()实现。             

提供有关指定管道的信息。由Nucleus SE中的NUSE_Pipe_Information()实现。             

返回(当前)为应用程序配置的管道数的计数。由Nucleus SE中的NUSE_Pipe_Count()实现。             

向应用程序添加新管道(创建)。未在Nucleus SE中实现。             

从应用程序中删除管道(删除)。未在Nucleus SE中实现。             

返回指向应用程序中所有管道(当前)的指针。未在Nucleus SE中实现。             

向管道(广播)上挂起的所有任务发送消息。未在Nucleus SE中实现。             

将详细检查每个服务调用的实现。             

管道读写服务             

可以在管道上执行的基本操作是向管道写入数据(有时称为发送)和从中读取数据(也称为接收)。也可以将数据写入管道前端,这也被称为堵塞。Nucleus RTOS和Nucleus SE各自为这些操作提供了三个基本API调用,这里将对此进行讨论。             

写在管道上             

Nucleus RTOS API对管道的写入调用非常灵活,允许您无限期地挂起,或者在操作无法立即完成的情况下暂停,也就是说,您尝试写入一个完整的管道。Nucleus SE提供相同的服务,除了task suspend是可选的并且不实现timeout。             

Nucleus RTOS还提供了一个向管道广播的功能,但Nucleus SE不支持这种功能。

Nucleus RTOS API Call for Sending to a Pipe

Service call prototype:

  STATUS NU_Send_To_Pipe(NU_PIPE *pipe, VOID  *message, 
                          UNSIGNED size, UNSIGNED suspend);

Parameters:

pipe – pointer to the user-supplied pipe control block
message – a pointer to the message to be sent
size – the number of bytes in the message. If the pipe supports variable-length messages, this parameter must be equal to or less than the message size supported by the pipe. If the pipe supports fixed-size messages, this parameter must be exactly the same as the message size supported by the pipe
suspend – specification for task suspend; may be NU_NO_SUSPEND or NU_SUSPEND or a timeout value

Returns:

NU_SUCCESS – the call was completed successfully
NU_INVALID_PIPE – the pipe pointer is invalid
NU_INVALID_POINTER – the message pointer is NULL 
NU_INVALID_SIZE – the message size is incompatible with the message size supported by the pipe
NU_INVALID_SUSPEND – suspend was attempted from a non-task thread
NU_PIPEE_FULL – the pipe is full and suspend was not specified
NU_TIMEOUT – the pipe is still full even after suspending for the specified timeout value
NU_PIPE_DELETED – the pipe was deleted while the task was suspended
NU_PIPE_RESET – the pipe was reset while the task was suspended

Nucleus SE API Call for Sending to a Pipe

This API call supports the key functionality of the Nucleus RTOS API.

Service call prototype:

<="" font="" >

<="" font="" >

STATUS NUSE_Pipe_Send(NUSE_PIPE pipe, U8 *message, 
                      U8 suspend);

Parameters:

pipe – the index (ID) of the pipe to be utilized
message – a pointer to the message to be sent, which is a sequence of bytes as long as the configured message size of the pipe
suspend – specification for task suspend; may be NUSE_NO_SUSPEND or NUSE_SUSPEND

Returns:

NUSE_SUCCESS – the call was completed successfully
NUSE_INVALID_PIPE – the pipe index is invalid
NUSE_INVALID_POINTER – the message pointer is NULL 
NUSE_INVALID_SUSPEND – suspend was attempted from a non-task thread or when blocking API calls were not enabled
NUSE_PIPE_FULL – the pipe is full and suspend was not specified
NUSE_PIPE_WAS_RESET – the pipe was reset while the task was suspended

管道发送的核SE实现             

NUSE_Pipe_Send()–检查API函数是否已启用suspend()的条件编译(取决于u)的API是否已启用。我们将在这里分别研究这两种变体。             

如果未启用阻塞,则此API调用的代码非常简单:

if (NUSE_Pipe_Items[pipe] == NUSE_Pipe_Size[pipe])  /* pipe                                                       full */{   return_value = NUSE_PIPE_FULL;}else                              /* pipe element available */{   data = &NUSE_Pipe_Data[pipe][NUSE_Pipe_Head[pipe]];   for (i=0; i<msgsize; i++)   {      *data++ = *message++;   }   NUSE_Pipe_Head[pipe] += msgsize;   if (NUSE_Pipe_Head[pipe] == (NUSE_Pipe_Size[pipe] * msgsize))   {      NUSE_Pipe_Head[pipe] = 0;   }   NUSE_Pipe_Items[pipe]++;   return_value = NUSE_SUCCESS;}

该函数只检查管道中是否有空间,并使用NUSE_pipe_Head[]索引将消息存储在管道的数据区域中。             

启用阻塞后,代码会变得更复杂:

do{   if (NUSE_Pipe_Items[pipe] == NUSE_Pipe_Size[pipe]) /* pipe                                                         full */   {      if (suspend == NUSE_NO_SUSPEND)      {         return_value = NUSE_PIPE_FULL;      }      else      {                                           /* block task */         NUSE_Pipe_Blocking_Count[pipe]++;         NUSE_Suspend_Task(NUSE_Task_Active, (pipe << 4) |                           NUSE_PIPE_SUSPEND);         return_value =            NUSE_Task_Blocking_Return[NUSE_Task_Active];         if (return_value != NUSE_SUCCESS)         {            suspend = NUSE_NO_SUSPEND;         }      }   }   else                             /* pipe element available */   {        data = &NUSE_Pipe_Data[pipe][NUSE_Pipe_Head[pipe]];      for (i=0; i<msgsize; i++)      {         *data++ = *message++;      }      NUSE_Pipe_Head[pipe] += msgsize;      if (NUSE_Pipe_Head[pipe] == (NUSE_Pipe_Size[pipe] *                                   msgsize))      {         NUSE_Pipe_Head[pipe] = 0;      }      NUSE_Pipe_Items[pipe]++;      if (NUSE_Pipe_Blocking_Count[pipe] != 0)      {         U8 index;         /* check whether a task is blocked                              on this pipe */         NUSE_Pipe_Blocking_Count[pipe]--;         for (index=0; index<NUSE_TASK_NUMBER; index++)         {            if ((LONIB(NUSE_Task_Status[index]) ==                  NUSE_PIPE_SUSPEND)                  && (HINIB(NUSE_Task_Status[index]) == pipe))            {               NUSE_Task_Blocking_Return[index] = NUSE_SUCCESS;               NUSE_Wake_Task(index);               break;            }         }      }      return_value = NUSE_SUCCESS;      suspend = NUSE_NO_SUSPEND;   }} while (suspend == NUSE_SUSPEND);

对代码的一些解释可能有用:             

代码包含在do…while循环中,当参数suspend的值为NUSE_suspend时,循环将继续。             

如果管道已满,并且suspend设置为NUSE_NO_suspend,则API调用将以NUSE_pipe_full退出。如果suspend设置为NUSE_suspend,则任务将被挂起。返回时(即,当任务被唤醒时),如果返回值为NUSE_SUCCESS,表示任务被唤醒是因为消息已被读取(而不是重置管道),则代码循环返回顶部。             

如果管道未满,则使用NUSE_pipe_Head[]索引存储提供的消息,以将消息存储在管道的数据区域中。检查管道上是否有任何任务挂起(等待接收)。如果有任务等待,第一个任务被唤醒。suspend变量被设置为NUSE_NO_suspend,API调用将退出并返回NUSE_SUCCESS。             

从管子里读东西             

从管道读取的Nucleus RTOS API调用非常灵活,使您能够无限期地挂起,或者在操作无法立即完成的情况下暂停,也就是说,您尝试从空管道中读取。Nucleus SE提供相同的服务,除了task suspend是可选的并且不实现timeout。

ucleus RTOS API Call for Receiving from a Pipe

Service call prototype:

STATUS NU_Receive_From_Pipe(NU_PIPE *pipe, VOID *message, UNSIGNED size, UNSIGNED *actual_size, UNSIGNED suspend);

Parameters:

pipe – pointer to user-supplied pipe control block
message – pointer to storage for the message to be received
size – the number of bytes in the message. This number must correspond to the message size defined when the pipe was created
suspend – specification for task suspend; may be NU_NO_SUSPEND or NU_SUSPEND or a timeout value

Returns:

NU_SUCCESS – the call was completed successfully
NU_INVALID_PIPE – the pipe pointer is invalid
NU_INVALID_POINTER – the message pointer is NULL 
NU_INVALID_SUSPEND – suspend was attempted from a non-task
NU_PIPE_EMPTY – the pipe is empty and suspend was not specified
NU_TIMEOUT – indicates that the pipe is still empty even after suspending for the specified timeout value
NU_PIPE_DELETED – the pipe was deleted while the task was suspended
NU_PIPE_RESET – the pipe was reset while the task was suspended

Nucleus SE API Call for Receiving from a Pipe

This API call supports the key functionality of the Nucleus RTOS API.

Service call prototype:

STATUS NUSE_Pipe_Receive(NUSE_PIPE pipe, U8 *message, 
U8 suspend);

Parameters:

pipe – the index (ID) of the pipe to be utilized
message – a pointer to storage for the message to be received, which is a sequence of bytes as long as the configured message size of the pipe
suspend – specification for task suspend; may be NUSE_NO_SUSPEND or NUSE_SUSPEND

Returns:

NUSE_SUCCESS – the call was completed successfully
NUSE_INVALID_PIPE – the pipe index is invalid
NUSE_INVALID_POINTER – the message pointer is NULL 
NUSE_INVALID_SUSPEND – suspend was attempted from a non-task thread or when blocking API calls were not enabled
NUSE_PIPE_EMPTY – the pipe is empty and suspend was not specified
NUSE_PIPE_WAS_RESET – the pipe was reset while the task was suspended

Nucleus SE Implementation of Pipe Receive

管道接收的核SE实现             

NUSE_Pipe_Receive()API函数的大部分代码(在参数检查之后)是通过条件编译选择的,这取决于是否启用了对阻塞(任务挂起)API调用的支持。我们将在这里分别研究这两种变体。             

如果未启用阻塞,则此API调用的代码非常简单:

if (NUSE_Pipe_Items[pipe] == 0)            /* pipe empty */{   return_value = NUSE_PIPE_EMPTY;}else{                                          /* message available */   data = &NUSE_Pipe_Data[pipe][NUSE_Pipe_Tail[pipe]];   for (i=0; i<msgsize; i++)   {      *message++ = *data++;   }   NUSE_Pipe_Tail[pipe] += msgsize;   if (NUSE_Pipe_Tail[pipe] == (NUSE_Pipe_Size[pipe] * msgsize))   {      NUSE_Pipe_Tail[pipe] = 0;   }   NUSE_Pipe_Items[pipe]--;   *actual_size = msgsize;   return_value = NUSE_SUCCESS;}

只需使用管道中的指针NUSE_Pipe_Tail[]从数据管道中返回数据,并通过管道返回数据。              启用阻塞后,代码会变得更复杂:

do{   if (NUSE_Pipe_Items[pipe] == 0)             /* pipe empty */   {      if (suspend == NUSE_NO_SUSPEND)      {         return_value = NUSE_PIPE_EMPTY;      }      else      {                                        /* block task */         NUSE_Pipe_Blocking_Count[pipe]++;         NUSE_Suspend_Task(NUSE_Task_Active, (pipe << 4) |                           NUSE_PIPE_SUSPEND);         return_value =               NUSE_Task_Blocking_Return[NUSE_Task_Active];         if (return_value != NUSE_SUCCESS)         {            suspend = NUSE_NO_SUSPEND;         }      }   }   else   {                                     /* message available */      data = &NUSE_Pipe_Data[pipe][NUSE_Pipe_Tail[pipe]];      for (i=0; i<msgsize; i++)      {         *message++ = *data++;      }      NUSE_Pipe_Tail[pipe] += msgsize;      if (NUSE_Pipe_Tail[pipe] == (NUSE_Pipe_Size[pipe] *                                    msgsize))      {         NUSE_Pipe_Tail[pipe] = 0;      }      NUSE_Pipe_Items[pipe]--;      if (NUSE_Pipe_Blocking_Count[pipe] != 0)      {         U8 index;         /* check whether a task is blocked */                           /* on this pipe */         NUSE_Pipe_Blocking_Count[pipe]--;         for (index=0; index<NUSE_TASK_NUMBER; index++)         {            if ((LONIB(NUSE_Task_Status[index]) ==                  NUSE_PIPE_SUSPEND)                  && (HINIB(NUSE_Task_Status[index]) == pipe))            {               NUSE_Task_Blocking_Return[index] = NUSE_SUCCESS;               NUSE_Wake_Task(index);               break;            }         }      }      *actual_size = msgsize;      return_value = NUSE_SUCCESS;      suspend = NUSE_NO_SUSPEND;   }} while (suspend == NUSE_SUSPEND);

对代码的一些解释可能有用:             

代码包含在do…while循环中,当参数suspend的值为NUSE_suspend时,循环将继续。             

如果管道为空,并且suspend设置为NUSE_NO_suspend,则API调用将以NUSE_pipe_empty退出。如果suspend设置为NUSE_suspend,则任务将被挂起。返回时(即,当任务被唤醒时),如果返回值为NUSE_SUCCESS,表示任务因已发送消息而被唤醒(而不是重置管道),则代码循环返回顶部。             

如果管道包含任何消息,则使用NUSE_pipe_Tail[]索引返回存储的消息,以从管道的数据区域获取消息。检查管道上是否有任何任务被挂起(等待发送)。如果有任务等待,第一个任务被唤醒。suspend变量被设置为NUSE_NO_suspend,API调用将退出并返回NUSE_SUCCESS。             

写在管道前面             

Nucleus RTOS-API调用写入管道的前端非常灵活,允许您无限期地挂起,或者在操作无法立即完成的情况下暂停超时;也就是说,您尝试写入一个完整的管道。Nucleus SE提供相同的服务,除了task suspend是可选的并且不实现timeout。

Nucleus RTOS API Call for Jamming to a Pipe

Service call prototype:

STATUS NU_Send_To_Front_Of_Pipe(NU_PIPE *pipe, VOID *message, 
UNSIGNED size, UNSIGNED suspend);

Parameters:

pipe – pointer to a user-supplied pipe control block
message – a pointer to the message to be sent
size – the number of bytes in the message. If the pipe supports variable-length messages, this parameter must be equal to or less than the message size supported by the pipe. If the pipe supports fixed-size messages, this parameter must be exactly the same as the message size supported by the pipe.
suspend – specification for task suspend; may be NU_NO_SUSPEND or NU_SUSPEND or a timeout value

Returns:

NU_SUCCESS – the call was completed successfully
NU_INVALID_PIPE – the pipe pointer is invalid
NU_INVALID_POINTER – the message pointer is NULL 
NU_INVALID_SIZE – the message size is incompatible with the message size supported by the pipe
NU_INVALID_SUSPEND – suspend was attempted from a non-task thread
NU_PIPE_FULL – the pipe is full and suspend was not specified
NU_TIMEOUT – the pipe is still full even after suspending for the specified timeout value
NU_PIPE_DELETED – the pipe was deleted while the task was suspended
NU_PIPE_RESET – the pipe was reset while the task was suspended

Nucleus SE API Call for Jamming to a Pipe

This API call supports the key functionality of the Nucleus RTOS API.

Service call prototype:

STATUS NUSE_Pipe_Jam(NUSE_PIPE pipe, ADDR *message, 
U8 suspend);

Parameters:

pipe – the index (ID) of the pipe to be utilized
message – a pointer to the message to be sent, which is a sequence of bytes as long as the configured message size of the pipe
suspend – specification for task suspend; may be NUSE_NO_SUSPEND or NUSE_SUSPEND

Returns:

NUSE_SUCCESS – the call was completed successfully
NUSE_INVALID_PIPE – the pipe index is invalid
NUSE_INVALID_POINTER – the message pointer is NULL 
NUSE_INVALID_SUSPEND – suspend was attempted from a non-task thread or when blocking API calls were not enabled
NUSE_PIPE_FULL – the pipe is full and suspend was not specified
NUSE_PIPE_WAS_RESET – the pipe was reset while the task was suspended

Nucleus SE Implementation of Jamming to a Pipe

The bulk of the code of the NUSE_Pipe_Jam() API function is very similar to that of NUSE_Pipe_Send() , except that the data is stored using the NUSE_Pipe_Tail[] index, thus:

if (NUSE_Pipe_Items[pipe] == NUSE_Pipe_Size[pipe])  /* pipe                                                       full */{   return_value = NUSE_PIPE_FULL;}else                                 /* pipe element available */{   if (NUSE_Pipe_Tail[pipe] == 0)   {      NUSE_Pipe_Tail[pipe] = (NUSE_Pipe_Size[pipe] - 1) * msgsize;   }   else   {      NUSE_Pipe_Tail[pipe] -= msgsize;   }   data = &NUSE_Pipe_Data[pipe][NUSE_Pipe_Tail[pipe]];   for (i=0; i<msgsize; i++)   {      *data++ = *message++;   }   NUSE_Pipe_Items[pipe]++;   return_value = NUSE_SUCCESS;}

 

posted @ 2020-07-11 06:11  吴建明wujianming  阅读(308)  评论(0编辑  收藏  举报