Texas Instruments DM6437EVM Host-side Demo Application (v0.5) ====================================================== This program runs on a host machine (typically a PC running Windows or Linux) and connects over the network to a DM6437EVM board, running the target-side demo application, in order to let the user control the target behavior and to stream audio and video files to and from the target. The program is written in ECMAScript -- popularly known as JavaScript -- and requires no development tools other than a text editor. You run the program by running the .bat file located in this directory. (To learn how to run the program in a graphical debugger, please look at the .bat file itself and comment out the appropriate line.) We should note that the core JavaScript language, used for this program, has nothing to do with Web pages; it is a general purpose scripting language like Perl or Python. JavaScript is not Java, but it lets a developer use existing body of Java libraries without requiring the developer to be a Java programmer. Three such libraries are used by this script: 1) Networking library 2) File I/O library 3) GUI library These libraries are part of the XDC toolset, used primarily for development of target software, and are included in the DM6437EVM tools installation. (An alternative scripting language, Perl, while more widely used, is considered less coder-friendly and would require a separate Perl tools installation. Another alternative -- not a script, but an executable developed in MS Visual C++ -- is less suitable for rapid development of applications like this one, and would require installation of licensed MS tools.) Structure of the application ---------------------------- The application is split into four modules: GUI control, Target control, File I/O, and networking (communication): Main.js <-----+------ Dm6437evm/Rpc.js <------+-- Dm6437evm/Ipc.js (GUI) | (target control) | (networked comm w/target) | | `------ Dm6437evm/Fileio.js <---' (File I/O) The main script, Main.js, is in charge only of the GUI: it draws buttons and input fields and listens for user's actions to send an appropriate command to the target (start playing, stop playing, switch mode etc.). It also starts a separate thread to run Fileio functions and thus serve the target with input and output audio/video files. The Rpc -- "Remote Procedure Call" -- module provides the GUI script with several functions, of which the important ones are: rpc.connect( ipAddr ) -- connects to the target at ipAddr rpc.paramGet( paramName ) -- gets a target state parameter, e.g. "mode" rpc.paramSet( paramName ) -- changes state, i.e. sets "mode" to "decode" rpc.controlPlay/Stop() -- starts/stops target's audio/video processing (paramGet() and paramSet() read and write target's state variables -- like I/O registers -- and what those are is defined by the target. The demo app accesses a few like "runFlag" -- is the demo running or stopped, "audioEnableFlag" -- is audio enabled, "mode" -- what mode it is running in, etc.) The Fileio module has an even simpler API: fileio.connect( ipAddr, port ) -- connects to the target's fileio port fileio.recvCmd() -- receive File I/O command from target fileio.dispatchCmd() -- run received File server cmd, eg. "read" (The target sends commands like "open file such and such", "read so and so many bytes from the file" to the host but the GUI script does not care what those are. Its only duty is to run them from a separate thread.) The Ipc module takes Rpc's and Fileio's data structures, serializes them and sends or receives them to or from the target over the network. The API -- not directly used by the GUI script -- looks like this: ipc.connect( ipAddr, port ) -- connects to the port at the given address ipc.writeWord( word ) -- writes a 32-bit word to the target ipc.readWord() -- reads a 32-bit word from the target ipc.writeString( string ) -- passes on a text string to the target ipc.readString() -- reads a text string from the target. For details about how Rpc, Fileio, and Ipc (Inter-Process Communication) modules work, please refer to their scripts directly. They follow a certain protocol for exchanging information between the host and the target. It is unlikely you will have to change any of those modules: if you want to modify the host and the target demo application for your own needs, on the host side you likely need to change only the GUI script -- add or remove some buttons and drop-down lists, and read and write some old and some new target state parameters, as defined by your target application. A note about ECMAScript (JavaScript) ------------------------------------ JavaScript's syntax allows C programmers to understand, and to a degree modify, programs written in this language even if they have never seen this language before. To learn how to make nontrivial modifications, or to write new JavaScript programs, please refer to this Web page: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide We believe it is not necessary to read it in order to understand the rest of this document. C programmers typically "get" patterns of JavaScript scripts quickly and can replicate them without formally learning the language. Also note that part of our JavaScript script is using Java library classes. This requires knowing the APIs of libraries in question, however using Java classes from JavaScript is much easier than writing Java programs in Java. (We do not do that here.) The main application script, Main.js ------------------------------------ The flow of the main script can be described in short as: initialize target communication modules, draw buttons and other widgets on the screen, assign a function to each button, and loop, waiting for the user to close the window; meanwhile, whenever the user clicks on a button, the function we assigned to the button runs -- typically sending some message to the target, e.g. "connect" or "start playback". In more details (and you can look at the code in parallel), Main.js flows like this: .---- global ---------------------. | - load target comm. scripts | | - define global variables | | - call main() | `---------------------------------' | | .---- main() ---------------------. `-->| - create target comm. objects | | - create GUI objects | | - call layoutWidgets() | | - call setEventListeners() | | - loop till the user closes app | `---------------------------------' | | .---- layoutWidgets() --------------. +--->| - place all controls (buttons, | | | text boxes, groups of controls) | | | on screen | | `-----------------------------------' | | .---- setEventListeners() ----------. `--->| - specify functions to be called | | for each button and other | | controls | `-----------------------------------' | | .---- eventFxnBtnConnect() -----. +-->| - connect to the target | | | - read target state variables | | | - set state of widgets based | | | on target state | | | - start the FileIo thread | | `-------------------------------' | | .---- eventFxnBtnDisconnect() --. +-->| - disconnect from the target | | `-------------------------------' | : ... etc. 1. First we load the two scripts, Rpc.js and Fileio.js, that implement communication with the target, i.e. sending messages to it over the network. They let us create target communication objects later on in main(). 2. We define global variables used in this script (Main.js). Some of them are references to library objects, others we define as null and initialize later on. First we create aliases for the GUI Java libraries ("classes") we use. We do not use the standard Java GUI library but something called "SWT" (Standard Windowing Toolkit), made by IBM for its development environment Eclipse. SWT works much faster and looks "normal" -- it's impossible to say that this application wasn't written in MSVC++ or Visual Basic just by looking at its screen. Next we define the "debugFxn" variable, to turn debugging on or off. This variable is really a function, but in JavaScript a variable can be of any type, including a function! So if a script line 'debugFxn( "Debug: File I/O thread started" );' somewhere down the road executes, what it will do depends on how we defined "debugFxn". If we defined "var debugFxn = print;" -- and print() is a built-in function -- the message will appear. If we defined "var debugFxn = function() {}", all calls to debugFxn() will be silent. Global variables "rpc" and "fileio" for target communication, and "display" and "shell" that refer to the system screen and our application's window are set to null and will be initialized in main(). Variable "myWidgets" is a hash-table -- an array whose elements are accessed by name instead of by index -- and initially empty, but will later be filled with references to various screen controls. For example, we will when appropriate read what the user has typed in the "txtIP1" box -- the box with the first part of the target IP address -- by calling 'myWidgets["txtIP1"].getText();' or, qw;ll check if he selected the "Encode" video mode with 'if (myWidgets["radioEncode"].getSelection() == true)'. 3. The final outside-of-any-function statement executed in this script is main(), which calls our function main() defined below. In JavaScript, a variable/function is in the scope if it is defined anywhere in the scope -- does not have to be defined before it is referenced. The main() function first creates an Rpc object, from the Rpc.js module. After the "rpc" variable is initialized, any function in the script can connect or send a message to the target, like rpc.connect( "168.132.141.15" ) or rpc.controlPlay(). Similarly with fileio and Fileio.js -- for details of Rpc and Fileio APIs refer to their scripts. After that, the main() function creates "display" and a "shell", initializing these global variables; "display" is the whole screen, "shell" is where buttons and other widgets are drawn. Then it calls the function that draws -- lays out -- the widgets, and another that assigns "event listener" functions that are called when a button is pressed. After that main() calls a function that grays out everything except the "connect" button's area, because the application has just started and allowing the user to press "play" without even connecting first would be wrong. The last part of the main() function is the standard loop for SWT GUI programs that refreshes the screen and calls event functions when a button click (or some other widget event) occurs, leaving the loop when the user has closed the main window. Drawing screen controls ("laying out widgets") ---------------------------------------------- Since we don't use a graphical editor to draw widgets on the screen, we have to lay them out within the script in a recipe-like fashion. That means that for our application window (the "shell") we say which groups of widgets are drawn next to each other and which are under others. Then in each group of widgets we specify how widgets inside it are laid out -- next to each other or some under others, and whether there are any further subgroups contained within the group. This will become obvious in a moment. Meanwhile let's clarify some terms -- a "widget" is a common name for any singular element like a button, a text field, label, drop-down box, etc., or a container for other elements, i.e. a "group" of widgets. These containers are special because they can contain other widgets -- simple elements and other containers. It is worth noting that we use two kinds of containers: "Groups" and "Composites", the only difference between them being that Groups have visible frames around widgets contained in it, while Composites are not visible. One final thing to know about containers is that we use so called "grid" layouts to specify how widgets inside them are laid out. Grids are matrices -- which can and often have only one row or only one column -- where each grid cell contains a widget (which, remember, can be another container with its own grid), and each grid cell can be aligned left or right or centered. An example to explain it all soon follows. A grid's column or row width or height can be controlled, but we usually don't have to: we can set the size of, say, a button inside it in pixels and the grid's column adapts automatically, expanding to match the widest element in the column. And often we don't have to do even that: when we put some text on the button, say " Connect ", the system calculates how wide the button should be for the text to show, and everything automatically fits. We can also control minor properties of containers like "margin width" or "vertical spacing" or "make all columns equal width" to create professional-looking applications. Let us now take a look at an example. Run the demo app and look at the "Connection" frame. It has several buttons and text fields, one drop-down list (called a "combo box"), and a few labels, looking on the screen like this: .-- Connection ----------------------. | | | Status [____NOT CONNECTED____] | | | | IP Addr [146].[252].[191].[38 ] | | | | (Discover) [____________________v] | Legend: | | [____] - text field | (Connect) (Disconnect) | (____) - push button | | [___v] - drop-down combo box `------------------------------------' The "Connection" frame is a cell in a larger grid, but it could be the only thing on the screen -- we'd draw it all the same. We need one container, "Group" because we want a visible frame, whose text will be "Connection", and before we lay out labels, text fields etc. inside it, we say that the group uses a grid with 2 columns in each row. The challenge, however, is that we have two widgets per row in all rows except the second -- the IP address takes 7 widgets: four text fields and three labels (each containing just the "." as its text). (A row is filled by adding an element to the container. When the newly added element exceeds the number of columns in the current row, it spills over into the next row.) So we need to treat the IP address set of fields differently: we need to lump up all of its widgets into an invisible container -- a "Composite", and put that composite in the second cell of the second row. Then, as far as the "Connection" group is concerned, it sees only two elements in each row. The Composite for the IP address we'll declare to have 7 columns per row, and then we'll alternate the for text fields and three "." labels to fill in its single row. That gives us the following layout: +- - - Connection - - - - - - - - - - - - - - - - - - - - - - - + : Status : [ NOT CONNECTED ] : +- - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - + : : +- - - -+- -+- - - -+- -+- - - -+- -+- - - -+ : : IP Address : : [146] : . : [252] : . : [191] : . : [38 ] : : : : +- - - -+- -+- - - -+- -+- - - -+- -+- - - -+ : +- - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - + : ( Discover ) : [ v] : +- - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - + : ( Connect ) : (Disconnect ) : +- - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - + Dotted lines indicate invisible grids. The outer grid has rows with 2 columns each, and the inner grid in the second row has one row with 7 columns. Now let's look at the script code that does this layout. We define two handy functions, WID() and END() (almost like macros) that make the code look more readable. WID(<new widget>) adds the new widget to the current widget, referenced with variable $w, and makes the new widget current until a matching END() is called. WID() also returns the reference to the newly created widget object, so that we can store it in myWidgets[] hash table. We only need references to a few widgets that we later want to somehow control; usually we keep only the references for the input fields and buttons. The following code creates the "Connection" frame inside the current widget (which happens to be the larger grid containing all other big frames in the screen, but that's irrelevant), and adds the first two elements, i.e. completes the first row: WID( widgets.Group( $w, SWT.NONE ) ); $w.setText( "Connection" ); // $w = current widget var gl = layout.GridLayout( 2, false ); $w.setLayout( gl ); WID( widgets.Label( $w, SWT.NONE ) ); $w.setText( " Status" ); END(); w["txtStatus"] = WID( widgets.Text( $w, SWT.BORDER | SWT.CENTER | SWT.READ_ONLY ) ); $w.setLayoutData( GD( 164, SWT.DEFAULT ) ); END(); So we create the "Connection" group, set its label text appropriately, and make it have a Grid Layout of 2 columns per row. The function ("constructor") that creates a new layout has signature, GridLayout( <number of columns>, <make columns equal width> ). All widgets, when created, as a first argument take the reference of the containing widget. With our macro-like functions it is always "$w". The second argument to a widget is usually some attributes, e.g. whether it has a border, how is its text justified, etc. We then add a label, "Status", and create a text box to contain connection status. The connection status text could be placed in another label like "Status", because we can change the text of any widget dynamically, but we use a text box for an aesthetic effect. We make the textbox have a border, have its text center-aligned, and be read only; we also record its reference in myWidgets["txtStatus"], where "w" is a short alias for "myWidgets". In the next line, we say that the grid cell where the text box is should be 164 pixels wide and have the default height (determined by the textbox's font and font size). So how do we know which widgets are available, and which properties they have? The answer lies at this page: http://www.eclipse.org/swt/widgets. It has a screenshot of each widget, its API reference, and example code snippet. The rest of the code lays out the "IP address" label, the invisible 7-column "Composite" with its IP address fields and labels, the "Discover" button and combo box, and the "Connect" and "Disconnect" buttons. Note how the END() function closes the definition of a widget: WID( widgets.Composite( $w, SWT.NONE ) ); var gl = new layout.GridLayout( 7, false ); gl.marginWidth = 0; $w.setLayout( gl ); w["txtIP1"] = WID( widgets.Text($w,SWT.BORDER|SWT.CENTER )); $w.setLayoutData( GD( 20, SWT.DEFAULT ) ); END(); WID( widgets.Label( $w, SWT.NONE ) ); $w.setText( "." ); END(); w["txtIP2"] = WID( widgets.Text($w,SWT.BORDER|SWT.CENTER)); $w.setLayoutData( GD( 20, SWT.DEFAULT ) ); END(); WID( widgets.Label( $w, SWT.NONE ) ); $w.setText( "." ); END(); ... etc, for IP3 and IP4 END(); w["btnDiscover"] = WID( widgets.Button( $w, SWT.PUSH ) ); $w.setText( " Discove&r " ); END(); w["cmbDiscover"] = WID( widgets.Combo( $w, SWT.READ_ONLY ) ); $w.setLayoutData( GD( 158, SWT.DEFAULT ) ); END(); w["btnConnect"] = WID( widgets.Button( $w, SWT.PUSH ) ); $w.setText( " &Connect " ); END(); w["btnDisconnect"] = WID( widgets.Button( $w, SWT.PUSH ) ); $w.setText( " Disc&onnect " ); END(); END(); The indentation before WID() and END() functions lets us better see who contains whom. Note again that it is not necessary to use WID() and END(), we use them because they improve readability of the code. (If you place a widget in the wrong container, you'll often get drastically different screens.) Reacting to button clicks ("setting widget event functions") ----------------------------------------------------------- The setEventListeners() function assigns a function to every widget that the user can click on. The first such assignment you will see -- remembering that "w" is an alias for the "myWidgets" hash table -- is w["btnDiscover"].addListener( SWT.Selection, eventFxnBtnDiscover ); That means, when the user presses ("selects") the "Discover" button, our eventFxnBtnDiscover() function is to be called. If you look at the body of that function further below, you'll see the expected: it calls the rpc.discover() function which returns zero or more IP addresses of targets who run the demo (determined by their response to a specific broadcast message, see Rpc.js for details), and then fills in the w["cmbDiscover"] drop down list with those addresses and copies the first in the list into the "IP address" input fields. If at least one is found, the user can click on the "Connect" button afterwards for the first found target, or select a different one from the drop down list. However, in the setEventListeners() you will see that events for which we have simpler actions can be defined right on the spot. Take this one for example: w["btnInVideoBrowse"].addListener( SWT.Selection, function( event ) { var dialog = new widgets.FileDialog( shell ); var fileName = dialog.open(); if (fileName != null) { w["cmbInVideo"].add( fileName, 0 ); w["cmbInVideo"].select( 0 ); w["txtInVideoSizeKB"].setText( Math.floor( new java.io.File( fileName ).length() / 1024 ) ); } } ); This is an event function for the "Browse for Input Video file" button. It opens a new file dialog, and, if the user has selected a file, it adds the file to the top of the "input video file" drop-down list and makes it the first choice. Then, while we're at it, we read the file's size and show it in the "txtInVideoSizeKB" read-only input video file size textbox. (The function call java.io.File(fileName).length() returns the file size in bytes or 0 if the file doesn't exist.) It is these versatile Java library functions like this that make scripts short. Exceptions ---------- (C++ and OOP developers can skip this section) If you look at the APIs provided by target communication modules Rpc.js and Fileio.js (and the one they use, Ipc.js), you will see that no function returns success or failure. Instead, if en error occurs, an /exception/ is trown, either by a system module that the function uses, or the function itself if it detects some irregularity. That exception travels up the call stack until someone catches it -- or, if no function catches it, the application exits in an error with its call stack listed. That frees us from having to check return status on every other line of code. Instead, we simply catch the exceptions -- by enclosing function(s) whose execution can result in an exception -- in what is called a "try-catch" block: try { function(s) called here } catch (e) { // we're here only if an error occurred print ("error occurred, reason: " + e) } You will see code like this in the Main script only and rarely elsewhere. Threading --------- Our application is a multi-threading one. The main thread runs the main() function, looping to see if display should be refreshed, dispatching any events, and exiting when the window is closed. Each of our widget event functions, called by the SWT GUI system, runs in the context of that main thread. So the main application thread is in charge of all the GUI. Another thread we run is the FileIO thread. When the main thread connects to the target, it soon after fires up a separate thread that also connects to the target but on a different port, and the new thread becomes the target's file server. The new thread reads input files from the disk and sends audio/video data to the target, and receives data from the target and writes output files. We also use an occasional timer thread, to update a counter or periodically check for target status. Creating a new thread in JavaScript is simple. For example, in code like this, print( "Hello" ); new java.lang.Thread( new java.lang.Runnable() { run: function() { print( "cruel" ); } } ).start(); print( "world" ); the main thread prints "Hello", then creates a secondary thread which will print "cruel" when runs and starts it, and finally prints "world". The new thread may print its message in between the two main thread's messages or after. The new thread also could have a loop, perhaps sleeping every now and then by calling java.lang.Thread.sleep(<milliseconds>) or yielding the CPU with java.lang.Thread.yield(). All of this is standard for any threading system; the difference is only in ease of thread creation. All threads can read and write all the script's global variables; for example, the thread running Fileio function loops while "stopFileIoThreadFlag" global variable is false; this variable is set to true by the main() function at its exit. Moreover, threads whose "run" functions are defined inline -- as in the example above -- have access to all the variables in the scope of the function which defined them. That lets us define quick, short thread functions right on the spot, without having to define separate functions and pass on piles of variables. The only exception to this idyllic picture comes when different threads need to access GUI objects: "shell" and "myWidgets[]" in our case. They cannot be accessed directly from a thread other than the main thread, i.e. this would fail: // main thread w["myText"].setText( "lovely" ); new java.lang.Thread( new java.lang.Runnable() { run: function() { // new thread print( "Hello " + w["myText"].getText() + " world" ); } } ).start(); The main thread sets the text of the "myText" text widget and creates the new thread. But the new thread is not allowed to call the "getText()" method of the w["myText"] object. It must goe around this limitation by calling a method "display.syncExec()" or "display.asyncExec()" and specify a thread-like code within it to access the widget: w["myText"].setText( "lovely" ); new java.lang.Thread( new java.lang.Runnable() { run: function() { var myTextContents; display.syncExec( new java.lang.Runnable() { run: function() { myTextContents = w["myText"].getText(); } } ); print( "Hello " + myTextContents + " world" ); } } ).start(); The new thread now makes a blocking call to the display.syncExec() method that creates yet another thread, but now one that is allowed to read the widget. The newest thread reads the contents of the text widget, stores it in the second thread's local variable, "myTextContents", and exits. Then the second thread continues and goes on to print the contents of its local variable, "myTextContents", knowing that it has been set to reflect the contents of the widgets that it couldn't access directly. You will notice that we use display.asyncExec() in a couple places in Main.js. One such example is the Fileio thread: the main thread in Main.js spawns a new thread to be a Fileio server upon connection to the target. The new thread calls fileio.recvCmd() and fileio.dispatchCmd( cmd ) methods in a loop. The later one can be (and often is) a write request from the target -- the target wants to write data to a file or text on the console. If you look at Fileio.js, you will see that the function that implements write also calls a method "showWriteInfo( filename, newFileSize )". This method is by default a dummy function -- but the fileio thread in Main.js sets this method to update the file size textboxes on the screen. And this is where display.asyncExec() comes to play: Fileio's showWriteInfo is effectively a callback, called from another thread, and set to update some widgets on the screen. We now know that is not allowed, so in Main.js' fileio thread we set the callback not to be a simple update of the text, but we wrap it around display.asyncExec() and it all works. Why didn't we use display.syncExec(), i.e. the blocking version? The answer is, we don't want the fileio thread to be blocked on what's a less important task -- updating the widgets -- and be less responsive to the data the target sends. This problem would get compounded if the main thread happened to be doing a blocking call itself, like rpc.controlStop() which exchanges some messages with the target. Then the Fileio thread would unnecessarily wait for that blocking call to complete just so it can finish updating some not-so-important widget. This is why display.asyncExec() is the right method to use. Final note ---------- One of the biggest powers of JavaScript comes from the fact that functions can be defined (and even generated!) on the fly. Any syntactically valid text can be turned into a function. Another is that variables can be of any type, and fields in a structure like hash-table can be added on the fly and be of any type. Both these features carry a danger with them: wrong functions can be constructed and we won't know until they run, and typos can happen and a wrong field or value will be set in a hash-table object without anyone complaining. With traditional languages, the compiler prevents some of these errors, but often also we cannot know if the value the compiler accepted is OK until we run the program. A third powerful feature is integration with Java classes and ability to use them easily. And since Java classes can be made that access native code like driver DLLs, it would not be difficult to create such wrapper Java classes that would let you call low-level driver functions from a JavaScript script. Information resources for ECMAScript (JavaScript) and libraries --------------------------------------------------------------- JavaScript programs can readily use Java libraries just by knowing their APIs. Here are the resources for the libraries used in this application: - JavaScript language: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide - Java Networking: - overview: http://java.sun.com/docs/books/tutorial/networking/index.html - sockets: http://java.sun.com/j2se/1.4.2/docs/api/java/net/Socket.html - Java File I/O: http://java.sun.com/docs/books/tutorial/essential/io/ - GUI: - widgets snapshots and APIs: http://www.eclipse.org/swt/widgets/ - programming SWT: http://www.developer.com/java/other/article.php/3330861Download Driver Pack
After your driver has been downloaded, follow these simple steps to install it.
Expand the archive file (if the download file is in zip or rar format).
If the expanded file has an .exe extension, double click it and follow the installation instructions.
Otherwise, open Device Manager by right-clicking the Start menu and selecting Device Manager.
Find the device and model you want to update in the device list.
Double-click on it to open the Properties dialog box.
From the Properties dialog box, select the Driver tab.
Click the Update Driver button, then follow the instructions.
Very important: You must reboot your system to ensure that any driver updates have taken effect.
For more help, visit our Driver Support section for step-by-step videos on how to install drivers for every file type.