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

📄 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.13
 *
 *  Last update              : 14:58:04 - 00/06/19
 *
 *  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>

/*
 * 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;

			while (size > 0) {
				Int s= send(writer_socket, buffer, size, 0);
				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 + -