/*---------------------------------------------------------------------------- ChucK Concurrent, On-the-fly Audio Programming Language Compiler and Virtual Machine Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved. http://chuck.stanford.edu/ http://chuck.cs.princeton.edu/ 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 U.S.A. -----------------------------------------------------------------------------*/ //----------------------------------------------------------------------------- // file: ulib_std.cpp // desc: standard class library // // author: Ge Wang (ge@ccrma.stanford.edu | gewang@cs.princeton.edu) // date: Spring 2004 //----------------------------------------------------------------------------- #include "ulib_std.h" #include #include #include #include "util_buffers.h" #include "util_console.h" #include "util_math.h" #include "util_string.h" #include "util_thread.h" #include "chuck.h" #include "chuck_type.h" #include "chuck_compile.h" #include "chuck_instr.h" #if defined(__PLATFORM_WIN32__) #include int setenv( const char *n, const char *v, int i ) { return !SetEnvironmentVariable(n, v); } #else #include #endif // for ConsoleInput and StringTokenizer #include #include #include "util_thread.h" using namespace std; #ifndef __DISABLE_KBHIT__ // KBHit CK_DLL_CTOR( KBHit_ctor ); CK_DLL_DTOR( KBHit_dtor ); CK_DLL_MFUN( KBHit_on ); CK_DLL_MFUN( KBHit_off ); CK_DLL_MFUN( KBHit_state ); CK_DLL_MFUN( KBHit_hit ); CK_DLL_MFUN( KBHit_more ); CK_DLL_MFUN( KBHit_getchar ); CK_DLL_MFUN( KBHit_can_wait ); static t_CKUINT KBHit_offset_data = 0; #endif // __DISABLE_KBHIT__ #ifndef __DISABLE_PROMPTER__ // Skot functions CK_DLL_CTOR( Skot_ctor ); CK_DLL_DTOR( Skot_dtor ); CK_DLL_MFUN( Skot_prompt ); CK_DLL_MFUN( Skot_prompt2 ); CK_DLL_MFUN( Skot_more ); CK_DLL_MFUN( Skot_getLine ); CK_DLL_MFUN( Skot_can_wait ); static t_CKUINT Skot_offset_data = 0; #endif // __DISABLE_PROMPTER__ // StrTok functions CK_DLL_CTOR( StrTok_ctor ); CK_DLL_DTOR( StrTok_dtor ); CK_DLL_MFUN( StrTok_set ); CK_DLL_MFUN( StrTok_reset ); CK_DLL_MFUN( StrTok_more ); CK_DLL_MFUN( StrTok_next ); CK_DLL_MFUN( StrTok_next2 ); CK_DLL_MFUN( StrTok_get ); CK_DLL_MFUN( StrTok_get2 ); CK_DLL_MFUN( StrTok_size ); static t_CKUINT StrTok_offset_data = 0; #ifdef AJAY #include // VCR functions CK_DLL_CTOR( VCR_ctor ); CK_DLL_MFUN( VCR_load ); CK_DLL_MFUN( VCR_reset ); CK_DLL_MFUN( VCR_seek ); CK_DLL_MFUN( VCR_more ); CK_DLL_MFUN( VCR_curr ); CK_DLL_MFUN( VCR_next ); CK_DLL_MFUN( VCR_pos ); CK_DLL_MFUN( VCR_size ); CK_DLL_MFUN( VCR_name ); static t_CKUINT VCR_offset_data = 0; // Cereal functions CK_DLL_CTOR( Cereal_ctor ); CK_DLL_MFUN( Cereal_open ); CK_DLL_MFUN( Cereal_close ); CK_DLL_MFUN( Cereal_send ); CK_DLL_MFUN( Cereal_recv ); CK_DLL_MFUN( Cereal_more ); static t_CKUINT Cereal_offset_data = 0; #endif //----------------------------------------------------------------------------- // name: libstd_query() // desc: query entry point //----------------------------------------------------------------------------- DLL_QUERY libstd_query( Chuck_DL_Query * QUERY ) { // get global Chuck_Env * env = QUERY->env(); // set name QUERY->setname( QUERY, "Std" ); /*! \example std.rand2f( 100.0, 1000.0 ) => stdout; */ // register deprecate type_engine_register_deprecate( env, "std", "Std" ); // begin class QUERY->begin_class( QUERY, "Std", "Object" ); QUERY->doc_class( QUERY, "Std is a standard library in ChucK, which includes utility functions for random number generation, unit conversions, and absolute value." ); // add abs QUERY->add_sfun( QUERY, abs_impl, "int", "abs" ); QUERY->add_arg( QUERY, "int", "value" ); QUERY->doc_func( QUERY, "Return absolute value of integer. " ); // add fabs QUERY->add_sfun( QUERY, fabs_impl, "float", "fabs" ); QUERY->add_arg( QUERY, "float", "value" ); QUERY->doc_func( QUERY, "Return absolute value of float. " ); // add rand QUERY->add_sfun( QUERY, rand_impl, "int", "rand"); //! return int between 0 and RAND_MAX QUERY->doc_func( QUERY, "Generates random integer between 0 and Std.RAND_MAX. (NOTE: soon-to-be-deprecated; use Math.random2())." ); // add rand2 QUERY->add_sfun( QUERY, rand2_impl, "int", "rand2" ); //! integer between [min,max] QUERY->add_arg( QUERY, "int", "min" ); QUERY->add_arg( QUERY, "int", "max" ); QUERY->doc_func( QUERY, "Generates random integer in range [min, max]. (NOTE: soon-to-be-deprecated; use Math.random2())." ); // add rand QUERY->add_sfun( QUERY, randf_impl, "float", "randf" ); //! rand between -1.0,1.0 QUERY->doc_func( QUERY, "Generates random floating point number in the range [-1, 1]. (Note: soon-to-be-deprecated; use Math.randomf())" ); // add rand2 QUERY->add_sfun( QUERY, rand2f_impl, "float", "rand2f" ); //! rand between min and max QUERY->add_arg( QUERY, "float", "min" ); QUERY->add_arg( QUERY, "float", "max" ); QUERY->doc_func( QUERY, "Generates random floating point number in the range [min, max]. (NOTE: soon-to-be-deprecated; use Math.random2f())" ); // add srand QUERY->add_sfun( QUERY, srand_impl, "void", "srand" ); QUERY->add_arg( QUERY, "int", "seed" ); QUERY->doc_func( QUERY, "Provide a seed to the random function. Different seeds will generate very different sequences of random numbers even if the seeds are close together. " "Alternatively, a sequence of random numbers can be repeated by setting the same seed. " ); // add sgn QUERY->add_sfun( QUERY, sgn_impl, "float", "sgn" ); //! return sign of value (-1, 0, 1) QUERY->add_arg( QUERY, "float", "value" ); QUERY->doc_func( QUERY, "Computes the sign of the input as -1.0 (negative), 0 (zero), or 1.0 (positive)." ); // add system //! see \example std.ck QUERY->add_sfun( QUERY, system_impl, "int", "system" ); //! issue system command QUERY->add_arg( QUERY, "string", "cmd" ); QUERY->doc_func( QUERY, "Pass a command to be executed in the shell (requires --caution-to-the-wind command-line flag)." ); // add atoi QUERY->add_sfun( QUERY, atoi_impl, "int", "atoi" ); //! string to integer QUERY->add_arg( QUERY, "string", "value" ); QUERY->doc_func( QUERY, "Converts ascii (string) to integer (int)." ); // add atof QUERY->add_sfun( QUERY, atof_impl, "float", "atof" ); //! string to float QUERY->add_arg( QUERY, "string", "value" ); QUERY->doc_func( QUERY, "Converts ascii (string) to floating point value (float)." ); // add itoa QUERY->add_sfun( QUERY, itoa_impl, "string", "itoa" ); //! int to string QUERY->add_arg( QUERY, "int", "i" ); QUERY->doc_func( QUERY, "Converts integer (int) to ascii (string)." ); // add ftoa QUERY->add_sfun( QUERY, ftoa_impl, "string", "ftoa" ); //! float to string QUERY->add_arg( QUERY, "float", "f" ); QUERY->add_arg( QUERY, "int", "precision" ); QUERY->doc_func( QUERY, "Converts floating point value (float) to ascii (string) with specified precision (number of decimal digits)." ); // add ftoi QUERY->add_sfun( QUERY, ftoi_impl, "int", "ftoi" ); //! float to int QUERY->add_arg( QUERY, "float", "f" ); QUERY->doc_func( QUERY, "Convert float to int. " ); // add getenv QUERY->add_sfun( QUERY, getenv_impl, "string", "getenv" ); //! fetch environment variable QUERY->add_arg( QUERY, "string", "value" ); QUERY->doc_func( QUERY, "Returns the value of an environment variable, such as of PATH." ); // add setenv QUERY->add_sfun( QUERY, setenv_impl, "int", "setenv" ); //! set environment variable QUERY->add_arg( QUERY, "string", "key" ); QUERY->add_arg( QUERY, "string", "value" ); QUERY->doc_func( QUERY, "Set value of environment variable named key to value." ); // add mtof //! see \example mand-o-matic.ck QUERY->add_sfun( QUERY, mtof_impl, "float", "mtof" ); //! midi note to frequency QUERY->add_arg( QUERY, "float", "value" ); QUERY->doc_func( QUERY, "Converts a MIDI note number to frequency (Hz). Note the input value is of type float (supports fractional note number)." ); // add ftom QUERY->add_sfun( QUERY, ftom_impl, "float", "ftom" ); //! frequency to midi note QUERY->add_arg( QUERY, "float", "value" ); QUERY->doc_func( QUERY, "Converts frequency (Hz) to MIDI note number space." ); // add powtodb QUERY->add_sfun( QUERY, powtodb_impl, "float", "powtodb" ); //! linear power to decibel QUERY->add_arg( QUERY, "float", "value" ); QUERY->doc_func( QUERY, "Converts signal power ratio to decibels (dB)." ); // add rmstodb QUERY->add_sfun( QUERY, rmstodb_impl, "float", "rmstodb" ); //! rms to decibel QUERY->add_arg( QUERY, "float", "value" ); QUERY->doc_func( QUERY, "Converts rms to decibels (dB)." ); // add dbtopow QUERY->add_sfun( QUERY, dbtopow_impl, "float", "dbtopow" ); //! decibel to linear QUERY->add_arg( QUERY, "float", "value" ); QUERY->doc_func( QUERY, "Converts decibels (dB) to signal power ratio." ); // add dbtorms QUERY->add_sfun( QUERY, dbtorms_impl, "float", "dbtorms" ); //! decibel to rms QUERY->add_arg( QUERY, "float", "value" ); QUERY->doc_func( QUERY, "Convert " ); // add dbtolin QUERY->add_sfun( QUERY, dbtolin_impl, "float", "dbtolin" ); //! decibel to linear QUERY->add_arg( QUERY, "float", "value" ); QUERY->doc_func( QUERY, "" ); // add lintodb QUERY->add_sfun( QUERY, lintodb_impl, "float", "lintodb" ); //! linear to decibel QUERY->add_arg( QUERY, "float", "value" ); QUERY->doc_func( QUERY, "" ); // add clamp QUERY->add_sfun( QUERY, clamp_impl, "int", "clamp" ); //! clamp to range (int) QUERY->add_arg( QUERY, "int", "value" ); QUERY->add_arg( QUERY, "int", "min" ); QUERY->add_arg( QUERY, "int", "max" ); QUERY->doc_func( QUERY, "" ); // add clampf QUERY->add_sfun( QUERY, clampf_impl, "float", "clampf" ); //! clamp to range (float) QUERY->add_arg( QUERY, "float", "value" ); QUERY->add_arg( QUERY, "float", "min" ); QUERY->add_arg( QUERY, "float", "max" ); QUERY->doc_func( QUERY, "" ); // add scalef QUERY->add_sfun( QUERY, scalef_impl, "float", "scalef" ); //! scale from source range to dest range (float) QUERY->add_arg( QUERY, "float", "value" ); QUERY->add_arg( QUERY, "float", "srcmin" ); QUERY->add_arg( QUERY, "float", "srcmax" ); QUERY->add_arg( QUERY, "float", "dstmin" ); QUERY->add_arg( QUERY, "float", "dstmax" ); QUERY->doc_func( QUERY, "" ); // finish class QUERY->end_class( QUERY ); // seed the rand srand( time( NULL ) ); Chuck_DL_Func * func = NULL; #ifndef __DISABLE_KBHIT__ // KBHit // begin class (KBHit) if( !type_engine_import_class_begin( env, "KBHit", "Event", env->global(), KBHit_ctor, KBHit_dtor ) ) return FALSE; // add member variable KBHit_offset_data = type_engine_import_mvar( env, "int", "@KBHit_data", FALSE ); if( KBHit_offset_data == CK_INVALID_OFFSET ) goto error; // add on() func = make_new_mfun( "void", "on", KBHit_on ); if( !type_engine_import_mfun( env, func ) ) goto error; // add off() func = make_new_mfun( "void", "off", KBHit_off ); if( !type_engine_import_mfun( env, func ) ) goto error; // add state() func = make_new_mfun( "void", "state", KBHit_state ); if( !type_engine_import_mfun( env, func ) ) goto error; // add hit() func = make_new_mfun( "Event", "hit", KBHit_hit ); if( !type_engine_import_mfun( env, func ) ) goto error; // add more() func = make_new_mfun( "int", "more", KBHit_more ); if( !type_engine_import_mfun( env, func ) ) goto error; // add getchar() func = make_new_mfun( "int", "getchar", KBHit_getchar ); if( !type_engine_import_mfun( env, func ) ) goto error; // add can_wait() func = make_new_mfun( "int", "can_wait", KBHit_can_wait ); if( !type_engine_import_mfun( env, func ) ) goto error; // end class type_engine_import_class_end( env ); // start it KBHitManager::init(); #endif // __DISABLE_KBHIT__ // register deprecate type_engine_register_deprecate( env, "Skot", "ConsoleInput" ); #ifndef __DISABLE_PROMPTER__ // begin class (Skot) if( !type_engine_import_class_begin( env, "ConsoleInput", "Event", env->global(), Skot_ctor, Skot_dtor ) ) return FALSE; // add member variable Skot_offset_data = type_engine_import_mvar( env, "int", "@Skot_data", FALSE ); if( Skot_offset_data == CK_INVALID_OFFSET ) goto error; // add prompt() func = make_new_mfun( "Event", "prompt", Skot_prompt ); if( !type_engine_import_mfun( env, func ) ) goto error; // add prompt() func = make_new_mfun( "Event", "prompt", Skot_prompt2 ); func->add_arg( "string", "what" ); if( !type_engine_import_mfun( env, func ) ) goto error; // add ready() func = make_new_mfun( "int", "more", Skot_more ); if( !type_engine_import_mfun( env, func ) ) goto error; // add getString() func = make_new_mfun( "string", "getLine", Skot_getLine ); if( !type_engine_import_mfun( env, func ) ) goto error; // add can_wait() func = make_new_mfun( "int", "can_wait", Skot_can_wait ); if( !type_engine_import_mfun( env, func ) ) goto error; // end class type_engine_import_class_end( env ); #endif // __DISABLE_PROMPTER__ // register deprecate type_engine_register_deprecate( env, "PRC", "StringTokenizer" ); // begin class (StrTok) if( !type_engine_import_class_begin( env, "StringTokenizer", "Object", env->global(), StrTok_ctor, StrTok_dtor ) ) return FALSE; // add member variable StrTok_offset_data = type_engine_import_mvar( env, "int", "@StrTok_data", FALSE ); if( StrTok_offset_data == CK_INVALID_OFFSET ) goto error; // add set() func = make_new_mfun( "void", "set", StrTok_set ); func->add_arg( "string", "line" ); if( !type_engine_import_mfun( env, func ) ) goto error; // add reset() func = make_new_mfun( "void", "reset", StrTok_reset ); if( !type_engine_import_mfun( env, func ) ) goto error; // add more() func = make_new_mfun( "int", "more", StrTok_more ); if( !type_engine_import_mfun( env, func ) ) goto error; // add next() func = make_new_mfun( "string", "next", StrTok_next ); if( !type_engine_import_mfun( env, func ) ) goto error; // add get() func = make_new_mfun( "string", "next", StrTok_next2 ); func->add_arg( "string", "out" ); if( !type_engine_import_mfun( env, func ) ) goto error; // add get() func = make_new_mfun( "string", "get", StrTok_get ); func->add_arg( "int", "index" ); if( !type_engine_import_mfun( env, func ) ) goto error; // add get() func = make_new_mfun( "string", "get", StrTok_get2 ); func->add_arg( "int", "index" ); func->add_arg( "string", "out" ); if( !type_engine_import_mfun( env, func ) ) goto error; // add size() func = make_new_mfun( "int", "size", StrTok_size ); if( !type_engine_import_mfun( env, func ) ) goto error; // end class type_engine_import_class_end( env ); #ifdef AJAY // begin class // init base class if( !type_engine_import_class_begin( env, "VCR", "Object", env->global(), VCR_ctor ) ) return FALSE; // add member variable VCR_offset_data = type_engine_import_mvar( env, "int", "@me", FALSE ); if( VCR_offset_data == CK_INVALID_OFFSET ) goto error; // add load() func = make_new_mfun( "int", "load", VCR_load ); func->add_arg( "string", "filename" ); func->add_arg( "int", "column" ); if( !type_engine_import_mfun( env, func ) ) goto error; // add reset() func = make_new_mfun( "int", "reset", VCR_reset ); if( !type_engine_import_mfun( env, func ) ) goto error; // add seek() func = make_new_mfun( "int", "seek", VCR_seek ); func->add_arg( "int", "where" ); if( !type_engine_import_mfun( env, func ) ) goto error; // add more() func = make_new_mfun( "int", "more", VCR_more ); if( !type_engine_import_mfun( env, func ) ) goto error; // add curr() func = make_new_mfun( "float", "curr", VCR_curr ); if( !type_engine_import_mfun( env, func ) ) goto error; // add next() func = make_new_mfun( "int", "next", VCR_next ); if( !type_engine_import_mfun( env, func ) ) goto error; // add pos() func = make_new_mfun( "int", "pos", VCR_pos ); if( !type_engine_import_mfun( env, func ) ) goto error; // add size() func = make_new_mfun( "int", "size", VCR_size ); if( !type_engine_import_mfun( env, func ) ) goto error; // add name() func = make_new_mfun( "string", "name", VCR_name ); if( !type_engine_import_mfun( env, func ) ) goto error; // end the class import type_engine_import_class_end( env ); #if defined(__PLATFORM_WIN32__) // begin class (Cereal) if( !type_engine_import_class_begin( env, "Cereal", "Object", env->global(), Cereal_ctor ) ) return FALSE; // add member Cereal_offset_data = type_engine_import_mvar( env, "int", "@Cereal_data", FALSE ); if( Cereal_offset_data == CK_INVALID_OFFSET ) goto error; // add open() func = make_new_mfun( "int", "open", Cereal_open ); func->add_arg( "string", "name" ); func->add_arg( "int", "baudrate" ); if( !type_engine_import_mfun( env, func ) ) goto error; // add close() func = make_new_mfun( "void", "close", Cereal_close ); if( !type_engine_import_mfun( env, func ) ) goto error; // add more() func = make_new_mfun( "int", "more", Cereal_more ); if( !type_engine_import_mfun( env, func ) ) goto error; // add send() func = make_new_mfun( "int", "send", Cereal_send ); func->add_arg( "int", "bite" ); if( !type_engine_import_mfun( env, func ) ) goto error; // add recv() func = make_new_mfun( "int", "recv", Cereal_recv ); if( !type_engine_import_mfun( env, func ) ) goto error; // end class type_engine_import_class_end( env ); #endif return TRUE; #else return TRUE; #endif error: // end the class import type_engine_import_class_end( env ); return FALSE; } #define RAND_INV_RANGE(r) (RAND_MAX / (r)) int irand_exclusive ( int max ) { int x = ::rand(); while (x >= max * RAND_INV_RANGE (max)) x = ::rand(); x /= RAND_INV_RANGE (max); return x; } // abs CK_DLL_SFUN( abs_impl ) { t_CKINT v = GET_CK_INT(ARGS); RETURN->v_int = v >= 0 ? v : -v; } // fabs CK_DLL_SFUN( fabs_impl ) { t_CKFLOAT v = GET_CK_FLOAT(ARGS); RETURN->v_float = v >= 0.0 ? v : -v; //RETURN->v_float = ::fabs( GET_CK_FLOAT(ARGS) ); } // rand CK_DLL_SFUN( rand_impl ) { RETURN->v_int = ::rand(); } // randf CK_DLL_SFUN( randf_impl ) { RETURN->v_float = ( 2.0 * ::rand() / (t_CKFLOAT)RAND_MAX - 1.0 ); } // randf CK_DLL_SFUN( rand2f_impl ) { t_CKFLOAT min = GET_CK_FLOAT(ARGS), max = *((t_CKFLOAT *)ARGS + 1); RETURN->v_float = min + (max-min)*(::rand()/(t_CKFLOAT)RAND_MAX); } // randi CK_DLL_SFUN( rand2_impl ) // inclusive. { // 1.3.1.0: converted int to t_CKINT for 64-bit compatibility t_CKINT min = *(t_CKINT *)ARGS, max = *((t_CKINT *)ARGS + 1); t_CKINT range = max - min; if ( range == 0 ) { RETURN->v_int = min; } //else if ( range < RAND_MAX / 2 ) { // RETURN->v_int = ( range > 0 ) ? min + irand_exclusive(1 + range) : max + irand_exclusive ( -range + 1 ) ; //} else { if( range > 0 ) { RETURN->v_int = min + (t_CKINT)( (1.0 + range) * ( ::rand()/(RAND_MAX+1.0) ) ); } else { RETURN->v_int = min - (t_CKINT)( (-range + 1.0) * ( ::rand()/(RAND_MAX+1.0) ) ); } } } // srand CK_DLL_SFUN( srand_impl ) { t_CKINT seed = GET_CK_INT(ARGS); ::srand( seed ); } // sgn CK_DLL_SFUN( sgn_impl ) { t_CKFLOAT v = GET_CK_FLOAT(ARGS); RETURN->v_float = v == 0.0f ? 0.0f : ( v > 0.0f ? 1.0f : -1.0f ); } // system CK_DLL_SFUN( system_impl ) { const char * cmd = GET_CK_STRING(ARGS)->str().c_str(); // check globals for permission if( !ChucK::enableSystemCall ) { CK_FPRINTF_STDERR( "[chuck]:error: VM not authorized to call Std.system( string )...\n" ); CK_FPRINTF_STDERR( "[chuck]: (command string was: \"%s\")\n", cmd ); CK_FPRINTF_STDERR( "[chuck]: (note: enable via --caution-to-the-wind flag or other means)\n" ); RETURN->v_int = 0; } else { // log EM_log( CK_LOG_SEVERE, "invoking system( CMD )..." ); EM_pushlog(); EM_log( CK_LOG_SEVERE, "CMD: \"%s\"", cmd ); EM_poplog(); RETURN->v_int = system( cmd ); } } // aoti CK_DLL_SFUN( atoi_impl ) { Chuck_String * str = GET_CK_STRING(ARGS); if( str ) { const char * v = str->str().c_str(); RETURN->v_int = atoi( v ); } else { RETURN->v_int = 0; } } // atof CK_DLL_SFUN( atof_impl ) { Chuck_String * str = GET_CK_STRING(ARGS); if( str ) { const char * v = GET_CK_STRING(ARGS)->str().c_str(); RETURN->v_float = atof( v ); } else { RETURN->v_float = 0.0; } } // itoa CK_DLL_SFUN( itoa_impl ) { t_CKINT i = GET_CK_INT(ARGS); // TODO: memory leak, please fix. Thanks. Chuck_String * a = (Chuck_String *)instantiate_and_initialize_object( SHRED->vm_ref->env()->t_string, SHRED ); a->set( itoa( i ) ); RETURN->v_string = a; } // ftoa CK_DLL_SFUN( ftoa_impl ) { t_CKFLOAT f = GET_NEXT_FLOAT(ARGS); t_CKINT p = GET_NEXT_INT(ARGS); Chuck_String * a = (Chuck_String *)instantiate_and_initialize_object( SHRED->vm_ref->env()->t_string, SHRED ); a->set( ftoa( f, (t_CKUINT)p ) ); RETURN->v_string = a; } // ftoi CK_DLL_SFUN( ftoi_impl ) { t_CKFLOAT f = GET_NEXT_FLOAT(ARGS); RETURN->v_int = (t_CKINT) f; } // getenv static Chuck_String g_str; // PROBLEM: not thread friendly CK_DLL_SFUN( getenv_impl ) { const char * v = GET_CK_STRING(ARGS)->str().c_str(); const char * s = getenv( v ); Chuck_String * a = (Chuck_String *)instantiate_and_initialize_object( SHRED->vm_ref->env()->t_string, SHRED ); a->set( s ? s : "" ); RETURN->v_string = a; } // setenv CK_DLL_SFUN( setenv_impl ) { const char * v1 = GET_NEXT_STRING(ARGS)->str().c_str(); const char * v2 = GET_NEXT_STRING(ARGS)->str().c_str(); RETURN->v_int = setenv( v1, v2, 1 ); } // mtof CK_DLL_SFUN( mtof_impl ) { t_CKFLOAT v = GET_CK_FLOAT(ARGS); RETURN->v_float = mtof(v); } // ftom CK_DLL_SFUN( ftom_impl ) { t_CKFLOAT v = GET_CK_FLOAT(ARGS); RETURN->v_float = ftom(v); } // powtodb CK_DLL_SFUN( powtodb_impl ) { t_CKFLOAT v = GET_CK_FLOAT(ARGS); RETURN->v_float = powtodb(v); } // rmstodb CK_DLL_SFUN( rmstodb_impl ) { t_CKFLOAT v = GET_CK_FLOAT(ARGS); RETURN->v_float = rmstodb(v); } // dbtopow CK_DLL_SFUN( dbtopow_impl ) { t_CKFLOAT v = GET_CK_FLOAT(ARGS); RETURN->v_float = dbtopow(v); } // dbtorms CK_DLL_SFUN( dbtorms_impl ) { t_CKFLOAT v = GET_CK_FLOAT(ARGS); RETURN->v_float = dbtorms(v); } CK_DLL_SFUN( dbtolin_impl ) { t_CKFLOAT v = GET_CK_FLOAT(ARGS); RETURN->v_float = pow(10.0, v/20.0); } CK_DLL_SFUN( lintodb_impl ) { t_CKFLOAT v = GET_CK_FLOAT(ARGS); RETURN->v_float = 20.0*log10(v); } CK_DLL_SFUN( clamp_impl ) { t_CKINT v = GET_NEXT_INT(ARGS); t_CKINT min = GET_NEXT_INT(ARGS); t_CKINT max = GET_NEXT_INT(ARGS); if(v < min) RETURN->v_int = min; else if( v > max) RETURN->v_int = max; else RETURN->v_int = v; } CK_DLL_SFUN( clampf_impl ) { t_CKFLOAT v = GET_NEXT_FLOAT(ARGS); t_CKFLOAT min = GET_NEXT_FLOAT(ARGS); t_CKFLOAT max = GET_NEXT_FLOAT(ARGS); if(v < min) RETURN->v_float = min; else if( v > max) RETURN->v_float = max; else RETURN->v_float = v; } CK_DLL_SFUN( scalef_impl ) { t_CKFLOAT v = GET_NEXT_FLOAT(ARGS); t_CKFLOAT srcmin = GET_NEXT_FLOAT(ARGS); t_CKFLOAT srcmax = GET_NEXT_FLOAT(ARGS); t_CKFLOAT dstmin = GET_NEXT_FLOAT(ARGS); t_CKFLOAT dstmax = GET_NEXT_FLOAT(ARGS); RETURN->v_float = dstmin + (dstmax-dstmin) * ((v-srcmin)/(srcmax-srcmin)); } #ifndef __DISABLE_KBHIT__ // static CBufferAdvance * KBHitManager::the_buf = NULL; t_CKINT KBHitManager::the_onoff = 0; t_CKBOOL KBHitManager::the_init = FALSE; XThread * KBHitManager::the_thread; #define BUFFER_SIZE 1024 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__) static void * kb_loop( void * ) #else static unsigned int __stdcall kb_loop( void * ) #endif { t_CKINT c; EM_log( CK_LOG_INFO, "starting kb loop..." ); // go while( KBHitManager::the_init ) { // if on if( KBHitManager::the_onoff ) { // see if we have kb hit while( kb_hit() ) { // get the next char c = kb_getch(); // queue it KBHitManager::the_buf->put( &c, 1 ); } } // wait usleep( 5000 ); } return 0; } // init t_CKBOOL KBHitManager::init() { // sanity check if( the_buf ) return FALSE; EM_log( CK_LOG_INFO, "initializing KBHitManager..." ); the_buf = new CBufferAdvance; if( !the_buf->initialize( BUFFER_SIZE, sizeof(t_CKINT) ) ) { EM_log( CK_LOG_SEVERE, "KBHitManager: couldn't allocate central KB buffer..." ); SAFE_DELETE( the_buf ); return FALSE; } the_onoff = 0; the_init = TRUE; the_thread = new XThread; the_thread->start( kb_loop, NULL ); return TRUE; } // shutdown void KBHitManager::shutdown() { EM_log( CK_LOG_INFO, "shutting down KBHitManager..." ); SAFE_DELETE( the_buf ); kb_endwin(); the_onoff = 0; the_init = FALSE; } // on() void KBHitManager::on() { the_onoff++; if( !kb_ready() ) kb_initscr(); } // off() void KBHitManager::off() { the_onoff--; if( kb_ready() && the_onoff == 0 ) kb_endwin(); } // open() t_CKBOOL KBHitManager::open( KBHit * kb ) { if( the_buf == NULL ) return FALSE; if( kb->m_buffer != NULL ) return FALSE; EM_log( CK_LOG_INFO, "adding KBHit..." ); // init the kb kb->m_buffer = the_buf; // read index kb->m_read_index = kb->m_buffer->join( (Chuck_Event *)kb->SELF ); return TRUE; } // close() t_CKBOOL KBHitManager::close( KBHit * kb ) { if( the_buf == NULL ) return FALSE; if( kb->m_buffer == NULL ) return FALSE; EM_log( CK_LOG_INFO, "removing KBHit..." ); // unjoin kb->m_buffer->resign( kb->m_read_index ); // done kb->m_read_index = 0; return TRUE; } // KBHit KBHit::KBHit() { m_buffer = NULL; m_read_index = 0; m_valid = FALSE; m_onoff = FALSE; m_echo = FALSE; SELF = NULL; } // ~KBHit() KBHit::~KBHit() { this->close(); } // open() t_CKBOOL KBHit::open() { return KBHitManager::open( this ); } // close() t_CKBOOL KBHit::close() { return KBHitManager::close( this ); } // on() void KBHit::on() { if( m_onoff == FALSE ) { KBHitManager::on(); open(); m_onoff = TRUE; } } // off() void KBHit::off() { if( m_onoff == TRUE ) { KBHitManager::off(); open(); m_onoff = FALSE; } } // empty t_CKBOOL KBHit::empty() { if( m_buffer == NULL ) return TRUE; if( m_onoff == FALSE ) return TRUE; // if( m_read_index == 0 ) return TRUE; return m_buffer->empty( m_read_index ); } // getch t_CKINT KBHit::getch() { t_CKINT c; if( empty() ) return 0; m_buffer->get( &c, 1, m_read_index ); return c; } // ctor CK_DLL_CTOR( KBHit_ctor ) { KBHit * kb = new KBHit; OBJ_MEMBER_INT(SELF, KBHit_offset_data) = (t_CKINT)kb; kb->SELF = SELF; kb->on(); } // dtor CK_DLL_DTOR( KBHit_dtor ) { delete (KBHit *)OBJ_MEMBER_INT(SELF, KBHit_offset_data); OBJ_MEMBER_INT(SELF, KBHit_offset_data) = 0; } // on CK_DLL_MFUN( KBHit_on ) { KBHit * kb = (KBHit *)(OBJ_MEMBER_INT(SELF, KBHit_offset_data)); kb->on(); } // off CK_DLL_MFUN( KBHit_off ) { KBHit * kb = (KBHit *)(OBJ_MEMBER_INT(SELF, KBHit_offset_data)); kb->off(); } // state CK_DLL_MFUN( KBHit_state ) { KBHit * kb = (KBHit *)(OBJ_MEMBER_INT(SELF, KBHit_offset_data)); RETURN->v_int = kb->state(); } // hit CK_DLL_MFUN( KBHit_hit ) { //KBHit * kb = (KBHit *)(OBJ_MEMBER_INT(SELF, KBHit_offset_data)); RETURN->v_object = SELF; } // more CK_DLL_MFUN( KBHit_more ) { KBHit * kb = (KBHit *)(OBJ_MEMBER_INT(SELF, KBHit_offset_data)); RETURN->v_int = (kb->empty() == FALSE); } // getchar CK_DLL_MFUN( KBHit_getchar ) { KBHit * kb = (KBHit *)(OBJ_MEMBER_INT(SELF, KBHit_offset_data)); RETURN->v_int = kb->getch(); } // can wait CK_DLL_MFUN( KBHit_can_wait ) { KBHit * kb = (KBHit *)(OBJ_MEMBER_INT(SELF, KBHit_offset_data)); RETURN->v_int = kb->empty(); } #endif // __DISABLE_KBHIT__ #ifndef __DISABLE_PROMPTER__ class LineEvent : public Chuck_Event { public: LineEvent( Chuck_Event * SELF ); ~LineEvent(); public: void prompt( const string & what = "" ); t_CKBOOL more(); string getLine(); t_CKBOOL can_wait(); void enqueue( const string & line ) { m_q.push( line ); } Chuck_Event * SELF; protected: queue m_q; }; // global variables t_CKBOOL g_le_launched = FALSE; t_CKBOOL g_le_wait = TRUE; CHUCK_THREAD g_le_thread = 0; map g_le_map; XMutex g_le_mutex; string g_le_what; // final cleanup (per host) void le_cleanup() { if( g_le_thread ) { // cancel thread #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__) pthread_cancel( g_le_thread ); #else CloseHandle( g_le_thread ); #endif g_le_thread = 0; // reset g_le_launched = FALSE; g_le_wait = TRUE; } } // le callback void * le_cb( void * p ) { char line[2048]; map::iterator iter; LineEvent * le = NULL; // loop while( true ) { // wait while( g_le_wait ) usleep( 10000 ); // REFACTOR-2017: TODO Ge: // I removed the check here for if there are no more vms running // Theoretically, we will always just kill this thread from outside of // it. Does that sound right to you? // do the prompt cout << g_le_what; cout.flush(); if( !cin.getline( line, 2048 ) ) break; // lock g_le_mutex.acquire(); // go through for( iter = g_le_map.begin(); iter != g_le_map.end(); iter++ ) { // get the line event le = (*iter).first; // add to its queue le->enqueue( line ); // broadcast it le->SELF->queue_broadcast(); } // unlock g_le_mutex.release(); // reset wait g_le_wait = TRUE; } return NULL; } LineEvent::LineEvent( Chuck_Event * SELF ) { // launch the cb if( !g_le_launched ) { #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__) pthread_create( &g_le_thread, NULL, le_cb, NULL ); #else g_le_thread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)le_cb, NULL, 0, 0 ); #endif g_le_launched = TRUE; } // lock g_le_mutex.acquire(); // add g_le_map[this] = this; this->SELF = SELF; // unlock g_le_mutex.release(); } LineEvent::~LineEvent() { // remove from global map g_le_map.erase( this ); } void LineEvent::prompt( const string & what ) { // set what g_le_what = what; if( g_le_what != "" ) g_le_what += " "; // signal g_le_wait = FALSE; } t_CKBOOL LineEvent::more() { // more return m_q.size() > 0; } string LineEvent::getLine() { string ret; // lock g_le_mutex.acquire(); // get next line if( m_q.size() ) { // get it ret = m_q.front(); // dequeue it m_q.pop(); } else { ret = "[ERROR -> getLine() called on empty Skot]"; } // unlock g_le_mutex.release(); return ret; } t_CKBOOL LineEvent::can_wait() { return !more(); } // Skot CK_DLL_CTOR( Skot_ctor ) { LineEvent * le = new LineEvent((Chuck_Event *)SELF); OBJ_MEMBER_INT(SELF, Skot_offset_data) = (t_CKINT)le; } CK_DLL_DTOR( Skot_dtor ) { delete (LineEvent *)OBJ_MEMBER_INT(SELF, Skot_offset_data); OBJ_MEMBER_INT(SELF, Skot_offset_data) = 0; } CK_DLL_MFUN( Skot_prompt ) { LineEvent * le = (LineEvent *)OBJ_MEMBER_INT(SELF, Skot_offset_data); le->prompt(); RETURN->v_int = (t_CKINT)(SELF); } CK_DLL_MFUN( Skot_prompt2 ) { LineEvent * le = (LineEvent *)OBJ_MEMBER_INT(SELF, Skot_offset_data); const char * v = GET_CK_STRING(ARGS)->str().c_str(); le->prompt( v ); RETURN->v_int = (t_CKINT)(SELF); } CK_DLL_MFUN( Skot_more ) { LineEvent * le = (LineEvent *)OBJ_MEMBER_INT(SELF, Skot_offset_data); RETURN->v_int = le->more(); } CK_DLL_MFUN( Skot_getLine ) { LineEvent * le = (LineEvent *)OBJ_MEMBER_INT(SELF, Skot_offset_data); // TODO: memory leak Chuck_String * a = (Chuck_String *)instantiate_and_initialize_object( SHRED->vm_ref->env()->t_string, SHRED ); a->set( le->getLine() ); RETURN->v_string = a; } CK_DLL_MFUN( Skot_can_wait ) { LineEvent * le = (LineEvent *)OBJ_MEMBER_INT(SELF, Skot_offset_data); RETURN->v_int = le->can_wait(); } #endif // __DISABLE_PROMPTER__ // StrTok class StrTok { public: StrTok(); ~StrTok(); public: void set( const string & line ); void reset(); t_CKBOOL more(); string next(); string get( t_CKINT index ); t_CKINT size(); protected: istringstream * m_ss; string m_next; vector m_tokens; vector::size_type m_index; }; StrTok::StrTok() { m_ss = NULL; m_index = 0; } StrTok::~StrTok() { SAFE_DELETE( m_ss ); } void StrTok::set( const string & line ) { string s; // delete SAFE_DELETE( m_ss ); // alloc m_ss = new istringstream( line ); // read reset(); m_tokens.clear(); while( (*m_ss) >> s ) m_tokens.push_back( s ); } void StrTok::reset() { m_index = 0; } t_CKBOOL StrTok::more() { return m_index < m_tokens.size(); } string StrTok::next() { if( !more() ) return ""; return m_tokens[m_index++]; } string StrTok::get( t_CKINT index ) { if( index >= (t_CKINT)m_tokens.size() ) return ""; return m_tokens[index]; } t_CKINT StrTok::size() { return (t_CKINT)m_tokens.size(); } CK_DLL_CTOR( StrTok_ctor ) { StrTok * tokens = new StrTok; OBJ_MEMBER_INT(SELF, StrTok_offset_data) = (t_CKINT)tokens; } CK_DLL_DTOR( StrTok_dtor ) { delete (StrTok *)OBJ_MEMBER_INT(SELF, StrTok_offset_data); OBJ_MEMBER_INT(SELF, StrTok_offset_data) = 0; } CK_DLL_MFUN( StrTok_set ) { StrTok * tokens = (StrTok *)OBJ_MEMBER_INT(SELF, StrTok_offset_data); Chuck_String * s = GET_CK_STRING(ARGS); if( s ) tokens->set( s->str() ); else tokens->set( "" ); } CK_DLL_MFUN( StrTok_reset ) { StrTok * tokens = (StrTok *)OBJ_MEMBER_INT(SELF, StrTok_offset_data); tokens->reset(); } CK_DLL_MFUN( StrTok_more ) { StrTok * tokens = (StrTok *)OBJ_MEMBER_INT(SELF, StrTok_offset_data); RETURN->v_int = (t_CKINT)tokens->more(); } CK_DLL_MFUN( StrTok_next ) { StrTok * tokens = (StrTok *)OBJ_MEMBER_INT(SELF, StrTok_offset_data); Chuck_String * a = (Chuck_String *)instantiate_and_initialize_object( SHRED->vm_ref->env()->t_string, SHRED ); a->set( tokens->next() ); RETURN->v_string = a; } CK_DLL_MFUN( StrTok_next2 ) { StrTok * tokens = (StrTok *)OBJ_MEMBER_INT(SELF, StrTok_offset_data); Chuck_String * a = GET_CK_STRING(ARGS); string s = tokens->next(); if( a ) a->set( s ); RETURN->v_string = a; } CK_DLL_MFUN( StrTok_get ) { StrTok * tokens = (StrTok *)OBJ_MEMBER_INT(SELF, StrTok_offset_data); t_CKINT index = GET_NEXT_INT(ARGS); Chuck_String * a = (Chuck_String *)instantiate_and_initialize_object( SHRED->vm_ref->env()->t_string, SHRED ); string s = tokens->get( index ); a->set( s ); RETURN->v_string = a; } CK_DLL_MFUN( StrTok_get2 ) { StrTok * tokens = (StrTok *)OBJ_MEMBER_INT(SELF, StrTok_offset_data); t_CKINT index = GET_NEXT_INT(ARGS); Chuck_String * a = GET_NEXT_STRING(ARGS); string s = tokens->get( index ); if( a ) a->set( s ); RETURN->v_string = a; } CK_DLL_MFUN( StrTok_size ) { StrTok * tokens = (StrTok *)OBJ_MEMBER_INT(SELF, StrTok_offset_data); RETURN->v_int = tokens->size(); } #ifdef AJAY class ColumnReader { public: ColumnReader(); virtual ~ColumnReader(); bool init( const string & filename, long col ); bool reset() { if( !fin.good() ) return false; where = 0; return true; } bool seek( long pos ) { if( pos < 0 || pos >= values.size() ) return false; where = pos; return true; } bool more() { return where < values.size(); } double curr(); bool next() { if( where < values.size() ) where++; return more(); } long pos() { return where; } long size() { return values.size(); } string name() { return n; } Chuck_String s; protected: bool get_str( string & out ); bool get_double( double & out ); protected: ifstream fin; string n; long column; long where; char line[0x1000]; long len; vector values; }; ColumnReader::ColumnReader() { n = "[NONE]"; column = -1; where = -1; len = 0x1000; } ColumnReader::~ColumnReader() { // close file if( fin.good() ) fin.close(); } bool ColumnReader::init( const string & filename, long col ) { // hmm if( col < 1 ) { CK_STDCERR << "column must be greater than 0!!!" << CK_STDENDL; return false; } // open file fin.open( filename.c_str(), ios::in ); // yes if( !fin.good() ) { CK_STDCERR << "ColumnReader: cannot open file: '" << filename << "'..." << CK_STDENDL; return false; } // set column column = col; // read first line if( !fin.getline( line, len ) ) { CK_STDCERR << "ColumnReader: cannot read first line: '" << filename << "'..." << CK_STDENDL; return false; } // get the name if( !get_str( n ) ) { CK_STDCERR << "ColumnReader: cannot seek to column " << col << ": " << filename << "..." << CK_STDENDL; return false; } double v; long i = 1; // read values while( fin.getline( line, len ) ) { v = 0.0; // get value if( !get_double( v ) ) { CK_STDCERR << "ColumnReader: cannot read column " << v << " on line i: " << n << "..." << CK_STDENDL; return false; } values.push_back( v ); } // well if( values.size() == 0 ) { CK_STDCERR << "ColumnReader: file doesn't not contain data after first line: " << n << "..." << CK_STDENDL; return false; } // set location where = 0; s.str = n; return true; } double ColumnReader::curr() { if( where >= values.size() ) { CK_STDCERR << "ColumnReader: trying to read beyond end of file: " << n << "..." << CK_STDENDL; return 0.0; } return values[where]; } bool ColumnReader::get_double( double & out ) { assert( column > 0 ); long c = 1; char * start = line; char * curr = start; while( c < column ) { // move past value while( *curr && *curr != ',' ) curr++; // move past , while( *curr && *curr == ',' ) curr++; // check if( *curr == '\0' ) { CK_STDCERR << "ColumnReader: cannot find column " << column << ": " << n << CK_STDENDL; return false; } // increment c++; // set start start = curr; } // move past value while( *curr && *curr != ',' ) curr++; // end *curr = '\0'; out = atof( start ); return true; } bool ColumnReader::get_str( string & out ) { assert( column > 0 ); long c = 1; char * start = line; char * curr = start; while( c < column ) { // move past value while( *curr && *curr != ',' ) curr++; // move past , while( *curr && *curr == ',' ) curr++; // check if( *curr == '\0' ) { CK_STDCERR << "ColumnReader: cannot find column " << column << ": " << n << CK_STDENDL; return false; } // increment c++; // set start start = curr; } // move past value while( *curr && *curr != ',' ) curr++; // end *curr = '\0'; out = start; return true; } CK_DLL_CTOR( VCR_ctor ) { OBJ_MEMBER_INT(SELF, VCR_offset_data) = (t_CKUINT)new ColumnReader; } CK_DLL_MFUN( VCR_load ) { ColumnReader * vcr = (ColumnReader*)OBJ_MEMBER_INT(SELF, VCR_offset_data); const char * filename = GET_NEXT_STRING(ARGS)->str.c_str(); t_CKINT column = GET_NEXT_INT(ARGS); RETURN->v_int = vcr->init( filename, column ); } CK_DLL_MFUN( VCR_reset ) { ColumnReader * vcr = (ColumnReader*)OBJ_MEMBER_INT(SELF, VCR_offset_data); RETURN->v_int = vcr->reset(); } CK_DLL_MFUN( VCR_seek ) { ColumnReader * vcr = (ColumnReader*)OBJ_MEMBER_INT(SELF, VCR_offset_data); t_CKINT where = GET_CK_INT(ARGS); RETURN->v_int = vcr->seek( where ); } CK_DLL_MFUN( VCR_more ) { ColumnReader * vcr = (ColumnReader*)OBJ_MEMBER_INT(SELF, VCR_offset_data); RETURN->v_int = vcr->more(); } CK_DLL_MFUN( VCR_curr ) { ColumnReader * vcr = (ColumnReader*)OBJ_MEMBER_INT(SELF, VCR_offset_data); RETURN->v_float = vcr->curr(); } CK_DLL_MFUN( VCR_next ) { ColumnReader * vcr = (ColumnReader*)OBJ_MEMBER_INT(SELF, VCR_offset_data); RETURN->v_int = vcr->next(); } CK_DLL_MFUN( VCR_pos ) { ColumnReader * vcr = (ColumnReader*)OBJ_MEMBER_INT(SELF, VCR_offset_data); RETURN->v_int = vcr->pos(); } CK_DLL_MFUN( VCR_size ) { ColumnReader * vcr = (ColumnReader*)OBJ_MEMBER_INT(SELF, VCR_offset_data); RETURN->v_int = vcr->size(); } CK_DLL_MFUN( VCR_name ) { ColumnReader * vcr = (ColumnReader*)OBJ_MEMBER_INT(SELF, VCR_offset_data); RETURN->v_string = &(vcr->s); } #ifdef __PLATFORM_WIN32__ // jeff's cereal class Serial { public: // one stop bit, 8 bits, no parity Serial(); ~Serial(); unsigned read( char * buffer, unsigned numberOfBytesToRead ); unsigned write( char * buffer, unsigned numberOfBytesToWrite ); void write( char c ); char read(); unsigned available() const; t_CKBOOL open( char * port, t_CKUINT baudrate ); void close(); private: HANDLE serialFile; }; Serial::Serial( ) { serialFile = NULL; } Serial::~Serial( ) { close(); } t_CKBOOL Serial::open( char * port, t_CKUINT baudrate ) { if( serialFile ) close(); // open port serialFile = CreateFile( port, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 ); if( serialFile == INVALID_HANDLE_VALUE ) { if( GetLastError() == ERROR_FILE_NOT_FOUND ) { EM_log( CK_LOG_SYSTEM, "error: cannot open serial port '%s'...", port ); } else { EM_log( CK_LOG_SYSTEM, "error opening serial port '%s'...", port ); } return FALSE; } // set params DCB dcbSerialParams = {0}; dcbSerialParams.DCBlength = sizeof( dcbSerialParams ); if( !GetCommState( serialFile, &dcbSerialParams) ) { EM_log( CK_LOG_SYSTEM, "error getting serial state..." ); close(); return FALSE; } dcbSerialParams.BaudRate = baudrate; dcbSerialParams.ByteSize = 8; dcbSerialParams.StopBits = ONESTOPBIT; dcbSerialParams.Parity = NOPARITY; if( !SetCommState( serialFile, &dcbSerialParams ) ) { EM_log( CK_LOG_SYSTEM, "error setting serial state..." ); close(); return FALSE; } // SET TIMEOUTS /* COMMTIMEOUTS timeouts = {0}; timeouts.ReadIntervalTimeout = 50; timeouts.ReadTotalTimeoutConstant = 50; timeouts.ReadTotalTimeoutMultiplier = 10; timeouts.WriteTotalTimeoutConstant= 50; timeouts.WriteTotalTimeoutMultiplier = 10; if( !SetCommTimeouts( serialFile, &timeouts ) ) { //error occureed. Inform user } */ return TRUE; } void Serial::close() { if( serialFile ) { CloseHandle( serialFile ); serialFile = NULL; } } void Serial::write( char c ) { write( &c, 1 ); } char Serial::read() { char c = '\0'; read( &c, 1 ); return c; } unsigned Serial::available() const { struct _COMSTAT status; unsigned long etat; memset( &status, 0, sizeof(status) ); if( serialFile ) { ClearCommError( serialFile, &etat, &status); return status.cbInQue; } return 0; } // try to read numberOfBytesToRead into buffer, return how many bytes read unsigned Serial::read( char * buffer, unsigned numberOfBytesToRead ) { DWORD bytesRead = 0; if( serialFile ) ReadFile( serialFile, buffer, numberOfBytesToRead, &bytesRead, NULL ); return bytesRead; } // try to write numberOfBytesToWrite to serial from buffer, return how many bytes written unsigned Serial::write( char * buffer, unsigned numberOfBytesToWrite ) { DWORD bytesWritten = 0; if( serialFile ) WriteFile( serialFile, buffer, numberOfBytesToWrite, &bytesWritten, NULL ); return bytesWritten; } // ctor CK_DLL_CTOR( Cereal_ctor ) { OBJ_MEMBER_UINT(SELF, Cereal_offset_data) = (t_CKUINT)new Serial; } // open CK_DLL_MFUN( Cereal_open ) { Serial * s = (Serial *)OBJ_MEMBER_UINT(SELF, Cereal_offset_data); Chuck_String * str = GET_NEXT_STRING(ARGS); t_CKINT i = GET_NEXT_INT(ARGS); // close s->close(); if( str ) RETURN->v_int = s->open( (char *)str->str.c_str(), i ); else RETURN->v_int = 0; } // close CK_DLL_MFUN( Cereal_close ) { Serial * s = (Serial *)OBJ_MEMBER_UINT(SELF, Cereal_offset_data); s->close(); } // more CK_DLL_MFUN( Cereal_more ) { Serial * s = (Serial *)OBJ_MEMBER_UINT(SELF, Cereal_offset_data); RETURN->v_int = s->available(); } // send CK_DLL_MFUN( Cereal_send ) { Serial * s = (Serial *)OBJ_MEMBER_UINT(SELF, Cereal_offset_data); t_CKINT i = GET_NEXT_INT(ARGS); s->write( i ); RETURN->v_int = i; } // recv CK_DLL_MFUN( Cereal_recv ) { Serial * s = (Serial *)OBJ_MEMBER_UINT(SELF, Cereal_offset_data); if( s->available() ) RETURN->v_int = (t_CKINT)s->read(); else RETURN->v_int = 0; } #endif #endif