241 lines
5.8 KiB
C
241 lines
5.8 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 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
|