Visual Universal Remote Control

Document Sample
Visual Universal Remote Control Powered By Docstoc
					Visual Universal Remote Control

Authors: Tyson Gilberstad Owen Taylor Jamie Aitken

Engl 271

Submitted to: Joe Benge, Mel Dundas

March/15th/2001

Executive Summary
Most universal remote controls have their buttons in fixed locations, and are programmed to specific functions (e.g. “channel up”). The visual universal remote control (VURC) that we’ve developed uses a graphical screen to display “virtual” buttons. The screen responds to touch on the button locations and controls the remote device (VCR, TV, stereo). As the buttons are not in fixed locations, the user can customize the screen to display the buttons in any location desired. The user configures the VURC through a PC application program dubbed “VURC Editor”. This program allows the user to define button locations and their functions, as well as create multiple menus on the remote. Once the menus have been created, the editor downloads them to the VURC through the serial port, and the remote is ready to use. The specification was reduced from it’s original design, as time constraints made it impossible to complete the required tasks.

i

Table of Contents
TITLE PAGE EXECUTIVE SUMMARY ………………………………………………………………..i TABLE OF CONTENTS………………………………………………………………….ii LIST OF FIGURES AND ILLUSTRATIONS…………………………………………...iv INTRODUCTION…………………………………………………………………………1 General System Description System Capabilities Ubicom SX52BD Micro-Controller MMC Memory Map and Menu Data Members a) Individual Button Information: Menu Links and IR Codes b) Visual Bitmap c) Menu Description d) Functional Bitmap e) Button Placement Information 5) Interfaces a) SX52BD !SPI" 16MB Sandisk MMC i) What is an MMC Card? ii) Electrical Interface iii) Command Structure iv) Relevant Theory v) Problems Encountered vi) Results b) SX52BD !6800 Family Timing" Epson SED1335F0A LCD Controller i) What Does the SED1335F0A Controller Do? ii) Electrical Interface (1) LAM Cable (2) Surfboard (3) LCM Interface iii) Timing Requirements iv) Command Set v) Problems Encountered vi) Results c) SX52BD !serial" Burr Brown ADS7843 Touchscreen Controller i) Electrical Interface ii) Code Description iii) Relevant Theory d) SX52BD !UART2" PIC16F874 IR Module i) Communication from SX52BD ii) Set-up Data iii) Electrical Interface iv) Results e) SX52BD !UART1" VURC EDITOR 6) Hardware Design 1) 2) 3) 4) 2 2 2 3 3 3 4 4 5

6 6 7 7 7 7 8 8 8 9 10 10 10 10 10 11 11 11 11 12 12 12

ii

a) IR Module b) Switching Power Supply c) Schematic Capture d) PCB Layout e) Footprint Library 7) Software Design a) Section Overview b) What is the VURC Editor? c) Initial Proposal d) Functional Description for VURC Editor Software e) Modules Included in the VURC Project Group f) What is a VURC menu? g) Creating Menus for the VURC h) What is a button? i) Creating a New Button j) Future Software Improvements CONCLUSIONS RECOMMENDATIONS BIBLIOGRAPHY GLOSSARY OF TERMS APPENDIX A: Visual Universal Remote Control System Block Diagram APPENDIX B: Switching Power Supply Circuitry APPENDIX C: Epson 1335F0A Command Set and Description APPENDIX E: Scenix SX52BD Code APPENDIX D: VURC Editor Flowcharts a) Main Program b) Creation of a New Screen c) Creation of a Button d) Placing a Button APPENDIX F: VURC Editor C++ Code APPENDIX G: PIC IR Code

13 13 13 14 14 14 14 14 15 15 17 17 17 17 18 19 19 21 22 25 26 27

85 86 87 88 89 144

iii

List of Figures and Illustrations
Figure 1: Electrical Interface between SX52BD and MMC card 6 Figure 2: SPI Command Structure for MMC card 7 Figure 3: Schematic Capture of Surfboard Designed to Enable Wire-wrapping to pins of 26-pin Surface Mount LAM Cable Connector (Used in interface between SX52BD and LCM) 8 Figure 4: Surfboard designed to interface SX52BD to LCM 9 Figure 5: Schematic interface between SX52BD and LCD via 26-pin surface mount LAM Cable Connector 9 Figure 6: Schematic Diagram of IR Module 13

iv

Introduction
The Visual Universal Remote Control project was done under the supervision of the Camosun College Electronics Department for credit in the Elex 290 project course. Although there are many different universal remote controls for use on infrared devices (such as TVs, VCRs, and stereo systems), only one or two have incorporated a touchscreen and LCD display to create a customizable remote control. The VURC was specified to create a remote that was different from your average remote control. This project was conceived to create a product that would have some use to a potential consumer, as if it were designed and marketed by an electronics company. The design had to expose the project group to embedded systems design and programming, as well as to give the project group exposure to sourcing parts. The project group was required to come up with an initial specification and a timeline for completing the different aspects of the project within a 3 month time period. The budget for the project was $250. The project group was then responsible for completing the specification as closely as possible given the time and cost constraints.

1

General System Description
The Visual Universal Remote Contol (VURC) is meant to be a stand-alone entertainment solution to all your Infra-Red (IR) needs. With it, you can control any IR device. It comes complete with a programmable touch-screen for functionality and ease of use. The VURC is powered by 4 “AA” batteries that only need to be replaced a couple times a year making it perfect for controlling your entertainment centre, whether it be for your stereo, your TV, your VCR, or your DVD player. Through out all of those boring old remotes; replace them all with the VURC!

System Capabilities
The VURC is unique in its capabilities. You can add as many IR devices as you like simply by programming the unique IR codes for the devices you wish to control into the VURC EDITOR (a windows based application for Windows 9x). You can customize the looks of each individual screen you add to the VURC using the VURC EDITOR. Simply connect the VURC to a PC COMM port as laid out in the user’s manual, and reprogram the VURC as many times as you wish.

Ubicom SX52BD Micro-Controller
The heart of the VURC consists of a Ubicom Ltd. SX52BD micro-controller. The SX52BD micro-controller was selected for its numerous I/O’s (40 in all), its extensive program memory (4096 words), and its fast instruction execution rate (one instruction executed every 20ns when running the controller off a 50MHz clock in turbo mode). Because the design of the VURC requires two UART channels, an existing Dual UART Virtual Peripheral (VP) produced by Ubicom was utilized. The advantage of using a VP is that a VP is run entirely in the Interrupt Sub Routine (ISR), which means that it does not affect any of your mainline code. It is therefore advantageous to keep any time dependant applications in the ISR, and control them from mainline code. This is the approach taken in the design of the VURC. All time independent code is run in the mainline, while time critical functions such as the UART’s are run in the ISR, but controlled from the mainline via semaphores. The SX52BD is interfaced to a 16MB Sandisk flash memory Multi-Media Card (MMC) via a Serial Peripheral Interface (SPI) interface. It is also interfaced to an Epson SED1335F0A LCD Controller following the timing requirements of a 6800 family device. The SX also maintains a serial interface to a Burr Brown ADS7843 Touchscreen Controller while transmitting and receiving data on multiple UART channels to a PC and a PIC16F874 micro-controller. As you can see, the SX52BD is the workhorse of the Visual Universal Remote Control Project.

2

MMC Memory Map and Menu Data Members
In order to prepare the reader for understanding what information is needed by the VURC to operate, the data members associated with each screen have been individually broken down into specific sections to allow detailed discussion of each topic. The following items will be discussed in detail below: • • • • • Individual Button Information: Menu Links and IR Codes Visual Bitmap Menu Description Functional Bitmap Button Placement Information

Presented at the end of this section, a graphical representation of the memory map (Figure 3) will help with the visualization of the overall menu structure. Individual Button Information: Menu Links and IR Codes The first item associated with each screen is the button and IR codes associated with each of the buttons. This is a 16-byte code that has two fields. The first field, which is the first (MSB) byte in the 16-byte code, tells the VURC whether the second field contains a menu link or an IR command. The second field, which consists of the remaining 15 bytes, contains the code itself. If the code is a link to a menu, only the first byte is taken into consideration. This limits the number of accessible menus to 256, although this does not affect the VURC project because physical memory size limits the number of possible menus to 180. If the code is an IR command, the remaining 15 bytes contain the actual code information that will be transmitted to the IR module when the user presses a button. Although most remotes require less than four bytes to operate a device, we have left extra space to allow a variety of devices to be operated. Visual Bitmap The second item associated with a screen is its visual bitmap. This is the graphical representation of the screen designed within the VURC Editor. Because we have designed this project to use a monochrome LCD: black pixel or white pixel, we also designed the visual bitmap to be monochrome in nature. This means that for every pixel that the user can see, one bit will be associated with every pixel. Using a screen of 320x240 (pixels), this makes for a total of 76800 pixels. Because there are 8 bits in every byte of data, 9600 bytes of memory are required to store every visual bitmap.

3

Menu Description The menu description is a 128-byte data member that consists of two items: the screen number and the menu description. The screen number is a 1-byte code that simply represents the number of the screen, which can be anywhere between 0 and 255. The remaining 127 bytes represents the description that has been entered by the user. Functional Bitmap The functional bitmap is the third item associated with a screen. This is a bitmap that the user never sees, but is key in the operation of the VURC. The purpose of this bitmap is as follows: When a user presses the touch-screen at a specific co-ordinate, this should cause the VURC to respond in one of three ways: 1) A new menu should be displayed on the LCD screen. 2) An IR command should be transmitted to operate a device (turn on/off TV, etc.) 3) Nothing should change if the user did not press the area within a valid button shown on the LCD screen. The purpose that the functional bitmap serves is to tell the VURC what button the user has pressed, if any button has been pressed at all. The functional bitmap is an 8-bit/pixel bitmap, which means that every pixel can have one of 256 different values associated with it. We have decided to assign these values to either represent an area that has no button ($00) or to represent a specific button ($01$FF). Because $00 is reserved to represent no button is associated with a particular pixels, the remaining 255 values can be assigned to specific buttons. Button Placement Information The last item associated with a screen is its button placement information. This is an array of 256 elements that contain the following items in each element: • Button Type (1 byte) • X co-ordinate (2 bytes) • Y co-ordinate (2 bytes) This means that the size for each element is 5 bytes, and the size for the entire array is 1280 bytes (256 * 5). The purpose of the button placement array is to store the upper-left hand co-ordinates of each button placed, as well as the type of button placed. Although this array does not serve any practical function within the VURC itself, it does serve a purpose within the

4

VURC Editor software: when the user is creating a screen, only the button type and coordinates are stored and manipulated. This means that all of the relevant screen information can be saved to disk using only 1280 bytes for the button placement array, and an additional 128 for the Menu Description. This allows the storage of a menu on disk using only 1408 bytes, a tiny amount compared to the 91904 bytes necessary to store the data on the VURC.

I vi ndi dualButton I or ati nf m on

( $FFF) $0Vi sualBi ap tm 4096- 3695 1 ( 000$1 $357F) M enu Descrpti i on 1 3696- 3823 1 ( $3580$35FF) Functi onalBi ap tm 1 382490623 ( $3600- 61 $1 FF) Button Pl acem ent I or ati nf m on 90624- 903 91 ( 6200- 66FF) $1 $1

The title at the top of each block depicts the type of information stored in that area, and the number shown represent the size of each block. (Hex values are shown for convenience in the brackets.) The total size for a single menu stored on the VURC is 91904 bytes. Because MMC memory must be written to in 512byte blocks, extra information is appended to the end of each menu to fill up the entire last block. The calculations used to find the unused space for each menu are shown below. 91904 bytes ÷ 512 bytes/block = 179.5 blocks " need 180 blocks 180 blocks * 512 bytes/block = 92160 bytes 92160 bytes available in 180 block - 91904 bytes per menu ___________________ = 256 extra bytes

Figure 1. Memory Map for Single Screen

5

Interfaces
SX52BD !SPI" 16MB Sandisk MMC " What is an MMC Card? MMC stands for Multi Media Card. An MMC card is a type of removable flash memory that comes in sizes of 4MB up to 128MB. It is very small and commonly used in devices such as digital camera’s. An MMC card can be run in one of two modes of operation. There is the MMC mode of operation, where you must adhere to the MMC specifications, or there is the SPI mode of operation, where you must adhere to the SPI mode of operation within the MMC specifications. For the VURC project, we chose the SPI mode of operation. Electrical Interface An MMC card was selected for the VURC project in an effort to minimize the number of I/O’s required by the SX52BD for the memory interface. An SPI interface only requires 4 I/O’s, while a parallel interface would have required in excess of 20 I/O’s. For a description of SPI, or I/O’s, please see SPI and I/O respectively in the glossary of terms. The following schematic shows the electrical CMOS level interface between I/O pins of the SX52BD micro-controller and the MMC card. Power pins have been left unconnected for simplicity of illustration.

RA5 RA4 RTCC Vss Vdd RE7 RE6 RE5 RE4 RE3 RE2 RE1 RE0

52 51 50 49 48 47 46 45 44 43 42 41 40

RA5 RA4 RTCC GND 3.3V RE7 RE6 RE5 RE4 RE3 RE2 RE1 RE0

Data Out VSS2 CLK VDD VSS1 Data In CS MMC Card

7 6 5 4 3 2 1

1 RA6 2 RA7 MCLR 3 OSC1 4 OSC2 5 6 3.3V GND 7 8 RA0 9 RA1 RA2 10 RA3 11 RB0 12 RB1 13

RA6 RA7 MCLR OSC1 OSC2 Vdd Vss RA0 RA1 RA2 RA3 RB0 RB1

U1 SX52BD

RD7 RD6 RD5 RD4 Vss Vdd RD3 RD2 RD1 RD0 RC7 RC6 RC5

39 38 37 36 35 34 33 32 31 30 29 28 27

RD7 RD6 RD5 RD4 GND 3.3V RD3 RD2 RD1 RD0 RC7 RC6 RC5

Figure 1

Electrical Interface between SX52BD micro-controller and MMC card (above)

RB2 RB3 RB4 RB5 RB6 RB7 3.3V GND RC0 RC1 RC2 RC3 RC4

14 15 16 17 18 19 20 21 22 23 24 25 26

RB2 RB3 RB4 RB5 RB6 RB7 Vdd Vss RC0 RC1 RC2 RC3 RC4

6

Command Structure Figure 2 below illustrates the command structure of the SPI command set for the MMC card. All commands sent to the MMC card from the SX52BD are of this format and are time independent in that the SX52BD controls the clock (i.e.: the SX52BD is the master and the MMC card is the slave).
Byte 1 6 1 Figure 2 Bytes 2 - 5 5 0 command 31 Command Argument 0 Byte 6 7 CRC

7 0

0 1

All the MultimediaCard commands are 6 bytes long and transmitted MSB first. Handshaking occurs between the MMC card and the SX52BD in the form of responses. A valid R1 response from the MMC card with respect to a command from the SX52BD is $00. Any other value indicates that an error has occurred. Each bit from 0 – 6 represents a flag for a different error such that you could have multiple errors reported by the MMC card in the one byte R1 response. Relevant Theory The total MMC card memory size is 224 = 16,777,216 bytes, or 16MB. This total memory size consists of 32,768 sectors. Each sector is 512 bytes in size and you cannot cross sector boundaries when reading or writing. Writes can only be 512 bytes at a time, while reads can be anywhere from 1 to 512 bytes. Remember all these rules, and you won’t have any problems. Problems Encounters The first problem encountered while performing this interface was bad code written by someone else that we were led to believe was completed. It turned out that the code did not work. Hence, two weeks were lost troubleshooting and fixing someone else’s code. Another problem arose when it was discovered that $2500 annual membership dues are required in order to obtain a full version of the MMC specifications. Therefore, a summarized version published by Sandisk was used. As a result, the information was hard to discern, and sometimes poorly laid out or lacking in content. Perhaps the most difficult task was actually getting the MMC card initialized. With poor documentation, and poorly written code that did not work, this proved very challenging. Results The results of this interface are that we are able to read variable lengths of data between 1 and 512 bytes, and we are able to write fixed length 512 byte sectors. 7

SX52BD !6800 Family Timing" Epson SED1335F0A LCD Controller " What Does the SED1335F0A Controller Do? The Epson SED1335F0A is a text/graphics LCD Controller that can be used to control varying sizes of LCD’s. In designing the VURC, this IC was already designed into the LCM, so all that we needed to do was to interface to the appropriate pins of the LCM as described below. Electrical Interface LAM Cable In order to interface the SX52BD to the SED1335F0A, a 26-pin Laminated (LAM) cable connection from the LCM was tapped. A LAM cable can only be accessed via a surface mount connector. This meant that a surfboard had to be designed. Surfboard Surfboard is short for surface mount board. For a more detailed description, please see surfboard in the glossary of terms. A surface mount to thru hole conversion was necessary in order wire wrap a connection from the surface mount LAM cable connector to the I/O pins of the SX52BD. Figure 3 below shows the schematic capture of a surfboard board designed by the VURC project team for this purpose.

J1 Vss Vdd Vo Ao WR(R/W) RD(E) DB0 DB1 DB2 DB3 DB4 DB5 DB6 DB7 CS RES Vee SEL1 DCLK CS DIN DOUT PEN PEN1 IN3 IN4 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 FH10A-26S-1SH

J2 13X2 TH HEADER

Figure 3

Schematic Capture of Surfboard Designed to Enable Wire-wrapping to pins of 26-pin Surface Mount LAM Cable Connector (Used in interface between SX52BD and LCM) 8

26 25 24 23 22 21 20 19 18 17 16 15 14

26 25 24 23 22 21 20 19 18 17 16 15 14

1 2 3 4 5 6 7 8 9 10 11 12 13

1 2 3 4 5 6 7 8 9 10 11 12 13

Figure 4 below shows the board after fabrication with its connection to the LCM.

Figure 4

Surfboard designed to interface SX52BD to LCM LCM Interface The following schematic in figure 5 shows what the interface to the LCD portion of the LCM looks like electrically on the final PCB. The final PCB layout will not require a surfboard (the surfboard was required for prototyping purposes).

J? R? GND 3.3V Vo RE6 RE5 RE4 RC0 RC1 RC2 RC3 RC4 RC5 RC6 RC7 GND RE3 -25V 3.3V 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 FH10A-26S-1SH

20k

+

C? 0.1uF

C? 10uF

Figure 5

Schematic interface between SX52BD and LCD via 26-pin surface mount LAM Cable Connector 9

Only pins 1 through 18 of the 26 available on the LAM Cable are required to interface to the LCD. Pins 19 through 26 make up the interface to the Burr Brown ADS7843 touchscreen controller. Timing Requirements In order to send data to, or read data from the SED1335F0A, one of two sets of timing requirements must be adhered to. The user of the SED1335F0A must select between 6800 Family and 8080 Family timing requirement. The VURC utilizes 6800 Family timing requirements. Command Set In order to write a command to the SED1335F0A, you must hold the A0 pin of the SED1335 high during a write cycle. For a complete command set description, refer to Appendix C. Problems Encountered One major problem encountered with the interface between the SX52BD and the Epson SED1335F0A was that the LCD would not initialize. The timing of the data and command transfers between the two controllers was know to meet the 6800 Family timing requirements with the help of a logic analyzer. Therefore, we knew that it must be incorrect parameters being sent to the Epson LCD controller. This problem was solved when example code was found on the internet along with initialization examples. Changing the parameter values produced an initialized LCD. Results The results of these efforts produced code that will initialize the LCD, which led to the display of text on the LCD. Graphic bitmap images can also be displayed on the LCD. SX52BD !Serial" Burr Brown ADS7843 Touchscreen Controller " The touch screen interface code sends commands to the Burr Brown controller and reads back the X and Y coordinates that was pressed on the touch screen. The code then verifies and translates those coordinates into an address into a lookup table into MMC memory to determine the course of action that should be taken. Electrical Interface The interface between the SX and the touch screen controller is a 3-wire interface consisting of data in, data out, and data clock. The transmission is done asynchronously, with a maximum clock frequency of 125 kHz. Code Description

10

The very first thing this interface does is request the X and Y coordinates from the touch screen controller in turn. These X and Y coordinates (12-bit values) are then taken and a lookup in MMC is done (MMC addresses [$00fdd300 + X] and [$00FDD500 + Y]), to find out the row and column number in the functional bitmap. The code then takes those values and adds them to the base menu offset for the menu that is currently displaying. A lookup is done on the functional bitmap (in MMC memory) to determine the button that was pressed. If a button was pressed, the number of the button is used in another lookup table (in MMC memory) to find out either the address of the next menu to be displayed by the LCD (this address is sent to the LCD interface module) or the IR code to be transmitted by the IR module (this code is sent to the IR interface module). The code then polls the touch screen until no button is being pressed, then exits back to the main code routine. Relevant Theory If the X and Y coordinates are not within the area of the LCD, or isn’t a valid button, no action is taken and the module exits back to the main code routine. See Appendix <insert number here> for a flowchart of the touch screen operation. SX52BD !UART2" PIC16F874 IR Module " The IR transmission module receives data from the SX52BD microcontroller and sends the requested code out via infrared modulation. The microcontroller chosen for the module is a PIC 16F874. Communication from SX52BD When the SX52BD wants an IR code sent out, it sends 15 bytes of data to the PIC microcontroller via a UART. The 15 bytes consist of the set-up data and command code to be transmitted. The PIC sets up the IR transmission routine using the set-up data, and transmits the command code out to the IR LED. The baud rate between the SX52BD and the PIC16F874 is specified at 19200 baud. Set-up Data The set-up data includes these variables: • Modulation Frequency • Transmission Protocol o REC-80 o RC-5 o Burst width modulation • Start burst length (if applicable)

11

• • • • •

Start space length (if applicable) Burst length for “1’s” and “0’s” Space length for “1’s” and “0’s” Number of times to repeat Miscellaneous flags

If the data received in the first byte from the SX52BD is invalid, the PIC will continue to receive the rest of the bytes, and then not operate on them. If the SX does NOT send 15 bytes of data, the PIC will sit and wait for the rest of the data, and will need to be reset before it functions again. If more than 15 bytes are sent, the results are unpredictable. Electrical Interface The PIC16F874 runs at 20 MHz to achieve fast enough operation to provide up to 60 kHz IR modulation. The baud rate between the SX52BD and the PIC16F874 is specified at 19200 baud. Results Only a single VCR’s (Mitsubishi’s) set-up and command codes have been tuned and verified, due to time constraints and availability of target devices. SX52BD !UART1" VURC EDITOR " Serial communication at a rate of 19200 baud (8 data, no parity, 1 stop bit) is used to interface the VURC to the PC. A serial cable is necessary to connect the female DB-9 connector of the VURC to the serial connector (DB-25 male or DB-9 male) of the PC. To initiate an upload or download to the VURC, the user must press the “programming button” which is located on the VURC. This causes the VURC to enter a loop in which it waits for commands from the PC. There are currently three commands that the PC can send to the VURC: read data, write data, and exit programming mode. Because the maximum read or write size available with the MMC card is 512 bytes (1 block), reading or writing data of larger sizes has been implemented using a loop where the PC acts as the master, and the VURC is the slave. Read commands sent to the VURC can request a memory block size of anywhere from 1 to 512 bytes, with an address that can be specified anywhere in MMC memory. When issuing a write command, the PC must ensure that it will send the VURC a total of 512 bytes. Failure to do so will cause an error in MMC memory.

12

Hardware Design
IR Module The hardware interface for the IR Module is a PIC 16F874 microcontroller connected to the SX52BD via the UART onboard the PIC. The output of the PIC to the IR devices is done through an IR LED connected to pin 2 on Port B.

U1 1 MCLR RA0 RA1 RA2 RA3 RA4 RA5 RB0 RB1 RB2 RB3 RB4 RB5 RB6 RB7 2 3 4 5 6 7 21 22 23 24 25 26 27 28 R1 100 D1 IR LED

Y1 C1 20PF C2 20PF

9 10

CLKIN CLKOUT

+

20MHz

+

From SX52BD

RX

11 12 13 14 15 16 17 18

RC0 RC1 RC2 RC3 RC4 RC5 RC6 RC7 PIC16F874

Figure 6 Schematic Diagram of IR module. Switching Power Supply The VURC is meant to be a stand-alone unit. This means that it must be battery powered, and if it is to be battery powered, then it must be power efficient. Otherwise, users of the VURC would have to replace the batteries fairly often, which would be an encumbrance. With this in mind, we set out to produce a 3.3V CMOS rail in conjunction with a –25V rail to power the LCD. We decided upon a source voltage of 6V (4 x 1.5V “AA” batteries) and quickly realized that linear regulators would not be an option if we were to make these batteries last. Therefore, we decided to design a switching power supply circuit using Step-Down Switching Regulators, or “Buck Converters.” Please refer to Appendix B for the design of this switching power supply. Schematic Capture The schematic capture for this project was performed using the Protel 99 SE package. Approximately two weeks was spent learning Protel 99 SE. For a reference to the Protel 99 SE User’s Manual studied during this time frame, please see the attached bibliography.

13

PCB Layout All PCB layouts for the VURC were performed using Protel 99 SE. The two weeks spent learning Protel 99 SE also entailed learning the PCB layout capabilities of the package. Footprint Library PCB footprint libraries were created while layout was performed. Again, this aspect of Protel 99 SE was learned during the two-week period.

Software Design
Section Overview This section deals with the design and implementation of the software used to create, modify and download screens to the VURC. The main concepts that are presented here are: a description of what the VURC Editor is and what it is intended to do, and a detailed functional description of the VURC Editor software. What is the VURC Editor? The VURC Editor is a PC (Personal Computer) software package that is written using Borland C++ Builder 4.0 and is designed to run under Windows 95, 98 or 2000. The program is intended to allow the user of the VURC to create and customize VURC screens allowing them total flexibility of use. The two main purposes of the VURC Editor are: • To create screens and buttons that will be displayed on the VURC itself. • To transfer data between the PC and MMC memory (via the SX52BD). Both of these items are discussed in greater detail later in this section. Initial Proposal The proposal presented at the beginning of the project included two requirements for the VURC Editor software: to allow the user to create bitmaps and transfer them to MMC memory aboard the VURC. After learning more about the scope of the project and making decisions on how the hardware would be implemented, it became apparent that the initial requirements would have to be revised. Because we chose to use two separate bitmaps within the VURC, the creation of bitmaps would be a multifaceted operation. While the user only sees the visual results of their button or screen design, the VURC Editor is actually working behind the scenes to create another representation of their actions. This allows the user the freedom to easily create buttons and screens, while the VURC Editor takes care of the functional coding.

14

Functional Description for VURC Editor Software The key items that are presented in the following sections are: • Modules included in project and associated member functions • Flowcharts showing: • What happens when a button is placed on a menu • What happens when a button is moved on menu Modules Included in the VURC Project Group To promote and practise modularity while creating the VURC Editor, specific tasks were broken down and placed in their own units and forms. This allows for easier future modifications, as well as less headache when attempting to debug faulty code. Shown below is a list of the units and forms contained within the VURC Editor, and a brief description of each is also included. The name of the unit is listed first, followed by the name of the associated form. If only one name is shown, there is no form associated with the unit being discussed. (A description of the terms “unit” and “form” can be found in the glossary) A) About / AboutBox – This is, quite simply, the form that is displayed when the user clicks Help|About. It contains the VURC Editor logo, team project members, and the current revision number. This form is shown only for information purposes; it doesn’t serve as a way to modify or alter the operation of the program in any way. B) BBar / ButtonBar – This form provides most of the functionality available to the user when creating a new screen. It allows the user to select a button, to view it’s visual and graphical bitmaps, and to place the button on the current menu. It also permits the user to select buttons that have already been placed and to move them around. Various information is shown on this form, such as the filename of the menu being edited, the description, and the X and Y co-ordinates of the mouse pointer in relation to the currently active window. C) ButtonClass– This object contains many data members and functions, which includes methods used to save and load button information to and from disk. Button bitmap information is stored in here, as well as the button function. D) ButtonEditor / ButtonEdit – This is the module that shows the button being created or edited and allows the user to draw. This window needs to be open to allow the user to access the EditButtonProperties Form. E) ButtonProperties / EditButtonProperties – This form and module allow the user to view and modify a buttons properties. This is probably the most important form in

15

the design of a new button as it allows you to change all associated button variables, as well as to load new graphical and functional bitmaps for each button. F) ButtonToolForm / ButtonTools – This form provides the user with information about the currently selected button, as well as a way to edit the properties of the current button via a link to the EditButtonProperties form. G) ConfigForm / ConfigBox – This form deals with the selection of the COM Port, the location of the button and menu subdirectories, and the size of the MMC card housed inside the VURC. H) MMCAddress / MMCAddressBox – This is a relatively new form that is intended to allow the user to specify a start address and size for reading from and writing to MMC memory. Although this form is currently not implemented, it will be shown prior to starting an upload or download to or from the VURC. I) NewButton / CreateNewButton – This form is shown when the user decides to create a new button by selecting File|New|Button from the main menu. The initial size, description and function can be entered in this form. J) PVChild / Child – This is the module that deals mostly with the layout of screens. Buttons can be dragged and dropped onto this form, and existing buttons can be moved. This form is of MDI Child style, meaning that multiple instances of this form can be open at once. Although many screen operations are initiated from within this module, Child relies heavily on the data members and methods of two separate objects: ScreenClass and ButtonClass. K) ScreenClass – This object encapsulates many data members and functions, which includes methods used to save and load screen information to and from disk. Drawing of the visual bitmap screen within Windows is taken care of from within this object. L) SplashSource / Splash – There really is not much involved in this form other than a window that contains a graphical picture. This form is shown upon starting the VURC Editor and is displayed for only a few moments on the screen. This graphic contains the title of the VURC Editor, and shows the current revision of the software. M) Test / TestForm – This module and form is designed for debugging purposes, so is of no use to the user. Access to this form has been removed from the project and main menu, but it could still be of use in future debugging. N) Vurc - This is the file that is initially loaded when the program is first started, and it instructs the program on which forms to create and in which order they will be created. This is for the most part a compiler generated file, although it was modified to show the splash screen upon starting the VURC Editor.

16

O) VURCedit / MainForm – This is the main form in the MDI application, and mainly contains links to other forms, while containing little actual code itself. The most important data contained within this form is the Main Menu and its options. P) VurcLink / VLink – All communication issues are dealt with in this module. The SendFile() and ReceiveData() functions are contained in this module, and the current upload/download status and time remaining are also shown on this form.

What is a VURC Menu? Although each menu inside the VURC contains all of the sections as previously outlined (visual bitmap, functional bitmap, description, etc.), it is essentially just a collection of buttons. Creating Menus for the VURC In the process of designing a menu that will be displayed on the VURC, there are two main purposes that the VURC Editor software serves. The first of these is to create buttons, while the second is to place buttons on a representation of the screen itself. Detailed information on how to create a menu can be found in the VURC Editor User’s Manual. What is a button? A button is a graphical representation of a button that would be found on a traditional IR There are two bitmaps associated with each button: one for the visual information, and another to represent the “active area” of the button. The active area of a button is simply the area that the user can press on the touchscreen to activate that button. It is important to ensure that the “active area” of the button is at least the size of the visual representation of the button. If it is smaller, the user will see the button displayed on the screen, but may have difficulty activating it because the “active area” of the button is only a portion of that of the button itself. Creating a New Button Creating a new button for a menu is a relatively simple operation, and the only technical information that the user requires is the IR code of the device that will be operated. Although IR codes may be difficult for the average user to find, they can be entered or updated easily at a later date.

17

Currently, creating a new button operates more as editing an existing button; a blank button is created, and then it’s properties are edited, and new visual and graphical bitmaps are associated with the button. Detailed information on how to create a button can be found in the VURC Editor User’s Manual. Future Software Improvements Although the software accomplishes the tasks set out for it in the proposal, there are many improvements or modifications that could be made to allow more flexibility and a greater ease of use for the end-user. Following is a list of items that would improve the VURC Editor software, some with brief descriptions as to what each may mean: Modifications to current code to allow better operation • instead of saving entire 91904 bytes file, only 1280 + 128 byte file will be saved • changing many class variable to private instead of public • implementing some of the existing variables within the config menu that would allow more versatile operation of the program • selection of MMC card size • selection of button and menu directories Implementation of new features or methods that would make the VURC Editor program more versatile: • allowing the user to import a bitmap for the entire screen • allowing the VURC Editor software to learn new IR codes through the use of an IR detector and store them on the PC • including more options in the “config” menu to allow customization of items such as: • form color • screen background and foreground colors (instead of just black and white) • allow the user to select the default size and functions of new buttons • creating a help file that would let the user know about specific features and meaning behind a variety of components • creating a tutorial that would walk the user through the creation of a button and then the placement of buttons on a new screen • checking for invalid input from the user at various points throughout the program (when the PC expects an integer value from the user, it doesn’t check to ensure that it in fact has received an integer value; this can cause fatal exceptions) • try {…} catch need to be implemented in some functions still to prevent fatal exceptions on function operations such as loading from disk and saving to disk • the automatic association of menu numbers upon creating a new menu • more drawing capabilities added to the creation and design of buttons • cutting, copying and pasting to and from clipboard (for bitmap images) • allowing the user to browse through screens on-board the VURC by description to allow them to select an individual screen without having to download every one to

18

•

see what it is " an alternative or modification to this would be to allow the download of only the 9600 bytes associated with the visual bitmap – the user could then select the desired screen and download the rest of the associated information reading data from MMC should be modified to check for sector crossings when trying to read from a location that does not start at the beginning of a sector

• layout of program itself: MDI style (Multiple Document Interface) • associated terms: • MDI child • active MDI child • problems encountered using the MDI style saving tool windows properly updated from the correct type of active child

19

Conclusions • • • • • •
The LCD and MMC modules were completed in their entirety. The IR, touchscreen, and PC modules were completed to a basic requirement. The interfaces between the modules were not completed. The power supply circuit was completed. The project budget fell within the $250 required by the college. The project incorporated an embedded microcontroller.

Recommendations • The specification included too many different modules to be incorporated into a
single product, given the time constraints of the project course. Fewer distinct modules would help produce a complete product within the required time allowance.

• There should be a quicker method for sourcing parts for the project course. Given
the bureaucracy of the college’s purchasing department, it was difficult to determine if parts would come in quickly enough to use in the project.

20

Bibliography
Specification for LCM Model # MTG-F3220FFWHSCW, Microtips Technology Inc., Taipei Hsien, Taiwan: 28 June, 2000 SED1335F LCD Controller Technical Manual, Version 0.4, S-MOS Systems, Inc., San Jose, California: September, 1995 MultiMediaCard Product Manual, Revision 2, Sandisk Corporation, Sunnyvale, California: April, 2000 SX Communications Contoller User’s Manual, Revision 3.1, Ubicom, Inc., Mountain View, California: 24 August, 2000 SX52BD Datasheet, Literature # SXL-DS03-10, Ubicom, Inc., Mountain View, California: 2000 Protel 99 SE Designer’s Handbook, Protel International Limited, California, USA: 2000

21

Glossary of Terms
Bitmap – is a coordinate map that contains information about the pixel color located at each coordinate. BOM – is an acronym for Bill Of Materials – this is a listing of parts in a PCB design containing information such as Manufacturer, Distributor, Quantity, Pricing, and Reference Designators CCFL – is an acronym for Cold Cathode Fluorescent Light – CCFL inverter circuitry is used to power the backlight for the LCD – due to power restrictions (i.e.: battery powered operation), this option is not implemented in the VURC CMOS – is an acronym for Complimentary Metal Oxide Semiconductor – CMOS voltage levels are lower that legacy TTL levels and are therefore more power efficient – a CMOS high can be in the range of 2.7V to 3.6V, typically 3.3V – to obtain your max. lows and your min. highs, you usually multiply Vdd by 0.3 and by 0.7 respectively depending on the IC COMM port – is an abbreviation for Communications Port – a serial interface to a PC which uses the RS232 protocol DTMF – is an acronym for Dual Tone Modulated Frequency – DTMF is an encoding scheme used in most telephones today DVD – is and acronym for Digital Video Disk – DVD’s are the evolution of VCR’s – they hold movie’s on a compact disk and then play them back in a much more interactive fashion that possible with a VCR Form – a form in C++Builder is a graphical window that can have contain properties such as edit boxes, text, and radio buttons. IC – is an acronym for Integrated Circuit – an Integrated Circuit is a circuit that has been integrated into a hermetically sealed environment or packaging – the actual circuitry inside an IC is on a silicon wafer and is typically too small for the naked eye to make out without the aid of a microscope I2C – stands for Inter Integrated Circuit - I2C is a three wire interface that utilizes a bidirectional data line to cut down on the number of I/O’s required for this serial peripheral interface IR – is an acronym for Infra Red – a method of controlling many digital devices such as TV’s, VCR’s, Stereo’s, and DVD players ISR – is an acronym for Interrupt Sub Routine – an ISR is assembly language code internal to a micro-controller that is executed every time an interrupt occurs

22

I/O – stands for input/output – the number of I/O pins a micro-controller has helps to determine its capabilities LCD – is an acronym for Liquid Crystal Display – a 320 x 240 liquid crystal display is used to display graphic bitmap images for different screens created by the user of the VURC LCM – is an acronym for Liquid Crystal Display Module – an LCM is termed a module because it incorporates things such as a touchscreen, touchscreen controller, and LCD controller all in one module (i.e.: all supporting circuitry is already there) – this approach saves development time and costs MDI – Multiple Document Interface : The style of interface used by many programs in Windows, such as Microsoft Word. An MDI document can have multiple documents open in separate windows. Micro-controller – an SX52BD “micro-controller” is the brain of the VURC – it controls the sequence of events that occur within the VURC MMC – is the acronym for Multi Media Card – this is a type of removable flash memory that is used to store the bitmap images to be displayed on the LCD Monochrome – a monochrome bitmap has only 2 colors - traditionally white and black PC – acronym for Personal Computer PCB – is an acronym for Printed Circuit Board – a printed circuit board is populated with the electronics which make up a design, by itself, it is just a board with copper traces and holes PIC – is a trademarked acronym for Programmable Integrated Circuit – a PIC is a microcontroller designed and manufactured by Microchip Semaphore – a semaphore is an elegant name for a software flag SPI – is an acronym for Serial Peripheral Interface – SPI is a four wire serial peripheral interface developed by Motorola – SPI utilizes separate Data In and Data Out lines Surfboard – The terminology “surfboard” with respect to the electronics industry is derived from surface mount board – a surfboard takes an electronic surface mount part and creates a thru-hole connection to the surface mount part – this technique is used in prototyping in order to access pins of surface mount parts

23

