RTLAB异步通信中AsuncIP.c 的注释

/*-------------------------------------------------------------------

 *一个异步通信案例, 
  *-----------------------------------------------------------------*/
#ifndef WIN32
#define PROGNAME "AsyncIP"

// Standard ANSI C headers needed for this program
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <termios.h>
#include <unistd.h>

#if defined(__QNXNTO__)
#       include <process.h>
#       include <sys/sched.h>
#       include <pthread.h>
#       include <devctl.h>
#       include <sys/dcmd_chr.h>
#elif defined(__linux__)
#       define _GNU_SOURCE   1
#       include <sched.h>
#   if defined(__redhawk__)
#       include <cpuset.h>
#       include <mpadvise.h>
#   endif
#endif

// Define RTLAB before including OpalPrint.h for messages to be sent
// to the OpalDisplay. Otherwise stdout will be used.
#define RTLAB
#include "OpalPrint.h"
#include "AsyncApi.h"
#include "AsyncIPUtils.h"

// This is just for initializing the shared memory access to communicate
// with the RT-LAB model. It's easier to remember the arguments like this
#define ASYNC_SHMEM_NAME argv[1]
#define ASYNC_SHMEM_SIZE atoi(argv[2])
#define PRINT_SHMEM_NAME argv[3]

// This defines the maximum number of signals (doubles) that can be sent
// or received by any individual Send or Recv block in the model. This
// only applies to the "model <-> asynchronous process" communication.
#define MAXSENDSIZE 64
#define MAXRECVSIZE 64

// Set the stack size of each thread.
#define STACKSIZE 4096

//通过 #pragma pack(1)和#pragma pack()对 来使用最小的内存保存data_out和data_in结构体
#pragma pack(1) //变量以一个字节对齐。变量紧缩
struct data_out//定义输出数据结构。
{
  short  dev_id;             // (2 bytes) Sender device ID
  int    msg_id;             // (4 bytes) Message ID
  short  msg_len;            // (2 bytes) Message length (data only)
  double data[MAXSENDSIZE];  // Up to MAXSENDSIZE doubles (8 bytes each)
};
//
struct data_in  //定义输入数据结构。
{
  short  dev_id;             // (2 bytes) Sender device ID
  int    msg_id;             // (4 bytes) Message ID
  short  msg_len;            // (2 bytes) Message length (data only)
  double data[MAXRECVSIZE];  // Up to MAXRECVSIZE doubles (8 bytes each)
};

#pragma pack()//返回标准的内存分配模式

volatile int thread_count = 0;

/************************************************************************/
int AssignProcToCpu0(void)
{
#if defined(__linux__)
#   if defined(__redhawk__)
    int             rc;
    pid_t           pid = getpid();
    cpuset_t        *pCpuset;

    pCpuset = cpuset_alloc();
    if (NULL == pCpuset)
    {
        fprintf(stderr, "Error allocating a cpuset\n");
        return(ENOMEM);
    }
    cpuset_init(pCpuset);
    cpuset_set_cpu(pCpuset, 0, 1);
    rc = mpadvise(MPA_PRC_SETBIAS, MPA_TID, pid, pCpuset);
    if (MPA_FAILURE == rc)
    {
        rc = errno;
        fprintf(stderr, "Error from mpadvise, %d %s, for pid %d\n", errno, strerror(errno), pid);
        cpuset_free(pCpuset);
        return(rc);
    }
    cpuset_free(pCpuset);
    return EOK;
#   else
    cpu_set_t bindSet;
    CPU_ZERO( &bindSet );
    CPU_SET( 0, &bindSet );
    /* changing process cpu affinity */
    if ( sched_setaffinity( 0, sizeof(cpu_set_t), &bindSet ) != 0 )
    {
        (int) fprintf(stderr, "Unable to bind the process to cpu 0. (sched_setaffinity errno %d)\n", errno );
        return EINVAL;
    }
    return EOK;
#   endif
#endif  // __linux__
}
/************************************************************************/

