reni_v0.67.c


1
// Known problems / open tasks
2
// - no time correlation between two results => create daemon
3
// - write output to a given filename
4
// - create string to send from of a one-byte-command
5
// - reevaluate over border from dx10.log (30MB)
6
// - reevaluate more than one call
7
///////////////////////////
8
//
9
//      +----------------- unused (left) connector
10
//      |      +---------- compensator (relative humidity, air temperature, barometric pressure)
11
//      |      |      +--- used (right) connector
12
//      |      |      |
13
//      v      |      v
14
//    +----\   v   /----+
15
//    |     \-----/     |
16
//    |       AUX       |
17
//    |      TP I/O     |
18
//    |                 |
19
//    | O     ML10    O |
20
//    |       EC10      |
21
//     \               /
22
//      \      O      /
23
//       \    USB    /
24
//        +---------+
25
//             A
26
//             |
27
//             +---------- USB connector
28
//
29
//
30
// The PC sends commands down to the DX10 interface via pipe 0x01 and reads its answers back via pipe 0x81.
31
// A 5Khz data-stream will be read from DX10 interface via pipe 0x82.
32
// After reading anything via 0x81 or 0x82 the PC asks immediately for an acknowledge via pipe 0x00.
33
// Before measuring dynamically the PC sends a command every 100ms (while measuring every 333ms).
34
// The answer takes typically 31ms (maximum 79ms).
35
//
36
37
#include <usb.h>
38
#include <stdio.h>
39
#include <math.h>
40
#include <process.h>     // needed for _beginthread()
41
#include <getopt.h>      // needed for getopt
42
#include "version.h"
43
44
// this device's vendor and product id
45
#define THIS_VID 0x0837
46
#define THIS_PID 0x000b
47
48
#define BOOTWAITCYCLES 22               // waiting time for green LED in 0,5 secs
49
#define STANDARD_MEASURE_FREQUENCY 5000 // internal frequency of measurements (5kHz)
50
#define WAVES_PER_MM 809078.31378724    // 1 / ( 0,0006328(wavelength) / 512(resolution) )
51
#define DYNAMIC_RANGE 0x400000          // at this value the dynamic data overflows
52
53
FILE *g_fp_out;
54
FILE *g_fp_log;
55
int g_iPkt_count=1;
56
int g_iPkt_max=250; // 250 = 0.05 sec * 5kHz (default measuring-Time: -t0.05)
57
int g_iReeval=0;
58
int g_iWarning=0;
59
int g_iCount=5; // 5 = 0.001 sec * 5kHz (default time-step-Interval: -i0.001)
60
int g_iDbgLevel=0;
61
usb_dev_handle *g_Dev = NULL; // the device handle
62
unsigned short g_iPacket=0;  // packet-counter
63
int g_iSync=-1;     // synchronisation with fifth short
64
int g_iMode=-1;     // counter within the 5 shorts
65
int g_iUsb=0;       // result = distance counter of wavelength/512
66
int g_iLastusb=0;   // last result
67
int g_iReduce=g_iCount;
68
69
70
#define ABS(x) ((x>0)?(x):(-(x)))
71
#define NEXT_RING_INDEX(x, y) (((x+1)<y)?(x+1):(x+1-y))
72
73
74
#define MAX_STREAM0x81 12
75
#define BUFFLEN0x81    0x200
76
struct {            // data for 12 asynchronous streams
77
    void* async;
78
    int nos;        // number of shorts
79
    unsigned int time0x81;
80
    unsigned int time0x00;
81
    int ret0x00;
82
  int fuel;
83
    unsigned short buff[BUFFLEN0x81];
84
} g_sInterrupt0x81[MAX_STREAM0x81];
85
int g_iInterrupt0x81_index_write;  // active stream for writing
86
int g_iInterrupt0x81_index_read;   // active stream for reading
87
int g_bInterrupt;               // switch for interrupt
88
89
#define MAX_STREAM0x82 20
90
#define BUFFLEN0x82    0x1000
91
struct {            // data for 20 asynchronous streams
92
    void* async;
93
    int nos;        // number of shorts
94
    unsigned short buff[BUFFLEN0x82];
95
} g_sData0x82[MAX_STREAM0x82];
96
int g_iData0x82_index; // active stream
97
98
99
100
#define END_TOKEN   (unsigned short)0xFEDC  // end of token
101
102
struct {            // list of tokens
103
    unsigned short words[8];
104
    char name[15];
105
} g_sTokenlist[]={
106
    {{0x8020,                                           END_TOKEN}, "DOWN_Init8020"}, // 8000 8020
107
    {{0x8060,                                           END_TOKEN}, "DOWN_Conf8060"}, // 8000 8060
108
    {{0x8030,                                           END_TOKEN}, "DOWN_MSta8030"}, // 8000 8030
109
    {{0x8040,                                           END_TOKEN}, "DOWN_MEnd8040"}, // 8000 8040   [8010 01ff 8020 0002]
110
    {{0x8011,0x01e2,0x0005,0x00e0,0x00c7,0x00ff,        END_TOKEN}, "DOWN_Clear   "}, // 8000 8011
111
    {{0x8010,0x01e2,0x0005,0x00e0,0x00c7,0x00ff,        END_TOKEN}, "DOWN_Initial "}, // 8000 8010 (8010) 0857 09ba 0173 01ff
112
    {{0x8010,0x01e2,0x0005,0x00d3,0x00ba,0x00ff,        END_TOKEN}, "DOWN_Zerosta "}, // 8000 8010 (8010) 00e1 0005 00f2 00d8 00ff
113
    {{0x8010,0x01e2,0x0005,0x00cc,0x00b3,0x00ff,        END_TOKEN}, "DOWN_Zerodyn "}, // 8000 8010 (8010) 00e1 0005 00f2 00d8 00ff
114
    {{0x8010,0x01e2,0x0005,0x00d0,0x00b7,0x00ff,        END_TOKEN}, "DOWN_Measure "}, // 8000 8010 (8010) 00e1 000e 00d0 0000 0000 0000 0000 0000 0010 0040 0000 0000 000f 00ff
115
    {{0x8010,0x01e2,0x0005,0x00cf,0x00b6,0x00ff,        END_TOKEN}, "DOWN_Unkn3   "}, // 8000 8010 (8010) 00e1 0005 00f2 00d8 00ff
116
    {{0x8010,0x01e2,0x0006,0x00d8,0x0000,0x00c0,0x00ff, END_TOKEN}, "DOWN_Unkn5   "}, // 8000 8010 (8010) 00e1 0005 00f2 00d8 00ff
117
    {{0x8010,0x01e2,0x0005,0x00dc,0x00c3,0x00ff,        END_TOKEN}, "DOWN_Unkn6   "}, // 8000 8010 (8010) 00e1 0005 00f2 00d8 00ff   [8020 0002]
118
    {{0x8010,0x01e3,0x0005,0x00e0,0x00c8,0x00ff,        END_TOKEN}, "DOWN_un_Init2"}, // 8000 8010
119
    {{0x8011,0x01e3,0x0005,0x00e0,0x00c8,0x00ff,        END_TOKEN}, "DOWN_un_Sync "}, // 8000 8011
120
};
121
// sequence must have the SAME order!!!
122
enum TOK {DOWN_Init8020
123
=0,       DOWN_Conf8060
124
,         DOWN_MSta8030
125
,         DOWN_MEnd8040
126
,         DOWN_Clear
127
,         DOWN_Initial
128
,         DOWN_Zerosta
129
,         DOWN_Zerodyn
130
,         DOWN_Measure
131
,         DOWN_Unkn3
132
,         DOWN_Unkn5
133
,         DOWN_Unkn6
134
,         DOWN_un_Init2
135
,         DOWN_un_Sync
136
,         DOWN_LAST//////////////////////////////
137
,         FUNCTION_WAIT             // wait 1000 msec
138
,         FUNCTION_LOAD_PIPE        // reset pipe 0x82, scheduling data transfer
139
,         FUNCTION_START_MEASURE
140
,         FUNCTION_STOP_MEASURE
141
,         END_PROGRAM
142
};
143
144
// Seen original order of commands:
145
// DOWN_Zerosta,    d3
146
// DOWN_Zerodyn,    cc
147
// DOWN_Unkn3,      cf
148
// DOWN_Conf8060,   %
149
// DOWN_Unkn5,      d800
150
// DOWN_Unkn3,      cf
151
152
153
154
// milli secs since first call
155
unsigned int msec(void)
156
{
157
    unsigned int a, d;
158
    long long ticks;
159
    static unsigned int first = 0;
160
    static unsigned int mhz = 0;
161
162
    if (mhz==0) {
163
        unsigned char temp[10] = {""};
164
        unsigned long size = sizeof(temp);
165
        HKEY hKey;
166
167
        RegOpenKey(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", &hKey);
168
        RegQueryValueEx(hKey, "~MHz", NULL, NULL, temp, &size);
169
        RegCloseKey(hKey);
170
        mhz=*(int*)temp;
171
        __asm__ volatile("rdtsc" : "=a" (a), "=d" (d));
172
        ticks = ((unsigned long long)a) | (((unsigned long long)d) << 32);
173
        first=ticks/mhz/1000;
174
        return 0;
175
    }
176
    __asm__ volatile("rdtsc" : "=a" (a), "=d" (d));
177
    ticks = ((unsigned long long)a) | (((unsigned long long)d) << 32);
178
    return (ticks/mhz/1000)-first;
179
}
180
181
#define DBG9   9    // stdout: print endless data
182
#define DBG3   3    // stdout:
183
#define DBG2   2    // stdout:
184
#define DBG1   1    // stdout: print only with option -d1
185
#define ALL    0    // stdout: print always
186
#define WARN  -1    // stderr: warning, continue program
187
#define EXIT  -2    // stderr: error, stop program immediately
188
void output(int mode, const char *fmt, ...)
189
{
190
    va_list ap;
191
    char string[4096];
192
  FILE*fp=stdout;
193
194
  if (mode>g_iDbgLevel)  // hide output because of low log-level
195
    return;
196
    if (mode<=WARN) {
197
    fflush(stdout);
198
    fp=stderr;
199
  }
200
    va_start(ap, fmt);
201
    vsprintf(string, fmt, ap);
202
    fprintf(fp, string);
203
    fflush(fp);
204
    va_end(ap);
205
    if (mode==WARN)
206
    g_iWarning++;
207
    if (mode==EXIT)
208
        exit(-1);
209
    return;
210
}
211
212
213
214
usb_dev_handle *open_dev(void)
215
{
216
    struct usb_bus *bus;
217
    struct usb_device *dev;
218
219
    for(bus = usb_get_busses(); bus; bus = bus->next)
220
        for(dev = bus->devices; dev; dev = dev->next)
221
            if(dev->descriptor.idVendor == THIS_VID && dev->descriptor.idProduct == THIS_PID)
222
                return usb_open(dev);
223
    return NULL;
224
}
225
226
227
228
short read_pipe_0x00(void)
229
{
230
    short tmp=0;
231
    int ret, i, iTime;
232
233
    if ((ret=usb_control_msg(
234
        g_Dev,                                  //    usb_dev_handle
235
        0x80,                                   // #  int requesttype => 80: read data from device
236
        0x00,                                   // #  int request
237
        0x0000,                                 // ## int value
238
        0x0000,                                 // ## int index
239
        (char*)&tmp,                            //    char *bytes
240
        0x0002,                                 // ## int size
241
        1000)) < 0)                             //    int timeout
242
        output(EXIT, "ERROR usb_control_msg\n");
243
    if(tmp != 0x0000)
244
        output(WARN, "pipe00 returns value\n");
245
    return tmp;
246
}
247
248
249
250
void get_reeval_line(unsigned short *adr, int *nos)
251
{
252
    int k, l, m;
253
    char sLine[9999];
254
    do {
255
        if(!fgets(sLine, 9999, g_fp_log))   // read data line
256
            output(EXIT, "ERROR no more data to simulate\n");
257
    } while ( (sLine[0]<'0') || (sLine[0]>'9') );   // skip comments...
258
    l=strlen(sLine);
259
    for (m=0, k=2; m<l; m++)            // read time, dir+pipe
260
        if (sLine[m]==' ')
261
            if (!--k)
262
                break;
263
    if (adr)
264
        for (k=0, m++; m<l; m+=5, k++)      // read all shorts
265
            sscanf(&sLine[m], "%04x", adr+k);
266
    if (nos)
267
        *nos=k;
268
//    sscanf(&sLine[0], "%d", iTime);
269
}
270
271
272
273
int write_command(unsigned short *words, int toklen)
274
{
275
    int i, iTime;
276
    int ret=0;
277
  static int iCount=0;
278
279
    if (g_iReeval)
280
        get_reeval_line(NULL, NULL);    // read line and skip
281
    else {
282
        int pos;
283
        char sString[32];
284
        fgetpos (g_fp_log, (fpos_t*)&pos);
285
        if (pos>30*1000*1000) {
286
            fclose(g_fp_log);
287
            sprintf(sString, "dx10_%06d.log", iCount++);
288
            remove(sString);
289
            rename("dx10.log", sString);
290
            g_fp_log=fopen("dx10.log", "w");
291
        }
292
        iTime=msec();
293
        fprintf(g_fp_log, "%d d01", iTime);
294
        for(i=0; i<toklen; i++)
295
            fprintf(g_fp_log, " %04x", words[i]);
296
        fprintf(g_fp_log, "\n");
297
        ret=usb_bulk_write(g_Dev, 0x01, (char*)words, toklen*2, 1000);
298
    }
299
    return ret;
300
}
301
302
303
304
void read_one_answer(void)      // read from the actual read index
305
{
306
    int i, iTime;
307
    if (g_iReeval) {
308
        get_reeval_line(&g_sInterrupt0x81[g_iInterrupt0x81_index_read].buff[0], &g_sInterrupt0x81[g_iInterrupt0x81_index_read].nos);  // data line
309
        get_reeval_line(NULL, NULL);    // skip pipe 0x00
310
    } else {
311
        while (g_iInterrupt0x81_index_write == g_iInterrupt0x81_index_read);   // wait, till a new interrupt has been written
312
// write BACK data from interruption log
313
    fprintf(g_fp_log, "//%d\n", g_sInterrupt0x81[g_iInterrupt0x81_index_read].fuel);
314
        iTime = g_sInterrupt0x81[g_iInterrupt0x81_index_read].time0x81;
315
        fprintf(g_fp_log, "%d b81", iTime);
316
        for(i=0; i<g_sInterrupt0x81[g_iInterrupt0x81_index_read].nos; i++)
317
            fprintf(g_fp_log, " %04x", g_sInterrupt0x81[g_iInterrupt0x81_index_read].buff[i]);
318
        fprintf(g_fp_log, "\n");
319
        iTime = g_sInterrupt0x81[g_iInterrupt0x81_index_read].time0x00;
320
        fprintf(g_fp_log, "%d b00 %04x\n", iTime, g_sInterrupt0x81[g_iInterrupt0x81_index_read].ret0x00);
321
    }
322
}
323
324
325
326
void read_data(void)      // read from the actual data index
327
{
328
    int i, j, iTime;
329
330
    if (g_iReeval) {
331
        get_reeval_line(&g_sData0x82[g_iData0x82_index].buff[0], &g_sData0x82[g_iData0x82_index].nos);  // data line
332
        get_reeval_line(NULL, NULL);    // skip pipe 0x00
333
    } else {
334
        if ((g_sData0x82[g_iData0x82_index].nos=usb_reap_async(g_sData0x82[g_iData0x82_index].async, 5000)/2) < 0)
335
            output(EXIT, "error reap02 %d\n", g_iData0x82_index);
336
337
// write BACK data
338
        iTime = msec();
339
        fprintf(g_fp_log, "%d b82", iTime);
340
        for(j=0; j<g_sData0x82[g_iData0x82_index].nos; j++)
341
            fprintf(g_fp_log, " %04x", g_sData0x82[g_iData0x82_index].buff[j]);
342
        fprintf(g_fp_log, "\n");
343
        fprintf(g_fp_log, "%d b00 %04x\n", msec(), read_pipe_0x00());
344
345
        // submit this transfer and returns immediately
346
        if (usb_submit_async(g_sData0x82[g_iData0x82_index].async, (char*)&g_sData0x82[g_iData0x82_index].buff[0], BUFFLEN0x82) < 0)
347
            output(EXIT, "error usb_submit_async:\n%s\n", usb_strerror());
348
    }
349
}
350
351
352
353
void interrupt_routine(void *dummy)
354
{
355
    int i, ret, fuel;
356
357
    // do once for setup
358
    for(i=0; i<MAX_STREAM0x81; i++)
359
        if (usb_bulk_setup_async(g_Dev, &g_sInterrupt0x81[i].async, 0x81) < 0)
360
            output(EXIT, "ERROR: no setup before interrupt:\n%s\n", usb_strerror());
361
362
    // submit this transfer and returns immediately
363
    for(i=0; i<MAX_STREAM0x81; i++) {
364
        if (usb_submit_async(g_sInterrupt0x81[i].async, (char*)&g_sInterrupt0x81[i].buff[0], BUFFLEN0x81) < 0)
365
            output(EXIT, "ERROR: no submit before interrupt:\n%s\n", usb_strerror());
366
    }
367
368
    // endless loop for interrupt
369
    while (g_bInterrupt) {
370
        // wait for the transfer to complete (no logging within interrupt)
371
        ret=usb_reap_async(g_sInterrupt0x81[g_iInterrupt0x81_index_write].async, 5000);
372
        if ((g_sInterrupt0x81[g_iInterrupt0x81_index_write].nos=ret/2) < 0) {
373
            if (g_bInterrupt) {
374
        for(i=0; i<MAX_STREAM0x81; i++)
375
          output(DBG1, "%d %d %d\n", i, g_sInterrupt0x81[i].time0x81, g_sInterrupt0x81[i].fuel);
376
                output(EXIT, "ERROR: no response in interrupt %d within time: %d\n"
377
                     "Perhaps no cable between DX10 and laser\n"
378
               "  or\n"
379
               "Replug USB cable\n", g_iInterrupt0x81_index_write, ret);
380
            } else
381
                break;
382
        }
383
        // store timervalue (log it later)
384
        g_sInterrupt0x81[g_iInterrupt0x81_index_write].time0x81=msec();
385
        g_sInterrupt0x81[g_iInterrupt0x81_index_write].ret0x00=read_pipe_0x00();
386
        g_sInterrupt0x81[g_iInterrupt0x81_index_write].time0x00=msec();
387
        // submit this transfer and returns immediately
388
        if (usb_submit_async(g_sInterrupt0x81[g_iInterrupt0x81_index_write].async,
389
                             (char*)&g_sInterrupt0x81[g_iInterrupt0x81_index_write].buff[0], BUFFLEN0x81) < 0) {
390
      for(i=0; i<MAX_STREAM0x81; i++)
391
        output(DBG1, "%d %d %d\n", i, g_sInterrupt0x81[i].time0x81, g_sInterrupt0x81[i].fuel);
392
            output(EXIT, "ERROR: no submit in interrupt:\n%s\n", usb_strerror());
393
    }
394
    fuel=g_iInterrupt0x81_index_write-g_iInterrupt0x81_index_read;
395
    if (fuel<0)
396
      fuel+=MAX_STREAM0x81;
397
    g_sInterrupt0x81[g_iInterrupt0x81_index_write].fuel=fuel;
398
        g_iInterrupt0x81_index_write = NEXT_RING_INDEX(g_iInterrupt0x81_index_write, MAX_STREAM0x81);
399
400
        if (fuel > MAX_STREAM0x81-5) {  // buffer overflow
401
      for(i=0; i<MAX_STREAM0x81; i++)
402
        output(DBG1, "%d %d %d\n", i, g_sInterrupt0x81[i].time0x81, g_sInterrupt0x81[i].fuel);
403
      output(EXIT, "ERROR: missing interrupt\nPerhaps type first <dx10 -b>\n");
404
        }
405
    Sleep(1);
406
    }
407
}
408
409
410
411
void evaluate_dynamic(int *offset)
412
{
413
    int j;
414
415
    if (g_sData0x82[g_iData0x82_index].buff[0] == g_iPacket) {
416
        if (g_iSync == -1) {
417
            for(j=1; j<15; j++)
418
                if (g_sData0x82[g_iData0x82_index].buff[j] >= 0x80)
419
                    break;
420
            if (g_iSync>13)
421
                output(EXIT, "ERROR: no sync\n");
422
            g_iSync=j+1;
423
            g_iMode=0;
424
        }
425
//
426
// Structure of datastream from 0x82:
427
// - First short of every packet is the packet-counter.
428
// - Then always 5 shorts for 1 distance (every 0,0002 sec = 5000 Hz).
429
// - Only the fifth short has bit 7 set.
430
//
431
// mode| bit. ..98  7654 3210
432
// ----+---------------------
433
//   0 | 0000 0000  0?cc cccc      0: always 0
434
//   1 | 0000 0000  0ccc cccc      1: always 1
435
//   2 | 0000 0000  0ccc cccc      c: counter (total 22 bit) for laser
436
//   3 | 0000 0000  0p0i iiii      i: intensity: 00-1F (00=0%, 1A=100%)
437
//   4 | 0000 0000  1000 qcc?      ?: unknown meaning (bit flickers)
438
//                                 q: non continuous beam
439
//                   p: no interference
440
//
441
// +----+----+ +----+----+ +----+----+ 
442
// |00cc|cccc| |cccc|cccc| |cccc|cccc| counter (total 22 bit) for laser
443
// |  26|5432| |1016|5432| |1054|3210| bit no
444
// |  42|2222| |2241|1111| |1100|0000| mode-byte
445
// +----+----+ +----+----+ +----+----+ 
446
//
447
        for(j=g_iSync; j<g_sData0x82[g_iData0x82_index].nos; j++) {
448
            switch(g_iMode++) {
449
                case 0:
450
                    g_iUsb+=(g_sData0x82[g_iData0x82_index].buff[j]&0x3F) << 0; // bit 0-5
451
                    if   (g_sData0x82[g_iData0x82_index].buff[j]&~0x7F)
452
                        output(WARN, "mode 0: not zero: %04X\n", g_sData0x82[g_iData0x82_index].buff[j]&~0x7F);
453
                    break;
454
                case 1:
455
                    g_iUsb+=(g_sData0x82[g_iData0x82_index].buff[j]&0x7F) << 6;  // bit 6-12
456
                    if   (g_sData0x82[g_iData0x82_index].buff[j]&~0x7F)
457
                        output(WARN, "mode 1: not zero: %04X\n", g_sData0x82[g_iData0x82_index].buff[j]&~0x7F);
458
                    break;
459
                case 2:
460
                    g_iUsb+=(g_sData0x82[g_iData0x82_index].buff[j]&0x7F) << 14;   // bit 14-20
461
                    if   (g_sData0x82[g_iData0x82_index].buff[j]&~0x7F)
462
                        output(WARN, "mode 2: not zero: %04X\n", g_sData0x82[g_iData0x82_index].buff[j]&~0x7F);
463
                    break;
464
                case 3:
465
                    if   (g_sData0x82[g_iData0x82_index].buff[j]&~0x5F)
466
                        output(WARN, "mode 3: not zero: %04X\n", g_sData0x82[g_iData0x82_index].buff[j]&~0x5F);
467
                    if ((g_sData0x82[g_iData0x82_index].buff[j]&0x1F) < 4) // low < 15%
468
                        output(EXIT, "ERROR: intensity too low\n");
469
                    break;
470
                case 4:
471
                    g_iUsb+=(g_sData0x82[g_iData0x82_index].buff[j]&0x02) << 13-1; // bit 13
472
                    g_iUsb+=(g_sData0x82[g_iData0x82_index].buff[j]&0x04) << 21-2; // bit 21
473
                    if  ((g_sData0x82[g_iData0x82_index].buff[j]&~0x0F) != 0x80)
474
                        output(WARN, "mode 4: not 0x0080: %04X\n", g_sData0x82[g_iData0x82_index].buff[j]&~0x0F);
475
           if (!((j==g_iSync+4)&&(g_iPacket==0))) {    // for the very first value not output (only store lastusb)
476
            if ((j==g_iSync+9)&&(g_iPacket==0)) {    // for the second value check direction and offset
477
              // For the very first time, offset is the 32bit static value.
478
              // After this calculation, offset is the 32bit value without the last 22bit (which comes from measurement)
479
              // Take the first two dynamic values (time-distance 1*0,0002) and calculate the value 500 time-steps before.
480
              // The difference of offset and this calculated value is the start value of offset.
481
              int off=0;
482
              if (g_iUsb-g_iLastusb >  DYNAMIC_RANGE/2) off=-DYNAMIC_RANGE;
483
              if (g_iUsb-g_iLastusb < -DYNAMIC_RANGE/2) off= DYNAMIC_RANGE;
484
              output(DBG3, "last static value / %5.3f:   %14.6f\n", DYNAMIC_RANGE/WAVES_PER_MM, 1.0*(*offset)/DYNAMIC_RANGE);
485
              output(DBG3, "calc dyn value :             %14.6f\n", 1.0*((g_iLastusb-off)-(g_iUsb-(g_iLastusb-off))*500)/DYNAMIC_RANGE);
486
              output(DBG3, "first offset in double:      %14.6f\n", 1.0*((*offset)-((g_iLastusb-off)-(g_iUsb-(g_iLastusb-off))*500))/DYNAMIC_RANGE);
487
              off=(int)floor(                         1.0*((*offset)-((g_iLastusb-off)-(g_iUsb-(g_iLastusb-off))*500)+DYNAMIC_RANGE/2)/DYNAMIC_RANGE);
488
              output(DBG3, "first offset:                      %d\n", off);
489
              *offset=off * DYNAMIC_RANGE;
490
            }
491
            if (g_iUsb-g_iLastusb >  DYNAMIC_RANGE/2) *offset-=DYNAMIC_RANGE;
492
            if (g_iUsb-g_iLastusb < -DYNAMIC_RANGE/2) *offset+=DYNAMIC_RANGE;
493
            
494
            int value=g_iUsb+*offset;
495
            if  (g_sData0x82[g_iData0x82_index].buff[j]&0x08)  // non continuous beam
496
              value=(int)(999.9999999*WAVES_PER_MM);
497
498
            if (!(--g_iReduce)) {  // measuring always with 5kHz, output with given time-step
499
              g_iReduce=g_iCount;
500
              if (g_fp_out)
501
                fprintf(g_fp_out, "%.4f\t%f\n", (double)g_iPkt_count*g_iCount/STANDARD_MEASURE_FREQUENCY, value/WAVES_PER_MM);
502
              else
503
                output(ALL,           "%f\n", value/WAVES_PER_MM);
504
              g_iPkt_count++;
505
            }
506
          }
507
                    g_iLastusb=g_iUsb;
508
                    g_iMode=0;
509
                    g_iUsb=0;
510
                    break;
511
                default:
512
                    output(EXIT, "ERROR: impossible mode\n");
513
            }
514
            if (g_iPkt_count >= g_iPkt_max)
515
        break;
516
        }
517
        g_iSync=1;
518
        g_iPacket++;
519
    } else
520
        output(WARN, "ERROR wrong packet number in distance calculation\n");
521
    output(DBG1, "distadyn: (%f, %d) %f\n", g_iLastusb/WAVES_PER_MM, *offset/DYNAMIC_RANGE, (g_iLastusb+*offset)/WAVES_PER_MM);
522
    fflush(stdout);
523
}
524
525
526
527
int evaluate_static(int iAns, unsigned short *iAnswer, int mode)
528
{
529
    int ret;
530
531
    if (iAns>13) // length
532
// iAnswer[ 0] 8000
533
// iAnswer[ 1] 8010
534
// skip this:  8010
535
    if (iAnswer[2]==0xe1) // type1 with: len .... sum FF
536
    if (iAnswer[3]==0x0e) // length from [00e1 to 00ff]
537
    if (iAnswer[4]==0xd0) { // type2: measure
538
// iAnswer[ 5] 0000 0000  s000 000?  s: sign of counter,  ?: after 82
539
// iAnswer[ 6] 0000 0000  cccc cccc  c(00-FF): counter
540
// iAnswer[ 7] 0000 0000  cccc cccc  c(00-FF): counter
541
// iAnswer[ 8] 0000 0000  cccc cccc  c(00-FF): counter
542
// iAnswer[ 9] 0000 0000  cccc cccc  c(00-FF): counter
543
// iAnswer[10] 0000 0000  qp01 0000  q: non continuous beam,  p: no interference
544
// iAnswer[11] 0000 0000  0r00 000b  r: red,  b: booting=>no counter, no intensity
545
// iAnswer[12] 0000 0000  000? 0000  ?:at p=0 for 4 ticks
546
// iAnswer[13] 0000 0000  000i iiii  i(00-1F): intensity
547
// iAnswer[14] 0000 0000  xxxx xxxx  sum of iAnswer[2]-iAnswer[13]
548
// iAnswer[15] 0000 0000  1111 1111  00ff
549
550
        if ((mode==0)||(mode==1)) {
551
            int ret = (iAnswer[6]<<24)|(iAnswer[7]<<16)|(iAnswer[8]<<8)|iAnswer[9];
552
            if (iAnswer[5]&0x0080)
553
                ret=-ret;
554
            if (iAnswer[10]&0x0080) // non continuous beam
555
                ret=(int)(999.9999999*WAVES_PER_MM);
556
            if (mode) {
557
                if (g_fp_out)
558
                    fprintf(g_fp_out, "%f\t%f\n", 0.0, ret/WAVES_PER_MM);
559
                else
560
                    output(ALL, "distance: %11.6f\n", ret/WAVES_PER_MM);
561
            }
562
            return ret;
563
        } else {
564
            ret = ((iAnswer[5]&~0x80)<<24)|(((iAnswer[10]^0x10)&0x80)<<16)|(iAnswer[11]<<8)|iAnswer[12];
565
            return (iAnswer[13]&0x1F);
566
        }
567
    }
568
    return 0;
569
}
570
571
572
573
int command(int iCommand, unsigned short *iAnswer)
574
{
575
    int i, stop, toklen;
576
    int iAns=0;
577
    unsigned short answer[32];
578
    if (!iAnswer)
579
        iAnswer=answer;
580
581
    // write command to usb
582
    for(toklen=0; g_sTokenlist[iCommand].words[toklen] != END_TOKEN; toklen++);    // toklen: length of tokens
583
    output(DBG2, "%s ", g_sTokenlist[iCommand].name);
584
    if(write_command(&g_sTokenlist[iCommand].words[0], toklen)< 0)
585
        output(EXIT, "ERROR write\n");
586
587
    // read complete answer from usb
588
    for(iAns=0, stop=0; stop<1; ) {
589
        // read one answer from usb
590
        read_one_answer();
591
//
592
// Seen return values
593
// ==================
594
//
595
// [800x, 8011]     abort, skip further answer or parts of it
596
// [8000, 8020]     init
597
// [8000, 8030]     start dynamical measurement
598
// [8000, 8060]     config?
599
// [8000, 8040]     stop dynamical measurement, often with 8010 xxxx and/or 8020 0002
600
// [8000, 8010]     start of data
601
// [8010, *]        data with expected further data
602
// [8010, *, ##ff]  normal end of data
603
// [8020, 0002]     interrupt?
604
// [*]              not seen yet
605
//
606
        // typical return value: 800x 80xx
607
        if (iAns==0) {
608
            if ((g_sInterrupt0x81[g_iInterrupt0x81_index_read].buff[0] & 0xFFFE) == 0x8000) {  // new correct answer
609
                for(i=0; i<g_sInterrupt0x81[g_iInterrupt0x81_index_read].nos; i++)
610
                    iAnswer[iAns++]=g_sInterrupt0x81[g_iInterrupt0x81_index_read].buff[i];        // fill complete answer
611
                if (g_sInterrupt0x81[g_iInterrupt0x81_index_read].buff[1]!=0x8010)
612
                    stop=1;
613
            // additional data to skip: e.g 8020 0002 or 8010 ... (after 8000 8040 or after abortion)
614
            } else if (g_sInterrupt0x81[g_iInterrupt0x81_index_read].buff[0]==0x8020) {
615
                output(DBG1, "skip 8020 at %d (", g_sInterrupt0x81[g_iInterrupt0x81_index_read].time0x81);
616
                for(i=0; i<g_sInterrupt0x81[g_iInterrupt0x81_index_read].nos; i++)
617
                    output(DBG1, " %04X", g_sInterrupt0x81[g_iInterrupt0x81_index_read].buff[i]);
618
                output(DBG1, ")\n");
619
            } else if (g_sInterrupt0x81[g_iInterrupt0x81_index_read].buff[0]==0x8010) {
620
                output(DBG1, "skip 8010 at %d (", g_sInterrupt0x81[g_iInterrupt0x81_index_read].time0x81);
621
                for(i=0; i<g_sInterrupt0x81[g_iInterrupt0x81_index_read].nos; i++)
622
                    output(DBG1, " %04X", g_sInterrupt0x81[g_iInterrupt0x81_index_read].buff[i]);
623
                output(DBG1, ")\n");
624
            } else {
625
                output(WARN, "SKIP UNKNOWN at %d! (", g_sInterrupt0x81[g_iInterrupt0x81_index_read].time0x81);
626
                for(i=0; i<g_sInterrupt0x81[g_iInterrupt0x81_index_read].nos; i++)
627
                    output(WARN, " %04X", g_sInterrupt0x81[g_iInterrupt0x81_index_read].buff[i]);
628
                output(WARN,")\n");
629
            }
630
            fflush(stdout);
631
        // all data:     (8000 8010) 8010 .... xxFF
632
        // typical data: (8000 8010) 8010 00E1 00yy ....   ..   .... 00FF
633
        //                                1    2    3      ..   yy-1 yy
634
        } else {
635
            if (g_sInterrupt0x81[g_iInterrupt0x81_index_read].buff[0]==0x8010) {  // korrekte Daten
636
                for(i=1; i<g_sInterrupt0x81[g_iInterrupt0x81_index_read].nos; i++)
637
                    iAnswer[iAns++]=g_sInterrupt0x81[g_iInterrupt0x81_index_read].buff[i];          // fill complete answer
638
                if ((g_sInterrupt0x81[g_iInterrupt0x81_index_read].buff[i-1] & 0x00FF) == 0xFF) {   // check last word == 0xFF
639
                    if (iAnswer[2]==0x00e1) {                                                       // if typical answer with type: 0x00E1
640
                        if ((iAnswer[3]+2==iAns) && (iAnswer[iAns-1]==0x00FF)) {    // stop only, if 0x00FF appears after the correct length
641
                            int sum=0;
642
                            for(i=2; i<iAnswer[3]; i++)                             // calculate check sum
643
                                sum+=iAnswer[i]&0x00FF;
644
                            if ((sum&0x00FF) != iAnswer[iAns-2])                    // check sum
645
                                output(WARN, "WARNING: invalid checksum\n");                     
646
                            stop=1;
647
                        }
648
                    } else
649
                        stop=1;  // stop for the very first answer of DOWN_Initial
650
                }
651
            // abortion with: 8000 8011
652
            } else if ( (g_sInterrupt0x81[g_iInterrupt0x81_index_read].buff[0]==0x8000) &&
653
                        (g_sInterrupt0x81[g_iInterrupt0x81_index_read].buff[1]==0x8011) ) {
654
                output(WARN, "abort with 8000 8011 at %d\n", g_sInterrupt0x81[g_iInterrupt0x81_index_read].time0x81);
655
                stop=1;
656
            } else {
657
                output(WARN, "SKIP UNKNOWN DATA at %d! (", g_sInterrupt0x81[g_iInterrupt0x81_index_read].time0x81);
658
                for(i=0; i<g_sInterrupt0x81[g_iInterrupt0x81_index_read].nos; i++)
659
                    output(WARN, " %04X", g_sInterrupt0x81[g_iInterrupt0x81_index_read].buff[i]);
660
                output(WARN, ")\n");
661
                stop=1;
662
            }
663
            fflush(stdout);
664
        }
665
        g_iInterrupt0x81_index_read = NEXT_RING_INDEX(g_iInterrupt0x81_index_read, MAX_STREAM0x81);
666
    }
667
  output(DBG2, "  <<<");
668
  for(i=0; i<iAns; i++)
669
        if (i<20)
670
            output(DBG2, " %04x", iAnswer[i]);
671
        else
672
            output(DBG9, " %04x", iAnswer[i]);
673
  output(DBG2, "\n");
674
675
    return iAns;
676
}
677
678
679
680
void measure_dynamic(int iFirstvalue)
681
{
682
    int i, j, iTime;
683
    output(DBG2, "START MEASURE\n");
684
    for(i=0; g_iPkt_count<g_iPkt_max; i++) {    // number of packets
685
        // wait for the transfer to complete
686
        read_data();
687
    output(DBG2, "     data");
688
    for(j=0; j<g_sData0x82[g_iData0x82_index].nos; j++)
689
            if (j<20)
690
                output(DBG2, " %04x", g_sData0x82[g_iData0x82_index].buff[j]);
691
            else
692
                output(DBG9, " %04x", g_sData0x82[g_iData0x82_index].buff[j]);
693
    output(DBG2, "\n");
694
695
        evaluate_dynamic(&iFirstvalue);
696
697
        g_iData0x82_index = NEXT_RING_INDEX(g_iData0x82_index, MAX_STREAM0x82);
698
        if((i%4)==0)                            // minimal communication during measurement
699
            command(DOWN_un_Sync, NULL);
700
        if ( (GetAsyncKeyState(VK_LCONTROL)) || // break this loop with Ctrl
701
             (GetAsyncKeyState(VK_RCONTROL)) ) break;
702
    }
703
}
704
705
706
707
int main(int argc, char**argv)
708
{
709
    int c=0;
710
    int i;
711
    int iToken=-1;
712
    int bAlign=0;
713
    int bBoot=0;
714
    int bZero=0;
715
    int bPoint=0;
716
  double dTmp;
717
    g_fp_out=fopen("_out.txt", "w");
718
719
    // test of configuration
720
    if (sizeof(g_sTokenlist)/sizeof(g_sTokenlist[0]) != DOWN_LAST)
721
        output(EXIT, "error: wrong configuration!\n");
722
        
723
    while (  (c = getopt(argc, argv, "abcpovsht:k:d:i:r")) != -1  ) {    // check options
724
        switch (c) {
725
        case 'o':
726
            g_fp_out=NULL;
727
            break;
728
        case 'a':
729
            bAlign=1;
730
            break;
731
        case 'b':
732
            bBoot=1;
733
            break;
734
        case 'c':
735
            bZero=1;
736
            break;
737
        case 'p':
738
            bPoint=1;
739
            break;
740
        case 'i':
741
            sscanf(optarg, "%lf", &dTmp);
742
            g_iCount=(int)(STANDARD_MEASURE_FREQUENCY*dTmp+0.5);
743
            break;
744
        case 't':
745
            sscanf(optarg, "%lf", &dTmp);
746
            g_iPkt_max=(int)(STANDARD_MEASURE_FREQUENCY*dTmp+0.5);
747
            break;
748
        case 'k':
749
            for (i=0; i<sizeof(g_sTokenlist)/sizeof(g_sTokenlist[0]); i++)
750
                if (!strncmp(g_sTokenlist[i].name, optarg, strlen(optarg)))
751
                    break;
752
            if (i<sizeof(g_sTokenlist)/sizeof(g_sTokenlist[0]))
753
                iToken=i;
754
            else
755
                output(EXIT, "error: command not found!\n");
756
            break;
757
        case 'r':
758
      g_iReeval=1;
759
            break;
760
        case 'd':
761
      sscanf(optarg, "%d", &g_iDbgLevel);
762
            break;
763
        // last options
764
        case 'v':
765
        case 'h':
766
        default :
767
            output(ALL, "Version %s\n", "v0.67");
768
            if (c == 'v') return(0);
769
            output(ALL, "%s options:\n", "reni");
770
            output(ALL, "  -h        print this Help text\n");
771
            output(ALL, "  -v        print Version\n");
772
            output(ALL, "  -o        write Output to stdout instead of out.txt\n");
773
            output(ALL, "  -t #      measuring-Time # sec [0.05]\n");
774
            output(ALL, "  -i #      time-step-Interval # sec [0.001] (fit for possible values)\n");
775
            output(ALL, "  -k #      direct execution of dx10 toKen # [none]\n");
776
            output(ALL, "  -a        Align intensity (signal strength <17%:too low, <48%:low)\n");
777
            output(ALL, "  -p        measure one static Point\n");
778
            output(ALL, "  -b        Boot laser (red LED)\n");
779
            output(ALL, "  -c        initialize Counter (set zero)\n");
780
            output(ALL, "  -r        Reevaluate last action\n");
781
            output(ALL, "  -d #      Debugging level\n");
782
            return(0);
783
        }
784
    }
785
    g_iInterrupt0x81_index_write=0;
786
    g_iInterrupt0x81_index_read=0;
787
788
  g_iPkt_max=g_iPkt_max/g_iCount+1;
789
790
    if (g_iReeval) {
791
        char sLine[512];
792
        g_fp_log=fopen("dx10.log","r");
793
        fgets(sLine, 512, g_fp_log);    // read first line with command line
794
    } else {
795
        g_fp_log=fopen("dx10.log","a");
796
        fprintf(g_fp_log, "#%s ", "reni");
797
        for(i=1; i<argc; i++)
798
            fprintf(g_fp_log, "%s ", argv[i]);
799
        fprintf(g_fp_log, "\n");
800
801
        msec(); // init time measure
802
803
        usb_init(); // initialize the library
804
        usb_find_busses(); // find all buses
805
        usb_find_devices(); // find all connected devices
806
807
        if(!(g_Dev = open_dev()))
808
            output(EXIT, "error: device not found!\nPlease plug in dx10 via USB.\n");
809
810
        if(usb_set_configuration(g_Dev, 1) < 0)
811
            output(EXIT, "error: setting config 1 failed\n");
812
813
        if(usb_claim_interface(g_Dev, 0) < 0) //-- URB_FUNCTION_SELECT_CONFIGURATION
814
            output(EXIT, "error: claiming interface 0 failed\n");
815
816
        if (usb_clear_halt(g_Dev, 0x81) < 0) //-- URB_FUNCTION_RESET_PIPE
817
            output(EXIT, "error: reset%s\n", usb_strerror());
818
819
        g_bInterrupt=1;
820
    int dummy;
821
        _beginthread( interrupt_routine, 0, &dummy );          // start a new thread
822
    }
823
824
    //
825
    // booting the laser
826
    //
827
    if (bBoot==1) { // initialize
828
        unsigned short iAnswer[32];
829
        int iAns;
830
        iAns=command(DOWN_Init8020, iAnswer);
831
        if ((iAns==2)&&(iAnswer[0]!=0x8000)&&(iAnswer[1]!=0x8020))
832
            output(EXIT, "ERROR: ret 8020\n");
833
        output(ALL, "Waiting for green LED ... "); fflush(stdout);
834
        if (!g_iReeval)
835
            Sleep(1000);
836
        for (i=0; i<4; i++) {
837
            iAns=command(DOWN_Clear, iAnswer);
838
            if ((iAns==2)&&(iAnswer[0]!=0x8000)&&(iAnswer[1]!=0x8011))
839
                output(EXIT, "ERROR: ret 8011 %d\n", i);
840
        }
841
        iAns=command(DOWN_Initial, iAnswer);       // first init (no 00e1, not 00xx)
842
        iAns=command(DOWN_Initial, iAnswer);       // second init
843
        for (i=0; i<BOOTWAITCYCLES; i++) {              // wait for green laser-led
844
            Sleep(500);
845
            iAns=command(DOWN_Measure, iAnswer);
846
            if (iAnswer[11]==0)
847
                i=BOOTWAITCYCLES*2;
848
        }
849
        if (i<BOOTWAITCYCLES*2)                         // check for timeout
850
            output(EXIT, "ERROR: waiting too long for green\nPerhaps you have to wait for warming up the laser.");
851
        iAns=command(DOWN_Zerosta, iAnswer);       // zero static value
852
        iAns=command(DOWN_Zerodyn, iAnswer);       // zero dynamic value
853
        output(ALL, " finished!\n");
854
        
855
    //
856
    // show intensity to align laser
857
    //
858
    } else if (bAlign) {    // show intensity
859
        unsigned short iAnswer[32];
860
        int iAns;
861
        int    iIntensity;
862
        double dIntensity;
863
        while (1) {
864
            char sBar[] =" . . . . . . . . . . . . . . . . . . . . . . . . . .";
865
            iAns=command(DOWN_Measure, iAnswer);
866
            iIntensity=evaluate_static(iAns, iAnswer, 2);
867
            if (iIntensity > 26)
868
                iIntensity = 26;
869
            dIntensity=iIntensity/26.0*100.0;       // in percent => too low < 15%, low < 46%
870
            output(ALL, "%3.0f ", dIntensity);
871
            if (iIntensity<=4) {
872
                for(i=0; i<iIntensity*2; i++)
873
                    sBar[i] = '-';
874
            }else if (iIntensity<=12) {
875
                for(i=0; i<iIntensity*2; i++)
876
                    sBar[i] = '~';
877
            }else{
878
                for(i=0; i<iIntensity*2; i++)
879
                    sBar[i] = '+';
880
            }
881
            sBar[ 4*2-1] = '|';
882
            sBar[12*2-1] = '|';
883
            sBar[26*2  ] = 0;
884
            output(ALL, "%s\n", sBar);
885
            fflush(stdout);
886
            if ( (GetAsyncKeyState(VK_LCONTROL)) || // break this loop with Ctrl
887
                 (GetAsyncKeyState(VK_RCONTROL)) ) break;
888
            Sleep(100);
889
        }
890
        
891
    //
892
    // one command for testing
893
    //
894
    } else if (iToken>=0) {
895
        int iAns;
896
        unsigned short iAnswer[32];
897
        output(DBG2, "one command: %s\n", g_sTokenlist[iToken].name);
898
        iAns=command(iToken, iAnswer);
899
        evaluate_static(iAns, iAnswer, 1);
900
        
901
    //
902
    // measure one static point
903
    //
904
    } else if (bPoint) {  // 
905
        unsigned short iAnswer[32];
906
        int iAns;
907
        output(DBG2, "one point\n", g_sTokenlist[iToken].name);
908
        iAns=command(DOWN_Measure, iAnswer);
909
        evaluate_static(iAns, iAnswer, 1);
910
        
911
    //
912
    // zero the laser for static and dynamic measurement
913
    //
914
    } else if (bZero) {  // zero static+dynamic
915
        unsigned short iAnswer[32];
916
        int iAns;
917
        output(DBG2, "zero static+dynamic\n");
918
        iAns=command(DOWN_Zerosta, iAnswer);       // zero static value
919
        iAns=command(DOWN_Zerodyn, iAnswer);       // zero dynamic value
920
        
921
    //
922
    // standard dynamical measurement
923
    //
924
    } else {  // measure dynamical
925
        unsigned short iAnswer[32];
926
        int iAns, iFirstvalue;
927
        output(DBG2, "measure dynamic\n");
928
        if (!g_iReeval) {  //  FUNCTION_LOAD_PIPE
929
            if (usb_clear_halt(g_Dev, 0x82) < 0)
930
                output(EXIT, "error: reset 82%s\n", usb_strerror());
931
            for(i=0; i<MAX_STREAM0x82; i++) // do once for setup
932
                if (usb_bulk_setup_async(g_Dev, &g_sData0x82[i].async, 0x82) < 0)
933
                    output(EXIT, "error usb_bulk_setup_async:\n%s\n", usb_strerror());
934
            for(i=0; i<MAX_STREAM0x82; i++) // submit this transfer and returns immediately
935
                if (usb_submit_async(g_sData0x82[i].async, (char*)&g_sData0x82[i].buff[0], BUFFLEN0x82) < 0)
936
                    output(EXIT, "error usb_submit_async:\n%s\n", usb_strerror());
937
        }
938
    Sleep(0);
939
        iAns=command(DOWN_Measure, iAnswer);
940
        iFirstvalue=evaluate_static(iAns, iAnswer, 0);
941
        iAns=command(DOWN_MSta8030, iAnswer);
942
        measure_dynamic(iFirstvalue);
943
        iAns=command(DOWN_MEnd8040, iAnswer);
944
        if (!g_iReeval)
945
            if (usb_resetep(g_Dev, 0x82) < 0)
946
                output(EXIT, "error: abort/reset 82%s\n", usb_strerror());
947
        iAns=command(DOWN_Measure, iAnswer);       // do not skip this! system hangs sometimes... reason unknown?
948
        evaluate_static(iAns, iAnswer, 0);
949
    }
950
951
    if (!g_iReeval) {
952
        g_bInterrupt=0;
953
        if (usb_resetep(g_Dev, 0x81) < 0)
954
            output(EXIT, "error: abort/reset 81%s\n", usb_strerror());
955
        if (usb_resetep(g_Dev, 0x82) < 0)
956
            output(EXIT, "error: abort/reset 82%s\n", usb_strerror());
957
958
        usb_release_interface(g_Dev, 0);
959
        usb_close(g_Dev);
960
    }
961
    if (g_fp_out) {
962
        fclose(g_fp_out);
963
    remove("out.txt");
964
    rename("_out.txt", "out.txt");
965
  }
966
    fclose(g_fp_log);
967
968
    if ( (g_iWarning) || (g_iDbgLevel))
969
        output(ALL, "warnings: %d\n", g_iWarning);
970
971
    return 0;
972
}