Surface Mount – An electronic surface mount component is a component whose pins are mounted (soldered) onto the surface of a PCB (i.e.: the pins do not go thru holes in the PCB) SX – is a prefix for the SX series of micro-controllers designed by Ubicom, Inc. – two controllers in the SX line include the SX28AC, and the SX52BD – the SX52BD is the master micro-controller utilized in the design of the VURC SX52BD – the SX52BD micro-controller sports 4K words of program memory and 256 bytes of data memory – it is designed and produced by Ubicom, Inc. and can be run at up to 100MHz executing instructions as quickly as once every 10ns Thru Hole – a electronic thru hole component is a component whose pins are mounted (soldered) thru holes in the PCB – thru hole connections to a PCB are typically sturdier and will stand up to stresses better than surface mount components Touch-screen – a resistive touch-screen overlays the LCD such that varying analog voltage levels are converted to digital 8 or 12 bit values that can be used to determine where the user has touched the screen and what consequent action is to take place UART – is an acronym for Universal Asynchronous Receive and Transmit – a UART is used as a means of transmitting and receiving data between a PC and certain peripheral devices via a PC COMM port Unit – a unit in C++Builder is a group of code that is contained in one file and quite often supports the functionality of a form. VP – is and acronym for Virtual Peripheral – a virtual peripheral is a function traditionally performed in hardware that has been done in software (e.g.: a UART coded in software is a UART Virtual Peripheral). Some examples of VP’s produced by Ubicom, Inc. for use on the SX series of Ubicom micro-controllers are: I2C, SPI, UART, DTMF, and more VURC – is an acronym for Visual Universal Remote Control VURC EDITOR – is the name of the Windows Based Application used to create and edit different screens for the VURC

24

Appendix A
Visual Universal Remote Control System Block Diagram

Resistive Touch Screen 320 x 240 LCD ADS7843 Touch Screen Controller SED1335F0A LCD Controller

Remote Control

Learning Circuitry

TV, VCR, Stereo, etc…

SX52BD Microcontroller

IR Transmission Circuitry

PC

16 Meg Flash MMC

Windows Based Program Where the User can create and update bitmaps for different screens

Switching Power Supply Circuitry (Battery Powered from 4 x 1.5V “AA’s”) Produces a 3.3V CMOS rail and a –25V rail for the LCD

25

Appendix B
Switching Power Supply Circuitry

1

2

3

4

D2 LL4148 2 C1 0.1uF T1 20uH 1 2 1

D

D 1 3.3V C2 100uF 10V
T -1

4

D1 1N5818 U1 1 D4 DL4007 6V 1 2 1 C3 100uF 20V
+

3

D3 Red

2

1
+

1 2 5 6

Boost Vin SHDN* GND

Vsw BIAS FB Vc

3 4 7 8 C4 3.3nF

R1 1.82k 1%

2

2 R3
330 Ω

4 x 1.5V "AA" Batteries

C 2

LT1376CS8

R2 4.99k 1%

C

1 2 1 + C5 0.1uF U2 SHDN POL REF FB MAX629ESA C9 * R5 C6 0.1uF 30.1k 1% 150pF R6 604k 1% 1 VCC LX GND ISET 2 1 2 B 3 GND 4 8 7 6 5 2.2uF C7 10uF 35V

L1 47uH C8

R4 1 2
2Ω

B D6

MBR0540L

MBR0540L

K A

D5

2

1 2

A K

-25V 1 2 C10 10uF 35V

A

Title Size A Date: File: 1 2 3

Power Supply for Visual Universal Remote Control
Number Drawn By: Jamie Aitken 11-Mar-2001 Sheet 2 of 2 C:\S chool\Quarter6\Elex290\schematics\VURC.ddb By: Drawn * 4 Revision Original Development

+

A

26

Appendix C Epson 1335F0A Command Set and Description

Code Class Command !RD !WR A0 D7 D6 D5 D4 D3 D2 D1 D0 SYSTEM SET System control SLEEP IN 1 0 1 0 1 0 1 0 0 1 1 53 Enter standby mode 1 0 1 0 1 0 0 0 0 0 0 40 Initialize device and display Hex Command Description

Command Read Parameters No. of Section bytes 8 0 3.2.1 3.2.2

DISP ON/OFF

1

0

1

0

1

0

1

1

0

0

D

58, Enable and Disable Display 59 and Display Flashing

1

3.3.1

SCROLL

1

0

1

0

1

0

0

0

1

0

0

44

Set display start address and display regions

10

3.3.2

CSRFORM Display control CGRAM ADR

1

0

1

0

1

0

1

1

1

0

1

5D

Set Cursor Type

2

3.3.3

1

0

1

0

1

0

1

1

1

0

0

5C

Set start address of character generator RAM

2

3.3.6

CSRDIR

1

0

1

0

1

0

0

1

1

4C CD CD TO 1 0 4F 1 0 5A

Set direction of cursor movement Set Horizontal Scroll Position

0

3.3.4

HDOT SCR

1

0

1

0

1

0

1

1

0

1

3.3.7

OVLAY

1

0

1

0

1

0

1

1

0

1

1

5B Set Display Overlay Format

1

3.3.5

CSRW Drawing Control SCRR

1 1

0 0

1 1

0 0

1 1

0 0

0 0

0 0

1 1

1 1

0 1

46 47

Set Cursor Address Read Cursor Address

2 2

3.4.1 3.4.2

MWRITE Memory Control MREAD

1

0

1

0

1

0

0

0

0

1

0

42

Write to Display Memory

--

3.5.1

1

0

1

0

1

0

0

0

0

1

1

43

Read from Display Memory

--

3.5.2

27

Appendix D Scenix SX52BD Code
; Filename: VURC_095.src ; ; Author(s): Jamie Aitken ; Student ; Camosun College ; Victoria, BC, Canada ; ; Owen Taylor ; Student ; Camosun College ; Victoria, BC, Canada ; ; Tyson Gilberstad ; Student ; Camosun College ; Victoria, BC, Canada ; ; Revision: 0.95 ; ; Part: Scenix SX52BD/PQ ; Date Code: AB0004AC ; Freq: 50MHz ; ; Compiled using: Advanced Transdata SX IDE V1.12.01, SASM V1.48 ; ; Date Written : Jan 11th, 2001 - present ; ; Last Revised : Mar 13th, 2001 ; ; Program Description: ; ;VURC stands for Visual Universal Remote Control: ; ;This program will run at the heart of the VURC project. The following code will ;interface to a Windows based program on a PC where it will download graphic bit; map images via the RS232 protocol. This data will be stored in Flash Memory by ;the SX52BD running this code. The program below will also interface to an LCD ;with touchscreen capabilities, which also means interfacing to the touchscreen. ;The code below will also be required to output IR codes for the VURC IR ;transmission circuitry. These codes will also be stored in the Flash Memory. ; ; ; Interface Pins: ; ; *****Pin assingment for UART interface***** ; ; rs232RxPin1 equ ra.2 ;UART1 receive input ; rs232TxPin1 equ ra.3 ;UART1 transmit output ; rs232RxPin2 equ ra.0 ;UART2 receive input ; rs232TxPin2 equ ra.1 ;UART2 transmit output ; ; *****Pin assingment for SPI_X interface***** ; ; spix_clk_pin EQU ra.4 ;SPI clock output ; spix_out_pin EQU ra.5 ;SPI-Master-Out-Slave-In ; spix_in_pin EQU ra.6 ;SPI-Master-In-Slave-Out ; spix_cs_pin EQU ra.7 ;SPI device select ; ; *****Control Pin assignments for LCD interface***** ; lcdAoPin equ re.6 ; lcdRWPin equ re.5 ; lcdEPin equ re.4 ; lcdRESPin equ re.3

28

; ; *****Data Port assigment for LCD interface***** ; lcdData equ rc ; ; *****Pin assignment for programming mode button***** ; programButton equ re.7 ;user places VURC into programming ; ;mode by pressing this button ; ; Revision History: ; ; 0.90 Set up template from single UART Virtual Peripheral Module. ; Wrote initial program description. ; -Jamie Aitken ; 0.91 Added pin assignments and pin definitions for SPI interface to MMC ; Flash Memory. Moved the main program to the last page of program ; memory by redifining the Program memory ORG defines. Changed the ; port A data direction register and latch init to accomodate the SPI ; interface to the 16MB Sandisk MMC (Multi Media Card). Ported the ; mmc_spix_ram bank and global register definitions from Craigs code ; into bank 2 of this code. This meant adding "_bank mmc_spix_ram" to ; numerous places in the code. Also changed bank instuctions to _bank ; instructions. Discovered that Craig's code was useless, and ; proceeded to write the synchronize, initialize, and read block ; routines basically from scratch. The end result is a program that ; reads the first 512 block sector of an MMC and spits the Hex value ; of the bytes back to Hyperterminal. ; -Jamie Aitken ; 0.92 Ported existing known good MMC interface code to a Dual UART ; virtual peripheral to accommodate interface to PIC16F874 via a ; second UART channel (at CMOS levels). ; -Jamie Aitken ; 0.93 Added code to talk with PC program: ; configLoop ; -> waits for PC to send control code to initiate data transfer ; readMMCcard ; Reads data from the MMC card and sends it to UART #1 ; -> The entire contents of the MMC card are read and sent ; writeMMCcard ; Reads data from UART #1 and writes it to the MMC card ; -> The entire contents of the MMC card are re-written ; -Jamie Aitken and Owen Taylor ; 0.94 Incorporated a write block function that will write a 512 byte ; sector of an MMC(multi-media card). Also incorporated pin and ; port definitions/assignments for use with LCD interface. ; **NOTE** ; -the LCD code below interfaces to a Microtips MTG-F32240FFWHSCW ; LCD Module (with resistive touchscreen) ; -the built-in LCD controller on the LCD Module is an Epson ; SED1335F0A ; -the built-in touchscreen controller on the LCD Module is a ; Burr Brown ADS7843 (8 or 12 bits of resolution) ; In page 5: wrote LCD initialization, reset, command, datawrite, ; and waitnotbusy functions. A small demo program in the mainloop ; will display a one line text message on the Microtips LCD ; referenced above. The LCD parameters of the SED1335F0A are now ; set up for first layer text and second layer graphics. Clearscreen ; functions have therefore been written to clear out any random data. ; $20 (space) is written to every memory location of the text layer, and ; $00 is written to every memory location of the graphics layer. ; -Jamie Aitken ; Added code to interface to LCM touchscreen that now reads in X and Y ; co-ordinates from the ADS7843 when the touchscreen is pressed. These ; data values consist of 12-bits of resolution in the X and Y directions. ; -Tyson Gilberstad ; 0.95 Wrote code to interface to Owen's Windows based program such that when ; the programButton is pressed (polled in mainline code), ; communications between the SX52BD UART 1 and COMM1 of the PC (Owen's ; window's based program) will commence. During this time, any screen ; touches will be ignored. If the programButton is polled and found to ; not be pressed, the mainline will continue with it's polling of the ; touchscreen. Once programming of the MMC card is completed by the

29

; Window's based GUI, the program will continue on with it's polling ; of the touchscreen and the programButton respectively. Added a fuction ; that will read from MMC and display a 9600 byte bitmap image on the ; LCD. ; -Jamie Aitken ; ; Put rest of revision history here... ;**************************************************************************************** *** ;**************************************************************************************** *** ; Target SX ; Uncomment one of the following lines to choose the SX28AC, SX48BD, SX52BD. ;**************************************************************************************** *** ;SX18_20 ;SX28AC SX48_52 ;**************************************************************************************** *** ; Assembler Used ; Uncomment the following line if using the Parallax SX-Key assembler. SASM assembler ; enabled by default. ;**************************************************************************************** *** ;SX_Key ;**************************************************************************************** *** ; Uncomment one of the following to run the UART VP's at the required baud rate ;**************************************************************************************** *** ; ** Baud Rates for UART 1 ** ;U1B1200 ;baud rate of 1.2 Kbps ;U1B2400 ;baud rate of 2.4 Kbps ;U1B4800 ;baud rate of 4.8 Kbps ;U1B9600 ;baud rate of 9.6 kbps U1B1920 ;baud rate of 19.2kbps ;U1B5760 ;baud rate of 57.6kbps ; ** Baud Rates for UART 2 ** ;U2B1200 ;baud rate of 1.2 Kbps ;U2B2400 ;baud rate of 2.4 Kbps ;U2B4800 ;baud rate of 4.8 Kbps ;U2B9600 ;baud rate of 9.6 kbps U2B1920 ;baud rate of 19.2kbps ;U2B5760 ;baud rate of 57.6kbps ;**************************************************************************************** *** ; Assembler directives ;High speed external osc, turbo mode, 8-level stack, and extended option reg. ;SX28 - 4 pages of program memory and 8 banks of RAM enabled by default. ;SX48/52 - 8 pages of program memory and 16 banks of RAM enabled by default. ;**************************************************************************************** *** IFDEF SX_Key ;SX-Key Directives

IFDEF SX28AC ;SX28AC device directives for SX-Key device SX28L,oschs2,turbo,stackx_optionx ENDIF

IFDEF SX48_52 device oschs2 ENDIF freq 50_000_000

;SX48/52/BD device directives for SX-Key

30

ELSE

;SASM Directives

IFDEF SX28AC ;SX28AC device directives for SASM device SX28,oschs2,turbo,stackx,optionx ENDIF IFDEF SX48_52 device SX52,oschs2 ENDIF ENDIF id '2UART VP' ; reset resetEntry ;SX48BD or SX52BD device directives for SASM

; set reset vector

;**************************************************************************************** ***** ;--------------------------------------Macro's----------------------------------------------; Macro: _bank ; Sets the bank appropriately for all revisions of SX. ; ; This is required since the bank instruction has only a 3-bit operand, it cannot be used to ; access all 16 banks of the SX48/52. FSR.7 (SX48/52bd production release) needs to be set ; appropriately, depending on the bank address being accessed. This macro fixes this. ; ; So, instead of using the bank instruction to switch between banks, use _bank instead. ;**************************************************************************************** ***** _bank macro 1 noexpand bank \1 IFDEF SX48_52 IF \1 & %10000000 ;SX48BD and SX52BD (production release) bank instruction expand setb fsr.7 ;modifies FSR bits 4,5 and 6. FSR.7 needs to be set by software. noexpand ELSE expand clrb fsr.7 noexpand ENDIF ENDIF endm ;**************************************************************************************** ***** ; Macro: _mode ; Sets the MODE register appropriately for all revisions of SX. ; ; This is required since the MODE (or MOV M,#) instruction has only a 4-bit operand. ; The SX28AC use only 4 bits of the MODE register, however the SX48/52BD have ; the added ability of reading or writing some of the MODE registers, and therefore use ; 5-bits of the MODE register. The MOV M,W instruction modifies all 8-bits of the ; MODE register, so this instruction must be used on the SX48/52BD to make sure the MODE ; register is written with the correct value. This macro fixes this. ; ; So, instead of using the MODE or MOV M,# instructions to load the M register, use ; _mode instead. ;**************************************************************************************** ***** _mode macro 1 noexpand IFDEF SX48_52 expand mov w,#\1

;loads the M register correctly for the SX48BD and SX52BD

31

mov m,w noexpand ELSE expand mov m,#\1 ;loads the M register correctly for the SX18AC, SX20AC ;and SX28AC noexpand ENDIF endm ;**************************************************************************************** ***** ; INCP/DECP macros for incrementing/decrementing pointers to RAM ; used to compensate for incompatibilities between SX28AC and SX52BD ;**************************************************************************************** ***** INCP macro 1 ; Increments a pointer to RAM inc \1 IFNDEF SX48_52 setb \1.4 ; If SX18 or SX28AC,keep bit 4 of the pointer = 1 ENDIF ; to jump from $1f to $30,etc endm DECP macro 1 ; Decrements a pointer to RAM IFDEF SX48_52 dec \1 ELSE clrb \1.4 ; If SX18 or SX28AC, forces rollover to next bank dec \1 ; if it rolls over. (skips banks with bit 4 = 0) setb \1.4 ; Eg: $30 ---> $20 ---> $1f ---> $1f ENDIF ; AND: $31 ---> $21 ---> $20 ---> $30 endm ;**************************************************************************************** ***** ; Error generating macros ; Used to generate an error message if the label is intentionally moved into the second page. ; Use for lookup tables. ;**************************************************************************************** ***** tablestart macro 0 ; Generates an error message if code that MUST be in ; the first half of a page is moved into the second half if $ & $100 ERROR 'Must be located in the first half of a page.' endif endm tableEnd macro 0 ; Generates an error message if code that MUST be in ; the first half of a page is moved into the second half if $ & $100 ERROR endif endm

'Must be located in the first half of a page.'

;**************************************************************************************** ***** ;--------------------------------------- Memory Organization -------------------------------;**************************************************************************************** ***** ;**************************************************************************************** ***** ;------------------------------- Data Memory address definitions----------------------------; These definitions ensure the proper address is used for banks 0 - 7 for 2K SX devices

32

; (SX28) and 4K SX devices (SX48/52). ;**************************************************************************************** ***** IFDEF SX48_52 global_org = $0A bank0_org = $00 bank1_org = $10 bank2_org = $20 bank3_org = $30 bank4_org = $40 bank5_org = $50 bank6_org = $60 bank7_org = $70 ELSE global_org = $08 bank0_org = $10 bank1_org = $30 bank2_org = $50 bank3_org = $70 bank4_org = $90 bank5_org = $B0 bank6_org = $D0 bank7_org = $F0 ENDIF ;**************************************************************************************** ***** ;-------------------------------- Global Register definitions-------------------------------; NOTE: Global data memory starts at $0A on SX48/52 and $08 on SX18/20/28. ;**************************************************************************************** ***** org flags0 global_org

equ global_org + 0 ; stores bit-wise operators like flags ; and function-enabling bits (semaphores) ;-----------------------------VP: RS232 Receive---------------------------------------------rs232Tx1Flag equ flags0.0 ;indicates that UART1 is transmitting if set or not transmitting if reset rs232Tx2Flag equ flags0.1 ;indicates that UART2 is transmitting if set or not transmitting if reset rs232Rx1Flag equ flags0.2 ;indicates that UART1 has received a byte if set rs232Rx2Flag equ flags0.3 ;indicates that UART2 has received a byte if set isrTemp0 equ global_org + 1 ; Interrupt Service Routine's temp register. ; Don't use this register in the mainline. localTemp0 equ global_org + 2 ; temporary storage register ; Used by first level of nesting ; Never guaranteed to maintain data localTemp1 equ global_org + 3 ; temporary storage register ; Used by second level of nesting ; or when a routine needs more than one ; temporary global register. localTemp2 equ global_org + 4 ; temporary storage register ; Used by third level of nesting or by ; main loop routines that need a loop ; counter, etc. ;**************************************************************************************** *****

33

;--------------------------- RAM Bank Register definitions----------------------------------;**************************************************************************************** ***** ;********************************************************************************* ; Bank 0 ;********************************************************************************* org bank0 =$ bank0_org

;********************************************************************************* ; Bank 1 ;********************************************************************************* org bank1_org

bank1 =$ rs232TxBank = $ ;UART Transmit bank rs232Tx1High ds 1 ;High Byte to be transmitted rs232Tx1Low ds 1 ;Low Byte to be transmitted rs232Tx1Count ds 1 ;counter to keep track of the bits sent rs232Tx1Divide ds 1 ;xmit timing counter rs232Tx1Byte ds 1 ;store the byte to be sent in this buffer rs232Tx2High ds 1 ;High Byte to be transmitted rs232Tx2Low ds 1 ;Low Byte to be transmitted rs232Tx2Count ds 1 ;counter to keep track of the bits sent rs232Tx2Divide ds 1 ;xmit timing counter rs232Tx2Byte ds 1 ;store the byte to be sent in this buffer MultiplexBank = $ ;Multipler Bank isrMultiplex ds 1 ;Used to jump between the ISR Threads when ; an Interrupt occurs ;********************************************************************************* ; Bank 2 ;********************************************************************************* org bank2 =$ rs232RxBank bank2_org

=$

rs232Rx1Count ds 1 ;counter to keep track of the number of bits received rs232Rx1Divide ds 1 ;receive timing counter rs232Rx1Byte ds 1 ;buffer for incoming byte rs232Byte1 ds 1 ;Used by serial routines rs232Rx2Count ds 1 ;counter to keep track of the number of bits received rs232Rx2Divide ds 1 ;receive timing counter rs232Rx2Byte ds 1 ;buffer for incoming byte rs232Byte2 ds 1 ;used by serial routines ;********************************************************************************* ; Bank 3 ;********************************************************************************* org bank3_org

bank3 = $ ClkDelayVar1 ds 1 ;these three ClkDelay variables are used to ClkDelayVar2 ds 1 ;create delays while clocking the MMC ClkDelayVar3 ds 1 blockReadB1 ds 1 ;this variable is used in conjunction with blockReadB2 ds 1 ;this one to count down 512 bytes in a block storeW ds 1 ;this data register will store a command for the ;mmc_cmd_block_read function passed to the function ;by the user

34

temp_addr_b3 ds 1 ;temporary storage of ;PC is reading contents of MMC temp_addr_b2 ds 1 ;temporary storage of ;PC is reading contents of MMC temp_addr_b1 ds 1 ;temporary storage of ;PC is reading contents of MMC temp_addr_b0 ds 1 ;temporary storage of ;PC is reading contents of MMC sectorCount ds 1 ;this data register will ;sectors left to be read from the ;display the current bitmap

address to read from when address to read from when address to read from when address to read from when hold the number of MMC in order to

;********************************************************************************* ; Bank 4 ;********************************************************************************* ;******************************** MMC_SPIX RAM **************************** ;SPIX and MMC make use of the same RAM bank org bank4_org bank4 = $ mmc_spix_ram = $ ;MMC/SPI control register bank ;next_samp_ptr ds 1 ;points to next sample in buffer ;mmc_temp_data ds 1 ;temporary storage to move the data ; between the SX RAM banks mmc_status ds 1 ;MMC driver status byte ;======== spix_busy equ mmc_status.7 ;Busy bit set by SPIX VP to HIGH when byte ;transfer (SPI) is in progress mmc_busy equ mmc_status.6 ;set when the MMC is in BUSY state. Used in WRITE MODE mmc_read_write_data equ mmc_status.5 ;indicates that BLOCK READ/WRITE cycle is in progress mmc_error equ mmc_status.4 ;any error in data transfer ;MMC_R1 and MMC_R2 contain the error message mmc_no_response equ mmc_status.3 ;no response R1 was received ;within required time mmc_data_error equ mmc_status.2 ;data error token received ;during Block Read/Write command mmc_no_data equ mmc_status.1 ;no data block received from MMC mmc_wrong_command equ mmc_status.0 ;Set by the commands decoder, indicates not supported command ;======== mmc_cmd ds 1 ;mmc command - 6 bytes mmc_addr_b3 ds 1 mmc_addr_b2 ds 1 mmc_addr_b1 ds 1 mmc_addr_b0 ds 1 mmc_cmd_crc ds 1 mmc_r1 ds 1 ;mmc response - 2bytes ;mmc_r2 ds 1 mmc_temp ds 1 ;temporary storage for MMC driver mmc_temp1 ds 1 mmc_temp2 ds 1 ;mmc_data_pointer ds 1 ;pointer to the current address ;of the SX data RAM ;SPIX data spix_data_io ds 1 ;one-byte I/O data buffer/shift register spix_temp ds 1 ;temporary storage spix_shift_counter ds 1 ;I/O shift counter readSizeH ds 1 ;MSbyte of the size of the block to read from ;the MMC readSizeL ds 1 ;LSbyte of the size of the block to read from ;the MMC ;-----------------------;********************************************************************************* ; Bank 5 ;********************************************************************************* org bank5_org

35

bank5 = $ lcdBank = $ ;the lcdBank contains variables in data memory ;for use with any aspect of the LCD interface lcdCounter0 ds 1 ;just a counter lcdCounter1 ds 1 ;just a counter lcdDelay1 ds 1 ;delay counter for lcdDelay function lcdDelay2 ds 1 ;delay counter for lcdDelay function lcdCmdReg ds 1 ;this one byte data memory location will hold ;commands to be written to the Epson SED1335F0A ;by the lcdSendCMD function lcdDataReg ds 1 ;this one byte data memory location will hold ;data to be written to the Epson SED1335F0A ;by the lcdWriteByte function ;********************************************************************************* ; Bank 6 ;********************************************************************************* org bank6_org

bank6 = $ touchBank = $ ;the touchBank contains variable in data memory ;for use with any aspect of the touchscreen interface touchAddHi ds 1 ;holds the resultant address offset for retrieval of touchAddMid ds 1 ;command from the MMC (menu switch OR ir code) touchAddLow ds 1 ; touchYPosRegHi ds 1 ;holds the high 8 bits of the Y position A/D for offset touchYPosRegLow ds 1 ;holds the low 4 bits of the Y position A/D for offset touchXPosRegLow ds 1 ;holds the low 4 bits of the X position A/D for offset touchXPosRegHi ds 1 ;holds the high 8 bits of the X position A/D for offset touchTempLow touchTempHi touchTemp ds touchBitsTemp touchDelayTemp touchFlags ds touchValid ds 1 ;temp registers ds 1 1 ds 1 ds 1 1

equ touchFlags.0

;********************************************************************************* ; Bank 7 ;********************************************************************************* org bank7 =$ bank7_org

IFDEF SX48_52 ;********************************************************************************* ; Bank 8 ;********************************************************************************* org $80 ;bank 8 address on SX52 bank8 =$

;********************************************************************************* ; Bank 9 ;********************************************************************************* org $90 ;bank 9 address on SX52 bank9 =$

;*********************************************************************************

36

; Bank A ;********************************************************************************* org $A0 ;bank A address on SX52 bankA =$

;********************************************************************************* ; Bank B ;********************************************************************************* org $B0 ;bank B address on SX52 bankB =$

;********************************************************************************* ; Bank C ;********************************************************************************* org $C0 ;bank C address on SX52 bankC =$

;********************************************************************************* ; Bank D ;********************************************************************************* org $D0 ;bank D address on SX52 bankD =$

;********************************************************************************* ; Bank E ;********************************************************************************* org $E0 ;bank E address on SX52 bankE =$

;********************************************************************************* ; Bank F ;********************************************************************************* org $F0 ;bank F address on SX52 bankF ENDIF ;**************************************************************************************** * ;---------------------------------- Port Assignment-------------------------------------;**************************************************************************************** * =$

RA_latch RA_DDIR RA_LVL RA_PLP

equ equ equ equ

%11111010 %00100101 %00000000 %00001111

;SX18/20/28/48/52 ;SX18/20/28/48/52 ;SX18/20/28/48/52 ;SX18/20/28/48/52

port port port port

A A A A

latch init DDIR value LVL value PLP value

RB_latch equ %00000000 ;SX18/20/28/48/52 port B latch init;intial value affter reset RB_DDIR equ %11111111 ;SX18/20/28/48/52 port B DDIR value;0=Output,1=Input RB_ST equ %11111111 ;SX18/20/28/48/52 port B ST value;0=Enable,1=Disable RB_LVL equ %00000000 ;SX18/20/28/48/52 port B LVL value;0=CMOS,1=TTL RB_PLP equ %00000000 ;SX18/20/28/48/52 port B PLP value;0=Enable,1=Disable RC_latch equ %00000000 ;SX18/20/28/48/52 port C latch init;intial value affter reset RC_DDIR equ %11111111 ;SX18/20/28/48/52 port C DDIR value;0=Output,1=Input RC_ST equ %00000000 ;SX18/20/28/48/52 port C ST value;0=Enable,1=Disable RC_LVL equ %00000000 ;SX18/20/28/48/52 port C LVL value;0=CMOS,1=TTL

37

RC_PLP

equ %11111111

;SX18/20/28/48/52 port C PLP value;0=Enable,1=Disable

IFDEF SX48_52 RD_latch equ %00000000 ;SX48/52 port D latch init;intial value affter reset RD_DDIR equ %11111101 ;SX48/52 port D DDIR value;0=Output,1=Input RD_ST equ %11111101 ;SX48/52 port D ST value;0=Enable,1=Disable RD_LVL equ %00000000 ;SX48/52 port D LVL value;0=CMOS,1=TTL RD_PLP equ %00000010 ;SX48/52 port D PLP value;0=Enable,1=Disable RE_latch equ %01001000 ;SX48/52 port E latch init;intial value affter reset RE_DDIR equ %10000100 ;SX48/52 port E DDIR value;0=Output,1=Input RE_ST equ %10000111 ;SX48/52 port E ST value;0=Enable,1=Disable RE_LVL equ %00000000 ;SX48/52 port E LVL value;0=CMOS,1=TTL RE_PLP equ %11111111 ;SX48/52 port E PLP value;0=Enable,1=Disable ENDIF

;**************************************************************************************** ***** ;--------------------------------- Pin Definitions -----------------------------------------;**************************************************************************************** ***** ;Pin assignments rs232Rxpin1 rs232Txpin1 rs232Rxpin2 rs232Txpin2 for UART(s) equ ra.2 equ ra.3 equ ra.0 equ ra.1

;UART1 ;UART1 ;UART2 ;UART2

receive input transmit output receive input transmit output

;Pin assingment for SPI_X interface spix_clk_pin equ ra.4 ;SPI clock output spix_out_pin equ ra.6 ;SPI-Master-Out-Slave-In spix_in_pin equ ra.5 ;SPI-Master-In-Slave-Out spix_cs_pin equ ra.7 ;SPI device select ;Pin assignments for LCD interface lcdAoPin equ re.6 lcdRWPin equ re.5 lcdEPin equ re.4 lcdRESPin equ re.3 ;Pin assignment for programming mode button programButton equ re.7 ;user places VURC into programming mode by ;pressing this button ;Pin assignment for Epson SED1335F0A busy flag statusFlag equ rc.6 ;the lcdWaitNotBusy function will poll this ;pin when checking the status of the lcd controller ;Pin assignments for the Touchscreen interface touchDin equ rd.1 ;sx sends data to the touch controller on this pin touchDclk equ re.0 ;pin for clocking data in and out of touch controller touchDout equ re.2 ;sx receives data from the touch controller on this pin ;**************************************************************************************** ***** ;--------------------------------- Port Definitions ----------------------------------------;**************************************************************************************** ***** ;Port definition for LCD interface lcdData equ rc ;**************************************************************************************** *****

38

;---------------------------------- Program constants --------------------------------------;**************************************************************************************** ***** ;**************************************************************************************** ***** ;UART Constants values ;**************************************************************************************** ***** intPeriod = 217 UARTfs Num = 4 = 230400

; Number of times ISR thread1 is called in the ; ISRMultiplexer IFDEF U1B1200 UARTBaud1 = 1200 ENDIF IFDEF U1B2400 UARTBaud1 = 2400 ENDIF IFDEF U1B4800 UARTBaud1 = 4800 ENDIF IFDEF U1B9600 UARTBaud1 = 9600 ENDIF IFDEF U1B1920 UARTBaud1 = 19200 ENDIF IFDEF U1B5760 UARTBaud1 = 57600 ENDIF UARTDivide1 = (UARTfs/(UARTBaud1*Num)) UARTStDelay1 = UARTDivide1 +(UARTDivide1/2)+1 IFDEF U2B1200 UARTBaud2 = 1200 ENDIF IFDEF U2B2400 UARTBaud2 = 2400 ENDIF IFDEF U2B4800 UARTBaud2 = 4800 ENDIF IFDEF U2B9600 UARTBaud2 = 9600 ENDIF IFDEF U2B1920 UARTBaud2 = 19200 ENDIF IFDEF U2B5760 UARTBaud2 = 57600 ENDIF UARTDivide2 = (UARTfs/(UARTBaud2*Num)) UARTStDelay2 = UARTDivide2 +(UARTDivide2/2)+1

39

IFDEF SX48_52 ;**************************************************************************************** ***** ; SX48BD/52BD Mode addresses ; *On SX48BD/52BD, most registers addressed via mode are read and write, with the ; exception of CMP and WKPND which do an exchange with W. ;**************************************************************************************** ***** ;------------------------------- Timer (read) addresses ------------------------------------TCPL_R TCPH_R TR2CML_R TR2CMH_R TR1CML_R TR1CMH_R TCNTB_R TCNTA_R equ equ equ equ equ equ equ equ $00 $01 $02 $03 $04 $05 $06 $07 ;Read ;Read ;Read ;Read ;Read ;Read ;Read ;Read Timer Timer Timer Timer Timer Timer Timer Timer Capture register Capture register R2 low byte R2 high byte R1 low byte R1 high byte control register control register low byte high byte

B A

;---------------------------------- Exchange addresses -------------------------------------CMP equ $08 ;Exchange Comparator enable/status register with W WKPND equ $09 ;Exchange MIWU/RB Interrupts pending with W ;----------------------------------Port setup (read) addresses------------------------------WKED_R equ $0A ;Read MIWU/RB Interrupt edge setup, 1 = falling, 0 = rising WKEN_R equ $0B ;Read MIWU/RB Interrupt edge setup, 0 = enabled, 1 = disabled ST_R equ $0C ;Read Port Schmitt Trigger setup, 0 = enabled, 1 = disabled LVL_R equ $0D ;Read Port Schmitt Trigger setup, 0 = enabled, 1 = disabled PLP_R equ $0E ;Read Port Schmitt Trigger setup, 0 = enabled, 1 = disabled DDIR_R equ $0F ;Read Port Direction ;-----------------------------------Timer (write) addresses---------------------------------CLR_TMR TR2CML_W TR2CMH_W TR1CML_W TR1CMH_W TCNTB_W TCNTA_W equ equ equ equ equ equ equ $10 $12 $13 $14 $15 $16 $17 ;Resets 16-bit Timer ;Write Timer R2 low byte ;Write Timer R2 high byte ;Write Timer R1 low byte ;Write Timer R1 high byte ;Write Timer control register B ;Write Timer control register A

;-------------------------------------Port setup (write) addresses--------------------------WKED_W equ $1A ;Write MIWU/RB Interrupt edge setup, 1 = falling, 0 = rising WKEN_W equ $1B ;Write MIWU/RB Interrupt edge setup, 0 = enabled, 1 = disabled ST_W equ $1C ;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled LVL_W equ $1D ;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled PLP_W equ $1E ;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled DDIR_W equ $1F ;Write Port Direction ELSE ;**************************************************************************************** ***** ; SX28AC Mode addresses ; *On SX28, all registers addressed via mode are write only, with the exception of ; CMP and WKPND which do an exchange with W. ;**************************************************************************************** ***** ;------------------------------------------Exchange addresses--------------------------------

40

CMP equ $08 ;Exchange Comparator enable/status register with W WKPND equ $09 ;Exchange MIWU/RB Interrupts pending with W ;-----------------------------------------Port setup (read) addresses-----------------------WKED_W equ $0A ;Write MIWU/RB Interrupt edge setup, 1 = falling, 0 = rising WKEN_W equ $0B ;Write MIWU/RB Interrupt edge setup, 0 = enabled, 1 = disabled ST_W equ $0C ;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled LVL_W equ $0D ;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled PLP_W equ $0E ;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled DDIR_W equ $0F ;Write Port Direction ENDIF ;*********************** MMC COMMAND INTERPRETER ********************** ; ;FUNCTIONS are not MMC card commands, but sequences of the commands. ;The MMC VP currently implements four separate FUNCTIONS ; - synchronize ; - initialize ; - read the data block ; - write the data block mmc_synchronize equ $FF ;send 80 SPI_clk signals for initial synchronization mmc_initialize equ $FE ;card initialization procedure ; flow chart (exept for synchronization) mmc_block_read_command equ $FD ;Complete implementation of the block read flow chart ;Send the Read Block Command and set the ;mmc_read_write_data flag in the MMC_STATUS byte ;The MMC /CS line is left active (LOW) until the data ;are read. Get the data block from MMC and ;finishes the read block cycle by setting MMC /CS mmc_block_write_command equ $FA ;complete implementation of the block writing ; ;MMC COMMANDS. ;Implemented MMC commands are used as FUNCTION calls ;Other commands listed here (but currently unimplemented) are presented ; mainly for reference. These commands are described in detail in the MMC manual. mmc_go_idle_state equ $40 ;CMD0 ;these three command are used as a part mmc_send_op_cond equ $41 ;CMD1 ;of INITIALIZE function mmc_set_blocklen equ $50 ;CMD16 mmc_read_single_block equ $51 ;CMD17 mmc_write_block equ $58 ;CMD24 ;----------------------;MMC commands currently NOT implemented: ;mmc_send_status equ $4d ;CMD13 assuming that status data come in the ;R2 bytes ;mmc_send_csd equ $49 ;CMD9 ;mmc_send_cid equ $4a ;CMD10 ;mmc_program_csd equ $5b ;CMD27 ;mmc_set_write_prot equ $5c ;CMD28 ;mmc_clr_write_prot equ $5d ;CMD29 ;mmc_send_write_prot equ $5e ;CMD30 ;mmc_tag_sector_start equ $60 ;CMD32 ;mmc_tag_sector_end equ $61 ;CMD33 ;mmc_untag_sector equ $62 ;CMD34 ;mmc_tag_erase_group_start equ $63 ;CMD35 ;mmc_tag_erase_group_end equ $64 ;CMD36 ;mmc_untag_erase_group equ $65 ;CMD37 ;mmc_erase eque $66 ;CMD38 ;mmc_crc_on equ $67 ;CMD59 ;****** Adjustable Paramaters ; sx_freq_factor = 1 ;this is a time delay scaling factor, ; for SX running at 50MHz(=1), 100MHz (=2)

41

MMC_size = 16 ;1-128 chip_type = 1 ;0 or 1

;storage size of MMC card ;0=SX18/28, 1=SX52

;***SPIX timing delays: ;spix_rate = (1 + (3 * ( sx_freq_factor - 1))) spix_rate = sx_freq_factor ;rate factor for SPIX.MMC ; (may need to be trimmed for different SX clock rates) sync_duration = 10 ;?-255 ;MMC SYNCHRONIZATION function duration cmd1_resp_wait = $80 * sx_freq_factor ;?-128 ;initialization (CMD1) response wait duration cmd1_delay1 = $8 ;* sx_freq_factor ;?-128 ;initialization (CMD1) internal loop delay cmd1_delay2 = $10 ;* sx_freq_factor ;?-128 ;initialization (CMD1) internal loop delay cmd1_delay3 = $80 * sx_freq_factor ;?-128 ;initialization (CMD1) internal loop delay resp_r1_delay = 32 * sx_freq_factor ;2-255 ;delay for a RESPONSE from MMC blk_rd_delay1 = 1 * sx_freq_factor ;?-255 ;delay for MMC initial block read preparation " written blk_rd_wait = 20 * sx_freq_factor ;?-255 ;read wait time MMC incoming data bytes blk_wr_delay = 20 * sx_freq_factor ;?-255 ;delay for MMC initial block write preparation

mmc_blk_size = 512 ;block size for reading/writing MMC (in SPI mode) mmc_buffsize = 32 ;MMC read/write buffer size: must be =(2^n)*16, n=0,1,2(,3 for SX52) ; (only 16 and 32 have been tested) IF MMC_size<16 end_of_mem = MMC_size<<4-3 ;last bank of mmc memory blocks ELSE ; for MMC cards >16Meg end_of_mem = MMC_size>>4-3 ;last bank of mmc memory blocks ENDIF end_of_mem = $37 ; or end of audio sample (comment this if needed) ;**************************************************************************************** ***** ;TouchScreen Constants values ;**************************************************************************************** ***** touchGetXCmd equ touchGetYCmd equ 0xD1 ;command byte for the X command retrieval 0x91 ;command byte for the Y command retrieval

menuMoffsetHi equ 0x01 ;Multiplier offset for current menu number menuMoffsetLow equ 0x62 ;(0x016200)

