This repository has been archived on 2025-03-02. You can view files and clone it, but cannot push or open issues or pull requests.
rc2007-soccer/source/ct-Bot/command.c
2007-02-11 18:32:03 +00:00

469 lines
12 KiB
C

/*
* 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