/*******    将数据发送到IP端口  ********************************************/
void *SendToIPPort (void * arg)
{
  unsigned int    SendID = 1;
  int    i,n;
  int    nbSend = 0;
  int    ModelState;

  double mdldata[MAXSENDSIZE];
  int    mdldata_size;
  struct data_out comdata;
  int    comdata_size;
  int   count = 0;

  OpalPrint("%s: SendToIPPort thread started\n", PROGNAME);

  OpalGetNbAsyncSendIcon(&nbSend);  //获得发送控制器的编号

  //王加
  OpalPrint("output ndSend%d\n", nbSend);

  if(nbSend >= 1)//大于等于1 则有数据需要被发送
    {
      do
    {
      // This call unblocks when the 'Data Ready' line of a send icon is asserted.
        //正常情况下,该if语句没有作用。
      if((n = OpalWaitForAsyncSendRequest (&SendID)) != EOK)    //若n!=EOK ,则 没有发送请求。
        {                                                       //SendID中保存 发起 发送请求的 控制器编号
            //当没有发送请求时,
          ModelState = OpalGetAsyncModelState();    //读取模型运行状态
          if ((ModelState != STATE_RESET) && (ModelState != STATE_STOP))//如果模型不是重置或停止状态
        {
          OpalSetAsyncSendIconError(n, SendID); //向 发起发送请求的控制器 返回错误信息:ENODEV    No send icon registered.
          OpalPrint("%s: OpalWaitForAsyncSendRequest(), errno %d\n", PROGNAME, n);
        }
          continue;
        }

      // 当没有遇到错误时,
      OpalSetAsyncSendIconError(0, SendID);  // 向SendID 发送错误信息:0.即没有错误

      OpalGetAsyncSendIconDataLength (&mdldata_size, SendID);// 获得由Send ID发送的数据的长度
      OpalPrint("output mdldata_size%d\n", mdldata_size);//在rtlab界面打印处数据长度。

      if (mdldata_size/sizeof(double) > MAXSENDSIZE)//如果数据长度超过了最大数据长度
        {
          OpalPrint("%s: Number of signals for SendID=%d exceeds allowed maximum (%d)\n", PROGNAME, SendID, MAXSENDSIZE);
          return NULL;
        }

      // 从模型的发送模块编号为SendID的模块中读取数据  (从共享内存中读取数据)
      OpalGetAsyncSendIconData (mdldata, mdldata_size, SendID);
//----------------数据修改~-------------
// ****** 定义数据包的封装格式 ******************************
// 根据需要,修改本部分内容。如数据类型。 

      comdata.dev_id  = SendID;  // Use the SendID as a device ID here
      comdata.msg_id++;          // The message ID is just incremented
      comdata.msg_len = mdldata_size;
//    comdata.msg_len = (mdldata_size/sizeof(double)) * sizeof(int); // 如果 comdata.data 是 "int" 型的  
// 在本例中,因为数据包中的数据是double格式的,因此不需要类型转换

      for (i=0; i < (mdldata_size / sizeof(double)); i++)
        comdata.data[i] = mdldata[i];
//      comdata.data[i] = (int)mdldata[i]; // If comdata.data was an "int"

      comdata_size = 8 + comdata.msg_len;//若发送数据的长度是变化的
//    comdata_size = sizeof(comdata);   // 对于固定长度的数据包
// **********************************************************************

      //  把数据发送到 IP端口
      if (SendPacket((char*)&comdata, comdata_size) < 0)
        OpalSetAsyncSendIconError  (errno, SendID); //向 SendID端口 发送 错误信息:errno
      else
        OpalSetAsyncSendIconError  (0, SendID);

      //下一个函数可以将异步过程变为同步过程。
      //为此,必须将model发送模块中的“Sending Mode”修改为NEED_REPLY_BEFORE_NEXT_SEND或NEED_REPLY_NOW
      //这会迫使model停下来等待OpalAsyncSendRequestDone函数执行完毕
      OpalAsyncSendRequestDone (SendID);//对提起发送请求模块的回复

      // 进行下一个步骤之前 确认模型没有停止运行
      ModelState = OpalGetAsyncModelState();
    } while ((ModelState != STATE_RESET) && (ModelState != STATE_STOP));
    //当模型停止或重置时,跳出while循环
      OpalPrint("%s: SendToIPPort: Finished\n", PROGNAME);//发送终止
    }

  else //当没有数据需要发送时
    {
      OpalPrint("%s: SendToIPPort: No transimission block for this controller. Stopping thread.\n", PROGNAME);
      //输出: 没有发送模块
    }

  thread_count--;
  return NULL;
}


