Hello,
i’ m trying to implement a multithreaded serial port driver for multiple
devices. I have attached the sourcecode. The problems are:
-
After recieving a full dataset another Interrupt raises and the read
command blocks (there is definitely only one dataset sent by the device). -
If I try to mask the IRQ, I can’t unmask it in the handling thread
(int_thread). After that every try to read from that port fails, until I
restart my program with the mask command removed and several (!) unmask
commands are called.
Any help would be greatly appreciated.
Valentin
Here is the code:
#include <fcntl.h> //open, write, read…
#include <pthread.h> //pthread_create…
#include <sched.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <termios.h>
#include <unistd.h> /* Support all standards /
#include <sys/mman.h> / Memory locking functions */
#include <sys/neutrino.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/types.h>
#define RW_BUFFER 2048 //Size of Read
#define DATA_SIZE 2048
#define NAME_LEN 100
#define NBYTE_READ 1
#define COM2_IRQ 3
#define COM1_IRQ 4
#define COM1_NAME “/dev/ser1”
#define COM2_NAME “/dev/ser2”
#define COM3_NAME “/dev/ser3”
#define COM4_NAME “/dev/ser4”
#define FALSE 0
#define TRUE 1
#define MINCHAR 1 /* blocking read until “min” chars received */
//port identification and settings
typedef struct
{
int fd; //file descriptor
char dev[NAME_LEN]; //name of device
char buf[RW_BUFFER]; //read or write buffer
unsigned int num; //number of characters to read
} sPort;
//interrupt identification
typedef struct
{
int id;
unsigned int irq;
int mask;
} sISR;
struct sigevent event;
//
/* open and configurate a Port /
/ needs: /
/ const char* Port…a device name /
/ speed_t Baud…baudrate for reading and writing */
//
sPort openPort (const char* Port, speed_t Baud)
{
int fc, fd;
sPort msPort;
struct termios tio, oldtio; //struct settings of io-file
//printf(“Delete buffer before open. Size of Buffer: %d\n”,
sizeof(msPort.buf));
memset (msPort.buf, ‘\0’, sizeof(msPort.buf));
strcpy (msPort.dev, Port);
//open for read and write operation (O_RDWR),
msPort.fd = open(Port, O_RDWR | O_NOCTTY | O_NDELAY);//O_NOCTTY: this
program doesn’t want to be the “controlling terminal”
//O_NDELAY: program doesn’t care what state the DCD signal
line is in
if (msPort.fd > 0)
{
tcgetattr(msPort.fd, &oldtio); /* save current serial port settings /
bzero(&tio, sizeof(tio)); / clear struct for new port settings */
/*
BAUDRATE: Set bps rate. You could also use cfsetispeed and
cfsetospeed.
CS8 : 8n1 (8bit,no parity,1 stopbit)
CLOCAL : local connection, no modem contol
CREAD : enable receiving characters
*/
cfsetispeed (&tio, Baud);
cfsetospeed (&tio, Baud);
tio.c_cflag = (CS8 | CLOCAL | CREAD);
//IGNPAR : ignore bytes with parity errors
tio.c_iflag = (IGNPAR);
//Raw output
tio.c_oflag = 0;
/* set input mode (non-canonical, no echo,…) */
tio.c_lflag = 0;
tio.c_cc[VTIME] = 0; /* inter-character timer unused /
tio.c_cc[VMIN] = MINCHAR; / blocking read until “min” chars
received */
tcflush(msPort.fd, TCIFLUSH); //flush terminal
tcsetattr(msPort.fd, TCSANOW, &tio); //set attributes
fc = fcntl(msPort.fd, F_SETFL, 0);
printf(“Port opened %s.\n”,Port);
}
return (msPort);
}
//
/* write msPort.buf to Port described by msPort.fd /
/ needs: /
/ struct sPort…see above for definition */
//
int writePort (sPort* msPort)
{
int i;
int size_written; //number of characters writen
//write to port
size_written = write (msPort->fd, msPort->buf, strlen(msPort->buf));
return(1);
}
//
/* read on Interrupt from msPort.dev to msPort.buf /
/ needs: /
/ struct sPort…see above for definition */
//
int readPort (sPort* msPort)
{
pthread_t ptid; //ID of thread created
/POSIX 1003.1 (Threads); create a thread for interupt handling and pass
msPort to thread(IRQ4 only)/
pthread_create (&ptid, NULL, int_thread, (void *) msPort);
printf(“Want to continue? (y/n)\n”);
while (getchar() != ‘n’)
printf(“Want to continue? (y/n)\n”);
return(1);
}
//
/* Thread waiting for interrupt on IRQ4 and read to buffer /
/ needed argument: /
/ struct sPort…see above for definition */
//
void* int_thread (void *arg)
{
int size_read, n_mask, id;
sPort *psPort = (sPort *)arg;
sISR msISR;
struct sched_param param;
msISR.id = 0; //init ISR struct
msISR.irq= 0;
msISR.mask =0;
ThreadCtl (_NTO_TCTL_IO, NULL); /*Request I/O privaty; ThreadCtl is QNX6
standard */
/****** set IRQ - Nummber /
if (strcmp(COM1_NAME,psPort->dev) == 0)
msISR.irq = COM1_IRQ;
else if (strcmp(COM2_NAME,psPort->dev) == 0)
msISR.irq = COM2_IRQ;
else
{
printf(“Error in int_thread: Device or IRQ unknown.\n”);
exit(EXIT_FAILURE);
}
/**************************/
/**** Attach an ISR to the thread so the trhread can Wait for an Interrupt
*********/
id = InterruptAttach (msISR.irq, isr_handler, (void *) &msISR, 0,
_NTO_INTR_FLAGS_END | _NTO_INTR_FLAGS_TRK_MSK); /*InterruptAttach is QNX6
standard */
msISR.id = id;
//boost the priority of the thread
param.sched_priority = 30;
pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m);
printf(“In thread with priority %d device %s\n”, getprio(0), psPort->dev);
/getprio is QNX4 standart/
while (1)
{
size_read = 0;
//Waiting for a Interrupt
InterruptWait (NULL, NULL); /*InterruptWait is QNX6 standard */
while (size_read < psPort->num)
{
size_read += read(psPort->fd, psPort->buf + size_read,
NBYTE_READ);
tcflush(psPort->fd, TCIFLUSH); //flush
terminal
}
n_mask = InterruptUnmask(msISR.irq, msISR.id);
}
InterruptDetach (msISR.id);
return (NULL);
}
// this is the Interrupt Service Routine
const struct sigevent * isr_handler (void *arg, int id)
{
sISR *psISR = (sISR *)arg;
memset(&event, 0, sizeof(event)); //Init of interrupt
signal for int_thread
event.sigev_notify = SIGEV_INTR;
psISR->mask = InterruptMask(psISR->irq, psISR->id);
// in a level-sensitive environment, clear the cause of !!from
QNX-Doc.!!
// the interrupt, or at least issue InterruptMask to
// disable the PIC from reinterrupting the kernel
// return a pointer to an event structure (preinitialized
// by main) that contains SIGEV INTR as its notification type.
// This causes the InterruptWait in “int thread” to unblock.
return (&event); // call int_thread
}
int main()
{
int baudrate;
sPort msPort;
/Initialize sPort - struct *******************************************/
msPort.fd = -1;
memset (msPort.dev, 0, sizeof(msPort.dev));
memset (msPort.buf, 0, sizeof(msPort.buf));
msPort.num = -1;
/***********************************************************************/
baudrate = 9600;
msPort = openPort (COM1_NAME, baudrate); //open and configurate Commport
strcpy(msPort.buf, “*99P\r”); //set command
msPort.num = 7;
writePort(&msPort); //write to port
readPort(&msPort); //read from port
return (0);
}