diff options
Diffstat (limited to 'source/ct-Bot/command.c')
-rw-r--r-- | source/ct-Bot/command.c | 469 |
1 files changed, 469 insertions, 0 deletions
diff --git a/source/ct-Bot/command.c b/source/ct-Bot/command.c new file mode 100644 index 0000000..a1993dd --- /dev/null +++ b/source/ct-Bot/command.c @@ -0,0 +1,469 @@ +/* + * 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 command.c + * @brief Kommando-Management + * @author Benjamin Benz (bbe@heise.de) + * @date 20.12.05 +*/ + +#include "ct-Bot.h" + +#include "led.h" +#include "log.h" + +#include "uart.h" +#include "adc.h" +#include "timer.h" +#include "mouse.h" + +#include "command.h" +#include "display.h" + +#include "sensor.h" +#include "motor.h" +#include "rc5.h" +#include "ir-rc5.h" +#include "bot-logic/bot-logik.h" +#include "bot-2-pc.h" + +#include <stdio.h> +#include <string.h> + +#ifdef PC + #include "tcp.h" + #include <pthread.h> +#endif + +#define COMMAND_TIMEOUT 10 /*!< Anzahl an ms, die maximal auf fehlende Daten gewartet wird */ + +#ifdef COMMAND_AVAILABLE + +#define RCVBUFSIZE (sizeof(command_t)*2) /*!< Groesse des Empfangspuffers */ + +command_t received_command; /*!< Puffer fuer Kommandos */ + +#ifdef PC + // Auf dword alignment bestehen, wird fuer MacOS X benoetigt + pthread_mutex_t command_mutex __attribute__ ((aligned (4))) + = PTHREAD_MUTEX_INITIALIZER; +#endif + +/*! + * Liest ein Kommando ein, ist blockierend! + * Greift auf low_read() zurueck + * Achtung, die Payload wird nicht mitgelesen!!! + * @see low_read() + */ +int8 command_read(void){ + int bytesRcvd; + int start=0; // start des Kommandos + int i; + command_t * command; // Pointer zum Casten der empfangegen Daten + char * ptr; // Nur zu Hilfszwecken + char buffer[RCVBUFSIZE]; // Buffer + #if BYTE_ORDER == BIG_ENDIAN + uint16 store; //Puffer für die Endian-Konvertierung + #endif + + uint16 old_ticks; // alte Systemzeit + + buffer[0]=0; // Sicherheitshalber mit sauberem Puffer anfangen + + // Daten holen, maximal soviele, wie ein Kommando lang ist + bytesRcvd=low_read(buffer,sizeof(command_t)); + + // LOG_DEBUG(("%d/%d read/av",bytesRcvd,tmp)); + // LOG_DEBUG(("%x %x %x",buffer[0],buffer[1],buffer[2])); + + // Suche nach dem Beginn des Frames + while ((start<bytesRcvd)&&(buffer[start] != CMD_STARTCODE)) { +// printf("\nStartzeichen nicht am Anfang des Puffers! (%d)\n",start); +// printf("."); + start++; + } + + // Wenn keine STARTCODE gefunden ==> Daten verwerfen + if (buffer[start] != CMD_STARTCODE){ + // LOG_DEBUG(("start not found")); + return -1; + } + + // LOG_DEBUG(("Start @%d",start)); + + // haben wir noch genug Platz im Puffer, um das Packet ferig zu lesen? + if ((RCVBUFSIZE-start) < sizeof(command_t)){ + // LOG_DEBUG(("not enough space")); +// printf("not enough space"); + return -1; // nein? ==> verwerfen + } + + i=sizeof(command_t) - (bytesRcvd-start)-1; + + + if (i> 0) { // Fehlen noch Daten ? + LOG_DEBUG(("command.c: Start @ %d es fehlen %d bytes ",start,i)); + // Systemzeit erfassen + old_ticks = TIMER_GET_TICKCOUNT_16; + + // So lange Daten lesen, bis das Packet vollstaendig ist, oder der Timeout zuschlaegt + while (i > 0){ + // Wenn der Timeout ueberschritten ist + if (TIMER_GET_TICKCOUNT_16-old_ticks > MS_TO_TICKS(COMMAND_TIMEOUT)) + return -1; // ==> Abbruch + // LOG_DEBUG(("%d bytes missing",i)); + i= low_read(buffer+bytesRcvd,i); + // LOG_DEBUG(("%d read",i)); + bytesRcvd+=i; + i=sizeof(command_t) - (bytesRcvd-start); + } + } + + // LOG_DEBUG(("%d/%d read/start",bytesRcvd,start)); + // LOG_DEBUG(("%x %x %x",buffer[start],buffer[start+1],buffer[start+2])); + + // Cast in command_t + command= (command_t *) ( buffer +start); + + // LOG_DEBUG(("start: %x ",command->startCode)); + // command_display(command); + + // validate (startcode ist bereits ok, sonst waeren wir nicht hier ) + if (command->CRC==CMD_STOPCODE){ + // LOG_DEBUG(("Command is valid")); + // Transfer + #ifdef PC + command_lock(); // on PC make storage threadsafe + #endif + ptr = (char *) &received_command; + for (i=0; i<sizeof(command_t);i++){ + *ptr=buffer[i+start]; + ptr++; + } + #if BYTE_ORDER == BIG_ENDIAN + /* Umwandeln der 16 bit Werte in Big Endian */ + store = received_command.data_l; + received_command.data_l = store << 8; + received_command.data_l |= (store >> 8) & 0xff; + + store = received_command.data_r; + received_command.data_r = store << 8; + received_command.data_r |= (store >> 8) & 0xff; + + store = received_command.seq; + received_command.seq = store << 8; + received_command.seq |= (store >> 8) & 0xff; + + /* "Umdrehen" des Bitfields */ + store = received_command.request.subcommand; + received_command.request.subcommand = store << 1; + received_command.request.direction = store >> 7; + #endif + #ifdef PC + command_unlock(); // on PC make storage threadsafe + #endif + + return 0; + } else { // Command not valid + // LOG_DEBUG(("Invalid Command:")); + // LOG_DEBUG(("%x %x %x",command->startCode,command->request.command,command->CRC)); + return -1; + } +} + +static uint16 count=1; /*!< Zaehler fuer Paket-Sequenznummer*/ + +/*! + * Uebertraegt ein Kommando und wartet nicht auf eine Antwort + * @param command Kennung zum Command + * @param subcommand Kennung des Subcommand + * @param data_l Daten fuer den linken Kanal + * @param data_r Daten fuer den rechten Kanal + * @param payload Anzahl der Bytes, die diesem Kommando als Payload folgen + */ +void command_write(uint8 command, uint8 subcommand, int16* data_l,int16* data_r,uint8 payload){ + command_t cmd; + + + cmd.startCode=CMD_STARTCODE; + cmd.request.direction=DIR_REQUEST; // Anfrage + cmd.request.command= command; + cmd.request.subcommand= subcommand; + + cmd.payload=payload; + if (data_l != NULL) + cmd.data_l = *data_l; + else + cmd.data_l = 0; + + if (data_r != NULL) + cmd.data_r = *data_r; + else + cmd.data_r = 0; + + cmd.seq=count++; + cmd.CRC=CMD_STOPCODE; + + low_write(&cmd); +} + + +/*! + * Uebertraegt ein Kommando und wartet nicht auf eine Antwort + * @param command Kennung zum Command + * @param subcommand Kennung des Subcommand + * @param data_l Daten fuer den linken Kanal + * @param data_r Daten fuer den rechten Kanal + */ +//void command_write(uint8 command, uint8 subcommand, int16* data_l,int16* data_r){ +//} + +/*! + * Gibt dem Simulator Daten mit Anhang und wartet nicht auf Antwort + * @param command Kennung zum Command + * @param subcommand Kennung des Subcommand + * @param data_l Daten fuer den linken Kanal + * @param data_r Daten fuer den rechten Kanal + * @param payload Anzahl der Bytes im Anhang + * @param data Datenanhang an das eigentliche Command + */ +void command_write_rawdata(uint8 command, uint8 subcommand, int16* data_l, int16* data_r, uint8 payload, uint8* data){ + command_write(command, subcommand, data_l, data_r,payload); + low_write_data(data, payload); +} + + +/*! + * Gibt dem Simulator Daten mit String-Anhang und wartet nicht auf Antwort + * @param command Kennung zum Command + * @param subcommand Kennung des Subcommand + * @param data_l Daten fuer den linken Kanal + * @param data_r Daten fuer den rechten Kanal + * @param data Datenanhang an das eigentliche Command + */ +void command_write_data(uint8 command, uint8 subcommand, int16* data_l, int16* data_r, const char* data){ + size_t len; + uint8 payload; + + if (data != NULL) { + len = strlen(data); + if (len > MAX_PAYLOAD) { + payload = MAX_PAYLOAD; + } else { + payload = len; + } + } else { + payload = 0; + } + + command_write(command, subcommand, data_l, data_r,payload); + low_write_data((uint8 *)data, payload); +} + +#ifdef MAUS_AVAILABLE + /*! + * Uebertraegt ein Bild vom Maussensor an den PC + */ + void transmit_mouse_picture(void){ + int16 dummy,i; + + int16 pixel; + uint8 data; + maus_image_prepare(); + + for (i=0; i<6; i++) { + dummy= i*54 +1; + command_write(CMD_SENS_MOUSE_PICTURE, SUB_CMD_NORM, &dummy , &dummy,54); + for (pixel=0; pixel <54; pixel++){ + data= maus_image_read(); + low_write_data((uint8 *)&data,1); + } + } + + } +#endif + + +/*! + * Wertet das Kommando im Puffer aus + * return 1, wenn Kommando schon bearbeitet wurde, 0 sonst + */ +int command_evaluate(void){ + uint8 analyzed = 1; + + #ifdef LOG_AVAILABLE + // command_display(&received_command); + #endif // LOG_AVAILABLE + + switch (received_command.request.command) { + #ifdef IR_AVAILABLE + case CMD_SENS_RC5: + ir_data=received_command.data_l; + break; + #endif + case CMD_AKT_LED: // LED-Steuerung + LED_set(received_command.data_l & 255); + break; + + // Einige Kommandos ergeben nur fuer reale Bots Sinn + case CMD_WELCOME: + #ifdef MCU + command_write(CMD_WELCOME, SUB_WELCOME_REAL,0,0,0); + #else + command_write(CMD_WELCOME, SUB_WELCOME_SIM,0,0,0); + #endif + break; + + + #ifdef MAUS_AVAILABLE + case CMD_SENS_MOUSE_PICTURE: // PC fragt nach dem Bild + transmit_mouse_picture(); + break; + #endif + + #ifdef BEHAVIOUR_REMOTECALL_AVAILABLE + case CMD_REMOTE_CALL: + switch (received_command.request.subcommand) { + case SUB_REMOTE_CALL_LIST: + remote_call_list(); + break; + case SUB_REMOTE_CALL_ORDER: + { + uint8 buffer[REMOTE_CALL_BUFFER_SIZE]; + low_read(buffer,received_command.payload); + bot_remotecall_from_command((uint8 *)&buffer); + + break; + } + default: + LOG_DEBUG(("unbekanntes Subkommando: %c",received_command.request.subcommand)); + break; + } + break; + #endif + + + // Einige Kommandos ergeben nur fuer simulierte Bots Sinn + #ifdef PC + case CMD_SENS_IR: + sensor_abstand(received_command.data_l,received_command.data_r); + break; + case CMD_SENS_ENC: + sensEncL+=received_command.data_l; + sensEncR+=received_command.data_r; + break; + case CMD_SENS_BORDER: + sensBorderL=received_command.data_l; + sensBorderR=received_command.data_r; + break; + case CMD_SENS_LINE: + sensLineL=received_command.data_l; + sensLineR=received_command.data_r; + break; + case CMD_SENS_LDR: + sensLDRL=received_command.data_l; + sensLDRR=received_command.data_r; + break; + case CMD_SENS_TRANS: + sensTrans=(char)received_command.data_l; + break; + #ifdef MAUS_AVAILABLE + case CMD_SENS_MOUSE: + sensMouseDX=received_command.data_l; + sensMouseDY=received_command.data_r; + break; + #endif + case CMD_SENS_ERROR: + sensError=(char)received_command.data_l; + sensor_update(); /* Error ist der letzte uebertragene Sensorwert, danach koennen wir uns um allgemeine updates kümmern*/ + break; + case CMD_DONE: + simultime=received_command.data_l; + system_time_isr(); /* Einmal pro Update-Zyklus aktualisieren wir die Systemzeit */ + // printf("X-Frame for Simultime = %d received ",simultime); + break; + #endif + default: + analyzed=0; // Command was not analysed yet + break; + } + return analyzed; +} + + + +#ifdef LOG_AVAILABLE +/*! + * Gibt ein Kommando auf dem Bildschirm aus + */ + void command_display(command_t * command){ + #ifdef PC +/* printf("START= %d\nDIR= %d CMD= %d SUBCMD= %d\nPayload= %d\nDATA = %d %d\nSeq= %d\nCRC= %d", + (*command).startCode, + (*command).request.direction, + (*command).request.command, + (*command).request.subcommand, + (*command).payload, + (*command).data_l, + (*command).data_r, + (*command).seq, + (*command).CRC); +*/ + LOG_DEBUG(("CMD: %c\tData L: %d\tSeq: %d\n", + (*command).request.command, + (*command).data_l, + (*command).seq)); + #else + LOG_DEBUG(("%x %x %x", + (*command).request.command, + (*command).data_l, + (*command).seq)); + +/* char* raw= (char*)command; + unsigned char i=0; + char hex[6]; + + display_cursor(4,1); + display_string("0x"); + to_hex(*raw,hex); + display_string(hex); + display_string(" "); + raw++; + + for (i=1; i<sizeof(command_t)-1; i++){ + to_hex(*raw++,hex); + display_string(hex); + } + + display_string(" "); + to_hex(*raw,hex); + display_string(hex); + + sprintf(hex,"%5d",(*command).seq); + display_string(" "); + display_string(hex); +*/ + #ifdef WIN32 + printf("\n"); + #endif + + #endif + } +#endif +#endif |