-- 
Steve Rosenbluth
Jim Henson's Creature Shop
2821 Burton St, Burbank CA
(818) 953-3030


I apologize for not having time to look at your code but attached is a
test program that works: it spits out a 14 char packet (115200 bps) at
60 Hz on the first serial port. give it a try ...

It requires that the rtl_sched.o module be loaded.

for those interested:
The code here is the beginning of a rewrite of the rt-com code, which I
intend to contribute in a few months. The original code is missing a lot
of RX/TX error detection, UART type autodection, API, etc. i'm going to
merge it with code from Chris Karcher's "RS232.C" freeware, which is
quite reliable (I have used it over the past few years).

-- 
Steve Rosenbluth
Jim Henson's Creature Shop
2821 Burton St, Burbank CA
(818) 953-3030
/* file: periodic_serial.c*/
/* sends serial packets out first serial port at 60 Hz using RTLinux */
/* steve Rosenbluth, JHCS 2-99 */
/*  epson dot-matrix printer condense code */
/*original serial code by Jens Michaelsen HCC */
/* compile with: gcc -Wall -O2 -D__KERNEL__ -D__RT__ -DMODULE -c periodic_serial.c */


/*------------------------- start of file rt_com.h ---------------*/


/* status masks, several bits may be set simultaneously     */
/* status information is returned by LineStatus and as      */
/* the high byte of COMData                                 */

#define DATA_READY   0x01     /* not an error               */
#define OVERRUN      0x02     /* error detected by hardware */
#define PARITY       0x04     /* error detected by hardware */
#define FRAME        0x08     /* error detected by hardware */
#define BREAK        0x10     /* not an error               */
#define BUFFER_FULL  0x80     /* error detected by software */
#define TXB_EMPTY    0x20     /* not an error               */
#define HARD_ERROR   (OVERRUN | PARITY | FRAME | BREAK)

#define RXB  0x00             /* port offsets */
#define TXB  0x00
#define IER  0x01
#define IIR  0x02
#define FCR  0x02
#define LCR  0x03
#define MCR  0x04
#define LSR  0x05
#define MSR  0x06
#define DLL  0x00
#define DLM  0x01
#define PARITY_EVEN  0        /* for port initialisation    */
#define PARITY_ODD   1
#define PARITY_NONE  2

/* bit masks which may be written to the MCR using ModemControl */
#define DTR          0x01     /* data Terminal Ready        */
#define RTS          0x02     /* Request To Send            */
#define Out1         0x04
#define Out2         0x08
#define LoopBack     0x10
#define RT_SERIAL_BUFSIZE 256
#define TRIGGER_LEVEL 4
#define FIFO 4

#define STD_COM_FLAG 0
#define RT_COM_CNT 3
#define COM_0   0
#define COM_1   1
#define COM_2   2
#define COM_3   3

#define BPS_110 110        /* 110 baud */
#define BPS_300 300        /*    .     */
#define BPS_600 600        /*    .     */
#define BPS_1200 1200      /*    .     */
#define BPS_2400 2400      /*    .     */
#define BPS_4800 4800      /*    .     */
#define BPS_9600 9600      /*    .     */
#define BPS_19K 19200      /*    .     */
#define BPS_38K 38400      /*    .     */
#define BPS_57K 57600      /*    .     */
#define BPS_115K 115200   /* 115200 baud */
#ifndef NULL
    #define NULL 0
#endif
#define RT_HIGHEST_PRIORITY 1                                               /* for 
rt_task_init */


/************* typedefs ************/
typedef struct {
  int  head;
  int  tail;
  char buf[ RT_SERIAL_BUFSIZE ];
} rt_buf_struct_t;

typedef struct {
  int magic;
  int baud_base;
  int port;
  int irq;
  int flag;
  void (*isr)(void); /* irq handler pointer */
  int type;
  int ier;  /* copy of chip register */
  rt_buf_struct_t ibuf;
  rt_buf_struct_t obuf;
} rt_com_struct_t;


/************ prototypes *************/
int rt_com_read(rt_com_struct_t *com_p, char * ptr, int cnt );
void rt_com_write(rt_com_struct_t *com_p, char * ptr, int cnt );
void rt_com_setup( int, unsigned, unsigned, unsigned, unsigned );
void rt_com_init( void );
void rt_com0_isr(void);
void rt_com_exit( void );

#if 0
static void rt_com_isr( int com );
static void rt_com0_isr(void) { rt_com_isr( 0 ); }
static void rt_com1_isr(void) { rt_com_isr( 1 ); }
static void rt_com2_isr(void) { rt_com_isr( 2 ); }
//static void rt_com3_isr(void) { rt_com_isr( 3 ); }
#endif

/*------------------------ start of file rt_com.c ----------------*/

#include <linux/version.h>      /* for modversions ? */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <asm/rt_irq.h>
#include <asm/system.h>   /* for r_save_flags(), r_cli() */
#include <asm/io.h>         /* for outb() */
#include </usr/src/rtl/include/rtl_sched.h> /* scheduling header*/


