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/ct-Bot.c
2007-02-11 18:32:03 +00:00

747 lines
18 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 ct-Bot.c
* @brief Demo-Hauptprogramm
* @author Benjamin Benz (bbe@heise.de)
* @date 26.12.05
*/
#include "ct-Bot.h"
#ifdef MCU
#include <avr/io.h>
#include <avr/interrupt.h>
// #include <avr/signal.h>
#include <avr/wdt.h>
#include "bot-2-pc.h"
#endif
#ifdef PC
#include "bot-2-sim.h"
#include "tcp.h"
#include "tcp-server.h"
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#endif
#ifdef TWI_AVAILABLE
#include "TWI_driver.h"
#endif
#include <string.h>
#include <stdio.h>
#include "global.h"
#include "display.h"
#include "led.h"
#include "ena.h"
#include "shift.h"
#include "delay.h"
#include "uart.h"
#include "adc.h"
#include "timer.h"
#include "sensor.h"
#include "log.h"
#include "motor.h"
#include "sensor-low.h"
#include "bot-logic/bot-logik.h"
#include "mouse.h"
#include "command.h"
#include "ir-rc5.h"
#include "rc5.h"
#include "timer.h"
#include "mmc.h"
#include "map.h"
#include "mmc-emu.h"
#include "mini-fat.h"
/* Nimmt den Status von MCU(C)SR bevor dieses Register auf 0x00 gesetzt wird */
#ifdef DISPLAY_SCREEN_RESETINFO
uint8 reset_flag;
#endif
/* Enthaelt den Start des Heaps und ermoeglicht z.B. die Berechnung des verwendeten RAMs */
#ifdef MCU
extern unsigned char __heap_start;
#endif
#ifdef TEST_AVAILABLE_COUNTER
#include <avr/eeprom.h>
uint8 resetsEEPROM __attribute__ ((section (".eeprom")))=0;
uint8 resetInfoEEPROM __attribute__ ((section (".eeprom")));
uint8 resets;
#endif
/*!
* Der Mikrocontroller und der PC-Simulator brauchen ein paar Einstellungen,
* bevor wir loslegen koennen.
*/
void init(void){
#ifdef MCU
PORTA=0; DDRA=0; //Alles Eingang alles Null
PORTB=0; DDRB=0;
PORTC=0; DDRC=0;
PORTD=0; DDRD=0;
// Watchdog aus!
wdt_disable();
timer_2_init();
// Ist das ein Power on Reset ?
#ifdef __AVR_ATmega644__
if ((MCUSR & 1) ==1 ) {
MCUSR &= ~1; // Bit loeschen
#else
if ((MCUCSR & 1) ==1 ) {
MCUCSR &= ~1; // Bit loeschen
#endif
delay(100);
asm volatile("jmp 0");
}
delay(100);
#ifdef DISPLAY_SCREEN_RESETINFO
#ifdef __AVR_ATmega644__
reset_flag = MCUSR & 0x1F; //Lese Grund fuer Reset und sichere Wert
MCUSR = 0; //setze Register auf 0x00 (loeschen)
#else
reset_flag = MCUCSR & 0x1F; //Lese Grund fuer Reset und sichere Wert
MCUCSR = 0; //setze Register auf 0x00 (loeschen)
#endif
#endif
#endif
#ifdef UART_AVAILABLE
uart_init();
#endif
#ifdef BOT_2_PC_AVAILABLE
bot_2_pc_init();
#endif
#ifdef PC
bot_2_sim_init();
#endif
#ifdef DISPLAY_AVAILABLE
display_init();
display_update=1;
#endif
#ifdef LED_AVAILABLE
LED_init();
#endif
motor_init();
bot_sens_init();
#ifdef BEHAVIOUR_AVAILABLE
bot_behave_init();
#endif
#ifdef MCU
#ifdef RC5_AVAILABLE
ir_init();
#endif
#endif
#ifdef MMC_AVAILABLE
mmc_init();
#endif
#ifdef MAUS_AVAILABLE
maus_sens_init();
#endif
#ifdef MAP_AVAILABLE
map_init();
#endif
#ifdef DISPLAY_BEHAVIOUR_AVAILABLE
behaviour_page = 1;
#endif
#ifdef TWI_AVAILABLE
Init_TWI();
Close_TWI();
#endif
}
#ifdef DISPLAY_AVAILABLE
/*!
* Zeigt ein paar Informationen an
*/
void display(void){
#ifdef DISPLAY_BEHAVIOUR_AVAILABLE
/*!
* Definitionen fuer die Verhaltensanzeige
*/
#undef TEST_AVAILABLE_COUNTER
Behaviour_t *ptr = behaviour;
int8 colcounter = 0;
int8 linecounter = 0;
int8 firstcol = 0;
#endif
#ifdef MCU
#ifndef LOG_DISPLAY_AVAILABLE
#ifdef DISPLAY_SCREENS_AVAILABLE
uint16 frei; // enthaelt im Screen 5 den freien RAM-Speicher
#endif // DISPLAY_SCREENS_AVAILABLE
#endif
#endif
#ifdef TEST_AVAILABLE_COUNTER
static int counter=0;
#endif
if (display_update >0)
#ifdef DISPLAY_SCREENS_AVAILABLE
switch (display_screen) {
case 0:
#endif
display_cursor(1,1);
display_printf("P=%03X %03X D=%03d %03d ",sensLDRL,sensLDRR,sensDistL,sensDistR);
display_cursor(2,1);
display_printf("B=%03X %03X L=%03X %03X ",sensBorderL,sensBorderR,sensLineL,sensLineR);
display_cursor(3,1);
display_printf("R=%2d %2d F=%d K=%d T=%d ",sensEncL % 10,sensEncR %10,sensError,sensDoor,sensTrans);
display_cursor(4,1);
#ifdef RC5_AVAILABLE
#ifdef MAUS_AVAILABLE
display_printf("I=%04X M=%05d %05d",RC5_Code,sensMouseX,sensMouseY);
#else
display_printf("I=%04X",RC5_Code);
#endif
#else
#ifdef MAUS_AVAILABLE
display_printf("M=%05d %05d",sensMouseX,sensMouseY);
#endif
#endif
#ifdef DISPLAY_SCREENS_AVAILABLE
break;
case 1:
#ifdef TIME_AVAILABLE
display_cursor(1,1);
display_printf("Zeit: %04d:%03d", timer_get_s(), timer_get_ms());
#endif
#ifdef BEHAVIOUR_AVAILABLE
display_cursor(2,1);
display_printf("TS=%+4d %+4d",target_speed_l,target_speed_r);
#endif
#ifdef SRF10_AVAILABLE
display_cursor(2,15);
display_printf("US%+4d",sensSRF10);
#endif
display_cursor(3,1);
display_printf("RC=%+4d %+4d",sensEncL,sensEncR);
display_cursor(4,1);
display_printf("Speed= %04d",(int16)v_center);
break;
case 2:
display_cursor(1,1);
#ifdef DISPLAY_BEHAVIOUR_AVAILABLE
/*!
* zeilenweise Anzeige der Verhalten
*/
display_printf("Verhalten (Pri/Akt)%d",behaviour_page);
colcounter = 0; linecounter = 2;
/* je nach Seitenwahl die ersten Saetze ueberlesen bis richtige Seite */
firstcol = (behaviour_page -1)*6;
/*!
* max. 3 Zeilen mit 6 Verhalten anzeigbar wegen Ueberschrift
* Seitensteuerung bei mehr Verhalten
*/
while((ptr != NULL)&& (linecounter<5)) {
if ((ptr->priority >= PRIO_VISIBLE_MIN) &&(ptr->priority <= PRIO_VISIBLE_MAX)) {
if (colcounter >= firstcol) {
display_cursor(linecounter,((colcounter % 2)* 12)+1);
#ifdef DISPLAY_DYNAMIC_BEHAVIOUR_AVAILABLE
display_printf(" %3d,%2d",ptr->priority,ptr->active);
#else
display_printf(" %3d,%2d",ptr->priority,ptr->active_new);
#endif
colcounter++;
/* bei colcounter 0 neue Zeile */
if (colcounter % 2 == 0)
linecounter++;
}
else
colcounter ++;
}
ptr = ptr->next;
}
#endif
#ifdef DISPLAY_ODOMETRIC_INFO
/* Zeige Positions- und Geschwindigkeitsdaten */
display_cursor(1,1);
display_printf("heading: %3d ",(int16)heading);
display_cursor(2,1);
display_printf("x: %3d y: %3d ",(int16)x_pos,(int16)y_pos);
display_cursor(3,1);
display_printf("v_l: %3d v_r: %3d ",(int16)v_left,(int16)v_right);
#ifdef MEASURE_MOUSE_AVAILABLE
display_cursor(4,1);
display_printf("squal: %3d v_c: %3d",maus_get_squal(),(int16)v_mou_center);
#endif
#endif
#ifdef TEST_AVAILABLE_COUNTER
display_printf("Screen 3");
display_cursor(2,1);
display_printf("count %d",counter++);
display_cursor(3,1);
display_printf("Reset-Counter %d",resets);
#endif
break;
case 3:
#ifdef DISPLAY_SCREEN_RESETINFO
display_cursor(1,1);
/* Zeige den Grund fuer Resets an */
display_printf("MCU(C)SR - Register");
display_cursor(2,1);
display_printf("PORF :%d WDRF :%d",binary(reset_flag,0),binary(reset_flag,3));
display_cursor(3,1);
display_printf("EXTRF:%d JTRF :%d",binary(reset_flag,1),binary(reset_flag,4));
display_cursor(4,1);
display_printf("BORF :%d",binary(reset_flag,2));
#endif
#ifdef DISPLAY_MMC_INFO
#ifdef MMC_INFO_AVAILABLE
{
uint32 size = 0;
uint8 csd[16];
static uint8 mmc_state= 0xFF;
uint8 dummy= mmc_init();
// hat sich was geaendert?
if (dummy!=mmc_state) {
mmc_state=dummy;
uint8 i;
for (i=0;i<16;i++)
csd[i]=0;
display_cursor(1,1);
if (mmc_state !=0){
display_printf("MMC not init (%d) ",mmc_state);
}else {
size=mmc_get_size();
mmc_read_csd(csd);
display_printf("MMC= %4d MByte ",size >> 20);
}
#ifndef MMC_WRITE_TEST_AVAILABLE
display_cursor(3,1);
for (i=0;i<16;i++){
if (i == 8) display_cursor(4,1);
if (i%2 == 0) display_printf(" ");
display_printf("%02x",csd[i]);
}
#endif // MMC_WRITE_TEST_AVAILABLE
}
#ifdef MMC_WRITE_TEST_AVAILABLE
if (mmc_state == 0){
static uint16 time = 0;
if (TIMER_GET_TICKCOUNT_16-time > MS_TO_TICKS(200)){
time = TIMER_GET_TICKCOUNT_16;
uint8 result = mmc_test();
if (result != 0){
display_cursor(3,1);
display_printf("mmc_test()=%u :( ", result);
}
}
}
#endif // MMC_WRITE_TEST_AVAILABLE
}
#else
#ifdef MMC_VM_AVAILABLE
#ifdef PC
display_cursor(3,1);
display_printf("mmc_emu_test() = %u ", mmc_emu_test());
#endif // PC
#endif // MMC_VM_AVAILABLE
#endif // MMC_INFO_AVAILABLE
#endif
break;
case 4:
/* Ausgabe des freien RAMs */
#ifdef MCU
#ifndef LOG_DISPLAY_AVAILABLE
frei = SP - (uint16) &__heap_start;
display_cursor(1,1);
display_printf("free RAM: %4d ",frei);
#endif
#endif
break;
}
#endif
}
#endif
#ifdef TEST_AVAILABLE
/*! Zeigt den internen Status der Sensoren mit den LEDs an */
void show_sensors(void){
uint8 led=0x00;
led_t * status = (led_t *)&led;
#ifdef TEST_AVAILABLE_ANALOG
(*status).rechts = (sensDistR >> 9) & 0x01;
(*status).links = (sensDistL >> 9) & 0x01;
(*status).rot = (sensLineL >> 9) & 0x01;
(*status).orange = (sensLineR >> 9) & 0x01;
(*status).gelb = (sensLDRL >> 9) & 0x01;
(*status).gruen = (sensLDRR >> 9) & 0x01;
(*status).tuerkis = (sensBorderL >> 9) & 0x01;
(*status).weiss = (sensBorderR >> 9) & 0x01;
#endif
#ifdef TEST_AVAILABLE_DIGITAL
(*status).rechts = sensEncR & 0x01;
(*status).links = sensEncL & 0x01;
(*status).rot = sensTrans & 0x01;
(*status).orange = sensError & 0x01;
(*status).gelb = sensDoor & 0x01;
#ifdef MAUS_AVAILABLE
(*status).gruen = (sensMouseDX >>1) & 0x01;
(*status).tuerkis = (sensMouseDY >>1) & 0x01;
#endif
#ifdef RC5_AVAILABLE
(*status).weiss = RC5_Code & 0x01;
#endif
#endif
LED_set(led);
}
#endif
#ifdef PC
/*!
* Zeigt Informationen zu den moeglichen Kommandozeilenargumenten an.
* Das Programm wird nach Anzeige des Hilfetextes per exit() beendet.
*/
void usage(void){
puts("USAGE: ct-Bot [-t host] [-T] [-h] [-s] [-M from] [-c FILE ID SIZE]");
puts("\t-t\tHostname oder IP Adresse zu der Verbunden werden soll");
puts("\t-T\tTestClient");
puts("\t-s\tServermodus");
puts("\t-M from\tKonvertiert eine Bot-map in eine PGM-Datei");
puts("\t-c \tErzeugt eine Mini-Fat-Datei fuer den Bot.");
puts("\t FILE\tDateiname");
puts("\t ID \tDie ID aus ASCII-Zeichen");
puts("\t SIZE\tDie Nutzgroesse der Datei in KByte");
puts("\t-h\tZeigt diese Hilfe an");
exit(1);
}
#endif
#ifdef MCU
/*!
* Hauptprogramm des Bots. Diese Schleife kuemmert sich um seine Steuerung.
*/
int main (void){
#endif
#ifdef PC
/*!
* Hauptprogramm des Bots. Diese Schleife kuemmert sich um seine Steuerung.
*/
int main (int argc, char *argv[]){
//Zum debuggen der Zeiten:
#ifdef DEBUG_TIMES
struct timeval start, stop;
#endif
int ch;
int start_server = 0; /*!< Wird auf 1 gesetzt, falls -s angegeben wurde */
int start_test_client =0; /*!< Wird auf 1 gesetzt, falls -T angegeben wurde */
char *hostname = NULL; /*!< Speichert den per -t uebergebenen Hostnamen zwischen */
int convert =0; /*!< Wird auf 1 gesetzt, wenn die Karte konvertiert werden soll */
int create =0; /*!< Wird auf 1 gesetzt, wenn eine neue Datei fuer Bot-mini-fat erzeugt werden soll */
char *from = NULL; /*!< Speichert den per -M uebergebenen Quellnamen zwischen */
// Die Kommandozeilenargumente komplett verarbeiten
while ((ch = getopt(argc, argv, "hsTt:M:c:")) != -1) {
switch (ch) {
case 's':
// Servermodus [-s] wird verlangt
start_server = 1;
break;
case 'T':
start_test_client=1;
break;
case 't':
// Hostname, auf dem ct-Sim laeuft wurde
// uebergeben. Der String wird in hostname
// gesichert.
{
const int len = strlen(optarg);
hostname = malloc(len + 1);
if (NULL == hostname)
exit(1);
strcpy(hostname, optarg);
}
break;
case 'M':
// Dateiname, fuer die Map wurde
// uebergeben. Der String wird in from
// gesichert.
{
int len = strlen(optarg);
from = malloc(len + 1);
if (NULL == from)
exit(1);
strcpy(from, optarg);
convert=1;
}
break;
case 'c':
// Datei fuer den Bot (mini-fat soll erzeugt werden
// Der Name wird in hostname gesichert.
{
int len = strlen(optarg);
from = malloc(len + 1);
if (NULL == from)
exit(1);
strcpy(from, optarg);
create=1;
}
break;
case 'h':
default:
// -h oder falscher Parameter, Usage anzeigen
usage();
}
}
argc -= optind;
argv += optind;
if (start_server != 0) { // Soll der TCP-Server gestartet werden?
printf("ARGV[0]= %s\n",argv[0]);
tcp_server_init();
tcp_server_run(100);
} else {
#ifdef MAP_AVAILABLE
/* Karte in pgm konvertieren */
if (convert !=0) {
printf("Konvertiere Karte %s in PGM %s\n",from,"map.pgm");
read_map(from);
map_to_pgm("map.pgm");
exit(0);
}
#endif // MAP_AVAILABLE
if (create !=0) {
printf("optind= %d argc=%d\n",optind, argc);
if (argc != 2){
usage();
exit(1);
}
char * id;
id = malloc(strlen(argv[0]));
strcpy(id,argv[0]);
char * s;
s = malloc(strlen(argv[1]));
strcpy(s,argv[1]);
int size = atoi(s);
create_mini_fat_file(from,id,size);
printf("Erstelle eine Mini-Fat-Datei (%s) mit %d kByte fuer den Bot. ID=%s \n",from,size,id);
// read_map(from);
// map_to_pgm("map.pgm");
exit(0);
}
printf("c't-Bot\n");
if (hostname)
// Hostname wurde per Kommandozeile uebergeben
tcp_hostname = hostname;
else {
// Der Zielhost wird per default durch das Macro IP definiert und
// tcp_hostname mit einer Kopie des Strings initialisiert.
tcp_hostname = malloc(strlen(IP) + 1);
if (NULL == tcp_hostname)
exit(1);
strcpy(tcp_hostname, IP);
}
if (start_test_client !=0) {
tcp_test_client_init();
tcp_test_client_run(100);
}
}
#endif
#ifdef TEST_AVAILABLE_MOTOR
uint16 calls=0; /*!< Im Testfall zaehle die Durchlaeufe */
#endif
init();
#ifdef WELCOME_AVAILABLE
display_cursor(1,1);
display_printf("c't-Roboter");
LED_set(0x00);
#ifdef LOG_AVAILABLE
LOG_DEBUG(("Hallo Welt!"));
#endif
#endif
#ifdef TEST_AVAILABLE_COUNTER
display_screen=2;
resets=eeprom_read_byte(&resetsEEPROM)+1;
eeprom_write_byte(&resetsEEPROM,resets);
/* Lege den Grund für jeden Reset im EEPROM ab */
eeprom_write_byte(&resetInfoEEPROM+resets,reset_flag);
#endif
/*! Hauptschleife des Bot */
for(;;){
#ifdef PC
receive_until_Frame(CMD_DONE);
#ifdef DEBUG_TIMES
//Zum debuggen der Zeiten:
GETTIMEOFDAY(&start, NULL);
int t1=(start.tv_sec - stop.tv_sec)*1000000 + start.tv_usec - stop.tv_usec;
printf("Done-Token (%d) in nach %d usec ",received_command.data_l,t1);
#endif
#endif
#ifdef MCU
bot_sens_isr();
#endif
#ifdef TEST_AVAILABLE
show_sensors();
#endif
// Testprogramm, dass den Bot erst links, dann rechtsrum dreht
#ifdef TEST_AVAILABLE_MOTOR
calls++;
if (calls == 1)
motor_set(BOT_SPEED_SLOW,-BOT_SPEED_SLOW);
else if (calls == 501)
motor_set(-BOT_SPEED_SLOW,BOT_SPEED_SLOW);
else if (calls== 1001)
motor_set(BOT_SPEED_STOP,BOT_SPEED_STOP);
else
#endif
// hier drin steckt der Verhaltenscode
#ifdef BEHAVIOUR_AVAILABLE
if (sensors_initialized ==1 )
bot_behave();
#ifdef LOG_AVAILABLE
//else
//LOG_DEBUG(("sens not init"));
#endif
#endif
#ifdef MCU
#ifdef BOT_2_PC_AVAILABLE
// static int16 lastTimeCom =0;
bot_2_pc_inform(); // Den PC ueber Sensorern und aktuatoren informieren
bot_2_pc_listen(); // Kommandos vom PC empfangen
// if (timer_get_s() != lastTimeCom) { // sollte genau 1x pro Sekunde zutreffen
// lastTimeCom = timer_get_s();
// }
#endif
#endif
#ifdef LOG_AVAILABLE
//LOG_DEBUG(("BOT TIME %d s", timer_get_s()));
#endif
// Alles Anzeigen
#ifdef DISPLAY_AVAILABLE
display();
#endif
#ifdef MCU
// delay(10);
#endif
#ifdef PC
command_write(CMD_DONE, SUB_CMD_NORM ,(int16*)&simultime,0,0);
flushSendBuffer();
//Zum debuggen der Zeiten:
#ifdef DEBUG_TIMES
GETTIMEOFDAY(&stop, NULL);
int t2=(stop.tv_sec - start.tv_sec)*1000000 +stop.tv_usec - start.tv_usec;
printf("Done-Token (%d) out after %d usec\n",simultime,t2);
#endif
#endif
}
/*! Falls wir das je erreichen sollten ;-) */
return 1;
}