;**************************************************************************************** ************ ;----------------------------------------------Program memory ORG defines-------------------------;**************************************************************************************** ************ INTERRUPT_ORG equ $0 ; Page 1 (Interupts must always start at location zero) RESETENTRY_ORG equ $1FB ; The program will jump here on reset SUBROUTINES1_ORG equ $200 ; Page 2 (subroutines in this location) STRINGS_ORG equ $300 ; The strings are in the location $300 SUBROUTINES2_ORG equ $400 ; Page 3 (subroutines in this location) SUBROUTINES3_ORG equ $600 ; Page 4 (subroutines in this location) LCD_ORG equ $800 ; Page 5 will store the LCD routines TOUCHSCREEN_ORG equ $A00 ; Page 6 will contain the touchscreen routines MISCELANEOUS_ORG equ $C00 ; Page 7 will contain miscelaneous routines MAINPROGRAM_ORG equ $E00 ; The main program is in the last page of ; program memory

;**************************************************************************************** ***** org INTERRUPT_ORG ; First location in program memory.

42

;**************************************************************************************** ***** ;**************************************************************************************** ***** ;----------------------------------- Interrupt Service Routine -----------------------------; Note 1: The interrupt code must always originate at address $0. ; Interrupt Frequency = (Cycle Frequency / -(retiw value)) ; For example: With a retiw value of -217 and an oscillator frequency ; of 50MHz, this code runs every 4.32us. ; Note 2: Mode Register 'M' is not saved in SX 28 but saved in SX 52 when an Interrupt ; occurs. If the code is to run on a SX 28 and 'M' register is used in the ISR, ; then the 'M' register has to be saved at the Start of ISR and restored at the ; End of ISR. ;**************************************************************************************** ***** org $0 interrupt ;3 ;**************************************************************************************** ***** ; Interrupt ; Interrupt Frequency = (Cycle Frequency / -(retiw value)) For example: ; With a retiw value of -217 and an oscillator frequency of 50MHz, this code runs ; every 4.32us. ;**************************************************************************************** ***** ;**************************************************************************************** ***** ;--------------------------------------------VP:VP Multitasker------------------------------; Virtual Peripheral Multitasker : up to 16 individual threads, each running at the ; (interrupt rate/16). Change them below: ;Input variable(s): isrmultiplex: variable used to choose threads ;Output variable(s): None,executes the next thread ;Variable(s) affected: isrmultiplex ;Flag(s) affected: None ;Program Cycles: 9 cycles (turbo mode) ;**************************************************************************************** ***** _bank inc mov Multiplexbank isrMultiplex w,isrMultiplex ; ; toggle interrupt rate ;

;**************************************************************************************** ***** ; The code between the tableStart and tableEnd statements MUST be completely within the first ; half of a page. The routines it is jumping to must be in the same page as this table. ;**************************************************************************************** ***** tableStart jmp jmp jmp jmp jmp jmp jmp jmp jmp jmp jmp jmp jmp jmp jmp ; Start all tables with this macro ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;

pc+w isrThread1 isrThread2 isrThread3 isrThread4 isrThread1 isrThread5 isrThread6 isrThread7 isrThread1 isrThread8 isrThread9 isrThread10 isrThread1 isrThread11

43

jmp jmp tableEnd

isrThread12 isrThread13

; ; ; End all tables with this macro.

;**************************************************************************************** ***** ;VP: VP Multitasker ; ISR TASKS ;**************************************************************************************** ***** isrThread1 ; Serviced at ISR rate/4

;**************************************************************************************** ***** ; Virtual Peripheral: Universal Asynchronous Receiver Transmitter (UART) These routines send ; and receive RS232 serial data, and are currently configured (though modifications can be ; made) for the popular "No parity-checking, 8 data bit, 1 stop bit" (N,8,1) data format. ; ; The VP below has 2 UARTS implemented - UART1 & UART2. Both the UARTs can work at independent ; Baud Rates. ; ; RECEIVING: The rs232Rx1flag & rs232Rx2flag are set high whenever a valid byte of data has ; been received and it is the calling routine's responsibility to reset this flag once the ; incoming data has been collected. ; ; TRANSMITTING: The transmit routine requires the data to be inverted and loaded ; (rs232Txhigh+rs232Txlow) register pair (with the inverted 8 data bits stored in ; rs232Txhigh and rs232Txlow bit 7 set high to act as a start bit). Then the number of bits ; ready for transmission (10=1 start + 8 data + 1 stop) must be loaded into the rs232Txcount ; register. As soon as this latter is done, the transmit routine immediately begins sending ; the data. This routine has a varying execution rate and therefore should always be ; placed after any timing-critical virtual peripherals such as timers, ; adcs, pwms, etc. ; Note: The transmit and receive routines are independent and either may be removed for each ;of the UARTs. The initial "_bank rs232TxBank" & "_bank rs232RxBank" (common) ;instruction is kept for Transmit & Receive routines. ; Input variable(s) : rs232Tx1Low (only high bit used), rs232Tx1High, rs232Tx1Count ; If rs232Tx1Flag SET, then transmit on UART1 ; rs232Tx2Low (only high bit used), rs232Tx2High, rs232Tx2Count ; If rs232Tx2Flag SET, then transmit on UART2 ; Output variable(s) : rs232Rx1Flag, rs232Rx1Byte ; rs232Rx2Flag, rs232Rx2Byte ; Variable(s) affected : rs232Tx1Divide, rs232Rx1Divide, rs232Rx1Count ; rs232Tx2Divide, rs232Rx2Divide, rs232Rx2Count ; Flag(s) affected : rs232Tx1Flag, rs232Tx2Flag ; rs232Rx1Flag, rs232Rx1Flag ;Program cycles: 22 worst case for Tx, 23 worst case for Rx ;Variable Length? Yes. ;**************************************************************************************** ***** UART1 rs232Transmit _bank rs232TxBank ;2 switch to serial register bank sb rs232Tx1Flag ;1 jmp rs232Receive1 ;1 decsz rs232Tx1Divide ;1 only execute the transmit routine jmp rs232Receive1 ;1 mov w,#UARTDivide1 ;1 load UART1 baud rate (50MHz) mov rs232Tx1Divide,w ;1 test rs232Tx1Count ;1 are we sending?

44

snz ;1 jmp rs232Receive1

;1

:txbit clc ;1 yes, ready stop bit rr rs232Tx1High ;1 and shift to next bit rr rs232Tx1Low ;1 dec rs232Tx1Count ;1 decrement bit counter snb rs232Tx1Low.6 ;1 output next bit clrb rs232TxPin1 ;1 sb rs232Tx1Low.6 ;1 setb rs232TxPin1 ;1 test rs232Tx1Count ;1 are we sending? snz ;1 clrb rs232Tx1Flag ;1,22 rs232Receive1 _bank rs232RxBank ;2 sb rs232RxPin1 ;1 get current rx bit clc ;1 snb rs232RxPin1 ;1 stc ;1 test rs232Rx1Count ;1 currently receiving byte? sz ;1 jmp :rxbit ;1 if so, jump ahead mov w,#9 ;1 in case start, ready 9 bits sc ;1 skip ahead if not start bit mov rs232Rx1Count,w ;1 it is, so renew bit count mov w,#UARTStDelay1 ;1 ready 1.5 bit periods (50MHz) mov rs232Rx1Divide,w ;1 :rxbit decsz rs232Rx1Divide ;1 middle of next bit? jmp :rs232RxOut1 ;1 mov w,#UARTDivide1 ;1 yes, ready 1 bit period (50MHz) mov rs232Rx1Divide,w ;1 dec rs232Rx1Count ;1 last bit? sz ;1 if not rr rs232Rx1Byte ;1 then save bit snz ;1 if so, setb rs232Rx1Flag ;1,23 then set flag :rs232RxOut1 UART2 _bank rs232TxBank ;2 switch to serial register bank sb rs232Tx2flag ;1 jmp rs232Receive2 ;1 decsz rs232Tx2Divide ;1 only execute the transmit routine jmp rs232Receive2 ;1 mov w,#UARTDivide2 ;1 load UART2 baud rate (50MHz) mov rs232Tx2Divide,w ;1 test rs232Tx2Count ;1 are we sending? snz ;1 jmp rs232Receive2 ;1 :txbit clc ;1 yes, ready stop bit rr rs232Tx2High ;1 and shift to next bit rr rs232Tx2Low ;1 dec rs232Tx2Count ;1 decrement bit counter snb rs232Tx2Low.6 ;1 output next bit clrb rs232TxPin2 ;1 sb rs232Tx2Low.6 ;1 setb rs232TxPin2 ;1 test rs232Tx2Count ;1 are we sending? snz ;1 clrb rs232Tx2Flag ;1,22 rs232Receive2 _bank rs232RxBank ;2 sb rs232RxPin2 ;1 get current rx bit clc ;1 snb rs232RxPin2 ;1 stc ;1 test rs232Rx2Count ;1 currently receiving byte?

45

sz ;1 jmp :rxbit ;1 if so, jump ahead mov w,#9 ;1 in case start, ready 9 bits sc ;1 skip ahead if not start bit mov rs232Rx2Count,w ;1 it is, so renew bit count mov w,#UARTStDelay2 ;1 ready 1.5 bit periods (50MHz) mov rs232Rx2Divide,w ;1 :rxbit decsz rs232Rx2Divide ;1 middle of next bit? jmp :rs232RxOut2 ;1 mov w,#UARTDivide2 ;1 yes, ready 1 bit period (50MHz) mov rs232Rx2Divide,w ;1 dec rs232Rx2Count ;1 last bit? sz ;1 if not rr rs232Rx2Byte ;1 then save bit snz ;1 if so, setb rs232Rx2Flag ;1,23 then set flag :rs232RxOut2 UARTOut ;**************************************************************************************** ***** ;===================================== PUT YOUR OWN VPs HERE================================== ; Virtual Peripheral: ; ;Input variable(s): ;Output variable(s): ;Variable(s) affected: ;Flag(s) affected: ;**************************************************************************************** ***** ;-------------------------------------------------------------------------------------------jmp isrOut ; 7 cycles until mainline program resumes execution ;-------------------------------------------------------------------------------------------isrThread2 ; Serviced at ISR rate/16 ;-------------------------------------------------------------------------------------------jmp isrOut ; 7 cycles until mainline program resumes execution ;-------------------------------------------------------------------------------------------isrThread3 ; Serviced at ISR rate/16 ;-------------------------------------------------------------------------------------------jmp isrOut ; 7 cycles until mainline program resumes execution ;-------------------------------------------------------------------------------------------isrThread4 ; Serviced at ISR rate/16 ;-------------------------------------------------------------------------------------------jmp isrOut ; 7 cycles until mainline program resumes execution ;-------------------------------------------------------------------------------------------isrThread5 ; Serviced at ISR rate/16 ;-------------------------------------------------------------------------------------------jmp isrOut ; 7 cycles until mainline program resumes execution ;-------------------------------------------------------------------------------------------isrThread6 ; Serviced at ISR rate/16 ;-------------------------------------------------------------------------------------------jmp isrOut ; 7 cycles until mainline program resumes execution ;-------------------------------------------------------------------------------------------isrThread7 ; Serviced at ISR rate/16 ;-------------------------------------------------------------------------------------------jmp isrOut ; 7 cycles until mainline program resumes execution

46

;-------------------------------------------------------------------------------------------isrThread8 ; Serviced at ISR rate/16 ;-------------------------------------------------------------------------------------------jmp isrOut ; 7 cycles until mainline program resumes execution ;-------------------------------------------------------------------------------------------isrThread9 ; Serviced at ISR rate/16 ;-------------------------------------------------------------------------------------------jmp isrOut ; 7 cycles until mainline program resumes execution ;-------------------------------------------------------------------------------------------isrThread10 ; Serviced at ISR rate/16 ;-------------------------------------------------------------------------------------------jmp isrOut ; 7 cycles until mainline program resumes execution ;-------------------------------------------------------------------------------------------isrThread11 ; Serviced at ISR rate/16 ;-------------------------------------------------------------------------------------------jmp isrOut ; 7 cycles until mainline program resumes execution ;-------------------------------------------------------------------------------------------isrThread12 ; Serviced at ISR rate/16 ;-------------------------------------------------------------------------------------------jmp isrOut ; 7 cycles until mainline program resumes execution ;-------------------------------------------------------------------------------------------isrThread13 ; Serviced at ISR rate/16 ; This thread must reload the isrMultiplex register _bank Multiplexbank mov isrMultiplex,#255 ;reload isrMultiplex so isrThread1 will be run on the ; next interrupt. jmp isrOut ; 7 cycles until mainline program resumes execution ; This thread must reload the isrMultiplex register ; since it is the last one to run in a rotation. ;-------------------------------------------------------------------------------------------isrOut ;********************************************************************************* ; Set Interrupt Rate ;********************************************************************************* isr_end mov w,#-intperiod ;refresh RTCC on return ;(RTCC = 217, no. of instructions executed in the ISR) retiw ;return from the interrupt ;**************************************************************************************** * ; End of the Interrupt Service Routine ;**************************************************************************************** * ;**************************************************************************************** * ; RESET VECTOR ;**************************************************************************************** * ;**************************************************************************************** * ;----------------------------------------Reset Entry------------------------------------

47

;**************************************************************************************** * org RESETENTRY_ORG ; Program starts here on power-up

resetEntry

page _resetEntry jmp _resetEntry ;**************************************************************************************** * ;-----------------------------------------UART Subroutines------------------------------;**************************************************************************************** * org SUBROUTINES1_ORG ;**************************************************************************************** * ; Function : getbyte ; INPUTS : rs232RX1Flag,rs232Rx2Flag ; OUTPUTS : Received byte in rs232Rx1Byte or rs232Rx2Byte ; Get byte via serial port and echo it back to the serial port ;**************************************************************************************** * getbyte getbyte1 _bank rs232RxBank ; switch to rs232 bank sb rs232RX1Flag ; check if byte has been received by UART1 jmp getbyte2 clrb rs232Rx1Flag ; reset the receive flag mov w,rs232Rx1Byte ; store byte (copy using W) mov rs232Byte1,w getbyte2 sb rs232Rx2Flag jmp :out clrb rs232Rx2Flag mov w,rs232Rx2Byte mov rs232Byte2,w :out retp ; check if byte has been received by UART2

;**************************************************************************************** ; Function : sendbyte ;INPUTS : rs232Tx1Flag set, rs232Tx1Byte - the byte to be sent via UART1 ; rs232Tx2Flag set, rs232Tx2Byte- the byte to be sent via UART2 ; OUTPUTS : Outputs The byte via RS-232 UART1/UART2 ; Send byte via serial port ; ;Note: Before calling a sendbyte in Main, it should be ensured that respective ; flag of the UART rs232Tx1Flag/rs232Tx2Flag is CLEAR, and if clear then a ; byte can be sent, then the respective UART flag must be SET. ;**************************************************************************************** sendbyte sendbyte1 _bank rs232TxBank test rs232Tx1Count sz jmp sendbyte2 sb rs232Tx1Flag jmp sendbyte2 mov w,rs232Tx1Byte w ; ready bits (inverse logic) rs232Tx1High,w ; store data byte rs232Tx1Low.7 ; set up start bit w,#10 ; 1 start + 8 data + 1 stop bit

not mov setb mov

48

mov

rs232Tx1Count,w

sendbyte2 test rs232Tx2Count sz jmp sendbyte1 sb rs232Tx2Flag jmp :out mov w,rs232Tx2Byte not w ; ready bits (inverse logic) mov rs232Tx2High,w ; store data byte setb rs232Tx2Low.7 ; set up start bit mov w,#10 ; 1 start + 8 data + 1 stop bit mov rs232Tx2Count,w :out retp ; leave and fix page bits ;********************************************************************************* ; Function : sendstring1 ; Care should be taken that the srings are located within program ; memory locations $300-$3ff as the area ; INPUTS : 'w', The address of a null-terminated string in program memory ; OUTPUTS : outputs the string via RS-232 UART1 ; Send string pointed to by address in W register ;Note: This routine is a locking routine in the sense that the function returns ; to 'main' (the calling function) only after all the bytes of the string ; are transmitted (until 00H is encountered). ;********************************************************************************* sendstring1 _bank rs232TxBank mov localTemp1,w ; store string address :string test rs232Tx1Count sz jmp :string setb rs232Tx1Flag ; SET flag for UART1 mov w,#STRINGS_ORG>>8 ; with indirect addressing mov m,w mov w,localTemp1 ; read next string character iread ; using the mode register test w ; are we at the last char? snz ; if not=0, skip ahead jmp :out ; yes, leave & fix page bits _bank rs232TxBank mov rs232Tx1Byte,w call sendByte1 ; not 0, so send character _bank rs232TxBank inc localTemp1 ; point to next character jmp :string ; loop until done :out clrb rs232Tx1Flag mov w,#$1F ; reset the mode register mov m,w retp

;********************************************************************************* ; Function : sendstring2 ; Care should be taken that the srings are located within program ; memory locations $300-$3ff as the area ; INPUTS : 'w', The address of a null-terminated string in program memory ; OUTPUTS : outputs the string via RS-232 UART2 ; Send string pointed to by address in W register ;Note: This routine is a locking routine in the sense that the function returns ; to 'main' (the calling function) only after all the bytes of the string ; are transmitted (until 00H is encountered). ;********************************************************************************* sendstring2 _bank rs232TxBank mov localTemp1,w :string test rs232Tx2Count

; store string address

49

sz jmp :string setb rs232Tx2Flag ; SET flag for UART2 mov w,#STRINGS_ORG>>8 ; with indirect addressing mov m,w mov w,localTemp1 ; read next string character iread ; using the mode register test w ; are we at the last char? snz ; if not=0, skip ahead jmp :out ; yes, leave & fix page bits _bank rs232TxBank mov rs232Tx2Byte,w call sendByte2 ; not 0, so send character _bank rs232TxBank inc localTemp1 ; point to next character jmp :string ; loop until done :out clrb rs232Tx2Flag mov w,#$1F ; reset the mode register mov m,w retp

;********************************************************************************* ;Function : sendhex ;INPUTS : w-The byte to be output ;OUTPUTS : outputs the hex byte via RS-232 ;Output a hex number ;********************************************************************************* sendhex mov localTemp1,w swap wreg and w,#$0f call hextable _bank rs232TxBank mov rs232Tx1Byte,w ;move byte to send into rs232Tx1Byte wait snb rs232Tx1Flag ;is flag clear? (ie: done sending any ;previous data?) if so, continue jmp wait ;wait for flag to clear setb rs232Tx1Flag ;set flag to send a byte call sendbyte1 mov w,localTemp1 and w,#$0f call hextable _bank rs232TxBank mov rs232Tx1Byte,w ;move byte to send into rs232Tx1Byte wait1 snb rs232Tx1Flag ;is flag clear? (ie: done sending any ;previous data?) if so, continue jmp wait1 ;wait for flag to clear setb rs232Tx1Flag ;set flag to send a byte call sendbyte1 retp hextable add pc,w retw '0' retw '1' retw '2' retw '3' retw '4' retw '5' retw '6' retw '7' retw '8' retw '9' retw 'A' retw 'B' retw 'C' retw 'D' retw 'E' retw 'F'

50

;**************************************************************************************** ** org STRINGS_ORG ; This label defines where strings are kept in program space. ;**************************************************************************************** ** ;**************************************************************************************** ** ;------------------------------------------ String Data ---------------------------------;**************************************************************************************** ** ;VP: RS232 Transmit _hitSpace dw 13,10,'File received, Hit Space...',0 _hello1 dw 13,10,'The following data has been written to and read from sector 1 of an MMC:',13,10,13,10,0 _hello2 dw 13,10,'Yup, The UART 2 works!!',0 _echodata dw 13,10,'Begin typing, and data will be echoed to the terminal:',13,10,0 _sendTextFile dw 13,10,'Send me a text file that is 514 bytes in size...',13,10,0 ;**************************************************************************************** * ;-----------------------------------------MMC Subroutines-------------------------------;**************************************************************************************** * org SUBROUTINES2_ORG ;****************************** ;*** 8-BIT SPI Master VP - SPIX ;****************************** ;SPIX DATA TRANSFER ;================== ; ;***Send the byte spix_send _bank mmc_spix_ram ;select SPIX RAM bank setb spix_busy ;set the bit indicating that ;SPIX started data transfer mov spix_shift_counter,#$08 ;set number of shifts spix_send_loop ;CLK_HIGH clrb spix_clk_pin ;set CLK_LOW movb spix_out_pin,spix_data_io.7 ;shift data out. CLK_LOW rl spix_data_io ;CLK_LOW mov spix_temp,#spix_rate ;transfer rate delay spix_loop2 djnz spix_temp,spix_loop2 ;CLK_LOW setb spix_clk_pin ;set CLK - HIGH mov spix_temp,#spix_rate ;transfer rate delay spix_loop3 djnz spix_temp,spix_loop3 ;CLK- HIGH djnz spix_shift_counter,spix_send_loop ;check the bit counter clrb spix_busy ;exit if done ; setb spix_out_pin ;don't set this bit because ;during initialization, this ;causes problems ret ;get the byte spix_get _bank mmc_spix_ram ;select SPIX RAM bank setb spix_busy ;prepare to start mov spix_data_io,#$ff ;preset all bits high STC ;including carry bit mov spix_shift_counter,#$08 ;set number of shifts spix_get_loop ;CLK_High clrb spix_clk_pin ;set CLK_LOW rl spix_data_io ;CLK_LOW IF sx_freq_factor>1 ;100 MHZ? mov spix_temp,#spix_rate ;transfer rate delay

51

spix_loop6 djnz spix_temp,spix_loop6 ; while CLK_LOW ENDIF SB spix_in_pin ;if new bit=1, then do nothing CLRB spix_data_io.0 ; otherwise, clear it accordingly setb spix_clk_pin ;set CLK_HIGH IF sx_freq_factor>1 ;100 MHZ? mov spix_temp,#spix_rate ;transfer rate delay spix_loop8 djnz spix_temp,spix_loop8 ;while CLK_High ENDIF djnz spix_shift_counter,spix_get_loop;check the bit counter setb spix_out_pin ;exit if done clrb spix_busy retp ;End of SPIX VP ;*********************** ; ;*** SPIX port initialization ; spix_init setb spix_clk_pin setb spix_out_pin setb spix_cs_pin RET ;*** Set MMC data address = 0 zero_MMC_addr CLR mmc_addr_b3 ;set the block address to read (hi byte first) CLR mmc_addr_b2 ; " CLR mmc_addr_b1 ; " CLR mmc_addr_b0 ; (lo byte last: always = 0 since 512 bytes/block) RET ;*** MMC Wait ;Sometimes a delay is needed for internal MMC processes ;mmc_long_wait MOV W,#$FF ;longest delay ;mmc_wait MOV mmc_temp1,W ;selectable delay (loaded in W prior to call) mloop49 mov mmc_temp,#$FF ;set wait cycles counter mloop69 djnz mmc_temp,mloop69 ;inner delay loop djnz mmc_temp1,mloop49 ;outer delay loop ret ;exit ;*** MMC Send "DUMMY" Bytes ;This subroutine generates a number of DUMMY byte transfer cycles on the SPI bus. ;The number of cycles should be specified in MMC_TEMP prior to the call. ;These dummy cycles are required by the MMC card data transfer protocol. ; mmc_delay _bank mmc_spix_ram call @spix_get djnz mmc_temp,mmc_delay ret ;*** MMC Send Command ;This Subroutine sends a 6 byte MMC command string starting with the MMC_CMD byte ;and finishing by CRC byte ; mmc_cmd_send _bank mmc_spix_ram ;select SPIX RAM bank mmc_loop2 mov spix_data_io,mmc_cmd call @spix_send ;send the byte call @Clk_delay ;delay between clock bursts _bank mmc_spix_ram mov spix_data_io,mmc_addr_b3 ;added following lines of code call @spix_send ;to send an argument to MMC instead call @Clk_delay ;delay between clock bursts _bank mmc_spix_ram mov spix_data_io,mmc_addr_b2 ;of just repeating the commands call @spix_send ;four times over call @Clk_delay ;delay between clock bursts _bank mmc_spix_ram mov spix_data_io,mmc_addr_b1 call @spix_send ;send the byte call @Clk_delay ;delay between clock bursts

52

_bank mmc_spix_ram mov spix_data_io,mmc_addr_b0 call @spix_send ;send the byte call @Clk_delay ;delay between clock bursts _bank mmc_spix_ram mov spix_data_io,mmc_cmd_crc ;send CRC to MMC call @spix_send ;send the byte call @Clk_delay ;delay between clock bursts _bank mmc_spix_ram setb spix_out_pin ;loop until all six bytes sent retp

;****************************MMC Get Response R1************************************** ;Get the response byte from the MMC. Wait for the response R1 for x=mmc_r1_wait_cycles ;byte cycles. If the R1 is not recieved or R1 is not $00, set the error flag. ;Number of wait cycles is recommended to be 2, but here we use 32 for safety. ;The routine can return two errors: (1) no response at all, (2) non zero response ;************************************************************************************* mmc_r1_get mmc_loop3

call @Clk_Delay ;delay between clock bursts while ;waiting for a response from MMC _bank mmc_spix_ram ;ensure proper bank access call @spix_get ;read the byte cjne spix_data_io,#$FF,mmc_loop4 ;if the byte is "FF" then repeat jmp mmc_loop3 ;mmc_r1_wait_cycles times retp

mmc_loop4 mov mmc_r1,spix_data_io ;move data to R1 response register call @Clk_delay ;delay between clock bursts _bank mmc_spix_ram ;clock MMC so that it can mov spix_data_io,#$FF ;finish internal operations call @spix_send retp ;return

;*****************************Delay Routine******************************** ;This routine should delay for approximately 3us ;This is with taking into account the operation of the ISR ;************************************************************************** Clk_delay _bank bank3 ;ensure bank3 access mov ClkDelayVar1,#$1A ;load delay variable 1 with #$1A delayLoop1 decsz ClkDelayVar1 ;delay routine jmp delayLoop1 retp ;*****************************Delay2 Routine******************************** ;The following routine should cause approximately a 1.5ms delay ;This is with taking into account the operation of the ISR ;*************************************************************************** Clk_delay2 _bank bank3 ;ensure bank3 access mov ClkDelayVar3,#$40 ;load delay variable 3 with #$40 mov ClkDelayVar2,#$FF ;load delay variable 2 with #$FF delayLoop2 decsz ClkDelayVar2 ;delay routine jmp delayLoop2 decsz ClkDelayVar3 jmp delayLoop2 retp ;************************************************************************* ;The reason that subroutines3_org is below is that the bottom half of page ;3 was full; consequently, calls to functions in the top half of page 3 ;did not work properly. org SUBROUTINES3_ORG

;******************** MMC Command Function Interpreter ******************* ;This is the MMC command decoder subroutine. This is an optional structure

53

;The actual commands can be executed separately. The use of this structure ;is to reduce the number of subroutines (i.e. CALLs) and replace them by JMPs ; mmc_execute _bank mmc_spix_ram cje mmc_cmd,#mmc_block_read_command,mmc_cmd_block_read cje mmc_cmd,#mmc_block_write_command,mmc_cmd_block_write cje mmc_cmd,#mmc_synchronize,mmc_cmd_synchronize cje mmc_cmd,#mmc_initialize,mmc_cmd_initialize setb mmc_wrong_command mmc_exit retp ;********************************************************************************* ;Function : mmc_cmd_block_read ;INPUTS : mmc_addr_b3, mmc_addr_b2, mmc_addr_b1, mmc_addr_b0, ; W register, readSizeH, readSizeL ;OUTPUTS : none ;This fuction will read the number of bytes specified in the readSizeH, ;readSizeL from the MMC starting at the address specified in mmc_addr_b3 ;thru mmc_addr_b0. The user of this function must ensure that sector ;boundaries are not crossed. Each sector in the MMC is 512 bytes in size, ;and a read function is not allowed to cross a sector boundary. Where the ;SX52BD passes the data obtained from for MMC is determined by the value ;passed to this function in the W register. A $01 in the W register means ;send the data out on UART1, a $02 in the W register means send the data ;out on UART 2, and a $04 in the W register means send the data out to ;the LCD using the lcdWriteByte function for each byte. ;********************************************************************************* mmc_cmd_block_read _bank bank3 mov storeW,w ;store contents of w in data ;register _bank mmc_spix_ram ;store address to read from mov w,mmc_addr_b0 ;in temporary registers _bank bank3 mov temp_addr_b0,w _bank mmc_spix_ram ;store address to read from mov w,mmc_addr_b1 ;in temporary registers _bank bank3 mov temp_addr_b1,w _bank mmc_spix_ram ;store address to read from mov w,mmc_addr_b2 ;in temporary registers _bank bank3 mov temp_addr_b2,w _bank mmc_spix_ram ;store address to read from mov w,mmc_addr_b3 ;in temporary registers _bank bank3 mov temp_addr_b3,w _bank mmc_spix_ram mov w,readSizeL mov mmc_addr_b0,w _bank bank3 mov blockReadB1,w

;set up a countdown for a ;variable byte block read

_bank mmc_spix_ram clr mmc_addr_b2 ;clear upper two bytes of argument clr mmc_addr_b3 ;in preparation for mmc_cmd_block_set ;function call mov w,readSizeH mov mmc_addr_b1,w _bank bank3 mov blockReadB2,w ;set up a countdown for a ;variable byte block read call @mmc_cmd_block_set test mmc_status ;check how set block length procedure went sz jmp @statusError ;exit if we got an error reading

54

;setting block length _bank bank3 mov w,temp_addr_b0 _bank mmc_spix_ram mov mmc_addr_b0,w _bank bank3 mov w,temp_addr_b1 _bank mmc_spix_ram mov mmc_addr_b1,w _bank bank3 mov w,temp_addr_b2 _bank mmc_spix_ram mov mmc_addr_b2,w _bank bank3 mov w,temp_addr_b3 _bank mmc_spix_ram mov mmc_addr_b3,w ;restore address to read from ;from temporary registers

;restore address to read from ;from temporary registers

;restore address to read from ;from temporary registers

;restore address to read from ;from temporary registers

_bank mmc_spix_ram ;Select the RAM Bank clrb spix_cs_pin ;set MMC_CS active (LOW) clr mmc_status :do_read mov mmc_cmd,#$51 ;send the BLOCK READ Command call @mmc_cmd_send call @mmc_r1_get _bank mmc_spix_ram cje mmc_r1,#$00,@mmc_read_data_block ;correct R1 is equal to #$00 setb mmc_error ;if not - set the error flag jmp mmc_read_error ;and exit mmc_read_data_block _bank mmc_spix_ram setb mmc_read_write_data ;select the RAM bank

;await data start byte = $FE mmc_label41 call @spix_get ;wait for data start byte = $FE call @Clk_delay ;delay between clock ;bursts _bank mmc_spix_ram cje spix_data_io,#$fe,@mmc_read_block ;End waiting if Start Byte jmp @mmc_label41 ;else read another byte mmc_read_block mmc_read_byte call @spix_get ;***************test where I need to send the byte (i.e.: UART1, UART2, or LCD)********* _bank bank3 cje storeW,#$01,@txUART1 ;if control byte is $01, then ;transmit on UART1 cje storeW,#$02,@txUART2 ;if control byte is $01, then ;transmit on UART1 cje storeW,#$04,@txLCD ;if control byte is $01, then ;transmit on UART1 jmp @mmc_read_error ;error, leave function txUART1 _bank mmc_spix_ram mov w,spix_data_io ;place byte read from MMC into ;the w register.... _bank rs232TxBank mov rs232Tx1Byte,w ;move byte to be sent into ;UART1 transmit register :loop1 snb rs232Tx1Flag ;check transmit flag, if clear ;then send another byte, otherwise jmp @:loop1 ;wait until clear setb rs232Tx1Flag ;set flag to tell UART to send ;the byte in rs232Tx1Byte call @sendByte1 ;write the received byte to ;hyperterminal via RS-232 jmp @byteSent ;byte sent on UART1, go check ;if done or get another to send

55

txUART2 _bank mmc_spix_ram mov w,spix_data_io ;place byte read from MMC into ;the w register.... _bank rs232TxBank mov rs232Tx2Byte,w ;move byte to be sent into ;UART1 transmit register :loop2 snb rs232Tx2Flag ;check transmit flag, if clear ;then send another byte, otherwise jmp @:loop2 ;wait until clear setb rs232Tx2Flag ;set flag to tell UART to send ;the byte in rs232Tx1Byte call @sendByte2 ;write the received byte to ;hyperterminal via RS-232 jmp @byteSent ;byte sent on UART2, go check ;if done or get another to send txLCD _bank mmc_spix_ram mov w,spix_data_io ;place byte read from MMC into call @lcdWriteByte ;the w register....

byteSent _bank bank3 ;ensure bank3 access testB1 test blockReadB1 ;is B1 == 0? sb z ;test status flag jmp testB1Again ;B1 != 0, so see if it is equal ;to 1 decB2 dec blockReadB2 ;B1 == 0, so decrement B2 and B1 decB1 dec blockReadB1 ;decrement B1 jmp mmc_read_byte ;get another byte from MMC testB1Again cjne blockReadB1,#$01,decB1 ;is B1 == 1? testB2 cjne blockReadB2,#$00,decB1 ;is B2 == 0? call @spix_get call @spix_get ;"read" two bytes CRC ;the CRC is not implemented and thus the data are not used

mmc_read_exit call @spix_get ;DUMMY read cycle mmc_read_error clrb mmc_read_write_data ;end the transfer and exit setb spix_cs_pin ;set MMC to inactive state jmp @mmc_exit ;done ;********************************************************************************* ;Function : mmc_cmd_block_write ;INPUTS : mmc_addr_b3, mmc_addr_b2, mmc_addr_b1 ;OUTPUTS : none ;This fuction will write 512 bytes received on UART 1 into the MMC starting ;at the address specified in mmc_addr_b3 thru mmc_addr_b1. mmc_addr_b0 ;will be set to zero by this function as you can only write to the MMC ;(while in SPI mode as opposed to MMC mode) in 512 byte blocks and you must ;begin writing each block at the beginning of a sector as you are not ;allowed to cross sector boundaries. Therefore, mmc_addr_b0 will always be ;set to zero. ;********************************************************************************* mmc_cmd_block_write jmp _mmc_cmd_block_write ;need to jump into second ;half of page where routine ;is located because can only ;call into first half of page ;*** MMC Synchronization***************************************************************** ;send $FF data to the MMC 10 times. Only called after power-up. ;**************************************************************************************** mmc_cmd_synchronize jmp _mmc_cmd_synchronize ;need to jump into second ;half of page where routine ;is located because can only ;call into first half of page ;*** MMC Initialization************************************************************* ;This function executes CMD0 and CMD1 with corresponding R1 MMC response detection ;*********************************************************************************** mmc_cmd_initialize jmp mmc_cmd_init

56

;*** MMC Set Block Length*********************************************************** ;This function sends a set block length command and arguments to the MMC ;*********************************************************************************** mmc_cmd_block_set jmp _mmc_cmd_block_set ;need to jump into second ;half of page where routine ;is located because can only ;call into first half of page org $700

;*** MMC Initialization************************************************************* ;This function executes CMD0 and CMD1 with corresponding R1 MMC response detection ;*********************************************************************************** mmc_cmd_init clrb spix_cs_pin ;set MCC_CS active (low) _bank mmc_spix_ram ;init all the variables clr mmc_status ;clear the status byte call @zero_MMC_addr ;set MMC data address to 0 mov mmc_cmd_crc,#$95 ;need to send a CRC because ;still in MMC mode ;the full sequence of hex values ;to be written to the MMC during ;the initial CMD0 that will ;send the MMC into SPI mode is ;as follows: $40 $00 $00 $00 $00 $95 mov mmc_cmd,#$40 ;execute CMD0 call @mmc_cmd_send call @mmc_r1_get ;get a response byte back _bank mmc_spix_ram cje mmc_r1,#$01,@mmc_label15;correct R1 is equal to #$01 setb mmc_error ;if not - set the error flag jmp mmc_label14 ;and exit mmc_label15 _bank mmc_spix_ram mov mmc_temp2,#cmd1_resp_wait ;load wait duration for response mmc_label13 clr mmc_status ;reset error status call @zero_MMC_addr ;set MMC data address to 0 mov mmc_cmd_crc,#$FF ;now that the MMC is in ;SPI mode, the MMC treats ;the CRC bits as don't cares ;by default although you can ;turn the CRC on using ;CMD 59 if you wish to ;implement the CRC math ;routines mov mmc_cmd,#$41 ;send CMD1 code call @mmc_cmd_send call @mmc_r1_get ;get the response call @Clk_delay ;delay between sending out ;the next initialization ;command Cmd1Repeat _bank mmc_spix_ram mov mmc_cmd,#$41 ;send CMD1 code call @mmc_cmd_send call @mmc_r1_get ;get the response cse mmc_r1,#$00 ;correct R1 is equal to #$00 jmp @Cmd1Repeat ;repeat CMD1, try to get ;a $00 response which would ;indicate that the card was ;finnished it's internal ;initialization processes mmc_label14 setb spix_cs_pin ;set MMC_CS to inactive (HIGH) jmp @mmc_exit ;exit ;********************************************************************************* ;Function : _mmc_cmd_block_set ;INPUTS : mmc_addr_b3, mmc_addr_b2, mmc_addr_b1, mmc_addr_b0 ;OUTPUTS : none ;This function will send a set block length command to the MMC of the size ;specified in the input arguments above. ;*********************************************************************************

57

_mmc_cmd_block_set clrb spix_cs_pin ;set MCC_CS active (low) _bank mmc_spix_ram ;init all the variables clr mmc_status ;clear the status byte mov mmc_cmd_crc,#$FF ;need to send a CRC even ;though CRC's are disabled mov mmc_cmd,#$50 ;execute CMD16 (set block length) call @mmc_cmd_send call @mmc_r1_get ;get a response byte back _bank mmc_spix_ram cje mmc_r1,#$00,@mmc_lenght_done;correct R1 is equal to $00 jmp mmc_length_error ;if not - set the error flag mmc_lenght_done _bank mmc_spix_ram clr mmc_status ;no-error exit jmp @mmc_length_exit mmc_length_error _bank mmc_spix_ram setb mmc_error ;set error flags and exit mmc_length_exit _bank mmc_spix_ram setb spix_cs_pin ;set MMC to inactive state jmp @mmc_exit ;done ;*** MMC Synchronization***************************************************************** ;send $FF data to the MMC 10 times. Only called after power-up. ;**************************************************************************************** _mmc_cmd_synchronize _bank mmc_spix_ram ;select the RAM bank call @spix_init ;initialize SPI I/O pins clr mmc_status ;initialize the MMC driver clr mmc_r1 ; clr mmc_r2 mov mmc_temp,#sync_duration ;get n bytes as a delay setb spix_out_pin ;need to clock out hi's on the SPI call @Clk_delay2 ;delay to allow for circuit mmc_lable1 _bank mmc_spix_ram mov spix_data_io,#$FF ;DO pin (MOSI) for either 1ms or call @spix_send ;74 clock cycles; this is part of ;the initialization sequence on p.22 ;of the SanDisk MultimediaCard Product ;Manual call @Clk_delay ;delay between toggling MOSI pin ;or CMD line while still in MMC mode _bank mmc_spix_ram ;select proper RAM bank djnz mmc_temp,@mmc_lable1 call @Clk_delay2 ;delay to allow for MMC jmp @mmc_exit ;********************************************************************************* ;Function : _mmc_cmd_block_write ;INPUTS : mmc_addr_b3, mmc_addr_b2, mmc_addr_b1 ;OUTPUTS : none ;This fuction will write 512 bytes received on UART 1 into the MMC starting ;at the address specified in mmc_addr_b3 thru mmc_addr_b1. mmc_addr_b0 ;will be set to zero by this function as you can only write to the MMC ;(while in SPI mode as opposed to MMC mode) in 512 byte blocks and you must ;begin writing each block at the beginning of a sector as you are not ;allowed to cross sector boundaries. Therefore, mmc_addr_b0 will always be ;set to zero. ;********************************************************************************* _mmc_cmd_block_write _bank mmc_spix_ram ;Select the RAM Bank clrb spix_cs_pin ;set MMC_CS active (LOW) clr mmc_status clr mmc_addr_b0 ;address byte zero will ;always be $00 to start ;a 512 byte sector in ;MMC memory without crossing ;over sector boundaries mov mmc_cmd,#$58 ;send the BLOCK WRITE Command call @mmc_cmd_send call @mmc_r1_get _bank mmc_spix_ram

