Abstract

This project is aimed at creating a network-capable Moon buggy game, using our AMC embedded boards. This game will test the NetDIMM boards ability for network gaming. We plan to implement a minimum of three boards. One board will be acting, as a server while the other two will be set as the clients, which are entering to play our moon buggy game. We will also have a web interface that will display the users’ scores.

Table of Contents

Title………………….. page 1

Title………………….. page 1

Title………………….. page 1

Title………………….. page 1

Title………………….. page 1

Title………………….. page 1

Table of Figures

Title………………….. page 1

Title………………….. page 1

Title………………….. page 1

Title………………….. page 1

Title………………….. page 1

Title………………….. page 1

All above pictures were provided by AJ Armstrong.

Overview

The project’s primary purpose is to test the embedded board on its network gaming capabilities. The material used in this project are, the AMC development board and a perforated board we composed containing an LCD and buttons which will be used in our network game.

This game will be entirely written in the C language. We compiled the code for testing purposes on the on a standard Linux machine. After fixing the bugs and putting the code through its initial testing we then compiled the code to work on our development board.

In short, there will be a minimum of 2 players and 1 server. The code can support additional clients, however, the more boards used will slow down game play. The game will be displayed on the LCD screen and the buttons to navigate the moon buggy. After the game is over it will display whether you one or lost, in addition, it will display who the winner of the game is. These results are then recorded and the results of the game will be displayed on a webpage. The webpage will also contain a running total of scores for a particular player.

Background

When designing our project we worked towards testing the network gaming capability. There might not be a huge market for our project because currently game programming is very extensive and require a lot from the hardware aspect. Our goal was not to market our game, it is to show how we can network the boards implementing this technology and our features can easily be changed to design something a client may be interested in.

Constraints

While designing and implementing our design there were some constraints and limitations encountered. The interface of the board is quite limited, it consists of just three buttons and the LCD. The LCD is quite restricting since because of its size, it contains only two lines.

The storage space on the development board is limited, which means graphics we are using for the webpage is limited.

Design

The project consists of two components: a server and a client.

Server

The server has a number of functions. It manages client connections, starts and ends games, stores scores and other player statistics, and generates a web interface containing all player statistics. The server and client communicate using a simple message-based protocol running over UDP.

The server starts by opening a datagram socket, listening (by default) on port 6544. It enters a loop, waiting for JOIN commands. When a JOIN is received, the address of the client is stored, along with the player name supplied with the command. The address will later be compared to those of incoming commands, to determine which client issued them. The client is immediately issued a WLCM command, informing it that it has successfully connected to the server, and will be included in the next game. When the minimum required players have joined, the server issues a REDY command to all the clients. This command informs the clients that the game is expected to begin in the given number of microseconds. The server then continues looping, waiting for more connections, until the timer runs out.

To start the game, the server first uses the system clock to get a number for use as a random seed. This seed will be sent to the clients, and will then be used to generate the landscape the player must navigate. This guarantees that all players will face an equal challenge. The server issues a STRT command, including the random seed, to all the clients. At this point, the game begins!

The server enters a loop, waiting for SCOR or DEAD commands from the clients. If a SCOR is received, the players score will be updated. If a DEAD is received, the player will be marked dead and his or her score will be updated. If a new client attempts to join the game during play, it is issued a WLCM command, and is excluded from the current game. Periodically, the web page is written, containing up-to-date scores and statistics about the players. When the last client has issued a DEAD command, the server determines who has the highest score, and issues an OVER command to all clients, supplying the name and score of the winner.

At this point, the server returns to the JOIN loop, waiting for more players.

Client

The client is the portion the user interacts with. It has two user interfaces, one designed using curses for the Unix console, and one for the NetDIMM interface board. In either case, the available screen space is considered to be 2 lines of 16 characters each. Three keys are used for input: up for jump, left for faster, and right for slower. The landscape scrolls from left to right across the bottom line of the screen at a rate of 10 characters per second. The buggy occupies one space, on the top line when jumping, on the bottom line otherwise. Every character passed successfully is considered to be worth one point.

The user interface designed for the NetDIMM interface board uses a set of custom characters to represent the ground, craters, boulders, and the buggy itself. The console interface simply makes use of available characters.

The client requires two command-line arguments, the first is the name of the player, the second the hostname of the server to connect to. When the client is launched, it first initializes the screen, and then creates a datagram socket, and attempts to connect to the server by sending a JOIN command. The client then waits for a WLCM from the server, informing it that it has been connected to the server. When the WLCM has been received, the client displays a message informing the user that it is waiting for the game to begin.

The client waits for the REDY command. This command informs it of the number of microseconds until the game is expected to begin. Once it is received, the client begins displaying a countdown on the screen, and waits for the STRT command.

When the STRT is received, along with the game seed, the game begins. The random number generator is initialized with the seed. The landscape is generated by getting a random number, which is taken as the number of spaces of flat terrain before the next obstacle, either a crater or a boulder. When the correct number of spaces have elapsed, an obstacle is placed, and a new random number is generated.

The player avoids obstacles by a combination of jumping, slowing down, and speeding up. During play, the client sends a SCOR command to the server twice per second, along with the player's current score. When the player finally hits an obstacle, the player dies, and a DEAD command is sent. A message is displayed informing the player of his or her score.

After the player dies, the client waits for an OVER command. The OVER command carries the name and score of the winner. The score is compared to the player's own score, and if they match, a message is displayed informing the player that he or she is the winner. Otherwise, the name and score of the winner are displayed. The client waits 3 seconds while the message is displayed, and then returns to wait for the REDY command.

Protocol: (All messages are UDP datagrams)

Clients connect to server by sending a JOIN command

Server replies with WLCM command

Server starts countdown by sending REDY command

Server starts game by sending STRT command

Clients report score to server by sending SCOR command

Clients report player death by sending DEAD command

Server ends game by sending OVER command

JOIN:

JOIN <playername>\n

WLCM:

WLCM\n

Acknowledge JOIN

REDY:

REDY <starttime>\n

starttime is the estimated time in microseconds until the game will begin.

0 means the time is unknown. Clients must wait for the STRT command

before starting!

STRT:

STRT <seed>\n

seed is the random seed of the level generator. All clients will recieve

