⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serialrpc.c

📁 TM1300/PNX1300系列DSP(主要用于视频处理)操作系统pSOS系统的几个demo
💻 C
字号:
/*
 *+-------------------------------------------------------------------+
 *| Copyright (c) 1999,2000 TriMedia Technologies Inc.                |
 *|                                                                   |
 *| This software  is furnished under a license  and may only be used |
 *| and copied in accordance with the terms  and conditions of such a |
 *| license  and with  the inclusion of this  copyright notice.  This |
 *| software or any other copies of this software may not be provided |
 *| or otherwise  made available  to any other person.  The ownership |
 *| and title of this software is not transferred.                    |
 *|                                                                   |
 *| The information  in this software  is subject  to change  without |
 *| any  prior notice  and should not be construed as a commitment by |
 *| TriMedia Technologies.                                            |
 *|                                                                   |
 *| This  code  and  information  is  provided  "as is"  without  any |
 *| warranty of any kind,  either expressed or implied, including but |
 *| not limited  to the implied warranties  of merchantability and/or |
 *| fitness for any particular purpose.                               |
 *+-------------------------------------------------------------------+
 *
 *
 *  Module name              : SerialRPC.c    1.11
 *
 *  Last update              : 10:22:13 - 99/06/14
 *
 *  Title                    : Serial communication driver for ANSI
 *                             I/O, target side
 *
 *  Description              : This file is a serial driver that
 *                             completes the generic serial host
 *                             library that can be used for
 *                             dispatching I/O via a serial form of
 *                             communication to a corresponding rpc
 *                             server. Such a server must have been
 *                             completed with the host counterpar of
 *                             this serial driver.
 *
 *                             This particular serial driver
 *                             communicates with the serial TM-1
 *                             application via tcp/ip, using a socket
 *                             as serial connection. During
 *                             initialization, this driver waits until
 *                             a serving host connects to a server
 *                             port. This port is currently hardcoded
 *                             (see function reader_task_body, below),
 *                             but this is easy to change.
 *
 *                             Starting a TM-1 application and its
 *                             serial server is to be performed using
 *                             the following steps:
 * 
 *                             1) start the TM-1 application. This
 *                             application is to be linked with the
 *                             target counterpart of this serial
 *                             driver, and has to have network access.
 *
 *                             2) start the serial server on a PC or
 *                             Unix machine that can reach the TM-1
 *                             application via tcp/ip. Stdin,
 *                             stdout/stderr of the TM-1 application
 *                             will be mapped to the stdin,
 *                             stdout/stderr of the server process (on
 *                             PC or Unix), and file I/O will be
 *                             effectively performed by this same
 *                             server process.
 *
 *                             This communication driver is
 *                             implemented on top of the pSOS Network
 *                             Architecture component (pNA), and hence
 *                             can *only* be used for psos-based
 *                             applications that have network access.
 *                             
 *                             Apart from this user visible aspect,
 *                             using pNA introduces the following
 *                             complications, which make the target
 *                             driver somewhat more complex than its
 *                             host counterpart:
 *                             	 
 *                             1) I/O initialization, which is
 *                             normally performed at startup of * the
 *                             Trimedia runtime support, has to * be
 *                             postponed until pNA is fully * active.
 *                             That is, in the root task. * This
 *                             postponing is achieved by * disabling
 *                             the standard I/O support * in function
 *                             SerialRPC_init, and * doing the actual
 *                             initialization in a * new function
 *                             SerialRPC_start. * SerialRPC_start is
 *                             to be explicitly * called from the root
 *                             task when it * wants to do I/O, as in
 *                             			  
 *                             		     void root()
 *                             		     {
 *                             		       SerialRPC_start();
 *                             		       ...
 *                             	 
 *                             2) In pSOS/pNA, a socket can only be
 *                             used by the task that created it. For
 *                             other tasks, synonyms have to be
 *                             created by means of function
 *                             shr_socket. For this reason, a reader-
 *                             and a writer task is created to do the
 *                             actual socket communication.
 *                             Application tasks that want to do I/O
 *                             communicate with these tasks using
 *                             message queues.
 *                             	  
 *                             Some implementation notes:
 *
 *                             1) The initialization routine creates
 *                             both queues first, and then both tasks.
 *                             The initialization routine awaits until
 *                             the reader task starts serving; this
 *                             reader task will await the writer task,
 *                             and then create both sockets before it
 *                             releases the initialization routine.
 *                             This synchronization will prevent race
 *                             conditions during startup.
 *
 *                             2) Written data (to the host) is
 *                             accumulated into packets of a specific
 *                             size, when possible. This avoids the
 *                             sending overhead of small data buffers.
 *                             Buffering is done in a buffer
 *                             'mtu_buffer'. The packet size assumes
 *                             ethernet here. Buffering output data
 *                             also keeps the initial endian probe
 *                             message to the host (which is sent
 *                             during RTS initialization) until pNA is
 *                             up and running.
 */