58

cje mmc_r1,#$00,@mmc_write_data_block ;correct R1 is equal to #$00 setb mmc_error ;if not - set the error flag jmp @mmc_write_error ;and exit ;********************* WRITE CYCLE: Write the data block to MMC******************************* ;Send the Start Byte=$FE, wait for response (R1 type) ;**************************************************************************************** ***** mmc_write_data_block _bank mmc_spix_ram ;select the RAM bank setb mmc_read_write_data mov spix_data_io,#$fe ;send the start byte $FE call @spix_send setb spix_out_pin ;need to set the data out pin high ;after using spix_send function _bank bank3 mov blockReadB1,#$00 ;set up a countdown for a mov blockReadB2,#$02 ;512 byte single block read :mmc_write_byte sb rs232Rx1Flag ;has a byte has been received by UART1? jmp @:mmc_write_byte ;no, so wait until a byte has ;been received on UART1 call @getbyte ;Get the received byte _bank rs232RxBank mov w,rs232Byte1 ;and place it into the working register _bank mmc_spix_ram ;select the RAM bank mov spix_data_io,w ;place the data received by UART1 ;into data register to be written to ;the MMC call @spix_send ;send byte setb spix_out_pin ;need to set the data out pin high ;after using spix_send function _bank bank3 ;ensure bank3 access decsz blockReadB1 ;need to count 512 bytes for jmp @:mmc_write_byte ;a single block write _bank bank3 decsz blockReadB2 jmp @:mmc_write_byte _bank mmc_spix_ram ;select the RAM bank mov spix_data_io,#$FF ;need to send a dummy CRC even ;though the CRC's are not in use call @spix_send ;send first byte of dummy CRC setb spix_out_pin ;need to set the data out pin high ;after using spix_send function _bank mmc_spix_ram ;select the RAM bank mov spix_data_io,#$FF ;need to send a dummy CRC even ;though the CRC's are not in use call @spix_send ;send second byte of dummy CRC setb spix_out_pin ;need to set the data out pin high ;after using spix_send function call @mmc_r1_get ;get data response token _bank mmc_spix_ram and mmc_r1,#$0f ;not a regular R1 format for responses ;to write operations only inerested in ;least significant nibble so mask out ;most significant nibble cje mmc_r1,#$05,@:wait_not_busy;if correct response is received from ;MMC, then go to wait until MMC ;completes internal write operations ;we will know when the MMC is finished ;by polling the spix_in_pin which the ;MMC will hold low until done jmp @mmc_write_error ;error occured while writing to MMC :wait_not_busy call @spix_get ;keep clocking MMC so that it can ;perform internal write operations jnb spix_in_pin,@:wait_not_busy;wait for the BUSY signal to clear mmc_write_done _bank mmc_spix_ram clr mmc_status ;no-error exit jmp @mmc_write_exit

59

mmc_write_error _bank mmc_spix_ram setb mmc_error ;set error flags and exit setb mmc_data_error mmc_write_exit _bank mmc_spix_ram clrb mmc_read_write_data ;end the transfer and exit setb spix_cs_pin ;set MMC to inactive state jmp @mmc_exit ;done ;********************************************************************************* ;--------------------------MMC Functions End Here--------------------------------;********************************************************************************* org LCD_ORG ;********************************************************************************* ;Page 5 in program memory begins at location $800, the LCD routines will ;reside in this page between $800 and $9FF. Jumps to and from the second half ;of the page (i.e.: $900 - $9FF) will be used in order to make use of the ;second half of the page. The reason this is necessary is that you can only ;call into the first half of a page, but you can jump anywhere in program ;memory. The trick is to jump back into the first half of program memory ;before returning from the function call. If you don't return from the ;function call with a suitable return instruction, then you will create a ;stack imbalance. ;********************************************************************************* ;********************************************************************************* ;--------------------------LCD Functions Begin Here------------------------------;********************************************************************************* ;********************************************************************************* ;Function : lcdInit ;INPUTS : none ;OUTPUTS : none ;Use this function to reset and initialize the LCD. Certain parameters ;involved in setting up the LCD can be modified below. ;********************************************************************************* lcdInit; call lcdReset ;reset the LCD ; _bank lcdBank ;ensure proper bank access to ;data memory ; mov lcdDelay1,#$00 ;load delay registers ; mov lcdDelay2,#$85 ;need to delay for a minumum of 3ms ;after a reset command is sent to the ;measured at approximately 3.4ms using a ;Hewlett Packard 1664A logic analyzer ; call lcdDelay ;Epson SED1335F0A LCD controller IC call lcdSysSetCmd ;this function will send a SYSTEM ;SET command to the Epson ;SED1335F0A LCD controller mov w,#$30 ;pass first parameter (P1) of the system ;set instruction to the lcdWriteByte ;function via the W register ;Note: DR = 0, T/L = 0, IV = 1, W/S = 0, ;M2 = 0, M1 = 0, M0 = 0 ;please refer to the Epson SED1335 ;Technical Manual for details on the above ;and below parameters call lcdWriteByte ;send P1 to SED1335F0A mov w,#$87 ;pass P2 to lcdWriteByte function via W ;register, WF = 1, FX = $7 call lcdWriteByte ;send P2 to SED1335F0A ; mov w,#$0F ;pass P3 to lcdWriteByte function via W ;register, FY = $F mov w,#$07 ;pass P3 to lcdWriteByte function via W ;register, FY = $7 call lcdWriteByte ;send P3 to SED1335F0A ; mov w,#$2C ;pass P4 to lcdWriteByte function via W ;register, C/R = $2C mov w,#$27 ;pass P4 to lcdWriteByte function via W ;register, C/R = $27

60

;

;

call lcdWriteByte ;send P4 to SED1335F0A mov w,#$2B ;pass P5 to lcdWriteByte function via W ;register, TC/R >= $2B mov w,#$39 ;pass P5 to lcdWriteByte function via W ;register, TC/R >= $39 call lcdWriteByte ;send P5 to SED1335F0A mov w,#$EF ;pass P6 to lcdWriteByte function via W ;register, L/F = $EF call lcdWriteByte ;send P6 to SED1335F0A mov w,#$2D ;pass P7 to lcdWriteByte function via W ;register, APL = $2D mov w,#$28 ;pass P7 to lcdWriteByte function via W ;register, APL = $28 call lcdWriteByte ;send P7 to SED1335F0A mov w,#$00 ;pass P8 to lcdWriteByte function via W ;register, APH = $00 call lcdWriteByte ;send P8 to SED1335F0A call lcdScrollCmd ;this function will send a scroll ;command to the Epson SED1335F0A ;LCD controller mov w,#$00 ;pass first parameter (P1) of the scroll ;instruction to the lcdWriteByte ;function via the W register ;P1 = SAD 1L = $00 ;please refer to the Epson SED1335 ;Technical Manual for details on the above ;and below parameters call lcdWriteByte ;send P1 to SED1335F0A mov w,#$00 ;pass P2 to lcdWriteByte function via W ;register, P2 = SAD 1H = $00 call lcdWriteByte ;send P2 to SED1335F0A mov w,#$EF ;pass P3 to lcdWriteByte function via W ;register, P3 = SL1 = $EF call lcdWriteByte ;send P3 to SED1335F0A mov w,#$B0 ;pass P4 to lcdWriteByte function via W ;register, P4 = SAD 2L = $B0 call lcdWriteByte ;send P4 to SED1335F0A mov w,#$04 ;pass P5 to lcdWriteByte function via W ;register, P5 = SAD 2H = $04 call lcdWriteByte ;send P5 to SED1335F0A mov w,#$EF ;pass P6 to lcdWriteByte function via W ;register, P6 = SL 2 = $EF call lcdWriteByte ;send P6 to SED1335F0A mov w,#$00 ;pass P7 to lcdWriteByte function via W ;register, P7 = SAD 3L = $00 call lcdWriteByte ;send P7 to SED1335F0A mov w,#$00 ;pass P8 to lcdWriteByte function via W ;register, P8 = SAD 3H = $00 call lcdWriteByte ;send P8 to SED1335F0A mov w,#$00 ;pass P9 to lcdWriteByte function via W ;register, P9 = SAD 4L = $00 call lcdWriteByte ;send P9 to SED1335F0A mov w,#$00 ;pass P10 to lcdWriteByte function via W ;register, P10 = SAD 4H = $00 call lcdWriteByte ;send P10 to SED1335F0A call lcdCsrFormCmd ;this function will send a ;CSRFORM command to the Epson ;SED1335F0A LCD controller mov w,#$04 ;pass parameter P1 of the CSRFORM ;instruction to the lcdWriteByte ;function via the W register ;CRX = $4, therefore, P1 = $04 call lcdWriteByte ;send P1 to SED1335F0A mov w,#$86 ;pass parameter P2 of the CSRFORM ;instruction to the lcdWriteByte ;function via the W register ;CM = 1, CRY = $6, therefore, P2 = $86 call lcdWriteByte ;send P2 to SED1335F0A call lcdCsrRightCmd ;this function will send a ;CSRDIR command to the Epson ;SED1335F0A LCD controller which

61

;will set the direction of automatic ;cursor increment to the right call lcdHdotScrCmd ;this function will send an HDOT SCR ;command to the Epson SED1335F0A ;LCD controller mov w,#$00 ;pass parameter P1 of the HDOT SCR ;instruction to the lcdWriteByte ;function via the W register ;D2,D1,D0 = %000, therefore, P1 = $00 ;this will set the horizontal pixel shift ;to zero call lcdWriteByte ;send P1 to SED1335F0A call lcdOvlayCmd ;this function will send an OVLAY ;command to the Epson SED1335F0A ;LCD controller mov w,#$01 ;pass parameter P1 of the OVLAY ;instruction to the lcdWriteByte ;function via the W register ;OV = 0, DM2 = 0, DM1 = 0, MX1 = 0, ;MX0 = 1, therefore, P1 = $00 call lcdWriteByte ;send P1 to SED1335F0A call lcdDispOnCmd ;this function will send a ;DISP ON command to the Epson ;SED1335F0A LCD controller mov w,#$16 ;pass parameter P1 of the Display on ;instruction to the lcdWriteByte ;function via the W register ;FP5 = 0, FP4 = 0, FP3 = 0, FP2 = 1, FP1 = 0 ;FP0 = 1, FC1 = 1, FC0 = 0, ;therefore, P1 = $16 call lcdWriteByte ;send P1 to SED1335F0A ;*************************clear screen below this line****************************** ;*************************clear text layer below this line************************** call lcdCsrwCmd ;this function will send a ;CSRW command to the Epson ;SED1335F0A LCD controller ;set cursor to start of first screen ;block mov w,#$00 ;pass parameter P1 of the CSRW ;instruction to the lcdWriteByte ;function via the W register ;CSRL = $00, therefore, P1 = $00 call lcdWriteByte ;send P1 to SED1335F0A mov w,#$00 ;pass parameter P2 of the CSRW ;instruction to the lcdWriteByte ;function via the W register ;CSRH = $00, therefore, P2 = $00 call lcdWriteByte ;send P2 to SED1335F0A _bank lcdBank ;ensure proper bank access mov lcdCounter0,#176;(4 x 256) + 176 = 1200 mov lcdCounter1,#5 ;need to countdown 1200 characters ;per screen for a screen clear call lcdMWriteCmd ;this function will send an ;MWRITE command to the Epson ;SED1335F0A LCD controller repeat1 mov w,#$20 ;$20 is the equivalent of a ' ' in ;the SED1335F0A internal character ;generator Font (internal character ;generator values are also equivalent ;to ascii table values) call lcdWriteByte ;display a ' ' on the LCD _bank lcdBank ;ensure proper bank access decsz lcdCounter0 ;repeat 675 times to clear entire jmp repeat1 ;screen using spaces because 45 decsz lcdCounter1 ;characters per line multiplied by jmp repeat1 ;15 lines = 675 characters per ;screen ;*************************clear text layer above this line************************** ;*************************clear graphics layer below this line********************** call lcdCsrwCmd ;this function will send a

62

;CSRW command to the Epson ;SED1335F0A LCD controller ;set cursor to start of first screen ;block mov w,#$B0 ;pass parameter P1 of the CSRW ;instruction to the lcdWriteByte ;function via the W register ;CSRL = $B0, therefore, P1 = $B0 call lcdWriteByte ;send P1 to SED1335F0A mov w,#$04 ;pass parameter P2 of the CSRW ;instruction to the lcdWriteByte ;function via the W register ;CSRH = $04, therefore, P2 = $04 call lcdWriteByte ;send P2 to SED1335F0A _bank lcdBank ;ensure proper bank access mov lcdCounter0,#128;(256x37)+ 128 = 9600 mov lcdCounter1,#38 ;need to countdown 9600 characters ;per screen for a screen clear call lcdMWriteCmd ;this function will send an ;MWRITE command to the Epson ;SED1335F0A LCD controller repeat2 mov w,#$00 ;want all zero's in second display ;memory page in order to clear the ;graphics. This page resides in ;display memory between $04B0 and $2A2F call lcdWriteByte ;write $00 to 64kB display memory onboard ;the LCM (clear graphics overlay page) _bank lcdBank ;ensure proper bank access decsz lcdCounter0 ;repeat 675 times to clear entire jmp repeat2 ;screen using spaces because 45 decsz lcdCounter1 ;characters per line multiplied by jmp repeat2 ;15 lines = 675 characters per ;screen ;*************************clear graphics layer above this line********************** ;*************************clear screen above this line****************************** call lcdCsrwCmd ;this function will send a ;CSRW command to the Epson ;SED1335F0A LCD controller ;set cursor to start of first screen ;block mov w,#$00 ;pass parameter P1 of the CSRW ;instruction to the lcdWriteByte ;function via the W register ;CSRL = $31, therefore, P1 = $31 call lcdWriteByte ;send P1 to SED1335F0A mov w,#$00 ;pass parameter P2 of the CSRW ;instruction to the lcdWriteByte ;function via the W register ;CSRH = $02, therefore, P2 = $02 call lcdWriteByte ;send P2 to SED1335F0A retp ;return and fix page bits ;********************************************************************************* ;Function : lcdReset ;INPUTS : none ;OUTPUTS : none ;This function sends a reset signal to the Epson SED1335F0A LCD ;controller ;********************************************************************************* lcdReset clrb lcdRESPin ;make active low reset pin low _bank lcdBank ;ensure proper bank access to data memory mov lcdDelay1,#$FF ;load delay registers mov lcdDelay2,#$09 ;reset pulse must be a minumum of 200us ;measured at 215us using Hewlett Packard ;1664A logic analyzer call lcdDelay ;for the SED1335F0A setb lcdRESPin ;make active low reset pin high retp ;*********************************************************************************

63

;Function : lcdSysSetCmd ;INPUTS : none ;OUTPUTS : none ;Sends a SYSTEM SET command to the Epson SED1335F0A LCD controller which ;is built into the Microtips MTG-F32240FFWHSCW LCD Module. ;This is a 1-byte command which must be followed by 8 one byte parameters. ; These parameters will: initialize the SED1335F0A, set window sizes of the ;LCD, and select the LCD interface format. This command, followed by the ;proper parameters, set the basic operating parameters of the SED1335F0A. ;********************************************************************************* lcdSysSetCmd mov w,#$40 ;pass the system set command to the call lcdSendCmd ;lcdSendCmd function retp ;return and fix page bits ;********************************************************************************* ;Function : lcdScrollCmd ;INPUTS : none ;OUTPUTS : none ;Sends the SCROLL command to the Epson SED1335F0A LCD controller which ;is built into the Microtips MTG-F32240FFWHSCW LCD Module. ;This 1-byte command must be followed by 3 one byte parameters. These ;parameters will: set the scroll start address and the number of lines ; per scroll block for a single layer display. If additional layers are ; required, you can simply add more parameters. Please see the Epson ; SED1335F0A technical manual for further details on the parameters ;involved with this instruction. ;********************************************************************************* lcdScrollCmd mov w,#$44 ;pass the scroll command to the call lcdSendCmd ;lcdSendCmd function retp ;********************************************************************************* ;Function : lcdHdotScrCmd ;INPUTS : none ;OUTPUTS : none ;Sends the HDOT SCR command to the Epson SED1335F0A lcd controller. ;While the scroll command only allows scrolling by characters, the HDOT SCR ;command allows the screen to be scrolled horizontally by pixels. ;********************************************************************************* lcdHdotScrCmd mov w,#$5A ;pass the HDOT SCR command to the call lcdSendCmd ;lcdSendCmd function retp ;return and fix page bits ;********************************************************************************* ;Function : lcdOvlayCmd ;INPUTS : none ;OUTPUTS : none ;Sends the OVLAY command to the Epson SED1335F0A lcd controller. This ;command sets the display overlay format by selecting layered screen ;composition and screen/text graphics mode. ;********************************************************************************* lcdOvlayCmd mov w,#$5B ;pass the OVLAY command to the call lcdSendCmd ;lcdSendCmd function retp ;return and fix page bits ;********************************************************************************* ;Function : lcdDispOffCmd ;INPUTS : none ;OUTPUTS : none ;Sends the DISP OFF command to the Epson SED1335F0A lcd controller. ;This instruction turns the display off. The single-byte parameter ;following this command enables and disables the cursor and layered ;screeens, and sets the cursor and screen flash rates. The cursor ;can be set to flash over one character or over a whole line. ;********************************************************************************* lcdDispOffCmd mov w,#$58 ;pass the DISP OFF command to the

64

call lcdSendCmd ;lcdSendCmd function retp ;return and fix page bits ;********************************************************************************* ;Function : lcdDispOnCmd ;INPUTS : none ;OUTPUTS : none ;Sends the DISP ON command to the Epson SED1335F0A lcd controller. ;This command turns the display on. No parameter is required because ;the lcdDispOffCmd should have been used prior to this command. The ;lcdDispOffCmd has already set the characteristics of the layered screens ;and cursor. However, a parameter may be passed following this command ;if desired. ;********************************************************************************* lcdDispOnCmd mov w,#$59 ;pass the DISP ON command to the call lcdSendCmd ;lcdSendCmd function retp ;return and fix page bits ;********************************************************************************* ;Function : lcdCsrwCmd ;INPUTS : none ;OUTPUTS : none ;Sends the CSRW command to the Epson SED1335F0A lcd controller. ;This command sets the cursor address such that any data following an ;MWRITE instruction will be written to display memory at the 16-bit cursor ;address contained in the cursor address register. The address contained ;in the cursor address register can be modified by passing two 1-byte ;parameters following this instruction as P1 and P2. ;********************************************************************************* lcdCsrwCmd mov w,#$46 ;pass the CSRW command to the call lcdSendCmd ;lcdSendCmd function retp ;return and fix page bits

;********************************************************************************* ;Function : lcdCsrFormCmd ;INPUTS : none ;OUTPUTS : none ;Sends the CSRFORM command to the Epson SED1335F0A lcd controller. ;The parameters following this command set the cursor size and display ;mode. ;********************************************************************************* lcdCsrFormCmd mov w,#$5D ;pass the CSRFORM command to the call lcdSendCmd ;lcdSendCmd function retp ;return and fix page bits ;********************************************************************************* ;Function : lcdCsrRightCmd ;INPUTS : none ;OUTPUTS : none ;Sends a CSRDIR command to the Epson SED1335F0A lcd controller. ;The parameters for this instuction are contained within the command in ;bits 0 and 1. Bit 0 of the command is the CD2 parameter, while bit 1 of ;the command is the CD1 parameter. With both of these parameters set to ;zero, the command, or C, is $4C as seen below. This will set the cursor ;auto increment direction to the right. This command does not require that ;any parameters follow as the only parameters are contained within the ;command itself. Note that this is not the way that most of the command ;set for the Epson SED1335F0A works. Usually, the command is a full byte, ;requiring any paramters needed to follow the command. The command in ;conjunction with the parameters make up the instruction. ;********************************************************************************* lcdCsrRightCmd mov w,#$4C ;pass the CSRDIR command to the call lcdSendCmd ;lcdSendCmd function retp ;return and fix page bits ;*********************************************************************************

65

;Function : lcdMWriteCmd ;INPUTS : none ;OUTPUTS : none ;Sends the MWRITE command to the Epson SED1335F0A lcd controller. You must ;follow this function call with the data you wish to write to the display ;memory of the SED1335F0A. Use the CSRW command to set the cursor address. ;********************************************************************************* lcdMWriteCmd mov w,#$42 ;pass the MWRITE command to the call lcdSendCmd ;lcdSendCmd function retp ;return and fix page bits ;********************************************************************************* ;Function : lcdSendCmd ;INPUTS : 1 byte command in the W register ;OUTPUTS : none ;Sends the 1 byte command specified in the W register to the Epson ;SED1335F0A. ;********************************************************************************* lcdSendCmd _bank lcdBank ;ensure proper bank access in data memory mov lcdCmdReg,w ;store command in lcdCmdReg clrb lcdEPin ;ensure that enable pin is low clrb lcdRWPin ;ensure that R/W pin is low (we are writing) setb lcdAoPin ;ensure that Ao pin is high (we are sending ;a command, not data or a parameter) _mode DDIR_W ;point MODE to write DDIR register mov w,#$00 ;Setup RC Direction, 0 = output, 1 = input mov !rc,w ;bring lcdData (port C) out of high impedance ;by changing to outputs _bank lcdBank ;ensure proper bank access in data memory ;may be able to get rid of this line of code ;later on, just a precaution mov lcdData,lcdCmdReg;write the one byte command to lcdData ;(port C) setb lcdEPin ;make enable pin high _bank lcdBank ;ensure proper bank access to data memory mov lcdDelay1,#$05 ;load delay registers mov lcdDelay2,#$01 ;and hold for a minumum of 150ns call lcdDelay ;using general purpose lcdDelay function clrb lcdEPin ;make enable pin low and SED1335F0A latches ;data _mode DDIR_W ;point MODE to write DDIR register mov w,#$FF ;Setup RC Direction, 0 = output, 1 = input mov !rc,w ;change lcdData (port C) back into high Z ;by changing to inputs retp ;return and fix page bits ;********************************************************************************* ;Function : lcdWriteByte ;INPUTS : 1 byte of data in the W register ;OUTPUTS : none ;Sends the 1 byte of data specified in the W register to the Epson ;SED1335F0A. This data could be a parameter following a command, part of a ;bitmap to be displayed on the LCD, part of a character from external ;character generator ROM, or a code to the internal character generator of ;the LCM to define which character is displayed next. Which of these it is ;depends on how you set-up the SED1335F0A via the system set command. ;********************************************************************************* lcdWriteByte _bank lcdBank ;ensure proper bank access in data memory mov lcdDataReg,w ;store data in lcdDataReg clrb lcdEPin ;ensure that enable pin is low clrb lcdRWPin ;ensure that R/W pin is low (we are writing) clrb lcdAoPin ;ensure that Ao pin is low (we are sending ;either data or a parameter, not a command) _mode DDIR_W ;point MODE to write DDIR register mov w,#$00 ;Setup RC Direction, 0 = output, 1 = input mov !rc,w ;bring lcdData (port C) out of high impedance ;by changing to outputs _bank lcdBank ;ensure proper bank access in data memory

66

;may be able to get rid of this line of code ;later on, just a precaution mov lcdData,lcdDataReg;write the one byte of data to lcdData ;(port C) setb lcdEPin ;make enable pin high _bank lcdBank ;ensure proper bank access to data memory mov lcdDelay1,#$05 ;load delay registers mov lcdDelay2,#$01 ;and hold for a minumum of 150ns call lcdDelay ;using general purpose lcdDelay function clrb lcdEPin ;make enable pin low and SED1335F0A latches ;data _mode DDIR_W ;point MODE to write DDIR register mov w,#$FF ;Setup RC Direction, 0 = output, 1 = input mov !rc,w ;change lcdData (port C) back into high Z ;by changing to inputs retp ;return and fix page bits ;********************************************************************************* ;Function : lcdDelay ;INPUTS : lcdDelay1, lcdDelay2 ;OUTPUTS : none ;This is a two byte general purpose lcd variable delay routine. Make ;lcdDelay2 variable = $01 if only a one byte delay routine is needed. ;********************************************************************************* _bank lcdBank ;ensure proper bank access to data ;memory lcdDelayLoop decsz lcdDelay1 ;is lcdDelay1 = 0? jmp lcdDelayLoop ;no, keep looping for longer delay decsz lcdDelay2 ;is lcdDelay2 = 0? jmp lcdDelayLoop ;no, keep looping for longer delay retp ;yes, return and fix page bits ;********************************************************************************* ;Function : lcdWaitNotBusy ;INPUTS : none ;OUTPUTS : none ;This function will poll the Epson SED1335F0A and wait until the lcd ;controller is not busy before returning and fixing the page bits. ;********************************************************************************* lcdWaitNotBusy clrb lcdEPin ;ensure that enable pin is low setb lcdRWPin ;ensure that R/W pin is high (we are ;reading the status flag) clrb lcdAoPin ;ensure that Ao pin is low (we are reading ;the status flag) setb lcdEPin ;tell the Epson SED1335F0A that we want ;to read the status flag now _bank lcdBank ;ensure proper bank access to data memory ;**********The following values may need to be adjusted in order to obtain********** ;******************************the desired delay************************************ mov lcdDelay1,#$10 ;load delay registers mov lcdDelay2,#$01 ;need to wait for a minumum of Tacc6 = 130ns call lcdDelay ;access time before checking Epson ;SED1335F0A status flag sb statusFlag ;is status flag set (i.e.: is lcd ;controller not busy)? jmp busy ;no, so wait for not busy jmp notBusy ;yes, so return from function busy clrb lcdEPin ;finished read, deactivate enable pin jmp lcdWaitNotBusy ;repeat read status flag process until ;not busy obtained notBusy clrb lcdEPin ;finished read, deactivate enable pin retp ;return and fix page bits ;********************************************************************************* ;Function : lcdDisplayBitmap ;INPUTS : mmc_addr_b3, mmc_addr_b2, mmc_addr_b1 ;OUTPUTS : none lcdDelay

67

;This function will display a 9600 byte bitmap on the LCD beginning at the ;address specified in mmc_addr_b3 thru mmc_addr_b1 above. The reason for ;not needing mmc_addr_b0 as an input is that each block's starting address ;ends in $00, thus we can always asume that mmc_addr_b1 can be set to $00 ;because the VURC EDITOR will store bitmap images starting at the beginning ;of a 512 byte sector in the MMC. ;********************************************************************************* lcdDisplayBitmap _bank bank3 mov sectorCount,#19 ;need to read 18 sectors plus 384 bytes ;in the 19th sector to display one bitmap call lcdCsrwCmd ;set up starting address of graphic mov w,#$B0 ;display memory call lcdWriteByte mov w,#$04 call lcdWriteByte call lcdMWriteCmd nextSector _bank mmc_spix_ram clr mmc_addr_b0 ;b0 is always $00 when beginning read at ;the beginning of a sector mov readSizeH,#$02 ;want to read 512 byte sectors mov readSizeL,#$00 mov w,#$04 ;display data retreived from MMC on LCD call @mmc_cmd_block_read _bank bank3 decsz sectorCount jmp incB1 ;display next sector of data inc mmc_addr_b1 ;increment b1 twice to get starting inc mmc_addr_b1 ;address of next sector mov readSizeH,#$01 ;want to read 384 bytes mov readSizeL,#$80 mov w,#$04 ;display data retreived from MMC on LCD call @mmc_cmd_block_read jmp bitmapExit incB1 _bank mmc_spix_ram inc mmc_addr_b1 ;increment b1 twice to get starting inc mmc_addr_b1 ;address of next sector jmp nextSector bitmapExit retp ;********************************************************************************* ;--------------------------LCD Functions End Here--------------------------------;*********************************************************************************

orgTOUCHSCREEN_ORG ;********************************************************************************* ;--------------------------Touch Screen Functions Begin Here---------------------;********************************************************************************* ;********************************************************************************* ;Function : checkTouchScreen ;INPUTS : none ;OUTPUTS : none ;This is the main loop for the whole touchscreen process. If a valid touch ;is sensed, then it will look up the appropriate address in MMC memory to ;figure out what must be done. If the button pressed is a menu change, then ;the start address of the menu in MMC memory will be passed to ;mmc_cmd_block_read. If the button pressed is a IR Code, then the start ;address of the IR code will be passed to mmc_cmd_block_read. Once the ;appropriate action has taken place, it will poll the touchscreen until no ;button is being pressed, and will return. ;********************************************************************************* ;NOTE: TO DO. 1)Add Set Block Length call with appropriate parameters. ; 2)Add code that takes the address of the beginning of the menu and ; place it into the mmc_addr registers before calling mmc_cmd_block_read

68

checkTouchScreen call getTouch sb touchValid ;if touch is valid, then skip next line retp ;return if no valid touch ;otherwise, call @hardcodeIR ; call lookupTouch ;lookup the address in MMC memory ;and take appropriate action checkTouchScreenLoop _bank touchBank mov touchTemp,#50 checkTouchScreenLoop2 call @Clk_Delay2 decsz touchTemp jmp checkTouchScreenLoop2 call getTouch ;debounce to wait until the button is depressed sb touchValid ;if touch is valid, skip next line retp ;otherwise keep polling until touchscreen no longer pressed jmp checkTouchScreenLoop retp ;********************************************************************************* ;Function : getTouch ;INPUTS : none ;OUTPUTS : touchValid, touchAddHi, touchAddMid, touchAddLow ;This reads in A/D values from the touchscreen and checks to see if it is ;within the valid area of the touchscreen. If it is not, it will return a 0 ;in touchValid. If it is, it will convert the X-Y coordinates into a 24-bit ;address for lookup into MMC memory (in touchAddHi, touchAddMid, and ;touchAddLow) and will return a 1 in touchValid. ;********************************************************************************* getTouch mov call call call mov mov call mov call call call mov mov _bank clr clr clr

W,#touchGetXCmd @out8touch @touchScreenBusy @in12touch touchXposRegHi,touchTempHi touchXposRegLow,touchTempLow @touchScreenBusy W,#touchGetYCmd @out8touch @touchScreenBusy @in12touch touchYposRegHi,touchTempHi touchYposRegLow,touchTempLow touchBank touchAddHi ;clear the registers in preparation for touchAddMid ;address calculations touchAddLow

jmp touchIsValid touchIsValidReturn sb touchValid retp ;returns bit = 0 in touchValid bit, invalid Touch ; jmp touchOffsetSetups touchOffsetSetupsReturn ; call touchOffsetXpos ; call touchOffsetYpos ; call touchOffsetMenunum retp ;********************************************************************************* ;Function : lookupTouch ;INPUTS : touchAddHi, touchAddMid, touchAddLow ;OUTPUTS : none ;This looks up the address (passed to it in the three input registers) in ;MMC memory and reads back a byte. If the byte is 0x01, then it is a menu ;change operation. If the byte is a 0x02, then it is an IR code.

69

;The function will pass the appropriate parameters to the mmc_cmd_block_read ;functions. If the byte is a 0x00, then it is nothing. The function should ;take no action and return. ;********************************************************************************* ;NOTE: TO DO: 1)Add the "no action" branch. ; 2)Fix the MenuChange option so that it takes in the address of the new ; Menu and passes it to the mmc_cmd_block_read function properly. lookupTouch ;SET BLOCK LENGTH TO 1 _bank touchBank mov W,touchAddHi _bank mmc_spix_ram mov mmc_addr_b2,W _bank touchBank mov W,touchAddMid _bank mmc_spix_ram mov mmc_addr_b1,W _bank touchBank mov W,touchAddLow _bank mmc_spix_ram mov mmc_addr_b0,W mov mmc_cmd,#0x51 call @mmc_cmd_send call @mmc_r1_get call touchMMCConvXfer mov touchTemp,W sb touchTemp.0 ;if bit is set, then menu change operation ; call touchMenuChange ; call touchIRSend ;else, is an IR operation nop retp touchMenuChange _bank mmc_spix_ram ; mov readSizeH,#0x25 ; mov readSizeL,#0x80 mov W,#0x04 call mmc_cmd_block_read retp touchIRSend _bank mmc_spix_ram inc mmc_addr_b0 ;increment the address by one snb c inc mmc_addr_b1 ;add carry on snb c inc mmc_addr_b2 ;add carry on ; mov readSizeH,#0x00 ; mov readSizeL,#0x0F mov W,#0x02 call mmc_cmd_block_read retp ;********************************************************************************* ;Function : out8touch ;INPUTS : W ;OUTPUTS : none ;This function clocks out a command byte to the touchscreen. The command ;must be placed into the W register before calling this function. ;********************************************************************************* out8touch _bank touchBank mov touchTemp,W mov touchBitsTemp,#0x08 out8touch_loop

rl touchTemp

70

sc jmp out8touch_zero out8touch_one setb touchDin jmp out8touch_back out8touch_zero clrb touchDin out8touch_back clrb touchDClk ; clock the data into the touchscreen controller call touchClockDelay setb touchDClk call touchClockDelay decsz touchBitsTemp jmp out8touch_loop clrb touchDin clrb touchDClk retp ;********************************************************************************* ;Function : in12touch ;INPUTS : none ;OUTPUTS : touchTempHi, touchTempLow ;This function will clock in 12 bits of data from the touchscreen ;controller, and place the lower 8 bits into a result register, and ;the highest 4 bits into a second result register. It will then shift the ;data in both registers to the right 6 times (Hi --> Low) and clear the LSB. ;The touchtempLow register will hold the least significant 8 bits, and the ;touchTempHi register will hold the most significant 2 bits, for a 10 bit ;EVEN result. ;********************************************************************************* ; check if 8 bits are done ; if not, loop again ; reset the clock and din bits (cleanup)

in12touch _bank touchBank clr touchTempHi mov touchBitsTemp,#0x08 in12touch_loop setb touchDClk call touchClockDelay clrb c ;clear the carry bit clrb touchDClk call touchClockDelay snb touchDout setb c rl touchTempHi ;shift the carry bit into the YPosReg decsz touchBitsTemp ;8 bits shifted in? jmp in12touch_loop ;if not, loop again _bank touchBank clr touchTempLow mov touchBitsTemp,#0x08 in12touch_loop2 setb touchDClk call touchClockDelay clrb c ;clear the carry bit clrb touchDClk call touchClockDelay snb touchDout setb c rl touchTempLow ;shift the carry bit into the YPosReg decsz touchBitsTemp ;8 bits shifted in? jmp in12touch_loop2 ;if not, loop again

mov touchBitsTemp,#0x07 jmp touchShiftLoop ;go to second half of page for linear code

71

touchShiftLoopReturn retp ;********************************************************************************* ;Function : touchOffsetYpos ;INPUTS : touchYposRegHi, touchYposRegLow, touchAddHi, touchAddMid, ; touchAddLow ;OUTPUTS : touchAddHi, touchAddMid, touchAddLow ;This will lookup (in MMC memory) the offset values for the given Y ;co-ordinate, and will add the offset to the total address offset in the ;touchAdd registers. ;********************************************************************************* ;This offset will be equal to 320 * Y position ;y = 76 - 431 (8 bit A/D) --> 0 - 239 (resolution of LCD) touchOffsetYpos mov mmc_addr_b1,#0xD3 clr mmc_addr_b0 _bank touchBank mov W,touchYposRegLow _bank mmc_spix_ram add mmc_addr_b0,W _bank touchBank mov W,touchYposRegHi _bank mmc_spix_ram add mmc_addr_b1,W mov mmc_cmd,#$51 call @mmc_cmd_send call @mmc_r1_get call touchMMCConvXfer ;return byte in W _bank touchBank mov touchYposRegHi,W call touchMMCConvXfer ;return byte in W _bank touchBank ;low byte in W so add to touchAddLow add touchAddLow,W snc inc touchAddMid ;add the carry to touchAddMid snc inc touchAddHi ;add the carry to touchAddHi mov W,touchYposRegHi add touchAddMid,W ;add to touchAddMid snc inc touchAddHi ;add the carry to touchAddHi retp ;********************************************************************************* ;Function : touchOffsetXpos ;INPUTS : touchXposRegHi, touchXposRegLow, touchAddHi, touchAddMid, ; touchAddLow ;OUTPUTS : touchAddHi, touchAddMid, touchAddLow ;This will lookup (in MMC memory) the offset values for the given X ;co-ordinate, and will add the offset to the total address offset in the ;touchAdd registers. ;********************************************************************************* ;This offset will be equal to X position ; x = 74 - 393 (from Touchscreen) --> 0 - 319 (resolution of LCD) touchOffsetXpos mov mmc_addr_b1,#0xD5 _bank touchBank mov W,touchXposRegLow _bank mmc_spix_ram add mmc_addr_b0,W _bank touchBank mov W,touchXposRegHi _bank mmc_spix_ram add mmc_addr_b1,W call @mmc_cmd_send

72

call @mmc_r1_get call touchMMCConvXfer ;return byte in W _bank touchBank mov touchAddHi,W call touchMMCConvXfer ;return byte in W _bank touchBank mov touchAddLow,W retp ;********************************************************************************* ;Function : touchOffsetMenunum ;INPUTS : menuNum ;OUTPUTS : touchAddHi, touchAddMid, touchAddLow ;First will shift the data in the touchADD registers to the left 4 times ;(16 address bytes per jump location). Then will add the base offset for ;the menu number into the touchADD registers. ;*********************************************************************************

;NOTE: TO DO: 1)multiply the Menu Number by the menuMoffset, and store the result ; in the touchADD registers. touchOffsetMenunum mov touchBitsTemp,#0x04 touchOffsetMenunumLoop clrb c rl touchAddLow ;this code shifts the data 4 times. rl touchAddMid rl touchAddHi decsz touchBitsTemp jmp touchOffsetMenunumLoop ;multiply menuNumber by menuMoffset, result is added to touchAddHi, touchAddMid, and ;touchAddLow retp ;********************************************************************************* ;Function : touchScreenBusy ;INPUTS : none ;OUTPUTS : none ; This function is a software delay. ;********************************************************************************* touchScreenBusy mov touchDelayTemp,#150 ;unused temp variable touchScreenBusyLoop decsz touchDelayTemp jmp touchScreenBusyLoop retp ;********************************************************************************* ;Function : touchClockDelay ;INPUTS : none ;OUTPUTS : none ;This function is a software delay. ;********************************************************************************* touchClockDelay mov touchDelayTemp,#11 touchClockDelayLoop decsz touchDelayTemp jmp touchClockDelayLoop retp ;********************************************************************************* ;Function : touchMMCConvXfer ;INPUTS : none ;OUTPUTS : W