/*************** global vars *****************/

rt_buf_struct_t rt_buf_struct;
rt_com_struct_t rt_com_struct;

#if 0
struct rt_com_struct rt_com_table[RT_COM_CNT] = {
   {0,115200_BPS,0x3F8,4,STD_COM_FLAG,rt_com0_isr},
   {0,115200_BPS,0x2F8,3,STD_COM_FLAG,rt_com1_isr},
   {0,115200_BPS,0x3E8,5,STD_COM_FLAG,rt_com2_isr},
// {0,115200_BPS,0x2E8,3,STD_COM_FLAG,rt_com4_isr},
};
#endif

RT_TASK thetask_struct;                                                       /* real 
time task structure. must not become deallocated */
/*const int MSSGLEN = 5; */
const int task_stack_size = 4000;                                             /* so 
parent can specify stack for real time task */
rt_com_struct_t com0 = {0,(int)BPS_115K,0x3F8,4,STD_COM_FLAG,rt_com0_isr};


/*-----------------------------------------------------------------------*/
void rt_com_write(rt_com_struct_t *com_p, char * ptr, int cnt )
{
   rt_buf_struct_t *b;
   long flags;
 
   b = &(com_p->obuf);
   r_save_flags(flags);
   r_cli();
   while(--cnt>=0)
   {
      b->buf[b->head++] = *ptr++;
      b->head &= (RT_SERIAL_BUFSIZE-1);
   }
   com_p->ier|=0x02;
   outb( com_p->ier, com_p->port + IER);
   r_restore_flags(flags);
}

/*-----------------------------------------------------------------------*/
int rt_com_read(rt_com_struct_t *com_p, char * ptr, int cnt )
{
   rt_buf_struct_t *b;
   long flags;
   int done = 0;

   b = &(com_p->ibuf);
   r_save_flags(flags); r_cli();
   while( ( b->head != b->tail ) && (--cnt >= 0 ) )
   {
      done++;
      *ptr++ = b->buf[b->tail++];
      b->tail &= (RT_SERIAL_BUFSIZE-1);
   }
   r_restore_flags(flags);
   return( done );
}

/*-----------------------------------------------------------------------*/
int rt_com_irq_get(rt_com_struct_t *p, unsigned char *c )
{
   rt_buf_struct_t *b = &( p->obuf );
   if( b->head != b->tail )
   {
     *c = b->buf[b->tail++];
     b->tail &= (RT_SERIAL_BUFSIZE-1);
     return( 1 );
   }
   return( 0 );
}


/*-----------------------------------------------------------------------*/
void rt_com_irq_put(rt_com_struct_t *p, unsigned char ch )
{
  rt_buf_struct_t *b = &( p->ibuf );
  b->buf[b->head++] = ch;
  b->head &= (RT_SERIAL_BUFSIZE-1);
}


/*-----------------------------------------------------------------------*/
/* the interrupt handler(s) */
void rt_com0_isr(void)
{
   rt_com_struct_t *com_p;
   unsigned char data;
   unsigned char isr;
   unsigned char stat;
   char loop = 4;

   com_p = &com0;

   do
   {
        /* Receive */

      stat = inb(com_p->port + LSR);
      while( stat & DATA_READY )
      {
         data = inb(com_p->port + RXB);
         rt_com_irq_put(com_p,data);
         stat = inb(com_p->port + LSR);
      };

    /* now Transmit */

      inb(com_p->port + MSR);
      if( stat & 0x20 )
      {
         if( rt_com_irq_get(com_p,&data) )
         {
            do
            {
               outb( data, com_p->port + TXB );
               stat = inb(com_p->port + LSR);
            } while( --loop>0 && rt_com_irq_get(com_p,&data) );
         }
         else
         {
            com_p->ier &= ~0x02;
            outb( com_p->ier, com_p->port + IER );
         }
         stat = inb(com_p->port + LSR);
      };
      isr = inb(com_p->port + IIR) & 0x0F;
   } while( (isr) && --loop>0);
}


/*-----------------------------------------------------------------------*/
static void enable_fifo(int base, int trigger)
{
   switch (trigger)
   {
      case  0: outb( 0x00, base + FCR ); break;
      case  1: outb( 0x01, base + FCR ); break;
      case  4: outb( 0x41, base + FCR ); break;
      case  8: outb( 0x81, base + FCR ); break;
      case 14: outb( 0xC1, base + FCR ); break;
      default:
   }
}


