The Mini Area Network (MAN) utilizes a token ring protocol to implement a simple chat function for a small cluster of computers (no more than four computers). Using a cost efficient MAN network costing less than a few hundred dollars allows a small group of users to chat over a secure network and not have to worry about expensive and complicated installation and network security.
Aspects of Operation
The idea is to use a single ATMEL AT90S8515 controller for each individual computer on the cluster and to connect the controllers to the computers using serial cables. The controllers themselves then connect to each other using the output and input ports on the controller boards forming the MAN. The design can be divided into six modules: Initializing the Loop, Transmitting the Token, Inputting Characters, Transmitting Characters, Receiving Characters and Displaying the Messages. Each module handles some form of communication between devices, either communication between a computer and a controller or communication between controllers.
Initializing the Loop
The module which initializes the loop is used to setup the communications link between the controllers and to prepare the loop for use. The basic scheme is to designate one of the controllers as the master by pressing the initialization button on one of the controllers. The master then sends out a initialization token on his output port, which he transmits until he receives it on his input port. The slave controllers each accept the initialization token and pass it on to the next controller on the ring.
Once the initialization token has been received by the slave controllers, they wait for the acknowledge character so they can jump into the main code loop to wait for the token or the identification number for new messages. When the master receives the acknowledge on his input port he begins to transmit the token. When the slaves receive a non acknowledge character on their input port they jump to either receive a token or a new character.
Transmitting the Token
The module which handles token passing uses the three signals to pass the token: the token signal, the no token signal and the acknowledge signal. The token itself is used to decide who has permission to send a message at any one time. The decision of who gets to speak next in this case is not arbitrary, the token is simply given to the next person clockwise from the last sender. It is important to note though that once the user is done sending text, he must pass on the token to give others the opportunity to speak.
The token is passed by the current token holder by transmitting the token to the next controller. Upon receiving the token, the controller sends out a no token signal to tell the following computers that there is no token. Controllers not transmitting the token or receiving the token automatically pass on the no token signal. This no token signal ensures the current token holder that the token receiver has definitely received the token. Once the current token holder receives the no token on his input port, he sends an acknowledge character to the controller receiving the token for a set time period to ensure the token receiver will have adequate time receive the signal. Once the set time is over, he sends the no token signal. This signal tells token receiver that he is free to send the next controller the token if he does not need it.
The module which takes in input characters from the user interface communicates between the computer and individual controller using the UART protocol through the RS-232 port. To get the user's keyboard character entries, every time a key is pressed the controller throws a UART receive interrupt and appends the new character onto the current message to be sent. In the interrupt code, each character received from the computer over the serial cable is echoed back onto the screen and at the same time is stored into the user buffer.
When the first character is received from the UART, the not done flag is set. This flag indicates that a message is in progress so the user's message must be printed out when the display is refreshed (refer to the documentation on displaying messages). Whenever this not done flag is set a null character is also appended to the end of the user's own message every time a new character is added to the user's message buffer. This null character marks the end of the incomplete message and prevents remnants of the old message from being printed when the display is refreshed. The message is concluded when the user presses the enter key, which clears the not done flag and sets the full buffer flag. The cleared not done flag tells the controller not to print the user's completed message anymore because it should be in the main message buffer by this time and the full buffer flag reminds the controller that the user buffer is full and ready for transmission next time the controller receives the token. Additionally, after the enter key is pressed the ASCII characters for a carriage return, a line feed and a terminating null are also appended to the end of the message.
The module which transmits the characters to be sent to the other controllers is similar to the initialization scheme of the sender transmitting bytes until he receives them on his input port. The transmission of characters is initiated by transmitting the sender's user identification number. An integral part of the transmission scheme is also to input the user's inputted message into the local buffer of messages. The transmit stage is started when the user receives the token from the person before him on the ring. If the full buffer flag indicates that the user's message buffer is full, the user will begin to transmit the contents of his buffer to the other users. Otherwise the user will pass the token on to the next user to allow him to send a message.
In order to setup the sequence for transmitting characters, the user downloads the locations of string buffer and the user buffer. The new buffer pointer is added to the general string buffer address to get the location of the newest message in the circularly referenced string buffer message queue. The new buffer location is where the contents of the user buffer will be stored, overwriting the oldest message in the string buffer. To save the message locally, the user identification number is saved at this new buffer pointer location in the string buffer, followed by two formatting characters. To begin sending characters, the sender transmits his identification number through the output port, where it is passed to the other users on the token ring to notify them to begin receiving and to notify them who is sending. The sender transmits the identification number until he receives it on his input port.
Once the sender receives the identification number, he then begins to transmit characters. As he transmits each character, a copy of the character is simultaneously saved locally into the new buffer pointer location. Each character is followed by an acknowledge character, which is not saved locally. The purpose of this acknowledge is to differentiate when the transmission of one character ends and the next begins. Otherwise, sending two identical characters in a row would result in only one reaching the other users. Once the null terminating character has been received by all of the users and saved locally, the screen is refreshed, and the token holder passes the token to the next user in the ring.
The module which receives the characters sent by another controller is closely meshed with the module for transmitting the characters and much of the components are similar. The receiving module differentiates between two transmissions of the same characters through the acknowledge signal sent in between each character transmission. When the controller receives one of the three other user identification numbers on his input port, he jumps into receiving mode.
The first task of receiving the characters is to allocate a place in the string buffer in which to store the incoming message by downloading the address of the string buffer and then adding the value of new buffer pointer to it to place the message into the string buffer by overwriting the oldest message. The receiving controller then places the identification number of the sending controller into this buffer along with two formatting characters. The receiver then waits for the next character, stores this character in the new buffer, and passes it to the next controller. The receiver then waits for the accompanying acknowledgment and passes it on with out storing it. Upon receiving the terminating null character of the message, the receiver refreshes his own screen updated with this new message appended and the oldest message overwritten. Once the screen is refreshed the code prepares to receive either new messages or the token.
The module which displays the messages is handled by the refresh function and the UART data register empty interrupt. The refresh function points the printer pointer to the correct characters to print the messages in the proper order and the UART interrupt transmits the data to the user's computer screen. The refresh function uses three pointers, old buffer, new buffer and print buffer to print out the current list of messages and also uses the address of the user's message buffer to print out the message the user is currently typing.
Old buffer is the pointer to the first character of the oldest message in the string buffer while new buffer is the pointer to the first character of the newest message, and print buffer is the pointer to the first character of the current message in the string buffer that is being printed. To refresh the text, the print buffer pointer is first set to old buffer so that the oldest message is printed up to its first terminating null character. Then the buffer size is added to print buffer so it corresponds to the beginning of the next message, and so forth. A modulo type function is applied to the print buffer so that the print buffer is reset to zero when it reaches the end of the string buffer. The pointer is moved until the pointer print buffer has made a full circuit around the string buffer and has printed the latest message. Once the print buffer pointer has made a full circuit, the user's buffer is added to the end if the user is currently in the middle of typing a sentence to allow the user to continue typing his message, seemingly uninterrupted.
The Mini Area Network performs quite satisfactorily in terms of functionality. The flicker from updating the display would probably be the first aspect in the project that should be changed as the flicker sometimes can be distracting when typing in mid-sentence. Additionally, on some occasions the display will sometimes not print the carriage return line feed and appends the following message to the same line, although this was not experienced often enough to be able to debug the situation. Most likely it can be attributed to an error in the UART transmission because on following refreshes the problem is corrected. Overall it was great to finally get a project which initially seemed impossible to actually work quite well.
The feature that would increase the functionality of the Mini Area Network the most would be a Graphical User Interface. It was hoped that the GUI could be added to the current design instead of the Hyper-Terminal interface. A chat specific GUI would allow for a more seamless display which did not flash quite so much during display updating, possibly storing the messages in a buffer on the computer itself. After downloading the communication application programming interface from the Sun Java site, however it was decided that a chat GUI would clearly be beyond the scope of this project.
Another feature for future versions would be an increased buffer length so message length could be much longer and more messages could be saved. Since the message buffer already maximizes the RAM on the board, a larger message buffer would require an external RAM off the board or another method of organizing the message buffer. The RAM off the board option would be complicated because the board does not have available ports. Additionally the option of having user names besides user1 and user2 could be added too.
The code can be downloaded here.
At startup After 1st refresh 9th refresh Address Offset Address Offset Address Offset newbuf 0 0 oldbuf 0 printbuf oldbuf 50 printbuf newbuf 50 50 100 oldbuf 100 printbuf 100 150 150 150 200 200 200 250 250 250 300 300 300 350 350 350 400 400 newbuf 400