/*****************  从IP端口接收数据  ***********************************/
void *RecvFromIPPort (void * arg)
{
  int    RecvID = 1;
  int    i, n1, n2, nt, n;
  int    nbRecv = 0;
  int    ModelState;

  double mdldata[MAXRECVSIZE];
  int    mdldata_size;
  struct data_in comdata;
  int    comdata_size;

  OpalPrint("%s: RecvFromIPPort thread started\n", PROGNAME);
  //开始接收数据
  OpalGetNbAsyncRecvIcon(&nbRecv); //解析 接收模块的编号

  if(nbRecv >= 1)   //如果存在模块需要接收数据
    {
      do
    {
      memset (&comdata, 0, sizeof(comdata));//对结构体清零

// ****** FORMAT TO SPECIFIC PROTOCOL HERE ******************************
//
// 当需要接收不止一个数据包时,修改此处代码。
      comdata_size = sizeof(comdata);
      n  = RecvPacket((char*)&comdata, comdata_size, 1.0);
      nt = n;

// 在本例中,接收到的数据长度是可变的。如果数据长度是固定的,可以删去下面这条语句
      comdata_size = 8 + comdata.msg_len;//该语句是否有问题。应该改为下行代码????????
      //comdata_size = 8 + comdata_size;//2018.3.13
// **********************************************************************

      if (n < 1)//没有接收到数据
        {
          ModelState = OpalGetAsyncModelState(); // 获取模型状态
          if ((ModelState != STATE_RESET) && (ModelState != STATE_STOP))
        {
          // n ==  0 意味着超时,所以继续即可
          //if (n == 0)
          // OpalPrint("%s: Timeout while waiting for data\n", PROGNAME, errno);
          // n == -1 意味着有严重的错误。
          if (n == -1)
            OpalPrint("%s: Error %d while waiting for data\n", PROGNAME, errno);
          continue;
        }
          break;
        }
      else if (nt != comdata_size)//如果nt和数据长度不等
        {
          // Disable this print. It may happen in TCP/IP mode. The server needs to be modified to check packet size.
          // OpalPrint("%s: Received incoherent packet (size: %d, complete: %d)\n", PROGNAME, nt, comdata_size);
          continue;
        }

// ****** FORMAT TO SPECIFIC PROTOCOL HERE ******************************
// 根据需要,修改本部分内容。如数据类型。 

      RecvID = comdata.dev_id;                             // Use the deviceID as the RecvID
      OpalSetAsyncRecvIconStatus(comdata.msg_id, RecvID); // Set the Status to the message ID
      OpalSetAsyncRecvIconError(0, RecvID);              // Set the Error to 0

      // Get the number of signals to send back to the model
      OpalGetAsyncRecvIconDataLength (&mdldata_size, RecvID);//获得 RecvID模块中定义的接收数据的长度
      //上句是什么意思????????
      if (mdldata_size/sizeof(double) > MAXRECVSIZE)
        {
          OpalPrint("%s: Number of signals for RecvID=%d (%d) exceeds allowed maximum (%d)\n", PROGNAME, RecvID, mdldata_size/sizeof(double), MAXRECVSIZE);
          return NULL;
        }
      if (mdldata_size > comdata.msg_len)
//        if (mdldata_size/sizeof(double) > comdata.msg_len/sizeof(int)) // If comdata.data was an "int"
        {
          OpalPrint("%s: Number of signals for RecvID=%d (%d) exceeds what was received (%d)\n", PROGNAME, RecvID, mdldata_size/sizeof(double), comdata.msg_len/sizeof(double));
        }

      for (i=0; i < (mdldata_size / sizeof(double)); i++)
        mdldata[i] = (double)comdata.data[i]; // 
// **********************************************************************

      OpalSetAsyncRecvIconData   (mdldata, mdldata_size, RecvID);//设定接收模块要接收的数据

      // Before continuing, we make sure that the real-time model
      // has not been stopped. If it has, we quit.
      ModelState = OpalGetAsyncModelState();
    } while ((ModelState != STATE_RESET) && (ModelState != STATE_STOP));

      OpalPrint("%s: RecvFromIPPort: Finished\n", PROGNAME);
    }

  else
    {
      OpalPrint("%s: RecvFromIPPort: No reception block for this controller. Stopping thread.\n", PROGNAME);
    }

  thread_count--;
  return NULL;
}
/************************************************************************/

