synthetic serial driver

Savin Zlobec savin@torina.fe.uni-lj.si
Tue Aug 5 13:44:00 GMT 2003


On Tue, 5 Aug 2003, Andrew Lunn wrote:

> On Tue, Aug 05, 2003 at 12:10:27AM +0200, Savin Zlobec wrote:
> > Hi!
> >
> > I've already mailed my assignment a week ago. But I guess
> > that mail needs about two weeks from here to US.
>
> Thats great. Thanks
>
> >
> > The code wich uses a buffer to fetch charachters
> > from auxiliary is based on code send to me from
> > Philippe Moutarlier - but I rewrote and modified
> > it so there is little of original code left.
> >
> > I can post here the diffs of Philippe's changes if it
> > is of any help.
>
> Yes please.
>
>     Andrew
>

I've attached my old sources and diffs of Philippe's changes.

savin
-------------- next part --------------
A non-text attachment was scrubbed...
Name: serial.tcl
Type: application/x-tcl
Size: 5437 bytes
Desc: 
URL: <http://sourceware.org/pipermail/ecos-devel/attachments/20030805/0737abd8/attachment.tcl>
-------------- next part --------------
//==========================================================================
//
//      synthserial.c
//
//      Serial device driver for the synthetic target 
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 2003 Savin Zlobec.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):    savin
// Contributors: 
// Date:         2003-03-27
//
//####DESCRIPTIONEND####
//
//==========================================================================

#include <pkgconf/devs_serial_ecosynth.h>

#include <cyg/infra/cyg_type.h>
#include <cyg/infra/cyg_ass.h>
#include <cyg/infra/diag.h>
#include <cyg/hal/hal_arch.h>
#include <cyg/hal/hal_io.h>
#include <cyg/hal/drv_api.h>
#include <cyg/io/io.h>
#include <cyg/io/devtab.h>
#include <cyg/io/serial.h>

// Protocol between this driver and the auxiliary
#define SYNTH_SERIAL_TX        0x01 // send char 
#define SYNTH_SERIAL_RX        0x02 // receive char
#define SYNTH_SERIAL_GETPARAMS 0x03 // get init parameters

typedef struct synth_serial_info {
    int           synth_id;         // Device id within the auxiliary
    cyg_vector_t  interrupt;        // Interrupt number allocated by the auxiliary
    cyg_handle_t  interrupt_handle; // Interrupt handle  
    cyg_interrupt interrupt_data;   // Interrupt data
} synth_serial_info;

static bool          synth_serial_init(struct cyg_devtab_entry *tab);
static bool          synth_serial_putc(serial_channel *chan, unsigned char c);
static Cyg_ErrNo     synth_serial_lookup(struct cyg_devtab_entry **tab, 
                                         struct cyg_devtab_entry  *sub_tab,
                                         const char               *name);
static unsigned char synth_serial_getc(serial_channel *chan);
static Cyg_ErrNo     synth_serial_set_config(serial_channel *chan, 
                                             cyg_uint32      key,
                                             const void     *xbuf, 
                                             cyg_uint32     *len);
static void          synth_serial_start_xmit(serial_channel *chan);
static void          synth_serial_stop_xmit(serial_channel *chan);
static cyg_uint32    synth_serial_ISR(cyg_vector_t   vector, 
                                      cyg_addrword_t data);
static void          synth_serial_DSR(cyg_vector_t   vector, 
                                      cyg_ucount32   count, 
                                      cyg_addrword_t data);

static SERIAL_FUNS(synth_serial_funs, 
                   synth_serial_putc, 
                   synth_serial_getc,
                   synth_serial_set_config,
                   synth_serial_start_xmit,
                   synth_serial_stop_xmit
);