;unused temp variable

73

;This function gets a single byte of data from the MMC and returns it in W. ;********************************************************************************* touchMMCConvXfer ; call @spix_get ;wait for data start byte = $FE ; call @Clk_delay ;delay between clock ; ;bursts ; _bank mmc_spix_ram ; cje spix_data_io,#$fe,@mmc_read_block ; ;End waiting if Start Byte ; jmp @mmc_label41 ;else read another byte ; call @spix_get ;get a data byte ; mov w,spix_data_io ;move into W and return retp testtxUART2 _bank rs232TxBank mov rs232Tx2Byte,w ;move byte to be sent into ;UART1 transmit register :loop2 snb rs232Tx2Flag ;check transmit flag, if clear ;then send another byte, otherwise jmp :loop2 ;wait until clear setb rs232Tx2Flag ;set flag to tell UART to send ;the byte in rs232Tx1Byte call @sendbyte2 ;write the received byte to ;hyperterminal via RS-232 retp ;byte sent on UART2, go check ;if done or get another to send

hardcodeIR jmp hardcodeIRjump hardcodeIRjumpret retp org $B00 ;second half of page for touchscreen linear functions (no calling) ;********************************************************************************* ;Function : touchIsValid ;INPUTS : touchXposRegHi, touchXposRegLow, touchYposRegHi, ; touchYposRegLow ;OUTPUTS : touchValid ; This function checks to ensure that the values in X and Y are valid values. ;If a valid number, set the touchValid bit and return. Otherwise, clear the ;touchValid bit and return. ; Valid Xs are: 73 < x < 394 ; Valid Ys are: 75 < y < 432 ; ;NOTE: this is a jump from the getTouch function, and the jump at the end ;of the function goes back where it came from. This is in order to cross ;into the second half of the program memory page. ;********************************************************************************* touchIsValid ;if bit 9 is a one, skip this check snb touchXposRegHi.0 jmp touchIsValid2 cjb touchXposRegLow,#74,touchNotValid ;check if touchXposRegLow is less than 74 ;and jump if NOT valid touchIsValid2 sb touchXposRegHi.0 ;if bit 9 is a zero, skip this check jmp touchIsValid3 cjae touchXposRegLow,#393,touchNotValid ;check if touchXposRegLow is equal to or greater ;than 393, and jump if NOT valid touchIsValid3 snb touchYposRegHi.0 ;if bit 9 is a one, skip this check jmp touchIsValid4 cjb touchYposRegLow,#76,touchNotValid ;check if touchYposRegLow is less than 76 ;and jump if NOT valid touchIsValid4 sb touchYposRegHi.0 ;if bit 9 is a zero, skip this check

74

jmp touchIsValidTrue cjae touchYposRegLow,#431,touchNotValid ;check if touchYposRegLow is equal to or greater ;than 431, and jump if NOT valid ;else, IS VALID! touchIsValidTrue setb touchValid jmp touchIsValidReturn touchNotValid clrb touchValid jmp touchIsValidReturn ;********************************************************************************* ;Function : touchOffsetSetups ;INPUTS : none ;OUTPUTS : mmc_addr_b0, mmc_addr_b1, mmc_addr_b3, mmc_cmd ;This sets up the registers that are common to both the Y and X conversion ;jumps. ; ;NOTE: this is a jump from the getTouch function, and the jump at the end ;of the function goes back where it came from. This is in order to cross ;into the second half of the program memory page. ;********************************************************************************* touchOffsetSetups ;SET BLOCK LENGTH <insert here> to 2 _bank mmc_spix_ram clr mmc_addr_b3 mov mmc_addr_b2,#0xFD clr mmc_addr_b0 mov mmc_cmd,#0x51 jmp touchOffsetSetupsReturn ;********************************************************************************* ;NOTE: this is a jump from the in12touch function, and the jump at the end ;of the function goes back where it came from. This is in order to cross ;into the second half of the program memory page. ;********************************************************************************* touchShiftLoop ;this loop shifts the bits in both registers to ;the right 6 times clrb c rr touchTempHi rr touchTempLow decsz touchBitsTemp jmp touchShiftLoop ; clrb touchTempLow.0 ;clear the LSB for jumping to jump table properly jmp touchShiftLoopReturn hardcodeIRjump mov w,#1 ;IR_TYPE call testtxUART2 call @Clk_Delay2 mov w,#23 ;IR_FREQ call testtxUART2 call @Clk_Delay2 mov w,#0 ;IR_STARTBURST call testtxUART2 call @Clk_Delay2 mov w,#0 ;IR_STARTSPACE call testtxUART2 call @Clk_Delay2 mov w,#10 ;IR_BURST call testtxUART2 call @Clk_Delay2 mov w,#9 call testtxUART2 call @Clk_Delay2 mov w,#21 call testtxUART2 call @Clk_Delay2 *yay*

75

mov w,#2 call testtxUART2 call @Clk_Delay2 mov w,#0xEA call testtxUART2 call @Clk_Delay2 mov w,#0x40 call testtxUART2 call @Clk_Delay2 mov w,#0 call testtxUART2 call @Clk_Delay2 mov w,#0 call testtxUART2 call @Clk_Delay2 mov w,#0 call testtxUART2 call @Clk_Delay2 mov w,#0 call testtxUART2 call @Clk_Delay2 mov w,#0 call testtxUART2 call @Clk_Delay2 jmp hardcodeIRjumpret ;********************************************************************************* ;--------------------------Touch Screen Functions End Here-----------------------;********************************************************************************* org MISCELANEOUS_ORG ;********************************************************************************* ;--------------------------Miscelaneous Functions Begin Here---------------------;********************************************************************************* ;**************************************************************************************** * ;Function : pcReadWriteMMC ;Inputs : None ;OUTPUTS : None ;This fuction is executed when the user of the VURC has pressed the programButton. ;This fuction will wait for a contol byte from the Windows based "VURC EDITOR" ;program. If the control byte received is $01, a read from MMC will be performed ;by the VURC EDITOR beginning at the location specified by the VURC EDITOR and of ;the number of bytes specified by the VURC EDITOR. If the control byte received is ;$02, then a 512 byte write to MMC will be performed by the VURC EDITOR beginning ;at the location specified by the VURC EDITOR. If the control byte received is ;$03, then this fucntion will return and fix the page bits. Control byte $03 ;signifies that the VURC EDITOR has completed communications with the VURC. ; ;**************************************************************************************** * pcReadWriteMMC _bank rs232RxBank ;switch to rs232 bank waitCode sb rs232Rx1Flag ;control code received? jmp waitCode ;no, wait for control code from ;VURC EDITOR call @getbyte ;control code received, go get it _bank rs232RxBank mov localtemp2,rs232Byte1 ;place control code into a ;global register cje localtemp2,#$01,@readCard;$01 is read MMC command from ;the VURC EDITOR cje localtemp2,#$02,@writeCard;$02 is write MMC command from ;the VURC EDITOR cje localtemp2,#$03,@pcCommOut;$03 is a return command from the ;VURC EDITOR jmp @CommandCodeError ;not a valid command readCard _bank rs232TxBank

76

mov rs232Tx1Byte,#$FE ;send acknowledge $FE to ;VURC EDITOR waitTXFlag1 snb rs232Tx1Flag ;is flag clear? (ie: done sending any ;previous data?) if so, continue jmp waitTxFlag1 ;otherwise, wait for flag to clear setb rs232Tx1Flag ;set flag to send a byte on UART1 call @sendByte1 ;send acknowledge now _bank rs232RxBank ;switch to rs232 bank waitSizeH sb rs232Rx1Flag ;readSizeH received? jmp waitSizeH ;no, wait for readSizeH from ;VURC EDITOR call @getbyte ;readSizeH received, go get it ; _bank rs232RxBank mov w,rs232Byte1 ;place readSizeH into W register _bank mmc_spix_ram ;ensure proper bank access mov readSizeH,w ;pass readSizeH to mmc_cmd_block_read ;function _bank rs232RxBank ;switch to rs232 bank waitSizeL sb rs232Rx1Flag ;readSizeL received? jmp waitSizeL ;no, wait for readSizeL from ;VURC EDITOR call @getbyte ;readSizeL received, go get it ; _bank rs232RxBank mov w,rs232Byte1 ;place readSizeL into W register _bank mmc_spix_ram ;ensure proper bank access mov readSizeL,w ;pass readSizeL to mmc_cmd_block_read ;function _bank rs232RxBank ;switch to rs232 bank waitAddrB3 sb rs232Rx1Flag ;mmc_addr_b3 received? jmp waitAddrB3 ;no, wait for mmc_addr_b3 from ;VURC EDITOR call @getbyte ;mmc_addr_b3 received, go get it ; _bank rs232RxBank mov w,rs232Byte1 ;place mmc_addr_b3 into W register _bank mmc_spix_ram ;ensure proper bank access mov mmc_addr_b3,w ;pass mmc_addr_b3 to mmc_cmd_block_read ;function _bank rs232RxBank ;switch to rs232 bank waitAddrB2 sb rs232Rx1Flag ;mmc_addr_b2 received? jmp waitAddrB2 ;no, wait for mmc_addr_b2 from ;VURC EDITOR call @getbyte ;mmc_addr_b2 received, go get it ; _bank rs232RxBank mov w,rs232Byte1 ;place mmc_addr_b2 into W register _bank mmc_spix_ram ;ensure proper bank access mov mmc_addr_b2,w ;pass mmc_addr_b2 to mmc_cmd_block_read ;function _bank rs232RxBank ;switch to rs232 bank waitAddrB1 sb rs232Rx1Flag ;mmc_addr_b1 received? jmp waitAddrB1 ;no, wait for mmc_addr_b1 from ;VURC EDITOR call @getbyte ;mmc_addr_b1 received, go get it ; _bank rs232RxBank mov w,rs232Byte1 ;place mmc_addr_b1 into W register _bank mmc_spix_ram ;ensure proper bank access mov mmc_addr_b1,w ;pass mmc_addr_b1 to mmc_cmd_block_read ;function _bank rs232RxBank ;switch to rs232 bank waitAddrB0 sb rs232Rx1Flag ;mmc_addr_b1 received? jmp waitAddrB0 ;no, wait for mmc_addr_b1 from ;VURC EDITOR call @getbyte ;mmc_addr_b0 received, go get it ; _bank rs232RxBank mov w,rs232Byte1 ;place mmc_addr_b0 into W register _bank mmc_spix_ram ;ensure proper bank access mov mmc_addr_b0,w ;pass mmc_addr_b0 to mmc_cmd_block_read

77

;function mov w,#$01 ;pass $01 to the mmc_cmd_block_read ;function to tell it that the data ;it reads is to be output on UART 1 call @mmc_cmd_block_read ;read from the MMC and output data ;on UART1 jmp @waitCode ;get next control code from PC writeCard _bank rs232TxBank mov rs232Tx1Byte,#$FD ;send acknowledge $FD to ;VURC EDITOR waitTXFlag2 snb rs232Tx1Flag ;is flag clear? (ie: done sending any ;previous data?) if so, continue jmp waitTXFlag2 ;otherwise, wait for flag to clear setb rs232Tx1Flag ;set flag to send a byte on UART1 call @sendByte1 ;send acknowledge now _bank rs232RxBank ;switch to rs232 bank waitAddrB3b sb rs232Rx1Flag ;mmc_addr_b3 received? jmp waitAddrB3b ;no, wait for mmc_addr_b3 from ;VURC EDITOR call @getbyte ;mmc_addr_b3 received, go get it ; _bank rs232RxBank mov w,rs232Byte1 ;place mmc_addr_b3 into W register _bank mmc_spix_ram ;ensure proper bank access mov mmc_addr_b3,w ;pass mmc_addr_b3 to mmc_cmd_block_read ;function _bank rs232RxBank ;switch to rs232 bank waitAddrB2b sb rs232Rx1Flag ;mmc_addr_b2 received? jmp waitAddrB2b ;no, wait for mmc_addr_b2 from ;VURC EDITOR call @getbyte ;mmc_addr_b2 received, go get it ; _bank rs232RxBank mov w,rs232Byte1 ;place mmc_addr_b2 into W register _bank mmc_spix_ram ;ensure proper bank access mov mmc_addr_b2,w ;pass mmc_addr_b2 to mmc_cmd_block_read ;function _bank rs232RxBank ;switch to rs232 bank waitAddrB1b sb rs232Rx1Flag ;mmc_addr_b1 received? jmp waitAddrB1b ;no, wait for mmc_addr_b1 from ;VURC EDITOR call @getbyte ;mmc_addr_b1 received, go get it ; _bank rs232RxBank mov w,rs232Byte1 ;place mmc_addr_b1 into W register _bank mmc_spix_ram ;ensure proper bank access mov mmc_addr_b1,w ;pass mmc_addr_b1 to mmc_cmd_block_read ;function call @mmc_cmd_block_write ;receive data on UART1 and write ;to MMC jmp @waitCode ;get next control code from PC pcCommOut retp ;return and fix page bits

;********************************************************************************* ;--------------------------Miscelaneous Functions End Here----------------------;********************************************************************************* ;**************************************************************************************** ***************** ;-----------------------------------------------------Main Program--------------------------------------; Program execution begins here on power-up or after a reset ;**************************************************************************************** ***************** org MAINPROGRAM_ORG _resetEntry

78

;**************************************************************************************** ** ;------------------------------- Initialize all port configuration ----------------------;**************************************************************************************** ** _mode ST_W ;point MODE to write ST register mov w,#RB_ST ;Setup RB Schmitt Trigger, 0 = enabled, 1 = disabled mov !rb,w mov w,#RC_ST ;Setup RC Schmitt Trigger, 0 = enabled, 1 = disabled mov !rc,w IFDEF SX48_52 mov w,#RD_ST ;Setup RD Schmitt Trigger, 0 = enabled, 1 = disabled mov !rd,w mov w,#RE_ST ;Setup RE Schmitt Trigger, 0 = enabled, 1 = disabled mov !re,w ENDIF _mode LVL_W ;point MODE to write LVL register mov w,#RA_LVL ;Setup RA CMOS or TTL levels, 1 = TTL, 0 = CMOS mov !ra,w mov w,#RB_LVL ;Setup RB CMOS or TTL levels, 1 = TTL, 0 = CMOS mov !rb,w mov w,#RC_LVL ;Setup RC CMOS or TTL levels, 1 = TTL, 0 = CMOS mov !rc,w IFDEF SX48_52 mov w,#RD_LVL ;Setup RD CMOS or TTL levels, 1 = TTL, 0 = CMOS mov !rd,w mov w,#RE_LVL ;Setup RE CMOS or TTL levels, 1 = TTL, 0 = CMOS mov !re,w ENDIF _mode PLP_W ;point MODE to write PLP register mov w,#RA_PLP ;Setup RA Weak Pull-up, 0 = enabled, 1 = disabled mov !ra,w mov w,#RB_PLP ;Setup RB Weak Pull-up, 0 = enabled, 1 = disabled mov !rb,w mov w,#RC_PLP ;Setup RC Weak Pull-up, 0 = enabled, 1 = disabled mov !rc,w IFDEF SX48_52 mov w,#RD_PLP ;Setup RD Weak Pull-up, 0 = enabled, 1 = disabled mov !rd,w mov w,#RE_PLP ;Setup RE Weak Pull-up, 0 = enabled, 1 = disabled mov !re,w ENDIF _mode DDIR_W ;point MODE to write DDIR register mov w,#RA_DDIR ;Setup RA Direction register, 0 = output, 1 = input mov !ra,w mov w,#RB_DDIR ;Setup RB Direction register, 0 = output, 1 = input mov !rb,w mov w,#RC_DDIR ;Setup RC Direction register, 0 = output, 1 = input mov !rc,w IFDEF SX48_52 mov w,#RD_DDIR ;Setup RD Direction register, 0 = output, 1 = input mov !rd,w mov w,#RE_DDIR ;Setup RE Direction register, 0 = output, 1 = input mov !re,w ENDIF mov w,#RA_latch ;Initialize RA data latch mov ra,w mov w,#RB_latch ;Initialize RB data latch mov rb,w mov w,#RC_latch ;Initialize RC data latch mov rc,w IFDEF SX48_52 mov w,#RD_latch ;Initialize RD data latch mov rd,w mov w,#RE_latch ;Initialize RE data latch mov re,w ENDIF

79

;**************************************************************************************** ***************** ;---------------------------------------------Clear all Data RAM locations------------------------------;**************************************************************************************** ****************** IFDEF SX48_52 ;SX48/52 RAM clear routine mov w,#$0a ;reset all ram starting at $0A mov fsr,w :zeroRam clr ind ;clear using indirect addressing incsz fsr ;repeat until done jmp :zeroRam _bank bank0 clr $10 clr $11 clr $12 clr $13 clr $14 clr $15 clr $16 clr $17 clr $18 clr $19 clr $1a clr $1b clr $1c clr $1d clr $1e clr $1f ELSE ;clear bank 0 registers

;SX18/20/28 RAM clear routine clr fsr ;reset all ram banks :zeroRam sb fsr.4 ;are we on low half of bank? setb fsr.3 ; To clear from 08 - Global Registers clr ind ;clear using indirect addressing incsz fsr ;repeat until done jmp :zeroRam ENDIF ;********************************************************************************* ; Initialize program/VP registers ;********************************************************************************* _bank rs232TxBank ;select rs232 bank mov w,#UARTDivide1 ;load rs232Tx1Divide with UART1 baud rate mov rs232Tx1Divide,w mov w,#UARTDivide2 ;load rs232Tx1Divide with UART2 baud rate mov rs232Tx1Divide,w ;********************************************************************************* ; Setup and enable RTCC interrupt, WREG register, RTCC/WDT prescaler ;********************************************************************************* = %10000000 ;Enables RTCC at address $01 (RTW hi) ;*WREG at address $01 (RTW lo) by default RTCC_ID = %01000000 ;Disables RTCC edge interrupt (RTE_IE hi) ;*RTCC edge interrupt (RTE_IE lo) enabled by default RTCC_INC_EXT = %00100000 ;Sets RTCC increment on RTCC pin transition (RTS hi) ;*RTCC increment on internal instruction (RTS lo) is default RTCC_FE = %00010000 ;Sets RTCC to increment on falling edge (RTE_ES hi) ;*RTCC to increment on rising edge (RTE_ES lo) is default RTCC_PS_ON = %00000000 ;Assigns prescaler to RTCC (PSA lo) RTCC_PS_OFF = %00001000 ;Assigns prescaler to WDT (PSA hi) PS_000 = %00000000 ;RTCC = 1:2, WDT = 1:1 PS_001 = %00000001 ;RTCC = 1:4, WDT = 1:2 PS_010 = %00000010 ;RTCC = 1:8, WDT = 1:4 PS_011 = %00000011 ;RTCC = 1:16, WDT = 1:8 PS_100 = %00000100 ;RTCC = 1:32, WDT = 1:16 RTCC_ON

80

PS_101 PS_110 PS_111

= %00000101 = %00000110 = %00000111

;RTCC = 1:64, WDT = 1:32 ;RTCC = 1:128, WDT = 1:64 ;RTCC = 1:256, WDT = 1:128

OPTIONSETUP equ RTCC_PS_OFF|PS_111 ; the default option setup for this program. mov w,#OPTIONSETUP ; setup option register for RTCC interrupts enabled mov !option,w ; and prescaler assigned to WDT. ;**************************************************************************************** ******************* ;-------------------------------- Initialize system Devices below this line ------------------------------;**************************************************************************************** ******************* initMMC :sync _bank mmc_spix_ram mov mmc_cmd,#$ff ;execute the SYNCHRONIZE function call @mmc_execute ; call @Clk_delay2 ;delay aprox. 3ms before sending ;initialization command _bank mmc_spix_ram init mov mmc_cmd,#$fe ;execute the INITIALIZE function call @mmc_execute test mmc_status jnz init ;repeat in case of syncronization/initialization error mov w,#_sendTextFile ;Prompt user to send text file setb rs232Tx1Flag ;Flag to transmit on UART1 call @sendString1 initLCD call @lcdInit ;initialize the LCD jmp @mainLoop ;**************************************************************************************** ******************* ;-------------------------------- Initialize system Devices above this line ------------------------------;**************************************************************************************** ******************* ;**************************************************************************************** ******************* ;------------------------------------------------ MAIN PROGRAM CODE --------------------------------------;**************************************************************************************** *******************

mainLoop ;***********Poll Programming Mode button below this line*************************** pollButton snb programButton ;has the programButton been pressed? call @pcReadWriteMMC ;yes, so initiate communication with ;Window's based program, i.e.: write data ;to MMC such as bitmap images, jumptables, ;etc.... ;no, so continue on and poll touchscreen ;for screen touches ;***********Poll Programming Mode button above this line*************************** ;*************Display Bitmap Mode button above this line*************************** _bank mmc_spix_ram mov mmc_addr_b3,#$00 ;set up address to read ;from in MMC (i.e.: beginning address ;of a graphic bitmap image mov mmc_addr_b2,#$00 mov mmc_addr_b1,#$10 call @lcdDisplayBitmap;display a bitmap

81

;*************Display Bitmap Mode button above this line*************************** ;*************************TouchScreen code below this line************************* ;getTouchLoop call @checkTouchScreen ;test for touches of the touchscreen and ;take appropriate action if a touch has ;occured, if no touches have occured, then ;return from function call and continue on ;to test for a press of the programButton jmp @pollButton ;continue polling the programButton ;*************************Touchscreen code above this line************************* ;************************write below this line************************************* ;:write call @zero_MMC_addr ;reset MMC data address pointer => 0 ; _bank mmc_spix_ram ; mov mmc_cmd,#$FA ;execute the 512 byte block write command ; call @mmc_execute ;pass 512 bytes received on UART1 into ;MMC memory ; _bank mmc_spix_ram ; test mmc_status ;check how write procedure went ; sz ; jmp @statusError ;exit if we got an error writing ;data block ; jmp @:finished ;finished

;************************write above this line************************************** ;**************Hyperterminal User interface for R/W demo below this line************ ; ; ; mov w,#_hitSpace setb rs232Tx1Flag call @sendString1 ; Send prompt to terminal at UART rate ; Flag to Tx on UART1

;:loop ; call @getByte ; cjne rs232Byte1,#' ',:loop ; just keep looping until user ; hits the space bar ; mov w,#_hello1 ; When space bar hit, send out string. ; call @sendString1 ; jmp :loop ;**************Hyperterminal User interface for R/W demo above this line************* ;***************************read below this line************************************* ;:read_init call @zero_MMC_addr ;reset MMC data address pointer => 0 ; _bank mmc_spix_ram ;:read_loop mov mmc_cmd,#$FD ;execute the block read command ; call @mmc_execute ; _bank mmc_spix_ram ; test mmc_status ;check how read procedure went ; sz ; jmp @statusError ;exit if we got an error reading ;data block ;*************************Read above this line************************************** ;*************************LCD code below this line********************************** ; call @lcdInit ;initialize the LCD ;lcd initialized...... ;display a test message now ; call @lcdMWriteCmd ;this function will send an ;MWRITE command to the Epson ;SED1335F0A LCD controller ; mov w,#'V'

82

; ; ; ; ; ; ; ;

call @lcdWriteByte mov w,#'U' call @lcdWriteByte mov w,#'R' call @lcdWriteByte mov w,#'C' call @lcdWriteByte jmp @:finished

;display a ;display a

'V' on the LCD 'U' on the LCD

;display an 'R' on the LCD ;display a ;finished 'C' on the LCD

;*************************LCD code above this line********************************** ;*************************TouchScreen code below this line************************** ;getTouchLoop ; call @getTouch ; jmp @getTouchLoop ;*************************Touchscreen code above this line************************** :finished jmp @$ ;loop here when finished

statusError jmp $ ;in case of read/write error ;reset and re-initialize the MMC ;by sending CMD0 and CMD1 sequence ;over again commandCodeError jmp $ ;this is where you will get stuck ;if an invalid contol code is received ;from the "VURC EDITOR" ;**************************************************************************************** * END ;End of program code ;**************************************************************************************** *

83

Appendix E VURC Editor Flowcharts

84

Appendix E(a) Main Program Flowchart Start

Load and display splash Startup form

Load other forms

Display main form which Contains main menu

Wait for user selection of menu item

End

85

Appendix E(b) Flowchart for Creation of a New Screen Start

Create new MDI child window of type Child

Create new instances of ScreenClass with default properties

Redraw screen using button placement array

Ensure ButtonBar toolbar is visible

Update infor about new screen on ButtonBar (name, XY co-ords, etc.)

Wait for user to place a button on the screen

End

86

Appendix E(c) Flowchart for Creation of a New Button

Start

Show NewButtonForm

Get information entered by user

Create a new instance of ButtonClass with properties entered by user in NewButtonForm

MDI Child window of type ButtonEdit

Display initial bitmap information in ButtonEdit window (white screen)

Ensure that ButtonTools window is visible

Wait for user to perform such operation such as drawing on button, choosing to edit button properties

End

87

Appendix E(d) Flowchart for Placing a Button Start

Get X-Y co-ordinates of mouse and ensure mouse is over active window of type ButtonEdit

Left mouse button pressed? YES Copy current button type and mouse X-Y co-ordinates into button placement array

NO

Redraw Screen

Left mouse button held down? NO

YES

Get new X-Y co-ordinates and update them in button placement array.

End

88

Appendix F VURC Editor C++ Code
/****************************************************************************/ // About.cpp //--------------------------------------------------------------------------#include <vcl.h> #pragma hdrstop #include "About.h" //--------------------------------------------------------------------------#pragma package(smart_init) #pragma resource "*.dfm" TAboutBox *AboutBox; //--------------------------------------------------------------------------__fastcall TAboutBox::TAboutBox(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------/****************************************************************************/ // BBar.h //--------------------------------------------------------------------------#ifndef BBarH #define BBarH //--------------------------------------------------------------------------#include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> #include <ExtCtrls.hpp> #include <ComCtrls.hpp> #include <ToolWin.hpp> #include "ButtonClass.h" #include <Buttons.hpp> #include <Menus.hpp> //--------------------------------------------------------------------------class TButtonBar : public TForm { __published: // IDE-managed Components TPanel *Panel1; TPanel *Panel2; TTabControl *TabControl1; TImage *Image1; TSpeedButton *SpeedButton1; TSpeedButton *SpeedButton2; TStatusBar *StatusBar1; TStatusBar *StatusBar2; TStatusBar *StatusBar3; TStatusBar *StatusBar4; TStatusBar *StatusBar5; TStatusBar *StatusBar6; TBitBtn *BitBtn1; TMenuItem *E1; TMenuItem *HideToolbar1; TPopupMenu *PopupMenu1; TGroupBox *GroupBox1; TMemo *Memo1; TUpDown *UpDown1; void __fastcall FormCreate(TObject *Sender); void __fastcall UpDown1Click(TObject *Sender, TUDBtnType Button); void __fastcall TabControl1Change(TObject *Sender); void __fastcall FormActivate(TObject *Sender); void __fastcall BitBtn1Click(TObject *Sender); void __fastcall E1Click(TObject *Sender); void __fastcall HideToolbar1Click(TObject *Sender); private: // User declarations public: // User declarations __fastcall TButtonBar(TComponent* Owner); void __fastcall LoadButtonBitmap(unsigned char buttonNum); void __fastcall LoadButtonFiles(void); void __fastcall UpdateInfo(void); short __fastcall GetFreeButtonNum(void);

89

bool __fastcall AssignButtonNum(short tempButtonNum); bool __fastcall UnassignButtonNum(short tempButtonNum); short __fastcall NumberOfLoadedButtons(void); void __fastcall ReloadBitmapFiles(void); ButtonClass* button[256]; short currentButton; bool buttonTaken[256]; }; //--------------------------------------------------------------------------extern PACKAGE TButtonBar *ButtonBar; //--------------------------------------------------------------------------#endif /****************************************************************************/ // BBar.cpp //--------------------------------------------------------------------------#include <vcl.h> #include <dir.h> #pragma hdrstop #include "BBar.h" #include "ButtonClass.h" #include "ButtonProperties.h" #include "VURCedit.h" #include "PVChild.h" //--------------------------------------------------------------------------#pragma package(smart_init) #pragma resource "*.dfm" TButtonBar *ButtonBar; #define MAXBUTTONS 200 //--------------------------------------------------------------------------__fastcall TButtonBar::TButtonBar(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------void __fastcall TButtonBar::ReloadBitmapFiles(void) { // this function is used to reload all button files from disk // this function is usually called after creating or editing a new button // clear loaded button information for (int i=0; i<sizeof(buttonTaken); i++) buttonTaken[i] = false; LoadButtonFiles(); // load button information from disk } //--------------------------------------------------------------------------void __fastcall TButtonBar::FormCreate(TObject *Sender) { // clear loaded button information for (int i=0; i<sizeof(buttonTaken); i++) buttonTaken[i] = false; LoadButtonFiles(); // load button information from disk currentButton = 1; UpDown1->Max = NumberOfLoadedButtons(); UpDown1->Min = 1; UpDown1->Position = currentButton; LoadButtonBitmap(currentButton); // display appropriate image for button } //--------------------------------------------------------------------------void __fastcall TButtonBar::UpDown1Click(TObject *Sender, TUDBtnType Button) { // this function is called whenever the up/down control is clicked // this should cause the next/previous button to be diplayed Application->ProcessMessages(); currentButton = UpDown1->Position;

90

UpdateInfo(); // show stats of newly selected button Application->ProcessMessages(); } //--------------------------------------------------------------------------void __fastcall TButtonBar::LoadButtonBitmap(unsigned char buttonNum) { // this function gets the button bitmap information from button[] (ButtonClass) // and displays it in ButtonBar // TabControl1->Tabindex determines which bitmap is loaded // (visible or functional) Image1->Picture->Bitmap->Assign(button[buttonNum]->bitmap[TabControl1->TabIndex]); Image1->Picture->Bitmap->PixelFormat = pf1bit; // make sure it's monochrome // make image fit bitmap Image1->Height = Image1->Picture->Bitmap->Height; Image1->Width = Image1->Picture->Bitmap->Width; } //--------------------------------------------------------------------------void __fastcall TButtonBar::TabControl1Change(TObject *Sender) { // this event occures whenever the tab is changed LoadButtonBitmap(currentButton); // display new bitmap (visible or functional) } //--------------------------------------------------------------------------void __fastcall TButtonBar::LoadButtonFiles(void) { // this function searches the button directory and loads the button files // (.btn) // more work needs to be done to ensure bad buttons are not loaded struct ffblk ffblk; // structure for searching for files int done; // flag for determining if that's all the buttons or not int loop = 1; done = findfirst("*.btn",&ffblk,0); // find the first instance of button while (!done) { button[loop] = new ButtonClass(); // create new instance of ButtonClass button[loop]->LoadButton(ffblk.ff_name); // load the button now button[loop]->fileName = ffblk.ff_name; // assign name as loaded from disk AssignButtonNum(button[loop]->num); loop++; // increment pointer for next button done = findnext(&ffblk); // check to see if there is another } if (loop > 256) ShowMessage ("Too many buttons loaded!!!"); } //--------------------------------------------------------------------------void __fastcall TButtonBar::UpdateInfo(void) { TChild* child = dynamic_cast<TChild*>(MainForm->MDIChildren[0]); // this function updates the info shown about the current button displayed LoadButtonBitmap(currentButton); // display new bitmap (visible or functional) if (child) // if there is a child window open { for (int i=1; i<sizeof(child->screen->description); i++) Memo1->Text += child->screen->description[i]; StatusBar1->Panels->Items[2]->Text = "Menu: " + IntToStr(child->screen>description[0]); AnsiString* tempString = new AnsiString; for (int i=1; i<sizeof(child->screen->description); i++) tempString += child->screen->description[i]; } StatusBar3->Panels->Items[0]->Text = "Button: " + IntToStr(currentButton) + " (of " + IntToStr(NumberOfLoadedButtons()) + ")"; StatusBar3->Panels->Items[1]->Text = IntToStr(button[currentButton]->width) + "x" + IntToStr(button[currentButton]->height); StatusBar4->SimpleText = button[currentButton]->description;

91

if (button[currentButton]->function[0] == 0x01) StatusBar5->SimpleText = "Menu link to menu " + IntToStr(button[currentButton]>function[1]); if (button[currentButton]->function[0] == 0x02) StatusBar5->SimpleText = "IR Command"; StatusBar6->SimpleText = button[currentButton]->fileName; } //--------------------------------------------------------------------------short __fastcall TButtonBar::GetFreeButtonNum(void) { // this function searches for a free button number and returns one if found // if unsuccessful, a -1 is returned int i = 1; while ((buttonTaken[i]) && (i < 256)) i++; if (i == 256) { ShowMessage ("All 256 buttons already used!!"); return (-1); // return error } return (i); // return unused button location } //--------------------------------------------------------------------------bool { // // // // __fastcall TButtonBar::AssignButtonNum(short tempButtonNum) this function checks to see whether or not a button number has already been assigned, and assigns one if within range and not used if successful, true is returned if unsuccessful, false is returned

