This chapter covers the following:
Since the process of building embedded systems is similar for both QNX 4 and for the new deeply embedded Neutrino 1.01 environment, we cover both operating systems in this chapter. We provide notes on the significant differences.
Before you attempt to configure Photon to run on your embedded system, we recommend that you use the information provided in this chapter to construct a trial embedded Photon environment on a normal PC.
At the end of the chapter, we've included sample files that you can use. If your PC doesn't have a standard keyboard, msoft mouse, or a video card supported by the drivers used in these examples, you'll have to modify the examples so that they'll work in your environment.
To simplify the specification of file lists, all lists that start with /qnx4 should be changed to /nto for the Neutrino equivalent. |
When you run Photon in a desktop environment, you simply type ph, a script that does all the work for you. The ph script:
Once Photon is started, you run the applications you want using either the window manager or desktop manager.
In an embedded environment, you'll need to perform all these steps yourself manually. This has many benefits, because it lets you pre-define the minimum files needed for your system and exactly how each driver/application will start.
Here's an outline of the steps required to boot directly into Photon with your application(s) running.
Each of these steps requires certain files to be installed in your target system. By pre-determining exactly what graphics hardware you have and what fonts your application will need, you can keep the number of files (disk space) to an absolute minimum.
We'll go through all the steps in detail and discuss the files needed for each step. At the end of this process, you should know exactly what Photon files you'll need to run your embedded application.
The PHOTON_PATH environment variable is intended to hold the base directory of the Photon installation. By default, this directory is /qnx4/photon.
Under Photon 1.13 and later, "/usr/photon" is a link to "qnx4/photon." All the Photon related runtime components can be found in this directory. PHOTON_PATH points directly to the new path. |
Under Neutrino, the default directory is /nto/photon. This location is expected to hold at least the following subdirectories:
The PHOTON_PATH environment variable should be set.
If you don't need to pass any command-line arguments to the Photon server, it can be started as follows:
Photon &
If your embedded environment is touchscreen or pen-based, you can adjust the input values for pointer events by specifying the -D, -R, and -U options. For example, to prevent random changes in position because the size of a finger press is larger than a pixel, specify the -U option. |
The server must be located in the current PATH and the path must be defined before running the command. In QNX 4, this path is /qnx4/photon/bin. Example:
export PATH=:/bin:/usr/bin:/qnx4/photon/bin
Because Neutrino 1.01 doesn't support shared libraries, you most likely won't want to include
Photon executables in your boot image because it would make your boot image too large.
Instead, you'd load the executables from a filesystem at boot time using the
-c option of the mknto buildfile. For example:
-c $PHOTON_PATH/bin/program &If you do include any of the Photon executables in your boot image, you must also include the /nto/photon/bin path in MKNTOPATH. To do so, add the following line to your buildfile: MKNTOPATH=/usr/nto/bin:/usr/nto/sys:/nto/photon/bin |
/qnx4/photon/bin/Photon
Normally in a desktop environment, you would use the inputtrap utility to automatically generate the correct command line and to invoke the Input driver with:
Input kbd kb msoft -R uart
In an embedded system, the input devices are often found at unusual locations, or are incapable of PnP identification, or are simply not supported by Input. In addition, the inputtrap utility tends to be quite large and would only waste precious storage and memory in a constrained environment. For these reasons, an embedded developer will typically specify the command line to Input manually.
The Input utility is customizable. You can change the size of the memory footprint, or you can create a custom module to support new devices that Input doesn't currently support. For more detailed information, please contact your QNX Sales Rep.
/bin/Input
In Neutrino the name is different:
/nto/photon/bin/Devg.input
The font manager comes with a convenient tool (mkfontsys) for customizing the font environment of an embedded system. The mkfontsys utility launches the Font Installer application (fontcfg), where you specify your required fonts, extensions, mappings, etc. It then takes your specifications and places the font configuration files and all the selected fonts in the specified embedded font directory. Finally, it displays the command you must put in your boot file to run the font manager correctly.
This utility is given a target directory where the resultant font configuration is written, and optionally a source directory containing an initial font setup (/qnx4/photon/font by default). For more information, see the mkfontsys utility in the Applications and Utilities chapter.
The Photon font server for Neutrino is essentially the same as that for QNX 4.
For an embedded system, a number of decisions about the level of font support must be made: mainly, which fonts are required and whether or not scalable or anti-aliased fonts are needed. Support for scalable fonts costs 70K code plus data space, depending on the Portable Font Resource (PFR) files used and the cache sizes set.
The first step is to decide which fonts you need. Almost certainly the phcursor.phf (system cursors) will be needed.
Check the browser's configuration to see what it expects, and use these fonts, modify the configuration to reflect what you have installed, or use the fontmap file to map them at run time.
The mapping or substitution of font names is performed using the fontmap file or the Mappings section of the fontcfg utility. Refer to the "Mappings tab" section in the Font Support chapter for more details.
It's simplest to use the QNX 4 development system to configure the fonts for the embedded system, and to assemble the font data and configuration files in the appropriate Embedded File System (EFS) build image directory.
For example, suppose the root directory of this image is /usr/EKit/bsp/board/build/root (the real pathname will depend on your development environment).
Change your current directory to be the root of your build subdirectory:
cd /usr/EKit/bsp/board/build/root
Under here make a font subdirectory for your embedded system. For example:
mkdir -p my_directory/font
You can't run mkfontsys as root. |
From this subdirectory, you use the mkfontsys and fontcfg utilities to create an initial set of configuration files, edit and save the configuration, and then copy the necessary font files into the build image framework for collection by mkffs:
mkfontsys -fi my_directory/font
If you name your embedded font subdirectory with the same pathname as the global font files (i.e. /qnx4/photon/font), you'll overwrite the global font configuration files. |
This example creates an initial configuration, launches the fontcfg utility to allow changes to be made (-f), updates the font configuration files, copies any referenced .phf/.pfr files into the specified target directory, and emits the correct startup command for inclusion into the startup script for the font server (-i). For more information, refer to the mkfontsys utility documentation.
If your startup script invokes a specific font server (e.g. phfontphf or phfontpfr), you don't get the pre-processing of the fontopt file by the phfont utility - you must manually pass each option contained in that file on the command line. This is the reason for the -i option on the mkfontsys utility.
You can test the font setup prior to building the embedded image by restarting your desktop font server, pointing it at the new configuration (invoke phfont with the -d option to specify the font subdirectory from the build image); to revert to your original setup, just run phfont &.
The recommended font server for your system configuration is displayed on the final line of output when the -i option is used.
If the capabilities of the font server are known in advance (PFR/scalable/anti-alias support via phfontpfr or simple bitmap support via phfontphf), then the appropriate server may be started directly:
/qnx4/photon/bin/phfontphf &
If the font files aren't in the local image, the directory containing these files and the configuration should be specified with the -d command-line option (either to phfont or the real servers phfontpfr and phfontphf):
/qnx4/photon/bin/phfontphf -d /hd/my_directory/font &
You should use the font manager as shown in the final line of the output generated by the mkfontsys -i command.
Normally in a desktop environment, you'd make use of the Photon crttrap program - it can determine your display hardware and set up a configuration (trap) file for your hardware, where you can pick your desired graphics mode and resolution.
In an embedded environment, this information should be pre-determined. The process of switching into graphics mode and starting the graphics driver should be done manually by specifying the commands directly, without the use of convenience tools like trappers and display-configuration applications.
In many embedded environments, the Video BIOS isn't present because of cost considerations. The Video BIOS is responsible for initializing the video controller chip, and any other setup required by the video subsystem, as today's graphic controllers often need elaborate setup before they can even be used in VGA mode.
On the desktop, the BIOS POST code calls into the Video BIOS and the controller is set up at this time. When the modeswitcher is invoked, the video controller is in an initialized state, so the modeswitcher doesn't need to know how to set up the controller. To add to this, many of the desktop modeswitchers emulate the code in the Video BIOS to perform the mode switch.
In the embedded system that doesn't use a BIOS, the job of setting up the video controller falls to either the IPL code (init_hw2) or the modeswitcher. If the system will be used in only one mode, then the IPL code usually is modified to set up the video controller. If more than one mode is to be supported, a special modeswitcher that can completely set up the controller without using the resources in the Video BIOS is used.
The first graphics mode to try is VGA 16-color 640*480. Almost all graphics cards support this mode.
You can get the graphics card into graphics mode (specifically 640*480 16-color) in several ways.
The simplest way is to use vesabios.ms (under Neutrino: Devgm.vesabios) with the parameter -i0x12, which tells the modeswitcher to set Int10h video mode 12h.
The vesabios program will interpret the BIOS code and set the graphics controller registers. Once this program terminates, the graphics card should be in graphics mode.
Alternatively, the registers may be programmed directly with a program such as this:
#include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/inline.h> #include <errno.h> boutb( int n, int iport, int dport, char *v ) { int i; if (iport == (dport-1)) { for ( i = 0 ; i<n; i++) { outw( iport, i | ((*v++)<<8) ); } } else { for ( i = 0 ; i<n; i++) { outb( iport, i ); outb( dport, *v++ ); } } } char VGA12Gen[] = { 0xE3, 0x04 }; char VGA12Seq[] = { 0x1, 0x1, 0xf, 0x00, 0x06 }; // 5 char VGA12Crtc[] = { 0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0x0B, 0x3E, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0xEA, 0x8C, 0xDF, 0x28, 0x00, 0xE7, 0x04, 0xE3, 0xFF }; // 25 char VGA12GC[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F, 0xFF }; // 9 char VGA12Attr[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x01, 0x00, 0x0F, 0x00, 0x00 }; // 21 int main() { int q; q = inb( 0x3da ); q = q; // force compiler to perform the inb outb(0x3C0, 0); // disable palette outb(0x3C2, VGA12Gen[0]); outb(0x3D4, 0x11); outb(0x3D5, 0); // unprotect crtc regs 0-7 // Reset and set sequencer regs boutb(5, 0x3C4, 0x3C5, VGA12Seq ); // set misc out reg outb(0x3C2, VGA12Gen[0]); outb( 0x3c4, 0 ); outb( 0x3c5, 3 ); // seq enable // set all crtc regs boutb(25, 0x3D4, 0x3D5, VGA12Crtc); // set all graphics controller regs outb( 0x3CC, 0); outb( 0x3CA, 1); boutb(9, 0x3CE, 0x3CF, VGA12GC); // set all attribute regs q = inb(0x3DA); q = q; // reset flip/flop boutb( 21, 0x3C0, 0x3C0, VGA12Attr); outb( 0x3C0, 0x20 ); // enable palette return 0; }
You could also initialize the graphics card before QNX 4 or Neutrino starts by executing a software interrupt 10h with AH=0 and AL=0x12.
Now that the graphics card is in graphics mode, run a standard Photon graphics driver:
Or
Pg.flat -g640x480x8 -A0xFF000000,0x100000 -WB640 &
Or
Devg.flat -g640x480x8 -A0xFF000000,0x100000 -WB640 &
Here's what the options mean for the Pg.vga4 and Devg.vga4 drivers
Here are the man pages for:
QNX 4: | Neutrino: |
---|---|
vesabios.ms | Devg.vesabios |
vgadir.ms | Devg.vgadir |
Both of these modeswitchers need a BIOS.
For other modeswitchers, execute crttrap trap under QNX 4. |
vesabios.ms [-i modenum] [-r regs] [-a pc_addr] [-w] [-V] [-VVV] [-c con_name] [-c none] [-n crt_name] [-n none] Devg.vesabios [-i modenum] [-r regs] [-a pc_addr] [-w] [-V] [-VVV]
This modeswitcher uses the emu86 interpreter to execute BIOS code through the software interrupt 10h.
If both -c none and -n none are specified, the modeswitcher sets the graphics mode and exits; otherwise, the modeswitcher waits for the graphics driver to terminate and then restores the console to text mode. |
-r 0x4F02,0x102,0,0
is equivalent to:
-i 0x102
vgadir.ms [-i modenum] [-c con_name] [-c none] [-n crt_name] [-n none] Devg.vgadir [-i modenum]
This modeswitcher programs the standard VGA CRTC register to put the card into graphics mode.
If both -c none and -n none are specified, the modeswitcher sets the graphics mode and exits; otherwise, the modeswitcher waits for the graphics driver to terminate and then restores the console to text mode. |
/qnx4/graphics/drivers/Pg.xxxx
/qnx4/graphics/drivers/xxxx.ms
/qnx4/photon/palette/default.pal
where xxxx denotes the name of the graphics driver and the modeswitcher that your machine needs.
In Neutrino the names are slightly different:
/nto/graphics/drivers/Devg.xxxx
/nto/graphics/drivers/Devgm.xxxx
/nto/photon/palette/default.pal
This step is optional if only a single application is used, or if your embedded system doesn't require the services provided by the window manager.
The Photon window manager for Neutrino is essentially the same as that for QNX 4.
At this time, the only known unsupported feature is that multiple Ph_WM_CLOSE messages to a non-responding app will not raise a SIGHUP on that process (until support for a channel-"netkill"-style operation is added to the kernel).
The workspace configuration file ($HOME/.photon/pwm/pwm.cfg) is identical in format and may be modified dynamically using the Neutrino-ported version of pwmopts. It's possible to create a configuration file under QNX 4, with a desired set of options, and copy this file to the appropriate user directory of an embedded system. Alternatively, non-default options may be set with command-line options or through the PHWMOPTS environment variable.
The personalized PWM menu ($HOME/.photon/pwm/pwm.menu), if used, may pose a problem if commands are given as absolute pathnames referencing QNX 4 executables (the use of unqualified command names should be portable across systems, provided the PHOTON_PATH environment variable is consistent). The standard PWM menu invokes all commands from $PHOTON_PATH/bin. For embedded systems, note that this menu may be completely disabled with the -W command-line switch.
/qnx4/photon/bin/pwm
If your application is a single executable and doesn't require the window manager, then you can link your application static - you won't need the Photon shared library.
Because shared libraries aren't supported yet, your application must be statically linked. |
If you need the window manager or have more than one Photon program running, then it's best to use the Photon shared library.
Your application files.
If your application needs the Photon shared library:
/usr/photon/bin/Photon_slib11 (Photon 1.11 or earlier)
Or
/usr/photon/bin/phlib_s11 (Photon 1.12 or later)
The following are file lists and sample boot procedures for QNX 4 and for Neutrino - you'll need to modify them for your particular needs (e.g. specify the filesystem you're using, and so on).
Here's a sample list of files that you'll need for your embedded system:
/bin/Input /home/user1/.profile /myapplication /qnx4/graphics/drivers/Pg.cirrus /qnx4/graphics/drivers/cirrusbios.ms /qnx4/photon/bin/phfontphf /qnx4/photon/bin/pwm
The following files are generated by mkfontsys:
/qnx4/photon/font/fontdir /qnx4/photon/font/fontext /qnx4/photon/font/fontmap /qnx4/photon/font/fontopt /qnx4/photon/font/pcterm12.phf /qnx4/photon/font/pcterm14.phf /qnx4/photon/font/pcterm20.phf /qnx4/photon/font/phcursor.phf
# Sample Photon buildfile /boot/sys/boot $ 1 boot -v -p /boot/sys/Proc32 $ Proc32 -l 2 -b -n 20 -p 50 -s 8 -t 20 /boot/sys/Slib32 $ Slib32 /qnx4/photon/bin/phlib.s11 $ phlib.s11 # # Include the emulator only if running on a 386 without a 387 # /bin/emu387 $ emu387 /bin/Dev $ Dev -n 3 /bin/Photon $ Photon # # Start a flash filesystem for the rest of the code # ../efs/Efsys.explr2 $ Efsys.explr2 -r 1,89A0,2048k -m/ /bin/sinit $ sinit -s /bin/startup -i /bin/startup
/* startup.c */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/stat.h> #include <process.h> #include <sys/types.h> #include <signal.h> #include <sys/kernel.h> #include <sys/stat.h> #include <sys/qnx_glob.h> #include <sys/qioctl.h> #include <fcntl.h> #include <conio.h> #include <termios.h> char *param1[12]; char *env[20]; char iov[11]; void main() { pid_t mode_switch_pid; int i, have_com1, have_com2, net_console = 0; struct stat buf; for(i=0; i<24; ++i) putc( '\n', stderr ); // This code can be useful so that the prints go to the con1 screen // on the development PC if ( stat( "//1/dev/con1", &buf ) != -1 ) { close( 1 ); // By closing stdout and stderr, we know they close( 2 ); // will be the next ones opened. open( "//1/dev/con1", O_WRONLY ); open( "//1/dev/con1", O_WRONLY ); printf( "Output redirected to '//1/dev/con1'\n" ); net_console = 1; // We can be more verbose about boot progress } /* display progress message */ printf( "\nBooting...\n\n" ); /* setup environment */ env[0] = "PATH=./:/bin:/etc:/qnx4/photon/bin"; env[1] = "HOME=/home/user1"; env[2] = "PHOTON=/dev/photon"; env[3] = NULL; /* setup startup directory */ chdir( "/home/user1" ); /* wait for Photon to start */ while(access("/dev/photon", F_OK)) sleep(1); /* bitmap only font server */ param1[i=0] = "/qnx4/photon/bin/phfontphf"; param1[++i] = "-Enormal"; param1[++i] = NULL; run_bg(param1,env,1); sleep( 2 ); /* run the Input manager (options are sample only) */ param1[i=0] = "/bin/Input"; param1[++i] = "kbd"; param1[++i] = "kb"; param1[++i] = "msoft"; param1[++i] = "-R"; param1[++i] = "uart"; param1[++i] = NULL; qnx_spawn(0, NULL, 0, 11, -1, 0, param1[0], param1, env, NULL, -1); /* run modeswitch - this is a Cirrus logic example */ param1[i=0] = "/qnx4/graphics/drivers/cirrusbios.ms"; param1[++i] = "-i0x101"; param1[++i] = "-A0x000A0000"; param1[++i] = "-S0x00010000"; param1[++i] = "-M0x0013,0,0,0,0x00080000"; param1[++i] = "-RL"; param1[++i] = "-cnone"; param1[++i] = NULL; mode_switch_pid = run_bg(param1, env, 1 ); sleep( 2 ); // This time needed for modeswitcher to initialize /* start window manager - optional */ param1[i=0] = "/qnx4/photon/bin/pwm"; param1[++i] = "-Wh"; param1[++i] = NULL; run_bg(param1,env,net_console); /* start graphics driver */ param1[i=0] = "/qnx4/graphics/drivers/Pg.cirrus"; param1[++i] = "-g640x480x8"; param1[++i] = "-A0xA0000,0x10000"; param1[++i] = "-WB640"; param1[++i] = "-WM0x0013,0,0,0,0x00080000"; param1[++i] = NULL; run_bg(param1,env,net_console); /* launch your application here */ param1[i=0] = "/myapplication"; param1[++i] = NULL; run_bg(param1,env,net_console); sleep( 5 ); kill( mode_switch_pid, SIGTERM ); // Don't need modeswitcher anymore if ( net_console ) printf( "\nStartup finished\n\n" ); exit(0); } int run_bg(char *cmds[], char *arge[], int print_something) { pid_t pid; if (print_something) { printf("Starting '%s'\n",cmds[0]); fflush(stdout); } pid = qnx_spawn(0, NULL, 0, -1, -1, _SPAWN_NOZOMBIE, cmds[0], cmds, arge, NULL, -1); if (pid == -1) { perror("\nCould not start! Image may be corrupt - please re-install...\n"); sleep(5); } return(pid); }
Here's a list of files that you'll need to build a Neutrino system.
The following files in /bin are the Neutrino executables in the /bin directory on the hard disk.
/bin/Devc.pty /bin/esh /home/root/.profile /nto/graphics/drivers/Devg.vga4 /nto/graphics/drivers/Devgm.vesabios /nto/photon/bin/Devg.input /nto/photon/bin/Photon /nto/photon/bin/phfontpfr /nto/photon/bin/pterm /nto/photon/bin/pwm
The following files are generated by mkfontsys:
/qnx4/photon/font/fontdir /qnx4/photon/font/fontext /qnx4/photon/font/fontmap /qnx4/photon/font/fontopt /qnx4/photon/font/pcterm12.phf /qnx4/photon/font/pcterm14.phf /qnx4/photon/font/pcterm20.phf /qnx4/photon/font/phcursor.phf
# Sample Neutrino buildfile startup.pc ProcNto # # Start a Filesystem Manager # Devb.eide -m/ & waitfor /nto # # Start the Pseudo Terminal Manager # -c /bin/Devc.pty & waitfor /dev/ptyp0 # # Step 1 # export PHOTON_PATH=/nto/photon # # Step 2 # -c $PHOTON_PATH/bin/Photon & waitfor /dev/photon # # Step 3 # -p11 -c $PHOTON_PATH/bin/Devg.input kbd kb msoft uart & # # Step 4 # -p12 -c $PHOTON_PATH/bin/phfontpfr -Enormal & waitfor /dev/phfont # # Step 5 # # the modeswitcher (Devgm.vesabios) must not be run in the background (&) -p12 -c /nto/graphics/drivers/Devgm.vesabios -i0x92 -p12 -c /nto/graphics/drivers/Devg.vga4 -g640x480x4 -A0xA0000,0x10000 -WB80 & # # Step 6 # export SHELL=/bin/esh export LOGNAME=root export HOME=/home/root export PATH=/bin:$PHOTON_PATH/bin -c $PHOTON_PATH/bin/pwm & # # Step 7 # -c $PHOTON_PATH/bin/pterm &
The following are observations that some customers have encountered when moving Photon to an embedded system.
The following flash filesystem properties will affect how you configure Photon:
$(ABOBJ) $(MYOBJ) $(LD) $(LDFLAGS) $(ABOBJ) $(MYOBJ) -M -o mine usemsg mine ../Usemsg phabbind mine $(ABMOD)
to:
$(ABOBJ) $(MYOBJ) $(LD) $(LDFLAGS) $(ABOBJ) $(MYOBJ) -M -o mine usemsg mine ../Usemsg phabbind mine.res $(ABMOD)
You'll also need to export the AB_RESOVRD path variable if the resource records aren't in the same directory as the executables. This avoids searching the directory containing the executables.
The config file routines aren't compatible with the flash filesystem. |
Many embedded systems lack components that are typical on a desktop machine. Here are a few items to watch for.
Here are some miscellaneous considerations:
Photon -D1000 &