#define SYNTH_SERIAL_INSTANCE(_number_)                                    \
static synth_serial_info synth_serial_info##_number_ = {                   \
    synth_id:          -1,                                                 \
    interrupt:          0,                                                 \
    interrupt_handle:   0                                                  \
};                                                                         \
static unsigned char synth_serial_out_buf##_number_[CYGNUM_IO_SERIAL_ECOSYNTH_SERIAL##_number_##_BUFSIZE]; \
static unsigned char synth_serial_in_buf##_number_[CYGNUM_IO_SERIAL_ECOSYNTH_SERIAL##_number_##_BUFSIZE];  \
static SERIAL_CHANNEL_USING_INTERRUPTS(synth_serial_channel##_number_,     \
                                       synth_serial_funs,                  \
                                       synth_serial_info##_number_,        \
                                       CYGNUM_SERIAL_BAUD_MIN,             \
                                       CYG_SERIAL_STOP_DEFAULT,            \
                                       CYG_SERIAL_PARITY_DEFAULT,          \
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,     \
                                       CYG_SERIAL_FLAGS_DEFAULT,           \
                                       &synth_serial_out_buf##_number_[0], sizeof(synth_serial_out_buf##_number_), \
                                       &synth_serial_in_buf##_number_[0], sizeof(synth_serial_in_buf##_number_) \
);                                                                         \
DEVTAB_ENTRY(synth_serial_io##_number_,                                    \
             CYGDAT_IO_SERIAL_ECOSYNTH_SERIAL##_number_##_NAME,            \
             0,                                                            \
             &cyg_io_serial_devio,                                         \
             synth_serial_init,                                            \
             synth_serial_lookup,                                          \
             &synth_serial_channel##_number_                               \
);

#ifdef CYGVAR_DEVS_SERIAL_ECOSYNTH_SERIAL0
SYNTH_SERIAL_INSTANCE(0);
#endif

static bool 
synth_serial_init(struct cyg_devtab_entry *tab)
{
    bool result = false;
    serial_channel *chan = (serial_channel *)tab->priv;
    synth_serial_info *synth_info = (synth_serial_info *)chan->dev_priv;

    if (synth_auxiliary_running) {
        synth_info->synth_id = 
            synth_auxiliary_instantiate("devs/serial/synth/ecosynth", 
                SYNTH_MAKESTRING(CYGPKG_DEVS_SERIAL_ECOSYNTH), 
                "serial", tab->name, (const char*) 0); 

        if (-1 != synth_info->synth_id) {
            result = true;
            synth_auxiliary_xchgmsg(synth_info->synth_id, 
                                    SYNTH_SERIAL_GETPARAMS, 0, 0, 0, 0,
                                    &(synth_info->interrupt), 0, 0, 0);

            cyg_drv_interrupt_create(synth_info->interrupt,
                                     0,
                                     (CYG_ADDRWORD)chan,
                                     &synth_serial_ISR,
                                     &synth_serial_DSR,
                                     &(synth_info->interrupt_handle),
                                     &(synth_info->interrupt_data));
            cyg_drv_interrupt_attach(synth_info->interrupt_handle);
            cyg_drv_interrupt_unmask(synth_info->interrupt);
        }
    }
    (chan->callbacks->serial_init)(chan);  
    return result;
}

static Cyg_ErrNo 
synth_serial_lookup(struct cyg_devtab_entry **tab, 
                    struct cyg_devtab_entry *sub_tab,
                    const char *name)
{
    serial_channel *chan = (serial_channel *)(*tab)->priv;
    (chan->callbacks->serial_init)(chan);
    return ENOERR;
}

static bool
synth_serial_putc(serial_channel *chan, unsigned char c)
{
    synth_serial_info *synth_info = (synth_serial_info *)chan->dev_priv;

    if (-1 != synth_info->synth_id) {
        synth_auxiliary_xchgmsg(synth_info->synth_id, SYNTH_SERIAL_TX, 0, 0,
                                &c, 1, 0, 0, 0, 0);
        return true;
    }
    return false;
}

static unsigned char 
synth_serial_getc(serial_channel *chan)
{
    synth_serial_info *synth_info = (synth_serial_info *)chan->dev_priv;

    if (-1 != synth_info->synth_id) {
        char c;
        int  l;
        do {
            synth_auxiliary_xchgmsg(synth_info->synth_id, SYNTH_SERIAL_RX, 0, 0,
                                    0, 0, &l, &c, 0, 1);
        } while (l < 0);
        return c;
    }   
    return 0; 
}