/*--------------------------- Includes ------------------------------*/

#include "errno.h"
#include <stdio.h>
#include "pna.h"
#include "psos.h"
#include <tmlib/tmtypes.h>
#include <assert.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <tmlib/AppSem.h>
#include <tmlib/dprintf.h>

/*
 * Avoid redefinition in fcntl.h
 * (clash with pna definition):
 */
#undef FREAD
#undef FWRITE

#include <fcntl.h>
#include "tmlib/HostCall.h"
#include "tmlib/AppModel.h"

/*--------------------------- Definitions ---------------------------*/

static ULONG reader_task;
static ULONG reader_queue;  /* for sending read requests to reader task */
static Int   reader_socket; /* for actual reading by reader task        */

static ULONG writer_task;
static ULONG writer_queue;  /* for sending write requests to writer task */
static Int   writer_socket; /* for actual writing by writer task         */

#define MTU 1500  /* maximum transmission unit (assumes ethernet connection) */

static Char  mtu_buffer[ MTU ];
static Int   mtu_pos;

static struct _AppSem_Semaphore buffer_lock= _AppSem_INITIALISED_SEM;

#define SYNC_BUFF   0
#define READ_BUFF   1
#define WRITE_BUFF  2

typedef struct {
    Int            kind;
    AppModel_AppId sender;
    Pointer        buffer;
    Int32          size;
} IOMsg;


/*------------------------------- Reading / Writing -----------------*/

/*
 * Wait until the reader or the writer
 * task (depending on the queue) comes up:
 */
static void await_active(ULONG queue)
{
   ULONG m[4];
   IOMsg iomsg;
   
   iomsg.kind   = SYNC_BUFF;
   iomsg.sender = AppModel_current_thread;
    
   m[0]= (ULONG)&iomsg;
   q_send( queue, m );
   AppModel_suspend_self();
}

/*
 * Send a buffer to the writer task,
 * for sending to the host:
 */
static void send_buffer(Pointer buffer, Int32 size)
{
   ULONG m[4];
   IOMsg iomsg;
    
   iomsg.kind   = WRITE_BUFF;
   iomsg.sender = AppModel_current_thread;
   iomsg.buffer = buffer;
   iomsg.size   = size;
    
   m[0]= (ULONG)&iomsg;
   q_send( writer_queue, m );
   AppModel_suspend_self();
}

/*
 * Send all pending output 
 * to the writer task,
 * for sending to the host:
 */
static void sync_buffer()
{
   send_buffer( mtu_buffer, mtu_pos );
    
   mtu_pos = 0;
}

void SerialRPC_write_buffer(Pointer buffer, Int32 size)
{
   AppSem_P(&buffer_lock);

   if (mtu_pos+size <= MTU) {
      memcpy( &mtu_buffer[mtu_pos], buffer, size);
      mtu_pos += size;
   } else if (mtu_pos > 0) {
      Int buffer_space= MTU-mtu_pos;

      memcpy( &mtu_buffer[mtu_pos], buffer, buffer_space);

      send_buffer( mtu_buffer, MTU );
      send_buffer( ((Address)buffer) + buffer_space, size - buffer_space);

      mtu_pos = 0;
   } else {
      send_buffer( buffer, size );
   }

   AppSem_V(&buffer_lock);
}

void SerialRPC_read_buffer(Pointer buffer, Int32 size)
{
   ULONG m[4];
   IOMsg iomsg;
	
   AppSem_P(&buffer_lock);

   if (mtu_pos > 0) { sync_buffer(); }

   AppSem_V(&buffer_lock);

   iomsg.kind   = READ_BUFF;
   iomsg.sender = AppModel_current_thread;
   iomsg.buffer = buffer;
   iomsg.size   = size;
   
   m[0]= (ULONG)&iomsg;
   q_send( reader_queue, m );
   AppModel_suspend_self();
}

