LDVmouse

Check-in [730e9fbd40]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:cleaning up ./Software
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 730e9fbd407b0d508a42b1e4a55fd15229a9cfe4
User & Date: ezaron 2016-06-24 17:25:19
Context
2016-06-24
17:33
minor cleaning in Matlab check-in: dbb5709f7a user: ezaron tags: trunk
17:25
cleaning up ./Software check-in: 730e9fbd40 user: ezaron tags: trunk
17:23
incorportated new changes, prior to submission to APS check-in: 50535ad2f6 user: ezaron tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Added Software/LDV.conf.sample.



























>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13

# Once you know the dev number and node, you may hardwire these values:
set ::LDVname "Catz"              ; # This is part of the vendor name of the mouse, just enough to be unique.
set ::LDVdev  15                  ; # This is the numeric device id as returned by "xinput --list".
set ::LDVnode /dev/input/event15  ; # This is the device node, i.e., the pseudo-file where mouse events are reported.

# SET THE FOLLOWING TO SUITABLE VALUES, WHICH WILL DEPEND ON
# THE MOUSE POLLING RATE:
#   The polling rate and number of samples used to compute average instrument values:
set ::LDVrate    1000 ; # Polling rate. Only used in the output file header.
set ::LDVnavg   10000 ; # Number of samples for averaging in LDVtransect: 10 sec
set ::LDVnsamp   5000 ; # Number of samples in the time series colllected by LDVts.tcl: 5 sec

Deleted Software/LDVconf.tcl~.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#
# Normally, you would source this file at the beginning of any of
# the other LDV mouse commands.
#
# We need root priviliges to execute some of these commands, so remember
# to run this with "sudo tclsh"
#
# Before you run this script, you should run "sudo ./evhz" to find out the
# device's polling rate.
# If the polling rate isn't high enough, 1 kHz seems to be max, then you can
# try:
#   sudo modprobe -r usbhid && sudo modprobe usbhid mousepoll=1
# AND THEN UNPLUG AND RE-PLUG IN THE MOUSE.
# See https://wiki.archlinux.org/index.php/Mouse_Polling_Rate for other settings.

# Set some global values:

# The polling rate and number of samples used to average:
set ::LDVrate   1000 ; # Polling rate. Only used in the output file header.
set ::LDVnavg   5000 ; # Number of samples for computing time-average in LDVtransect.tcl.
set ::LDVnsamp  5000 ; # Number of samples in time series by LDVts.tcl. 5 sec
#set ::LDVnsamp  300000 ; # Number of samples in time series by LDVts.tcl. 5 minutes


# Once you know the dev number and node, you may hardwire these values:
set ::LDVname "Catz"
set ::LDVdev  14
set ::LDVnode /dev/input/event16

# Note that "sudo ./evhz" will output the list of nodes and their associated
# devices.

###########################################################
# You should not need to modify anything below this line. #
###########################################################

# Find the mouse by name by parsing the output of xinput --list
proc finddev mousename {
    if { [ catch {exec xinput --list | grep "$mousename" } retstr ]
     } {
	puts "Could not find device named $mousename."
	puts "Returning dev=0."
#	puts "retstr = $retstr"
	return 0
    }
    regexp {id=(\d+?)\s} $retstr -> dev
    puts "Found \"$mousename\" mouse on dev=$dev"
    return $dev
}