static Cyg_ErrNo
synth_serial_set_config(serial_channel *chan, cyg_uint32 key,
                         const void *xbuf, cyg_uint32 *len)
{
    switch (key) {
    case CYG_IO_SET_CONFIG_SERIAL_INFO:
      {
        if ( *len < sizeof(cyg_serial_info_t) ) {
            return -EINVAL;
        }
        *len = sizeof(cyg_serial_info_t);
        return ENOERR;
      }
      break;
    default:
        return -EINVAL;
    }
    return ENOERR;
}

static void
synth_serial_start_xmit(serial_channel *chan)
{
    (chan->callbacks->xmt_char)(chan);
}

static void 
synth_serial_stop_xmit(serial_channel *chan)
{
}

static cyg_uint32 
synth_serial_ISR(cyg_vector_t vector, cyg_addrword_t data)
{
    cyg_drv_interrupt_mask(vector);
    cyg_drv_interrupt_acknowledge(vector);
    return CYG_ISR_CALL_DSR;
}

static void       
synth_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
{
    serial_channel *chan = (serial_channel *)data;
    synth_serial_info *synth_info = (synth_serial_info *)chan->dev_priv;

    if (-1 != synth_info->synth_id) {
        char c;
        int  l;
        synth_auxiliary_xchgmsg(synth_info->synth_id, SYNTH_SERIAL_RX, 0, 0,
                                0, 0, &l, &c, 0, 1);
        (chan->callbacks->rcv_char)(chan, c);
    }
    cyg_drv_interrupt_unmask(vector);
}

// ----------------------------------------------------------------------------
// EOF synthserial.c
-------------- next part --------------
--- serial.tcl.orig	Wed May  7 18:26:24 2003
+++ serial.tcl	Sat Aug  2 14:20:41 2003
@@ -52,25 +52,34 @@
     # The protocol between eCos and this script.
     variable SYNTH_SERIAL_TX        0x01
     variable SYNTH_SERIAL_RX        0x02
     variable SYNTH_SERIAL_GETPARAMS 0x03
     
+    
     # This array holds all the interesting data for all the
     # interfaces, indexed by the instance id. It is also useful
     # to keep track of the instance id's associated with serial 
     # devices.
     array set data [list]
     set ids [list]