if ((tempButtonNum < 1) || (tempButtonNum > 255)) { ShowMessage ("Button not within range (1-256)"); ShowMessage (tempButtonNum); return 0; // unsuccessful } if (buttonTaken[tempButtonNum]) { AnsiString* tempString = new AnsiString; *tempString = "Duplicate button number ("; *tempString += IntToStr(tempButtonNum); *tempString += ")"; ShowMessage (*tempString); delete tempString; tempString = NULL; return 0; // unsuccessful } else { buttonTaken[tempButtonNum] = true; // assign button number return 1; // successful } } //--------------------------------------------------------------------------bool { // // // // __fastcall TButtonBar::UnassignButtonNum(short tempButtonNum) this function checks to determine if the button number is withing range and if so, removes it from the used button list if successful, true is returned if unsuccessful, false is returned

if ((tempButtonNum < 1) || (tempButtonNum > 255)) { ShowMessage ("Button not within range (1-256)"); return 0; // unsuccessful } buttonTaken[tempButtonNum] = false; // unassign button number return 1; // successful

92

} //--------------------------------------------------------------------------short __fastcall TButtonBar::NumberOfLoadedButtons(void) { // this function counts and returns how many buttons are currently loaded short tempTotalButtons = 0; for (int i=1; i<256; i++) if (buttonTaken[i]) tempTotalButtons++; return (tempTotalButtons); } //--------------------------------------------------------------------------void __fastcall TButtonBar::FormActivate(TObject *Sender) { UpdateInfo(); // show info about current button } //--------------------------------------------------------------------------void __fastcall TButtonBar::BitBtn1Click(TObject *Sender) { // this function is called when the "Edit Button Properties" button is pressed // is causes the Button Property Editor to display the current button EditButtonProperties->EditButton(button[currentButton]); // show the button propery editor form EditButtonProperties->ShowModal(); UpdateInfo(); // show new properties of button Application->ProcessMessages(); } //--------------------------------------------------------------------------void { // // // __fastcall TButtonBar::E1Click(TObject *Sender) this function is called when "Edit Button Properties" is selected from drop-down menu is causes the Button Property Editor to display the current button

EditButtonProperties->EditButton(button[currentButton]); // show the button propery editor form EditButtonProperties->ShowModal(); UpdateInfo(); // show new properties of button Application->ProcessMessages(); } //--------------------------------------------------------------------------void __fastcall TButtonBar::HideToolbar1Click(TObject *Sender) { ButtonBar->Hide(); } //--------------------------------------------------------------------------/****************************************************************************/ // ButtonClass.h //--------------------------------------------------------------------------#ifndef ButtonClassH #define ButtonClassH //--------------------------------------------------------------------------class ButtonClass { private: void OpenFile(AnsiString fileName); // for stream operations bool CreateFile(AnsiString fileName); void CloseFile(void); TFileStream *myFile; public: ButtonClass(void); // default constructor ~ButtonClass(void); // default destructor ButtonClass(short buttonNumber); // overloaded contructor // void SaveButton(AnsiString fileName); void SaveButton(int tempButtonNum); // overloaded function void LoadButton(AnsiString fileName); // button properties

93

AnsiString fileName; short num; char description[128]; char function[16]; // for the actual function as seen by VURC short width, height; Graphics::TBitmap* bitmap[2]; // for visual and functional bitmaps protected: }; // end of ButtonClass //--------------------------------------------------------------------------#endif /****************************************************************************/ // ButtonClass.cpp //--------------------------------------------------------------------------#include <vcl.h> #pragma hdrstop #include "ButtonClass.h" #pragma package(smart_init) //--------------------------------------------------------------------------ButtonClass::ButtonClass(void) { myFile = NULL; // make stream pointer point at nothing bitmap[0] = new Graphics::TBitmap; bitmap[1] = new Graphics::TBitmap; } // end of default constructor //--------------------------------------------------------------------------ButtonClass::~ButtonClass(void) { delete bitmap[0]; delete bitmap[1]; myFile->Free(); } // end of default destructor //--------------------------------------------------------------------------ButtonClass::ButtonClass(short buttonNumber) { // overloaded contructor num = buttonNumber; bitmap[0] = new Graphics::TBitmap; bitmap[1] = new Graphics::TBitmap; } //--------------------------------------------------------------------------void ButtonClass::OpenFile(AnsiString fileName) { try { myFile = new TFileStream(fileName, fmOpenRead); // open the file now } catch(...) { ShowMessage("Can't open file!!!"); } } //--------------------------------------------------------------------------bool ButtonClass::CreateFile(AnsiString fileName) { bool success = 1; try { myFile = new TFileStream(fileName, fmCreate); // create the file } catch(EFCreateError &E) { ShowMessage(E.Message); // show error message success = 0; } return (success); } //---------------------------------------------------------------------------

94

void ButtonClass::CloseFile(void) { myFile->Free(); } //--------------------------------------------------------------------------void ButtonClass::LoadButton(AnsiString fileName) { // this function load the button information from a saved file OpenFile(fileName); myFile->ReadBuffer(&num, sizeof(num)); myFile->ReadBuffer(description, sizeof(description)); myFile->ReadBuffer(function, sizeof(function)); myFile->ReadBuffer(&width, sizeof(width)); myFile->ReadBuffer(&height, sizeof(height)); bitmap[0]->LoadFromStream(myFile); bitmap[1]->LoadFromStream(myFile); CloseFile(); // close the file now } //--------------------------------------------------------------------------void ButtonClass::SaveButton(AnsiString fileName) { // this function saves the button information to disk if (CreateFile(fileName)) // if file successfully created { myFile->WriteBuffer(&num, sizeof(num)); myFile->WriteBuffer(description, sizeof(description)); myFile->WriteBuffer(function, sizeof(function)); myFile->WriteBuffer(&width, sizeof(width)); myFile->WriteBuffer(&height, sizeof(height)); bitmap[0]->SaveToStream(myFile); bitmap[1]->SaveToStream(myFile); } CloseFile(); } //--------------------------------------------------------------------------/* void ButtonClass::SaveButton(int tempButtonNum) { // this function saves the button information to disk as // "tempButtonNum.btn" AnsiString* fileName = new AnsiString; *fileName = IntToStr(tempButtonNum); *fileName += ".btn"; // adds appropriate extension CreateFile(*fileName); delete fileName; fileName = NULL; myFile->WriteBuffer(&num, sizeof(num)); myFile->WriteBuffer(description, sizeof(description)); myFile->WriteBuffer(function, sizeof(function)); myFile->WriteBuffer(&width, sizeof(width)); myFile->WriteBuffer(&height, sizeof(height)); bitmap[0]->SaveToStream(myFile); bitmap[1]->SaveToStream(myFile); CloseFile(); } */ //--------------------------------------------------------------------------/****************************************************************************/ // ButtonEditor.h //--------------------------------------------------------------------------#ifndef ButtonEditorH #define ButtonEditorH //--------------------------------------------------------------------------#include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp>

95

#include <Forms.hpp> #include <ExtCtrls.hpp> #include "ButtonClass.h" #include <Dialogs.hpp> #include <ExtDlgs.hpp> //--------------------------------------------------------------------------class TButtonEdit : public TForm { __published: // IDE-managed Components TImage *Image1; TSaveDialog *SaveDialog1; void __fastcall FormClose(TObject *Sender, TCloseAction &Action); void __fastcall FormCreate(TObject *Sender); void __fastcall FormActivate(TObject *Sender); void __fastcall Image1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y); void __fastcall Image1MouseMove(TObject *Sender, TShiftState Shift, int X, int Y); void __fastcall Image1MouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y); void __fastcall FormCloseQuery(TObject *Sender, bool &CanClose); private: // User declarations public: // User declarations void __fastcall UpdateInfo(void); void __fastcall UpdatePen(void); void __fastcall SaveButton(void); void __fastcall SaveButtonAs(void); void __fastcall SaveInfo(HANDLE file, const void* buffer, int size); bool buttonModified; bool buttonSaved; Graphics::TBitmap* bitmap1; Graphics::TBitmap* bitmap2; Graphics::TBitmap* bitmap3; ButtonClass* button; TColor currentColor; __fastcall TButtonEdit(TComponent* Owner); }; //--------------------------------------------------------------------------extern PACKAGE TButtonEdit *ButtonEdit; //--------------------------------------------------------------------------#endif /****************************************************************************/ // ButtonEditor.cpp //--------------------------------------------------------------------------#include <vcl.h> #pragma hdrstop #include "ButtonEditor.h" #include "NewButton.h" #include "ButtonToolForm.h" #include "BBar.h" #include "VURCedit.h" //--------------------------------------------------------------------------#pragma package(smart_init) #pragma resource "*.dfm" TButtonEdit *ButtonEdit; //--------------------------------------------------------------------------__fastcall TButtonEdit::TButtonEdit(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------void __fastcall TButtonEdit::FormCreate(TObject *Sender) { buttonModified = true; // yes, button has changed buttonSaved = false; // no, button hasn't been ever been saved // create a new instance of ButtonClass button = new ButtonClass; bitmap1 = new Graphics::TBitmap; bitmap2 = new Graphics::TBitmap; bitmap3 = new Graphics::TBitmap;

96

// set the width and height from the Button Creation Form int width = StrToInt(CreateNewButton->Edit1->Text); int height = StrToInt(CreateNewButton->Edit2->Text); Image1->Width = width; Image1->Height = height; ClientWidth = width; ClientHeight = height; button->width = width; button->height = height; // define new bitmap properties for visible bitmap bitmap1->PixelFormat = pf1bit; bitmap1->Width=width; bitmap1->Height=height; bitmap1->Monochrome = true; // make the canvas totally white Image1->Canvas->Brush->Color = clWhite; // clWhite = 0x00FFFFFF Image1->Canvas->Brush->Style = bsSolid; Image1->Canvas->FillRect(Image1->Canvas->ClipRect); Image1->Picture->Bitmap->PixelFormat = pf1bit; Image1->Picture->Bitmap->Monochrome = true; bitmap1->Assign(Image1->Picture->Bitmap); bitmap2->Assign(bitmap1); bitmap3->Assign(bitmap1); // copy original bitmap // clear the bitmap images and assign valid bitmap info to structure button->bitmap[0]->Assign(bitmap1); button->bitmap[1]->Assign(bitmap1); bitmap1->Dormant(); // Free up GDI resources bitmap1->FreeImage(); // Free up memory bitmap2->Dormant(); bitmap2->FreeImage(); bitmap3->Dormant(); bitmap3->FreeImage(); Image1->Picture->Bitmap->Assign(bitmap1); // tell Image which bitmap to use if (ButtonBar->GetFreeButtonNum() != -1) { button->num = ButtonBar->GetFreeButtonNum(); ButtonBar->AssignButtonNum(button->num); } button->fileName = "Untitled.btn"; Caption = button->fileName; UpdateInfo(); // update info on buttonbar } //--------------------------------------------------------------------------void __fastcall TButtonEdit::FormClose(TObject *Sender, TCloseAction &Action) { if (!buttonSaved) ButtonBar->UnassignButtonNum(button->num); // remove button used // delete button; delete bitmap1; delete bitmap2; delete bitmap3; button = NULL; bitmap1 = NULL; bitmap2 = NULL; bitmap3 = NULL; Action = caFree; // cause the window to close instead of minimize } //--------------------------------------------------------------------------void __fastcall TButtonEdit::FormActivate(TObject *Sender) { UpdateInfo(); // update the status window when this window is activated } //--------------------------------------------------------------------------void __fastcall TButtonEdit::UpdateInfo(void) {

97

Image1->Picture->Bitmap->Assign(button->bitmap[0]); // show visual bitmap ButtonTools->Label3->Caption = IntToStr(button->num); AnsiString* tempString = new AnsiString; *tempString = IntToStr(button->width); *tempString += " x "; *tempString += IntToStr(button->height); ButtonTools->Label5->Caption = *tempString; delete tempString; tempString = NULL; ButtonTools->Memo1->SelectAll(); ButtonTools->Memo1->SetSelTextBuf(button->description); if (button->function[0] == 0x01) { AnsiString* tempString = new AnsiString; *tempString = "Menu link to menu "; *tempString += IntToStr((unsigned char)button->function[1]); // show integer equivalent ButtonTools->Label1->Caption = *tempString; delete tempString; tempString = NULL; } if (button->function[0] == 0x02) ButtonTools->Label1->Caption = "IR Command"; } //--------------------------------------------------------------------------void __fastcall TButtonEdit::Image1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { if (Active) { if (Button==mbLeft) { UpdatePen(); // get info about color, etc. from ButtonTools Image1->Canvas->Pixels[X][Y] = currentColor; } } } //--------------------------------------------------------------------------void __fastcall TButtonEdit::Image1MouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { if (Active) // make sure child is Active { if (Shift.Contains(ssLeft)) //make sure left button is down { Image1->Canvas->Pixels[X][Y] = currentColor; Application->ProcessMessages(); // give Windows time to update picture } } } //--------------------------------------------------------------------------void __fastcall TButtonEdit::Image1MouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { if (Active) // make sure it's this child that is active { if (Button == mbLeft) //make sure its the left button being released { Application->ProcessMessages(); } } } //--------------------------------------------------------------------------void __fastcall TButtonEdit::UpdatePen(void) { // this function updates the drawing tools from ButtonTools if (ButtonTools->SpeedButton1->Down) currentColor = clBlack; if (ButtonTools->SpeedButton2->Down) currentColor = clWhite; } //--------------------------------------------------------------------------void __fastcall TButtonEdit::SaveButton(void) { // this function saves the current button to disk if (!buttonSaved)

98

{ SaveDialog1->FileName = Caption; if (SaveDialog1->Execute()) { button->fileName = ExtractFileName(SaveDialog1->FileName); Caption = button->fileName; } else return; // don't save at all if they cancel the save dialog button->SaveButton(button->fileName); buttonSaved = true; buttonModified = false; } } //--------------------------------------------------------------------------void __fastcall TButtonEdit::SaveButtonAs(void) { // this function saves the current button to disk // and always prompts for a name to save as SaveDialog1->FileName = Caption; if (SaveDialog1->Execute()) { button->fileName = ExtractFileName(SaveDialog1->FileName); Caption = button->fileName; button->SaveButton(button->fileName); buttonSaved = true; buttonModified = false; } } //--------------------------------------------------------------------------void __fastcall TButtonEdit::FormCloseQuery(TObject *Sender, bool &CanClose) { if (buttonModified) { AnsiString* tempString = new AnsiString; *tempString = "Save "; *tempString += Caption; *tempString += " ?"; int answer; if (Sender == MainForm) answer = MessageDlg(*tempString, mtConfirmation, TMsgDlgButtons() << mbYes << mbNo,0); else answer = MessageDlg(*tempString, mtConfirmation, TMsgDlgButtons() << mbYes << mbNo << mbCancel,0); delete tempString; tempString = NULL; if (answer == mrYes) { SaveDialog1->FileName = Caption; SaveButton(); } if (answer == mrCancel) CanClose = false; // stop window from closing } } //--------------------------------------------------------------------------/****************************************************************************/ // ButtonProperties.h //--------------------------------------------------------------------------#ifndef ButtonPropertiesH #define ButtonPropertiesH //--------------------------------------------------------------------------#include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> #include <ExtCtrls.hpp> #include <Buttons.hpp> #include <Dialogs.hpp> #include <ExtDlgs.hpp> #include <ComCtrls.hpp>

99

#include "ButtonClass.h" //--------------------------------------------------------------------------class TEditButtonProperties : public TForm { __published: // IDE-managed Components TPanel *Panel1; TBitBtn *BitBtn1; TBitBtn *BitBtn2; TBitBtn *BitBtn3; TBitBtn *BitBtn4; TOpenPictureDialog *OpenPictureDialog1; TPageControl *PageControl1; TTabSheet *TabSheet1; TTabSheet *TabSheet2; TLabel *Label4; TLabel *Label6; TLabel *Label7; TBevel *Bevel3; TGroupBox *GroupBox1; TMemo *Memo1; TGroupBox *GroupBox2; TLabel *Label1; TBevel *Bevel1; TLabel *Label3; TLabel *Label2; TRadioButton *RadioButton1; TRadioButton *RadioButton2; TEdit *Edit1; TEdit *Edit3; TEdit *Edit4; TEdit *Edit5; TEdit *Edit6; TEdit *Edit7; TEdit *Edit8; TEdit *Edit9; TEdit *Edit10; TEdit *Edit11; TEdit *Edit12; TEdit *Edit13; TEdit *Edit14; TEdit *Edit15; TEdit *Edit16; TEdit *Edit17; TPanel *Panel2; TPanel *Panel3; TImage *Image1; TImage *Image2; TEdit *Edit18; TLabel *Label8; void __fastcall RadioButton1Click(TObject *Sender); void __fastcall RadioButton2Click(TObject *Sender); void __fastcall FormActivate(TObject *Sender); void __fastcall BitBtn2Click(TObject *Sender); void __fastcall BitBtn3Click(TObject *Sender); void __fastcall BitBtn4Click(TObject *Sender); void __fastcall FormCreate(TObject *Sender); void __fastcall FormDestroy(TObject *Sender); void __fastcall Edit18KeyPress(TObject *Sender, char &Key); private: // User declarations public: // User declarations __fastcall TEditButtonProperties(TComponent* Owner); void __fastcall EditButton(ButtonClass* button); void __fastcall UpdateStatus(void); ButtonClass* tempButton; // to modify info Graphics::TBitmap* bitmap[2]; // for bitmap info }; //--------------------------------------------------------------------------extern PACKAGE TEditButtonProperties *EditButtonProperties; //--------------------------------------------------------------------------#endif /****************************************************************************/ // ButtonProperties.cpp //--------------------------------------------------------------------------#include <vcl.h> #pragma hdrstop #include "ButtonProperties.h"

100

#include "ButtonEditor.h" #include "VURCedit.h" #include "BBar.h" //--------------------------------------------------------------------------#pragma package(smart_init) #pragma resource "*.dfm" TEditButtonProperties *EditButtonProperties; bool numChanged = false; //--------------------------------------------------------------------------__fastcall TEditButtonProperties::TEditButtonProperties(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------void __fastcall TEditButtonProperties::FormCreate(TObject *Sender) { tempButton = new ButtonClass; // create new instance of button bitmap[0] = new Graphics::TBitmap; bitmap[1] = new Graphics::TBitmap; } //--------------------------------------------------------------------------void __fastcall TEditButtonProperties::FormDestroy(TObject *Sender) { //delete tempButton; // free memory tempButton = NULL; } //--------------------------------------------------------------------------void __fastcall TEditButtonProperties::EditButton(ButtonClass* button) { tempButton = button; // new button to edit } //--------------------------------------------------------------------------void __fastcall TEditButtonProperties::RadioButton1Click(TObject *Sender) { Edit1->Enabled = true; // restore menu # edit box // Edit2->Enabled = false; // gray out IR code edit box // this needs to be changed to allow the 15 separate edit boxes to be selected // or un-selected } //--------------------------------------------------------------------------void __fastcall TEditButtonProperties::RadioButton2Click(TObject *Sender) { Edit1->Enabled = false; // gray out menu # edit box // Edit2->Enabled = true; // restore IR code edit box } //--------------------------------------------------------------------------void __fastcall TEditButtonProperties::FormActivate(TObject *Sender) { UpdateStatus(); } //--------------------------------------------------------------------------void __fastcall TEditButtonProperties::BitBtn2Click(TObject *Sender) { // this function is called when the "Save and Close" button is pressed // it tells the button to save it's (updated) information to disk if (numChanged) { // check to see if number was actually changed if (StrToInt(Edit18->Text) != tempButton->num) { ShowMessage ("Reassigning button number"); // assign new button number if (ButtonBar->AssignButtonNum(StrToInt(Edit18->Text)) != -1) tempButton->num = StrToInt(Edit18->Text); } } // update bitmaps stored in button tempButton->bitmap[0]->Assign(bitmap[0]);

101

tempButton->bitmap[1]->Assign(bitmap[1]); Memo1->SelectAll(); // select all current text in memo Memo1->GetSelTextBuf(tempButton->description, sizeof(tempButton->description)); if (RadioButton1->Checked) // menu link button { tempButton->function[0] = 0x01; // menu link AnsiString tempString; tempString = Edit1->Text; tempButton->function[1] = StrToInt(tempString); } if (RadioButton2->Checked) { tempButton->function[0] = 0x02; char buffer[15]; // Edit2->GetTextBuf(buffer,sizeof(buffer)); // for (int i=0; i<15; i++) // tempButton->function[i+1] = buffer[i]; } tempButton->SaveButton(tempButton->fileName); // save the button to disk ButtonBar->ReloadBitmapFiles(); } //--------------------------------------------------------------------------void __fastcall TEditButtonProperties::BitBtn3Click(TObject *Sender) { // this function loads a saved bitmap into the visual bitmap if (OpenPictureDialog1->Execute()) // let the user select a file now { bitmap[0]->LoadFromFile(OpenPictureDialog1->FileName); Image1->Picture->Bitmap->Assign(bitmap[0]); tempButton->width = bitmap[0]->Width; tempButton->height = bitmap[0]->Height; // update info shown on screen to reflect new size AnsiString* tempString = new AnsiString; *tempString = IntToStr(bitmap[0]->Width); *tempString += " x "; *tempString += IntToStr(bitmap[0]->Height); Label7->Caption = *tempString; delete tempString; tempString = NULL; } } //--------------------------------------------------------------------------void __fastcall TEditButtonProperties::BitBtn4Click(TObject *Sender) { // this function loads a saved bitmap into the functional bitmap if (OpenPictureDialog1->Execute()) // let the user select a file now { Graphics::TBitmap* tempBitmap = new Graphics::TBitmap; tempBitmap->LoadFromFile(OpenPictureDialog1->FileName); if ((tempBitmap->Width == bitmap[0]->Width) && (tempBitmap->Height == bitmap[0]->Height)) { bitmap[1]->Assign(tempBitmap); // store the bitmap now Image2->Picture->Bitmap->Assign(bitmap[1]); // show new bitmap } else ShowMessage("The functional bitmap MUST be the same dimensions as the visual bitmap!!"); delete tempBitmap; // free memory tempBitmap = NULL; } } //--------------------------------------------------------------------------void __fastcall TEditButtonProperties::UpdateStatus(void) { numChanged = false; // reset flag // refresh bitmap images bitmap[0]->Assign(tempButton->bitmap[0]); bitmap[1]->Assign(tempButton->bitmap[1]); Image1->Picture->Bitmap->Assign(bitmap[0]);

102

Image2->Picture->Bitmap->Assign(bitmap[1]); Edit18->Text = IntToStr(tempButton->num); AnsiString* tempString = new AnsiString; *tempString = IntToStr(tempButton->width); *tempString += " x "; *tempString += IntToStr(tempButton->height); Label7->Caption = *tempString; delete tempString; tempString = NULL; Memo1->SelectAll(); // select all current text in memo Memo1->SetSelTextBuf(tempButton->description); if (tempButton->function[0] == 0x01) { RadioButton1->Checked = true; Edit1->Enabled = true; // Edit2->Enabled = false; Edit1->Text = IntToStr((unsigned char) tempButton->function[1]); } if (tempButton->function[0] == 0x02) { RadioButton2->Checked = true; Edit1->Enabled = false; // Edit2->Enabled = true; AnsiString tempString; for (int i=1; i<16; i++) tempString += tempButton->function[i]; // Edit2->Text = tempString; } } //--------------------------------------------------------------------------void __fastcall TEditButtonProperties::Edit18KeyPress(TObject *Sender, char &Key) { if (!numChanged) { numChanged = true; ShowMessage("Changing the number can cause problems, so beware!"); } } //--------------------------------------------------------------------------/****************************************************************************/ // ButtonToolForm.h //--------------------------------------------------------------------------#ifndef ButtonToolFormH #define ButtonToolFormH //--------------------------------------------------------------------------#include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> #include <Buttons.hpp> #include <ComCtrls.hpp> #include <ExtCtrls.hpp> //--------------------------------------------------------------------------class TButtonTools : public TForm { __published: // IDE-managed Components TPageControl *PageControl1; TTabSheet *TabSheet1; TSpeedButton *SpeedButton1; TSpeedButton *SpeedButton2; TSpeedButton *SpeedButton3; TSpeedButton *SpeedButton4; TSpeedButton *SpeedButton5; TTabSheet *TabSheet2; TGroupBox *GroupBox1; TButton *Button1; TGroupBox *GroupBox2; TLabel *Label1; TMemo *Memo1; TButton *Button2; TLabel *Label2;

103

TBevel *Bevel2; TLabel *Label3; TLabel *Label4; TBevel *Bevel3; TLabel *Label5; void __fastcall Button1Click(TObject *Sender); void __fastcall Button2Click(TObject *Sender); private: // User declarations public: // User declarations __fastcall TButtonTools(TComponent* Owner); }; //--------------------------------------------------------------------------extern PACKAGE TButtonTools *ButtonTools; //--------------------------------------------------------------------------#endif /****************************************************************************/ // ButtonToolForm.cpp //--------------------------------------------------------------------------#include <vcl.h> #pragma hdrstop #include "ButtonToolForm.h" #include "ButtonEditor.h" #include "VURCedit.h" #include "ButtonProperties.h" //--------------------------------------------------------------------------#pragma package(smart_init) #pragma resource "*.dfm" TButtonTools *ButtonTools; //--------------------------------------------------------------------------__fastcall TButtonTools::TButtonTools(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------void __fastcall TButtonTools::Button1Click(TObject *Sender) { TButtonEdit* buttonEdit = dynamic_cast<TButtonEdit*>(MainForm->MDIChildren[0]); if (!buttonEdit) return; // if no new button windows is active or open buttonEdit->SaveButton(); } //--------------------------------------------------------------------------void __fastcall TButtonTools::Button2Click(TObject *Sender) { TButtonEdit* buttonEdit = dynamic_cast<TButtonEdit*>(MainForm->MDIChildren[0]); if (!buttonEdit) // if no new button windows is active or open { ShowMessage ("No button selected!"); return; } // tell the property editor which button to edit EditButtonProperties->EditButton(buttonEdit->button); // show the button propery editor form EditButtonProperties->ShowModal(); buttonEdit->UpdateInfo(); // refresh bitmap, etc. } //--------------------------------------------------------------------------/****************************************************************************/ // ChildClass.h //--------------------------------------------------------------------------#ifndef ChildClassH #define ChildClassH #include "ButtonClass.h" //--------------------------------------------------------------------------class ScreenClass { private: protected: public: ScreenClass(void); // default constructor ~ScreenClass(void); // default destructor ButtonClass* button[5];

104

void CopyButton(int buttonNum, ButtonClass* oldButton); Graphics::TBitmap* bitmap1; Graphics::TBitmap* bitmap2; Graphics::TBitmap* bitmap3; short buttonsInScreen; short buttonHistory[5]; }; // end of ScreenClass #endif /****************************************************************************/ // ChildClass.cpp //--------------------------------------------------------------------------#include <vcl.h> #pragma hdrstop #include "ChildClass.h" //--------------------------------------------------------------------------#pragma package(smart_init) //--------------------------------------------------------------------------ChildClass::ChildClass(void) { // default constructor } ChildClass::~ChildClass(void) { // default destructor } void ChildClass::CopyButton(int buttonNum, ButtonClass* oldButton) { button[buttonNum] = oldButton; } /****************************************************************************/ // ConfigForm.h //--------------------------------------------------------------------------#ifndef ConfigFormH #define ConfigFormH //--------------------------------------------------------------------------#include <stdio.h> #include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> #include <Buttons.hpp> //--------------------------------------------------------------------------class TConfigBox : public TForm { __published: // IDE-managed Components TGroupBox *GroupBox1; TBitBtn *BitBtn1; TGroupBox *GroupBox2; TLabel *Label1; TLabel *Label2; TEdit *Edit1; TEdit *Edit2; TComboBox *ComboBox1; TBitBtn *BitBtn2; TGroupBox *GroupBox3; TComboBox *ComboBox2; void __fastcall FormCreate(TObject *Sender); void __fastcall BitBtn1Click(TObject *Sender); void __fastcall FormActivate(TObject *Sender); private: // User declarations bool OpenFile(const char* fileName); bool CreateFile(const char* fileName); void CloseFile(void); FILE* myFile; public: // User declarations __fastcall TConfigBox(TComponent* Owner); void LoadConfigInfo(void); void SaveConfigInfo(void);

105

char char char char

comPort[5]; buttonDirectory[500]; menuDirectory[500]; memoryCardSize[7];

}; //--------------------------------------------------------------------------extern PACKAGE TConfigBox *ConfigBox; //--------------------------------------------------------------------------#endif /****************************************************************************/ /* Filename: ConfigForm.cpp Author: Owen Taylor Last Revision: March 10, 2001 Project: VURCProjectGroup The form included with this file allows the user to select the COM Port, button and menu directories, and size of the MMC card. Routines within this file save and load this data as an .INI file. When the main program is first started, the data is loaded from the .INI file and the form data is updated. Currently, only the COM Port selection affects anything inside the program. All of the selections are saved to and loaded from disk, however. */ //--------------------------------------------------------------------------#include <vcl.h> #pragma hdrstop #include "ConfigForm.h" //--------------------------------------------------------------------------#pragma package(smart_init) #pragma resource "*.dfm" TConfigBox *ConfigBox; #define FILENAME "VURC.INI" //--------------------------------------------------------------------------__fastcall TConfigBox::TConfigBox(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------void __fastcall TConfigBox::FormCreate(TObject *Sender) { LoadConfigInfo(); Edit1->SetTextBuf(buttonDirectory); Edit2->SetTextBuf(menuDirectory); ComboBox1->SetTextBuf(comPort); ComboBox1->SetTextBuf(memoryCardSize); } //--------------------------------------------------------------------------bool TConfigBox::OpenFile(const char* fileName) { if ((myFile = fopen(fileName, "r")) == NULL) // open for reading return 0; // error opening file else return 1; // file opened successfully } //--------------------------------------------------------------------------bool TConfigBox::CreateFile(const char* fileName) { bool success = 1; try { myFile = fopen(fileName, "w"); // open for writing //myFile = new TFileStream(fileName, fmCreate); // create the file } catch(EFCreateError &E) { ShowMessage(E.Message); // show error message success = 0; } return (success); } //---------------------------------------------------------------------------

106

void TConfigBox::CloseFile(void) { fclose(myFile); } //--------------------------------------------------------------------------void TConfigBox::LoadConfigInfo(void) { // this function loads the config information from an .ini file char spacer[200]; if (OpenFile(FILENAME)) // if file successfully opened { fscanf(myFile, "%s %s", spacer, buttonDirectory); fscanf(myFile, "%s %s", spacer, menuDirectory); fscanf(myFile, "%s %s", spacer, comPort); fscanf(myFile, "%s %s", spacer, memoryCardSize); CloseFile(); // close the file now } else { // load default values from form itself ComboBox1->GetTextBuf(comPort,5); ComboBox2->GetTextBuf(memoryCardSize,5); Edit1->GetTextBuf(buttonDirectory,500); Edit2->GetTextBuf(menuDirectory,500); SaveConfigInfo(); // make new .ini file } } //--------------------------------------------------------------------------void TConfigBox::SaveConfigInfo(void) { // this function saves the button information to disk if (CreateFile(FILENAME)) // if file { // write some data to the file fprintf(myFile, "[BUTTON_DIRECTORY] fprintf(myFile, " [MENU_DIRECTORY] fprintf(myFile, " [COM_PORT] fprintf(myFile, " [MMC_CARD_SIZE] } successfully created %s\n", %s\n", %s\n", %s\n", buttonDirectory); menuDirectory); comPort); memoryCardSize);

CloseFile(); } //--------------------------------------------------------------------------void __fastcall TConfigBox::BitBtn1Click(TObject *Sender) { // this function is called when the OK button is pressed ComboBox1->GetTextBuf(comPort,5); ComboBox2->GetTextBuf(memoryCardSize,7); Edit1->GetTextBuf(buttonDirectory,500); Edit2->GetTextBuf(menuDirectory,500); SaveConfigInfo(); } //--------------------------------------------------------------------------void __fastcall TConfigBox::FormActivate(TObject *Sender) { Edit1->SetTextBuf(buttonDirectory); Edit2->SetTextBuf(menuDirectory); ComboBox1->SetTextBuf(comPort); ComboBox2->SetTextBuf(memoryCardSize); } //--------------------------------------------------------------------------/****************************************************************************/ // MMCAddress.h //--------------------------------------------------------------------------#ifndef MMCAddressH #define MMCAddressH //--------------------------------------------------------------------------#include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp>

107

#include <Buttons.hpp> //--------------------------------------------------------------------------class TMMCAddressBox : public TForm { __published: // IDE-managed Components TLabel *Label1; TLabel *Label2; TEdit *Edit1; TEdit *Edit2; TEdit *Edit3; TEdit *Edit4; TEdit *Edit5; TBitBtn *BitBtn1; TBitBtn *BitBtn2; void __fastcall Edit2KeyUp(TObject *Sender, WORD &Key, TShiftState Shift); void __fastcall FormActivate(TObject *Sender); void __fastcall Edit3KeyUp(TObject *Sender, WORD &Key, TShiftState Shift); void __fastcall Edit4KeyUp(TObject *Sender, WORD &Key, TShiftState Shift); void __fastcall Edit2Enter(TObject *Sender); private: // User declarations public: // User declarations __fastcall TMMCAddressBox(TComponent* Owner); }; //--------------------------------------------------------------------------extern PACKAGE TMMCAddressBox *MMCAddressBox; //--------------------------------------------------------------------------#endif /****************************************************************************/ // MMCAddress.cpp //--------------------------------------------------------------------------#include <vcl.h> #pragma hdrstop #include "MMCAddress.h" //--------------------------------------------------------------------------#pragma package(smart_init) #pragma resource "*.dfm" TMMCAddressBox *MMCAddressBox; //--------------------------------------------------------------------------__fastcall TMMCAddressBox::TMMCAddressBox(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------void __fastcall TMMCAddressBox::FormActivate(TObject *Sender) { ActiveControl = Edit2; // start the user in the address box } //--------------------------------------------------------------------------void __fastcall TMMCAddressBox::Edit2KeyUp(TObject *Sender, WORD &Key, TShiftState Shift) { if (Edit2->Text.Length() == 2) { ActiveControl = Edit3; Edit3->SelectAll(); } } //--------------------------------------------------------------------------void __fastcall TMMCAddressBox::Edit3KeyUp(TObject *Sender, WORD &Key, TShiftState Shift) { if (Edit3->Text.Length() == 2) { ActiveControl = Edit4; Edit4->SelectAll(); } } //--------------------------------------------------------------------------void __fastcall TMMCAddressBox::Edit4KeyUp(TObject *Sender, WORD &Key, TShiftState Shift) { if (Edit4->Text.Length() == 2)

108

{ ActiveControl = Edit5; Edit5->SelectAll(); } } //--------------------------------------------------------------------------void __fastcall TMMCAddressBox::Edit2Enter(TObject *Sender) { Edit2->SelectAll(); // cause the entire box to be selected } //--------------------------------------------------------------------------/****************************************************************************/ // NewButton.h //--------------------------------------------------------------------------#ifndef NewButtonH #define NewButtonH //--------------------------------------------------------------------------#include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> #include <Buttons.hpp> #include <ExtCtrls.hpp> //--------------------------------------------------------------------------class TCreateNewButton : public TForm { __published: // IDE-managed Components TMemo *Memo1; TLabel *Label6; TBitBtn *BitBtn1; TBitBtn *BitBtn2; TGroupBox *GroupBox1; TLabel *Label1; TLabel *Label2; TLabel *Label5; TLabel *Label7; TEdit *Edit1; TEdit *Edit2; TGroupBox *GroupBox2; TRadioButton *RadioButton1; TRadioButton *RadioButton2; void __fastcall BitBtn1Click(TObject *Sender); void __fastcall FormShow(TObject *Sender); private: // User declarations public: // User declarations __fastcall TCreateNewButton(TComponent* Owner); }; //--------------------------------------------------------------------------extern PACKAGE TCreateNewButton *CreateNewButton; //--------------------------------------------------------------------------#endif /****************************************************************************/ // NewButton.cpp //--------------------------------------------------------------------------#include <vcl.h> #pragma hdrstop #include "NewButton.h" #include "ButtonEditor.h" #include "ButtonToolForm.h" #include "BBar.h" //--------------------------------------------------------------------------#pragma package(smart_init) #pragma resource "*.dfm" TCreateNewButton *CreateNewButton; //--------------------------------------------------------------------------__fastcall TCreateNewButton::TCreateNewButton(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------void __fastcall TCreateNewButton::BitBtn1Click(TObject *Sender) { ButtonTools->Show(); // make sure the button tools are visible TButtonEdit* bEdit = new TButtonEdit(this); // create new button // put the description in the button info

109

Memo1->SelectAll(); Memo1-> GetSelTextBuf(bEdit->button->description,sizeof(bEdit->button->description)); //Puts Memo1->Text into Buffer if (RadioButton1->Checked) bEdit->button->function[0] = 0x01; // menu command if (RadioButton2->Checked) bEdit->button->function[0] = 0x02; // IR command for (int i=1; i<16; i++) bEdit->button->function[i] = 0; // clear code to begin with bEdit->UpdateInfo(); } //--------------------------------------------------------------------------void __fastcall TCreateNewButton::FormShow(TObject *Sender) { Memo1->Text = "No description"; } //--------------------------------------------------------------------------/****************************************************************************/ // PVChild.h //--------------------------------------------------------------------------#ifndef PVChildH #define PVChildH //--------------------------------------------------------------------------#include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> #include <ExtCtrls.hpp> #include "ScreenClass.h" #include <Dialogs.hpp> //--------------------------------------------------------------------------class TChild : public TForm { __published: // IDE-managed Components TImage *Image; TSaveDialog *SaveDialog1; TOpenDialog *OpenDialog1; void __fastcall FormClose(TObject *Sender, TCloseAction &Action); void __fastcall FormCreate(TObject *Sender); void __fastcall FormActivate(TObject *Sender); void __fastcall ImageMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y); void __fastcall ImageMouseMove(TObject *Sender, TShiftState Shift, int X, int Y); void __fastcall ImageMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y); private: // User declarations public: // User declarations __fastcall TChild(TComponent* Owner); void __fastcall UpdateInfo(void); void __fastcall UpdateMouseInfo(int X, int Y); void __fastcall LoadBitmap(AnsiString fileName); void __fastcall LoadScreen(void); void __fastcall SaveScreen(void); void __fastcall SaveScreenAs(void); void __fastcall SaveBitmap(AnsiString fileName); void __fastcall CopyNewButton(int x, int y, Graphics::TBitmap* bitmapA, Graphics::TBitmap* bitmapB, __int8 newColor); void __fastcall ClearBitmap(void); Graphics::TBitmap* bitmap1; Graphics::TBitmap* bitmap2; Graphics::TBitmap* bitmap3; int TCopyMode; ScreenClass* screen;

//

}; //--------------------------------------------------------------------------extern PACKAGE TChild *Child; //--------------------------------------------------------------------------#endif /****************************************************************************/ // PVChild.cpp //--------------------------------------------------------------------------#include <vcl.h>

110

#pragma hdrstop #include "PVChild.h" #include "BBar.h" #include "VURCedit.h" //--------------------------------------------------------------------------#pragma package(smart_init) #pragma resource "*.dfm" TChild *Child; //__int8 bits[320][240]; short currentButton; //--------------------------------------------------------------------------__fastcall TChild::TChild(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------void __fastcall TChild::FormCreate(TObject *Sender) { screen = new ScreenClass; // create a new instance of screen bitmap1 = new Graphics::TBitmap; bitmap2 = new Graphics::TBitmap; // bitmap3 = new Graphics::TBitmap; // ClearBitmap(); // clear the array that represents the functional bitmap // define new bitmap properties for visible bitmap bitmap1->PixelFormat = pf1bit; bitmap1->Width=320; bitmap1->Height=240; bitmap1->Monochrome = true; // define new bitmap properties for hidden bitmap bitmap2->PixelFormat = pf1bit; bitmap2->Width=320; bitmap2->Height=240; bitmap2->Monochrome = true; // define new bitmap properties for functional bitmap // bitmap3->Width=320; // bitmap3->Height=240; // change size of image Image->Width = bitmap1->Width; Image->Height = bitmap1->Height; // change size of window ClientWidth = bitmap1->Width; ClientHeight = bitmap1->Height; // make the canvas totally white Image->Canvas->Brush->Color = clWhite; // clWhite = 0x00FFFFFF Image->Canvas->Brush->Style = bsSolid; Image->Canvas->FillRect(Image->Canvas->ClipRect); Image->Picture->Bitmap->PixelFormat = pf1bit; // black and white only //copy the image to bitmap1 bitmap1->Assign(Image->Picture->Bitmap); bitmap2->Assign(bitmap1); // bitmap3->Assign(bitmap1); // copy original bitmap // bitmap3->PixelFormat = pf8bit; // change the format to 8 bit // bitmap3->Monochrome = false; // no, it's not monochrome anymore // bitmap3->HandleType = bmDIB; // device independant bitmap type bitmap1->Dormant(); // Free up GDI resources bitmap1->FreeImage(); // Free up memory bitmap2->Dormant(); bitmap2->FreeImage(); Caption = "Untitled"; // let the user know this is a new picture UpdateInfo(); // update info on buttonbar } //--------------------------------------------------------------------------void __fastcall TChild::FormClose(TObject *Sender, TCloseAction &Action) { // this handler is called when the form is actually closed

111

if (Caption == "Untitled") SaveScreenAs(); delete bitmap1; delete bitmap2; Action = caFree; // causes window to close instead of minimize } //--------------------------------------------------------------------------void __fastcall TChild::FormActivate(TObject *Sender) { // this function is called when the form becomes activated UpdateInfo(); //update the info window } //--------------------------------------------------------------------------void __fastcall TChild::UpdateInfo(void) { // this function updates the info in ButtonBar // this is usually called when the window gets focus // refresh button data in ButtonBar ButtonBar->StatusBar2->Panels->Items[0]->Text = Caption; ButtonBar->UpdateInfo(); } //--------------------------------------------------------------------------void __fastcall TChild::UpdateMouseInfo(int X, int Y) { // this function updates various info in ButtonBar as the mouse if moved // X and Y are the current location of the mouse ButtonBar->StatusBar1->Panels->Items[0]->Text = ("X: ") + IntToStr(X); ButtonBar->StatusBar1->Panels->Items[1]->Text = ("Y: ") + IntToStr(Y); } //--------------------------------------------------------------------------void __fastcall TChild::ImageMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { // TCopyMode = cmSrcCopy; TCopyMode = cmSrcAnd; if (Active) { if (Button==mbLeft) { if (ButtonBar->SpeedButton1->Down) // button select mode { screen->UpdatePlacedButtonBitmap(); // check for overlapping buttons if (screen->ButtonsOverlapping()) ButtonBar->StatusBar2->Panels->Items[1]->Text = "Overlapping buttons"; else ButtonBar->StatusBar2->Panels->Items[1]->Text = ""; currentButton = screen->placedButtonBitmap[X][Y]-1; if (currentButton == 0) // no button present at location return; // exit function ButtonBar->currentButton = screen->placedButton[currentButton].Type; ButtonBar->UpdateInfo(); } if (ButtonBar->SpeedButton2->Down) // button drop mode { // place the button in the middle of the cursor int newX, newY; int buttonWidth, buttonHeight; buttonWidth = ButtonBar->button[ButtonBar->currentButton]->bitmap[0]->Width; buttonHeight = ButtonBar->button[ButtonBar->currentButton]->bitmap[0]->Height; newX = X - (buttonWidth / 2); newY = Y - (buttonHeight / 2); // test to make sure button is within bounds if ((X + (buttonWidth/2)) > Image->Width) newX = Image->Width - (buttonWidth);

112

if (newX newX = if ((Y + newY = if (newY newY =

< 1) 0; (buttonHeight/2)) > Image->Height) Image->Height - (buttonHeight); < 1) 0;

// get the next available number for button storage currentButton = screen->GetFreeButtonNum(); //ButtonBar->Label8->Caption = currentButton; screen->placedButton[currentButton].Type = ButtonBar->currentButton; screen->placedButton[currentButton].X = newX; screen->placedButton[currentButton].Y = newY; screen->DrawScreen(Image->Picture->Bitmap); Application->ProcessMessages(); } } } } //--------------------------------------------------------------------------void __fastcall TChild::ImageMouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { //TColor currentColor; //currentColor = (TColor)0x00C700; /* the high-order byte of a TColor value contains palette information if the highest-order byte is zero (00), the color obtained is the closest matching color in the system palette. If the highest-order byte is one (01), the color obtained is the closest matching color in the currently realized palette. If the highest-order byte is two (02), the value is matched with the nearest color in the logical palette of the current device context. Some useful color variables: clBtnFace clWindow clWindowText */ if (Active) // make sure child is Active { if (Shift.Contains(ssLeft)) //make sure left button is down { // if (ButtonBar->SpeedButton2->Down) // button drop mode { // place the button in the middle of the cursor int newX, newY; int buttonWidth, buttonHeight; buttonWidth = ButtonBar->button[ButtonBar->currentButton]->bitmap[0]->Width; buttonHeight = ButtonBar->button[ButtonBar->currentButton]->bitmap[0]->Height; newX = X - (buttonWidth / 2); newY = Y - (buttonHeight / 2); // test to make sure button is within bounds if ((X + (buttonWidth/2)) > Image->Width) newX = Image->Width - (buttonWidth); if (newX < 1) newX = 0; if ((Y + (buttonHeight/2)) > Image->Height) newY = Image->Height - (buttonHeight); if (newY < 1) newY = 0; // update co-ordinates for current button screen->placedButton[currentButton].X = newX; screen->placedButton[currentButton].Y = newY; // redraw the bitmap screen->DrawScreen(Image->Picture->Bitmap); Application->ProcessMessages(); } } UpdateMouseInfo(X,Y); // show co-ordinates of cursor } } //---------------------------------------------------------------------------