the same seed for a given game.

SCOR:

SCOR <score>\n

score is the player's current score. This command will be issued to the

server by the client once every second.

DEAD:

DEAD <score>\n

score is the player's score at the time of death.

OVER:

OVER <winnername> <score>\n

winnername is the name of the winner. score is the winner's score.

The receiving client may only assume it is the winner if the score

matches it's own, as duplicate player names are allowed.

QUIT:

QUIT

Server closing, or player leaving game.

EROR:

EROR

This command may be issued by either server or client at any time

if one party receives unexpected or otherwise erroneous data from

the other.

Results

Appendices

Appendix A: Source Code

mbgy.c	Page 12

mbgyd.c	Page 12

mbgyd.h	Page 12

toolkit.c	Page 12

toolkit.h	Page 12

ioboard.c	Page 12

ioboard.h	Page 12

stk.c	Page 12

stk.h	Page 12

mbgy.c

/*

* mbgy, a moon-buggy clone for the AMC NetDIMM

* Copyright (C) 2004 Philip Bock

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation; either version 2 of the License, or

* (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

*/

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <sys/time.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <fcntl.h>

#include <errno.h>

#include "stk.h"

#include "toolkit.h"

#ifdef USE_IOBOARD

#include "ioboard.h"

#else

#include <curses.h>

#endif

#define DISPLAY_LENGTH 16

#define FRAME_TIME 100000 /* In microseconds */

#define UPDATE_TIME 5 /* Frames between updates */

#ifndef USE_IOBOARD

#define BUGGY_GLYPH '«'

#define BUGGY_JUMP_GLYPH '«'

#define FLAT_TERRAIN_GLYPH '_'

#define CRATER_GLYPH ' '

#define BOULDER_GLYPH '.'

#else

#define BUGGY_GLYPH 4

#define BUGGY_JUMP_GLYPH 3

#define FLAT_TERRAIN_GLYPH 2

#define CRATER_GLYPH 1

#define BOULDER_GLYPH 0

#endif

/* Protocol commands */

#define UNKNOWN_CMD 0

#define JOIN_CMD 1

#define WLCM_CMD 2

#define REDY_CMD 3

#define STRT_CMD 4

#define SCOR_CMD 5

#define DEAD_CMD 6

#define OVER_CMD 7

#define QUIT_CMD 8

#define EROR_CMD 10

void cleanup(void);

int start_game(int seed);

void get_keys(unsigned int *, unsigned int *, unsigned int *);

void update(char *, unsigned int, unsigned int, unsigned int);

void draw(char *buffer);

long wait_for_start(void);

int join_server(char *name);

int get_winner(char *name, int length);

void print_won(int score);

void print_lost(char *name, int score);

unsigned long utime(void);

int get_command(char *buffer, int length, char **arg1, char **arg2);

char charset[] = {

0x00, 0x0E, 0x1F, 0x1E, 0x0E, 0x1F, 0x16, 0x0D, /* boulder */

0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x1B, 0x1F, /* crater */

0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x16, 0x0D, /* flat terrain */

0x00, 0x0C, 0x1F, 0x1F, 0x0A, 0x00, 0x00, 0x00, /* jumping buggy */

0x00, 0x0C, 0x1F, 0x1F, 0x0A, 0x1F, 0x16, 0x0D /* buggy */

};

int sckt;

int main(int argc, char **argv) {

int score, win_score, port = 6544;

int seed;

char *hostname;

char *player, winner[16];

if (argc < 3) {

printf("Usage:\n\tmbgy <playername> <hostname> [port]\n");

exit(EXIT_FAILURE);

}

player = argv[1];

hostname = argv[2];

if (argc > 3)

port = atoi(argv[3]);

atexit(cleanup);

#ifndef USE_IOBOARD

/* Send error messages somewhere useful */

freopen("mbgy_log.txt", "w", stderr);

/* Set up curses */

initscr();

nonl();

cbreak();

noecho();

keypad(stdscr, TRUE);

nodelay(stdscr, 1);

/* Flush input buffer */

while (getch() != ERR);

#else

open_ioboard();

/* Display on, cursor off, shift cursor right, no display shift on write */

set_lcd(1, 0, 1, 0);

lcd_charset(charset, 5);

#endif

sckt = stk_connect(hostname, port, SOCK_DGRAM);

if (sckt < 0) {

fprintf(stderr, "Error opening socket\n");

exit(EXIT_FAILURE);

}

if (join_server(player) == -1) {

fprintf(stderr, "Error connecting to server\n");

exit(EXIT_FAILURE);

}

for (;;) {

/* Wait for the game to start */

if ((seed = wait_for_start()) == -1) {

fprintf(stderr, "Error reading from socket (wait_for_start)\n");

exit(EXIT_FAILURE);

}

if ((score = start_game(seed)) == -1) {

fprintf(stderr, "Error reading from socket (start_game)\n");

exit(EXIT_FAILURE);

}

if ((win_score = get_winner(winner, 16)) == -1) {

fprintf(stderr, "Error reading from socket (get_winner)\n");

exit(EXIT_FAILURE);

}

if (score == win_score)

print_won(score);

else

print_lost(winner, win_score);

sleep(3);

}

cleanup();

return 0;

}

void cleanup(void) {

if (sckt >= 0)

close(sckt);

#ifndef USE_IOBOARD

/* Flush input buffer */

while (getch() != ERR);

endwin();

#else

clear_lcd();

#endif

}

int start_game(int seed) {

unsigned int buggy_pos = (DISPLAY_LENGTH / 4) * 3, buggy_jump_time = 0;

unsigned int play_time = 0, flat_length = 0, holddown = 0, dead = 0;

unsigned int update_timer = UPDATE_TIME;

char next_char, buffer[256];

unsigned long frame_start_time;

unsigned int left = 0, right = 0, up = 0;

/* Display Buffer */

char dbuf[DISPLAY_LENGTH + 1];

memset(dbuf, FLAT_TERRAIN_GLYPH, DISPLAY_LENGTH);

dbuf[DISPLAY_LENGTH] = '\0';

srand(seed); /* Set the random seed */

/* Game loop */

while (!dead) {

/* Record current time */

frame_start_time = utime();

/* Move forward by one space */

if (!flat_length) { /* Time for an obstacle! */

if (rand() > RAND_MAX / 2)

next_char = CRATER_GLYPH;

else

next_char = BOULDER_GLYPH;

flat_length = (rand() % 10) + 4;

}

else

next_char = FLAT_TERRAIN_GLYPH;

memmove(dbuf + 1, dbuf, DISPLAY_LENGTH - 1);

dbuf[0] = next_char;

/* Check for collisions */

if (!buggy_jump_time && (dbuf[buggy_pos] != FLAT_TERRAIN_GLYPH))

dead = 1; /* Player hit something! */

/* Get control key states */

get_keys(&left, &right, &up);

if (up && !buggy_jump_time && !holddown) { /* Jump! */

buggy_jump_time = 4;

up = 0;

}

if (left && (buggy_pos > 0)) {

buggy_pos--;

left = 0;

}

if (right && (buggy_pos < (DISPLAY_LENGTH - 1))) {

buggy_pos++;

right = 0;

}

/* Draw the display */

snprintf(buffer, (2 * DISPLAY_LENGTH) + 3, "%-16i\n%s\n", (play_time * FRAME_TIME / 1000000), dbuf);

buffer[buggy_pos + (buggy_jump_time?0:1 * 17)] = BUGGY_GLYPH;

draw(buffer);

if (holddown)

holddown = 0;

if (buggy_jump_time) {

buggy_jump_time--;

if (!buggy_jump_time) /* Buggy has landed, set holddown timer */

holddown = 1;

}

play_time++;

flat_length--;

/* Is it time to send our score to the server? */

if (update_timer == 0) {

update_timer = UPDATE_TIME;

snprintf(buffer, 256, "SCOR %i\n", play_time);

if (send(sckt, buffer, strlen(buffer) + 1, 0) == -1)

return -1;

}

else

update_timer--;

/* Wait until FRAME_TIME has elapsed */

ssleep(FRAME_TIME - (utime() - frame_start_time));

}

/* Tell server we're dead */

snprintf(buffer, 256, "DEAD %i\n", play_time);

if (send(sckt, buffer, strlen(buffer) + 1, 0) == -1)

return -1;

snprintf(buffer, 256, " You Died! \nYour Score: %4i", play_time);

draw(buffer);

return play_time;

}

int get_winner(char *name, int length) {

char buffer[256], *winner, *score;

if (get_command(buffer, 256, &winner, &score) != OVER_CMD) {

send(sckt, "EROR\n", 5, 0);

return -1;

}

strncpy(name, winner, length);

return atoi(score);

}

void draw(char *buffer) {

#ifdef USE_IOBOARD

print_lcd(buffer);

#else

mvprintw(0, 0, buffer);

refresh();

#endif

}

void get_keys(unsigned int *left, unsigned int *right, unsigned int *up) {

#ifdef USE_IOBOARD

get_buttons(left, up, right);

#else

int c;

while ((c = getch()) != ERR) {

switch (c) {

case KEY_LEFT: *left = 1; break;

case KEY_RIGHT: *right = 1; break;

case KEY_UP: *up = 1; break;

default: return;

}

}

#endif

}

int join_server(char *name) {

char buffer[256];

/* Send JOIN */

snprintf(buffer, 256, "JOIN %s\n", name);

if (send(sckt, buffer, strlen(buffer) + 1, 0) == -1)

return -1;

/* Get WLCM */

if (get_command(buffer, 256, NULL, NULL) != WLCM_CMD) {

send(sckt, "EROR\n", 5, 0);

return -1;

}

return 0;

}

long wait_for_start(void) {

char buffer[256], *atime, *seed;

int command = 0;

long start_time;

/* Tell the user what's going on */

snprintf(buffer, 256, " Waiting for \n game start... ");

draw(buffer);

if (get_command(buffer, 256, &atime, NULL) != REDY_CMD) {

send(sckt, "EROR\n", 5, 0);

return -1;

}

/* How long until the game is expected to start? */

start_time = atol(atime) + utime();

/* Go non-blocking */

fcntl(sckt, F_SETFL, fcntl(sckt, F_GETFL) | O_NDELAY);

/* Print a countdown timer until the game starts */

while (command == 0) {

if (start_time > utime())

snprintf(buffer, 256, " Waiting for \n players... %2li ", (start_time - utime()) / 1000000);

else

snprintf(buffer, 256, " Waiting for \n players...");

draw(buffer);

/* Check for STRT */

if ((command = get_command(buffer, 256, &seed, NULL)) == -1)

return -1;

/* Nothing recved yet */

if (command == 0) {

ssleep(10000);

continue;

}

if (command != STRT_CMD) {

send(sckt, "EROR\n", 5, 0);

return -1;

}

}

/* Return to Blocking mode */

fcntl(sckt, F_SETFL, fcntl(sckt, F_GETFL) ^ O_NDELAY);

return atol(seed);

}

void print_won(int score) {

char buffer[256];

snprintf(buffer, 256, " You Won! \nYour Score: %4i", score);

draw(buffer);

}

void print_lost(char *name, int score) {

char buffer[256];

snprintf(buffer, 256, " You Lost! \n%5s Won: %5i", name, score);

draw(buffer);

}

int get_command(char *buffer, int length, char **arg1, char **arg2) {

int data_length;

char *c, *t1 = NULL, *t2 = NULL;

data_length = recv(sckt, buffer, length - 1, 0);

if (data_length == -1) {

if (errno == EWOULDBLOCK)

return 0;

else

return -1;

}

/* Guarantee null-termination */

buffer[data_length] = '\0';

for (c = buffer; *c != '\0'; c++) {

/* If this char is a space, and next is not the end of the command */

if ((*(c + 1) != '\0') && (*c == ' ')) {

if (t1 == NULL)

t1 = c + 1;

else if (t2 == NULL)

t2 = c + 1;

else /* We've found both arguments already */

break;

*c = '\0';

}

if (*c == '\n') /* Remove \n */

*c = '\0';

}

/* Only return arguments that will be used */

if (arg1 != NULL)

*arg1 = t1;

if (arg2 != NULL)

*arg2 = t2;

if (strcmp("WLCM", buffer) == 0)

return WLCM_CMD;

else if (strcmp("REDY", buffer) == 0)

return REDY_CMD;

else if (strcmp("STRT", buffer) == 0)

return STRT_CMD;

else if (strcmp("OVER", buffer) == 0)

return OVER_CMD;

else if (strcmp("EROR", buffer) == 0)

return EROR_CMD;

else if (strcmp("QUIT", buffer) == 0)

return QUIT_CMD;

else

return UNKNOWN_CMD;

}

mbgyd.c

/*

* mbgy, a moon-buggy clone for the AMC NetDIMM

* Copyright (C) 2004 Philip Bock

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation; either version 2 of the License, or

* (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

*/

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <time.h>

#include <unistd.h>

#include <sys/time.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <fcntl.h>

#include <errno.h>

#include "stk.h"

#include "toolkit.h"

#include "mbgyd.h"

#define UNKNOWN_CMD 0

#define JOIN_CMD 1

#define WLCM_CMD 2

#define REDY_CMD 3

#define STRT_CMD 4

#define SCOR_CMD 5

#define DEAD_CMD 6

#define OVER_CMD 7

#define QUIT_CMD 8

#define EROR_CMD 10

#define MIN_PLAYERS 2 /* Default minimum players */

#define MAX_PLAYERS 4 /* Default maximum players */

#define JOIN_DELAY 15 /* Default time (s) to wait for more players after minimum players have joined */

#define PORT 6544

#define PAGE_DELAY 5 /* Interval of html generation, in secs */

#define POLL_DELAY 10000 /* Time in microseconds to delay between polling the socket */

#define DISCONNECT_TIME 1500000 /* in microseconds */

#ifdef USE_IOBOARD

#define STATUS_PAGE "/var/index.html"

#else

#define STATUS_PAGE "/home/phil/public_html/mbgy.html"

#endif

int wait_for_players(void);

int new_player(char *name, struct sockaddr_in *addr);

int play_game(void);

int find_winner(void);

int find_player(struct sockaddr_in *addr);

int get_command(char *buffer, int length, char **arg1, char **arg2, struct sockaddr_in *addr);

int sckt;

int numplayers = 0, minplayers = MIN_PLAYERS, maxplayers = MAX_PLAYERS, join_delay = JOIN_DELAY;

int numgames = 0; /* Number of completed games */

struct Player players[MAX_PLAYERS];

int main(int argc, char **argv) {

/* Read in limits from the command-line */

if (argc > 1)

minplayers = atoi(argv[1]);

if (argc > 2)

maxplayers = atoi(argv[2]);

if (argc > 3)

join_delay = atoi(argv[3]);

/* Verify that the limits are sane */

if (maxplayers > MAX_PLAYERS)

maxplayers = MAX_PLAYERS;

if (minplayers > maxplayers)

minplayers = maxplayers;

if (minplayers < 1)

minplayers = 1;

sckt = stk_listen(NULL, PORT, SOCK_DGRAM, 5); /* Any address, port 6544, UPD, backlog 5 */

if (sckt < 0) {

fprintf(stderr, "Error opening listening socket: %i", sckt);

return 1;

}

for (;;) {

/* Start a new game */

if (wait_for_players() == -1) {

fprintf(stderr, "Socket Error\n");

close(sckt);

exit(EXIT_FAILURE);

}

if (play_game() == -1) {

fprintf(stderr, "Socket Error\n");

close(sckt);

exit(EXIT_FAILURE);

}

}

return 0;

}

int wait_for_players(void) {

struct sockaddr_in addr;

int c, command, addr_len = sizeof(struct sockaddr);

unsigned long time_to_start = 0;

char buffer[256], *name;

printf("Waiting for new players (%i players already in game)...\n", numplayers);

/* Wait for new players */

while (numplayers < minplayers) {

if ((command = get_command(buffer, 256, &name, NULL, &addr)) == -1)

return -1; /* Socket error */

if (command == JOIN_CMD)

new_player(name, &addr);

else {

/* Wrong command. Issue error. */

if (sendto(sckt, "EROR\n", 5, 0, (struct sockaddr *) &addr, addr_len) == -1)

return -1;

}

}

/* Okay, time to start counting down to game start */

time_to_start = utime() + (join_delay * 1000000);

printf("Game will start in %i seconds...\n", join_delay);

/* Tell players we're REDY for a new game */

for (c = 0; c < numplayers; c++) {

snprintf(buffer, 256, "REDY %li\n", time_to_start - utime());

if (sendto(sckt, buffer, strlen(buffer) + 1, 0, (struct sockaddr *) &players[c].addr, addr_len) == -1)

return -1;

}

/* Go non-blocking */

fcntl(sckt, F_SETFL, fcntl(sckt, F_GETFL) | O_NDELAY);

/* Wait for more new players */

while ((numplayers < maxplayers) && (utime() < time_to_start)) {

if ((command = get_command(buffer, 256, &name, NULL, &addr)) == -1)

return -1; /* Socket error */

/* Did we get a command? */

if (command == 0) {

ssleep(POLL_DELAY);

continue;

}

if (command == JOIN_CMD) {

new_player(name, &addr);

/* Let the player know we're REDY */

snprintf(buffer, 256, "REDY %li\n", time_to_start - utime());

if (sendto(sckt, buffer, strlen(buffer) + 1, 0, (struct sockaddr *) &players[c].addr, addr_len) == -1)

return -1;

}

else {

/* Wrong command. Issue error. */

if (sendto(sckt, "EROR\n", 5, 0, (struct sockaddr *) &addr, addr_len) == -1)

return -1;

}

}

/* Return to blocking */

fcntl(sckt, F_SETFL, fcntl(sckt, F_GETFL) ^ O_NDELAY);

return 1;

}

int new_player(char *name, struct sockaddr_in *addr) {

int c, addr_len = sizeof(struct sockaddr);

char buffer[256];

/* Check that this player hasn't already joined the game,

and that we have room for one more player */

if ((numplayers < maxplayers) && (find_player(addr) == -1)) {

c = numplayers;

numplayers++;

/* Copy name and address of player */

strncpy(players[c].name, name, 16);

memcpy(&players[c].addr, addr, sizeof(struct sockaddr));

/* Initialize the player to zero */

players[c].dead = players[c].score = 0;

players[c].high = players[c].low = players[c].avg = 0;

players[c].gamesplayed = 0;

printf("%s (%s:%i) has joined the game\n", players[c].name, inet_ntoa(players[c].addr.sin_addr), players[c].addr.sin_port);

/* Player is in the game, send acknowledge */

snprintf(buffer, 256, "WLCM\n");

if (sendto(sckt, buffer, strlen(buffer) + 1, 0, (struct sockaddr *) &players[c].addr, addr_len) == -1)

return -1;

return 1;

}

else {

sendto(sckt, "EROR\n", 6, 0, (struct sockaddr *) &addr, addr_len);

return -1;

}

}

int play_game(void) {

struct sockaddr_in addr;

int addr_len = sizeof(struct sockaddr);

int command, winner, game_not_over = numplayers;

unsigned int c;

long seed;

unsigned long page_time = utime() + (PAGE_DELAY * 1000000), ttime;

char buffer[256], *score;

seed = time(NULL);

/* Increment gamesplayed */

for (c = 0; c < numplayers; c++)

players[c].gamesplayed++;

printf("Game starting with %i players.\n", numplayers);

/* Send all players the game seed, and set lastupdate_time */

snprintf(buffer, 256, "STRT %li\n", seed);

for (c = 0; c < numplayers; c++) {

if (sendto(sckt, buffer, strlen(buffer) + 1, 0, (struct sockaddr *) &players[c].addr, addr_len) == -1)

return -1;

players[c].lastupdate_time = utime();

players[c].score = 0;

}

htmlgen(STATUS_PAGE, players, numplayers);

/* Go non-blocking */

fcntl(sckt, F_SETFL, fcntl(sckt, F_GETFL) | O_NDELAY);

/* While the game isn't over */

while (game_not_over) {

/* Write web status page, if it's time */

if (utime() > page_time) {

htmlgen(STATUS_PAGE, players, numplayers);

page_time = utime() + (PAGE_DELAY * 1000000);

}

command = get_command(buffer, 256, &score, NULL, &addr);

if (command == -1)

return -1;

if (command == 0) { /* Nothing recved yet. */

ssleep(POLL_DELAY); /* 1/10th the default client frame_time */

continue;

}

if ((c = find_player(&addr)) == -1) {

/* Are you joining? */

if (command == JOIN_CMD) {

/* Welcome. We'll start in a little while */

new_player(score, &addr); /* Funny thing, score == name */

}

else {

/* Who are you, and what are you doing here? */

if (sendto(sckt, "EROR\n", 6, 0, (struct sockaddr *) &addr, addr_len) == -1)

return -1;

}

}

else {

switch (command) {

case SCOR_CMD:

/* Buffer overflow alert? */

players[c].score = atoi(score);

players[c].lastupdate_time = utime();

break;

case DEAD_CMD:

players[c].score = atoi(score);

players[c].dead = 1;

players[c].lastupdate_time = utime();

printf("%s died with score %i\n", players[c].name, players[c].score);

game_not_over--;

break;

default:

/* Huh? */

if (sendto(sckt, "EROR\n", 5, 0, (struct sockaddr *) &addr, addr_len) == -1)

return -1;

break;

}

}

/* Check that players are still connected */

ttime = utime();

for (c = 0; c < numplayers; c++) {

if (players[c].gamesplayed && !players[c].dead && ((ttime - players[c].lastupdate_time) > DISCONNECT_TIME)) {

printf("%s has left the game (no update for %li microseconds)\n", players[c].name, ttime - players[c].lastupdate_time);

game_not_over--;

numplayers--;

if (c < numplayers) /* If this isn't the last player */

memmove(players + c, players + c + 1, sizeof(struct Player) * (numplayers - c));

c--;

}

}

}

/* Return to blocking */

fcntl(sckt, F_SETFL, fcntl(sckt, F_GETFL) ^ O_NDELAY);

/* Figure out who won */

winner = find_winner();

printf("Game over. %s is the winner with score %i\n", players[winner].name, players[winner].score);

/* GAME OVER! Tell players who won */

snprintf(buffer, 256, "OVER %s %i\n", players[winner].name, players[winner].score);

for (c = 0; c < numplayers; c++)

if (players[c].gamesplayed)

if (sendto(sckt, buffer, strlen(buffer) + 1, 0, (struct sockaddr *) &players[c].addr, addr_len) == -1)

return -1;

/* Calculate stats and prepare for next game */

for (c = 0; c < numplayers; c++) {

if (players[c].gamesplayed) {

if (players[c].score > players[c].high)

players[c].high = players[c].score;

if ((players[c].score < players[c].low) || (players[c].low == 0))

players[c].low = players[c].score;

players[c].avg = ((players[c].gamesplayed * players[c].avg) + players[c].score) / (players[c].gamesplayed);

players[c].score = players[c].dead = 0;

}

}

/* Write web status page one more time */

htmlgen(STATUS_PAGE, players, numplayers);

return 1;

}

int find_winner(void) {

int c, winner = 0;

for (c = 0; c < numplayers; c++) {

if (players[c].gamesplayed && (players[c].score > players[winner].score))

winner = c;

}

return winner;

}

int find_player(struct sockaddr_in *addr) {

int addr_len = sizeof(struct sockaddr), c;

for (c = 0; c < numplayers; c++) {

if (memcmp(addr, &players[c].addr, addr_len) == 0)

break;

}

if (c == numplayers) /* Player not found */

return -1;

else

return c;

}

int get_command(char *buffer, int length, char **arg1, char **arg2, struct sockaddr_in *addr) {

unsigned int addr_len = sizeof(struct sockaddr);

int data_length;

char *c, *t1 = NULL, *t2 = NULL;

data_length = recvfrom(sckt, buffer, length - 1, 0, (struct sockaddr *) addr, &addr_len);

if (data_length == -1) {

if (errno == EWOULDBLOCK)

return 0;

else

return -1;

}

/* Guarantee null-termination */

buffer[data_length] = '\0';

for (c = buffer; *c != '\0'; c++) {

/* If this char is a space, and next is not the end of the command */

if ((*(c + 1) != '\0') && (*c == ' ')) {

if (t1 == NULL)

t1 = c + 1;

else if (t2 == NULL)

t2 = c + 1;

else /* We've found both arguments already */

break;

*c = '\0';

}

if (*c == '\n') /* Remove \n */

*c = '\0';

}

/* Only return arguments that will be used */

if (arg1 != NULL)

*arg1 = t1;

if (arg2 != NULL)

*arg2 = t2;

if (strcmp("JOIN", buffer) == 0)

return JOIN_CMD;

else if (strcmp("SCOR", buffer) == 0)

return SCOR_CMD;

else if (strcmp("DEAD", buffer) == 0)

return DEAD_CMD;

else if (strcmp("EROR", buffer) == 0)

return EROR_CMD;

else if (strcmp("QUIT", buffer) == 0)

return QUIT_CMD;

else

return UNKNOWN_CMD;

}

mbgyd.h

/*

* mbgy, a moon-buggy clone for the AMC NetDIMM

* Copyright (C) 2004 Philip Bock

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation; either version 2 of the License, or

* (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

*/

#ifndef __MBGYD_H__

#define __MBGYD_H__

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

struct Player {

struct sockaddr_in addr;

char name[17];

/* Current game */

int dead, score;

/* Statistics */

int high, low, avg;

int gamesplayed;

/* To check for disconnections */

long lastupdate_time;

};

int htmlgen(char *filename, struct Player *, int size);

#endif

toolkit.c

/*

* mbgy, a moon-buggy clone for the AMC NetDIMM

* Copyright (C) 2004 Philip Bock

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation; either version 2 of the License, or

* (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

*/

#include <string.h>

#include <unistd.h>

#include <sys/time.h>

void ssleep(unsigned long wait) {

#ifdef USE_IOBOARD

unsigned long done_time = wait + utime();

while (utime() < wait);

#else

usleep(wait);

#endif

}

unsigned long utime(void) {

struct timeval tv;

struct timezone tz;

gettimeofday(&tv, &tz);

return (tv.tv_sec * 1000000) + tv.tv_usec;

}

toolkit.h

/*

* mbgy, a moon-buggy clone for the AMC NetDIMM

* Copyright (C) 2004 Philip Bock

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation; either version 2 of the License, or

* (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

*/

#ifndef __TOOLKIT_H__

#define __TOOLKIT_H__

int nlotoa(char *, int, unsigned long);

void ssleep(unsigned long);

unsigned long utime(void);

#endif

ioboard.c

/*

* ioboard interface library

*

* mbgy, a moon-buggy clone for the AMC NetDIMM

* Copyright (C) 2004 Philip Bock

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation; either version 2 of the License, or

* (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

*/

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <linux/dimmio.h>

#include <fcntl.h>

#include <sys/types.h>

#include <errno.h>

#include "ioboard.h"

#include "toolkit.h"

/* dimmio data */

struct dimm_io button_io[3]; /* Button signal */

struct dimm_io portc_io[8]; /* Bargraph, LCD signal */

struct dimm_io latchc_io[2]; /* Latch control */

struct dimm_io lcdc_io[3]; /* LCD control */

int io1dev = -1;

int buttons_open = 0, bargraph_open = 0, latch_open = 0, lcd_open = 0;

/* Configures a pin by port and bit number */

void set_config_by_port_bit(struct dimm_io *pin, short port, short bit, unsigned char mode, unsigned char pull_up_dn) {

int error;

pin->port_number = port;

pin->bit_number = bit;

pin->mode = mode;

pin->pull_up_dn = pull_up_dn;

error = ioctl(io1dev, DIMM_IO_IOCTL_SET_CONFIG_BY_PORT_BIT, pin);

if (error < 0)

{

fprintf(stderr, "Unable to configure device. Error code: %i\n", errno);

close(io1dev);

exit(EXIT_FAILURE);

}

}

/* Reads a pin using offset */

void read_by_offset(struct dimm_io *pin) {

int error;

lseek(io1dev, pin->offset, SEEK_SET);

error = read(io1dev, &(pin->state), 1);

if (error < 0)

{

fprintf(stderr, "Error in reading from device. Error code: %i\n", errno);

close(io1dev);

exit(EXIT_FAILURE);

}

}

/* Writes a value to a pin using offset */

void write_by_offset(struct dimm_io *pin) {

int error;

lseek(io1dev, pin->offset, SEEK_SET);

error = write(io1dev, &(pin->state), 1);

if (error < 0) {

fprintf(stderr, "Error in writing to device\n");

close(io1dev);

exit(EXIT_FAILURE);

}

}

/* Read a series of pins */

void read_pins(struct dimm_io *pins, int num_pins) {

int c, error;

for (c = 0; c < num_pins; c++) {

lseek(io1dev, pins[c].offset, SEEK_SET);

error = read(io1dev, &(pins[c].state), 1);

if (error < 0) {

fprintf(stderr, "Error in writing to device\n");

close(io1dev);

exit(EXIT_FAILURE);

}

}

}

/* Write a series of pins */

void write_pins(struct dimm_io *pins, int num_pins) {

int c, error;

for (c = 0; c < num_pins; c++) {

lseek(io1dev, pins[c].offset, SEEK_SET);

error = write(io1dev, &(pins[c].state), 1);

if (error < 0) {

fprintf(stderr, "Error in writing to device\n");

close(io1dev);

exit(EXIT_FAILURE);

}

}

}

void lcd_execute(int wait_time) {

lcdc_io[0].state = 1;

write_by_offset(&lcdc_io[0]);

ssleep(wait_time);

lcdc_io[0].state = 0;

write_by_offset(&lcdc_io[0]);

}

void open_ioboard(void) {

int c, errorcode;

if (io1dev > -1)

return;

/* Open dimmio device */

io1dev = open("/dev/io1", O_RDWR);

if (io1dev < 0) {

fprintf(stderr, "Unable to open /dev/io1\n");

exit(EXIT_FAILURE);

}

/* Buttons */

printf("Opening Buttons\n");

for (c = 0; c < 3; c++) {

button_io[c].port_number = 10; /* Port K */

button_io[c].bit_number = c + 4; /* Pins 4, 5, and 6 */

button_io[c].mode = 0; /* Input */

button_io[c].state = 0;

button_io[c].pull_up_dn = 0; /* No idea */

errorcode = ioctl(io1dev, DIMM_IO_IOCTL_SET_CONFIG_BY_PORT_BIT, &button_io[c]);

if (errorcode < 0) {

fprintf(stderr, "Buttons: unable to configure /dev/io1 for button %i. Error code %i\n", c, errorcode);

close(io1dev);

exit(EXIT_FAILURE);

}

}

/* Latch */

printf("Opening Latch\n");

latchc_io[0].bit_number = 0; /* Pin 0 */

latchc_io[1].bit_number = 2; /* Pin 2 */

for (c = 0; c < 2; c++) {

latchc_io[c].port_number = 9; /* Port J */

latchc_io[c].mode = 1; /* Output */

latchc_io[c].state = 1;

latchc_io[c].pull_up_dn = 0;

errorcode = ioctl(io1dev, DIMM_IO_IOCTL_SET_CONFIG_BY_PORT_BIT, &latchc_io[c]);

if (errorcode < 0) {

fprintf(stderr, "Latch: unable to configure /dev/io1. Error code %i\n", errorcode);

close(io1dev);

exit(EXIT_FAILURE);

}

}

/* Bargraph */

printf("Opening Bargraph\n");

for (c = 0; c < 8; c++) {

portc_io[c].port_number = 2; /* Port C */

portc_io[c].bit_number = c; /* Pins 0 - 7 */

portc_io[c].mode = 1; /* Output */

portc_io[c].state = 0;

portc_io[c].pull_up_dn = 0;

errorcode = ioctl(io1dev, DIMM_IO_IOCTL_SET_CONFIG_BY_PORT_BIT, &portc_io[c]);

if (errorcode < 0) {

fprintf(stderr, "Bargraph: unable to configure /dev/io1. Error code %i\n", errorcode);

close(io1dev);

exit(EXIT_FAILURE);

}

}

/* LCD */

printf("Opening LCD\n");

/*

* 0: K0 - E

* 1: D5 - RS

* 2: D6 - R/W

*/

lcdc_io[0].port_number = 10;	/* Port K */

lcdc_io[0].bit_number = 0;	/* Pin 0 */

lcdc_io[1].port_number = 3;	/* Port D */

lcdc_io[1].bit_number = 5;	/* Pin 5 */

lcdc_io[2].port_number = 3;	/* Port D */

lcdc_io[2].bit_number = 6;	/* Pin 6 */

/* LEDs */

for (c = 0; c < 8; c++) {

lcdc_io[c].mode = 1; /* Output */

lcdc_io[c].state = 0;

lcdc_io[c].pull_up_dn = 0;

errorcode = ioctl(io1dev, DIMM_IO_IOCTL_SET_CONFIG_BY_PORT_BIT, &lcdc_io[c]);

if (errorcode < 0) {

fprintf(stderr, "LCD: unable to configure /dev/io1. Error code %i\n", errorcode);

close(io1dev);

exit(EXIT_FAILURE);

}

}

printf("Setting LCD\n");

/* Set 8 bit data length, both lines, 5x7 font */

lcdc_io[0].state = lcdc_io[1].state = lcdc_io[2].state = 0;

portc_io[7].state = portc_io[6].state = portc_io[2].state = 0;

portc_io[5].state = portc_io[4].state = portc_io[3].state = 1;

write_pins(lcdc_io, 3);

write_pins(portc_io, 8);

/* Execute */

lcd_execute(40);

}

void get_buttons(int *b1, int *b2, int *b3) {

int temp[3];

/* Save the old state */

temp[0] = button_io[0].state;

temp[1] = button_io[1].state;

temp[2] = button_io[2].state;

/* Get the new state */

read_pins(button_io, 3);

/* If any have changed state since last time, debounce */

if ((button_io[0].state != temp[0]) || (button_io[1].state != temp[1]) || (button_io[2].state != temp[2])) {

ssleep(1500);

/* This is weird. If the state doesn't change during the debounce,

we keep that. If it does, we keep *that*, too. */

read_pins(button_io, 3);

}

*b1 = button_io[0].state;

*b2 = button_io[1].state;

*b3 = button_io[2].state;

}

void enable_bargraph(int state) {

if (state)

latchc_io[1].state = 1;

else

latchc_io[1].state = 0;

write_by_offset(&latchc_io[1]);

}

void set_bargraph(int bargraph[8]) {

/* Unlatch bargraph */

latchc_io[0].state = 0;

write_by_offset(&latchc_io[0]);

/* Set bargraph */

portc_io[0].state = bargraph[0];

portc_io[1].state = bargraph[1];

portc_io[2].state = bargraph[2];

portc_io[3].state = bargraph[3];

portc_io[4].state = bargraph[4];

portc_io[5].state = bargraph[5];

portc_io[6].state = bargraph[6];

portc_io[7].state = bargraph[7];

write_pins(portc_io, 8);

/* Latch bargraph */

latchc_io[0].state = 1;

write_by_offset(&latchc_io[0]);

}

void set_lcd(int display, int cursor_mode, int direction, int shift) {

/*

* display: 0 - LCD off

*	1 - LCD on

* cursor_mode: 0 - invisible

*	1 - visible, static

*	2 - visible, blinking

* direction: 0 - move left

*	1 - move right

* shift: 0 - do not shift display on write

*	1 - shift display on write

*/

/* Set Display mode */

lcdc_io[1].state = lcdc_io[2].state = 0;

portc_io[7].state = portc_io[6].state = portc_io[5].state = portc_io[4].state = 0;

portc_io[3].state = 1;

portc_io[2].state = display;

portc_io[1].state = (cursor_mode > 0)?1:0;

portc_io[0].state = (cursor_mode > 1)?1:0;

write_pins(lcdc_io, 3);

write_pins(portc_io, 8);

lcd_execute(40);

/* Set Entry mode */

lcdc_io[1].state = lcdc_io[2].state = 0;

portc_io[7].state = portc_io[6].state = portc_io[5].state = portc_io[4].state = portc_io[3].state = 0;

portc_io[2].state = 1;

portc_io[1].state = direction;

portc_io[0].state = shift;

write_pins(lcdc_io, 3);

write_pins(portc_io, 8);

lcd_execute(40);

}

void clear_lcd(void) {

lcdc_io[1].state = lcdc_io[2].state = 0;

portc_io[7].state = portc_io[6].state = portc_io[5].state = portc_io[4].state = \

portc_io[3].state = portc_io[2].state = portc_io[1].state = 0;

portc_io[0].state = 1;

write_pins(lcdc_io, 3);

write_pins(portc_io, 8);

lcd_execute(1640); /* Wait 1.64 ms */

}

void lcd_charset(char *charset, int chars) {

int c, d;

lcdc_io[1].state = lcdc_io[2].state = 0;

portc_io[7].state = 0;

portc_io[6].state = 1;

portc_io[5].state = portc_io[4].state = portc_io[3].state = \

portc_io[2].state = portc_io[1].state = portc_io[0].state = 0;

/* Set custom char mode, first character */

write_pins(lcdc_io, 3);

write_pins(portc_io, 8);

lcd_execute(40);

/* Now set to data mode */

lcdc_io[1].state = 1;

for(c = 0; c < (chars * 8); c++)

{

for (d = 0; d < 8; d++)

portc_io[d].state = (charset[c] >> d) & 1;

write_pins(portc_io, 8);

lcd_execute(40);

}

}

void set_lcd_cursor(unsigned int x, unsigned int y) {

int addr, c, wait;

if (x > 39)

return;

lcdc_io[1].state = lcdc_io[2].state = 0;

if ((x == 0) && (y == 0)) {

portc_io[7].state = portc_io[6].state = portc_io[5].state = \

portc_io[4].state = portc_io[3].state = portc_io[2].state = 0;

portc_io[1].state = 1;

wait = 1640;

}

else {

addr = x + y?0:0x40;

portc_io[7].state = 1;

for (c = 0; c < 7; c++)

portc_io[c].state = (addr >> c) & 1;

wait = 40;

}

write_pins(lcdc_io, 3);

write_pins(portc_io, 8);

lcd_execute(wait);

}

void shift_lcd(int dist, int cd) {

int c;

lcdc_io[1].state = lcdc_io[2].state = 0;

portc_io[7].state = portc_io[6].state = portc_io[5].state = 0;

portc_io[4].state = 1;

portc_io[3].state = cd;

portc_io[2].state = (dist >= 0)?1:0;

write_pins(lcdc_io, 3);

write_pins(portc_io, 8);

if (dist > 0)

for (c = 0; c < dist; c++)

lcd_execute(40);

else

for (c = 0; c > dist; c--)

lcd_execute(40);

}

void print_lcd(char *string) {

int c, d;

lcdc_io[1].state = 1;

lcdc_io[2].state = 0;

write_pins(lcdc_io, 3);

for (c = 0; string[c] != '\0'; c++) {

switch (string[c]) {

case '\n':

set_lcd_cursor(0, 1);

break;

case '\r':

/* How am I going to know what line we're on?

This feature is officially unimplemented. */

break;

default:

for (d = 0; d < 8; d++)

portc_io[d].state = (string[c] >> d) & 1;

write_pins(portc_io, 8);

lcd_execute(40);

break;

}

}

}

ioboard.h

/*

* ioboard interface library

*

* mbgy, a moon-buggy clone for the AMC NetDIMM

* Copyright (C) 2004 Philip Bock

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation; either version 2 of the License, or

* (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

*/

#ifndef __IOBOARD_H__

#define __IOBOARD_H__

void open_ioboard(void);

void get_buttons(int *, int *, int *);

void enable_bargraph(int);

void set_bargraph(int [8]);

void set_lcd(int, int, int, int);

void lcd_charset(char *, int);

void clear_lcd(void);

void set_lcd_cursor(unsigned int, unsigned int);

void shift_lcd(int, int);

void print_lcd(char *);

#endif

stk.c

/*

* stk.c: Socket Toolkit

*

* mbgy, a moon-buggy clone for the AMC NetDIMM

* Copyright (C) 2004 Philip Bock

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation; either version 2 of the License, or

* (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

*/

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <netdb.h>

#include "stk.h"

struct sockaddr *stk_address(const char *hostname, int port)

{

struct hostent *host;

struct sockaddr_in *address;

if (hostname != NULL)

if ((host = gethostbyname(hostname)) == NULL)

return NULL;

address = malloc(sizeof(struct sockaddr_in));

address->sin_family = AF_INET;

address->sin_port = htons(port);

if (hostname != NULL)

memcpy(&address->sin_addr, host->h_addr_list[0], host->h_length);

else

address->sin_addr.s_addr = INADDR_ANY;

memset(&address->sin_zero, '\0', 8);

return (struct sockaddr *) address;

}

int stk_connect(const char *hostname, int port, int type)

{

struct sockaddr *address;

int sckt;

if ((address = stk_address(hostname, port)) == NULL)

return -2;

if ((sckt = socket(PF_INET, type, 0)) == -1)

return -1;

if (connect(sckt, address, sizeof(struct sockaddr)) == -1) {

close(sckt);

return -3;

}

free(address);

return sckt;

}

int stk_listen(const char *ip, int port, int type, int backlog)

{

struct sockaddr *address;

int sckt;

if ((address = stk_address(ip, port)) == NULL)

return -2; /* Error resolving hostname */

if ((sckt = socket(PF_INET, type, 0)) == -1)

return -1; /* Error creating socket */

if (bind(sckt, address, sizeof(struct sockaddr)) == -1) {

close(sckt);

return -3; /* Error binding to port */

}

free(address);

if (type == SOCK_STREAM) {

if (listen(sckt, backlog) == -1) {

close(sckt);

return -4; /* Error listening on socket */

}

}

return sckt;

}

stk.h

/*

* stk.h: Socket Toolkit

*

* mbgy, a moon-buggy clone for the AMC NetDIMM

* Copyright (C) 2004 Philip Bock

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation; either version 2 of the License, or

* (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

*/

#ifndef __STK_H__

#define __STK_H__

struct sockaddr *stk_address(const char *hostname, int port);

int stk_connect(const char *hostname, int port, int type);

int stk_listen(const char *ip, int port, int type, int backlog);

#endif

1

2004-04-25T15:42:57