root/tbt/trunk/tbt.cpp

Revision 874, 10.2 kB (checked in by jaromil, 1 year ago)

new -x flag for file format conversion

Line 
1 /*  Time Based Text
2  *
3  *  (C) Copyright 2006 - 2007  Denis Rojo <jaromil@dyne.org>
4  *      Idea shared with Joan & Dirk <jodi@jodi.org>
5  *
6  * This source code is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Public License as published
8  * by the Free Software Foundation; either version 2 of the License,
9  * or (at your option) any later version.
10  *
11  * This source code is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * Please refer to the GNU Public License for more details.
15  *
16  * You should have received a copy of the GNU Public License along with
17  * this source code; if not, write to:
18  * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <errno.h>
26 #include <string>
27
28 #include <tbt.h>
29 #include <jutils.h>
30
31 #ifdef linux
32 #include <rtclock.h>
33 #endif
34
35
36 TBTEntry::TBTEntry()
37  : Entry() {
38   key  = 0;
39   msec = 0;
40   // just a hint
41   set_name("char64,msec64");
42 }
43
44 TBTEntry::~TBTEntry() { }
45
46 bool TBTEntry::parse_uint64(void *buf) {
47
48   uint64_t *p = (uint64_t*)buf;
49
50   key  = *p;
51   msec = *(p+1);
52  
53   return true;
54 }
55
56 // pallotron: 08/04/2007
57 // this method takes an ascii line (readed from an ascii file) and convert it
58 // to the key,msec couple.
59 // there's actually a problem with the backspace key... the S-Lang widget prints
60 // ^P... without delete the previous char... the tbtchk_ascii.cpp test problem
61 // print correctly the backspace value in my shell... :(
62 // TODO: fix this...
63 bool TBTEntry::parse_ascii(char *buf) {
64
65   unsigned char k = 0;
66   unsigned long int m = 0;
67
68   sscanf(buf, "%c:%lu\n", &k, &m);
69   key = (uint64_t)k;
70   msec = (uint64_t)m;
71
72   return true;
73 }
74
75
76 int TBTEntry::render_uint64(void *buf) {
77   int len; // length in bytes
78   uint64_t tmp[2];
79
80   tmp[0] = key;
81   tmp[1] = msec;
82
83   len = 16; //sizeof(uint64_t)*2;
84
85   memcpy(buf, (void*)tmp, len);
86
87   return len;
88 }
89
90 int TBTEntry::render_ascii(void *buf) {
91   int len;
92   char tmp[512];
93  
94   len = snprintf(tmp,511,"%c:%lu\n",(int)key, (unsigned long)msec);
95   if(len<0) {
96     error("error rendering in ascii: %s", strerror(errno));
97     return 0;
98   }
99
100   memcpy(buf,tmp,len*sizeof(char));
101   return len;
102 }
103
104 int TBTEntry::render_html(void *buf) {
105   int len;
106   char tmp[512];
107
108   len = snprintf(tmp,511,"[%lu,%lu]", (unsigned long)key, (unsigned long)msec);
109   if(len<0) {
110     error("error rendering in javascript array: %s", strerror(errno));
111     return 0;
112   }
113
114   memcpy(buf, tmp, len*sizeof(char));
115   return len;
116
117
118
119
120
121
122 TBT::TBT()  {
123
124   // zeroing counters
125   now    = 0;
126   past   = 0;
127
128   position = 1;
129
130   rtc  = false;
131   quit = false;
132
133   // posix timing
134   gettime.tv_sec   = 0;
135   gettime.tv_usec  = 0;
136   psleep.tv_sec    = 0;
137   psleep.tv_nsec   = 0;
138
139   buffer = new Linklist;
140
141   clock  = NULL;
142
143 }
144
145 TBT::~TBT() {
146
147   clear();
148
149   delete buffer;
150 }
151
152 int TBT::init() {
153
154 #ifdef linux
155   // try /dev/rtc clock
156   clock = new RTClock();
157   if( clock->init() ) {
158     notice("real time clock device is present");
159
160    
161     // set the frequency to 1024 HZ
162     // so 1 second we have 1024 ticks (what we call microsec)
163     // it is very hard to match machine time with human time, indeed
164     // if you care about *real* precision, then this is the riddle:
165     // /dev/rtc allows to set as frequencies only powers of two.
166     clock->set_freq( 1024 );
167    
168     // this launches the internal clock thread
169     if( ! clock->start() ) {
170       error("can't run real time clock at 1024HZ");
171       delete clock;
172       clock = NULL;
173     } else
174       rtc = true;
175    
176   }
177 #endif
178  
179   if(!rtc) { // use posix
180    
181     if( gettimeofday(&gettime, NULL) <0 ) {
182       error("error getting (posix) time: %s",strerror(errno));
183       error("no timing source available, impossible to go further");
184       return 0;
185     }
186
187     past = (gettime.tv_sec * 1000) + (gettime.tv_usec / 1000);
188  
189   }
190
191   return 1;
192 }
193  
194
195 void TBT::clear() {
196
197   // erase all entries and free the memory
198   TBTEntry *ent;
199   ent = (TBTEntry*)buffer->begin();
200  
201   // when deleting objects that's the trick with linklist
202   // it scrolls up the next at the beginning
203   while(ent) {
204     delete ent;
205     ent = (TBTEntry*) buffer->begin();
206   }
207  
208 }
209
210 void TBT::append(uint64_t key) {
211   TBTEntry *ent;
212   ent = new TBTEntry();
213
214   // compute time delay since last key
215   // the NOW is WHEN this operation is executed
216   compute_delta( ent );
217
218   ent->key  = (uint64_t)key;
219
220   buffer->append(ent);
221 }
222
223
224
225 // keysize is in bytes here, because if it would be in bits
226 // we wouldn't be able to fread() single bits at precise timing
227
228 int TBT::fdappend(int filedes, int keysize) {
229
230   TBTEntry *ent;
231   uint64_t entmask;
232   uint64_t bitmask;
233   FILE *fd;
234   int c, len;
235  
236   fd = fdopen(filedes, "r");
237   if(!fd) {
238     error("can't open file descriptor %u: %s", filedes, strerror(errno));
239     return 0;
240   }
241  
242   // max bytes for an entry here
243   if(!keysize) keysize = 4;
244   else if(keysize > 4) keysize = 4;
245  
246   // render the bitmask
247   bitmask = 0xff;
248   for( c=keysize ; c>1; c--)
249     bitmask |= bitmask<<8;
250
251
252   act("appending from file descriptor %u", filedes);
253
254   c = 0;
255
256   quit = false;
257
258   while( ! quit ) {
259    
260     if( feof(fd) ) break;
261    
262     len = fread((void*)&entmask, keysize, 1, fd);
263     if(!len) break;
264     else if(len != keysize) {
265       warning("truncated entry, %u bytes read: %s", len, strerror(errno));
266       continue;
267     }
268
269     func("appending new entry %c", entmask);
270
271     ent = new TBTEntry();
272
273     // compute time delay since last key
274     // the NOW is WHEN this operation is executed
275     compute_delta( ent );
276    
277     ent->key = (entmask & bitmask);
278
279     buffer->append(ent);
280     c++;
281
282   }
283
284   act("appended %u entries from file descriptor %u", c, filedes);
285
286   return c;
287
288 }
289
290
291
292 uint64_t TBT::getkey() {
293   TBTEntry *ent;
294   ent = (TBTEntry*) buffer->pick(position);
295  
296   if(!ent) {
297     func("NULL entry at position %u", position);
298     return 0;
299   }
300
301   position++;
302
303   // this pauses execution by time delta in entry
304   // here are implemented rtc and posix
305   if(!rtc) {
306
307     psleep.tv_sec = ent->msec / 1000;
308     psleep.tv_nsec = (ent->msec % 1000) * 1000000;
309     nanosleep(&psleep, NULL);
310
311   }
312 #ifdef linux
313     else clock->sleep(ent->msec);
314 #endif
315
316   return ent->key;
317 }
318
319 int TBT::load(char *filename) {
320
321   int c, len;
322
323   void *buf;
324
325   FILE *fd;
326
327   fd = fopen(filename, "r");
328   if(!fd) {
329     error("can't open file: %s", strerror(errno));
330     return false;
331   }
332
333   clear();
334
335   // max bytes for an entry here
336   buf = malloc(64);
337
338   TBTEntry *ent;
339
340   c = 0;
341  
342   act("loading file %s", filename);
343
344   while( ! feof(fd) ) {
345
346     len = fread(buf, 4, 4, fd);
347     if(!len) break;
348     else if(len != 4) {
349       warning("truncated entry, %u elements read", len);
350       continue;
351     }
352    
353     ent = new TBTEntry();
354
355     if( ! ent->parse_uint64(buf) ) {
356       error("error in TBTEntry::parse_uint64");
357       continue;
358     }
359
360     buffer->append( ent );
361     c++;
362
363   }
364
365   free(buf);
366
367   position = 1;
368
369   return c;
370 }
371
372 // pallotron: 08/04/2007
373 // this method is the same of the load() method.
374 // except that it reads from a pure ascii file
375 // each line is passed to the parse_ascii method
376 int TBT::load_ascii(char *filename) {
377
378   int c;
379
380   char ascii_line[512];
381
382   FILE *fd;
383
384   fd = fopen(filename, "r");
385   if(!fd) {
386     error("can't open ascii file: %s", strerror(errno));
387     return false;
388   }
389
390   clear();
391
392   TBTEntry *ent;
393
394   c = 0;
395  
396   act("loading ascii file %s", filename);
397
398   while( ! feof(fd) ) {
399
400     fgets(ascii_line, 512, fd);
401    
402     ent = new TBTEntry();
403
404     if( ! ent->parse_ascii(ascii_line) ) {
405       error("error in TBTEntry::parse_ascii");
406       continue;
407     }
408
409     buffer->append( ent );
410     c++;
411
412   }
413
414   position = 1;
415
416   return c;
417 }
418
419 int TBT::save_bin(char *filename) {
420
421   int c, len;
422
423   void *buf;
424
425   FILE *fd;
426
427   fd = fopen(filename, "w");
428   if(!fd) {
429     error("can't oper file %s for writing: %s", filename, strerror(errno));
430     return false;
431   }
432  
433   // max bytes for an entry here
434   buf = malloc(512);
435
436
437   TBTEntry *ent;
438   ent = (TBTEntry*) buffer->begin();
439
440   // cycle thru with counter
441   c = 0;
442   while( ent ) {
443  
444     len = ent->render_uint64(buf);
445
446     fwrite(buf, len, 1, fd);
447    
448     c++;
449        
450     ent = (TBTEntry*) ent->next;
451
452   }
453
454  
455   fflush(fd);
456   fclose(fd);
457
458   free(buf);
459
460   return c;
461 }
462
463 int TBT::save_ascii(char *filename) {
464
465   int c, len;
466
467   void *buf;
468
469   FILE *fd;
470
471   fd = fopen(filename, "w");
472   if(!fd) return false;
473  
474   // max bytes for an entry here
475   buf = malloc(512);
476
477   TBTEntry *ent;
478   ent = (TBTEntry*)buffer->begin();
479
480   // cycle thru with counter
481   c = 0;
482   while( ent ) {
483  
484     len = ent->render_ascii(buf);
485
486     fwrite(buf, len, 1, fd);
487    
488     c++;
489
490     ent = (TBTEntry*) ent->next;
491   }
492  
493   fflush(fd);
494   fclose(fd);
495
496   free(buf);
497
498   return c;
499 }
500
501 int TBT::save_html(char *filename) {
502
503   int c, len;
504
505   void *buf;
506
507   FILE *fd;
508
509   fd = fopen(filename, "w");
510   if(!fd) return false;
511
512   fputs("<html><head>\n"
513         "<script language=\"JavaScript\" src=\"tbt-typewriter.js\"></script>\n"
514         "<title>Time Based Text - recorded with tbt.dyne.org</title></head>\n"
515         "<body text=\"#FFFFFF\" bgcolor=\"#000000\">\n"
516         "<div id=\"textDestination\">\n"
517         "</div>\n"
518         "<script language=\"JavaScript\">\n"
519         "<!--\n", fd);
520
521   // start array
522   fwrite("var TimeBasedText=[",sizeof(char),19,fd);
523
524   // max bytes for an entry here
525   buf = malloc(512);
526
527   TBTEntry *ent;
528   ent = (TBTEntry*) buffer->begin();
529
530   // cycle thru with counter
531   c = 0;
532   while( ent ) {
533
534     if(c>0) // put a comma
535       fwrite(",",sizeof(char),1,fd);
536
537     len = ent->render_html(buf);
538
539     fwrite(buf, len, 1, fd);
540    
541     c++;
542        
543     ent = (TBTEntry*) ent->next;
544   }
545
546
547   // close array
548   fwrite("]\n",sizeof(char),2,fd);
549
550   fputs("\n"
551         "var tbt = new TBT();\n"
552         "tbt.startTyping(\"textDestination\", TimeBasedText);\n"
553         "//--></script>\n"
554         "</body></html>\n\n", fd);
555   fflush(fd);
556   fclose(fd);
557
558   free(buf);
559
560   return c;
561 }
562
563 void TBT::compute_delta(TBTEntry *tbt) {
564
565   // get the NOW
566   // here is implemented rtc and posix
567   if(!rtc) {
568
569     // posix 1003.1-2001 gettimeofday
570     if( gettimeofday(&gettime, NULL) <0)
571       error("error getting time: %s",strerror(errno));
572     now = (gettime.tv_sec * 1000) + (gettime.tv_usec / 1000);
573    
574   }
575 #ifdef linux
576     else now = clock->msec;
577 #endif
578
579   tbt->msec = now - past;
580   // take care of unsigned
581
582   past = now;
583
584 }
Note: See TracBrowser for help on using the browser.