113

void __fastcall TChild::ImageMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { if (Active) // make sure it's this child that is active { if (Button == mbLeft) //make sure its the left button being released { // place the button in the middle of the cursor int newX, newY; int buttonWidth, buttonHeight; buttonWidth = ButtonBar->button[ButtonBar->currentButton]->bitmap[0]->Width; buttonHeight = ButtonBar->button[ButtonBar->currentButton]->bitmap[0]->Height; //buttonWidth = ButtonBar->Image1->Picture->Bitmap->Width; //buttonHeight = ButtonBar->Image1->Picture->Bitmap->Height; newX = X - (buttonWidth / 2); newY = Y - (buttonHeight / 2); // test to make sure button is within bounds if ((X + (buttonWidth/2)) > Image->Width) newX = Image->Width - (buttonWidth); if (newX < 1) newX = 0; if ((Y + (buttonHeight/2)) > Image->Height) newY = Image->Height - (buttonHeight); if (newY < 1) newY = 0; // check for overlapping buttons if (screen->ButtonsOverlapping()) ButtonBar->StatusBar2->Panels->Items[1]->Text = "Overlapping buttons"; else ButtonBar->StatusBar2->Panels->Items[1]->Text = ""; } // update the mouse co-ordinates UpdateMouseInfo(X,Y); } } //--------------------------------------------------------------------------void __fastcall TChild::LoadBitmap(AnsiString fileName) { bitmap1->LoadFromFile(fileName); // load the file from disk bitmap1->Monochrome = true; bitmap2->Assign(bitmap1); AnsiString temp; temp = "b_" + fileName; //bitmap3->LoadFromFile(temp); Image->Width = bitmap1->Width; Image->Height = bitmap1->Height; ClientWidth = bitmap1->Width; ClientHeight = bitmap1->Height; Image->Picture->Bitmap->Assign(bitmap1); Image->Picture->Bitmap->PixelFormat = pf1bit; // monochrome Image->Canvas->Draw(0,0,bitmap1); Caption = ExtractFileName(fileName); UpdateInfo(); // update status window } //--------------------------------------------------------------------------void __fastcall TChild::LoadScreen(void) { if (OpenDialog1->Execute()) screen->LoadScreen(OpenDialog1->FileName); Caption = ExtractFileName(OpenDialog1->FileName); // draw the newly loaded screen screen->DrawScreen(Image->Picture->Bitmap); } //--------------------------------------------------------------------------void __fastcall TChild::SaveScreen(void) { screen->UpdateClassInfo(); if (Caption == "Untitled") SaveScreenAs(); else {

114

screen->UpdateClassInfo(); screen->SaveScreen(Caption); ShowMessage ("Screen Saved"); } } //--------------------------------------------------------------------------void __fastcall TChild::SaveScreenAs(void) { if (SaveDialog1->Execute()) { screen->UpdateClassInfo(); screen->SaveScreen(SaveDialog1->FileName); ShowMessage ("Screen Saved"); Caption = ExtractFileName(SaveDialog1->FileName); } } //--------------------------------------------------------------------------void __fastcall TChild::SaveBitmap(AnsiString fileName) { Image->Picture->Bitmap->SaveToFile(fileName); } //--------------------------------------------------------------------------/* void __fastcall TChild::ClearBitmap(void) { for (int i=0; i<320; i++) for (int j=0; j<240; j++) bits[i][j] = 0; } //--------------------------------------------------------------------------*/ void __fastcall TChild::CopyNewButton(int x, int y, Graphics::TBitmap* bitmapA, Graphics::TBitmap* bitmapB, __int8 newColor) { // This function is passed two coordinates, two bitmaps, and a color. // The first bitmap, which MUST be smaller than the second, is copied // into the second bimtap at location x, y, and every pixel present in bitmapA // which is a zero is changed to the new color specified. Graphics::TBitmap* tempBitmap; tempBitmap = new Graphics::TBitmap; tempBitmap->Assign(bitmapA); // assign the small bitmap to the temp bitmap for modification tempBitmap->PixelFormat = pf8bit; int x1, x2, y1, y2; x1 = bitmapA->Width; y1 = bitmapA->Height; x2 = bitmapB->Width; y2 = bitmapB->Height; if ((x1 > x2) || (y1 > y2)) return; destination bitmap // in case source bitmap is bigger than

for (int j=0; j<y1; j++) for (int i=0; i<x1; i++) { if (bitmapA->Canvas->Pixels[i][j] == 0) { tempBitmap->Canvas->Pixels[i][j] = newColor; //bits[i+x][j+y] = newColor; } } bitmapB->Canvas->Draw(x,y,tempBitmap); delete tempBitmap; // free memory } //--------------------------------------------------------------------------/****************************************************************************/ // ScreenClass.h //--------------------------------------------------------------------------#ifndef ScreenClassH #define ScreenClassH

115

#include "ButtonClass.h" //--------------------------------------------------------------------------class ScreenClass { private: bool OpenFile(AnsiString fileName); // for stream operations bool CreateFile(AnsiString fileName); void CloseFile(void); TFileStream *myFile; protected: public: struct PlacedButtonStruct { unsigned char Type; short X; short Y; }; struct ButtonFunctionStruct { char Byte[16]; }; ScreenClass(void); // default constructor ~ScreenClass(void); // default destructor void void void void void LoadScreen(AnsiString FileName); SaveScreen(AnsiString FileName); DrawScreen(Graphics::TBitmap* bitmap); UpdatePlacedButtonBitmap(void); UpdateClassInfo(void);

short NumButtons(void); short GetFreeButtonNum(void); bool ButtonsOverlapping(void); void ClearPlacedButtonBitmap(void); char description[128]; ButtonFunctionStruct buttonFunction[256]; // for menu link/IR command info unsigned char visualBitmap[9600]; // for visual screen (1-bit) unsigned char functionalBitmap[320][240]; // for functional screen (8-bit) PlacedButtonStruct placedButton[256]; unsigned char placedButtonBitmap[320][240]; // for selecting buttons on-screen }; // end of ScreenClass #endif /****************************************************************************/ // ScreenClass.cpp //--------------------------------------------------------------------------#include <vcl.h> #pragma hdrstop #include "ScreenClass.h" #include "BBar.h" //--------------------------------------------------------------------------#pragma package(smart_init) #define MAXBUTTONS 256 //--------------------------------------------------------------------------ScreenClass::ScreenClass(void) { // default constructor myFile = NULL; // make stream pointer point at nothing // clear description for (int i=0; i<sizeof(description); i++) description[i] = 0; // clear button function array for (int i=0; i<MAXBUTTONS; i++)

116

for (int j=0; j<16; j++) buttonFunction[i].Byte[j] = 0; // clear visual bitmap for (int i=0; i<sizeof(visualBitmap); i++) visualBitmap[i] = 0; // clear functional bitmap for (int i=0; i<320; i++) for (int j=0; j<240; j++) functionalBitmap[i][j] = 0; // clear placedButton array for (int i=0; i<MAXBUTTONS; i++) { placedButton[i].Type = 0; placedButton[i].X = 0; placedButton[i].Y = 0; } // clear placed button "bitmap" for (int i=0; i<320; i++) for (int j=0; j<240; j++) placedButtonBitmap[i][j] = 0; } //--------------------------------------------------------------------------ScreenClass::~ScreenClass(void) { // default destructor myFile->Free(); } //--------------------------------------------------------------------------bool ScreenClass::OpenFile(AnsiString fileName) { myFile = new TFileStream(fileName, fmOpenRead); if (myFile != NULL) return 1; // success else return 0; // failure } //--------------------------------------------------------------------------bool ScreenClass::CreateFile(AnsiString fileName) { bool success = 1; try { myFile = new TFileStream(fileName, fmCreate); // create the file } catch(EFCreateError &E) { ShowMessage(E.Message); // show error message success = 0; } return (success); } //--------------------------------------------------------------------------void ScreenClass::CloseFile(void) { myFile->Free(); } //--------------------------------------------------------------------------void ScreenClass::LoadScreen(AnsiString fileName) { // this function load the button information from a saved file if (OpenFile(fileName)) // if file successfully opened { myFile->ReadBuffer(buttonFunction, sizeof(buttonFunction)); myFile->ReadBuffer(visualBitmap, sizeof(visualBitmap)); myFile->ReadBuffer(description, sizeof(description)); myFile->ReadBuffer(functionalBitmap, sizeof(functionalBitmap)); //myFile->ReadBuffer(placedButton, sizeof(placedButton)); for (int i=0; i<256; i++) {

117

myFile->ReadBuffer(&placedButton[i].Type, sizeof(placedButton[i].Type)); myFile->ReadBuffer(&placedButton[i].X, sizeof(placedButton[i].X)); myFile->ReadBuffer(&placedButton[i].Y, sizeof(placedButton[i].Y)); } } CloseFile(); // close the file now } //--------------------------------------------------------------------------void ScreenClass::SaveScreen(AnsiString fileName) { // this function saves the button information to disk if (CreateFile(fileName)) // if file successfully created { myFile->WriteBuffer(buttonFunction, sizeof(buttonFunction)); myFile->WriteBuffer(visualBitmap, sizeof(visualBitmap)); myFile->WriteBuffer(description, sizeof(description)); myFile->WriteBuffer(functionalBitmap, sizeof(functionalBitmap)); for (int i=0; i<256; i++) { myFile->WriteBuffer(&placedButton[i].Type, sizeof(placedButton[i].Type)); myFile->WriteBuffer(&placedButton[i].X, sizeof(placedButton[i].X)); myFile->WriteBuffer(&placedButton[i].Y, sizeof(placedButton[i].Y)); } //myFile->WriteBuffer(placedButton, sizeof(placedButton)); } CloseFile(); } //--------------------------------------------------------------------------void ScreenClass::DrawScreen(Graphics::TBitmap* bitmap) { // clear the bitmap first bitmap->Canvas->Brush->Color = clWhite; // clWhite = 0x00FFFFFF bitmap->Canvas->Brush->Style = bsSolid; bitmap->Canvas->FillRect(bitmap->Canvas->ClipRect); // the following relies on the assumption that all the buttons will // be in order with no unused buttons between - create a function for this bitmap->Canvas->CopyMode = cmSrcAnd; // this draws the visual bitmap on bitmap for (int i=1; i<=NumButtons(); i++) bitmap->Canvas->Draw(placedButton[i].X, placedButton[i].Y, ButtonBar->button[placedButton[i].Type]->bitmap[0]); } //--------------------------------------------------------------------------void { // // // // ScreenClass::UpdatePlacedButtonBitmap(void) this function update the placed button bitmap the functional bitmaps from each of the buttons is used in this function (it is assumed the functional area will always be equal to or larger than the visual area)

int x = 0; int y = 0; int width = 0; int height = 0; unsigned char buttonNum; for (int k=1; k<=NumButtons(); k++) { buttonNum = placedButton[k].Type; width = ButtonBar->button[buttonNum]->bitmap[1]->Width; height = ButtonBar->button[buttonNum]->bitmap[1]->Height; x = placedButton[k].X; y = placedButton[k].Y; for (int j=0; j<(height); j++) for (int i=0; i<(width); i++) if (ButtonBar->button[buttonNum]->bitmap[1]->Canvas->Pixels[i][j] == 0) placedButtonBitmap[i+x][j+y] = k + 1; } } //---------------------------------------------------------------------------

118

bool ScreenClass::ButtonsOverlapping(void) { // this function checks to see if any buttons are currently overlapping // (according to the placed button bitmap) int x = 0; int y = 0; int width = 0; int height = 0; unsigned char buttonNum; bool overlap = false; ClearPlacedButtonBitmap(); for (int k=1; k<=NumButtons(); k++) { buttonNum = placedButton[k].Type; width = ButtonBar->button[buttonNum]->bitmap[1]->Width; height = ButtonBar->button[buttonNum]->bitmap[1]->Height; x = placedButton[k].X; y = placedButton[k].Y; for (int j=0; j<(height); j++) for (int i=0; i<(width); i++) if (ButtonBar->button[buttonNum]->bitmap[1]->Canvas->Pixels[i][j] == 0) { if (placedButtonBitmap[i+x][j+y] != 0) overlap = true; placedButtonBitmap[i+x][j+y] = k + 1; } } if (overlap) return(1); return(0); } //--------------------------------------------------------------------------short ScreenClass::NumButtons(void) { // this function counts how many buttons are in the current screen and // return that value short count = 0; for (int i=0; i<MAXBUTTONS; i++) if (placedButton[i].Type != 0) count++; return (count); } //--------------------------------------------------------------------------short ScreenClass::GetFreeButtonNum(void) { // this function finds a free button number for (short i=1; i<MAXBUTTONS; i++) if (placedButton[i].Type == 0) return(i); return(0); // didn't find a button } //--------------------------------------------------------------------------void ScreenClass::ClearPlacedButtonBitmap(void) { // clear placed button "bitmap" for (int i=0; i<320; i++) for (int j=0; j<240; j++) placedButtonBitmap[i][j] = 0; } //--------------------------------------------------------------------------void ScreenClass::UpdateClassInfo(void) { // this function updates buttonFunction, visualBitmap, & functionalBitmap // this information is necessary for the use of the VURC // update buttonFunction for (int i=1; i<=NumButtons(); i++) { for (int j=0; j<16; j++) buttonFunction[placedButton[i].Type].Byte[j] = ButtonBar>button[placedButton[i].Type]->function[j]; }

119

unsigned short temp = 0; unsigned char tempVisualBitmap[320][240]; unsigned char buttonNum; int width; int height; int x = 0; int y = 0; // clear temporary bitmap for (int j=0; j<240; j++) for (int i=0; i<320; i++) tempVisualBitmap[i+x][j+y] = 0; // create a temporary bitmap for (int k=1; k<=NumButtons(); k++) { buttonNum = placedButton[k].Type; x = placedButton[k].X; y = placedButton[k].Y; width = ButtonBar->button[buttonNum]->bitmap[0]->Width; height = ButtonBar->button[buttonNum]->bitmap[0]->Height; for (int j=0; j<height; j++) for (int i=0; i<width; i++) { if (ButtonBar->button[buttonNum]->bitmap[0]->Canvas->Pixels[i][j] == 0) tempVisualBitmap[i+x][j+y] = 1; else tempVisualBitmap[i+x][j+y] = 0; } } // this creates the visual bitmap that is shown on the VURC temp = 0x00; // ensure temp variable is cleared for (int i=0; i<76800; i++) { // get current X and Y co-ordinates y = i / 320; x = i % 320; temp <<= 1; // left shift 1 bit if (tempVisualBitmap[x][y] == 0) temp &= 0xfe; // clear first bit else temp |= 0x01; // set first bit if ((i % 8) == 0) visualBitmap[(i/8)-1] = temp; } // update functionalBitmap for (int k=1; k<=NumButtons(); k++) { buttonNum = placedButton[k].Type; width = ButtonBar->button[buttonNum]->bitmap[1]->Width; height = ButtonBar->button[buttonNum]->bitmap[1]->Height; x = placedButton[k].X; y = placedButton[k].Y; for (int j=0; j<(height); j++) for (int i=0; i<(width); i++) if (ButtonBar->button[buttonNum]->bitmap[1]->Canvas->Pixels[i][j] == 0) functionalBitmap[i+x][j+y] = buttonNum; } } //--------------------------------------------------------------------------/****************************************************************************/ // SplashSource.cpp //--------------------------------------------------------------------------#include <vcl.h> #pragma hdrstop #include "SplashSource.h" //--------------------------------------------------------------------------#pragma package(smart_init) #pragma resource "*.dfm"

120

TSplash *Splash; //--------------------------------------------------------------------------__fastcall TSplash::TSplash(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------/****************************************************************************/ // Test.h //--------------------------------------------------------------------------#ifndef testH #define testH //--------------------------------------------------------------------------#include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> #include <ExtCtrls.hpp> //--------------------------------------------------------------------------class TTestForm : public TForm { __published: // IDE-managed Components TButton *Button1; TPanel *Panel2; TImage *Image2; TPanel *Panel1; TImage *Image1; TTimer *Timer1; TPanel *Panel7; TPanel *Panel4; TPanel *Panel3; TImage *Image3; TPanel *Panel6; void __fastcall Timer1Timer(TObject *Sender); void __fastcall FormClose(TObject *Sender, TCloseAction &Action); void __fastcall Button1Click(TObject *Sender); private: // User declarations public: // User declarations __fastcall TTestForm(TComponent* Owner); }; //--------------------------------------------------------------------------extern PACKAGE TTestForm *TestForm; //--------------------------------------------------------------------------#endif /****************************************************************************/ // Test.cpp //--------------------------------------------------------------------------#include <vcl.h> #pragma hdrstop #include #include #include #include "test.h" "BBar.h" "VURCedit.h" "PVChild.h"

//--------------------------------------------------------------------------#pragma package(smart_init) #pragma resource "*.dfm" TTestForm *TestForm; //--------------------------------------------------------------------------__fastcall TTestForm::TTestForm(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------void __fastcall TTestForm::Timer1Timer(TObject *Sender) { TChild* child = dynamic_cast<TChild*>(MainForm->ActiveMDIChild); if (child) { Panel1->Width = child->bitmap1->Width; Panel1->Height = child->bitmap1->Height; Image1->Width = child->bitmap1->Width; Image1->Height = child->bitmap1->Height; Image1->Picture->Bitmap->Assign(child->bitmap1); Image1->Canvas->Draw(0,0,child->bitmap1);

121

Panel2->Width = child->bitmap2->Width; Panel2->Height = child->bitmap2->Height; Image2->Width = child->bitmap2->Width; Image2->Height = child->bitmap2->Height; Image2->Picture->Bitmap->Assign(child->bitmap2); Image2->Canvas->Draw(0,0,child->bitmap2); // Panel3->Width = child->bitmap3->Width; // Panel3->Height = child->bitmap3->Height; // Image3->Width = child->bitmap3->Width; // Image3->Height = child->bitmap3->Height; // Image3->Picture->Bitmap->Assign(child->bitmap3); // Image3->Canvas->Draw(0,0,child->bitmap3); } } //--------------------------------------------------------------------------void __fastcall TTestForm::FormClose(TObject *Sender, TCloseAction &Action) { Action = caFree; // causes window to close instead of minimize } //--------------------------------------------------------------------------void __fastcall TTestForm::Button1Click(TObject *Sender) { TChild* child = dynamic_cast<TChild*>(MainForm->MDIChildren[1]); if (child) { child->Image->Canvas->Brush->Color = clWhite; child->Image->Canvas->Brush->Style = bsSolid; child->Image->Canvas->FillRect(child->Image->Canvas->ClipRect); child->Image->Canvas->Brush->Color = clBlack; child->Image->Canvas->Rectangle(20, 20, 50, 50); } } //--------------------------------------------------------------------------/****************************************************************************/ // vurc.cpp //--------------------------------------------------------------------#include <vcl.h> #include "SplashSource.h" #pragma hdrstop //--------------------------------------------------------------------USERES("vurc.res"); USEFORM("VURCedit.cpp", MainForm); USEFORM("PVChild.cpp", Child); USEFORM("About.cpp", AboutBox); USEFORM("VurcLink.cpp", VLink); USEFORM("ConfigForm.cpp", ConfigBox); USEFORM("BBar.cpp", ButtonBar); USEUNIT("ButtonClass.cpp"); USEUNIT("ScreenClass.cpp"); USEFORM("NewButton.cpp", CreateNewButton); USEFORM("ButtonEditor.cpp", ButtonEdit); USEFORM("ButtonToolForm.cpp", ButtonTools); USEFORM("SplashSource.cpp", Splash); USEFORM("ButtonProperties.cpp", EditButtonProperties); USEFORM("MMCAddress.cpp", MMCAddressBox); //--------------------------------------------------------------------------WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { Application->Initialize(); Application->Title = "VURC Editor"; Splash = new TSplash(static_cast<void *>(NULL)); //no owner Splash->Show(); Application->ProcessMessages(); // this is necessary to show the Splash now Application->CreateForm(__classid(TMainForm), &MainForm); Application->CreateForm(__classid(TAboutBox), &AboutBox); Application->CreateForm(__classid(TVLink), &VLink); Application->CreateForm(__classid(TConfigBox), &ConfigBox); Application->CreateForm(__classid(TCreateNewButton), &CreateNewButton); Application->CreateForm(__classid(TButtonTools), &ButtonTools); Application->CreateForm(__classid(TButtonBar), &ButtonBar); Application->CreateForm(__classid(TEditButtonProperties), &EditButtonProperties); Application->CreateForm(__classid(TMMCAddressBox), &MMCAddressBox); Application->Run();

122

return 0; } //--------------------------------------------------------------------/****************************************************************************/ //--------------------------------------------------------------------------#ifndef VURCeditH #define VURCeditH //--------------------------------------------------------------------------#include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> #include <ActnList.hpp> #include <ImgList.hpp> #include <Menus.hpp> #include <ComCtrls.hpp> //#include <DBActns.hpp> #include <StdActns.hpp> #include <ToolWin.hpp> #include <ExtCtrls.hpp> //#include <Db.hpp> //#include <DBCtrls.hpp> //#include <Chart.hpp> //#include <DBChart.hpp> //#include <TeEngine.hpp> //#include <TeeProcs.hpp> #include <Dialogs.hpp> //--------------------------------------------------------------------------class TMainForm : public TForm { __published: // IDE-managed Components TMainMenu *MainMenu1; TImageList *ImageList1; TMenuItem *File1; TMenuItem *Save1; TMenuItem *N1; TMenuItem *Exit1; TMenuItem *Communication1; TMenuItem *Help1; TToolBar *ToolBar1; TMenuItem *About1; TMenuItem *Contents1; TMenuItem *N2; TMenuItem *OpenFile1; TSaveDialog *SaveDialog1; TOpenDialog *OpenDialog1; TToolButton *ToolButton1; TToolButton *ToolButton2; TToolButton *ToolButton3; TToolButton *ToolButton4; TStatusBar *StatusBar1; TToolButton *ToolButton5; TMenuItem *ReadMMCCard1; TMenuItem *WriteMMCCard1; TMenuItem *N4; TMenuItem *Config1; TMenuItem *Windows1; TMenuItem *ToggleToolbar1; TMenuItem *NewFile1; TMenuItem *SaveAs1; TMenuItem *NewMenu1; TMenuItem *NewButton1; TMenuItem *ToggleButtonEditor1; TToolButton *ToolButton6; TToolButton *ToolButton7; TMenuItem *N5; TMenuItem *Tile1; TMenuItem *Cascade1; TMenuItem *ArrangeAll1; TToolButton *ToolButton8; TMenuItem *SendFile1; TMenuItem *N6; TMenuItem *ReceiveFile1; void __fastcall Exit1Click(TObject *Sender); void __fastcall About1Click(TObject *Sender); void __fastcall Contents1Click(TObject *Sender); void __fastcall Save1Click(TObject *Sender); void __fastcall OpenFile1Click(TObject *Sender); void __fastcall ReadMMCCard1Click(TObject *Sender); void __fastcall WriteMMCCard1Click(TObject *Sender);

123

void __fastcall Config1Click(TObject *Sender); void __fastcall ToggleToolbar1Click(TObject *Sender); void __fastcall SaveAs1Click(TObject *Sender); void __fastcall NewMenu1Click(TObject *Sender); void __fastcall NewButton1Click(TObject *Sender); void __fastcall ToggleButtonEditor1Click(TObject *Sender); void __fastcall FormClose(TObject *Sender, TCloseAction &Action); void __fastcall FormShow(TObject *Sender); void __fastcall ToolButton7Click(TObject *Sender); void __fastcall Tile1Click(TObject *Sender); void __fastcall Cascade1Click(TObject *Sender); void __fastcall ArrangeAll1Click(TObject *Sender); void __fastcall FormCloseQuery(TObject *Sender, bool &CanClose); void __fastcall SendFile1Click(TObject *Sender); void __fastcall ReceiveFile1Click(TObject *Sender); private: // User declarations public: // User declarations __fastcall TMainForm(TComponent* Owner); }; //--------------------------------------------------------------------------extern PACKAGE TMainForm *MainForm; //--------------------------------------------------------------------------#endif /****************************************************************************/ /* Filename: VURCedit.cpp Author: Owen Taylor Last Revision: March 10, 2001 Project: VURCProjectGroup This is the main form for the VURC editor. Although this form has little actual code in it, it provides a doorway to other sections that actually do most of the work. The form itself contains little more than the main menu. Because this program is written to operate as an MDI interface, (Multiple Document Interface), opening or creating a file causes an MDI child to be created. */ //--------------------------------------------------------------------------#include <vcl.h> #include <stdlib.h> #include <string.h> #include <io.h> #include <dos.h> #pragma hdrstop #include #include #include #include #include #include #include #include #include #include #include "VURCedit.h" "About.h" "PVChild.h" "BBar.h" "NewButton.h" "ButtonEditor.h" "ButtonToolForm.h" "SplashSource.h" "VurcLink.h" "ConfigForm.h" "MMCAddress.h"

//--------------------------------------------------------------------------#pragma package(smart_init) #pragma resource "*.dfm" TMainForm *MainForm; //--------------------------------------------------------------------------__fastcall TMainForm::TMainForm(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------void __fastcall TMainForm::Exit1Click(TObject *Sender) { int answer; answer = MessageDlg("Are you sure you want to exit?", mtConfirmation, TMsgDlgButtons() << mbYes << mbNo, 0); if (answer == 6) exit(0);

124

} //--------------------------------------------------------------------------void __fastcall TMainForm::About1Click(TObject *Sender) { // MessageDlg("VURC Editor - v0.90 - Jan 24, 2001\n\nJamie Aitken\nTyson Gilberstad\nOwen Taylor", // mtInformation, TMsgDlgButtons() << mbOK, 0); AboutBox->ShowModal(); // shows the about information } //--------------------------------------------------------------------------void __fastcall TMainForm::Contents1Click(TObject *Sender) { ShowMessage("Sorry, no help for you yet!!"); } //--------------------------------------------------------------------------void __fastcall TMainForm::OpenFile1Click(TObject *Sender) { TChild* child = new TChild(this); if (!child) return; child->LoadScreen(); } //--------------------------------------------------------------------------void __fastcall TMainForm::Save1Click(TObject *Sender) { TChild* child = dynamic_cast<TChild*>(ActiveMDIChild); if (child) // check to see if it is a menu child->SaveScreen(); TButtonEdit* buttonEdit = dynamic_cast<TButtonEdit*>(ActiveMDIChild); if (buttonEdit) // check to see if it is a button buttonEdit->SaveButton(); } //--------------------------------------------------------------------------void __fastcall TMainForm::SaveAs1Click(TObject *Sender) { TChild* child = dynamic_cast<TChild*>(ActiveMDIChild); if (child) child->SaveScreenAs(); TButtonEdit* buttonEdit = dynamic_cast<TButtonEdit*>(ActiveMDIChild); if (buttonEdit) // check to see if it is a button buttonEdit->SaveButtonAs(); } //--------------------------------------------------------------------------void __fastcall TMainForm::ReadMMCCard1Click(TObject *Sender) { VLink->ReadMMCCard(); } //--------------------------------------------------------------------------void __fastcall TMainForm::WriteMMCCard1Click(TObject *Sender) { VLink->WriteMMCCard(); } //--------------------------------------------------------------------------void __fastcall TMainForm::Config1Click(TObject *Sender) { ConfigBox->ShowModal(); } //--------------------------------------------------------------------------void __fastcall TMainForm::ToggleToolbar1Click(TObject *Sender) { if (ButtonBar->Visible) ButtonBar->Hide(); else ButtonBar->Show(); } //--------------------------------------------------------------------------void __fastcall TMainForm::NewMenu1Click(TObject *Sender) { // show button selector

125

ButtonBar->Show(); // create new child window TChild* child = new TChild(this); child->Show(); // show the child window now } //--------------------------------------------------------------------------void __fastcall TMainForm::NewButton1Click(TObject *Sender) { CreateNewButton->ShowModal(); } //--------------------------------------------------------------------------void __fastcall TMainForm::ToggleButtonEditor1Click(TObject *Sender) { if (ButtonTools->Visible) ButtonTools->Hide(); else ButtonTools->Show(); } //--------------------------------------------------------------------------void __fastcall TMainForm::FormClose(TObject *Sender, TCloseAction &Action) { Action = caFree; } //--------------------------------------------------------------------------void __fastcall TMainForm::FormShow(TObject *Sender) { // this removes the splash screen after the form is shown if(Splash) // check to see if the pointer is valid { Sleep(2000); // 2 second delay so we get to see opening form delete Splash; // delete the splash form Splash = NULL ; // set the pointer so we don't do this again } } //--------------------------------------------------------------------------void __fastcall TMainForm::ToolButton7Click(TObject *Sender) { CreateNewButton->ShowModal(); } //--------------------------------------------------------------------------void __fastcall TMainForm::Tile1Click(TObject *Sender) { Tile(); // tile the open windows } //--------------------------------------------------------------------------void __fastcall TMainForm::Cascade1Click(TObject *Sender) { Cascade(); // cascade the open windows } //--------------------------------------------------------------------------void __fastcall TMainForm::ArrangeAll1Click(TObject *Sender) { ArrangeIcons(); } //--------------------------------------------------------------------------void __fastcall TMainForm::FormCloseQuery(TObject *Sender, bool &CanClose) { if (MessageDlg("Are you sure you want to exit?", mtConfirmation, TMsgDlgButtons() << mbYes << mbNo,0) == mrNo) CanClose = false; } //--------------------------------------------------------------------------void { // // // __fastcall TMainForm::SendFile1Click(TObject *Sender) this function sends a file to the VURC this needs to be improved to allow an address to be specified for now, the file is always sent to $00000000 (LSB is always $00)

126

if(OpenDialog1->Execute()) // if successfully got a filename VLink->SendFile(OpenDialog1->FileName.c_str(), 0x00, 0x00, 0x00); } //--------------------------------------------------------------------------void __fastcall TMainForm::ReceiveFile1Click(TObject *Sender) { // this function receives data from the VURC and saves it to disk if(OpenDialog1->Execute()) // if successfully got a filename VLink->ReadData(OpenDialog1->FileName.c_str(), 0x00, 0x00, 0x00, 0x00, 12345); } //--------------------------------------------------------------------------/****************************************************************************/ // VurcLink.h //--------------------------------------------------------------------------#ifndef VurcLinkH #define VurcLinkH //--------------------------------------------------------------------------#include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> #include <ComCtrls.hpp> #include "CGAUGES.h" #include <ExtCtrls.hpp> //--------------------------------------------------------------------------class TVLink : public TForm { __published: // IDE-managed Components TLabel *Label2; TCGauge *CGauge1; TLabel *Label5; TLabel *Label3; TLabel *Label1; TButton *Button1; void __fastcall FormKeyPress(TObject *Sender, char &Key); void __fastcall Button1Click(TObject *Sender); private: // User declarations public: // User declarations __fastcall TVLink(TComponent* Owner); void __fastcall ReadMMCCard(void); void __fastcall WriteMMCCard(void); void __fastcall SendFile(char* fileName, unsigned char a3, unsigned char a2, unsigned char a1); void __fastcall ReadData(char* fileName, unsigned char a3, unsigned char a2, unsigned char a1, unsigned char a0, long int fileSize); void __fastcall SendByte(HANDLE hHandle, unsigned char byte); void __fastcall CancelOperation(void); long int FileSize(char* fileName); void IntegerToHex(int number, unsigned char result[], int digits); }; //--------------------------------------------------------------------------extern PACKAGE TVLink *VLink; //--------------------------------------------------------------------------#endif /****************************************************************************/ /* Filename: VurcLink.cpp Author: Owen Taylor Last Revision: March 10, 2001 Project: VURCProjectGroup This form and code is used to communicate with the VURC unit. Files can be send and received, and the entire contents of MMC memory can be read from and saved to disk, or overwritten with data from a disk. */ //--------------------------------------------------------------------------#include <vcl.h> #include <io.h> // to check the size of file #include <fcntl.h> // for opening file #pragma hdrstop

127

#include "VurcLink.h" #include "ConfigForm.h" //--------------------------------------------------------------------------#pragma package(smart_init) #pragma link "CGAUGES" #pragma resource "*.dfm" TVLink *VLink; HANDLE hComm = NULL; // to handle com port communications HANDLE hFile = NULL; // to open file COMMTIMEOUTS ctmoNew = {0}, ctmoOld; #define BAUDRATE "19200,N,8,1" bool cancel = false; // for cancelling operations part way through //--------------------------------------------------------------------------__fastcall TVLink::TVLink(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------void __fastcall TVLink::SendFile(char* fileName, unsigned char a3, unsigned char a2, unsigned char a1) { DCB dcbCommPort; long int fileSize = FileSize(fileName); // get the size of the file // open com port 1 (serial port) hComm = CreateFile( ConfigBox->comPort, GENERIC_READ | GENERIC_WRITE, 0, // exclusive access 0, // no security OPEN_EXISTING, 0, // no overlapped I/O 0); // if the port can't be opened, stop application if(hComm == INVALID_HANDLE_VALUE) MessageDlg("Can't Open COM port!!", mtError, TMsgDlgButtons() << mbOK, 0); // now open the file that will be downloaded hFile = CreateFile( fileName, GENERIC_READ, 0, // exclusive access 0, // no security OPEN_EXISTING, 0, // no overlapped I/O 0); if(hFile == INVALID_HANDLE_VALUE) MessageDlg("Can't Open File!!", mtError, TMsgDlgButtons() << mbOK, 0); // set the com timeouts GetCommTimeouts(hComm,&ctmoOld); ctmoNew.ReadTotalTimeoutConstant = 100; ctmoNew.ReadTotalTimeoutMultiplier = 0; ctmoNew.WriteTotalTimeoutMultiplier = 0; ctmoNew.WriteTotalTimeoutConstant = 0; SetCommTimeouts(hComm, &ctmoNew); // set baud rate, parity, word size, and stop bits // (no handshaking by default) dcbCommPort.DCBlength = sizeof(DCB); GetCommState(hComm, &dcbCommPort); BuildCommDCB(BAUDRATE, &dcbCommPort); SetCommState(hComm, &dcbCommPort); unsigned long dwBytesRead = 0; // for number of bytes read in loop long dwTotalBytesRead = 0; // for total number of bytes read unsigned long lpBytesWritten; unsigned char inBuffer[512]; // read buffer // change the cursor to an hourglass TCursor oldCursor = Screen->Cursor; Screen->Cursor = crHourGlass; if (hComm && hFile) // make sure both were opened/created successfully

128

{ Caption = "Sending File to VURC"; Label2->Caption = "Bytes Sent:"; CGauge1->Progress = 0; Label3->Caption = "0K of 0K"; Label1->Caption = "Time remaining: unknown"; Show(); // show the form now DWord time = GetTickCount(); int timeLeft; int secondsLeft; int loopCount = 0; Caption = "Waiting for response from VURC"; // update status do { loopCount++; // increment loop pointer for updating items SendByte(hComm, 0x02); // transmit write command to MMC do { ReadFile(hComm, inBuffer, 1, &dwBytesRead, NULL); // wait for acknowledge if (cancel) { cancel = false; Hide(); // restore the cursor to it's previous state Screen->Cursor = oldCursor; // clear the internal com buffer and close the port Sleep(250); PurgeComm(hComm, PURGE_RXABORT); SetCommTimeouts(hComm, &ctmoOld); CloseHandle(hComm); // close com port CloseHandle(hFile); // close file hComm = NULL; hFile = NULL; return; } Application->ProcessMessages(); if (dwBytesRead == 0) Caption = "Waiting for response from VURC"; } while (dwBytesRead == 0); // wait until we receive a byte Caption = "Sending data to VURC"; // update status // check to see if we received one byte and it is the correct command reponse if ((dwBytesRead == 1) && (inBuffer[0] == (0xfd))) { // send the address now SendByte(hComm,a3); SendByte(hComm,a2); SendByte(hComm,a1); // if if a1 increment address for next write (a1 > 0xfd) a2++; // increment a2 if necessary (a2 == 0xff) a3++; // increment a3 if necessary += 0x02; // increment a1 by $02 -> actually is $0200 = decimal 512

// send the rest of the data now ReadFile(hFile, inBuffer, sizeof(inBuffer), &dwBytesRead, NULL); WriteFile(hComm, &inBuffer, dwBytesRead, &lpBytesWritten, NULL); dwTotalBytesRead += dwBytesRead; // keep track of total bytes read Label3->Caption = IntToStr((int)(dwTotalBytesRead/1000)) + "K of " + IntToStr((int)(fileSize/1000)) + "K"; CGauge1->Progress = (int)((dwTotalBytesRead * 100) / fileSize); // update time remaining timeLeft = (GetTickCount() - time) * ((fileSize-dwTotalBytesRead)/512); time = GetTickCount(); secondsLeft = (timeLeft/1000); // update every fifth time through the loop if ((loopCount % 5) == 0) { Label1->Caption = "Time remaining: " + IntToStr(secondsLeft) + " seconds"; Label1->Invalidate(); } CGauge1->Invalidate(); Label3->Invalidate(); Application->ProcessMessages(); // give it time to invalidate

129

} } while (dwTotalBytesRead < fileSize); // while not at the end of the file } // check to see if we've sent an even 512 block // if not, send the remainder as 0's // if the last entire 512 Byte block wasn't used, fill the remainder with 0's for (int i=0; i<(fileSize % 512); i++) SendByte(hComm, 0x00); SendByte(hComm, 0x03); // transmit resume command Hide(); // restore the cursor to it's previous state Screen->Cursor = oldCursor; // clear the internal com buffer and close the port Sleep(250); PurgeComm(hComm, PURGE_RXABORT); SetCommTimeouts(hComm, &ctmoOld); CloseHandle(hComm); // close com port CloseHandle(hFile); // close file hComm = NULL; hFile = NULL; } //--------------------------------------------------------------------------void __fastcall TVLink::ReadData(char* fileName, unsigned char a3, unsigned char a2, unsigned char a1, unsigned char a0, long int fileSize) { // this function reads data from the MMC (through the SX52BD) and stores it // in a file on disk. This needs to be changed to check if any memory // bounds are being crossed when reading // (can't read across the end of a 512 byte block) // the data received is stored in the file specified by fileName DCB dcbCommPort; // open com port 1 (serial port) hComm = CreateFile( ConfigBox->comPort, GENERIC_READ | GENERIC_WRITE, 0, // exclusive access 0, // no security OPEN_EXISTING, 0, // no overlapped I/O 0); // if the port can't be opened, stop application if(hComm == INVALID_HANDLE_VALUE) MessageDlg("Can't Open COM port!!", mtError, TMsgDlgButtons() << mbOK, 0); // now create the file that will contain data received hFile = CreateFile( "download.tst", GENERIC_WRITE, 0, // exclusive access 0, // no security CREATE_ALWAYS, 0, // no overlapped I/O 0); if(hFile == INVALID_HANDLE_VALUE) MessageDlg("Can't Create File!!", mtError, TMsgDlgButtons() << mbOK, 0); // set the com timeouts GetCommTimeouts(hComm,&ctmoOld); ctmoNew.ReadTotalTimeoutConstant = 1000; ctmoNew.ReadTotalTimeoutMultiplier = 2; ctmoNew.WriteTotalTimeoutMultiplier = 0; ctmoNew.WriteTotalTimeoutConstant = 0; SetCommTimeouts(hComm, &ctmoNew); // set baud rate, parity, word size, and stop bits // (no handshaking by default) dcbCommPort.DCBlength = sizeof(DCB); GetCommState(hComm, &dcbCommPort); BuildCommDCB(BAUDRATE, &dcbCommPort); SetCommState(hComm, &dcbCommPort);

