MiniRTL: A Minimal Real-Time Linux by Peter Wurmsdobler and Nicholas McGuire Listing One extern unsigned short int rt_daq_aget( void ); extern void rt_daq_aset(unsigned short int channel, unsigned short int value); Listing Two typedef struct { int w; /* setpoint */ int k; /* gain */ } shm_t *shm; /* shm to user space */ pthread_t control_thread; /* control thread */ void *rt_control_function( void *t ) /* control thread's function */ { int Y, U, E; shm->k = 0; shm->w = 0; pthread_make_periodic_np( control_thread, gethrtime(), SAMPLE_TIME ); while(1) /* this is the periodic part */ { pthread_wait_np(); /* wait for next sample hit */ Y = rt_daq_aget(); /* get DAQ input */ E = (int) ( shm->w - Y ); /* control deviation */ U = (unsigned short int)( shm->k * E ); /* P controller */ rt_daq_aset( OUTPUT_CHANNEL, U ); /* output control variable */ rtf_put( Y_FIFO, &Y, sizeof(Y) ); /* stuff Y into fifo */ rtf_put( U_FIFO, &U, sizeof(U) ); /* stuff U into fifo */ } } /* interrupt service routine for "emergency shutdown" */ unsigned int rt_spp_isr( unsigned int irq_number, struct pt_regs *p ) { rt_daq_aset( OUTPUT_CHANNEL, 0 ); /* output 0 */ pthread_make_periodic_np( control_thread, HRTIME_INFINITY, 0 ); return 0; } Listing Three int init_module(void) { pthread_attr_t attr; /* attributes */ struct sched_param param; /* parameter */ /* Get a hard IRQ for SPP */ rtl_request_global_irq( SPP_IRQ, rt_spp_isr ); /* Initialize shared memory */ shm_allocate( SHM_NAME, SHM_SIZE, (void **) &shm ); /* Initialize rt-fifos */ rtf_create( Y_FIFO, FIFO_SIZE ); rtf_create( U_FIFO, FIFO_SIZE ); /* and now we initialize the kernel thread. */ pthread_attr_init( &attr ); pthread_attr_setcpu_np( &attr, 0 ); sched_param.sched_priority = 1; pthread_attr_setschedparam( &attr, ¶m ); pthread_create( &control_thread, &attr, rt_control_function, (void *)1 ); return 0; } void cleanup_module(void) { /* Release the SPP */ rtl_free_global_irq( SPP_IRQ ); /* Delete control thread */ pthread_delete_np( control ); /* Release rt-fifos */ rtf_destroy( Y_FIFO ); rtf_destroy( U_FIFO ); /* Release shared memory */ shm_deallocate( shm ); } Listing Four #include #include #include #include /* set the paralell port address */ int lpt_port=0x378; /* compiled in addresses are unpractical so lsets define a module parameter * that permits setting the parport address at module insertion time * insmod sched_toggle.o lpt_port=0x3bc would override 0x378 . */ MODULE_PARM(lpt_port,"i"); pthread_t thread; /* the runtime thread toggling D0-D3 of the paralell port */ void * toggle(void *arg) { int nibl; hrtime_t now; struct sched_param p; p. sched_priority = 1; /* set the attributes for the thread, this * defines the scheduling policy and priority */ pthread_setschedparam (pthread_self(), SCHED_FIFO, &p); now = gethrtime(); /* get the current time in nano-seconds */ /* make the thread periodic * starting now, with a period of 500000000 nano-seconds */ pthread_make_periodic_np (pthread_self(), now, 500000000); nibl = 0x0f; while (1) { outb(nibl,lpt_port); /* write it out to the parport*/ nibl = ~nibl; /* two's complement of nibl*/ pthread_wait_np (); /* put the thread on the wait queue */ } return 0; } /* init_module is called when the module is inserted it will do * the basic setup and register the module with the kernel */ int init_module(void) { rtl_printf("sched_toggle.c: RTL thread starts on CPU%d: using LPT at 0x%x\n", rtl_getcpuid(),lpt_port); /* create the thread. attributes are "initialized" to NULL and * set in toggle thread, attributes, function, ARG */ return pthread_create (&thread, NULL , toggle , 0 ); } /* when the module is removed with rmmod sched_toggle this is called * to cleanup any kernels trace of this module */ void cleanup_module(void) { /* send a request to thread asking for cancelation */ pthread_cancel (thread); /* wait until thread gave up and exited properly */ pthread_join (thread, NULL); } 7