/************************************************************************/
int main (int argc, char *argv[]) 
{
  Opal_GenAsyncParam_Ctrl IconCtrlStruct;
  int                     err;
  pthread_t               tid_send,  tid_recv;
  pthread_attr_t          attr_send, attr_recv;

  // Check for the proper arguments to the program
  if (argc < 4)
    {
      printf("Invalid Arguments: 1-AsyncShmemName 2-AsyncShmemSize 3-PrintShmemName\n");
      exit(0);
    }

/*王添加*/ 
 for( int argNum = 0; argNum < argc; argNum++ )
  {
      printf("%d -> %s\n", argNum, argv[argNum]);
      OpalPrint("%d -> %s\n", argNum, argv[argNum]);
  }
 ///-------接下来一段不用改动

  // Enable the OpalPrint function. This prints to the OpalDisplay.
  if (OpalSystemCtrl_Register(PRINT_SHMEM_NAME) != EOK)
    {
      printf("%s: ERROR: OpalPrint() access not available\n", PROGNAME);
      exit(-1); 
    }

  // 开辟共享内存 -----------------------
  if((OpalOpenAsyncMem (ASYNC_SHMEM_SIZE, ASYNC_SHMEM_NAME)) != EOK)
    {
      OpalPrint("%s: ERROR: Model shared memory not available\n", PROGNAME);
      exit(-1);
    }

  // For Redhawk, Assign this process to CPU 0 in order to support partial XHP
  AssignProcToCpu0();  

  // Get IP Controler Parameters (ie: ip address, port number...) and
  // initialize the device on the QNX node.
  memset(&IconCtrlStruct, 0, sizeof(IconCtrlStruct));
  if((err = OpalGetAsyncCtrlParameters(&IconCtrlStruct, sizeof(IconCtrlStruct))) != EOK)
    {
      OpalPrint("%s: ERROR: Could not get controller parameters (%d).\n", PROGNAME, err);
      exit(-1);
    }
  if(InitSocket (IconCtrlStruct) != EOK)
    {
      OpalPrint("%s: ERROR: Initialization failed.\n", PROGNAME);
      exit(-1);
    }
  //以上代码不用改动
//---------------开始传输---------
  thread_count++;
  pthread_attr_init (&attr_send);
  //pthread_attr_setstacksize (&attr_send, STACKSIZE); // Has been known to crash the application
  if ((pthread_create (&tid_send, &attr_send, SendToIPPort, NULL)) == -1)
    {
      OpalPrint("%s: ERROR: Could not create thread (SendToIPPort), errno %d\n", PROGNAME, errno);
      thread_count--;
    }


  // Start reception thread -----------------------------------------
  thread_count++;
  pthread_attr_init (&attr_recv);
  //pthread_attr_setstacksize (&attr_recv, STACKSIZE); // Has been known to crash the application
  if ((pthread_create (&tid_recv, &attr_recv, RecvFromIPPort, NULL)) == -1)
    {
      OpalPrint("%s: ERROR: Could not create thread (RecvFromIPPort), errno %d\n", PROGNAME, errno);
      thread_count--;
    }

  // Wait for both threads to finish --------------------------------
  if ((err = pthread_join (tid_send, NULL)) != 0)
    { OpalPrint("%s: ERROR: pthread_join (SendToIPPort), errno %d\n", PROGNAME, err); }
  if ((err = pthread_join (tid_recv, NULL)) != 0)
    { OpalPrint("%s: ERROR: pthread_join (RecvFromIPPort), errno %d\n", PROGNAME, err); }

  // Close the ip port and shared memories ----------------------
  CloseSocket (IconCtrlStruct);
  OpalCloseAsyncMem (ASYNC_SHMEM_SIZE,ASYNC_SHMEM_NAME);
  OpalSystemCtrl_UnRegister(PRINT_SHMEM_NAME);

  return(0);
}
/************************************************************************/
#endif
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
rtlab是一个用于实时仿真和测试的软件平台。rtlab提供了一个开放式的、易于使用的环境,使用户能够进行复杂的系统仿真、开发和调试。 rtlab使用说明书主要包括以下内容: 1. 安装和配置:rtlab的安装和配置很简单,用户只需要按照说明书的步骤进行操作即可完成安装。同时,还需要根据实际需求进行配置,如选择和设置硬件接口等。 2. 建模和仿真:rtlab提供了丰富的建模和仿真工具,用户可以使用这些工具来建立系统模型,并进行实时仿真。通过这些工具,用户可以模拟复杂的物理系统,并观察系统的行为和性能。 3. 开发和调试:rtlab支持多种编程语言和开发环境,用户可以使用自己熟悉的语言和工具开发自己的应用程序。同时,rtlab还提供了调试工具,用户可以使用这些工具来调试代码和跟踪程序的执行过程。 4. 测试和验证:rtlab提供了一系列的测试和验证工具,用户可以使用这些工具来测试系统的性能和功能,并验证系统是否满足设计要求。通过这些工具,可以提前发现系统的潜在问题,并进行优化和改进。 5. 文档和教程rtlab提供了详细的文档和教程,用户可以根据自己的需要学习和了解rtlab的各种功能和特性。同时,还可以参考这些文档和教程进行实际操作,以便更好地使用rtlab进行实时仿真和测试。 综上所述,rtlab使用说明书提供了关于rtlab软件平台安装、配置、建模、仿真、开发、调试、测试、验证等方面的详细指导,帮助用户快速上手并有效地使用rtlab进行实时仿真和测试。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值