• Main Page
  • Modules
  • Classes
  • Files
  • File List

tbt.cpp

00001 /*  Time Based Text
00002  *
00003  *  (C) Copyright 2006 - 2008  Denis Roio <jaromil@dyne.org>
00004  *      Idea shared with Joan & Dirk <jodi@jodi.org>
00005  *
00006  * This source code is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Public License as published 
00008  * by the Free Software Foundation; either version 2 of the License,
00009  * or (at your option) any later version.
00010  *
00011  * This source code is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00014  * Please refer to the GNU Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Public License along with
00017  * this source code; if not, write to:
00018  * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019  *
00020  */
00021 
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <unistd.h>
00025 #include <errno.h>
00026 #include <string>
00027 
00028 #include <tbt.h>
00029 #include <jutils.h>
00030 #include <string.h>
00031 #include <errno.h>
00032 
00033 #include <slw/keycodes.h>
00034 
00035 #ifdef linux
00036 #include <rtclock.h>
00037 #endif
00038 
00039 
00040 TBTEntry::TBTEntry() 
00041  : Entry() {
00042   key  = 0;
00043   msec = 0;
00044   // just a hint
00045   set_name("char64,msec64");
00046 }
00047 
00048 TBTEntry::~TBTEntry() { }
00049 
00050 bool TBTEntry::parse_uint64(void *buf) {
00051 
00052   uint64_t *p = (uint64_t*)buf;
00053 
00054   key  = *p;
00055   msec = *(p+1);
00056   
00057   return true;
00058 }
00059 
00060 
00061 // the  following method  takes an  ascii line  (readed from  an ascii
00062 // file) and convert it to the key,msec couple.
00063 
00064 // there's  actually a problem  with the  backspace key...  the S-Lang
00065 // widget  prints  ^P...  without  delete  the  previous  char...  the
00066 // tbtchk_ascii.cpp test  problem print correctly  the backspace value
00067 // in my shell... :( - pallotron 08/04/2007
00068 
00069 // found out with caedes: standard ascii code for BS is 8
00070 // somehow s-lang reports different values when grabbing low level
00071 // kind of weird to see how many different values are on various platforms...
00072 // anyway we'll normalize all this to ASCII (dec 8) now. -jrml
00073 
00074 bool TBTEntry::parse_ascii(char *buf) {
00075 
00076   unsigned char k = 0;
00077   unsigned long int m = 0;
00078 
00079   sscanf(buf, "%c:%lu\n", &k, &m);
00080   key = (uint64_t)k;
00081   msec = (uint64_t)m;
00082 
00083   return true;
00084 }
00085 
00086 
00087 int TBTEntry::render_uint64(void *buf) {
00088   int len; // length in bytes
00089   uint64_t tmp[2];
00090 
00091   tmp[0] = key;
00092   tmp[1] = msec;
00093 
00094   len = 16; //sizeof(uint64_t)*2;
00095 
00096   memcpy(buf, (void*)tmp, len);
00097 
00098   return len;
00099 }
00100 
00101 int TBTEntry::render_ascii(void *buf) {
00102   int len;
00103   char tmp[512];
00104   
00105   len = snprintf(tmp,511,"%c:%lu\n",(int)key, (unsigned long)msec);
00106   if(len<0) {
00107     error("error rendering in ascii: %s", strerror(errno));
00108     return 0;
00109   }
00110 
00111   memcpy(buf,tmp,len*sizeof(char));
00112   return len;
00113 }
00114 
00115 int TBTEntry::render_html(void *buf) {
00116   int len;
00117   char tmp[512];
00118 
00119   len = snprintf(tmp,511,"[%lu,%lu]", (unsigned long)key, (unsigned long)msec);
00120   if(len<0) {
00121     error("error rendering in javascript array: %s", strerror(errno));
00122     return 0;
00123   }
00124 
00125   memcpy(buf, tmp, len*sizeof(char));
00126   return len;
00127 }  
00128 
00129 
00130 
00131 
00132 
00133 TBT::TBT()  {
00134 
00135   // zeroing counters
00136   now    = 0;
00137   past   = 0;
00138 
00139   position = 1;
00140 
00141   rtc  = false;
00142   quit = false;
00143 
00144   // posix timing
00145   gettime.tv_sec   = 0;
00146   gettime.tv_usec  = 0;
00147   psleep.tv_sec    = 0;
00148   psleep.tv_nsec   = 0;
00149 
00150   buffer = new Linklist;
00151 
00152   clock  = NULL;
00153 
00154 }
00155 
00156 TBT::~TBT() {
00157 
00158   clear();
00159 
00160   delete buffer;
00161 }
00162 
00163 int TBT::init() {
00164 
00165 #ifdef linux
00166   if(rtc) { // realtime clock use requested
00167     rtc = false; // let's check now
00168 
00169     // try /dev/rtc clock
00170     clock = new RTClock();
00171     if( clock->init() ) {
00172       notice("real time clock device is present");
00173       
00174       
00175       // set the frequency to 1024 HZ
00176       // so 1 second we have 1024 ticks (what we call microsec)
00177       // it is very hard to match machine time with human time, indeed
00178       // if you care about *real* precision, then this is the riddle:
00179       // /dev/rtc allows to set as frequencies only powers of two.
00180       clock->set_freq( 1024 );
00181       
00182       // this launches the internal clock thread
00183       if( ! clock->start() ) {
00184         error("no permission to run real time clock at 1024HZ");
00185         delete clock;
00186         clock = NULL;
00187       } else
00188         rtc = true;
00189     }
00190   }
00191 #endif
00192   
00193   if(!rtc) { // use posix
00194     
00195     if( gettimeofday(&gettime, NULL) <0 ) {
00196       error("error getting (posix) time: %s",strerror(errno));
00197       error("no timing source available, impossible to go further");
00198       return 0;
00199     }
00200 
00201     past = (gettime.tv_sec * 1000) + (gettime.tv_usec / 1000);
00202   
00203   }
00204 
00205   return 1;
00206 }
00207   
00208 
00209 void TBT::clear() {
00210 
00211   // erase all entries and free the memory
00212   TBTEntry *ent;
00213   ent = (TBTEntry*)buffer->begin();
00214   
00215   // when deleting objects that's the trick with linklist
00216   // it scrolls up the next at the beginning
00217   while(ent) {
00218     delete ent; 
00219     ent = (TBTEntry*) buffer->begin();
00220   }
00221   
00222 }
00223 
00224 void TBT::append(uint64_t key) {
00225   TBTEntry *ent;
00226   ent = new TBTEntry();
00227 
00228   // compute time delay since last key
00229   // the NOW is WHEN this operation is executed
00230   compute_delta( ent );
00231 
00232   // normalize ambiguous keycodes
00233   switch( key ) {
00234 
00235   case KEY_BACKSPACE_ASCII:
00236   case KEY_BACKSPACE:
00237   case KEY_BACKSPACE_APPLE:
00238   case KEY_BACKSPACE_SOMETIMES:
00239     ent->key = (uint64_t)KEY_BACKSPACE_ASCII;
00240     break;
00241     
00242   case KEY_NEWLINE:
00243   case KEY_ENTER:
00244     ent->key  = (uint64_t)KEY_ENTER;
00245     break;
00246 
00247   default:
00248     ent->key = (uint64_t)key;
00249 
00250   }
00251 
00252   buffer->append(ent);
00253 }
00254 
00255 
00256 
00257 
00258 uint64_t TBT::getkey() {
00259   TBTEntry *ent;
00260   ent = (TBTEntry*) buffer->pick(position);
00261   
00262   if(!ent) {
00263     func("NULL entry at position %u", position);
00264     return 0;
00265   }
00266 
00267   position++;
00268 
00269   // this pauses execution by time delta in entry
00270   // here are implemented rtc and posix
00271   if(!rtc) {
00272 
00273     psleep.tv_sec = ent->msec / 1000;
00274     psleep.tv_nsec = (ent->msec % 1000) * 1000000;
00275     nanosleep(&psleep, NULL);
00276 
00277   }
00278 #ifdef linux
00279     else clock->sleep(ent->msec);
00280 #endif
00281 
00282   return ent->key;
00283 }
00284 
00285 int TBT::load(char *filename) {
00286 
00287   int c, len;
00288 
00289   void *buf;
00290 
00291   FILE *fd;
00292 
00293   fd = fopen(filename, "r");
00294   if(!fd) {
00295     error("can't open file: %s", strerror(errno));
00296     return false;
00297   }
00298 
00299   clear();
00300 
00301   // max bytes for an entry here
00302   buf = malloc(64);
00303 
00304   TBTEntry *ent;
00305 
00306   c = 0;
00307   
00308   act("loading file %s", filename);
00309 
00310   while( ! feof(fd) ) {
00311 
00312     len = fread(buf, 4, 4, fd);
00313     if(!len) break;
00314     else if(len != 4) {
00315       warning("truncated entry, %u elements read", len);
00316       continue;
00317     }
00318     
00319     ent = new TBTEntry();
00320 
00321     if( ! ent->parse_uint64(buf) ) {
00322       error("error in TBTEntry::parse_uint64");
00323       continue;
00324     }
00325 
00326     buffer->append( ent );
00327     c++;
00328 
00329   }
00330 
00331   free(buf);
00332 
00333   position = 1;
00334 
00335   return c;
00336 }
00337 
00338 // pallotron: 08/04/2007
00339 // this method is the same of the load() method.
00340 // except that it reads from a pure ascii file
00341 // each line is passed to the parse_ascii method
00342 int TBT::load_ascii(char *filename) {
00343 
00344   int c;
00345 
00346   char ascii_line[512];
00347 
00348   FILE *fd;
00349 
00350   fd = fopen(filename, "r");
00351   if(!fd) {
00352     error("can't open ascii file: %s", strerror(errno));
00353     return false;
00354   }
00355 
00356   clear();
00357 
00358   TBTEntry *ent;
00359 
00360   c = 0;
00361   
00362   act("loading ascii file %s", filename);
00363 
00364   while( ! feof(fd) ) {
00365 
00366     fgets(ascii_line, 512, fd);
00367     
00368     ent = new TBTEntry();
00369 
00370     if( ! ent->parse_ascii(ascii_line) ) {
00371       error("error in TBTEntry::parse_ascii");
00372       continue;
00373     }
00374 
00375     buffer->append( ent );
00376     c++;
00377 
00378   }
00379 
00380   position = 1;
00381 
00382   return c;
00383 }
00384 
00385 int TBT::save_bin(char *filename) {
00386 
00387   int c, len;
00388 
00389   void *buf;
00390 
00391   FILE *fd;
00392 
00393   fd = fopen(filename, "w");
00394   if(!fd) {
00395     error("can't oper file %s for writing: %s", filename, strerror(errno));
00396     return false;
00397   }
00398   
00399   // max bytes for an entry here
00400   buf = malloc(512);
00401 
00402 
00403   TBTEntry *ent;
00404   ent = (TBTEntry*) buffer->begin();
00405 
00406   // cycle thru with counter
00407   c = 0;
00408   while( ent ) {
00409  
00410     len = ent->render_uint64(buf);
00411 
00412     fwrite(buf, len, 1, fd);
00413     
00414     c++;
00415         
00416     ent = (TBTEntry*) ent->next;
00417 
00418   }
00419 
00420   
00421   fflush(fd);
00422   fclose(fd);
00423 
00424   free(buf);
00425 
00426   return c;
00427 }
00428 
00429 int TBT::save_ascii(char *filename) {
00430 
00431   int c, len;
00432 
00433   void *buf;
00434 
00435   FILE *fd;
00436 
00437   fd = fopen(filename, "w");
00438   if(!fd) return false;
00439   
00440   // max bytes for an entry here
00441   buf = malloc(512);
00442 
00443   TBTEntry *ent;
00444   ent = (TBTEntry*)buffer->begin();
00445 
00446   // cycle thru with counter
00447   c = 0;
00448   while( ent ) {
00449  
00450     len = ent->render_ascii(buf);
00451 
00452     fwrite(buf, len, 1, fd);
00453     
00454     c++;
00455 
00456     ent = (TBTEntry*) ent->next;
00457   }
00458   
00459   fflush(fd);
00460   fclose(fd);
00461 
00462   free(buf);
00463 
00464   return c;
00465 }
00466 
00467 int TBT::save_doku(char *filename) {
00468 
00469   int c, len;
00470 
00471   void *buf;
00472 
00473   FILE *fd;
00474 
00475   fd = fopen(filename, "w");
00476   if(!fd) return false;
00477 
00478   fputs("{{tbt>[", fd);
00479   // max bytes for an entry here
00480   buf = malloc(512);
00481   TBTEntry *ent;
00482   ent = (TBTEntry*) buffer->begin();
00483   // cycle thru with counter
00484   c = 0;
00485   while( ent ) {
00486 
00487     if(c>0) // put a comma
00488       fwrite(",",sizeof(char),1,fd);
00489 
00490     len = ent->render_html(buf);
00491 
00492     fwrite(buf, len, 1, fd);
00493     
00494     c++;
00495         
00496     ent = (TBTEntry*) ent->next;
00497   }
00498 
00499   fputs("]}}\n", fd);
00500   fflush(fd);
00501   fclose(fd);
00502 
00503   free(buf);
00504 
00505   return c;
00506 }
00507 
00508 int TBT::save_html(char *filename) {
00509 
00510   int c, len;
00511 
00512   void *buf;
00513 
00514   FILE *fd;
00515 
00516   fd = fopen(filename, "w");
00517   if(!fd) return false;
00518 
00519   fputs("<html><head>\n"
00520         "<script language=\"JavaScript\" src=\"tbt-typewriter.js\"></script>\n"
00521         "<title>Time Based Text - recorded with tbt.dyne.org</title></head>\n"
00522         "<body text=\"#FFFFFF\" bgcolor=\"#000000\">\n"
00523         "<div id=\"textDestination\">\n"
00524         "</div>\n"
00525         "<script language=\"JavaScript\">\n"
00526         "<!--\n", fd);
00527 
00528   // start array
00529   fwrite("var TimeBasedText=[",sizeof(char),19,fd);
00530 
00531   // max bytes for an entry here
00532   buf = malloc(512);
00533 
00534   TBTEntry *ent;
00535   ent = (TBTEntry*) buffer->begin();
00536 
00537   // cycle thru with counter
00538   c = 0;
00539   while( ent ) {
00540 
00541     if(c>0) // put a comma
00542       fwrite(",",sizeof(char),1,fd);
00543 
00544     len = ent->render_html(buf);
00545 
00546     fwrite(buf, len, 1, fd);
00547     
00548     c++;
00549         
00550     ent = (TBTEntry*) ent->next;
00551   }
00552 
00553 
00554   // close array
00555   fwrite("]\n",sizeof(char),2,fd);
00556 
00557   fputs("\n"
00558         "var tbt = new TBT();\n"
00559         "tbt.startTyping(\"textDestination\", TimeBasedText);\n"
00560         "//--></script>\n"
00561         "</body></html>\n\n", fd);
00562   fflush(fd);
00563   fclose(fd);
00564 
00565   free(buf);
00566 
00567   return c;
00568 }
00569 
00570 void TBT::compute_delta(TBTEntry *tbt) {
00571 
00572   // get the NOW
00573   // here is implemented rtc and posix
00574   if(!rtc) {
00575 
00576     // posix 1003.1-2001 gettimeofday
00577     if( gettimeofday(&gettime, NULL) <0)
00578       error("error getting time: %s",strerror(errno));
00579     now = (gettime.tv_sec * 1000) + (gettime.tv_usec / 1000);
00580     
00581   }
00582 #ifdef linux
00583     else now = clock->msec;
00584 #endif
00585 
00586   tbt->msec = now - past;
00587   // take care of unsigned
00588 
00589   past = now;
00590 
00591 }

Generated on Mon Apr 9 2012 15:29:22 for TimeBasedText_code_doc by  doxygen 1.7.1