# Determine the file name for accessing the mouse:
proc getnode dev {
    # On puppy linux, the mouse seems to show up at
    #	return /dev/sudo modprobe -r usbhid && sudo modprobe usbhid mousepoll=1
    # THEN UN-PLUG AND RE-PLUG MOUSE.
    # 	Mad CAT:
    #	return /dev/input/event8
    # Titanium:
    #	return /dev/input/event3
    #    return /dev/input/event2
    # red button is here:
    #	return /dev/input/event2
    #	return /dev/input/event12

    # Not all linux's seem to have the list-props option for xinput.
    # Execute xinput and grab the line containing "Device Node"
    if { [ catch {exec xinput list-props $dev | grep "Device Node"} retstr ]
     } {
	puts "Could not find device node for dev= $dev."
	puts "Returning devnode=0."
	#	puts "retstr = $retstr"
	return 0
    }
    # Parse the result to pull out the file name which is within quotes
    regexp {\"(.+?)\"} $retstr -> match
    puts "Found dev=$dev on node=$match"
    return $match
}

# Find the active device node just by grabbing output from everything
# /dev/input/event* until something shows up.
# Use this as a last resort in case xinput list-props fails.
set ::state 0
set ::ms 0
proc getnode_alt dev {
    puts "Searching for the device node corresponding to dev=$dev."
    puts "   Please move the mouse or sensor ...."
    after 3000
    set eventnodes [glob /dev/input/event*]
    foreach e $eventnodes {
	update
	puts "   Checking $e"
	after 250 set ::state timeout
	set ::ms [open $e rb]
	chan configure $::ms -encoding binary -translation binary -buffering none -blocking 0
	chan event $::ms readable {close $::ms; set ::state 1}
#	puts $::state
	vwait ::state
	after cancel set ::state timeout
#	puts $::state
	switch $::state {timeout {close $::ms ; puts "   ... no response"} default {return $e}}
	puts "Unable to find events associated with the mouse movement."
	return 0
    }
}


if {$::LDVnode == 0} {
    # Find the device number from the device name:
    set ::LDVdev  [finddev $::LDVname]
    
    # Try to find the node, e.g., /dev/input/event12:
    set ::LDVnode [getnode $::LDVdev]
    
    if {$::LDVnode == 0} {
	# If the above command fails because the linux does not have
	# full xinput command, then we search all active nodes.
	set ::LDVnode [getnode_alt $::LDVdev]
    }
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
















































































































































































































































Deleted Software/testdev.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
#!/usr/local/bin/bltwish

##!/usr/bin/tclsh
#package require Tk
#package require BLT

#!/usr/local/bin/tclsh8.5

# xinput query-state 11
# xinput test 11
# xinput test-xi2
# xinput list-props 11
# sudo tclsh to run this script

# This will increase the mouse polling rate to 1kHz:
# sudo modprobe -r usbhid && sudo modprobe usbhid mousepoll=1
# THEN UN-PLUG AND RE-PLUG MOUSE.
# See https://wiki.archlinux.org/index.php/Mouse_Polling_Rate for other settings.

# Set up tcl/tk with tools we need to graph the data:


namespace import blt::*

# Initialize vectors
set nsamp 250 ;  # nominally, 1 second of data
#set nsamp 1000 ;  # nominally, 1 second of data
set nsamp 6000 ;  # nominally, 3 second of data at 500Hz
vector create utvec($nsamp) vtvec($nsamp) uvec($nsamp) vvec($nsamp)
vector create vzero($nsamp)

# "xinput list" provides a list of possible input devices.
# Device 11 is the mouse on my laptop.
# Default location (sometimes?)
set dev 9
# After setting polling rate with usbhid:
set dev 15
# Logitech wireless? It seems that after unplugging and replugging, the device comes back on 15:
#set dev 16
#set dev 10
#set dev 11

# Disable the mouse:
proc disablemouse dev {
    # other pointers should continue to work.
    exec xinput disable $dev
}

# Enable the mouse:
proc enablemouse dev {
    exec xinput enable $dev
}

# Determine the file name for accessing the mouse:
proc getnode dev {
	# On puppy linux, the mouse seems to show up at
#	return /dev/sudo modprobe -r usbhid && sudo modprobe usbhid mousepoll=1
# THEN UN-PLUG AND RE-PLUG MOUSE.
# 	Mad CAT:
#	return /dev/input/event8
# Titanium:
#	return /dev/input/event3
	return /dev/input/event2
	# red button is here:
#	return /dev/input/event2
#	return /dev/input/event12

    # Execute xinput and grab the line containing "Device Node"
    set retstr [exec xinput list-props $dev | grep "Device Node"]
    # Parse the result to pull out the file name which is within quotes
    regexp {\"(.+?)\"} $retstr -> match
    return $match
}

# Find out the polling rate on the device:
proc checkrate dev {
    set devnode [getnode $dev]

    # "xinput list-props 11" shows that the mouse is at /dev/input/event6
    # We must run tclsh as root, "sudo tclsh", in order to access the mouse in the following:

    # Open the channel and configure it for directly reading binary data.
    set ms [open $devnode rb]
    chan configure $ms -encoding binary -translation binary -buffering none
    
    puts "Start moving the device and keep it in continuous motion."
    set i 0
    set count 0
    set imax 1000
    set dtsum 0.
    while {$i < $imax} {
	set buf [read $ms 16]
	#    binary scan $buf iissi tvsec tvusec type code value
	binary scan $buf iissi tvsec tvusec type code value
	puts "$tvsec $tvusec $type $code $value"
	# See linux/linux.h for a desciption of the event structure:
	# tvsec
	# tvusec
	# type = 0 (sync) 2 (rel)
	# code = 0 (xaxis) 1 (yaxis)
	# value = amount of change.
	if {$type == 0} {
	    if {$count > 0} {
		set dt    [expr ($tvsec - $tsec)+($tvusec - $tusec)/1.e6]
		set dtsum [expr $dtsum + $dt]
	    }
	    set tsec  $tvsec
	    set tusec $tvusec
	    incr count
	}
	incr i
    }
    set rate [expr $dtsum/$count ] ; # Average dt over test period.
    set rate [expr 1./$rate ] ; # convert rate to Hz = 1/sec
    puts "Found polling rate = $rate Hz from $count samples."

    # Close the channel:
    close $ms

    return
}


# Read the device and compute instantaneous and average velocity in device units.
# Note that the vectors utvec, vtvec, uvec, and vvec are global variables.
proc rawvel {dev nsamp} {
    set devnode [getnode $dev]

    ::utvec set ::vzero
    ::vtvec set ::vzero
    ::uvec  set ::vzero
    ::vvec  set ::vzero

    set uttmp  [list]
    set utmp   [list]
    set vttmp  [list]
    set vtmp   [list]

    # Open the channel and configure it for directly reading binary data.
    # Need to put this in a "catch" statement with reminder to 
    # run tclsh as sudo.
    set ms [open $devnode rb]
    chan configure $ms -encoding binary -translation binary -buffering none

    set i 0
    set buf [read $ms 16]
    #    binary scan $buf iissi tvsec tvusec type code value
    binary scan $buf iissi tsec tusec type code value

#    puts "$tsec $tusec $type $code $value"
    set u_tsec_old  $tsec
    set u_tusec_old $tusec
    set v_tsec_old  $tsec
    set v_tusec_old $tusec
    set t0 [expr $tsec + $tusec/1.e6]

    set ucount 0
    set vcount 0
    while {$i < $nsamp} {
	set buf [read $ms 16]
	#    binary scan $buf iissi tvsec tvusec type code value
	binary scan $buf iissi tsec tusec type code value
#	puts "$tsec $tusec $type $code $value"
	# sec
	# usec
	# type = 0 (sync) 2 (rel)
	# code = 0 (xaxis) 1 (yaxis)
	# value = amount of change.
	# Only record increments when a relative change is reported:

	if {$type == 2} {
	    if {$code == 0} {
		set u_dt    [expr ($tsec - $u_tsec_old)+($tusec - $u_tusec_old)/1.e6]
		set u_tsec_old  $tsec
		set u_tusec_old $tusec
		lappend uttmp  [expr ($tsec+$tusec/1.e6)-$t0]
		#		lappend utmp   [expr $value/$u_dt]
		# It seems that each value returned is a speed, so it is not necessary to divide
		# by the time increment
		lappend utmp   $value
		incr ucount
	    }
	    if {$code == 1} {
		set v_dt    [expr ($tsec - $v_tsec_old)+($tusec - $v_tusec_old)/1.e6]
		set v_tsec_old  $tsec
		set v_tusec_old $tusec
		lappend vttmp  [expr ($tsec+$tusec/1.e6)-$t0]
#		lappend vtmp   [expr $value/$v_dt]
		# It seems that each value returned is a speed, so it is not necessary to divide
		# by the time increment
		lappend vtmp   $value
		incr vcount
	    }
	}
	incr i
#	puts "$ucount $vcount"
    }

    # Close the channel:
    close $ms

    ::utvec set $uttmp
    ::uvec  set $utmp
    ::vtvec set $vttmp
    ::vvec  set $vtmp

    if {[::uvec length] > 1} {
	if {[::vvec length] > 1} {
	    set ubar [vector expr {mean(::uvec)}]
	    set vbar [vector expr {mean(::vvec)}]
	    ::uvec set [vector expr {::uvec - $ubar}]
	    ::vvec set [vector expr {::vvec - $vbar}]
	    set uvar [vector expr {mean(::uvec * ::uvec)}]
	    set vvar [vector expr {mean(::vvec * ::vvec)}]
	    if {[::uvec length] <= [::vvec length]} {
		set lu [::uvec length]
		set lu [expr $lu - 1]
		::vvec set ::vvec(0:$lu)
		::vtvec set ::vtvec(0:$lu)
		set uvcov [vector expr {mean(::uvec * ::vvec)}]
	    } else {
		set lu [::vvec length]
		set lu [expr $lu - 1]
		::uvec set ::uvec(0:$lu)
		::utvec set ::utvec(0:$lu)
		set uvcov [vector expr {mean(::uvec * ::vvec)}]
	    }
	    puts "$ubar $vbar $uvar $vvar $uvcov"
    	    return "$ubar $vbar $uvar $vvar $uvcov"
	}
    }

    return "#ERROR"
}

proc value_dialog {string} {
    set w [toplevel .[clock seconds]]
    wm resizable $w 0 0
    wm title $w "Value request"
    wm attributes $w -topmost true
    label  $w.l -text $string
    entry  $w.e -textvar $w -bg white
    bind $w.e <Return> {set done 1}
    button $w.ok     -text OK     -command {set done 1}
    button $w.c      -text Clear  -command "set $w {}"
    button $w.cancel -text Cancel -command "set $w {}; set done 1"
    grid $w.l  -    -        -sticky news
    grid $w.e  -    -        -sticky news
    grid $w.ok $w.c $w.cancel
    focus $w.e
    vwait done
    destroy $w
    set ::$w
}


stripchart .s1 -height 2i -width 8i -bufferelements no
stripchart .s2 -height 2i -width 8i -bufferelements no

pack .s1 .s2

.s1 element create line1 -xdata utvec -ydata uvec -symbol none
.s2 element create line2 -xdata vtvec -ydata vvec -symbol none -color red
#.s1 axis configure y -min -16000 -max 16000
#.s2 axis configure y -min -16000 -max 16000

# Disable the selected device so you can keep using the computer while
# the mouse is collecting data:
# Does not work on puppy linux:
#disablemouse $dev

# Bind keypress event to write the next available out string to file.
global outnow
set outnow 0
bind . <Key> {global outnow ; set outnow 1}

set tstamp [clock format [clock seconds] -format %y%m%dT%H%M%S]
set fid [open ./Data/d${tstamp}.dat w]
set hdr [value_dialog "Enter header for output file:"]
puts $fid "###"
puts $fid "### Output of testdev.tcl on [exec hostname]."
puts $fid "### Edward D. Zaron"
puts $fid "### Dept of Civil and Environmental Engineering"
puts $fid "### Portland State University"
puts $fid "### Portland, OR USA"
puts $fid "### ezaron@pdx.edu"
puts $fid "### 503-725-2435"
puts $fid "###" 
puts $fid "### $hdr"
puts $fid "### Columns are in instrument units:"
puts $fid "### ubar vbar uvar vvar uvcov"
puts $fid "###"
flush $fid

# Enter the event loop and collect data:
while {1 == 1} {
	update idletasks
	set out [rawvel $dev $nsamp]
#	For some reason update idletasks is not enough to force
#	evaluation of the bind script.
#	update idletasks
	update
	puts $outnow
	if {$outnow == 1} {
	    set xval [value_dialog "X Value:"]
	    puts "Writing data to file."
	    puts $fid "$xval $out"
	    set outnow 0
	    flush $fid
	}
}

# How shall we despike or average?

## unused stuff below:
proc getselection {} {
    set ret [.devlist curselection]
    puts "You chose number $ret"
    return $ret
}

proc selectdevice {} {
    # Choose device:
    set devname [split [exec xinput list --name-only] \n]
    set devid   [split [exec xinput list --id-only] \n]

    listbox .devlist
    set count 0
    foreach id $devid {
	set str "id = $id [lindex $devname $count]"
	.devlist insert end $str
	incr count
    }
    
    button .choose -text "Select" -command getselection
    pack .devlist .choose -expand true -fill both

}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




































































































































































































































































































































































































































































































































































































































































































Deleted Software/ts.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
#!/usr/local/bin/bltwish

##!/usr/bin/tclsh
#package require Tk
#package require BLT

#!/usr/local/bin/tclsh8.5

# xinput query-state 11
# xinput test 11
# xinput test-xi2
# xinput list-props 11
# sudo tclsh to run this script

# This will increase the mouse polling rate to 1kHz:
# sudo modprobe -r usbhid && sudo modprobe usbhid mousepoll=1
# THEN UN-PLUG AND RE-PLUG MOUSE.
# See https://wiki.archlinux.org/index.php/Mouse_Polling_Rate for other settings.

# Set up tcl/tk with tools we need to graph the data:


namespace import blt::*

# Initialize vectors
set nsamp 250 ;  # nominally, 1 second of data
#set nsamp 1000 ;  # nominally, 1 second of data
set nsamp 6000 ;  # nominally, 3 second of data at 500Hz
set nsamp 60000 ;  # Lng run

# COLLECT A TIME SERIES OF nsamp DURATION AND WRITE TO FILE.

vector create utvec($nsamp) vtvec($nsamp) uvec($nsamp) vvec($nsamp)
vector create vzero($nsamp)

# "xinput list" provides a list of possible input devices.
# Device 11 is the mouse on my laptop.
# Default location (sometimes?)
set dev 9
# After setting polling rate with usbhid:
set dev 15
# Logitech wireless? It seems that after unplugging and replugging, the device comes back on 15:
#set dev 16
#set dev 10
#set dev 11

# Disable the mouse:
proc disablemouse dev {
    # other pointers should continue to work.
    exec xinput disable $dev
}

# Enable the mouse:
proc enablemouse dev {
    exec xinput enable $dev
}

# Determine the file name for accessing the mouse:
proc getnode dev {
	# On puppy linux, the mouse seems to show up at
#	return /dev/sudo modprobe -r usbhid && sudo modprobe usbhid mousepoll=1
# THEN UN-PLUG AND RE-PLUG MOUSE.
# 	Mad CAT:
#	return /dev/input/event8
# Titanium:
#	return /dev/input/event3
	return /dev/input/event2
	# red button is here:
#	return /dev/input/event2
#	return /dev/input/event12

    # Execute xinput and grab the line containing "Device Node"
    set retstr [exec xinput list-props $dev | grep "Device Node"]
    # Parse the result to pull out the file name which is within quotes
    regexp {\"(.+?)\"} $retstr -> match
    return $match
}

# Find out the polling rate on the device:
proc checkrate dev {
    set devnode [getnode $dev]

    # "xinput list-props 11" shows that the mouse is at /dev/input/event6
    # We must run tclsh as root, "sudo tclsh", in order to access the mouse in the following:

    # Open the channel and configure it for directly reading binary data.
    set ms [open $devnode rb]
    chan configure $ms -encoding binary -translation binary -buffering none
    
    puts "Start moving the device and keep it in continuous motion."
    set i 0
    set count 0
    set imax 1000
    set dtsum 0.
    while {$i < $imax} {
	set buf [read $ms 16]
	#    binary scan $buf iissi tvsec tvusec type code value
	binary scan $buf iissi tvsec tvusec type code value
	puts "$tvsec $tvusec $type $code $value"
	# See linux/linux.h for a desciption of the event structure:
	# tvsec
	# tvusec
	# type = 0 (sync) 2 (rel)
	# code = 0 (xaxis) 1 (yaxis)
	# value = amount of change.
	if {$type == 0} {
	    if {$count > 0} {
		set dt    [expr ($tvsec - $tsec)+($tvusec - $tusec)/1.e6]
		set dtsum [expr $dtsum + $dt]
	    }
	    set tsec  $tvsec
	    set tusec $tvusec
	    incr count
	}
	incr i
    }
    set rate [expr $dtsum/$count ] ; # Average dt over test period.
    set rate [expr 1./$rate ] ; # convert rate to Hz = 1/sec
    puts "Found polling rate = $rate Hz from $count samples."

    # Close the channel:
    close $ms

    return
}


# Read the device and compute instantaneous and average velocity in device units.
# Note that the vectors utvec, vtvec, uvec, and vvec are global variables.
proc rawvel {dev nsamp} {
    set devnode [getnode $dev]

    ::utvec set ::vzero
    ::vtvec set ::vzero
    ::uvec  set ::vzero
    ::vvec  set ::vzero

    set uttmp  [list]
    set utmp   [list]
    set vttmp  [list]
    set vtmp   [list]

    # Open the channel and configure it for directly reading binary data.
    # Need to put this in a "catch" statement with reminder to 
    # run tclsh as sudo.
    set ms [open $devnode rb]
    chan configure $ms -encoding binary -translation binary -buffering none

    set i 0
    set buf [read $ms 16]
    #    binary scan $buf iissi tvsec tvusec type code value
    binary scan $buf iissi tsec tusec type code value

#    puts "$tsec $tusec $type $code $value"
    set u_tsec_old  $tsec
    set u_tusec_old $tusec
    set v_tsec_old  $tsec
    set v_tusec_old $tusec
    set t0 [expr $tsec + $tusec/1.e6]

    set ucount 0
    set vcount 0
    while {$i < $nsamp} {
	set buf [read $ms 16]
	#    binary scan $buf iissi tvsec tvusec type code value
	binary scan $buf iissi tsec tusec type code value
#	puts "$tsec $tusec $type $code $value"
	# sec
	# usec
	# type = 0 (sync) 2 (rel)
	# code = 0 (xaxis) 1 (yaxis)
	# value = amount of change.
	# Only record increments when a relative change is reported:

	if {$type == 2} {
	    if {$code == 0} {
		set u_dt    [expr ($tsec - $u_tsec_old)+($tusec - $u_tusec_old)/1.e6]
		set u_tsec_old  $tsec
		set u_tusec_old $tusec
		lappend uttmp  [expr ($tsec+$tusec/1.e6)-$t0]
		#		lappend utmp   [expr $value/$u_dt]
		# It seems that each value returned is a speed, so it is not necessary to divide
		# by the time increment
		lappend utmp   $value
		incr ucount
	    }
	    if {$code == 1} {
		set v_dt    [expr ($tsec - $v_tsec_old)+($tusec - $v_tusec_old)/1.e6]
		set v_tsec_old  $tsec
		set v_tusec_old $tusec
		lappend vttmp  [expr ($tsec+$tusec/1.e6)-$t0]
#		lappend vtmp   [expr $value/$v_dt]
		# It seems that each value returned is a speed, so it is not necessary to divide
		# by the time increment
		lappend vtmp   $value
		incr vcount
	    }
	}
	incr i
#	puts "$ucount $vcount"
    }

    # Close the channel:
    close $ms

    ::utvec set $uttmp
    ::uvec  set $utmp
    ::vtvec set $vttmp
    ::vvec  set $vtmp

    return 0
}

proc value_dialog {string} {
    set w [toplevel .[clock seconds]]
    wm resizable $w 0 0
    wm title $w "Value request"
    wm attributes $w -topmost true
    label  $w.l -text $string
    entry  $w.e -textvar $w -bg white
    bind $w.e <Return> {set done 1}
    button $w.ok     -text OK     -command {set done 1}
    button $w.c      -text Clear  -command "set $w {}"
    button $w.cancel -text Cancel -command "set $w {}; set done 1"
    grid $w.l  -    -        -sticky news
    grid $w.e  -    -        -sticky news
    grid $w.ok $w.c $w.cancel
    focus $w.e
    vwait done
    destroy $w
    set ::$w
}


stripchart .s1 -height 2i -width 8i -bufferelements no
stripchart .s2 -height 2i -width 8i -bufferelements no

pack .s1 .s2

.s1 element create line1 -xdata utvec -ydata uvec -symbol none
.s2 element create line2 -xdata vtvec -ydata vvec -symbol none -color red
#.s1 axis configure y -min -16000 -max 16000
#.s2 axis configure y -min -16000 -max 16000

# Disable the selected device so you can keep using the computer while
# the mouse is collecting data:
# Does not work on puppy linux:
#disablemouse $dev

# Bind keypress event to write the next available out string to file.
global outnow
set outnow 0
bind . <Key> {global outnow ; set outnow 1}

proc newfile {} {
set tstamp [clock format [clock seconds] -format %y%m%dT%H%M%S]
set fid [open ./Data/ts${tstamp}.dat w]
set hdr [value_dialog "Enter header for output file:"]
puts $fid "###"
puts $fid "### Output of testdev.tcl on [exec hostname]."
puts $fid "### Edward D. Zaron"
puts $fid "### Dept of Civil and Environmental Engineering"
puts $fid "### Portland State University"
puts $fid "### Portland, OR USA"
puts $fid "### ezaron@pdx.edu"
puts $fid "### 503-725-2435"
puts $fid "###" 
puts $fid "### $hdr"
puts $fid "### Columns are in instrument units"
puts $fid "### k utvec(k) uvec(k)"
puts $fid "### k vtvec(k) vvec(k)"
flush $fid
return $fid
}

# Enter the event loop and collect data:
while {1 == 1} {
	update idletasks
	set out [rawvel $dev $nsamp]
#	For some reason update idletasks is not enough to force
#	evaluation of the bind script.
#	update idletasks
	update
	puts $outnow
	if {$outnow == 1} {
	    puts "Writing data to file."
	    set fid [newfile]
		set k 0
		while {$k < [::utvec length]} {
		    puts $fid "$k $::utvec($k) $::uvec($k)"
		    incr k
		}
		set k 0
		while {$k < [::vtvec length]} {
		    puts $fid "$k $::vtvec($k) $::vvec($k)"
		    incr k
		}
	    set outnow 0
	    flush $fid
	    close $fid
	}
}

# How shall we despike or average?

## unused stuff below:
proc getselection {} {
    set ret [.devlist curselection]
    puts "You chose number $ret"
    return $ret
}

proc selectdevice {} {
    # Choose device:
    set devname [split [exec xinput list --name-only] \n]
    set devid   [split [exec xinput list --id-only] \n]

    listbox .devlist
    set count 0
    foreach id $devid {
	set str "id = $id [lindex $devname $count]"
	.devlist insert end $str
	incr count
    }
    
    button .choose -text "Select" -command getselection
    pack .devlist .choose -expand true -fill both

}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<