Category : Files from Magazines
Archive   : JAN94.ZIP
Filename : RISC.ASC
Output of file : RISC.ASC contained in archive : JAN94.ZIP
by Mitchell Bunnell
Listing One
/* conf.h -- tuning parameters for packet switch example */
#define OCHAN_MAX 8 /* number of serial input channels */
#define ICHAN_MAX 8 /* number of serial output channels */
#define IRATE_MIL_SEC 10 /* input/process task rate */
#define ORATE0_MIL_SEC 20 /* output task rate for output channel 0 */
#define ORATE_MIL_SEC 100 /* output rate for other output channels */
#define IBYTES_PER_SEC 2000 /* bytes per second on input channel */
#define MIN_PACKET_SIZE 4 /* minimum input packet size (bytes) */
#define PACK_BYTES_MAX 80 /* maximum number of data bytes/packet */
/* calculated buffer sizes based on throughput and task rates */
#define IBUFF_MAX ((IBYTES_PER_SEC*IRATE_MIL_SEC)/1000)
#define OBUFF_MAX ((IBUFF_MAX*ORATE_MIL_SEC)/IRATE_MIL_SEC)
#define PACKETS_MAX ((IBUFF_MAX*ICHAN_MAX)/MIN_PACKET_SIZE)
extern int num_ichans, num_ochans;
extern int packet_process_prio;
/* packet.h -- data structure definitions for packet switch example */
#define PACKET_START_BYTE 0xFE
/* input packet format -
byte 0xFE PACKET START
byte 0x?? OUTPUT CHANNEL
byte 0x?? NUMBER OF BYTES IN PACKET
byte 0x?? DATA BYTES
.
.
.
byte 0x??
output packet format -
byte 0xFE PACKET START
byte 0x?? NUMBER OF BYTES IN PACKET
byte 0x?? CHECKSUM OF DATA BYTES
byte 0x?? DATA BYTES
.
.
.
byte 0x??
*/
/* internal structure for incoming/outgoing packets */
struct packet {
struct packet *next;
char checksum;
char curr_bytes;
char ochan;
char nbytes;
char data[PACK_BYTES_MAX];
};
/* structures for double buffers used for output */
struct buff {
int nbytes;
char data[OBUFF_MAX];
};
struct outbuff {
int chan;
int fd;
int thread_id;
int thread_priority;
struct buff *ready_buff;
struct buff *sending_buff;
int sending_buff_sent;
int new_send_sem;
struct buff buffs[2];
};
extern struct outbuff ochans[];
extern struct packet *get_new_packet();
extern struct packet *deq_packet();
/* input.c -- code for input task of packet switch example */
#include
#include
#include
#include
#include "conf.h"
#include "packet.h"
/* input channel structures */
struct packet *partial_packet[ICHAN_MAX];
int input_state[ICHAN_MAX];
int infds[ICHAN_MAX];
unsigned char ibuff[IBUFF_MAX];
/* input states */
#define STATE1_NEED_STARTBYTE 0
#define STATE2_NEED_OCHAN 1
#define STATE3_NEED_BYTECOUNT 2
#define STATE4_NEED_DATA 3
/* input_packets -- read some data from incoming channel and store
in packet structure. Enqueue these packets on the FIFO packet list.
*/
input_packets(chan)
int chan;
{
int out;
register int i;
register struct packet *p;
int state;
out = read(infds[chan], ibuff, IBUFF_MAX);
if (out <= 0)
return out;
p = partial_packet[chan];
state = input_state[chan];
for (i=0; i < out; i++) {
switch (state) {
case STATE1_NEED_STARTBYTE:
if (ibuff[i] == PACKET_START_BYTE)
state = STATE2_NEED_OCHAN;
break;
case STATE2_NEED_OCHAN:
p = get_new_packet();
p->curr_bytes = 0;
p->ochan = ibuff[i];
state = STATE3_NEED_BYTECOUNT;
break;
case STATE3_NEED_BYTECOUNT:
p->nbytes = ibuff[i];
if (p->nbytes > PACK_BYTES_MAX)
p->nbytes = PACK_BYTES_MAX;
state = STATE4_NEED_DATA;
break;
case STATE4_NEED_DATA:
p->data[p->curr_bytes++] = ibuff[i];
if (p->curr_bytes >= p->nbytes) {
enq_packet(p);
state = STATE1_NEED_STARTBYTE;
}
}
}
partial_packet[chan] = p;
input_state[chan] = state;
return 0;
}
void handler()
{
}
/* input_task -- input thread main loop. Read incoming data from
all channels and seperate into packets. Perform checksum on
these packets and put packets in output double buffer for
the output task to take care of.
*/
input_task()
{
int chan;
static struct itimerval v;
int output_rc, output0_rc;
/* set periodic timer for input rate */
signal(SIGALRM, handler);
sigblock(sigmask(SIGALRM));
v.it_value.tv_sec = v.it_interval.tv_sec = 0;
v.it_value.tv_usec = v.it_interval.tv_usec = IRATE_MIL_SEC*1000;
setitimer(ITIMER_REAL, &v, (struct itimerval *)0);
output_rc = output0_rc = 0;
for (;;) {
sigpause(0);
for (chan=0; chan < num_ichans; chan++) {
input_packets(chan);
}
process_packets();
if (output0_rc++ >= (ORATE0_MIL_SEC/IRATE_MIL_SEC)) {
switch_obuffer(0);
}
if (output_rc++ >= (ORATE_MIL_SEC/IRATE_MIL_SEC)) {
output_rc = 0;
for (chan=1; chan < num_ochans; chan++) {
switch_obuffer(chan);
}
}
}
}
/* open_input_channels -- open serial input channels */
open_input_channels()
{
int i;
char name[80];
for (i=0; i < num_ichans; i++) {
sprintf(name, "/dev/ichan%-d", i);
infds[i] = open(name, O_RDONLY|O_NONBLOCK);
if (infds[i] < 0) {
fprintf(stderr, "couldn't open %s\n", name);
exit(1);
}
}
}
/* main.c -- start of packet switch example */
#include
#include
#include
#include "conf.h"
int num_ichans, num_ochans;
int packet_process_prio;
main(argc, argv)
int argc;
char **argv;
{
if (argc != 3) {
fprintf(stderr, "usage %s
exit(1);
}
num_ichans = atoi(argv[1]);
num_ochans = atoi(argv[2]);
if (num_ichans <= 0 || num_ichans > ICHAN_MAX) {
fprintf(stderr, "bad number of input channels (%d). ", num_ichans);
fprintf(stderr, "minimum is 1 maximum is %d\n", ICHAN_MAX);
exit(1);
}
if (num_ochans <= 0 || num_ochans > OCHAN_MAX) {
fprintf(stderr, "bad number of output channels (%d). ", num_ochans);
fprintf(stderr, "minimum is 1 maximum is %d\n", OCHAN_MAX);
exit(1);
}
packet_process_prio = getpriority(PRIO_PROCESS, 0);
open_input_channels();
open_output_channels();
init_output_tasks();
init_packets();
input_task();
}
/* output.c -- code for output double buffers and output threads in
packet switch example */
#include
#include
#include
#include "conf.h"
#include "packet.h"
struct outbuff ochans[OCHAN_MAX];
/* switch_obuffer -- switch output double buffer */
switch_obuffer(chan)
int chan;
{
struct outbuff *buffp;
struct buff *tmp;
buffp = &ochans[chan];
if (!buffp->sending_buff_sent) {
fprintf(stderr, "out of real-time. channel %d\n", chan);
return;
}
/* switch buffers. double buffering */
buffp->sending_buff_sent = 0;
tmp = buffp->ready_buff;
buffp->ready_buff = buffp->sending_buff;
buffp->sending_buff = tmp;
sem_signal(buffp->new_send_sem);
buffp->ready_buff->nbytes = 0;
}
/* put_packet_in_buff -- copy a packet (output format) to the
output buffer for a channel
*/
put_packet_in_buff(chan, pkt)
int chan;
struct packet *pkt;
{
struct outbuff *buffp;
struct buff *rbuff;
int i;
if (chan == -1) { /* broadcast */
for (i=0; i < num_ochans; i++) {
put_packet_in_buff(i, pkt);
}
return;
}
if (chan >= num_ochans) {
return; /* bad channel number */
}
buffp = &ochans[chan];
rbuff = buffp->ready_buff;
if (3+pkt->nbytes + rbuff->nbytes > OBUFF_MAX) {
fprintf(stderr, "output buffer full %d\n", chan);
return; /* output buffer full */
}
rbuff->data[rbuff->nbytes++] = PACKET_START_BYTE;
rbuff->data[rbuff->nbytes++] = pkt->nbytes;
rbuff->data[rbuff->nbytes++] = pkt->checksum;
bcopy(pkt->data, &rbuff->data[rbuff->nbytes], pkt->nbytes);
rbuff->nbytes += pkt->nbytes;
return;
}
/* output_task -- main routine for each output thread. Simply
write output buffer to output channel.
*/
output_task(buffp)
struct outbuff *buffp;
{
int out;
for (;;) {
sem_wait(buffp->new_send_sem);
out = write(buffp->fd,buffp->sending_buff->data,
buffp->sending_buff->nbytes);
buffp->sending_buff_sent = 1;
}
}
/* init_dbuff -- initialize a double buffer (one per each output channel. */
init_dbuff(chan, p)
int chan;
struct outbuff *p;
{
char name[80];
p->chan = chan;
p->ready_buff = &p->buffs[0];
p->sending_buff = &p->buffs[1];
p->sending_buff_sent = 1;
sprintf(name, "ochan%-d", chan);
sem_delete(name);
p->new_send_sem = sem_get(name, 0);
if (p->new_send_sem < 0) {
fprintf(stderr, "could not get sem %s\n", name);
exit(1);
}
}
/* init_output_tasks -- initialize output double buffers and
create output threads
*/
init_output_tasks()
{
int i;
int res;
pthread_attr_t thread_attr;
pthread_t tid;
for (i=0; i < num_ochans; i++) {
init_dbuff(i, &ochans[i]);
pthread_attr_create(&thread_attr);
thread_attr.pthread_attr_prio = packet_process_prio - 1 - i;
res = pthread_create(&tid, thread_attr, output_task, &ochans[i]);
if (res < 0) {
fprintf(stderr, "could not create output thread %d\n", i);
exit(1);
}
}
}
/* open_output_channels -- open serial output channels */
open_output_channels()
{
int i;
int fd;
static char name[80];
for (i=0; i < num_ichans; i++) {
sprintf(name, "/dev/ochan%-d", i);
ochans[i].fd = fd = open(name, O_WRONLY|O_TRUNC);
if (fd < 0) {
fprintf(stderr, "couldn't open %s\n", name);
exit(1);
}
}
}
/* packet.c -- routines and data structures to deal with packets */
#include "conf.h"
#include "packet.h"
/* packet lists */
struct packet *packet_head, *packet_tail;
struct packet *packet_free;
struct packet packet_table[PACKETS_MAX];
/* free_packet -- put packet on free list */
free_packet(p)
struct packet *p;
{
p->next = packet_free;
packet_free = p;
}
/* get_new_packet -- get a free packet */
struct packet *get_new_packet()
{
struct packet *p;
p = packet_free;
packet_free = p->next;
return p;
}
/* enq_packet -- put packet on FIFO packet list */
enq_packet(p)
register struct packet *p;
{
p->next = 0;
if (packet_head)
packet_tail->next = p;
else
packet_head = p;
packet_tail = p;
}
/* deq_packet -- get packet form FIFO packet list */
struct packet *deq_packet()
{
register struct packet *p;
if (p=packet_head)
packet_head = p->next;
return p;
}
/* init_packets -- initialize free packet list */
init_packets()
{
register int i;
for (i=0; i < PACKETS_MAX; i++)
free_packet(&packet_table[i]);
}
/* process.c -- perform processing needed on packets */
#include "conf.h"
#include "packet.h"
/* do_checksum -- perform checksum on a packet */
do_checksum(pkt)
struct packet *pkt;
{
register int sum;
register char *p;
register count;
count = sum = pkt->nbytes;
p = pkt->data;
while (count--) {
sum += *p++;
}
pkt->checksum = sum;
}
/* process_packets -- take each packet of of the FIFO packet queue
and put it in its appropriate output buffer
*/
process_packets()
{
register struct packet *p;
do {
p = deq_packet();
if (p) {
do_checksum(p);
put_packet_in_buff(p->ochan, p);
free_packet(p);
}
} while (p);
}
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/