hydra network control and visualizationitech.fgcu.edu/faculty/zalewski/cen3213/files/hydra...section...
TRANSCRIPT
HYDRA Network Control and Visualization
Scott Marks and Rick Haberkamp
CNT 4104 – Computer Network Programming
Dr. Janusz Zalewski
November 26, 2008
Marks & Haberkamp
Page 2 of 39
Table of Contents
Table of Contents 2
Section 1: Introduction 3
Section 2: Problem Description 7
Section 3: Solution 11
Section 4: Implementation 18
References 23
Appendix A: Server Source Code (C#) 24
Appendix B: Player Client Source Code (C#) 30
Appendix C: Developer Client Source Code (C#) 32
Appendix D: HYDRA Game Source Code (Spin) 34
Marks & Haberkamp
Page 3 of 39
Section 1: Introduction
General Information
The XGameStation HYDRA Game Development Kit is an advanced version of the simplistic
XGameStation Pico Edition 2.0 console [6]. The HYDRA console, pictured in Figure 1.1, is controlled by
Parallax’s Propeller multiprocessor, which is comprised of eight 32-bit processors. The Propeller can run
programs written in Propeller Assembly language, Spin object-oriented language by Parallax or a
combination of both [2]. Spin is comparable to C++ since it has direct control over the eight Propeller
processors and memory. [3]
Figure 1.1: HYDRA gaming console with a 128 KB game cartridge attached [1]
Embedded Systems Programming Project: Programming an Internet Interface
Concept Overview. The previous project’s goal was to implement an interface that would allow
two HYDRA consoles to communicate over a network via attached computers. A USB cable connected
each HYDRA to a PC and serial communication was achieved using serial-to-USB drivers. The computers
then acted as relays by passing HYDRA game state information across a network or the Internet. Figure
1.2 depicts the setup organization and flow of data communications. There were two aspects to this
Embedded Systems Programming project: the HYDRA game and the PC software.
Marks & Haberkamp
Page 4 of 39
Television HYDRA Game System Computer
Network Hub / InternetNES Controller
NES Controller
HYDRA Game SystemTelevision Computer
Figure 1.2: Equipment configuration and data flow diagram [3]
HYDRA Game
The game was built using peer-to-peer communication so only one version of the software was
required (not two for a server and client). The game worked by each HYDRA controlling one ghost via its
connected controller. The game software would send the x- and y-coordinates of its ghost to the other
HYDRA via the project’s developed network interface. The other HYDRA would receive the coordinates
and display the player’s ghost in the appropriate place on the screen. This process was also completed in
the opposite direction so that both players saw the same screen.
. A simple game of “tag” was created for the HYDRA consoles. As shown in the
Figure 1.3 screenshot, two ghosts, one controlled by each HYDRA player, could move anywhere on the
screen. The object of the game was to avoid being “it” by tagging the other player’s ghost but not be
tagged back by the other player afterward. The game did not include any means of scoring or rule
verification—these components were to be managed by the players.
The difficulty in creating this game software was the need to develop a method of
communication. This was completed over serial-to-USB by passing individual bytes of information. Each
byte utilized one bit that designated it to be an x- or y-coordinate. We arbitrarily picked the least
significant bit to be the coordinate bit—zero to represent the x-coordinate and one to represent the y-
Marks & Haberkamp
Page 5 of 39
coordinate. If a packet of information was lost somewhere along the line of communication, the ghost
would simply be updated on the reception of the next packet containing the dropped coordinate byte.
This was a simple solution that provided error checking and was easy to implement.
Figure 1.3: HYDRA game screenshot [3]
PC Software
Unlike the HYDRA game software, this HydraNet program required a designated server and
client. In order to give the users the most flexibility and to save on programming unneeded code, we
created one application that had the ability to act as either role per the user’s instructions. Each player
was then asked set up questions such as IP address and COM port. The user could exit the program by
either typing “exit” at the “Enter a command:” prompt or by using normal Microsoft Windows closing
techniques. A screenshot of both iterations of the software can be seen in Figure 1.4.
. Originally, this computer software was built in Java since we were both significantly
more familiar with Java than any other language. During testing, which utilized a HYDRA chat example
provided in the HYDRA Development Kit, it was learned that Java uses Unicode instead of ASCII. This
created many problems with communication and was ultimately scrapped. With the project deadline
quickly approaching, we switched to Visual Basic .NET to program the PC software. This was decided
because of the ease at which VB.NET handles sockets, threading and serial communication, which were
all essential to this program.
Marks & Haberkamp
Page 6 of 39
Figure 1.4: HydraNet server (top) and client (bottom) running on the same PC [3]
Results. Overall, the Embedded Systems Programming project was a success. Both the HYDRA
game and PC interface programs worked effectively and without error. For further information about
this previous project’s background, implementation and source code please see “Programming an
Internet Interface for the HYDRA Game Development Kit” [3].
Marks & Haberkamp
Page 7 of 39
Section 2: Problem Description
Definition of Problem
The goal of this project is to create a multiplayer game to run over a network using a single
HYDRA console for game state computation and multiple computers running the HYDRA game
visualization and controls. The equipment configuration and data flow is shown in Figure 2.1. This
method has several advantages over the project completed in the Embedded Systems Programming
course. Among the most obvious advantages are:
1. Support for two or more players
2. Only a single HYDRA is needed
3. No televisions are required to observe the game state at any given time
4. No extra (non-standard) controllers are necessary
5. The game can be played anywhere there is a PC with an Internet connection
Computer / Server
Network Hub / Internet
HYDRA Game System
Computer / ClientComputer / Client Computer / Client
Figure 2.1: Equipment configuration and data flow diagram
Marks & Haberkamp
Page 8 of 39
Outline of Solution
Our basic network layer organization, shown in Figure 2.2, will be comprised of five main layers.
The HYDRA will have the game application (layer 0) along with the data transmission and USB driver
(layer 1). The PC connected to the HYDRA will have the server transport software (layer 2). The
computers operated by the players will have the client transport software (layer 3) and the game
simulator application (layer 4). Each PC connected to the server will be required to individually run the
client software and game simulator application, which will probably be combined into one program.
Server Transport Layer Software(PC)
Transmitter / USB Driver(HYDRA)
Application / Game(HYDRA)
Client Transport Layer Software (PC)
Application / Game Simulator(PC)
Client Transport Layer Software (PC)
Application / Game Simulator(PC)
Client Transport Layer Software (PC)
Application / Game Simulator(PC)
Figure 2.2: Basic network layer organization
Outline of Implementation
The single HYDRA game console will assume a server-type role for the multiplayer game and will
essentially have the following three tasks:
1. Handle all communication received from clients connected through the Internet
2. Change game state appropriately
3. Send out game state information to all clients
The HYDRA will be directly connected to a PC (Figure 2.1) in order to give it access to an Internet
connection and allow other computers to connect as clients. All PC-to-PC communication will take place
over the Internet through a standalone application. The programming language of choice is C# since this
language has many uses in the real world, we have some experience programming with it, there are
Marks & Haberkamp
Page 9 of 39
numerous similarities between C# and Java, and porting the previous project’s VB.NET application
should be easier than porting to another language such as C++. However, if unexpected problems arise
with this language we will probably switch to C++ or Java.
Remote Game Development
In order to allow a remote developer to connect to the server and upload new games to the
HYDRA console, we will have to include Parallax’s Propellent DLL library in our server. This library is
provided by Parallax specifically for communicating with a Propeller multiprocessor from a PC over a
serial port. The Propellent library includes support that will allow us to:
• Establish a connection to the Propeller chip on the HYDRA
• Compile the source files
• Upload compiled files to the HYDRA
• Reset the HYDRA console
• Finalize changes before unloading the Propellent library [4]
Without this library, uploading game files from the Internet to the HYDRA would be nearly
impossible to complete in a semester-long project.
Anticipated Hurdles
The primary challenge of this project is how to differentiate between each player’s controller
(keyboard) inputs in the HYDRA. Previously, it was trivial to discern between x- and y-coordinates for
one player’s ghost. This project must utilize a significantly more advanced method. Since there are no
socket-type methods of serial over USB communication written in Parallax Spin, we will have to research
on proper algorithms for this type of data relay. If this problem cannot be overcome, we may have to
resort to calculating each player’s position on their computer and sending this information to the
HYDRA. This will still be more complex than the previous project but should be simpler to implement
than passing controller inputs.
Other issues that may arise during this project are also related to message passing and data
handling. To summarize these concerns, they are listed below in question form:
1. How will the HYDRA cope with the volume of incoming player input data?
2. How will the HYDRA differentiate between each player and between different inputs?
3. How will the HYDRA effectively output all player positions?
Marks & Haberkamp
Page 10 of 39
4. Will the computer server software easily handle multiple clients with significant data
transfer?
Marks & Haberkamp
Page 11 of 39
Section 3: Solution
Server Program Description
The server application, as diagrammed in Figure 3.1, is expected to handle communication with
each of the clients, as well as communication with the HYDRA. Upon running the server, the socket
server is initialized and two threads are created to establish communication with the HYDRA. An
additional thread is created that waits until an exit command is issued from the server's console and sets
a global exit variable flag. Next, the server enters a loop that listens for player and developer clients.
Upon a client connection it determines which type of client has connected and then creates an
appropriate thread for the connection.
Initialize socket server
While exit flag not true
Create HYDRA send/receive
threads
Create thread that checks for exit
command and sets exit flag
Listen for clients
If client is a player
Create client player thread
Create client developer thread
true
false
true
Terminate Threadsfalse
End Program
Start Program
Figure 3.1: Server program flowchart
HYDRA Send/Receive Threads. The server program needs two threads to properly communicate
to the HYDRA. The receive thread, shown on the left of Figure 3.2, gets the screen data and saves the
information to a buffer. This buffer is used in conjunction with the player threads in a producer-
consumer relationship. The send thread, which is on the right of Figure 3.3, uses a very similar design
Marks & Haberkamp
Page 12 of 39
except it reads from a buffer and sends the information to the HYDRA. Again, this player buffer is
implemented with a producer-consumer relationship. The start and end bytes are necessary to manage
information loss during data transfer between the server and HYDRA. The implementation of this
protocol is detailed later in this section.
While exit flag not true
Get start byte
Save screen data to screen buffer
false
true
End thread While exit flag not true
Send start byte
Send end byte
false
true
End thread
Get screen data
Send player count and player number
byte
Send player’s input byte
Read from player buffer
Get end byte
Figure 3.2: Flowcharts of server’s threads for HYDRA receive (left) and send (right)
Player Send/Receive Threads. These simple threads, which are provided in Figure 3.3, manage
data transfer between the HYDRA and player clients. Both threads utilize a producer-consumer
relationship with the HYDRA threads that are joined by common buffers. The receive thread handles
player inputs and the send thread controls screen information.
Marks & Haberkamp
Page 13 of 39
While exit flag not true
Get player’s input
Save player information to player buffer
false
true
End thread While exit flag not true
Read from screen buffer
Send screen data
false
true
End thread
Figure 3.3: Flowcharts of server’s threads for player receive (left) and send (right)
Developer Thread
Download game files
Compile game files Reset HYDRAUpload game files
to HYDRASend confirmation to client of success
. The developer thread is created by the server application, and handles
communication between the server and a developer client. Figure 3.4 outlines the thread’s algorithm.
After a developer client is connected, it receives the necessary game files from the client to be uploaded
to the HYDRA. The thread then uploads these files to the HYDRA, along with any support files that are
required, such as the USB driver and communication sources, and handle additional logic required to run
the new files on the HYDRA. Finally, the thread sends a signal to the client that the upload and reset
commands have completed successfully.
Figure 3.4: Server’s developer thread flowchart
Player Client Program Description
In a player client, as shown in Figure 3.5, the application handles communication with the
server, as well as output the game state to the screen for viewing. Upon running the client application, a
GUI is created for the user that displays the game state as well as a few buttons. The user then inputs
the server's IP and port number, the socket client is initialized and communication to the server is
established. The client sends a boolean variable to the server in order to instruct it that the client
connecting is using normal player credentials. Three threads are then created upon establishing the
connection with the server: one for sending inputs to the server, one for receiving the game state from
the server and one to display the current game state on the screen.
Marks & Haberkamp
Page 14 of 39
Create GUI Input server IP and port
Send client type (player)
Button press:
player on/reset
Create thread to send inputs
Create thread to draw game state
Create thread to receive game state
Button press:
player off
Figure 3.5: Player client program flowchart
Developer Client Program Description
In a developer client, which is flowcharted in Figure 3.6, the application handles communication
with the server. When the developer program is run, the GUI is initialized with an interface that contains
server information inputs and a multiple-file selector. As with the player client, the user inputs the
server's IP and port number and communication with the server is started. The client sends a boolean
variable to the server to instruct the server that it is a developer. Next, the user selects game files to
upload to the HYDRA and then it uploads those files upon a button press. Finally, the client will wait for
a confirmation from the server and display a message to the screen to notify the user.
Create GUI Input server IP and port
Send client type (player)
Initialize socket client
Select game files to upload
Wait for confirmation
Upload selected files
Figure 3.6: Developer client program flowchart
Marks & Haberkamp
Page 15 of 39
HYDRA Game Description
The game expands slightly on the game produced in the Embedded Systems project. There are
several distinct differences. First, the number of sprites on the screen has gone from two to as many as
4 to 8. The maximum number of players is determined by hardware limits that have yet to be
determined. The actual number of sprites on the screen also varies depending on the number of players
currently connected to the game. Second, the player sprites have changed from ghosts to varying
shapes, numbers or letters. This is required to differentiate between multiple players on the screen.
Finally, the HYDRA uses all new send and receive algorithms, created in this project, to transmit multiple
bytes of data in packets of information.
Player Information and Inputs Packet
Four-byte packets are used, as shown in Figure 3.7, to effectively communicate player
information and inputs between the server application and HYDRA console. Each packet begins with a
start byte of all zeros. The second byte is used to output the current player count and the appropriate
player number to the HYDRA. This byte is split into two four-bit components, the most-significant four
bits are used for the player count and the least-significant four bits are used to distinguish between
players. The next byte is used to communicate the player's inputs to the HYDRA. It is split into eight
individual bits, each acting as a flag that are 0 unless it is set to 1 to show that an instruction has been
inputted for that action. The meanings of the bits are as follows: Player On/Reset, Player Off, UNUSED,
Fire, Left, Right, Up, Down. Lastly, the ending byte will be a series of eight bits, all set to 1.
0000 0000 Start
XXXX XXXX Player Count and Number
XXXX XXXX Player Input
1111 1111 End
Figure 3.7: Player information packet
Algorithm to Read Player Information Packet
An algorithm was needed to handle the HYDRA’s reception of the packets from the server
application. It is written to handle a packet that is made of four bytes, as described above, that are
padded with a starting and an ending byte. The algorithm, which is in Figure 3.8, loops through
continually until a starting byte is encountered (or if the start flag has been set to 1). Upon receiving a
Marks & Haberkamp
Page 16 of 39
starting byte, the next byte is checked to make sure it is not a starting or ending byte, and is saved as a
valid entry into a variable for player count and number.
If the second byte received is instead an ending byte, the program loops back to the beginning
and waits for another starting byte (the current packet will be lost). If the second byte were to be a
starting byte, the flag is set to let the first block of code know that a starting byte has been encountered
already and the program loops back to the beginning. The first statement is bypassed and reception of
the next packet is continued.
If the second byte was valid, the algorithm then checks the third byte. If it is valid, the program
saves the byte into a variable for player inputs. Otherwise, it follows the same logic of looping back and
setting the flag if the third byte received was a starting byte.
If the third byte is valid, the algorithm then checks to ensure that the fourth byte received is an
ending byte. If it is a valid ending byte, the algorithm changes the player state to appropriately match
the instructions found in the second (player count and number) and third (player inputs) bytes.
Otherwise, it loops back, setting the start flag if it was a start byte that was encountered, and waits for
another starting byte.
1. bool start=0; int rec;
2. while(true){
3. /*** START BYTE ***/
4. rec=serial.get;
5. if(rec!=0 || !start) continue;
6. start=0;
7. int player, input;
8. /*** PLAYER BYTE ***/
9. rec=serial.get;
10. if(rec==0 || rec==255){
11. if(rec==0) start=1;
12. continue;
13. }else player=rec;
14. /*** INPUT BYTE ***/
15. rec=serial.get;
16. if(rec==0 || rec==255){
17. if(rec==0) start=1;
18. continue;
19. }else input=rec;
20. /*** END BYTE ***/
21. rec=serial.get;
Marks & Haberkamp
Page 17 of 39
22. if(rec!=255){
23. if(rec==0) start=1;
24. continue;
25. }
26. /*** CHANGE PLAYER STATE ***/
27. }
Figure 3.8: Packet reading algorithm for player information
Marks & Haberkamp
Page 18 of 39
Section 4: Implementation
Implementing the HYDRA Game
In order to make the HYDRA game expandable with this setup of multiple client players over a
network, the source code was split into two files. The first file is game.spin, which holds the game
functionality and sprite information. The second file is usb_comm.spin and provides functions for
handling communication over the USB connection with the server.
The game file has three primary components:
1. start function begins the game and starts cogs to operate sending and receiving through
the USB connection
2. update function is needed by the USB communication file to update players on the
screen when inputs are received
3. sprite bitmaps, which are 16x16 pixels and made up of 16 words (32 bytes), are for
player icons
The USB communication source contains four functions:
1. start is used to open the USB connection
2. getInput receives player input and runs the update function from the game file
3. sendState sends the game state to the server so player clients can update the screen
4. sendSprites sends all of the sprite bitmaps to the server so that when a player connects
to the game, the client can download the sprite information
This design allows future developers a greater ability to adjust the game without adjusting the
server and player client computer programs. To change the game, a developer only has to adjust the
three components listed above for the game file. For example, if the developer wants the fire button to
slow down the player movement instead of speed it up, they simply have to adjust the numbers in the
game’s update function.
To avoid problems of sending too much data over and over again with the repeated
transmission of the game screen to the player clients, we elected to send the sprites on startup and only
send player coordinates for the frequent game state updates. This dramatically reduces that amount of
data transferred over the USB and network connections. The downside to this implementation is that
developers will only be able to write games that have players move around on a black screen. The
Marks & Haberkamp
Page 19 of 39
implementation also only permits monochrome. The game does not utilize color because it would
dramatically increase the amount of data to be sent. Instead of one bit indicating black or white for each
pixel, two bits are needed for each pixel to represent four colors or four bits for 16 colors.
Unfortunately, at their current state, the game.spin and usb_comm.spin files will not compile
due to an issue of circular referencing. Most likely we will have to combine these files into one, while
still attempting to maintain the desired level of ease for future developers.
Implementing the Server and Clients
Development of the server and client software has been done using the C# programming
language. This allows for an easier adaptation of the logic from the Embedded Systems project versions
of our software, which was written using Visual Basic .NET. Many of the classes and functions in VB.NET
also exist in C# because they are both based upon Microsoft’s .NET Framework.
The server software, shown in Figure 4.1 with two clients connected, creates a server socket
connection and listens for incoming connection requests at a user-designated port (the default is
12345). When a connection request is received, a new thread is created so that it can service the
incoming player client connection. When a maximum of eight player client connection requests have
been granted, the server will no longer respond to incoming requests or create additional player client
threads. While more clients could be connected, the HYDRA game only supports up to eight players at a
time for simplicity in programming and communications.
Figure 4.1: Server with two clients connected
The client software, pictured in Figure 4.2, creates an intuitive, uncluttered form that any user
should be able to use without an issue. A player is required to enter the IP address and port of the
server (the defaults are localhost and 12345). The player then presses the “Connect” button to submit a
Marks & Haberkamp
Page 20 of 39
connection request to the server. When a connection request has been acknowledged by the server, a
client socket connection is opened to establish the communication. Additionally, when a player presses
the “Connect” button, the “Disconnect” button becomes enabled so that they may submit a
disconnection request at any point after communication has been established with the server.
Figure 4.2: Player client window shown connected to the server
During development, the “Disconnect” button did not work as expected. When a disconnection
request was issued by a player, the client socket connection was closed on the client side only. The
request was not properly communicated to the server and, as a result, the server did not acknowledge
the client's request to close the socket connection. This created a problem since the connection
remained open after a player client had disconnected from the server and prevented additional clients
from connecting to the server, assuming the eight-player limit has already been reached. The server
would not service additional incoming requests even if all eight of the player clients have left the game
so the server would have to be restarted to restore functionality to the software.
This was resolved simply by adding a test case to the while loop on the server side. The server
now checks the byte from the client to see if it is greater than or equal to zero. While the client is
connected, this byte will never be negative. However, once the stream ends, the server’s read function
will automatically return an integer value of -1.
Another issue that we were able to resolve was that Microsoft’s Windows Vista naturally uses
the new IPv6 standard for IP addresses and Microsoft’s Windows XP only supports the IPv4 standard.
Marks & Haberkamp
Page 21 of 39
This created some confusion with the server when it displayed the IP address for clients to connect to
the server. Since Vista still supports IPv4 we were able to find a way to display the old version of the IP
address. By adapting code found from 4GuysFromRolla.com [5], we were able to write a function to
always return the IPv4 address regardless of whether the server was running on Windows Vista or
Windows XP.
The developer client, displayed in Figure 4.3, connects to the same server software that is used
for the HYDRA game operation. Before uploading the game file to the server, the developer has to first
compile the source code files into an .eeprom file using Parallax’s Propeller Tool. This file is selected
using the developer client and uploaded to the server. The server downloads the file and runs the
necessary methods in the Propellent DLL file to upload the compiled game file to the HYDRA. In order
for the game to take effect, the HYDRA is then restarted. This process is shown on the server in Figure
4.4 using the game created during the Embedded Systems project.
Figure 4.3: Developer client window shown connected to the server
Currently, there is a minor issue with the developer not staying connected to the server after an
upload occurs. The developer has to click the “Disconnect” button and reconnect if they wish to upload
another game file. This may be a desired effect since the developer should disconnect to permit players
to attempt to play the uploaded game. The functionality is still undetermined and is expected to be
working in a successful and efficient manner by the final project demo.
Marks & Haberkamp
Page 22 of 39
Figure 4.4: Server after a developer uploaded a game file
Marks & Haberkamp
Page 23 of 39
References
[1] “HYDRA Game Development Kit.” XGameStation: Video Game System Development
[2] LaMothe, André.
. 2008. Nurve
Networks, LLC. 19 Feb 2008. <http://www.xgamestation.com/view_product.php?id=33>.
Game Programming for the Propeller Powered HYDRA
[3] Marks, S., Haberkamp, R. “Programming an Internet Interface for the HYDRA Game Development
Kit.” CEN 3213 – Embedded Systems Programming, FGCU. 28 April 2008.
. 2006. Nurve Networks, LLC.
[4] “Propellent Library.” Propellent (Library and Executable)
[5] Rae, Mark. “Returning an IPv4 Address in an IPv6-Enabled Environment.”
. 2008. Parallax, Inc. 8 Oct 2008.
<http://www.parallax.com/tabid/442/Default.aspx>.
4GuysFromRolla.com
[6] “XGameStation Pico Edition Kit 2.0.”
.
2007. Jupitermedia Corporation. 20 Nov 2008.
<http://aspnet.4guysfromrolla.com/articles/071807-1.aspx>
XGameStation: Video Game System Development. 2008. Nurve
Networks, LLC. 13 Oct 2008. <http://www.xgamestation.com/view_product.php?id=34>.
Marks & Haberkamp
Page 24 of 39
Appendix A: Server Source Code (C#)
1. using System; 2. using System.Net; 3. using System.Net.Sockets; 4. using System.Runtime.CompilerServices; 5. using System.Runtime.InteropServices; 6. using System.IO; 7. using System.IO.Ports; 8. using System.Threading; 9. using System.Reflection; 10. 11. namespace HydraServer { 12. class HydraServer { 13. const int MAX_PLAYERS=8; 14. const int MAX_DEVS=1; 15. 16. //bool exitFlag=false; 17. int numPlayers=0; 18. int numDevs=0; 19. 20. TcpListener server; 21. SerialPort hydra; 22. 23. #region Propellent.dll prototypes 24. [DllImport("Propellent.dll")] 25. static extern unsafe void InitPropellent(uint WinHandle, bool StorePrefs,
char[] RegPath); 26. 27. [DllImport("Propellent.dll")] 28. static extern unsafe uint GetPropellerVersion(); 29. 30. [DllImport("Propellent.dll")] 31. static extern unsafe void SetLibraryPath(char[] Value); 32. 33. [DllImport("Propellent.dll")] 34. static extern unsafe void SetSerialSearchMethod(uint Value); 35. 36. [DllImport("Propellent.dll")] 37. static extern unsafe void SetResetSignal(byte Value); 38. 39. [DllImport("Propellent.dll")] 40. static extern unsafe void* CompileSource(char[] Filename, bool ShowError); 41. 42. [DllImport("Propellent.dll")] 43. static extern unsafe void DownloadToPropeller(char[] Filename, byte
DownloadCmd); 44. 45. [DllImport("Propellent.dll")] 46. static extern unsafe void FinalizePropellent(); 47. #endregion 48. 49. HydraServer() { 50. // welcome message 51. Console.WriteLine("Welcome to the HYRDA server."); 52. 53. // connect to the HYDRA 54. //connectToHydra(); 55. 56. // get and display server IP address
Marks & Haberkamp
Page 25 of 39
57. //string ip=Dns.GetHostEntry(Dns.GetHostName()).AddressList[0].ToString();
58. Console.WriteLine("Server IP address is "+getIP4Address()); 59. 60. // get port number from user, if user enters nothing, default it 12345 61. Console.Write("Choose port (default=12345): "); 62. int port; 63. if(!int.TryParse(Console.ReadLine(), out port)) { 64. port=12345; 65. } 66. Console.WriteLine("Server port is "+port); 67. 68. // start the server 69. server=new TcpListener(port); 70. server.Start(); 71. Console.WriteLine("Server is running..."); 72. 73. // start the command line 74. ThreadPool.QueueUserWorkItem(new WaitCallback(console)); 75. 76. while(true) { 77. if(server.Pending()==true&&numPlayers<MAX_PLAYERS) { 78. // accept a client 79. TcpClient client=server.AcceptTcpClient(); 80. 81. // check to see if the client is a player or developer 82. // and start appropriate thread 83. int isPlayer=client.GetStream().ReadByte(); 84. if(isPlayer==1 && numPlayers<MAX_PLAYERS) { 85. ThreadPool.QueueUserWorkItem(new WaitCallback(playerComm),
(object)client); 86. } else if(isPlayer==0 && numDevs<MAX_DEVS) { 87. ThreadPool.QueueUserWorkItem(new WaitCallback(devComm),
(object)client); 88. } 89. } 90. } 91. } 92. 93. // checks for commands from the server console 94. void console(object s) { 95. while(true) { 96. string str=Console.ReadLine(); 97. if(str.CompareTo("exit")==0) { 98. // shuts down the server program 99. Environment.Exit(0); 100. } else if(str.Substring(0, 7).CompareTo("upload ")==0) { 101. // allows HYDRA file upload directly from the server 102. 103. // serial connection needs to be closed before the 104. // Propellent DLL can have access 105. hydra.Close(); 106. 107. // run Propellent for file name after "upload" command 108. propellent(str.Substring(7)); 109. 110. // restart serial connection 111. hydra.Open(); 112. } 113. } 114. } 115. 116. // handles communication with player clients
Marks & Haberkamp
Page 26 of 39
117. void playerComm(object c) { 118. numPlayers++; // increment the number of connected players 119. 120. // get TcpClient object from parameter 121. TcpClient client=(TcpClient)c; 122. Console.WriteLine("Client connected ("+numPlayers+")."); 123. 124. // get stream from player client 125. Stream stm=client.GetStream(); 126. 127. // read player inputs from client 128. int b; 129. while((b=stm.ReadByte())>=0) { 130. switch(b) { 131. case 1: 132. Console.WriteLine("right"); 133. break; 134. case 2: 135. Console.WriteLine("left"); 136. break; 137. case 4: 138. Console.WriteLine("down"); 139. break; 140. case 8: 141. Console.WriteLine("up"); 142. break; 143. case 16: 144. Console.WriteLine("fire"); 145. break; 146. default: 147. break; 148. } 149. } 150. 151. // close the connection with the player client 152. client.Client.Close(); 153. client.Close(); 154. Console.WriteLine("Client disconnected."); 155. numPlayers--; // decrement the number of connected players 156. } 157. 158. // handles communication with developer clients 159. void devComm(object c) { 160. // get TcpClient object from parameter 161. TcpClient client=(TcpClient)c; 162. Console.WriteLine("Developer connected."); 163. 164. // get streams from developer client 165. Stream stm=client.GetStream(); 166. StreamReader sr=new StreamReader(stm); 167. 168. while(((int)sr.Peek())>=0) { 169. // get file name and size from client 170. string filename=sr.ReadLine(); 171. string filepath= 172.
Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase).Substring(6)+
173. "\\hydra_files\\"; 174. int filebytes=Convert.ToInt32(sr.ReadLine()); 175. Console.WriteLine("Downloading game file ["+filename+"]
("+filebytes+" bytes)..."); 176.
Marks & Haberkamp
Page 27 of 39
177. // create stream to write file 178. FileStream fstm=new FileStream(filepath+filename,
FileMode.OpenOrCreate); 179. 180. // read all of the file's bytes from client 181. int b; 182. for(int i=0; i<filebytes; i++) { 183. b=stm.ReadByte(); 184. fstm.WriteByte((byte)b); 185. } 186. 187. fstm.Close(); // close the file stream 188. 189. // verify that the file was saved completely 190. FileInfo fi=new FileInfo(filepath+filename); 191. if(filebytes==fi.Length) { 192. Console.WriteLine("Downloaded game file ["+filename+"]."); 193. 194. // serial connection needs to be closed before the 195. // Propellent DLL can have access 196. hydra.Close(); 197. 198. // run Propellent for downloaded file 199. propellent(filename); 200. 201. // restart serial connection 202. hydra.Open(); 203. } else { 204. Console.WriteLine("Game file download failed."); 205. } 206. } 207. 208. // close the connection with the developer client 209. client.Client.Close(); 210. client.Close(); 211. Console.WriteLine("Developer disconnected."); 212. } 213. 214. // returns the IPv4 address of the server 215. string getIP4Address() { 216. // Adapted from: http://aspnet.4guysfromrolla.com/articles/071807-
1.aspx 217. 218. string IP4Address=String.Empty; 219. 220. foreach(IPAddress ip in Dns.GetHostAddresses(Dns.GetHostName())) { 221. if(ip.AddressFamily.ToString()=="InterNetwork") { 222. IP4Address=ip.ToString(); 223. break; 224. } 225. } 226. 227. if(IP4Address!=String.Empty) { 228. return IP4Address; 229. } 230. 231. foreach(IPAddress IPA in Dns.GetHostAddresses(Dns.GetHostName())) { 232. if(IPA.AddressFamily.ToString()=="InterNetwork") { 233. IP4Address=IPA.ToString(); 234. break; 235. } 236. } 237.
Marks & Haberkamp
Page 28 of 39
238. return IP4Address; 239. } 240. 241. #region HYDRA methods 242. // connects to the HYDRA via serial-over-USB 243. unsafe void connectToHydra() { 244. Console.WriteLine("Verify that the HYDRA is on."); 245. 246. while(true) { 247. // auto scan for port number 248. InitPropellent(0, false, null); 249. uint ver=GetPropellerVersion(); 250. FinalizePropellent(); 251. uint port=ver>>16; // port number is in bits 31-16 252. 253. // create serial port 254. hydra=new SerialPort("COM"+port, 9600, Parity.None, 8,
StopBits.One); 255. 256. // open serial port 257. try { 258. hydra.Open(); 259. break; 260. } catch(Exception) { 261. while(true) { 262. // check if user wants to try again 263. Console.Write("There was an error opening the serial port.
Try again? [Y/N]: "); 264. string s=Console.ReadLine().ToLower(); 265. if(s.CompareTo("y")==0) { 266. break; 267. } else if(s.CompareTo("n")==0) { 268. Console.WriteLine("Cannot connect to HYDRA. Closing
server."); 269. Environment.Exit(0); 270. } 271. } 272. 273. 274. } 275. } 276. 277. Console.WriteLine("The server is connected to the HYDRA."); 278. } 279. 280. // sends player inputs to HYDRA 281. [MethodImpl(MethodImplOptions.Synchronized)] 282. void sendToHydra(byte[] data) { 283. // send start byte 284. // send player data 285. // send input 286. // send end byte 287. } 288. 289. // uploads game files to the HYDRA and restarts it 290. [MethodImpl(MethodImplOptions.Synchronized)] 291. unsafe static void propellent(string filename) { 292. InitPropellent(0, false, null); // initializes Propellent 293. 294. // create proper file path 295. string filepath=
Marks & Haberkamp
Page 29 of 39
296. Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase).Substring(6)+
297. "\\hydra_files\\"; 298. string file=filepath+filename; 299. 300. SetSerialSearchMethod(0); // specifies auto search for serial port 301. SetResetSignal(0); // specifies DTR for reset signal 302. 303. // upload the game file 304. Console.WriteLine("Uploading file located at:"); 305. Console.WriteLine(file); 306. char[] cfile=file.ToCharArray(); 307. DownloadToPropeller(cfile, 3); 308. 309. FinalizePropellent(); // finalizes the Propellent 310. Console.WriteLine("Game file successfully uploaded to HYRDA."); 311. } 312. #endregion 313. 314. static void Main(string[] args) { 315. HydraServer hs=new HydraServer(); 316. } 317. } 318. }
Marks & Haberkamp
Page 30 of 39
Appendix B: Player Client Source Code (C#)
1. using System; 2. using System.Collections.Generic; 3. using System.ComponentModel; 4. using System.Data; 5. using System.Drawing; 6. using System.Text; 7. using System.Windows.Forms; 8. using System.Net; 9. using System.Net.Sockets; 10. 11. namespace HydraPlayer { 12. public partial class FormPlayer : Form { 13. // player input byte codes 14. const byte PI_ON=128; // player on/reset 15. const byte PI_OFF=64; // player off 16. // skips bit 6 17. const byte PI_FIRE=16; // fire 18. const byte PI_UP=8; // up 19. const byte PI_DOWN=4; // down 20. const byte PI_LEFT=2; // left 21. const byte PI_RIGHT=1; // right 22. 23. TcpClient server; 24. 25. public FormPlayer() { 26. InitializeComponent(); 27. } 28. 29. // handler for Connect button 30. void btnConnect_Click(object sender, EventArgs e) { 31. string ip=txtServerIP.Text; 32. int port=Convert.ToInt32(txtServerPort.Text); 33. 34. // connect to server 35. try { 36. server=new TcpClient(ip, port); 37. } catch(SocketException) { 38. MessageBox.Show("Failed to connect to the server."); 39. return; 40. }; 41. 42. // tell the server that this is a player client 43. server.GetStream().WriteByte(1); 44. 45. // start the keyboard event handler 46. this.btnDisconnect.KeyDown+=new KeyEventHandler(btnDisconnect_KeyDown); 47. 48. // switch to the Disconnect button 49. btnConnect.Enabled=false; 50. btnDisconnect.Enabled=true; 51. 52. // disable server IP and port textboxes 53. txtServerIP.Enabled=false; 54. txtServerPort.Enabled=false; 55. } 56. 57. // handler for Disconnect button 58. void btnDisconnect_Click(object sender, EventArgs e) {
Marks & Haberkamp
Page 31 of 39
59. // close the socket connection with the server 60. server.Client.Close(); 61. server.Close(); 62. 63. // stop the keyboard event handler 64. this.btnDisconnect.KeyDown-=new KeyEventHandler(btnDisconnect_KeyDown); 65. 66. // switch to the Connect button 67. btnConnect.Enabled=true; 68. btnDisconnect.Enabled=false; 69. 70. // enable server IP and port textboxes 71. txtServerIP.Enabled=true; 72. txtServerPort.Enabled=true; 73. } 74. 75. // handler for keyboard input 76. void btnDisconnect_KeyDown(object sender, KeyEventArgs e) { 77. byte input=0; 78. switch(e.KeyCode) { 79. case Keys.A: 80. input=PI_LEFT; 81. break; 82. case Keys.D: 83. input=PI_RIGHT; 84. break; 85. case Keys.W: 86. input=PI_UP; 87. break; 88. case Keys.S: 89. input=PI_DOWN; 90. break; 91. case Keys.E: 92. input=PI_FIRE; 93. break; 94. default: 95. break; 96. } 97. 98. sendInput(input); 99. } 100. 101. // sends player inputs to server 102. void sendInput(byte input) { 103. server.GetStream().WriteByte(input); 104. } 105. } 106. }
Marks & Haberkamp
Page 32 of 39
Appendix C: Developer Client Source Code (C#)
1. using System; 2. using System.Collections.Generic; 3. using System.ComponentModel; 4. using System.Data; 5. using System.Drawing; 6. using System.Text; 7. using System.Windows.Forms; 8. using System.Net; 9. using System.Net.Sockets; 10. using System.IO; 11. 12. namespace HydraDev { 13. public partial class FormDev : Form { 14. TcpClient server; 15. 16. public FormDev() { 17. InitializeComponent(); 18. } 19. 20. private void btnConnect_Click(object sender, EventArgs e) { 21. string ip=txtServerIP.Text; 22. int port=Convert.ToInt32(txtServerPort.Text); 23. 24. // connect to server 25. try { 26. server=new TcpClient(ip, port); 27. } catch(SocketException) { 28. MessageBox.Show("Failed to connect to the server."); 29. return; 30. }; 31. 32. // tell the server that this is a player client 33. server.GetStream().WriteByte(0); 34. 35. // switch to the Disconnect button 36. btnConnect.Enabled=false; 37. btnDisconnect.Enabled=true; 38. btnUploadFile.Enabled=true; 39. 40. // disable server IP and port textboxes 41. txtServerIP.Enabled=false; 42. txtServerPort.Enabled=false; 43. } 44. 45. private void btnDisconnect_Click(object sender, EventArgs e) { 46. // close the socket connection with the server 47. server.Client.Close(); 48. server.Close(); 49. 50. // switch to the Connect button 51. btnConnect.Enabled=true; 52. btnDisconnect.Enabled=false; 53. btnUploadFile.Enabled=false; 54. 55. // enable server IP and port textboxes 56. txtServerIP.Enabled=true; 57. txtServerPort.Enabled=true; 58. }
Marks & Haberkamp
Page 33 of 39
59. 60. private void btnFileOpen_Click(object sender, EventArgs e) { 61. // open the select file dialog box 62. openFileDialog.FileName=txtGameFile.Text; 63. openFileDialog.InitialDirectory=txtGameFile.Text; 64. openFileDialog.ShowDialog(); 65. } 66. 67. private void openFileDialog_FileOk(object sender, CancelEventArgs e) { 68. // update the game file text box with the file selected in the dialog box 69. txtGameFile.Text=openFileDialog.FileName; 70. } 71. 72. private void btnUploadFile_Click(object sender, EventArgs e) { 73. StreamWriter sw=new StreamWriter(server.GetStream()); 74. 75. // get file info 76. string filename=txtGameFile.Text; 77. FileInfo fileinfo=new FileInfo(filename); 78. 79. if(fileinfo.Exists) { 80. // send file name 81. sw.WriteLine(fileinfo.Name); 82. sw.Flush(); 83. 84. // send file size 85. sw.WriteLine(fileinfo.Length); 86. sw.Flush(); 87. 88. // send file 89. server.Client.SendFile(filename); 90. } 91. } 92. } 93. }
Marks & Haberkamp
Page 34 of 39
Appendix D: HYDRA Game Source Code (Spin)
Source Code for game.spin
1. ' ///////////////////////////////////////////////////////////////////////////// 2. ' Zoidberg Tag 2.0 3. ' ///////////////////////////////////////////////////////////////////////////// 4. 5. CON 6. 7. _clkmode = xtal2 + pll8x ' enable external clock range 5-10MHz and pll
times 8 8. _xinfreq = 10_000_000 + 0000 ' set frequency to 10 MHZ plus some error due to
XTAL (1000-5000 usually works) 9. _stack = 128 ' accomodate display memory and stack 10. 11. ' Screen sizes and centers 12. SCR_X_MAX = 192 13. SCR_Y_MAX = 160 14. SCR_X_CEN = 96 15. SCR_Y_CEN = 80 16. 17. ' player input bit codes 18. PI_ON = %1000_0000 ' player on/reset 19. PI_OFF = %0100_0000 ' player off 20. PI_FIRE = %0001_0000 ' fire 21. PI_UP = %0000_1000 ' up 22. PI_DOWN = %0000_0100 ' down 23. PI_LEFT = %0000_0010 ' left 24. PI_RIGHT = %0000_0001 ' right 25. 26. ' Max number of players allowed 27. ' Cannot exceed 8 players 28. P_MAX = 4 29. 30. VAR 31. ' Number of active players 32. byte p_num_active 33. byte p_active 34. 35. ' Player positions 36. byte px[P_MAX] 37. byte py[P_MAX] 38. 39. ' Player fire button (turbo) 40. byte pf[P_MAX] 41. 42. ' Stack for reading players' positions 43. long read_stack[100] 44. 45. ' Stack for sending game state 46. long send_stack[100] 47. 48. ' Pointers to player sprites 49. long sprites[P_MAX] 50. 51. OBJ 52. 53. usb : "usb_comm.spin" ' USB driver 54.
Marks & Haberkamp
Page 35 of 39
55. PUB Start | temp 56. 57. ' start the usb connection 58. usb.startComm 59. 60. ' initialize players to all inactive 61. p_num_active:=0 62. p_active:=0 63. 64. ' set player info 65. repeat i from 0 to P_MAX 66. ' set all player positions to center of screen 67. px[i]:=SCR_X_CEN 68. py[i]:=SCR_Y_CEN 69. 70. ' set turbo to off 71. pf[i]:=0 72. 73. ' set a sprite to each player 74. sprites[0]:=@sprite_bitmap_0 75. sprites[1]:=@sprite_bitmap_1 76. sprites[2]:=@sprite_bitmap_2 77. sprites[3]:=@sprite_bitmap_3 78. 79. usb.sendSprites(P_MAX, @sprites) 80. 81. ' start a new cog to read all player inputs 82. cognew(usb.getInput, @read_stack) 83. 84. ' start a new cog to send game state to players 85. cognew(usb.sendState, @send_stack) 86. 87. 88. PUB update(player, input) 89. 90. ' player count & player number 91. ' XXXX 0000 (player count with max players = 14) 92. ' 0000 XXXX (player number) 93. p_num_active:=player>>4 94. p:=(player & %0000_1111) 95. 96. if input==PI_ON 97. if !isActive(p) 98. p_num_active+=1 99. setActive(p, 1) 100. px[p]:=SCR_X_CEN 101. py[p]:=SCR_Y_CEN 102. pf[p]:=0 103. else if input==PI_OFF 104. if isActive(p) 105. p_num_active-=1 106. setActive(p, 0) 107. else if input==PI_FIRE 108. pf[p]:=!pf[p] 109. else if input==PI_UP 110. py[p]+=2+pf[p] 111. else if input==PI_DOWN 112. py[p]-=2+pf[p] 113. else if input==PI_LEFT 114. px[p]-=2+pf[p] 115. else if input==PI_RIGHT 116. px[p]+=2+pf[p] 117.
Marks & Haberkamp
Page 36 of 39
118. PUB isActive(player) : temp 119. temp:=(1 << player) & p_active 120. temp:=temp >> player 121. 122. PUB setActive(player, val) 123. p_active:=p_active & (val << player) 124. 125. DAT 126. 127. ' each bitmap is 16x16 pixels, 1 word x 16 words 128. ' each bitmap is displayed in monochrome 129. 130. sprite_bitmap_0 word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 131. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 132. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 133. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 134. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 135. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 136. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 137. word %0_0_0_0_0_0_0_1_1_0_0_0_0_0_0_0 138. word %0_0_0_0_0_0_0_1_1_0_0_0_0_0_0_0 139. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 140. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 141. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 142. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 143. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 144. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 145. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 146. 147. sprite_bitmap_1 word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 148. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 149. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 150. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 151. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 152. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 153. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 154. word %0_0_0_0_1_1_0_0_0_0_1_1_0_0_0_0 155. word %0_0_0_0_1_1_0_0_0_0_1_1_0_0_0_0 156. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 157. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 158. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 159. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 160. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 161. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 162. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 163. 164. sprite_bitmap_2 word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 165. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 166. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 167. word %0_0_0_0_0_0_0_1_1_0_0_0_0_0_0_0 168. word %0_0_0_0_0_0_0_1_1_0_0_0_0_0_0_0 169. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 170. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 171. word %0_0_0_0_1_1_0_0_0_0_1_1_0_0_0_0 172. word %0_0_0_0_1_1_0_0_0_0_1_1_0_0_0_0 173. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 174. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 175. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 176. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 177. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 178. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 179. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 180.
Marks & Haberkamp
Page 37 of 39
181. sprite_bitmap_3 word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 182. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 183. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 184. word %0_0_0_0_0_0_0_1_1_0_0_0_0_0_0_0 185. word %0_0_0_0_0_0_0_1_1_0_0_0_0_0_0_0 186. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 187. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 188. word %0_0_0_0_1_1_0_0_0_0_1_1_0_0_0_0 189. word %0_0_0_0_1_1_0_0_0_0_1_1_0_0_0_0 190. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 191. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 192. word %0_0_0_0_0_0_0_1_1_0_0_0_0_0_0_0 193. word %0_0_0_0_0_0_0_1_1_0_0_0_0_0_0_0 194. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 195. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 196. word %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0
Source Code for usb_comm.spin
1. ' USB driver for communication to a server 2. 3. CON 4. MAX_BYTE = 255 5. 6. OBJ 7. usb : "FullDuplexSerial.spin" ' USB driver 8. game : "game.spin" ' Game file 9. 10. PUB startComm 11. ' Start the USB connection 12. usb.start(31, 30, 0, 9600) ' receive pin, transmit pin, mode, baud rate 13. 14. PUB getInput | start, rec, player, input, p 15. 16. start=0 17. 18. repeat 19. ' start byte 20. rec:=usb.rxtime(5) 21. if rec!=0 || !start 22. continue 23. start:=0 24. 25. ' player byte 26. rec:=usb.rxtime(5) 27. if rec==0 || rec==MAX_BYTE 28. if rec==0 29. start:=1 30. continue 31. else 32. player:=rec 33. 34. ' input byte 35. rec:=usb.rxtime(5) 36. if rec==0 || rec==MAX_BYTE 37. if rec==0 38. start:=1 39. continue 40. else 41. input:=rec 42. 43. ' end byte
Marks & Haberkamp
Page 38 of 39
44. rec:=usb.rxtime(5) 45. if rec!=MAX_BYTE 46. if rec==0 47. start:=1 48. continue 49. 50. game.update(player, input) 51. 52. PUB sendState 53. ' send x, y of each player 54. ' send info on active players 55. 56. repeat 57. repeat p from 0 to P_MAX 58. ' start byte 59. usb.tx(0) 60. 61. ' info on active players 62. usb.tx(p_active) 63. 64. ' player's x-coordinate 65. usb.tx(px[p]) 66. 67. ' player's y-coordinate 68. usb.tx(py[p]) 69. 70. ' end byte 71. usb.tx(MAX_BYTE) 72. 73. PUB sendSprites(p_max, sprites) | start, rec, byte1, byte2 74. 75. repeat i from 0 to p_max 76. repeat j from 0 to 16 77. start=0 78. 79. ' start byte 80. rec:=usb.rxtime(5) 81. if rec!=0 || !start 82. continue 83. start:=0 84. 85. ' first byte 86. rec:=usb.rxtime(5) 87. if rec==0 || rec==255 88. if rec==0 89. start:=1 90. continue 91. else 92. byte1:=rec 93. 94. ' second byte 95. rec:=usb.rxtime(5) 96. if rec==0 || rec==255 97. if rec==0 98. start:=1 99. continue 100. else 101. byte2:=rec 102. 103. ' end byte 104. rec:=usb.rxtime(5) 105. if rec!=255 106. if rec==0
Marks & Haberkamp
Page 39 of 39
107. start:=1 108. continue 109. 110. ' change player info!!!