123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507 |
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <pthread.h>
- #include <unistd.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <sys/time.h>
- #include <sys/prctl.h>
- #include <sys/socket.h>
- #include "client.h"
- static int renderEventHandler( Tcl_Event* evPtr, int flags ){
-
- int i;
- const char* res;
- unsigned char pos;
- char type;
- const char* buf[200];
- char statusText[1024];
- struct renderEvent* render;
- struct timeval startTime;
- struct timeval endTime;
- int avgRender;
-
- //get start time
- gettimeofday( &startTime, NULL );
-
- //init some vars
- render = ( struct renderEvent* )evPtr;
- for( i = 0; i < 200; i++ ) buf[i] = "0";
-
- //render objects to buf
- for( i = 0; i < render->count * 2; i++ ){
-
- type = render->data[i];
- i++;
- pos = render->data[i];
-
- if( type == 'f' ){
- if( pos > 199 ) continue;
- buf[pos] = "1";
- }
-
- if( pos < 11 || pos > 188 ) continue;
-
- if( type == 'u' || type == 'd' ){
- buf[ pos - 1 ] = "1";
- buf[ pos ] = "1";
- buf[ pos + 1 ] = "1";
- if( type == 'u' ){
- buf[ pos - 10 ] = "1";
- buf[ pos + 9 ] = "1";
- buf[ pos + 11 ] = "1";
- } else {
- buf[ pos - 11 ] = "1";
- buf[ pos - 9 ] = "1";
- buf[ pos + 10 ] = "1";
- }
- }else if( type == 'l' || type == 'r' ){
- buf[ pos - 10 ] = "1";
- buf[ pos ] = "1";
- buf[ pos + 10 ] = "1";
- if( type == 'l' ){
- buf[ pos - 9 ] = "1";
- buf[ pos - 1 ] = "1";
- buf[ pos + 11 ] = "1";
- } else {
- buf[ pos - 11 ] = "1";
- buf[ pos + 1 ] = "1";
- buf[ pos + 9 ] = "1";
- }
- }else if( type == 'b' ){
- buf[ pos - 10 ] = "1";
- buf[ pos - 1 ] = "1";
- buf[ pos + 1 ] = "1";
- buf[ pos + 10 ] = "1";
- }else if( type == 'B' ){
- buf[ pos ] = "1";
- buf[ pos - 11 ] = "1";
- buf[ pos - 9 ] = "1";
- buf[ pos + 9 ] = "1";
- buf[ pos + 11 ] = "1";
- }
- }
-
- if( render->count ) ckfree( render->data );
-
- //"render" buffer on checkboxes
- for( i = 0; i < 200; i++ ){
- res = Tcl_SetVar( render->tcl, fieldPixelsIds[i], buf[i], TCL_GLOBAL_ONLY );
- if( !res ){
- printf( "on err\n" );
- break;
- }
- }
-
- //calculate render time
- gettimeofday( &endTime, NULL );
- render->avgRender[*render->avgIndex] = (endTime.tv_usec+((endTime.tv_sec-startTime.tv_sec)*1000000)) - startTime.tv_usec;
- (*render->avgIndex)++;
- if( *render->avgIndex == 10 ) {
- *render->avgIndex = 0;
-
- avgRender = 0;
-
- for( i = 0; i < 10; i++ ) avgRender += render->avgRender[i];
-
- avgRender /= 10;
-
- //update status bar
- sprintf( statusText, "RT: %ius", avgRender );
- Tcl_SetVar( render->tcl, "statusText", statusText, 0 );
- }
-
- return 1;
- }
- static int allertEventHandler( Tcl_Event* evPtr, int flags ){
-
- struct alertEvent* ev;
- char buf[4096];
-
- ev = (struct alertEvent*)evPtr;
-
- sprintf( buf, "tk_messageBox -type ok -icon info -title Message -message \"%s\"", ev->msg );
- Tcl_Eval( ev->tcl, buf );
-
- //ckfree( ev->msg );
-
- return 1;
- }
- static int connect2serverResult( Tcl_Event* evPtr, int flags ){
-
- struct alertEvent* ev;
- char buf[4096];
-
- ev = (struct alertEvent*)evPtr;
- sprintf( buf, "connect2serverRes \"%s\"", ev->msg );
- Tcl_Eval( ev->tcl, buf );
- //ckfree( ev->msg );
- return 1;
- }
- /*
- net proto
- server -> client
- <num objs u8> <obj desc u8> <obj pos u8> ....
- client -> server
- <intent u8> <intent desc u8>
- */
- static void networkThreadCleanup( void *arg ) {
-
- struct instance* this;
-
- this = arg;
-
- close( this->netClientSocket );
- this->netClientSocket = -1;
- }
- static void* networkThread( void* arg ){
-
- int res;
- int bytes;
- char buf[16];
- char* msg2gui;
- struct instance* this;
- struct renderEvent* ev;
- struct alertEvent* dropEv;
-
- pthread_cleanup_push( networkThreadCleanup, arg );
- prctl( PR_SET_NAME, "net", 0, 0, 0 );
-
- this = arg;
- msg2gui = "Failed to connect to server.";
-
- //connect to server
- res = connect( this->netClientSocket, (struct sockaddr*)&this->serverAddress, sizeof(this->serverAddress) );
- if( res ){
- perror( "connect" );
- goto l_connectResult;
- }
-
- //handshake
- res = write( this->netClientSocket, "TANKS", 5 );
- if( res != 5 ) goto l_connectResult;
-
- res = recv( this->netClientSocket, buf, 2, MSG_WAITALL );
- if( res != 2 ) goto l_connectResult;
-
- buf[2] = 0x00;
- if( strcmp(buf, "OK") ) goto l_connectResult;
-
- msg2gui = "0";
-
- l_connectResult:
-
- dropEv = ckalloc( sizeof(*dropEv) );
- dropEv->tclEvent.proc = connect2serverResult;
- dropEv->tcl = this->tcl;
- dropEv->msg = msg2gui;
-
- Tcl_ThreadQueueEvent( this->tclThread, (Tcl_Event*)dropEv, TCL_QUEUE_TAIL );
- Tcl_ThreadAlert( this->tclThread );
-
- if( msg2gui[0] != '0' ) goto l_exit;
-
- l_again:
-
- //obj count
- res = recv( this->netClientSocket, buf, 1, MSG_WAITALL );
- if( res != 1 ) goto l_drop;
-
- ev = ckalloc( sizeof(*ev) );
- ev->tclEvent.proc = renderEventHandler;
- ev->tcl = this->tcl;
- ev->count = buf[0];
- ev->avgRender = this->avgRender;
- ev->avgIndex = &this->avgIndex;
-
- if( buf[0] ) {
- bytes = buf[0] * 2;
- ev->data = ckalloc( bytes );
- res = recv( this->netClientSocket, ev->data, bytes, MSG_WAITALL );
- if( res != bytes ){
- ckfree( ev->data );
- ckfree( ev );
- goto l_drop;
- }
- }
-
- Tcl_ThreadQueueEvent( this->tclThread, (Tcl_Event*)ev, TCL_QUEUE_TAIL );
- Tcl_ThreadAlert( this->tclThread );
-
- goto l_again;
-
- l_drop:
- dropEv = ckalloc( sizeof(*dropEv) );
- dropEv->tclEvent.proc = allertEventHandler;
- dropEv->tcl = this->tcl;
- dropEv->msg = "Connection lost.";
-
- Tcl_ThreadQueueEvent( this->tclThread, (Tcl_Event*)dropEv, TCL_QUEUE_TAIL );
- Tcl_ThreadAlert( this->tclThread );
-
- l_exit:
- pthread_cleanup_pop( 1 );
- return NULL;
- }
- static int benchCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] ){
-
- int i;
- char* val;
- const char* res;
-
- if( objc < 2 ) return TCL_OK;
- val = Tcl_GetString( objv[1] );
- if( !val ) return TCL_OK;
-
- for( i = 0; i < 200; i++ ){
- res = Tcl_SetVar( tcl, fieldPixelsIds[i], val, TCL_GLOBAL_ONLY );
- if( !res ) return TCL_ERROR;
- }
-
- return TCL_OK;
- }
- static int connect2serverCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] ){
-
- int res;
- const char* ipStr;
- const char* portStr;
- unsigned short port;
- struct instance* this;
- struct timeval socketTimeout;
-
- this = clientData;
- socketTimeout.tv_sec = 10;
- socketTimeout.tv_usec = 0;
-
- //check already connected
- if( this->netClientSocket >= 0 ){
- Tcl_SetVar( tcl, "resmsg", "Already connected.", 0 );
- return TCL_OK;
- }
-
- //get string ip and port values from gui
- ipStr = Tcl_GetVar( tcl, "serverIp", TCL_GLOBAL_ONLY );
- portStr = Tcl_GetVar( tcl, "serverPort", TCL_GLOBAL_ONLY );
-
- //check ip not null
- if( !ipStr ){
- Tcl_SetVar( tcl, "resmsg", "Enter server IP.", 0 );
- return TCL_OK;
- }
-
- //check port not null
- if( !portStr ){
- Tcl_SetVar( tcl, "resmsg", "Enter server port.", 0 );
- return TCL_OK;
- }
-
- //set net family
- this->serverAddress.sin_family = AF_INET;
-
- //parse and check ip
- this->serverAddress.sin_addr.s_addr = inet_addr( ipStr );
- if( this->serverAddress.sin_addr.s_addr == -1 ){
- Tcl_SetVar( tcl, "resmsg", "Wrong server IP.", 0 );
- return TCL_OK;
- }
-
- //parse and check port
- res = sscanf( portStr, "%hu", &port );
- if( res != 1 ){
- Tcl_SetVar( tcl, "resmsg", "Wrong server port.", 0 );
- return TCL_OK;
- }
- this->serverAddress.sin_port = htons( port );
-
- //create socket
- this->netClientSocket = socket( AF_INET, SOCK_STREAM, 0 );
- if( this->netClientSocket < 0 ){
- perror( "socket" );
- Tcl_SetVar( tcl, "resmsg", "Create socket failed.", 0 );
- return TCL_OK;
- }
-
- //set SO_RCVTIMEO for socket
- res = setsockopt( this->netClientSocket, SOL_SOCKET, SO_RCVTIMEO, &socketTimeout, sizeof(socketTimeout) );
- if( res ){
- perror( "socket set SO_RCVTIMEO" );
- Tcl_SetVar( tcl, "resmsg", "Failed to configure socket.", 0 );
- close( this->netClientSocket );
- this->netClientSocket = -1;
- return TCL_OK;
- }
-
- //set SO_SNDTIMEO for socket
- res = setsockopt( this->netClientSocket, SOL_SOCKET, SO_SNDTIMEO, &socketTimeout, sizeof(socketTimeout) );
- if( res ){
- perror( "socket set SO_SNDTIMEO" );
- Tcl_SetVar( tcl, "resmsg", "Failed to configure socket.", 0 );
- close( this->netClientSocket );
- this->netClientSocket = -1;
- return TCL_OK;
- }
-
- //start network thread
- res = pthread_create( &this->netThread, NULL, networkThread, this );
- if( res ){
- printf( "net pthread_create: %s\n", strerror(res) );
- Tcl_SetVar( tcl, "resmsg", "Failed to start network thread.", 0 );
- close( this->netClientSocket );
- this->netClientSocket = -1;
- return TCL_OK;
- }
-
- return TCL_OK;
- }
- static int dropConnectionCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] ){
-
- struct instance* this;
-
- this = clientData;
-
- if( this->netClientSocket < 0 ) return TCL_OK;
-
- pthread_cancel( this->netThread );
- pthread_join( this->netThread, NULL );
-
- return TCL_OK;
- }
- static int tankCmdCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] ){
-
- int res;
- struct instance* this;
- char* cmd;
- char* arg;
- char pendingCmd[2];
-
- this = clientData;
-
- if( objc < 3 ) return TCL_OK;
- cmd = Tcl_GetString( objv[1] );
- arg = Tcl_GetString( objv[2] );
- if( !cmd || !arg ) return TCL_OK;
-
- pendingCmd[1] = arg[0];
- pendingCmd[0] = cmd[0];
-
- res = write( this->netClientSocket, pendingCmd, 2 );
- if( res != 2 ) perror( "socket cmd write" );
-
- return 0;
- }
- static int tankControlCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] ){
-
- int res;
- struct instance* this;
- char* key;
- char* pressed;
-
- static char oldkey;
- static char keys[3];
-
- char moveDirect[2];
-
- this = clientData;
-
- //get function args
- if( objc < 3 ) return TCL_OK;
- key = Tcl_GetString( objv[1] );
- pressed = Tcl_GetString( objv[2] );
- if( !key || !pressed ) return TCL_OK;
-
- //update keys array
- if( pressed[0] == '1' ){
- if( keys[0] != key[0] ){
- keys[2] = keys[1];
- keys[1] = keys[0];
- keys[0] = key[0];
- }
- }else{
- if( keys[0] == key[0] ){
- keys[0] = keys[1];
- keys[1] = keys[2];
- keys[2] = 0x00;
- }else if( keys[1] == key[0] ){
- keys[1] = keys[2];
- keys[2] = 0x00;
- }else if( keys[2] == key[0] ){
- keys[2] = 0x00;
- }
- }
-
- //if current key not changed, then done
- if( keys[0] == oldkey ) return 0;
-
- //update current key
- oldkey = keys[0];
-
- moveDirect[0] = 'g';//means gearbox
- moveDirect[1] = oldkey ? oldkey : 0x00;
-
- res = write( this->netClientSocket, moveDirect, 2 );
- if( res != 2 ) perror( "socket control write" );
-
- return 0;
- }
- int main ( int argc, char* argv[] ){
-
- int res;
- struct instance this;
-
- prctl( PR_SET_NAME, "main", 0, 0, 0 );
-
- this.tclThread = Tcl_GetCurrentThread();
- this.netClientSocket = -1;
- //this.pendingCmd[0] = 0x00;
- //this.moveDirect[0] = 0x00;
- this.avgIndex = 0;
-
- Tcl_FindExecutable( argv[0] );
-
- //create and init tcl/tk
- this.tcl = Tcl_CreateInterp();
- Tcl_Init( this.tcl );
- Tk_Init( this.tcl );
-
- //load main window layout
- res = Tcl_EvalFile( this.tcl, "mainWindow.tcl" );
- if( res ){
- printf( "failed to eval mainWindow.tcl\n" );
- goto l_cleanup;
- }
-
- //setup callbacks for functions in tcl
- Tcl_CreateObjCommand( this.tcl, "bench1_core", benchCore, &this, NULL );
- Tcl_CreateObjCommand( this.tcl, "connect2serverCore", connect2serverCore, &this, NULL );
- Tcl_CreateObjCommand( this.tcl, "dropConnection", dropConnectionCore, &this, NULL );
- Tcl_CreateObjCommand( this.tcl, "tankControl", tankControlCore, &this, NULL );
- Tcl_CreateObjCommand( this.tcl, "tankCmd", tankCmdCore, &this, NULL );
-
- //mait gui loop
- Tk_MainLoop();
-
- l_cleanup:
-
- Tcl_DeleteInterp( this.tcl );
-
- printf( "Exit.\n" );
- return 0;
- }
|