-
+    set baudRate 115200
     # -------------------------------------------------------------------------
 
     proc instantiate { id name data } {
 
         # open pty and init input handler 
-        # FIXME: hardcoded file name 
-        set fid [open "loop1" "r+"]
-        fconfigure $fid -translation binary -encoding binary -buffering none
+	puts "serial name : $name" 
+	if { [string equal -length -1 $name "/dev/ser0"] } {
+	    set serial_dev "/dev/ttyS0"
+	    set fid [open "/dev/ttyS0" "r+"]
+	} else {
+	    return ""
+	}
+        fconfigure $fid -blocking 0 -translation binary -encoding binary -buffering none \
+	    -mode $serial::baudRate,n,8,1
+	exec -- stty -F $serial_dev crtscts 
+
         fileevent $fid readable [list serial::handle_input $id]
         
         # allocate an interrupt vector
         set vector [synth::interrupt_allocate $name]
         if { -1 == $vector } {
@@ -96,17 +105,28 @@
 #            puts "Put char '$reqdata'"
             puts -nonewline $serial::data($id,fid) $reqdata  
         } elseif { $reqcode == $serial::SYNTH_SERIAL_RX } {
             set len [llength $serial::data($id,in_buff)]
             if { $len == 0 } {
-                synth::send_reply -1 1 0
+		synth::send_reply -1 1 0
             } else {
-                set replay [binary format "a" \
-                    [lindex $serial::data($id,in_buff) 0]]
-                set serial::data($id,in_buff) \
-                    [lrange $serial::data($id,in_buff) 1 $len]
-                synth::send_reply [expr $len - 1] 1 $replay
+		if { $len >= $reply_len } {
+		    set slen $reply_len
+		} else {
+		    set slen $len
+		}
+		#puts "len $slen"
+		
+		for { set i 0 } { $i < $slen } { incr i } {		    
+		    append replay [lindex $serial::data($id,in_buff) $i] 
+		}
+		
+		#set replay [lrange $serial::data($id,in_buff) 0 [expr $len - 1]]
+		set serial::data($id,in_buff) \
+                    [lrange $serial::data($id,in_buff) $slen [expr $len - 1]]
+                synth::send_reply [expr $len - $slen] $slen $replay
+		#puts "replay $slen $replay"
             }
         } elseif { $reqcode == $serial::SYNTH_SERIAL_GETPARAMS } {
             synth::send_reply $serial::data($id,int_vector) 0 ""
         } else {
             synth::report_error "Received unexpected request $reqcode for serial device"
@@ -114,14 +134,25 @@
     }
 
     # -------------------------------------------------------------------------
  
     proc handle_input { id } {
-        set ch [read $serial::data($id,fid) 1]
-#        puts "Got char '$ch'"
-        lappend serial::data($id,in_buff) $ch
-        synth::interrupt_raise $serial::data($id,int_vector)
+	set len [llength $serial::data($id,in_buff)]
+	if { $len <  80 } {
+	    set ch [read $serial::data($id,fid) 1]
+	    #        puts "Got char '$ch'"
+	    set blocked [fblocked $serial::data($id,fid)]
+	    if { $blocked == 0 } {
+		lappend serial::data($id,in_buff) $ch
+		
+	    }    
+	} 
+#elseif { $len == 80 } {
+	#    puts "getting full !"
+	 #   flush stdout
+#	}
+	synth::interrupt_raise $serial::data($id,int_vector)
     }
  
     # -------------------------------------------------------------------------
 
     proc ecos_exited { arg_list } {
-------------- next part --------------
--- synthserial.c.orig	Wed May  7 18:29:37 2003
+++ synthserial.c	Sat Aug  2 14:20:45 2003
@@ -35,10 +35,14 @@
 //
 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
 // at http://sources.redhat.com/ecos/ecos-license/
 // -------------------------------------------
 //####ECOSGPLCOPYRIGHTEND####
+
+//Updated by Philippe Moutarlier at Alliant Networks to cover 
+//interrupt misses.
+
 //==========================================================================
 //#####DESCRIPTIONBEGIN####
 //
 // Author(s):    savin
 // Contributors: 
@@ -68,10 +72,11 @@
 typedef struct synth_serial_info {
     int           synth_id;         // Device id within the auxiliary
     cyg_vector_t  interrupt;        // Interrupt number allocated by the auxiliary
     cyg_handle_t  interrupt_handle; // Interrupt handle  
     cyg_interrupt interrupt_data;   // Interrupt data
+  char is_throttled;
 } synth_serial_info;
 
 static bool          synth_serial_init(struct cyg_devtab_entry *tab);
 static bool          synth_serial_putc(serial_channel *chan, unsigned char c);
 static Cyg_ErrNo     synth_serial_lookup(struct cyg_devtab_entry **tab, 
@@ -143,10 +148,11 @@
                 SYNTH_MAKESTRING(CYGPKG_DEVS_SERIAL_ECOSYNTH), 
                 "serial", tab->name, (const char*) 0); 
 
         if (-1 != synth_info->synth_id) {
             result = true;
+	    synth_info->is_throttled = 0;
             synth_auxiliary_xchgmsg(synth_info->synth_id, 
                                     SYNTH_SERIAL_GETPARAMS, 0, 0, 0, 0,
                                     &(synth_info->interrupt), 0, 0, 0);
 
             cyg_drv_interrupt_create(synth_info->interrupt,
@@ -206,24 +212,41 @@
 
 static Cyg_ErrNo
 synth_serial_set_config(serial_channel *chan, cyg_uint32 key,
                          const void *xbuf, cyg_uint32 *len)
 {
-    switch (key) {
-    case CYG_IO_SET_CONFIG_SERIAL_INFO:
-      {
-        if ( *len < sizeof(cyg_serial_info_t) ) {
-            return -EINVAL;
-        }
-        *len = sizeof(cyg_serial_info_t);
-        return ENOERR;
+  long f; 
+  synth_serial_info *synth_info = (synth_serial_info *)chan->dev_priv;
+  switch (key) {
+  case CYG_IO_SET_CONFIG_SERIAL_INFO:
+    {
+      if ( *len < sizeof(cyg_serial_info_t) ) {
+	return -EINVAL;
       }
-      break;
-    default:
-        return -EINVAL;
+      *len = sizeof(cyg_serial_info_t);
+      return ENOERR;
     }
-    return ENOERR;
+    break;
+  case CYG_IO_SET_CONFIG_SERIAL_HW_RX_FLOW_THROTTLE:
+    {
+      f = *(long *)xbuf;
+      if(f){
+	synth_info->is_throttled = 1;
+	//diag_printf("throttled\n");
+	cyg_drv_interrupt_mask(synth_info->interrupt);
+      }
+      else{
+	synth_info->is_throttled = 0;
+	//diag_printf("started\n");
+	cyg_drv_interrupt_unmask(synth_info->interrupt);
+      }
+    }
+    break;
+  default:
+    return -EINVAL;
+  }
+  return ENOERR;
 }
 
 static void
 synth_serial_start_xmit(serial_channel *chan)
 {
@@ -241,22 +264,73 @@
     cyg_drv_interrupt_mask(vector);
     cyg_drv_interrupt_acknowledge(vector);
     return CYG_ISR_CALL_DSR;
 }
 
+
+//how many character max do we want from the peer for
+//each call to synth_auxiliary_xchgmsg
+#define MAX_CHAR_PER_READ 10
+static char buff[MAX_CHAR_PER_READ];
+//how many char in the current buffer;
+static int nb_read;
+//next to read
+static int next_to_read;
+
 static void       
 synth_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
 {
     serial_channel *chan = (serial_channel *)data;
     synth_serial_info *synth_info = (synth_serial_info *)chan->dev_priv;
 
     if (-1 != synth_info->synth_id) {
         char c;
-        int  l;
-        synth_auxiliary_xchgmsg(synth_info->synth_id, SYNTH_SERIAL_RX, 0, 0,
-                                0, 0, &l, &c, 0, 1);
-        (chan->callbacks->rcv_char)(chan, c);
+        int  l= 0,len;
+	int i;
+	if(synth_info->is_throttled)
+	  diag_printf("WHAT ARE WE DOING HERE !\n");
+#if 0
+	//Do we still have something in out buffer (in case we were throttled)
+	if(nb_len)
+	  {
+	    len = nb_len;
+	    for (i = next_to_read ; i < (next_to_read + len) && !synth_info->is_throttled; i++){
+	      (chan->callbacks->rcv_char)(chan, buff[i]);
+	      nb_read--;
+	      next_to_read++;
+	    }
+	  }
+	if(nb_len)
+	  {
+	    cyg_drv_interrupt_unmask(vector);
+	    return;
+	  }
+#endif
+	//make sure we get everything out of the host. This help 
+	//when we miss interrupts. 
+	//this is potentially blocking the dsr for a little while, 
+	//but this is in fact a good thing. The host side should be 
+	//able to bufferize in the mean time.
+	
+	while(l >= 0){
+	  synth_auxiliary_xchgmsg(synth_info->synth_id, SYNTH_SERIAL_RX, 0, 0,
+				  0, 0, &l,buff, &len, MAX_CHAR_PER_READ);
+	  
+	  if(l >= 0 && len){
+
+	    //buff[len] = 0;
+	    //printf("%s\n",buff);
+	    for (i = 0 ; i < len ; i++){
+	      (chan->callbacks->rcv_char)(chan, buff[i]);
+	      //diag_printf("i= %d\n",i);
+	    }
+
+	    //we were throttled : stop reading from host.
+	    if(synth_info->is_throttled)
+	      return;
+	  }
+	}
     }
     cyg_drv_interrupt_unmask(vector);
 }
 
 // ----------------------------------------------------------------------------


More information about the Ecos-devel mailing list