/*--------------------------- Initialisation / Termination ----------*/

extern Bool _bypass_rpc_init;

Bool SerialRPC_init( void ) 
{
   _bypass_rpc_init= True;
   return True;
}

static void reader_task_body()
{
   Int                  listener;
   struct sockaddr_in   addr;
   long                 addrlen = sizeof (struct sockaddr_in);
   int                  port    = 3357;

   /* 
    * Wait for connection to the specified port
    * from the serial host, and create reader- 
    * and writer socket:
    */

   addr.sin_family      = AF_INET;
   addr.sin_addr.s_addr = htonl(INADDR_ANY);
   addr.sin_port        = htons(port);

   listener = socket(AF_INET, SOCK_STREAM, 0);
   assert (listener != -1);

   bind(listener, (Pointer)&addr, sizeof (struct sockaddr_in));

   listen(listener, 5);

   reader_socket = accept(listener, (Pointer)&addr, &addrlen);
   assert (reader_socket != -1); 

   closesocket(listener);

   await_active(writer_queue);

   writer_socket= shr_socket( reader_socket, writer_task );
   assert (writer_socket != -1); 

   /*    --.--   */

   /* 
    * Start serving messages:
    */

   while (1) {
      ULONG m[4];
      IOMsg *iomsg;

      q_receive(reader_queue, Q_WAIT, 0, m);
      iomsg= (Pointer)m[0];

      switch (iomsg->kind) {
         case SYNC_BUFF :
            {
               AppModel_resume(iomsg->sender);
               break;
            }

         case READ_BUFF  :
            {
               Address buffer = iomsg->buffer;
               UInt    size   = iomsg->size;

               while (size > 0) {
                  Int s= recv(reader_socket, buffer, size, 0);
                  assert( s > 0 );
                  assert( s <= size );
                  buffer += s;
                  size   -= s;
               }
               
               AppModel_resume(iomsg->sender);
               break;
            }
         
         default : assert(False);
      }
   };
}

static void writer_task_body()
{
   while (1) {
      ULONG m[4];
      IOMsg *iomsg;
      
      q_receive(writer_queue, Q_WAIT, 0, m);
      iomsg = (Pointer) m [0];
      
      switch (iomsg->kind) {
         case SYNC_BUFF:
            AppModel_resume(iomsg->sender);
         break;
         
         case WRITE_BUFF:
         {
            Address buffer = iomsg->buffer;
            UInt    size   = iomsg->size;
            Int     s;

            while (size > 0) {
               DP (("send (%d, 0x%X, %d, 0)\n", writer_socket,
                     buffer, size));
               s = send(writer_socket, buffer, size, 0);
               DP (("s %d\n", s));
               assert( s > 0 );
               assert( s <= size );
               buffer += s;
               size   -= s;
            }
               
            AppModel_resume(iomsg->sender);
         }
         break;
         
         default:
            assert(False);
      }
   };
}

void SerialRPC_start()
{
   if ( q_create("rdrq", 0, Q_LOCAL | Q_FIFO | Q_NOLIMIT, &reader_queue)
         || q_create("wrtq", 0, Q_LOCAL | Q_FIFO | Q_NOLIMIT, &writer_queue)
         || t_create("rdrt", 200, 0x10000, 0x10000, 0, &reader_task)
         || t_create("wrtt", 200, 0x10000, 0x10000, 0, &writer_task)
         || t_start(reader_task, T_PREEMPT | T_TSLICE | T_ASR | T_ISR, reader_task_body, 0)
         || t_start(writer_task, T_PREEMPT | T_TSLICE | T_ASR | T_ISR, writer_task_body, 0)
) {
      /* trouble */
   } else {
      await_active(reader_queue);
      
      _open(TCS_STDIN_NAME,  O_RDONLY,                     0666);
      _open(TCS_STDOUT_NAME, O_WRONLY | O_CREAT | O_TRUNC, 0666);
      _open(TCS_STDERR_NAME, O_WRONLY | O_CREAT | O_TRUNC, 0666);
   }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -