diff options
Diffstat (limited to 'source/ct-Bot/pc')
-rw-r--r-- | source/ct-Bot/pc/bot-2-sim.c | 241 | ||||
-rw-r--r-- | source/ct-Bot/pc/delay_pc.c | 66 | ||||
-rw-r--r-- | source/ct-Bot/pc/display_pc.c | 175 | ||||
-rw-r--r-- | source/ct-Bot/pc/ir-rc5_pc.c | 54 | ||||
-rw-r--r-- | source/ct-Bot/pc/led_pc.c | 72 | ||||
-rw-r--r-- | source/ct-Bot/pc/mini-fat.c | 65 | ||||
-rw-r--r-- | source/ct-Bot/pc/mmc-emu_pc.c | 200 | ||||
-rw-r--r-- | source/ct-Bot/pc/motor-low_pc.c | 81 | ||||
-rw-r--r-- | source/ct-Bot/pc/mouse_pc.c | 87 | ||||
-rw-r--r-- | source/ct-Bot/pc/sensor-low_pc.c | 45 | ||||
-rw-r--r-- | source/ct-Bot/pc/tcp-server.c | 274 | ||||
-rw-r--r-- | source/ct-Bot/pc/tcp.c | 282 |
12 files changed, 1642 insertions, 0 deletions
diff --git a/source/ct-Bot/pc/bot-2-sim.c b/source/ct-Bot/pc/bot-2-sim.c new file mode 100644 index 0000000..f76b326 --- /dev/null +++ b/source/ct-Bot/pc/bot-2-sim.c @@ -0,0 +1,241 @@ +/* + * c't-Sim - Robotersimulator fuer den c't-Bot + * + * 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. + * + */ + +/*! @file bot-2-sim.c + * @brief Verbindung c't-Bot zu c't-Sim + * @author Benjamin Benz (bbe@heise.de) + * @date 26.12.05 +*/ + +#include "ct-Bot.h" + +#ifdef PC + +#include <stdio.h> // for printf() and fprintf() +#include <stdlib.h> // for atoi() and exit() +#include <string.h> // for strlen() +#include <sys/time.h> +#include <pthread.h> +#include <time.h> + +#include "bot-2-sim.h" +#include "tcp.h" +#include "command.h" +#include "display.h" +#include "sensor.h" +#include "bot-logic/bot-logik.h" +#include "motor.h" +#include "command.h" + + + +/* Linux with glibc: + * _REENTRANT to grab thread-safe libraries + * _POSIX_SOURCE to get POSIX semantics + */ +#ifdef __linux__ +# define _REENTRANT +//# define _POSIX_SOURCE +#endif + +/* Hack for LinuxThreads */ +#ifdef __linux__ +# define _P __P +#endif + +#define low_init tcp_init /*!< Low-Funktion zum Initialisieren*/ + +pthread_t simThread; /*!< Simuliert den Bot */ +pthread_t bot_2_sim_Thread; /*!< Thread sammelt Sensordaten, uebertraegt Motor-Daten */ + +pthread_cond_t command_cond = PTHREAD_COND_INITIALIZER; /*!< Schuetzt das Kommando */ +pthread_mutex_t command_cond_mutex = PTHREAD_MUTEX_INITIALIZER; /*!< Schuetzt das Kommando */ + +void signal_command_available(void); +int wait_for_command(int timeout_s); + +#ifdef WIN32 + /* These are winbase.h definitions, but to avoid including + tons of Windows related stuff, it is reprinted here */ + + typedef struct _FILETIME { + unsigned long dwLowDateTime; + unsigned long dwHighDateTime; + } FILETIME; + + void __stdcall GetSystemTimeAsFileTime(FILETIME*); + + void gettimeofday_win(struct timeval* p, void* tz /* IGNORED */){ + union { + long long ns100; // time since 1 Jan 1601 in 100ns units + FILETIME ft; + } _now; + + GetSystemTimeAsFileTime( &(_now.ft) ); + p->tv_usec=(long)((_now.ns100 / 10LL) % 1000000LL ); + p->tv_sec= (long)((_now.ns100-(116444736000000000LL))/10000000LL); + return; + } +#endif + +/*! + * Dieser Thread nimmt die Daten vom PC entgegen + */ +void *bot_2_sim_rcv_isr(void * arg){ + #ifdef DISPLAY_AVAILABLE + display_cursor(11,1); + #endif + printf("bot_2_sim_rcv_isr() comming up\n"); + for (;;){ + // only write if noone reads command + if (command_read()!=0) + printf("Error reading command\n"); // read a command + else { +// command_display(&received_command); // show it + if (command_evaluate() ==0) // use data transfered + signal_command_available(); // tell anyone waiting + } + } + return 0; +} + +/*! + * Schleife, die Kommandis empfaengt und bearbeitet, bis ein Kommando vom Typ Frame kommt + * @param frame Kommando zum abbruch + */ +int8 receive_until_Frame(int8 frame){ + int8 result=0; + for(;;){ + result=command_read(); + if (result!=0){ + printf("Error reading command\n"); // read a command + return result; + } else { + command_evaluate(); + } + + if (received_command.request.command == frame) + return 0; + } +} + + +/*! + * Ein wenig Initialisierung kann nicht schaden + */ +void bot_2_sim_init(void){ + low_init(); + +// if (pthread_create(&bot_2_sim_Thread, // thread struct +// NULL, // default thread attributes +// bot_2_sim_rcv_isr, // start routine +// NULL)) { // arg to routine +// printf("Thread Creation failed"); +// exit(1); +// } + + int j; + int16 null=0; + for(j=0;j<5;j++) + command_write(CMD_WELCOME, SUB_WELCOME_SIM ,&null,&null,0); + + flushSendBuffer(); +} + + +int not_answered_error=1; /*!< Wurde ein Packet beantwortet */ + + + + +/*! + * Wartet auf die Antwort des PC + * @param timeout_s Wartezeit in Sekunden + * @return 0, wenn Ok + */ +int wait_for_command(int timeout_s){ + struct timespec ts; + struct timeval tp; + int result=0; + + pthread_mutex_lock(&command_cond_mutex); + + GETTIMEOFDAY(&tp, NULL); + // Convert from timeval to timespec + ts.tv_sec = tp.tv_sec; + ts.tv_nsec = tp.tv_usec * 1000; + ts.tv_sec += timeout_s; + + result= pthread_cond_timedwait(&command_cond, &command_cond_mutex, &ts); + + pthread_mutex_unlock(&command_cond_mutex); + + return result; +} + +/*! + * Wartet auf die Antwort des PC + * Achtung blockierend ohne Timeout + * @param command Das kommando auf das gewartet wird. + * @return 0, wenn Ok + */ +int wait_for_special_command(uint8 command){ + int result=0; + while (1){ + result= wait_for_command(1000); + + if ((result==0) && (received_command.request.command == command)) + return result; + } + +} + +/*! + * Benachrichtigt wartende Threads ueber eingetroffene Kommandos + */ +void signal_command_available(void){ + pthread_mutex_lock(&command_cond_mutex); + pthread_cond_signal(&command_cond); + pthread_mutex_unlock(&command_cond_mutex); +} + +/*! + * Schickt einen Thread in die Warteposition + * @param timeout_us Wartezeit in Mikrosekunden + */ +void wait_for_time(long timeout_us){ + pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + struct timespec ts; + struct timeval tp; + + pthread_mutex_lock(&mutex); + GETTIMEOFDAY(&tp, NULL); + // Convert from timeval to timespec + + tp.tv_usec += (timeout_us % 1000000); + tp.tv_sec += (timeout_us / 1000000); + + ts.tv_sec = tp.tv_sec+ (tp.tv_usec/1000000); + ts.tv_nsec = (tp.tv_usec % 1000000)* 1000; + + pthread_cond_timedwait(&cond, &mutex, &ts); + pthread_mutex_unlock(&mutex); +} +#endif diff --git a/source/ct-Bot/pc/delay_pc.c b/source/ct-Bot/pc/delay_pc.c new file mode 100644 index 0000000..71dff08 --- /dev/null +++ b/source/ct-Bot/pc/delay_pc.c @@ -0,0 +1,66 @@ +/* + * c't-Sim - Robotersimulator fuer den c't-Bot + * + * 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. + * + */ + +/*! @file delay_pc.c + * @brief Hilfsroutinen + * @author Benjamin Benz (bbe@heise.de) + * @date 20.12.05 +*/ +#include "ct-Bot.h" + +#ifdef PC + +#ifdef WIN32 + + /* Windows */ + #include <windows.h> + + /*! Sleep Funktion */ + #define SLEEP(__value) Sleep(__value) + +#else + + /* Linux */ + #include <unistd.h> + + /*! Sleep Funktion */ + #define SLEEP(__value) usleep(__value) + +#endif + +/*! + * Warte 100 ms + */ +void delay_100ms(void){ + + SLEEP(100); +} + + +/*! + * Verzoegert um ms Millisekunden + * Wenn RTC_AVAILABLE, dann ueber rtc, sonst ueber delay_100ms. + * ==> Aufloesung ohne rtc: 100-ms-Schritte, mit rtc: 5-ms-Schritte + * @param ms Anzahl der Millisekunden + */ +void delay(int ms){ + + SLEEP(ms); +} +#endif diff --git a/source/ct-Bot/pc/display_pc.c b/source/ct-Bot/pc/display_pc.c new file mode 100644 index 0000000..60a7dab --- /dev/null +++ b/source/ct-Bot/pc/display_pc.c @@ -0,0 +1,175 @@ +/* + * c't-Sim - Robotersimulator fuer den c't-Bot + * + * 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. + * + */ + +/*! @file display_pc.c + * @brief Routinen zur Displaysteuerung + * @author Benjamin Benz (bbe@heise.de) + * @date 20.12.05 +*/ + +#include "ct-Bot.h" + +#ifdef PC + +#include "display.h" +#include <stdarg.h> +#include <stdio.h> + +/* definiere DISPLAY_REMOTE_AVAILABLE, wenn die Display-Daten per TCP an das + * Simulationsprogramm gesendet werden sollen. Wenn es nicht gesetzt ist, + * dann erscheint die LCD Ausgabe auf der Startkonsole */ + + +#ifdef DISPLAY_REMOTE_AVAILABLE + #include "command.h" + #include "bot-2-sim.h" +#else + #ifdef WIN32 + #include <windows.h> + #endif /* WIN32 */ +#endif + +#ifdef DISPLAY_AVAILABLE + +/*! Puffergroesse fuer eine Zeile in bytes */ +#define DISPLAY_BUFFER_SIZE (DISPLAY_LENGTH + 1) + +uint8 display_update=0; /*!< Muss das Display aktualisiert werden? */ +#ifdef DISPLAY_SCREENS_AVAILABLE + uint8 display_screen=0; /*!< Muss das Display aktualisiert werden? */ +#endif + +char display_buf[DISPLAY_BUFFER_SIZE]; /*!< Pufferstring fuer Displayausgaben */ + +#ifdef DISPLAY_REMOTE_AVAILABLE + #define CLEAR command_write(CMD_AKT_LCD, SUB_LCD_CLEAR, NULL, NULL,0) + #define POSITION(Ze, Sp) {Ze--; Sp--; command_write(CMD_AKT_LCD, SUB_LCD_CURSOR, (int16*)&(Sp),(int16*) &(Ze),0);} + #define printf(data) {command_write_data(CMD_AKT_LCD, SUB_LCD_DATA, NULL, NULL, (data));} +#else + #ifdef WIN32 + static void clrscr(void); + static void gotoxy(int x, int y); + #define POSITION(Ze, Sp) gotoxy(Sp, Ze) + #define CLEAR clrscr() + #else + #define POSITION(Ze, Sp) printf("\033[%d;%dH",Ze,Sp) /*!< Befehl um eine Posion anzuspringen */ + #define CLEAR printf("\033[2J") /*!< Befehl um das display zu loeschen */ + #endif +#endif + + +/*! + * Loescht das ganze Display + */ +void display_clear(void){ + CLEAR; +} + +/*! +** LCD_Cursor: Positioniert den LCD-Cursor bei "row", "column". +*/ +void display_cursor (uint8 row, uint8 column) { + int16 r=row, c=column; // Cast auf int16 + POSITION(r, c); +} + +/*! + * Init Display + */ +void display_init(void){ + CLEAR; +} + +/*! + * Zeigt einen String an + * @return -1, falls String zu Ende; 0, falls Zeile (20 Zeichen) zu Ende + */ +int display_string(char data[DISPLAY_LENGTH]){ + printf(data); + return -1; +} + +/*! + * Schreibt einen String auf das Display. + * @param format Format, wie beim printf + * @param ... Variable Argumentenliste, wie beim printf + */ +void display_printf(char *format, ...) { + + va_list args; + + /* Sicher gehen, das der zur Verfuegung stehende Puffer nicht + * ueberschrieben wird. + */ + va_start(args, format); + vsnprintf(display_buf, DISPLAY_BUFFER_SIZE, format, args); + va_end(args); + + printf(display_buf); + + return; +} + +#ifndef DISPLAY_REMOTE_AVAILABLE +#ifdef WIN32 + +/*! + * Loescht die Konsole. + */ +static void clrscr(void) { + COORD coordScreen = { 0, 0 }; + DWORD cCharsWritten; + CONSOLE_SCREEN_BUFFER_INFO csbi; + DWORD dwConSize; + HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + + GetConsoleScreenBufferInfo(hConsole, &csbi); + dwConSize = csbi.dwSize.X * csbi.dwSize.Y; + FillConsoleOutputCharacter( hConsole, + TEXT(' '), + dwConSize, + coordScreen, + &cCharsWritten); + GetConsoleScreenBufferInfo(hConsole, &csbi); + FillConsoleOutputAttribute( hConsole, + csbi.wAttributes, + dwConSize, + coordScreen, + &cCharsWritten); + SetConsoleCursorPosition(hConsole, coordScreen); + return; +} + +/*! + * Springt an die angegebenen Koordinaten in der Konsole. + * @param x Spalte + * @param y Zeile + */ +static void gotoxy(int x, int y) { + COORD point; + point.X = x-1; point.Y = y-1; + SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), point); + return; +} + +#endif /* WIN32 */ +#endif /* !DISPLAY_REMOTE_AVAILABLE */ + +#endif +#endif diff --git a/source/ct-Bot/pc/ir-rc5_pc.c b/source/ct-Bot/pc/ir-rc5_pc.c new file mode 100644 index 0000000..4072f1a --- /dev/null +++ b/source/ct-Bot/pc/ir-rc5_pc.c @@ -0,0 +1,54 @@ +/* + * c't-Sim - Robotersimulator fuer den c't-Bot + * + * 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. + * + */ + +/*! @file ir-rc5_pc.c + * @brief Routinen fuer die Dekodierung von RC5-Fernbedienungs-Codes + * @author Benjamin Benz (bbe@heise.de) + * @date 20.12.05 +*/ + +#include "ct-Bot.h" + +#ifdef PC + +#include "ir-rc5.h" +#include "command.h" +#include "bot-2-sim.h" + +#ifdef IR_AVAILABLE + +volatile uint16 ir_data = 0; /*!< letztes komplett gelesenes RC5-Paket */ + +/*! + * IR-Daten lesen + * @return Wert von ir_data, loescht anschliessend ir_data + */ +uint16 ir_read(void) { + uint16 retvalue = ir_data; + ir_data = 0; + return retvalue; +} + +/*! + * Init IR-System + */ +void ir_init(void) { +} +#endif +#endif diff --git a/source/ct-Bot/pc/led_pc.c b/source/ct-Bot/pc/led_pc.c new file mode 100644 index 0000000..7aadcad --- /dev/null +++ b/source/ct-Bot/pc/led_pc.c @@ -0,0 +1,72 @@ +/* + * c't-Sim - Robotersimulator fuer den c't-Bot + * + * 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. + * + */ + +/*! @file led_pc.c + * @brief Routinen zur LED-Steuerung + * @author Benjamin Benz (bbe@heise.de) + * @date 26.12.05 +*/ + +#include "ct-Bot.h" +#include "bot-2-sim.h" +#include "command.h" + +#ifdef PC + +#include "led.h" + +#ifdef LED_AVAILABLE +uint8 led=0; /*!< Status der LEDs */ +/*! + * Initialisiert die LEDs + */ +void LED_init(){ +} + +/*! + * Schaltet einzelne LEDs an + * andere werden nicht beeinflusst + * @param LED Bitmaske der anzuschaltenden LEDs + */ +void LED_on(uint8 LED){ + led |= LED; + LED_set(led); +} + +/*! + * Schaltet einzelne LEDs aus + * andere werden nicht beeinflusst + * @param LED Bitmaske der anzuschaltenden LEDs + */ +void LED_off(uint8 LED){ + led &= ~LED; + LED_set(led); +} + +/*! + * Zeigt eine 8-Bit-Variable mit den LEDs an + * @param LED Wert, der gezeigt werden soll + */ +void LED_set(uint8 LED){ + int16 led=LED; + command_write(CMD_AKT_LED, SUB_CMD_NORM ,&led,&led,0); +} + +#endif +#endif diff --git a/source/ct-Bot/pc/mini-fat.c b/source/ct-Bot/pc/mini-fat.c new file mode 100644 index 0000000..f806ceb --- /dev/null +++ b/source/ct-Bot/pc/mini-fat.c @@ -0,0 +1,65 @@ +/* + * c't-Bot + * + * 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. + * + */ + +/*! @file mini-fat.c + * @brief Routinen zum erstellen von markierten Files fuer eine MMC-Karte. + * @author Benjamin Benz (bbe@heise.de) + * @date 04.01.07 +*/ + +#include "ct-Bot.h" +#include "mini-fat.h" + +#ifdef PC + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +/*! + * Erzeugt eine Datei, die an den ersten Bytes die ID enthaelt. Dann folgen 512 - sizeof(id) nullen + * Danach kommen so viele size kByte Nullen + * @param filename Der Dateiname der zu erzeugenden Datei + * @param id_string Die ID des Files, wie sie zu beginn steht + * @param size kByte Nutzdaten, die der MCU spaeter beschreiben darf + */ +void create_mini_fat_file(const char* filename, const char* id_string, uint32 size){ + printf("Erstelle eine Mini-Fat-Datei mit dem Namen %s\n",filename); + FILE *fp = fopen(filename, "w"); + + /* Dateiparameter vorbereiten */ + uint8 id_len = strlen(id_string) >= MMC_FILENAME_MAX ? 254 : strlen(id_string); + file_len_t length = {size*1024 - 512}; // im ersten Block stehen interne Daten + + printf("Schreibe ID: \"%s\"\n",id_string); + fwrite(id_string,id_len,1,fp); + + /* Dateilaenge in die Datei schreiben */ + fseek(fp, 256, SEEK_SET); + int8 i; + for (i=3; i>=0; i--) + putc(length.u8[i], fp); + + printf("Erzeuge Speicherplatz fuer %lu kByte Nutzdaten\n",size); + fseek(fp, size*1024-1, SEEK_SET); // Ans Dateiende springen + putc(0, fp); // eine Null schreiben + fclose(fp); +} + +#endif diff --git a/source/ct-Bot/pc/mmc-emu_pc.c b/source/ct-Bot/pc/mmc-emu_pc.c new file mode 100644 index 0000000..9d265b3 --- /dev/null +++ b/source/ct-Bot/pc/mmc-emu_pc.c @@ -0,0 +1,200 @@ +/* + * c't-Bot + * + * 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. + * + */ + +/*! + * @file mmc-emu_pc.c + * @brief MMC / SD-Card Emulation fuer PC + * @author Timo Sandmann (mail@timosandmann.de) + * @date 10.12.2006 + */ + +/* Die PC-Emulation einer MMC / SD-Card ermoeglicht es, am PC dieselben Funktionen zu benutzen, wie bei einer echten + * MMC / SD-Card. Als Speichermedium dient hier eine Datei (MMC_EMU_FILE), deren Groesse sich mit MMC_EMU_SIZE in Byte + * einstellen laesst. Ist die Datei nicht vorhanden oder derzeit kleiner als MMC_EMU_SIZE, wird sie angelegt bzw. + * vergroessert. Achtung, startet man den C-Bot vom Sim aus, liegt die Datei, falls kein absoluter Pfad angegeben wurde, im + * Verzeichnis dem ct-Sims, von der Konsole aus gestartet erwartet / erzeugt der Code die Datei im Unterverzeichnis + * "Debug-Linux" bzw. "Debug-W32". + * Eine sinnvolle (und die derzeit einzig moegliche) Verwendung der Emulation ergibt sich im Zusammenspiel mit dem + * Virtual Memory Management fuer MMC. Ein Verhalten kann in diesem Fall immer auf dieselbe Art und Weise Speicher anfordern, + * je nach System liegt dieser physisch dann entweder auf einer MMC / SD-Card (MCU) oder in einer Datei (PC). Fuer das + * Verhalten ergibt sich kein Unterschied und es kann einfach derselbe Code verwendet werden. + * Moechte man die Funktion mmc_fopen() benutzen, also auf FAT16-Dateien zugreifen, so ist zu beachten, dass deren "Dateiname" + * in der Datei fuer die Emulation am Anfang eines 512 Byte grossen Blocks steht (denn auf einer echten MMC / SD-Card ezeugt + * ein Betriebssystem eine neue Datei immer am Anfang eines Clusters und mmc_fopen() sucht nur dort nach dem "Dateinamen"). + * Im Moment gibt es noch keine Funktion zum Anlegen einer neuen Datei auf einer echten oder emulierten MMC / SD-Card. + * Die Code der Emulation ist voellig symmetrisch zum Code fuer eine echte MMC / SD-Card aufgebaut. + */ + +#include "ct-Bot.h" +#include <stdio.h> +#include "mmc-emu.h" +#include "mmc-vm.h" +#include "display.h" + +#ifdef PC +#ifdef MMC_VM_AVAILABLE + +#define MMC_EMU_SIZE 0x2000000 /*!< Groesse der emulierten Karte in Byte */ +#define MMC_EMU_FILE "mmc_emu.dat" /*!< Name / Pfad der Datei fuer die Emulation */ + +volatile uint8 mmc_emu_init_state=1; /*!< Initialierungsstatus der Karte, 0: ok, 1: Fehler */ +static FILE* mmc_emu_file; /*!< Der Inhalt der emulierten Karte wird einfach in eine Datei geschrieben */ + +/*! + * Checkt Initialisierung der emulierten Karte + * @return 0, wenn initialisiert + * @see mcu/mmc.c + * @date 29.12.2006 + */ +inline uint8 mmc_emu_get_init_state(void){ + return mmc_emu_init_state; +} + +/*! + * Initialisiere die emulierte SD/MMC-Karte + * @return 0 wenn allles ok, sonst 1 + * @see mcu/mmc.c + * @date 29.12.2006 + */ +uint8 mmc_emu_init(void){ + mmc_emu_init_state = 0; + mmc_emu_file = fopen(MMC_EMU_FILE, "r+"); // Datei versuchen zu oeffnen + if (mmc_emu_file == NULL){ + /* Datei existiert noch nicht oder kann nicht erzeugt werden */ + mmc_emu_file = fopen(MMC_EMU_FILE, "w+"); // Datei neu anlegen + if (mmc_emu_file == NULL) { + /* Datei kann nicht erzeugt werden */ + mmc_emu_init_state = 1; + return 1; + } + } + if (mmc_emu_get_size() < MMC_EMU_SIZE){ + /* vorhandene Datei ist zu klein, also auf MMC_EMU_SIZE vergroessern */ + mmc_emu_init_state = 1; + if (fseek(mmc_emu_file, MMC_EMU_SIZE-1, SEEK_SET) != 0) return 2; + if (putc(0, mmc_emu_file) != 0) return 3; + if (fflush(mmc_emu_file) != 0) return 4; + mmc_emu_init_state = 0; + } + return 0; +} + +/*! + * Liest einen Block von der emulierten Karte + * @param addr Nummer des 512-Byte Blocks + * @param buffer Puffer von mindestens 512 Byte + * @return 0 wenn alles ok ist + * @see mcu/mmc.c + * @date 10.12.2006 + */ +uint8 mmc_emu_read_sector(uint32 addr, uint8* buffer){ + if (mmc_emu_get_init_state() != 0 && mmc_emu_init() !=0) return 1; + if (fseek(mmc_emu_file, addr<<9, SEEK_SET) != 0) return 2; // Adresse in Byte umrechnen und an Dateiposition springen + if (fread(buffer, 512, 1, mmc_emu_file) != 1) return 3; // Block lesen + return 0; +} + +/*! + * Schreibt einen 512-Byte Sektor auf die emulierte Karte + * @param addr Nummer des 512-Byte Blocks + * @param buffer Zeiger auf den Puffer + * @param async Wird bei der PC-Version nicht ausgewertet + * @return 0 wenn alles ok ist + * @date 10.12.2006 + * @see mcu/mmc.c + */ +uint8 mmc_emu_write_sector(uint32 addr, uint8* buffer, uint8 async){ + if (mmc_emu_get_init_state() != 0 && mmc_emu_init() !=0) return 1; + if (fseek(mmc_emu_file, addr<<9, SEEK_SET) != 0) return 2; // Adresse in Byte umrechnen und an Dateiposition springen + if (fwrite(buffer, 512, 1, mmc_emu_file) != 1) return 3; // Block schreiben + if (fflush(mmc_emu_file) != 0) return 4; // Puffer leeren + return 0; +} + +/*! + * Liefert die Groesse der Karte zurueck + * @return Groesse der emulierten Karte in Byte. + * @date 29.12.2006 + */ +uint32 mmc_emu_get_size(void){ + if (mmc_emu_get_init_state() != 0 && mmc_emu_init() !=0) return 0; + if (fseek(mmc_emu_file, 0L, SEEK_END) != 0) return 0; // Groesse der emulierten Karte = Groesse der Datei + return ftell(mmc_emu_file)+1; +} + +/*! + * Testet VM und MMC / SD-Card Emulation am PC + * @date 30.12.2006 + */ +uint8 mmc_emu_test(void){ + /* Initialisierung checken */ + if (mmc_emu_init_state != 0 && mmc_emu_init() != 0) return 1; + uint16 i; + static uint16 pagefaults = 0; + /* virtuelle Adressen holen */ + static uint32 v_addr1 = 0; + static uint32 v_addr2 = 0; + static uint32 v_addr3 = 0; + static uint32 v_addr4 = 0; + if (v_addr1 == 0) v_addr1 = mmcalloc(512, 1); // Testdaten 1 + if (v_addr2 == 0) v_addr2 = mmcalloc(512, 1); // Testdaten 2 + if (v_addr3 == 0) v_addr3 = mmcalloc(512, 1); // Dummy 1 + if (v_addr4 == 0) v_addr4 = mmcalloc(512, 1); // Dummy 2 + /* Pointer auf Puffer holen */ + uint8* p_addr = mmc_get_data(v_addr1); + if (p_addr == NULL) return 2; + /* Testdaten schreiben */ + for (i=0; i<512; i++) + p_addr[i] = (i & 0xff); + /* Pointer auf zweiten Speicherbereich holen */ + p_addr = mmc_get_data(v_addr3); + if (p_addr == NULL) return 3; + /* Testdaten Teil 2 schreiben */ + for (i=0; i<512; i++) + p_addr[i] = 255 - (i & 0xff); + /* kleiner LRU-Test */ + p_addr = mmc_get_data(v_addr1); + p_addr = mmc_get_data(v_addr4); + p_addr = mmc_get_data(v_addr1); + p_addr = mmc_get_data(v_addr3); + p_addr = mmc_get_data(v_addr1); + p_addr = mmc_get_data(v_addr4); + /* Pointer auf Testdaten Teil 1 holen */ + p_addr = mmc_get_data(v_addr1); + if (p_addr == NULL) return 4; + /* Testdaten 1 vergleichen */ + for (i=0; i<512; i++) + if (p_addr[i] != (i & 0xff)) return 5; + /* Pointer auf Testdaten Teil 2 holen */ + p_addr = mmc_get_data(v_addr3); + if (p_addr == NULL) return 6; + /* Testdaten 2 vergleichen */ + for (i=0; i<512; i++) + if (p_addr[i] != (255 - (i & 0xff))) return 7; + /* Pagefaults merken */ + pagefaults = mmc_get_pagefaults(); + /* kleine Statistik ausgeben */ + display_cursor(3,1); + display_printf("Pagefaults: %5u ", pagefaults); + // hierher kommen wir nur, wenn alles ok ist + return 0; +} + +#endif // MMC_VM_AVAILABLE +#endif // PC diff --git a/source/ct-Bot/pc/motor-low_pc.c b/source/ct-Bot/pc/motor-low_pc.c new file mode 100644 index 0000000..1bd7e80 --- /dev/null +++ b/source/ct-Bot/pc/motor-low_pc.c @@ -0,0 +1,81 @@ +/* + * c't-Sim - Robotersimulator fuer den c't-Bot + * + * 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. + * + */ + +/*! @file motor-low_pc.c + * @brief Low-Level Routinen fuer die Motorsteuerung des c't-Bots + * @author Benjamin Benz (bbe@heise.de) + * @date 01.12.05 +*/ + +#include "ct-Bot.h" + +#ifdef PC + +#include <stdlib.h> +#include "command.h" +#include "bot-2-sim.h" +#include "motor-low.h" +#include "motor.h" + + +int16 motor_left; /*!< zuletzt gestellter Wert linker Motor */ +int16 motor_right; /*!< zuletzt gestellter Wert rechter Motor */ + +/*! + * Initilisiert alles fuer die Motosteuerung + */ +void motor_low_init(){ +} + +/*! + * Unmittelbarer Zugriff auf die beiden Motoren, + * normalerweise NICHT verwenden! + * @param left PWM links + * @param right PWM rechts +*/ +void bot_motor(int16 left, int16 right){ + command_write(CMD_AKT_MOT, SUB_CMD_NORM ,&left,&right,0); + + if (right < 0 ) + direction.right= DIRECTION_BACKWARD; + if (right > 0 ) + direction.right= DIRECTION_FORWARD; + if (left < 0 ) + direction.left= DIRECTION_BACKWARD; + if (left > 0 ) + direction.left= DIRECTION_FORWARD; + + motor_left=left; + motor_right=right; + +} + +/*! + * Stellt die Servos + * Sinnvolle Werte liegen zwischen 8 und 16 + * @param servo Nummer des Servos + * @param servo Zielwert + */ +void servo_low(uint8 servo, uint8 pos){ + int16 p = pos; + int16 s = servo; + command_write(CMD_AKT_SERVO, SUB_CMD_NORM ,&s,&p,0); +} + +#endif diff --git a/source/ct-Bot/pc/mouse_pc.c b/source/ct-Bot/pc/mouse_pc.c new file mode 100644 index 0000000..c8e1dda --- /dev/null +++ b/source/ct-Bot/pc/mouse_pc.c @@ -0,0 +1,87 @@ +/* + * c't-Bot + * + * 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. + * + */ + +/*! @file mouse.c + * @brief Routinen fuer die Ansteuerung eines opt. Maussensors + * @author Benjamin Benz (bbe@heise.de) + * @date 26.12.05 +*/ +#include "global.h" + +#include "ct-Bot.h" +#include "log.h" + +#ifdef PC + +uint8 mousePicture[18*18]; + +/*! + * Initialisiere Maussensor + */ +void maus_sens_init(void){ +} + +uint16 pixIndex=0; + +/*! + * Bereitet das auslesen eines ganzen Bildes vor + */ +void maus_image_prepare(void){ + pixIndex=0; + + int x,y; + for (x=0; x<18;x++) + for (y=0; y<18;y++) + mousePicture[y + x*18] = 0x40 | y*4; + + mousePicture[0]|= 0x80; // Start of Frame + +} + +/*! + * Liefert bei jedem Aufruf das naechste Pixel des Bildes + * Insgesamt gibt es 324 Pixel + * <pre> + * 18 36 ... 324 + * .. .. ... .. + * 2 20 ... .. + * 1 19 ... 307 + * </pre> + * Bevor diese Funktion aufgerufen wird, muss maus_image_prepare() aufgerufen werden! + * @return Die Pixeldaten (Bit 0 bis Bit5), Pruefbit, ob Daten gueltig (Bit6), Markierung fuer den Anfang eines Frames (Bit7) + */ +int8 maus_image_read(void){ + + if (pixIndex==324) + pixIndex =0; + + return mousePicture[pixIndex++]; +} + +/*! + * Gibt den SQUAL-Wert zurueck. Dieser gibt an, wieviele Merkmale der Sensor + * im aktuell aufgenommenen Bild des Untergrunds wahrnimmt. + * Fuer simulierten Bot zur Zeit mit einem fixen Wert belegt, da fuer den + * Boden im Sim keine Texturen verwendet werden + */ +int8 maus_get_squal(void) { + return 70; +} + +#endif diff --git a/source/ct-Bot/pc/sensor-low_pc.c b/source/ct-Bot/pc/sensor-low_pc.c new file mode 100644 index 0000000..b10e9ea --- /dev/null +++ b/source/ct-Bot/pc/sensor-low_pc.c @@ -0,0 +1,45 @@ +/* + * c't-Sim - Robotersimulator fuer den c't-Bot + * + * 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. + * + */ + +/*! @file sensor-low_pc.c + * @brief Low-Level Routinen fuer die Sensor Steuerung des c't-Bots + * @author Benjamin Benz (bbe@heise.de) + * @date 01.12.05 +*/ + +#include "ct-Bot.h" + +#ifdef PC + +#include "sensor-low.h" + +/*! + * Initialisiere alle Sensoren + */ +void bot_sens_init(void){ +} + +/*! + * Alle Sensoren aktualisieren. + * Das geschieht auf der PC Seite anders -- in einem eigenen Thread. + * Diese Funktion ist nur ein Dummy zur Kompatibilitaet. + */ +void bot_sens_isr(void){ +} +#endif diff --git a/source/ct-Bot/pc/tcp-server.c b/source/ct-Bot/pc/tcp-server.c new file mode 100644 index 0000000..7d1f53b --- /dev/null +++ b/source/ct-Bot/pc/tcp-server.c @@ -0,0 +1,274 @@ +/* + * c't-Sim - Robotersimulator fuer den c't-Bot + * + * 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. + * + */ + +/*! @file tcp-server.c + * @brief Demo-TCP-Server + * @author Benjamin Benz (bbe@heise.de) + * @date 26.12.05 +*/ +#include "ct-Bot.h" + +#ifdef PC + +#include "bot-2-sim.h" +#include "tcp.h" +#include "display.h" +#include "command.h" + +#include <time.h> +#include <sys/time.h> + + +/* Linux with glibc: + * _REENTRANT to grab thread-safe libraries + * _POSIX_SOURCE to get POSIX semantics + */ +#ifndef WIN32 +# define _REENTRANT +//# define _POSIX_SOURCE +#else +// #define WIN32 +#endif + +/* Hack for LinuxThreads */ +#ifdef __linux__ +# define _P __P +#endif + +#include <pthread.h> + +#ifdef WIN32 + #include <winsock.h> +#else + #include <arpa/inet.h> + #include <sys/socket.h> + #include <netinet/in.h> +#endif + +#include <stdio.h> // for printf() and fprintf() +#include <stdlib.h> // for atoi() and exit() +#include <string.h> // for memset() +#include <unistd.h> // for close() + +#include "global.h" + +int server; /*!< Server-Socket */ + +struct sockaddr_in serverAddr; /*!< Lokale Adresse */ +struct sockaddr_in clientAddr; /*!< Client-Adresse */ +unsigned int clntLen; /*!< Laenge der Datenstruktur der Client-Adresse */ + +/*! + * Init TCP-Server + */ +void tcp_server_init(void){ + #ifdef DISPLAY_AVAILABLE +// display_init(); + #endif + + #ifdef WIN32 + WSADATA wsaData; + WORD wVersionRequested; + int err; + + wVersionRequested = MAKEWORD( 2, 0 ); // 2.0 and above version of WinSock + err = WSAStartup( wVersionRequested, &wsaData ); + if ( err != 0 ) { + fprintf(stderr, "Couldn't not find a usable WinSock DLL.\n"); + exit(1); + } + #endif + + + // Create socket for incoming connections + if ((server = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){ + printf("socket() failed\n"); + exit(1); + } + + int i=1; + setsockopt(server,SOL_SOCKET,SO_REUSEADDR,(char*)&i,sizeof(i)); + + memset(&serverAddr, 0, sizeof(serverAddr)); // Clean up + serverAddr.sin_family = AF_INET; // Internet address family + serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); // Any incoming interface + serverAddr.sin_port = htons(PORT); // Local port to listen on + + // Bind to the local address + if (bind(server, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) <0 ){ + printf("bind() failed\n"); + exit(1); + } + + // Mark the socket so it will listen for incoming connections + if (listen(server, 5) < 0){ + printf("listen() failed\n"); + exit(1); + } +} + +/*! + * Hauptschleife des TCP-Servers + */ +int tcp_server_run (int runs){ + char buffer[MAX_PAYLOAD]; // Buffer + struct timeval start, stop; + printf("TCP-Server alive\n"); + + int seq=0; +// tcp_server_init(); + +// printf("Initialized\n"); + + for(;;){ + /* Set the size of the in-out parameter */ + clntLen = sizeof(clientAddr); + + printf("Waiting for client\n"); + // Wait for a client to connect + if ((tcp_sock = accept(server, (struct sockaddr *) &clientAddr, &clntLen)) < 0) + printf("accept() failed"); + + printf("Connected to %s on Port: %d\n", inet_ntoa(clientAddr.sin_addr),PORT); + + int16 simultime=0; + int i; + for(i=0;i<runs;i++){ + simultime+=10; + + command_write(CMD_SENS_IR, SUB_CMD_NORM ,(int16*)&simultime,(int16*)&simultime,0); + command_write(CMD_SENS_ENC, SUB_CMD_NORM ,(int16*)&simultime,(int16*)&simultime,0); + command_write(CMD_SENS_BORDER, SUB_CMD_NORM ,(int16*)&simultime,(int16*)&simultime,0); + command_write(CMD_SENS_LINE, SUB_CMD_NORM ,(int16*)&simultime,(int16*)&simultime,0); + command_write(CMD_SENS_LDR, SUB_CMD_NORM ,(int16*)&simultime,(int16*)&simultime,0); + command_write(CMD_SENS_TRANS, SUB_CMD_NORM ,(int16*)&simultime,0,0); + command_write(CMD_SENS_DOOR, SUB_CMD_NORM ,(int16*)&simultime,(int16*)&simultime,0); + command_write(CMD_SENS_MOUSE, SUB_CMD_NORM ,(int16*)&simultime,(int16*)&simultime,0); + command_write(CMD_SENS_ERROR, SUB_CMD_NORM ,(int16*)&simultime,(int16*)&simultime,0); + command_write(CMD_SENS_RC5, SUB_CMD_NORM ,0,0,0); + + command_write(CMD_DONE, SUB_CMD_NORM ,(int16*)&simultime,0,0); + flushSendBuffer(); + + GETTIMEOFDAY(&stop, NULL); + int t2= (stop.tv_sec - start.tv_sec)*1000000 + stop.tv_usec - start.tv_usec; + printf("X-Token (%d) out after %d usec ",simultime,t2); + + + received_command.request.command =0; + while(received_command.request.command != CMD_DONE ){ + if (command_read() != 0){ + // Fehler + printf("Probleme beim Lesen eines Kommandos\n"); + } else { + // Alles ok, evtl. muessen wir aber eine Payload abholen + if (received_command.payload != 0) { + // printf ("fetching payload (%d bytes)\n",received_command.payload); + low_read(buffer,received_command.payload); + } + if (received_command.seq != seq){ + printf("Sequenzzaehler falsch! Erwartet: %d Empfangen %d \n",seq,received_command.seq); + } + } + seq=received_command.seq+1; + } + GETTIMEOFDAY(&start, NULL); + + + int t= (start.tv_sec - stop.tv_sec)*1000000 + start.tv_usec - stop.tv_usec; + printf("X-Token (%d) back after %d usec\n",received_command.data_l,t); + + + if (received_command.data_l != simultime){ + printf("Falschen X-Frame erhalten ==> Exit\n"); + exit(0); + } + +/* + printf("Rechenzeit: %d usec\n",(stop.tv_sec - start.tv_sec)*1000000 +stop.tv_usec - start.tv_usec); + + command_read(); + if + #ifdef LOG_AVAILABLE + command_display(&received_command); + #endif + + received_command.request.direction=DIR_ANSWER; + tcp_send_cmd(&received_command); + */ + } + + printf("TCP-Server hat seine %d runs durch und beendet sich. So long and thanks for all the fish\n",runs); + + #ifdef WIN32 + WSACleanup(); + #endif + exit(0); + } + + return 1; +} + + +/*! + * Init TCP-test-Client + */ +void tcp_test_client_init(void){ + tcp_init(); + printf("Connecting Testclient to %s on Port: %d ", tcp_hostname, 10001); + + if ((tcp_sock=tcp_openConnection(tcp_hostname)) != -1) + printf ("established \n"); + else { + printf ("failed\n"); + exit(1); + } +} + +/*! + * Hauptschleife des TCP-Test-Clients + */ +int tcp_test_client_run (int runs){ + char buffer[255]; + + int len=0; + int i=0; + + if (runs > 0) + printf("Answering %d frames\n",runs); + else + printf("Answering all frames\n"); + + for(;;){ + if ((runs > 0) && (i > runs)) + break; + i++; + buffer[0]=0; + len=0; + + len= tcp_read(&buffer,255); + tcp_write(&buffer,len); + } + printf("Finished %d frames\n",runs); + + exit(1); + return 1; +} + +#endif diff --git a/source/ct-Bot/pc/tcp.c b/source/ct-Bot/pc/tcp.c new file mode 100644 index 0000000..d654f3d --- /dev/null +++ b/source/ct-Bot/pc/tcp.c @@ -0,0 +1,282 @@ +/* + * c't-Sim - Robotersimulator fuer den c't-Bot + * + * 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. + * + */ + +/*! @file tcp.c + * @brief TCP/IP-Kommunikation + * @author Benjamin Benz (bbe@heise.de) + * @date 26.12.05 +*/ + +#include "ct-Bot.h" + +#define USE_SEND_BUFFER + +#ifdef PC + +/* Linux with glibc: + * _REENTRANT to grab thread-safe libraries + * _POSIX_SOURCE to get POSIX semantics + */ +#ifndef WIN32 +# define _REENTRANT +//# define _POSIX_SOURCE +#else +// #define WIN32 +#endif + +/* Hack for LinuxThreads */ +#ifdef __linux__ +# define _P __P +#endif + +#include <pthread.h> + + +#ifdef WIN32 + #include <winsock.h> +#else + #include <arpa/inet.h> + #include <sys/socket.h> + #include <netinet/in.h> + #include <netdb.h> // for gethostbyname() + #include <netinet/tcp.h> +#endif + + +#include <stdio.h> // for printf() and fprintf() +#include <stdlib.h> // for atoi() and exit() +#include <string.h> // for memset() +#include <unistd.h> // for close() + +#include "tcp.h" +#include "display.h" + +int tcp_sock=0; /*!< Unser TCP-Socket */ +char *tcp_hostname = NULL; /*!< Hostname, auf dem ct-Sim laeuft */ + +#ifdef PC + uint8 sendBuffer[1024]; /*!< Sendepuffer fuer ausgehende Packete */ + int sendBufferPtr=0; /*!< Index in den Sendepuffer */ +#endif + +/*! + * Oeffnet eine TCP-Verbindung zum Server + * @param hostname Symbolischer Name des Host, auf dem ct-Sim laeuft + * @return Der Socket +*/ +int tcp_openConnection(const char *hostname){ + struct sockaddr_in servAddr; // server address + int sock=0; // Socket descriptor + struct hostent *he = gethostbyname(hostname); + + // Ueberpruefen, ob der Hostname aufgeloest werden konnte + if (NULL == he) { + printf("gethostbyname() failed\n"); + exit(1); + } + + // Create a stream socket for TCP + if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){ + printf("socket() failed"); + exit(1); + } + + int flag = 1; + setsockopt(sock, /* socket affected */ + IPPROTO_TCP, /* set option at TCP level */ + TCP_NODELAY, /* name of option */ + (char *) &flag, /* the cast is historical + cruft */ + sizeof(int)); /* length of option value */ + + // Prepare server address structure + memset(&servAddr, 0, sizeof(servAddr)); // Zero out structure + servAddr.sin_family = AF_INET; // Internet address + servAddr.sin_port = htons(PORT); // Port + + // Die erste Adresse aus der Liste uebernehmen + memcpy(&servAddr.sin_addr, *(he->h_addr_list), sizeof(servAddr.sin_addr)); + + // Open Connection to the server + if (connect(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0){ + printf("tcp_openConnection() to %s failed\n", inet_ntoa(servAddr.sin_addr)); + exit(1); + } + + return sock; +} + +/*! + * Schliesst eine TCP-Connection + * @param sock Der Socket +*/ +void tcp_closeConnection(int sock){ + close(sock); + #ifdef WIN32 + WSACleanup(); + #endif +} + +/*! + * Sende Kommando per TCP/IP im Little Endian + * Diese Funktion setzt vorraus, dass die Symbole BYTE_ORDER und BIG_ENDIAN + * bzw. LITTLE_ENDIAN definiert wurden. Damit dies auf Linux/Unix + * funktioniert darf _POSIX_SOURCE nicht definiert werden. Fuer Windows + * wird dies in der Headerdatei tcp.h erledigt. + * Getestet wurde dies bisher auf folgenden Systemen: + * - MacOSX (PPC, big endian) + * - Gentoo Linux (hppa, big endian) + * - OpenBSD (i386, little endian) + * - Windows 2000 (i386, little endian mit dem MinGW) + * Sollten in command_t weitere Werte mit mehr bzw. weniger als 8 bit + * aufgenommen werden muss hier eine entsprechende Anpassung erfolgen. + * @param cmd Zeiger auf das Kommando + * @return Anzahl der gesendete Bytes + */ +int tcp_send_cmd(command_t *cmd){ +#if BYTE_ORDER == BIG_ENDIAN + command_t le_cmd; + + /* Kopieren des Kommandos und auf Little Endian wandeln */ + memcpy(&le_cmd, cmd, sizeof(command_t)); + + /* Alle 16bit Werte in Little Endian wandeln */ + le_cmd.data_l = cmd->data_l << 8; + le_cmd.data_l |= (cmd->data_l >> 8) & 0xff; + le_cmd.data_r = cmd->data_r << 8; + le_cmd.data_r |= (cmd->data_r >> 8) & 0xff; + le_cmd.seq = cmd->seq <<8; + le_cmd.seq |= (cmd->seq >> 8) & 0xff; + + /* "Umdrehen" des Bitfields */ + le_cmd.request.subcommand = cmd->request.subcommand >> 1; + le_cmd.request.direction = (cmd->request.subcommand & 1) << 7; + + return tcp_write(&le_cmd, sizeof(command_t)); +#else + return tcp_write(cmd, sizeof(command_t)); +#endif +} + +/*! Puffert daten im Sendepuffer zwischen + * @param data zeiger auf die daten + * @param length Anzahl der Bytes + * @return -1 wenn kein Platz mehr im Puffer ist, 0 wenn alles ok ist + */ +int copy2Buffer(uint8* data, int length){ + int i; + uint8 * ptr = data; + + if ((sendBufferPtr + length) > sizeof(sendBuffer)) + return -1; + +// printf("Store %d bytes",length); + // Auf dem PC kopieren wir nur alles in den Ausgangspuffer + for (i=0; i< length ; i++){ + sendBuffer[sendBufferPtr++]= *ptr++ ; + } +// printf(" %d Bytes now in buffer\n",sendBufferPtr); + return 0; +} + +/*! + * Uebertrage Daten per TCP/IP + * @param data Zeiger auf die Daten + * @param length Anzahl der Bytes + * @return 0 wenn alles ok, -1 wenn puffer voll +*/ +int tcp_write(void* data, int length){ + #ifdef USE_SEND_BUFFER + return copy2Buffer(data, length); + #else + if (send(tcp_sock,data,length,0) != length){ + printf("send() sent a different number of bytes than expected"); + return -1; + } + return length; + #endif +} + +/*! + * Lese Daten von TCP/IP-Verbindung. + * Achtung: blockierend! + * @param data Zeiger auf die Daten + * @param length Anzahl der gewuenschten Bytes + * @return Anzahl der uebertragenen Bytes +*/ +int tcp_read(void* data, int length){ + int bytesReceived=0; + + if ((bytesReceived = recv(tcp_sock, data, length, 0)) <= 0){ + printf("recv() failed or connection closed prematurely\n"); + exit(1); + return -1; + } + + return bytesReceived; +} + +/*! + * Initialisiere TCP/IP Verbindung + */ +void tcp_init(void){ + #ifdef WIN32 + WSADATA wsaData; + WORD wVersionRequested; + int err; + + wVersionRequested = MAKEWORD( 2, 0 ); // 2.0 and above version of WinSock + err = WSAStartup( wVersionRequested, &wsaData ); + if ( err != 0 ) { + fprintf(stderr, "Couldn't not find a usable WinSock DLL.\n"); + exit(1); + } + #endif + + + if ((tcp_sock=tcp_openConnection(tcp_hostname)) != -1) + printf ("connection to %s established on Port: %d\n", tcp_hostname, PORT); + else { + printf ("connection to %s failed on Port: %d\n", tcp_hostname, PORT); + exit(1); + } + +} + +/*! + * Schreibt den Sendepuffer auf einen Schlag raus + * @return -1 bei Fehlern, sonst zahl der uebertragenen Bytes + */ +int flushSendBuffer(void){ + #ifdef USE_SEND_BUFFER + // printf("Flushing Buffer with %d bytes\n",sendBufferPtr); + + int length=sendBufferPtr; + sendBufferPtr=0; // Puffer auf jedenfall leeren + if (send(tcp_sock,(char*)&sendBuffer,length,0) != length){ + printf("send() sent a different number of bytes than expected"); + return -1; + } + return length; + #else + return 0; + #endif +} + +#endif |