130

unsigned long dwBytesRead = 0; // for number of bytes read in loop long dwTotalBytesReceived = 0; // for total number of bytes read unsigned long lpBytesWritten; unsigned char inBuffer[512]; // read buffer // change the cursor to an hourglass TCursor oldCursor = Screen->Cursor; Screen->Cursor = crHourGlass; if (hComm && hFile) // make sure both were successful { Caption = "Reading data from VURC"; Label2->Caption = "Bytes Received:"; CGauge1->Progress = 0; Label3->Caption = "0K of 0K"; Show(); // show the form now DWord time = GetTickCount(); int timeLeft; int secondsLeft; int loopCount = 0; Label1->Caption = "Time remaining: unknown"; // used to calculate the next block size to be sent to the VURC unsigned char bH, bL; unsigned char tempBuffer[2]; long int bytesLeft = fileSize; Invalidate(); Application->ProcessMessages(); do { loopCount++; // increment loop pointer for updating items SendByte(hComm, 0x01); // transmit read command to MMC do { ReadFile(hComm, inBuffer, 1, &dwBytesRead, NULL); // wait for acknowledge if (dwBytesRead == 0) Caption = "Waiting for response from VURC"; if (cancel) // check to see if the user has cancelled the operation { cancel = false; CancelOperation(); // close COM Port & files Screen->Cursor = oldCursor; // restore cursor to original state return; // end function now } Application->ProcessMessages(); } while (dwBytesRead == 0); // wait until we receive a byte Caption = "Sending data to VURC"; // update status // check to see if we received one byte and it is the correct command reponse if ((dwBytesRead == 1) && (inBuffer[0] == (0xfe))) { bytesLeft = fileSize - dwTotalBytesReceived; // check to see if we're on the last block or not if ((bytesLeft) < 512) IntegerToHex((bytesLeft), tempBuffer, 2); else { IntegerToHex(512, tempBuffer, 2); // just calculate 512 bytes bytesLeft = 512; // for read buffer } // store the result in the corresponding characters bH = tempBuffer[1]; bL = tempBuffer[0]; // send the size of the block now SendByte(hComm,bH); SendByte(hComm,bL); // send the address now SendByte(hComm,a3); SendByte(hComm,a2); SendByte(hComm,a1); SendByte(hComm,a0);

131

// if if a1

increment address for next read (a1 > 0xfd) a2++; // increment a2 if necessary (a2 == 0xff) a3++; // increment a3 if necessary += 0x02; // increment a1 by $02 -> actually is $0200 = decimal 512

// receive data from VURC now //ReadFile(hTestFile, inBuffer, sizeof(inBuffer), &dwBytesRead, NULL); // testing only ReadFile(hComm, inBuffer, bytesLeft, &dwBytesRead, NULL); ReadFile(hComm, inBuffer, 512, &dwBytesRead, NULL); WriteFile(hFile, &inBuffer, dwBytesRead, &lpBytesWritten, NULL); dwTotalBytesReceived += dwBytesRead; // keep track of total bytes read Label3->Caption = IntToStr((int)(dwTotalBytesReceived/1000)) + "K of " + IntToStr((int)(fileSize/1000)) + "K"; CGauge1->Progress = (int)((dwTotalBytesReceived * 100) / fileSize); // // update time remaining timeLeft = (GetTickCount() - time) * ((fileSize-dwTotalBytesReceived)/512); time = GetTickCount(); secondsLeft = (timeLeft/1000); // update every fifth time through the loop if ((loopCount % 5) == 0) { Label1->Caption = "Time remaining: " + IntToStr(secondsLeft) + " seconds"; Label1->Invalidate(); } CGauge1->Invalidate(); Label3->Invalidate(); Application->ProcessMessages(); // give it time to invalidate //Sleep(50); // for testing only - remove for final } } while (dwTotalBytesReceived < fileSize); // while not at the end of the file } SendByte(hComm, 0x03); // transmit resume command Hide(); // restore the cursor to it's previous state Screen->Cursor = oldCursor; // clear the internal com buffer and close the port Sleep(250); PurgeComm(hComm, PURGE_RXABORT); SetCommTimeouts(hComm, &ctmoOld); CloseHandle(hComm); // close com port CloseHandle(hFile); // close file hComm = NULL; hFile = NULL; //CloseHandle(hTestFile); // close file } //---------------------------------------------------------------------------

void __fastcall TVLink::ReadMMCCard(void) { DCB dcbCommPort; // open com port 1 (serial port) hComm = CreateFile( ConfigBox->comPort, GENERIC_READ | GENERIC_WRITE, 0, // exclusive access 0, // no security OPEN_EXISTING, 0, // no overlapped I/O 0); // if the port can't be opened, stop application if(hComm == INVALID_HANDLE_VALUE) MessageDlg("Can't Open COM port!!", mtError, TMsgDlgButtons() << mbOK, 0); // now open the file that we will save to hFile = CreateFile( "mmc1.dat", GENERIC_WRITE, 0, // exclusive access 0, // no security CREATE_ALWAYS, 0, // no overlapped I/O 0);

132

if(hFile == INVALID_HANDLE_VALUE) MessageDlg("Can't Create File!!", mtError, TMsgDlgButtons() << mbOK, 0); int answer; answer = MessageDlg("Connect VURC with MMC Card Inserted.", mtInformation, TMsgDlgButtons() << mbOK << mbCancel, 0); int error = 0; // reset error flag if (answer == 1) // if the user hit OK { // set the com timeouts GetCommTimeouts(hComm,&ctmoOld); ctmoNew.ReadTotalTimeoutConstant = 100; ctmoNew.ReadTotalTimeoutMultiplier = 0; ctmoNew.WriteTotalTimeoutMultiplier = 0; ctmoNew.WriteTotalTimeoutConstant = 0; SetCommTimeouts(hComm, &ctmoNew); // set baud rate, parity, word size, and stop bits // (no handshaking by default) dcbCommPort.DCBlength = sizeof(DCB); GetCommState(hComm, &dcbCommPort); BuildCommDCB(BAUDRATE, &dcbCommPort); SetCommState(hComm, &dcbCommPort); PurgeComm(hComm, PURGE_TXABORT | PURGE_TXCLEAR); // change the cursor to an hourglass TCursor oldCursor = Screen->Cursor; Screen->Cursor = crHourGlass; //unsigned long int MMCSize = 0; // size as returned from SX52 unsigned long int MMCSize2 = 0; // actual size of file received DWord dwBytesRead; char inBuffer[1024]; /* do { Sleep(10); TransmitCommChar(hComm, 0x70); // transmit synchronize command ReadFile(hComm, inBuffer, 5, &dwBytesRead, NULL); } while (!dwBytesRead); */ TransmitCommChar(hComm, 0x01); // transmit read request // get data from the COM port ReadFile(hComm, inBuffer, 50, &dwBytesRead, NULL); if (dwBytesRead != 1) { error = 1; // set the error flag if (dwBytesRead == 0) ShowMessage("No data received!! Check connection."); if (dwBytesRead != 5) ShowMessage("Error... faulty data read."); } if(!error) // make sure an error hasn't occurred { char code=inBuffer[0]; if (code!=0x02) { error = 1; ShowMessage ("Incorrect data received"); ShowMessage (inBuffer[0]); } else { /* for (int i=0; i<4; i++) { char size[4]; for (int i=0; i<4; i++) size[i] = inBuffer[i+1]+0x30; // convert into ascii equivalent MMCSize = atol(size); // convert ascii to a long int

133

} */ unsigned long lpBytesWritten; TransmitCommChar(hComm, 0x03); // signal that we're ready unsigned long times = 0; float status = 0; Show(); // save the data to file do { ReadFile(hComm, inBuffer, 1024, &dwBytesRead, NULL); WriteFile(hFile, &inBuffer, dwBytesRead, &lpBytesWritten, NULL); MMCSize2 += dwBytesRead; // add to total received for error checking times++; if (times%10==0) { //Label4->Caption=MMCSize2; status=(MMCSize2/160000); CGauge1->Progress = status; Refresh(); } } while (dwBytesRead!=0); Hide(); /* if (MMCSize != MMCSize2) ShowMessage ("Incorrect number of bytes read!!!"); else ShowMessage ("Card successfully read."); */ ShowMessage ("Finished reading card."); ShowMessage ("Number of bytes received:"); ShowMessage (MMCSize2); } } // restore the cursor Screen->Cursor = oldCursor; } // clear the internal com buffer and restore port settings Sleep(250); PurgeComm(hComm, PURGE_RXABORT); SetCommTimeouts(hComm, &ctmoOld); CloseHandle(hComm); // close com port CloseHandle(hFile); // close the file hComm = NULL; hFile = NULL; } //--------------------------------------------------------------------------void __fastcall TVLink::WriteMMCCard(void) { DCB dcbCommPort; // open com port 1 (serial port) hComm = CreateFile( ConfigBox->comPort, GENERIC_READ | GENERIC_WRITE, 0, // exclusive access 0, // no security OPEN_EXISTING, 0, // no overlapped I/O 0); // if the port can't be opened, stop application if(hComm == INVALID_HANDLE_VALUE) MessageDlg("Can't Open COM port!!", mtError, TMsgDlgButtons() << mbOK, 0); // now open the file that will be downloaded hFile = CreateFile( "mmc2.dat", GENERIC_READ, 0, // exclusive access 0, // no security OPEN_EXISTING,

134

0, // no overlapped I/O 0); if(hFile == INVALID_HANDLE_VALUE) MessageDlg("Can't Open File!!", mtError, TMsgDlgButtons() << mbOK, 0); // set the com timeouts GetCommTimeouts(hComm,&ctmoOld); ctmoNew.ReadTotalTimeoutConstant = 400; ctmoNew.ReadTotalTimeoutMultiplier = 0; ctmoNew.WriteTotalTimeoutMultiplier = 0; ctmoNew.WriteTotalTimeoutConstant = 0; SetCommTimeouts(hComm, &ctmoNew); // set baud rate, parity, word size, and stop bits // (no handshaking by default) dcbCommPort.DCBlength = sizeof(DCB); GetCommState(hComm, &dcbCommPort); BuildCommDCB(BAUDRATE, &dcbCommPort); SetCommState(hComm, &dcbCommPort); PurgeComm(hComm, PURGE_RXABORT); int answer; answer = MessageDlg("Connect VURC with MMC Card Inserted.", mtInformation, TMsgDlgButtons() << mbOK << mbCancel, 0); int error = 0; // reset error flag if (answer == 1) // if the user hit OK { DWord dwBytesRead; // number of bytes read from file char inBuffer[100]; // buffer for receiving data //unsigned long int MMCSize = 0; // size as returned from SX52 unsigned long int MMCSize2 = 0; // actual size of file received unsigned long lpBytesWritten; TransmitCommChar(hComm, 0x02); // send write request // get data from the COM port ReadFile(hComm, inBuffer, 50, &dwBytesRead, NULL); if (dwBytesRead != 1) { if (dwBytesRead == 0) ShowMessage ("No response received from VURC"); else ShowMessage ("Incorrect response received"); error = 1; // set error flag ShowMessage (dwBytesRead); } if (!error) { // change the cursor to an hourglass TCursor oldCursor = Screen->Cursor; Screen->Cursor = crHourGlass; TransmitCommChar(hComm, 0x03); // signal that we're ready // send the file through COM port do { ReadFile(hFile, inBuffer, 50, &dwBytesRead, NULL); WriteFile(hComm, &inBuffer, dwBytesRead, &lpBytesWritten, NULL); MMCSize2 += dwBytesRead; // add to total received for error checking } while (dwBytesRead!=0); ReadFile(hComm, inBuffer, 50, &dwBytesRead, NULL); if (dwBytesRead == 1) { if (inBuffer[0] == 0x01) ShowMessage ("Successful MMC card write"); else if (inBuffer[0] == 0x02) ShowMessage ("Unsuccessful MMC card write!!"); else ShowMessage ("Unknown code received from VURC"); } else ShowMessage ("Data write not verified"); // restore the cursor Screen->Cursor = oldCursor;

135

} } // clear the internal com buffer and restore port settings Sleep(250); PurgeComm(hComm, PURGE_RXABORT); SetCommTimeouts(hComm, &ctmoOld); CloseHandle(hComm); // close com port CloseHandle(hFile); // close the file hComm = NULL; hFile = NULL; } //--------------------------------------------------------------------------void TVLink::IntegerToHex(int number, unsigned char result[], int digits) { int initial = number; for(int i=0; i<digits; i++) { result[i] = initial % 256; initial = initial / 256; } } //--------------------------------------------------------------------------long int TVLink::FileSize(char* fileName) { // this function returns the size of a file stored on disk long int size; int handle; // for handling the file // open file for reading only handle = open(fileName, O_RDONLY); size = filelength(handle); // store the size in a temporary variable close(handle); // close the file handle = NULL; return (size); } //--------------------------------------------------------------------------void __fastcall TVLink::SendByte(HANDLE hHandle, unsigned char byte) { DWord lpBytesWritten; WriteFile(hHandle, &byte, 1, &lpBytesWritten, NULL); } //--------------------------------------------------------------------------void { // // // __fastcall TVLink::FormKeyPress(TObject *Sender, char &Key) this function is called whenever the user hits a key while this form is active. The only key-stroke that is currently tested for is ESC (27) Hitting ESC should cause the current upload/download to cancel

if (Key == 27) // escape key cancel = true; // cancel operation } //--------------------------------------------------------------------------void { // // // __fastcall TVLink::Button1Click(TObject *Sender) This function is called when the "Cancel" button on the VurcLink form is hit. This should allow the user the opportunity to cancel the upload or download.

if (MessageDlg("Are you sure you want to cancel?", mtConfirmation, TMsgDlgButtons() << mbYes << mbNo,0) == mrYes) cancel = true; } //--------------------------------------------------------------------------void __fastcall TVLink::CancelOperation(void) { // this function is called from within the upload/download routines. // it closes the com port and open files Hide(); // hide the form

136

// clear the internal com buffer and close the port Sleep(250); PurgeComm(hComm, PURGE_RXABORT); SetCommTimeouts(hComm, &ctmoOld); CloseHandle(hComm); // close com port CloseHandle(hFile); // close file hComm = NULL; hFile = NULL; } //---------------------------------------------------------------------------

137

Appendix G PIC IR Code
LIST P=16F874, R=DEC ;---------------------------------------------------------#include <P16F874.INC>

;---------------------------------------------------------; Variables ;---------------------------------------------------------; IR UART RECEIVE VARIABLES ;---------------------------------------------------------IR_TYPE equ 0x20 ; (e.g. RC-5) IR_FREQ equ 0x21 ; N nops between toggle on IR pin IR_STARTBURST equ 0x22 ; N repeats on carrier freq IR_STARTSPACE equ 0x23 ; N * 100 us IR_BURST equ 0x24 ; N repeats on carrier freq IR_ZEROSPACE equ 0x25 ; N * 100 us IR_ONESPACE equ 0x26 ; N * 100 us IR_DATABYTES equ 0x27 ; num of data BYTES to be sent IR_DATA1 equ 0x28 IR_DATA2 equ 0x29 IR_DATA3 equ 0x2A IR_DATA4 equ 0x2B IR_DATA5 equ 0x2C IR_DATA6 equ 0x2D IR_DATA7 equ 0x2E IR_REPEAT equ 0x2F ; number of times to re-transmit data IR_ZEROBURST equ IR_BURST IR_ONEBURST equ IR_ZEROSPACE IR_SPACE equ IR_ONESPACE

;---------------------------------------------------------; Program Code Variables ;---------------------------------------------------------UART_FLAGS equ 0x30 UART_RECEIVED equ 0 UART_DATA equ 0x31 TEMP equ 0x32 TEMP2 equ 0x33 BYTE equ 0x34 BIT_COUNT equ 0x35 BURST_TEMP equ 0x36 DATABYTES_TEMP equ 0x37 DATANIBBLES_TEMP equ DATABYTES_TEMP ;---------------------------------------------------------; Program Code ;---------------------------------------------------------ORG 0 GOTO Start ;ISR for UART ORG 4 GOTO UART_ISR Start

138

BSF STATUS,RP0 MOVLW 0x07 MOVWF ADCON1 BCF STATUS,RP0 CALL GOTO CALL ; GOTO ; ; ; ; ; ; ; ; IR_SETUP TESTLOOP UART_SETUP LOOP

MAIN ROUTINE LOOP -------------------------------------This loop is the main handler for the microcontroller. This waits for 16 bytes of data from the UART and places the information into the appropriate variables used for tranmission. When the tranmission sequence is complete, it decodes the transmission protocol necessary for IR tranmission, and calls the appropriate IR tranmission protocol routine.

LOOP BTFSS UART_FLAGS,UART_RECEIVED GOTO LOOP ; BTFSC UART_DATA,7 ; CALL ERROR MOVF UART_DATA,W MOVWF IR_TYPE BCF UART_FLAGS,UART_RECEIVED LOOP2 BTFSS UART_FLAGS,UART_RECEIVED GOTO LOOP2 MOVF UART_DATA,W MOVWF IR_FREQ BCF UART_FLAGS,UART_RECEIVED LOOP3 BTFSS UART_FLAGS,UART_RECEIVED GOTO LOOP3 MOVF UART_DATA,W MOVWF IR_STARTBURST BCF UART_FLAGS,UART_RECEIVED LOOP4 BTFSS UART_FLAGS,UART_RECEIVED GOTO LOOP4 MOVF UART_DATA,W MOVWF IR_STARTSPACE BCF UART_FLAGS,UART_RECEIVED LOOP5 BTFSS UART_FLAGS,UART_RECEIVED GOTO LOOP5 MOVF UART_DATA,W MOVWF IR_BURST BCF UART_FLAGS,UART_RECEIVED LOOP6 BTFSS UART_FLAGS,UART_RECEIVED GOTO LOOP6 MOVF UART_DATA,W MOVWF IR_ZEROSPACE BCF UART_FLAGS,UART_RECEIVED LOOP7 BTFSS UART_FLAGS,UART_RECEIVED GOTO LOOP7 MOVF UART_DATA,W MOVWF IR_ONESPACE BCF UART_FLAGS,UART_RECEIVED LOOP8 BTFSS UART_FLAGS,UART_RECEIVED GOTO LOOP8 MOVF UART_DATA,W MOVWF IR_DATABYTES BCF UART_FLAGS,UART_RECEIVED LOOP9 BTFSS UART_FLAGS,UART_RECEIVED

139

GOTO LOOP7 MOVF UART_DATA,W MOVWF IR_DATA1 BCF UART_FLAGS,UART_RECEIVED LOOP10 BTFSS UART_FLAGS,UART_RECEIVED GOTO LOOP10 MOVF UART_DATA,W MOVWF IR_DATA2 BCF UART_FLAGS,UART_RECEIVED LOOP11 BTFSS UART_FLAGS,UART_RECEIVED GOTO LOOP7 MOVF UART_DATA,W MOVWF IR_DATA3 BCF UART_FLAGS,UART_RECEIVED LOOP12 BTFSS UART_FLAGS,UART_RECEIVED GOTO LOOP12 MOVF UART_DATA,W MOVWF IR_DATA4 BCF UART_FLAGS,UART_RECEIVED LOOP13 BTFSS UART_FLAGS,UART_RECEIVED GOTO LOOP13 MOVF UART_DATA,W MOVWF IR_DATA5 BCF UART_FLAGS,UART_RECEIVED LOOP14 BTFSS UART_FLAGS,UART_RECEIVED GOTO LOOP14 MOVF UART_DATA,W MOVWF IR_DATA6 BCF UART_FLAGS,UART_RECEIVED LOOP15 BTFSS UART_FLAGS,UART_RECEIVED GOTO LOOP15 MOVF UART_DATA,W MOVWF IR_DATA7 BCF UART_FLAGS,UART_RECEIVED LOOP16 BTFSS UART_FLAGS,UART_RECEIVED GOTO LOOP7 MOVF UART_DATA,W MOVWF IR_REPEAT BCF UART_FLAGS,UART_RECEIVED BCF INTCON,GIE BTFSC IR_TYPE,0 CALL IR_REC80_SEND BTFSC IR_TYPE,1 CALL IR_SONY_SEND GOTO LOOP ; ; ; ; ; ; Function: UART_ISR ----------------------------------------This function is the interrupt service routine for the UART. It takes the data from the UART output register and places it into a temporary register, and sets a flag for the main loop to know that a byte reception has occured, and it may proceed.

UART_ISR BCF PIR1,TXIF BCF RCSTA,CREN ; TURN OFF CONTINUOUS RECEPTION (DO I NEED THIS??) BSF STATUS,RP0 MOVF RCREG,W BCF STATUS,RP1 MOVWF UART_DATA BSF UART_FLAGS,UART_RECEIVED BCF RCSTA,CREN ; TURN ON CONTINUOUS RECEPTION (DO I NEED THIS??) RETFIE

140

; Function IR_REC80_SEND ; ----------------------------------; This function send an IR transmission out under REC-80 protocols. IR_REC80_SEND ;FIRST OFF SEND START BURST CALL SEND_STARTBURST CALL SEND_STARTSPACE_REC80 MOVF IR_DATABYTES,W MOVWF DATABYTES_TEMP MOVF IR_DATA1,W CALL SEND_BYTE_REC80 DECFSZ DATABYTES_TEMP GOTO REC80_BYTE2 GOTO REC80_DONE_IR_SEND REC80_BYTE2 MOVF IR_DATA2,W CALL SEND_BYTE_REC80 DECFSZ DATABYTES_TEMP GOTO REC80_BYTE3 GOTO REC80_DONE_IR_SEND REC80_BYTE3 MOVF IR_DATA3,W CALL SEND_BYTE_REC80 DECFSZ DATABYTES_TEMP GOTO REC80_BYTE4 GOTO REC80_DONE_IR_SEND REC80_BYTE4 MOVF IR_DATA4,W CALL SEND_BYTE_REC80 DECFSZ DATABYTES_TEMP GOTO REC80_BYTE5 GOTO REC80_DONE_IR_SEND REC80_BYTE5 MOVF IR_DATA5,W CALL SEND_BYTE_REC80 DECFSZ DATABYTES_TEMP GOTO REC80_BYTE6 GOTO REC80_DONE_IR_SEND REC80_BYTE6 MOVF IR_DATA6,W CALL SEND_BYTE_REC80 DECFSZ DATABYTES_TEMP GOTO REC80_BYTE7 GOTO REC80_DONE_IR_SEND REC80_BYTE7 MOVF IR_DATA7,W CALL SEND_BYTE_REC80 REC80_DONE_IR_SEND CALL IR_PULSE ;MAY HAVE TO ADD REPEATER CODE HERE RETURN ; FUNCTION SEND_BYTE_REC80 ; ----------------------------------------------; This function sends a single BYTE of data under REC-80 protocol. SEND_BYTE_REC80 MOVWF BYTE MOVLW 0x8 MOVWF BIT_COUNT SENDL0 RLF BYTE,F BTFSC STATUS,C GOTO SENDL2 CALL REC80_IR_ZERO DECFSZ BIT_COUNT ;8 BITS DONE? GOTO SENDL0 RETURN SENDL2 CALL REC80_IR_ONE DECFSZ BIT_COUNT

141

GOTO SENDL0 RETURN ; FUNCTION REC80_IR_ZERO ; -----------------------------------------------------; This function sends a zero bit under REC-80 protocol. REC80_IR_ZERO MOVF IR_BURST,W CALL IR_PULSE MOVF IR_ZEROSPACE,W CALL DELAYN ;DELAY THE TIME NEEDED AFTER A ZERO BIT RETURN ; FUNCTION REC80_IR_ONE ; -----------------------------------------------------; This function sends a one bit under REC-80 protocol. REC80_IR_ONE MOVF IR_BURST,W CALL IR_PULSE MOVF IR_ONESPACE,W CALL DELAYN ;DELAY THE TIME NEEDED AFTER A ONE SPACE RETURN ; ; ; ; ; FUNCTION: IR_PULSE ----------------------------------------------This function sends an IR pulse out at the specified modulation frequency. The length of the pulse is placed in W before the function is called.)

IR_PULSE MOVWF BURST_TEMP IR_PULSE_LOOP BSF PORTB,2 CALL DELAYFREQ BCF PORTB,2 CALL DELAYFREQ DECFSZ BURST_TEMP GOTO IR_PULSE_LOOP RETURN ; ; ; ; ; FUNCTION: SEND_STARTBURST -----------------------------------------------This function sends out an IR pulse at the specified modulation frequency. The length of the pulse is placed in W before the function is called.)

SEND_STARTBURST MOVF IR_STARTBURST,W MOVWF BURST_TEMP IR_PULSE_LOOP2 BSF PORTB,2 CALL DELAYFREQ BCF PORTB,2 CALL DELAYFREQ DECFSZ BURST_TEMP GOTO IR_PULSE_LOOP2 RETURN ; ; ; ; FUNCTION: SEND_STARTSPACE_REC80 ---------------------------------------------------This function is simply a delay function for the specified time. This is used by REC-80 for a preamble space.

SEND_STARTSPACE_REC80 MOVF IR_STARTSPACE,W CALL DELAYN RETURN

142

; FUNCTION: DELAYN ; ---------------------------------------------------; This function is a software delay of n x 100 us. DELAYN MOVWF TEMP2 DELAYLOOP2 CALL DELAY100US DECFSZ TEMP2 GOTO DELAYLOOP2 RETURN ; FUNCTION: DELAY100US ; ---------------------------------------------------; This function is a software delay of 100 us. DELAY100US MOVLW D'165' MOVWF TEMP DELAYLOOP DECFSZ TEMP GOTO DELAYLOOP RETURN

;165 x 3 x .2

; FUNCTION: DELAY50US ; ---------------------------------------------------; This function is a software delay of 50 us. DELAY50US MOVLW D'82' ;82 x 3 x .2 MOVWF TEMP DELAYLOOP4 DECFSZ TEMP GOTO DELAYLOOP4 RETURN ; ; ; ; ; FUNCTION: DELAY50US ---------------------------------------------------This function is a software delay dependant on IR_FREQ. This is used to create the modulated output at the correct frequency.

DELAYFREQ MOVF IR_FREQ,W MOVWF TEMP DELAYLOOP3 DECFSZ TEMP GOTO DELAYLOOP3 RETURN ; ; ; ; FUNCTION: IR_SETUP --------------------------------------------------This function sets up the PORTB register to an output for the IR transmitter.

IR_SETUP CLRF PORTB BSF STATUS,RP0 CLRF TRISB BCF STATUS,RP0 RETURN ; ; ; ; ; FUNCTION: UART_SETUP -------------------------------------------------------This function sets up the UART to the appropriate settings commented below. The baud rate for this UART is defaulted to 19.2 kbps, and its setup as an asynchronous UART with high speed baud rate generation for better accuracy.

UART_SETUP BSF STATUS,RP0 BCF TXSTA,SYNC ; Asynchronous Mode

143

BSF TXSTA,BRGH ; High speed baud rate generation for less error. BSF PIE1,RCIE MOVLW 64 MOVWF SPBRG ; Baud Rate value for 19.2 kHz BCF STATUS,RP0 BSF INTCON,PEIE ; Peripheral interrupt enable BSF RCSTA,SPEN ; Serial port enable BSF RCSTA,CREN ; Continuous receive enable (do I need this??) BSF INTCON,GIE ; Global interrupt enable RETURN

; ; ; ;

FUNCTION IR_SONY_SEND ---------------------------------------------------------------This function sends out an IR transmission under Sony's pulse-width variation protocol.

IR_SONY_SEND CALL SEND_STARTBURST MOVF IR_SPACE,W CALL DELAYN ;DELAY THE TIME NEEDED AFTER A BIT CALL DELAY50US MOVF IR_DATABYTES,W MOVWF DATANIBBLES_TEMP MOVF IR_DATA1,W CALL SEND_NIBBLE_SONY DECFSZ DATANIBBLES_TEMP GOTO SONY_NIBBLE2 GOTO SONY_DONE_IR_SEND SONY_NIBBLE2 SWAPF IR_DATA1,W CALL SEND_NIBBLE_SONY DECFSZ DATANIBBLES_TEMP GOTO SONY_NIBBLE3 GOTO SONY_DONE_IR_SEND SONY_NIBBLE3 MOVF IR_DATA2,W CALL SEND_NIBBLE_SONY DECFSZ DATANIBBLES_TEMP GOTO SONY_NIBBLE4 GOTO SONY_DONE_IR_SEND SONY_NIBBLE4 SWAPF IR_DATA2,W CALL SEND_NIBBLE_SONY DECFSZ DATANIBBLES_TEMP GOTO SONY_NIBBLE5 GOTO SONY_DONE_IR_SEND SONY_NIBBLE5 MOVF IR_DATA3,W CALL SEND_NIBBLE_SONY DECFSZ DATANIBBLES_TEMP GOTO SONY_NIBBLE6 SONY_NIBBLE6 SWAPF IR_DATA3,W CALL SEND_NIBBLE_SONY SONY_DONE_IR_SEND RETURN ; FUNCTION: SEND_NIBBLE_SONY ; ----------------------------------------; This function transmits a single nibble (4 bits) under the Sony protocol.

SEND_NIBBLE_SONY MOVWF BYTE MOVLW 0x4 MOVWF BIT_COUNT SENDSL0 RLF BYTE,F BTFSC STATUS,C GOTO SENDSL2 CALL SONY_IR_ZERO

144

DECFSZ BIT_COUNT ;4 BITS DONE? GOTO SENDSL0 RETURN SENDSL2 CALL SONY_IR_ONE DECFSZ BIT_COUNT GOTO SENDSL0 RETURN ; FUNCTION SONY_IR_ZERO ; -----------------------------------------------------; This function sends a zero bit under SONY protocol. SONY_IR_ZERO MOVF IR_ZEROBURST,W CALL IR_PULSE ;PULSE THE TIME NEEDED FOR A ZERO BIT MOVF IR_SPACE,W CALL DELAYN ;DELAY THE TIME NEEDED AFTER A ZERO BIT CALL DELAY50US RETURN ; FUNCTION SONY_IR_ONE ; -----------------------------------------------------; This function sends a one bit under SONY protocol. SONY_IR_ONE MOVF IR_ONEBURST,W CALL IR_PULSE ;PULSE THE TIME NEEDED FOR A ONE BIT MOVF IR_SPACE,W CALL DELAYN ;DELAY THE TIME NEEDED AFTER A BIT CALL DELAY50US RETURN ; TEST FUNCTIONS ; -------------------------------------------------; These functions are used for testing sections of code. TESTLOOP MOVLW 4 ; MOVWF IR_TYPE MOVLW 20 MOVWF IR_FREQ MOVLW 0 MOVWF IR_STARTBURST MOVLW 0 MOVWF IR_STARTSPACE MOVLW 34 MOVWF IR_BURST MOVLW 0 MOVWF IR_ONEBURST MOVLW 9 MOVWF IR_SPACE MOVLW 4 MOVWF IR_DATABYTES MOVLW 0xAD MOVWF IR_DATA1 MOVLW 0x55 MOVWF IR_DATA2 MOVLW 0x4B MOVWF IR_DATA3 MOVLW 0x40 MOVWF IR_DATA4 MOVLW 3 MOVWF IR_REPEAT CALL IR_RC5_SEND MOVLW 0x40 CALL DELAYN GOTO TESTLOOP TEST MOVLW 0xFF

145

MOVWF PORTB NOP NOP NOP CLRF PORTB GOTO TEST ; Function IR_RC5_SEND ; ----------------------------------; This function send an IR transmission out under RC5 protocols. IR_RC5_SEND MOVF IR_DATABYTES,W MOVWF DATABYTES_TEMP MOVF IR_DATA1,W CALL SEND_BYTE_RC5 DECFSZ DATABYTES_TEMP GOTO RC5_BYTE2 GOTO RC5_DONE_IR_SEND RC5_BYTE2 MOVF IR_DATA2,W CALL SEND_BYTE_RC5 DECFSZ DATABYTES_TEMP GOTO RC5_BYTE3 GOTO RC5_DONE_IR_SEND RC5_BYTE3 MOVF IR_DATA3,W CALL SEND_BYTE_RC5 DECFSZ DATABYTES_TEMP GOTO RC5_BYTE4 GOTO RC5_DONE_IR_SEND RC5_BYTE4 MOVF IR_DATA4,W CALL SEND_BYTE_RC5 DECFSZ DATABYTES_TEMP GOTO RC5_BYTE5 GOTO RC5_DONE_IR_SEND RC5_BYTE5 MOVF IR_DATA5,W CALL SEND_BYTE_RC5 DECFSZ DATABYTES_TEMP GOTO RC5_BYTE6 GOTO RC5_DONE_IR_SEND RC5_BYTE6 MOVF IR_DATA6,W CALL SEND_BYTE_RC5 DECFSZ DATABYTES_TEMP GOTO RC5_BYTE7 GOTO RC5_DONE_IR_SEND RC5_BYTE7 MOVF IR_DATA7,W CALL SEND_BYTE_RC5 RC5_DONE_IR_SEND RETURN SEND_BYTE_RC5 MOVWF BYTE MOVLW 0x8 MOVWF BIT_COUNT SENDRC5L0 RLF BYTE,F BTFSS STATUS,C GOTO SENDRC5L2 MOVF IR_BURST,W CALL IR_PULSE DECFSZ BIT_COUNT ;4 BITS DONE? GOTO SENDRC5L0 RETURN SENDRC5L2

146

MOVF IR_SPACE,W CALL DELAYN DECFSZ BIT_COUNT GOTO SENDRC5L0 RETURN END

147

1

2

3

4

5

6

1 1
+

6V R7 10K D RE7

Vdd

1 2 3

2

2

Vdd

JP1 HEADER 3

C11 10uF

C16 0.1uF

1

K

R8 470

RD2

Q1 Q2N2222 C19 0.1uF R9
10Ω

1

+

C12 10uF

RA6 RA7 Vdd OSC1 OSC2 Vdd Vss RA0 RA1 RA2 RA3 RB0 RB1

1 2 3 4 5 6 7 8 9 10 11 12 13

RA5 RA4 RTCC Vss Vdd RE7 RE6 RE5 RE4 RE3 RE2 RE1 RE0

SW1 OMRON_B3S-1000

***Note*** This IR LED may need to be reversed.....

2

D7 IR LED

1

2

1

52 51 50 49 48 47 46 45 44 43 42 41 40

RA5 RA4 Vss Vss Vdd RE7 RE6 RE5 RE4 RE3 RE2 RE1 RE0

D

1 2 3

RA6 RA7 MCLR OSC1 OSC2 Vdd Vss RA0 RA1 RA2 RA3 RB0 RB1

U4 SX52BD

RD7 RD6 RD5 RD4 Vss Vdd RD3 RD2 RD1 RD0 RC7 RC6 RC5

39 38 37 36 35 34 33 32 31 30 29 28 27

RD7 RD6 RD5 RD4 Vss Vdd RD3 RD2 RD1 RD0 RC7 RC6 RC5

2

A

1

+

C13 10uF

C20 0.1uF

2

2

C

RB2 RB3 RB4 RB5 RB6 RB7 Vdd Vss RC0 RC1 RC2 RC3 RC4

C

P1 Female DB9 J1 CS Data In VSS1 VDD CLK VSS2 Data Out 1 2 3 4 5 6 7 RA7 RA5 Vdd

1

1 6 2 7 3 8 4 9 5

1 6 2 7 3 8 4 9 5

RA4 RA6 R10 U3 C17 0.1uF 1 2 3 4 5 6 7 8 C22 0.1uF C1+ V+ C1C2+ C2VTR2 OUT RX2 IN LTC1386 C21 0.1uF Vcc GND TR1 OUT RX1 IN RX1 OUT TR1 IN TR2 IN RX2 OUT 16 15 14 13 12 RA2 11 RA3 10 9 Vdd Vss Vdd Vo RE6 RE5 RE4 RC0 RC1 RC2 RC3 RC4 RC5 RC6 RC7 Vss RE3 -25V Vdd RE0 RD1 RE2 J2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 FH10A-26S-1SH

Tyco MMC Receptacle

2

2

RB2 RB3 RB4 RB5 RB6 RB7 1 Vdd Vss RC0 RC1 RC2 RC3 RC4
+

14 15 16 17 18 19 20 21 22 23 24 25 26
C14 10uF C23 0.1uF 20k B C18 0.1uF

B

J? CON4

1 2 3 4

+

C24 0.1uF C27 10pF -25V 3.3V -25V Vdd Y1 50MHz JP3 HEADER 2

C15 10uF

J3 2 1 CON2 6V

PowSup 6V

1 2

Vdd OSC1

GND

PowSup.Sch A C28 10pF OSC2 Title A

1 2

R11 470K

JP4 HEADER 2

Visual Universal Remote Control with Touchscreen
Number Drawn By: Jamie Aitken 21-Mar-2001 Sheet 1 of 2 X:\VURC project\Jamie\schematics\VURC.ddb Drawn By: 5 6 Revision Original Development

Size B Date: File: 1 2 3 4

1

2

3

4

D9 LL4148 2 C29 0.1uF 1 ANODE CATHODE T2 20uH

1

D

2

D

1

ANODE CATHODE

3.3V D10 Red Power LED

1 2 CATHODE ANODE

1
+

C30 100uF 10V

4

3

T-1

D8 1N5818 R12 1.82k 1%

21

U5 D11 DL4007 6V 1 Cathode Anode 2 1 2 Boost Vin SHDN* GND LT1376CS8 Vsw BIAS FB Vc 3 4 7 8

2

2
R14
330 Ω

4 x 1.5V "AA" Batteries

1

C31 100uF 20V +

5 6

C

C32 3.3nF

R13 4.99k 1%

C

2

1 1
C25 0.1uF U6 1 2 B 3 GND 4 SHDN POL REF FB MAX629ESA C36 150pF R17 604k 1% VCC LX GND ISET 8 7 6 5 2.2uF + C33 10uF L2 47uH

2

2

C35

R15

1

2

2Ω

B D13

MBR0540L

MBR0540L

K A

D12

2

1 2

A K

-25V

2
C26 0.1uF 30.1k 1% A Title

1

Power Supply for Visual Universal Remote Control
Number Drawn By: Jamie Aitken 21-Mar-2001 Sheet 2 of 2 X:\VURC project\Jamie\schematics\VURC.ddb Drawn By: * 4 Revision Original Development

Size A Date: File: 1 2 3

+

R16

C34 10uF 35V

1

A