QNX I/O Programming
https://code.google.com/p/rt-embedded-project6/source/browse/trunk/Project3.c?r=6
http://rt-embedded-project6.googlecode.com/svn-history/r6/trunk/Project3.c
/********************************************************************** * Project3.c * * Configures the parallel port to generate a 1kHz square wave. * * Authors: * Sajin George * Russ Martin * Oliver Wing * * Credit to http://psy.swan.ac.uk/staff/carter/qnx/tut_nto_parout.htm * for the otherwise very tricky setup of the parallel port for output. */ #include <stdlib.h> #include <stdio.h> #include <unistd.h> // for sleep() #include <stdint.h> #include <time.h> #include <hw/inout.h> // for in*() and out*() functions #include <sys/neutrino.h> // for ThreadCtl() #include <sys/mman.h> // for mmap_device_io() #include <sys/siginfo.h> // for sigevent and signal handling #include "types.h" /* The Neutrino IO port used here corresponds to a single register, which is * one byte long */ #define PORT_LENGTH 1 /* The first parallel port usually starts at 0x378. Each parallel port is * three bytes wide. The first byte is the Data register, the second byte is * the Status register, the third byte is the Control register. */ #define DATA_ADDRESS 0x378 #define CTRL_ADDRESS 0x37a /* bit 2 = printer initialisation (high to initialise) * bit 4 = hardware IRQ (high to enable) */ #define INIT_BIT 0x04 // One-bit constants. #define LOW 0x00 #define HIGH 0xFF // Arbitrary test value for post. Can be any byte #define TEST_VAL 0x55 /* Clock resolution in nanoseconds. Must be less than or equal to 500 us for * the 1kHz clock to properly be generated.*/ #define CLOCK_RESOLUTION 500000 // Variables that control the square wave. bool outputHigh = false; bool portInitialized = false; uintptr_t data_handle; /* Flip the output bits. * Param: signo: ID of signal that generates the call to this method * This is unused, but required by signal/event handler */ void FlipOutput(int signo) { if (portInitialized) { if (outputHigh) { out8( data_handle, LOW ); outputHigh = false; } else { out8( data_handle, HIGH ); outputHigh = true; } } } // Power-on self test functions. bool POST() { UINT8 testIn; //write a bit out to register out8(data_handle, TEST_VAL); //now read in; the parallel port is write-only, //but reading it will return the last byte sent testIn=in8(data_handle); //fail if not equal to byte sent return(testIn==TEST_VAL); } int main(int argc, char *argv[]) { // Control register for parallel port uintptr_t ctrl_handle; // Structs and values needed for timer and event handler struct sigevent event; timer_t timer2KHz; struct itimerspec timerInfo; struct _clockperiod clockResolution; // Give the thread root permissions to access the hardware if ( ThreadCtl( _NTO_TCTL_IO, NULL ) == -1 ) { fprintf( stderr, "Can't get root permissions!\n" ); return -1; } // Set the clock resolution to something below 500 usec. clockResolution.nsec = CLOCK_RESOLUTION; clockResolution.fract = 0; if ( ClockPeriod( CLOCK_REALTIME, &clockResolution, NULL, 0 /* unimportant parameter */ ) == -1 ) { fprintf( stderr, "Clock not allowing the necessary resolution change!\n" ); return -1; } // Get a handle to the parallel port's Control register ctrl_handle = mmap_device_io( PORT_LENGTH, CTRL_ADDRESS ); // Initialise the parallel port out8( ctrl_handle, INIT_BIT ); // Get a handle to the parallel port's Data register data_handle = mmap_device_io( PORT_LENGTH, DATA_ADDRESS ); // Set up a basic signal notification to trigger SIGUSR1. SIGEV_SIGNAL_INIT ( &event, SIGUSR1 ); // Connect a timer to the signal notification. timer_create( CLOCK_REALTIME, &event, &timer2KHz ); // Everything's ready to go. portInitialized = true; // Run POST tests. if ( POST() ) { // Everything passed! printf( "POST successful!\n" ); } else { // Something is wrong. printf( "POST failed!\n" ); return -1; } // Install the timer signal handler. signal( SIGUSR1, FlipOutput ); /* Set up the timer to trigger a signal once every 500 us (twice per cycle). * Wait 500 us until the first signal, and then 500 us for each future signal. */ timerInfo.it_value.tv_sec = 0; // Timer period div 1E9 nsec timerInfo.it_value.tv_nsec = CLOCK_RESOLUTION; // Timer period mod 1E9 nsec timerInfo.it_interval = timerInfo.it_value; // Timer is pure periodic timer_settime( timer2KHz, 0 /* relative time */, &timerInfo, NULL ); // Wait for and process signals as they arise. for ( ;; ) { } return 0; }