/*-----------------------------------------------------------------------*/
void rt_com_setup( int com, unsigned baud, unsigned parity,
   unsigned stopbits, unsigned wordlength )
{
   /*struct rt_com_struct * p = &(rt_com_table[com]);*/
   rt_com_struct_t *com_p;
   unsigned char temp;
   unsigned char rs_dvsrl,rs_dvsrh;

   com_p = &com0;

   outb( 0x00, com_p->port + IER );    /* disable UART interrupts */

   inb( com_p->port + IIR );        /* clear irq */
   inb( com_p->port + LSR );
   inb( com_p->port + RXB );
   inb( com_p->port + MSR );

#if 0
   if(!baud) return;
   divider = (unsigned) ((com_p->baud_base + com_p->baud_base % baud) / baud);
   outb( divider % 256, com_p->port + DLL );
   outb( divider / 256, com_p->port + DLM );
#endif

  /* get the baud rate divisor values */
  rs_dvsrh = 0;
  switch(baud){
    case 110:
      rs_dvsrh = 0x04;
      rs_dvsrl = 0x17;
      break;
    case 300:
      rs_dvsrh = 0x01;
      rs_dvsrl = 0x80;
      break;
    case 600:
      rs_dvsrl = 0xC0;
      break;
    case 1200:
      rs_dvsrl = 0x60;
      break;
    case 2400:
      rs_dvsrl = 0x30;
      break;
    case 4800:
      rs_dvsrl = 0x18;
      break;
    case 9600:
      rs_dvsrl = 0x0C;
      break;
    case 19200:
      rs_dvsrl = 0x06;
      break;
    case 38400:
      rs_dvsrl = 0x03;
      break;
    case 57600:
      rs_dvsrl = 0x02;
      break;
    case 115200:
      rs_dvsrl = 0x01;
      break;
    default:
        /* FIXME: return error */
      rs_dvsrl = 0x01;
    }
   outb( 0x80, com_p->port + LCR );    /* enable baud rate divisor registers */
   outb(rs_dvsrl, com_p->port + DLL );
   outb(rs_dvsrh, com_p->port + DLM );

   switch (parity)
   {
      case PARITY_ODD:  temp = 0x08; break;
      case PARITY_EVEN: temp = 0x18; break;
      default:          temp = 0x00;
   }
   outb( (wordlength-5) + ((stopbits-1) << 2) + temp, com_p->port + LCR );
   outb( DTR + RTS + Out1 + Out2, com_p->port + MCR );
   com_p->ier = 0x01;
   outb( com_p->ier, com_p->port + IER);
   enable_fifo( com_p->port, TRIGGER_LEVEL );
}


/*-----------------------------------------------------------------------*/
void rt_com_init( void )
{
    rt_com_struct_t *com_p;

      com_p = &com0;
      
        /* FIXME: handle the error !!*/
      if (!check_region(com_p->port,8))
        return;
      request_region(com_p->port,8,"rt_com");
      request_RTirq(com_p->irq, com_p->isr);
      rt_com_setup(COM_0,BPS_115K,0,1,8);
}


/*-----------------------------------------------------------------------*/
void rt_com_exit( void )
{
    rt_com_struct_t *com_p;

      com_p = &com0;

      rt_com_setup(COM_0,0,0,1,8);
      release_region(com_p->port,8);
      free_RTirq(com_p->irq);
}


/****************************//* the entry-point function of the rt task */
void Periodic_entry_point(int arg)                               /* initing parent 
sends in unique fifo number */
{
#define MESSAGE_LEN 14
    static char message[MESSAGE_LEN] = "Serial_Packet ";
    /* int ret;*/
    /*static int i=0;*/
    
    while (1)
    {
        #if 0
        ret = rtf_put(incoming_fifo_id, message, MSSG_LEN);                     /* 
shove our message into the chat fifo */
        if (ret == RT_ERROR)
            ;                                                                  /* 
FIXME: handle error */
        #endif
        
        rt_com_write(&com0, message, (int)MESSAGE_LEN );
        /*printk("!");*/ 
        
        rt_task_wait();                                                        /* end 
this task until next periodic call */
    }
}


/****************************/
int init_module(void)                                                         /* 
called by kernel ?!? */
{
    RTIME now, period;                                                                
/* (64 bit) for storing current captured clock tick */

    rt_com_init();
    /*rtf_create(CTL_FIFO_ID, CTL_FIFO_LEN); */                                    /* 
control channel for messages to rt process */
    /*rtf_create(CHAT_FIFO_ID, CHAT_FIFO_LEN);   */                                /* 
fifo from which rt task talks to us */
    rt_task_init(&thetask_struct, Periodic_entry_point, NULL, task_stack_size, 
RT_HIGHEST_PRIORITY);
    now = rt_get_time();                                               /* capture 
current time to start periodic func now */
    period = (RTIME) ((long double)RT_TICKS_PER_SEC * (1.0 / 60.0));       /* calc # 
ticks in one period of desired frequency */
    /*printk("making periodic...\n");*/
    rt_task_make_periodic(&thetask_struct, now, period);       /* makes rt task 
actually run */
    /*rtf_create_handler(CTL_FIFO_ID, Ctl_fifo_handler); */                        /* 
register our handler: invoked when fifo is written */
    
    return 0;
}

/****************************/
void cleanup_module(void)
{
    #if 0
    rtf_destroy(CTL_FIFO_ID);                                                  /* get 
rid of the control fifo */
    rtf_destroy(CHAT_FIFO_ID);                                                 /* get 
rid of chat fifo */
    #endif 

    rt_task_delete(&thetask_struct);                                           /* take 
our task out of the rt executive */
}


Reply via email to