Commit 52e659d531be3f0b11ac00670129cbbc3adae6fa

Authored by Brice Colombier
0 parents
Exists in master

Initial commit

Showing 11 changed files with 1142 additions and 0 deletions

... ... @@ -0,0 +1 @@
  1 +*.pyc
0 2 \ No newline at end of file
HECTOR_data_acq.tcl View file @ 52e659d
... ... @@ -0,0 +1,754 @@
  1 +##############################################################################
  2 +#
  3 +# Design unit: HECTOR TCL language extension
  4 +#
  5 +# File name: HECTOR_data_acq.tcl
  6 +#
  7 +# Description: TCL language extension providing high-level access to
  8 +# communication interface with HECTOR evaluation boards.
  9 +#
  10 +# System: TCL v. 8.5 and higher
  11 +#
  12 +# Author: O. Petura - Hubert Curien Laboratory
  13 +#
  14 +# Copyright: Hubert Curien Laboratory, 2016
  15 +#
  16 +# Revision: Version 1.00, April 2016
  17 +#
  18 +##############################################################################
  19 +
  20 +
  21 +# Timeout for the UART response in seconds
  22 +set UART_timeout 5
  23 +
  24 +# Timeout between two consequent checks of UART input buffer
  25 +set uart_check_timeout 100
  26 +
  27 +# Opens a connection to HECTOR evaluation board
  28 +proc openDevice {dev {verbose 0}} {
  29 +
  30 + global tcl_platform
  31 +
  32 +# Append \\.\ to serial port number when we are running on Windows
  33 + if {[string first "Win" $tcl_platform(os)] != -1} {
  34 + set dev "\\\\.\\$dev"
  35 + }
  36 +
  37 +# Open the serial device
  38 + if { [catch { open $dev "r+" } fd ] } {
  39 + if {$verbose != 0} {
  40 + puts "Error opening device '$dev'\n Error description: $::errorInfo"
  41 + }
  42 + puts "Error opening device '$dev'"
  43 + set ret -1
  44 + } else {
  45 +# Configure communication parameters
  46 + fconfigure $fd -blocking 0 -buffering none -mode "115200,n,8,1" -translation binary -eofchar {}
  47 +
  48 +# Update the application status
  49 + puts "Connection to '$dev' opened"
  50 +
  51 +# Create device handle
  52 + set ret [list $dev $fd]
  53 +
  54 + }
  55 +
  56 + return $ret
  57 +
  58 +}
  59 +
  60 +# Disconnect from the HECTOR evaluation board
  61 +proc disconnect {device} {
  62 +
  63 +# Close the connection to the serial device
  64 + close [lindex $device 1]
  65 +
  66 +# Update the application status
  67 + puts "Connection to '[lindex $device 0]' closed"
  68 +}
  69 +
  70 +# Poll the serial device for input data
  71 +proc pollDevice {device {verbose 0}} {
  72 +
  73 +# Read the input serial buffer
  74 + set data [read [lindex $device 1]]
  75 +
  76 +# If there is something, process it
  77 + if {[string length $data] != 0} {
  78 + if {$verbose != 0} {
  79 + puts "Received data: [toHEX $data]"
  80 + }
  81 +
  82 +# Get the MSS status packet header offset
  83 + set offset [string first "\x13\x57\x00\x00" $data]
  84 + if {$offset != -1} {
  85 +# Get the status fields
  86 + set response [string range $data [expr $offset + 11] [expr $offset + 11]]
  87 + set progress [string range $data [expr $offset + 8] [expr $offset + 8]]
  88 + set aq_state [string range $data [expr $offset + 9] [expr $offset + 9]]
  89 + set gpio [string range $data [expr $offset + 10] [expr $offset + 10]]
  90 +
  91 + binary scan $response c1 ret(response)
  92 + binary scan $progress c1 ret(progress)
  93 + binary scan $aq_state c1 ret(aq_state)
  94 + set ret(gpio) [toHEX $gpio]
  95 + return [list $ret(response) $ret(progress) $ret(aq_state) $ret(gpio)]
  96 + } else {
  97 +
  98 +# Get the FPGA status packet header offset
  99 + set offset [string first "\x13\xF5\x00\x00" $data]
  100 + if {$offset != -1} {
  101 +# Get the status fields
  102 + set fpga_data [string range $data [expr $offset + 4] [expr $offset + 7]]
  103 + set fpga_status [string range $data [expr $offset + 8] [expr $offset + 11]]
  104 +
  105 + set ret(fpga_data) [toHEX $fpga_data]
  106 + set ret(fpga_status) [toHEX $fpga_status]
  107 + return [list $ret(fpga_status) $ret(fpga_data)]
  108 + }
  109 + }
  110 + } else {
  111 + set ret(response) -1
  112 + set ret(appError) 1
  113 + return [list $ret(response) $ret(appError)]
  114 + }
  115 +
  116 +}
  117 +
  118 +# Wait for a specified time
  119 +proc wait_ms {ms} {
  120 +
  121 +# Create a variable name
  122 + set varName finished_[clock clicks]
  123 + global $varName
  124 +
  125 +# Set the variable after a specified timeout
  126 + after $ms set $varName 1
  127 +
  128 +# Wait for the variable to be set
  129 + vwait $varName
  130 +
  131 +# Clear the variable from memory
  132 + unset $varName
  133 +}
  134 +
  135 +# Convert a binary string to HEX
  136 +proc toHEX {in} {
  137 + set ret ""
  138 + for {set i 0} {$i < [string length $in]} {incr i} {
  139 + binary scan [string index $in $i] c1 byte
  140 + if {$byte < 0} {set byte [expr 256 + $byte]}
  141 + set HI [expr $byte >> 4]
  142 + set LO [expr $byte & 15]
  143 + switch $HI {
  144 + 0 {append ret "0"}
  145 + 1 {append ret "1"}
  146 + 2 {append ret "2"}
  147 + 3 {append ret "3"}
  148 + 4 {append ret "4"}
  149 + 5 {append ret "5"}
  150 + 6 {append ret "6"}
  151 + 7 {append ret "7"}
  152 + 8 {append ret "8"}
  153 + 9 {append ret "9"}
  154 + 10 {append ret "A"}
  155 + 11 {append ret "B"}
  156 + 12 {append ret "C"}
  157 + 13 {append ret "D"}
  158 + 14 {append ret "E"}
  159 + 15 {append ret "F"}
  160 + }
  161 + switch $LO {
  162 + 0 {append ret "0"}
  163 + 1 {append ret "1"}
  164 + 2 {append ret "2"}
  165 + 3 {append ret "3"}
  166 + 4 {append ret "4"}
  167 + 5 {append ret "5"}
  168 + 6 {append ret "6"}
  169 + 7 {append ret "7"}
  170 + 8 {append ret "8"}
  171 + 9 {append ret "9"}
  172 + 10 {append ret "A"}
  173 + 11 {append ret "B"}
  174 + 12 {append ret "C"}
  175 + 13 {append ret "D"}
  176 + 14 {append ret "E"}
  177 + 15 {append ret "F"}
  178 + }
  179 + }
  180 + return $ret
  181 +}
  182 +
  183 +# Function to convert HEX to DEC
  184 +proc fromHEX {in} {
  185 + set in_end [expr [string length $in] - 1]
  186 + set ret 0
  187 + for {set i $in_end} {$i >= 0} {incr i -1} {
  188 + switch [string index $in $i] {
  189 + "0" {set val 0}
  190 + "1" {set val 1}
  191 + "2" {set val 2}
  192 + "3" {set val 3}
  193 + "4" {set val 4}
  194 + "5" {set val 5}
  195 + "6" {set val 6}
  196 + "7" {set val 7}
  197 + "8" {set val 8}
  198 + "9" {set val 9}
  199 + "A" {set val 10}
  200 + "B" {set val 11}
  201 + "C" {set val 12}
  202 + "D" {set val 13}
  203 + "E" {set val 14}
  204 + "F" {set val 15}
  205 + }
  206 + set ret [expr $ret + ($val * (16**($in_end - $i)))]
  207 + }
  208 + return $ret
  209 +}
  210 +
  211 +# Function to read bit value from a specific bit field in decimal value
  212 +proc getBitValue {decNumber bitFieldIndex} {
  213 + return [expr ( $decNumber & (2**$bitFieldIndex) ) >> $bitFieldIndex]
  214 +}
  215 +
  216 +# Bitwise XOR of two HEX values
  217 +proc xorHEX { in1 in2 } {
  218 + if { [string length $in1] != [string length $in2] } {
  219 + return -1
  220 + } else {
  221 + set ret ""
  222 + for {set i 0} {$i < [string length $in1]} {incr i} {
  223 + set num1 [fromHEX [string index $in1 $i]]
  224 + set num2 [fromHEX [string index $in2 $i]]
  225 + set xor_val [expr $num1^$num2]
  226 + if {$xor_val < 10} {
  227 + set hex_val $xor_val
  228 + } else {
  229 + switch $xor_val {
  230 + "10" {set hex_val "A"}
  231 + "11" {set hex_val "B"}
  232 + "12" {set hex_val "C"}
  233 + "13" {set hex_val "D"}
  234 + "14" {set hex_val "E"}
  235 + "15" {set hex_val "F"}
  236 + }
  237 + }
  238 + set ret "$ret$hex_val"
  239 + }
  240 + return $ret
  241 + }
  242 +}
  243 +
  244 +##############
  245 +## COMMANDS ##
  246 +##############
  247 +
  248 +proc getStatus {device {verbose 0}} {
  249 + global UART_timeout
  250 + global uart_check_timeout
  251 +
  252 + set data "\x13\xC0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07"
  253 + puts -nonewline [lindex $device 1] $data
  254 + if {$verbose != 0} {
  255 + puts "Sending: [toHEX $data]"
  256 + }
  257 +
  258 + set resp "-1 1"
  259 + set start [clock seconds]
  260 + while { [string match $resp "-1 1"] } {
  261 + set resp [pollDevice $device $verbose]
  262 + if { [clock seconds] > [expr $start + $UART_timeout] } {
  263 + break
  264 + }
  265 + wait_ms $uart_check_timeout
  266 + }
  267 + set st1 $resp
  268 +
  269 + set data "\x13\xFB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
  270 + puts -nonewline [lindex $device 1] $data
  271 + if {$verbose != 0} {
  272 + puts "Sending: [toHEX $data]"
  273 + }
  274 +# Return the response of the command
  275 + set resp "-1 1"
  276 + set start [clock seconds]
  277 + while { [string match $resp "-1 1"] } {
  278 + set resp [pollDevice $device $verbose]
  279 + if { [clock seconds] > [expr $start + $UART_timeout] } {
  280 + break
  281 + }
  282 + wait_ms $uart_check_timeout
  283 + }
  284 + set st2 $resp
  285 +
  286 + set status [list [lindex $st1 0] [lindex $st1 1] [lindex $st1 2] [lindex $st1 3] [lindex $st2 0] [lindex $st2 1]]
  287 +
  288 + return $status
  289 +}
  290 +
  291 +proc sendFabricCommand {device command data {verbose 0}} {
  292 + global UART_timeout
  293 + global uart_check_timeout
  294 +
  295 + set data "\x13\xFB\x00\x00[binary format I1 $data][binary format I1 $command]"
  296 + puts -nonewline [lindex $device 1] $data
  297 + if {$verbose != 0} {
  298 + puts "Sending: [toHEX $data]"
  299 + }
  300 +# Return the response of the command
  301 + set resp "-1 1"
  302 + set start [clock seconds]
  303 + while { [string match $resp "-1 1"] } {
  304 + set resp [pollDevice $device $verbose]
  305 + if { [clock seconds] > [expr $start + $UART_timeout] } {
  306 + break
  307 + }
  308 + wait_ms $uart_check_timeout
  309 + }
  310 + return $resp
  311 +}
  312 +
  313 +proc sendFabricReset {device {verbose 0}} {
  314 + global UART_timeout
  315 + global uart_check_timeout
  316 +
  317 + set data "\x13\xC0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04"
  318 + puts -nonewline [lindex $device 1] $data
  319 + if {$verbose != 0} {
  320 + puts "Sending: [toHEX $data]"
  321 + }
  322 +# Return the response of the command
  323 + set resp "-1 1"
  324 + set start [clock seconds]
  325 + while { [string match $resp "-1 1"] } {
  326 + set resp [pollDevice $device $verbose]
  327 + if { [clock seconds] > [expr $start + $UART_timeout] } {
  328 + break
  329 + }
  330 + wait_ms $uart_check_timeout
  331 + }
  332 + return $resp
  333 +}
  334 +
  335 +proc sendDaughterReset {device {verbose 0}} {
  336 + global UART_timeout
  337 + global uart_check_timeout
  338 +
  339 + set data "\x13\xC0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05"
  340 + puts -nonewline [lindex $device 1] $data
  341 + if {$verbose != 0} {
  342 + puts "Sending: [toHEX $data]"
  343 + }
  344 +# Return the response of the command
  345 + set resp "-1 1"
  346 + set start [clock seconds]
  347 + while { [string match $resp "-1 1"] } {
  348 + set resp [pollDevice $device $verbose]
  349 + if { [clock seconds] > [expr $start + $UART_timeout] } {
  350 + break
  351 + }
  352 + wait_ms $uart_check_timeout
  353 + }
  354 + return $resp
  355 +}
  356 +
  357 +proc mountDisk {device {verbose 0}} {
  358 + global UART_timeout
  359 + global uart_check_timeout
  360 +
  361 + set data "\x13\xC0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06"
  362 + puts -nonewline [lindex $device 1] $data
  363 + if {$verbose != 0} {
  364 + puts "Sending: [toHEX $data]"
  365 + }
  366 +# Return the response of the command
  367 + set resp "-1 1"
  368 + set start [clock seconds]
  369 + while { [string match $resp "-1 1"] } {
  370 + set resp [pollDevice $device $verbose]
  371 + if { [clock seconds] > [expr $start + $UART_timeout] } {
  372 + break
  373 + }
  374 + wait_ms $uart_check_timeout
  375 + }
  376 + return $resp
  377 +}
  378 +
  379 +proc createFileSystem {device {verbose 0}} {
  380 + global UART_timeout
  381 + global uart_check_timeout
  382 +
  383 + set data "\x13\xC0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08"
  384 + puts -nonewline [lindex $device 1] $data
  385 + if {$verbose != 0} {
  386 + puts "Sending: [toHEX $data]"
  387 + }
  388 +# Return the response of the command
  389 + set resp "-1 1"
  390 + set start [clock seconds]
  391 + while { [string match $resp "-1 1"] } {
  392 + set resp [pollDevice $device $verbose]
  393 + if { [clock seconds] > [expr $start + $UART_timeout] } {
  394 + break
  395 + }
  396 + wait_ms $uart_check_timeout
  397 + }
  398 + return $resp
  399 +}
  400 +
  401 +proc beginAcquisition {device filename size {verbose 0}} {
  402 + global UART_timeout
  403 + global uart_check_timeout
  404 +
  405 + set data "\x13\xFD\x00\x00$filename [binary format I1 $size]"
  406 + puts -nonewline [lindex $device 1] $data
  407 + if {$verbose != 0} {
  408 + puts "Sending command: [toHEX $data]"
  409 + }
  410 +# Return the response of the command
  411 + set resp "-1 1"
  412 + set start [clock seconds]
  413 + while { [string match $resp "-1 1"] } {
  414 + set resp [pollDevice $device $verbose]
  415 + if { [clock seconds] > [expr $start + $UART_timeout] } {
  416 + break
  417 + }
  418 + wait_ms $uart_check_timeout
  419 + }
  420 + return $resp
  421 +}
  422 +
  423 +proc loadInputFile {device filename size {verbose 0}} {
  424 + global UART_timeout
  425 + global uart_check_timeout
  426 +
  427 + set data "\x13\x3D\x00\x00$filename [binary format I1 $size]"
  428 + puts -nonewline [lindex $device 1] $data
  429 + if {$verbose != 0} {
  430 + puts "Sending command: [toHEX $data]"
  431 + }
  432 +# Return the response of the command
  433 + set resp "-1 1"
  434 + set start [clock seconds]
  435 + while { [string match $resp "-1 1"] } {
  436 + set resp [pollDevice $device $verbose]
  437 + if { [clock seconds] > [expr $start + $UART_timeout] } {
  438 + break
  439 + }
  440 + wait_ms $uart_check_timeout
  441 + }
  442 + return $resp
  443 +}
  444 +
  445 +proc configureGPIO {device GPIO {verbose 0}} {
  446 + global UART_timeout
  447 + global uart_check_timeout
  448 +
  449 + set data "\x13\xC0\x00\x00\x00\x00\x00\x00\x00\x00[binary format c1 $GPIO]\x09"
  450 + puts -nonewline [lindex $device 1] $data
  451 + if {$verbose != 0} {
  452 + puts "Sending command: [toHEX $data]"
  453 + }
  454 +# Return the response of the command
  455 + set resp "-1 1"
  456 + set start [clock seconds]
  457 + while { [string match $resp "-1 1"] } {
  458 + set resp [pollDevice $device $verbose]
  459 + if { [clock seconds] > [expr $start + $UART_timeout] } {
  460 + break
  461 + }
  462 + wait_ms $uart_check_timeout
  463 + }
  464 + return $resp
  465 +}
  466 +
  467 +proc setGPIO {device GPIO {verbose 0}} {
  468 + global UART_timeout
  469 + global uart_check_timeout
  470 +
  471 + set data "\x13\xC0\x00\x00\x00\x00\x00\x00\x00\x00[binary format c1 $GPIO]\x0A"
  472 + puts -nonewline [lindex $device 1] $data
  473 + if {$verbose != 0} {
  474 + puts "Sending command: [toHEX $data]"
  475 + }
  476 +# Return the response of the command
  477 + set resp "-1 1"
  478 + set start [clock seconds]
  479 + while { [string match $resp "-1 1"] } {
  480 + set resp [pollDevice $device $verbose]
  481 + if { [clock seconds] > [expr $start + $UART_timeout] } {
  482 + break
  483 + }
  484 + wait_ms $uart_check_timeout
  485 + }
  486 + return $resp
  487 +}
  488 +
  489 +proc softReset {device {verbose 0}} {
  490 + global UART_timeout
  491 + global uart_check_timeout
  492 +
  493 + set data "\x13\xC0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0B"
  494 + puts -nonewline [lindex $device 1] $data
  495 + if {$verbose != 0} {
  496 + puts "Sending command: [toHEX $data]"
  497 + }
  498 +# Return the response of the command
  499 + set resp "-1 1"
  500 + set start [clock seconds]
  501 + while { [string match $resp "-1 1"] } {
  502 + set resp [pollDevice $device $verbose]
  503 + if { [clock seconds] > [expr $start + $UART_timeout] } {
  504 + break
  505 + }
  506 + wait_ms $uart_check_timeout
  507 + }
  508 + return $resp
  509 +}
  510 +
  511 +# board =
  512 +# 1 - HDMI
  513 +# 2 - SATA
  514 +proc selectDaughterBoard {device board {verbose 0}} {
  515 + global UART_timeout
  516 + global uart_check_timeout
  517 +
  518 + if { $board == 1 } {
  519 + set command 2
  520 + } elseif { $board == 2 } {
  521 + set command 3
  522 + } else {
  523 + set command 0
  524 + }
  525 + set data "\x13\xFB\x00\x00\x00\x00\x00\x00[binary format I1 $command]"
  526 + puts -nonewline [lindex $device 1] $data
  527 + if {$verbose != 0} {
  528 + puts "Sending command: [toHEX $data]"
  529 + }
  530 +# Return the response of the command
  531 + set resp "-1 1"
  532 + set start [clock seconds]
  533 + while { [string match $resp "-1 1"] } {
  534 + set resp [pollDevice $device $verbose]
  535 + if { [clock seconds] > [expr $start + $UART_timeout] } {
  536 + break
  537 + }
  538 + wait_ms $uart_check_timeout
  539 + }
  540 + return $resp
  541 +}
  542 +
  543 +###########################
  544 +## Application functions ##
  545 +###########################
  546 +
  547 +# Find the connected disk drives
  548 +proc findDiskDrives {} {
  549 + global tcl_platform
  550 +
  551 + set drives ""
  552 +
  553 + if {[string match $tcl_platform(os) "Linux"]} {
  554 + if { [catch {exec blkid} disks] } {
  555 + puts "blkid is not available. Automatic disk recognition is impossible."
  556 + return -1
  557 + } else {
  558 + set disks [split $disks "\n"]
  559 + foreach disk $disks {
  560 + set uuid_offset [string first "UUID=" $disk]
  561 + set device [string range $disk 0 [expr [string first ":" $disk] - 1]]
  562 +# Get the mountpoint
  563 + set mountpoint ""
  564 + set f [open "/proc/mounts" "r"]
  565 + while { [gets $f line] >= 0} {
  566 + if {[string first $device $line] != -1} {
  567 + set mountpoint [lindex $line 1]
  568 + break
  569 + }
  570 + }
  571 + close $f
  572 +
  573 + if { $uuid_offset != -1 } {
  574 + set uuidStart [expr $uuid_offset + 5]
  575 + set uuidEnd [string first "\"" $disk [expr $uuidStart + 1]]
  576 + set uuidString [string range $disk [expr $uuidStart + 1] [expr $uuidEnd - 1]]
  577 + lappend drives [list $device $uuidString $mountpoint]
  578 + }
  579 + }
  580 + }
  581 + } elseif {[string first "Win" $tcl_platform(os)] != -1} {
  582 + set disks [file volumes]
  583 + foreach disk $disks {
  584 + set disk [string range $disk 0 end-1]
  585 + if {[catch {exec cmd /c vol $disk} resp]} {
  586 + continue
  587 + } else {
  588 + set disk [string range $disk 0 end-1]
  589 + set uuidString [string range $resp end-8 end]
  590 + lappend drives [list $disk $uuidString "$disk:/"]
  591 + }
  592 + }
  593 + } else {
  594 + puts "Only linux and windows platforms are supported for the moment"
  595 + return -1
  596 + }
  597 +
  598 + return $drives
  599 +}
  600 +
  601 +# Find HECTOR disk
  602 +proc findHECTOR {{timeout 5}} {
  603 + set start [clock seconds]
  604 + set hectorDrive 0
  605 +
  606 + while { $hectorDrive == 0 && [expr [clock seconds] - $start] < $timeout} {
  607 + set disks [findDiskDrives]
  608 + foreach disk $disks {
  609 + if { [string match "48A1-0000" [lindex $disk 1]] } {
  610 + set hectorDrive $disk
  611 + break
  612 + }
  613 + }
  614 + wait_ms 100
  615 + }
  616 + return $hectorDrive
  617 +}
  618 +
  619 +# Sync filesystem
  620 +proc syncDrives {} {
  621 + global tcl_platform
  622 +
  623 + if {[string match $tcl_platform(os) "Linux"]} {
  624 + if { [catch {exec sync} ret] } {
  625 + puts "Disk sync failed."
  626 + return -1
  627 + } else {
  628 + return 0
  629 + }
  630 + } elseif {[string first "Win" $tcl_platform(os)] != -1} {
  631 + if { [catch {exec "sync.exe"} ret] } {
  632 + puts "Disk sync failed."
  633 + return -1
  634 + } else {
  635 + return 0
  636 + }
  637 + } else {
  638 + puts "Only linux and windows platforms are supported for the moment"
  639 + return -1
  640 + }
  641 +}
  642 +
  643 +proc acquireData {device filename filesize {interface 0} {debug 0}} {
  644 + global tcl_platform
  645 +
  646 +
  647 +# Reset the FPGA controller
  648 + set err [softReset $device $debug]
  649 + if {[lindex $err 0] != 0} {
  650 + puts "Soft reset failed with code $err"
  651 + return $err
  652 + }
  653 +
  654 +# Set the right interface
  655 +# 0 = SATA
  656 +# 1 = HDMI
  657 + if { $interface == 0 } {
  658 + set err [sendFabricCommand $device 3]
  659 + if { [lindex $err 0] != 0 } {
  660 + puts "Interface set error. Code: $err"
  661 + }
  662 + } elseif { $interface == 1 } {
  663 + set err [sendFabricCommand $device 4]
  664 + if { [lindex $err 0] != 0 } {
  665 + puts "Interface set error. Code: $err"
  666 + }
  667 + }
  668 +
  669 +# Reset the daugther module
  670 + set err [sendDaughterReset $device $debug]
  671 + if {[lindex $err 0] != 0} {
  672 + puts "Daughter reset failed with code $err"
  673 + return $err
  674 + }
  675 +
  676 +# Create filesystem
  677 + set err [createFileSystem $device $debug]
  678 + if {[lindex $err 0] != 0 } {
  679 + puts "Filesystem creation failed with code $err"
  680 + return $err
  681 + }
  682 +
  683 +## Create a progressbar
  684 +# set progressbar {[=====|=====|=====|=====]}
  685 +# puts $progressbar
  686 +# set progressStep [expr 100.0 / ([string length $progressbar] - 2)]
  687 +
  688 +# Start the measurement
  689 + set err [beginAcquisition $device ACQ $filesize]
  690 + if {[lindex $err 0] != 0 } {
  691 + puts "Acquisition failed to start. Error code: $err"
  692 + return $err
  693 + }
  694 +
  695 +# set progress 0
  696 +# puts -nonewline {[}
  697 +# flush stdout
  698 + while {[lindex $err 2] != 0} {
  699 + set err [getStatus $device $debug]
  700 + if {[lindex $err 0] != 0 } {
  701 + puts "An error occured during data acquisition. Error code: $err"
  702 + return $err
  703 + } else {
  704 + puts -nonewline "[lindex $err 1] %\r"
  705 + flush stdout
  706 + #if { [lindex $err 1] > $progress } {
  707 + # set steps [expr ([lindex $err 1] - $progress) / $progressStep]
  708 + # if { $steps >= 1 } {
  709 + # set progress [expr $progress + ( floor($steps) * $progressStep)]
  710 + # #puts "$progress - $steps"
  711 + # for {set i 0} {$i < [expr floor($steps)]} {incr i} {
  712 + # puts -nonewline "#"
  713 + # flush stdout
  714 + # }
  715 + # }
  716 + #}
  717 + }
  718 + }
  719 + puts {}
  720 + flush stdout
  721 +
  722 +# Mount the disk
  723 + set err [mountDisk $device $debug]
  724 + if {[lindex $err 0] != 0} {
  725 + puts "Mounting disk failed with error code $err"
  726 + return $err
  727 + }
  728 +
  729 +# Search for the hector disk
  730 + set hectorDrive [findHECTOR 5]
  731 +
  732 + if { $hectorDrive == 0 } {
  733 + puts "Hector disk drive not found. You will have to search for it manually."
  734 + return 1
  735 + }
  736 +
  737 +# Check for the mountpoint
  738 + if { [string length [lindex $hectorDrive 2]] == 0 } {
  739 + puts "Hector disk drive is not mounted. Please mount the device [lindex $hectorDrive 0]."
  740 + return 1
  741 + }
  742 +
  743 +# Copy the file from hector disk to the PC
  744 + if { [string match $tcl_platform(os) "Linux"] } {
  745 + puts [lindex $hectorDrive 2]/ACQ
  746 + file copy -force [lindex $hectorDrive 2]/ACQ $filename
  747 + } elseif { [string first $tcl_platform(os) "Win"] != -1 } {
  748 + file copy -force {"[lindex $hectorDrive 2]/ACQ"} $filename
  749 + }
  750 +
  751 + puts "Acquired data are available in the file $filename"
  752 +
  753 + return 0
  754 +}
binary_par.py View file @ 52e659d
... ... @@ -0,0 +1,58 @@
  1 +# Author: Brice Colombier
  2 +# Laboratoire Hubert Curien
  3 +# 42000 Saint-Etienne - France
  4 +# Contact: b.colombier@univ-st-etienne.fr
  5 +# Project: Demonstrator
  6 +# File: binary_par.py
  7 +# Date : 2016-10-12
  8 +
  9 +import parity as par
  10 +import get_parities_from_indices as gpfi
  11 +
  12 +
  13 +def binary_par(reference_response, blocks_to_correct, response_on_board):
  14 +
  15 + """Implementation of the BINARY algorithm found in the CASCADE protocol.
  16 +
  17 + From a reference response and a list of blocks to correct, it obtains the
  18 + parities of the blocks on board. According to these parities, it narrows
  19 + down to either the first or the second half of each block.
  20 +
  21 + """
  22 +
  23 + block_size = int(len(blocks_to_correct[0]))
  24 + if block_size < 2:
  25 + raise ValueError("Illegal block size: too short", blocks_to_correct)
  26 + # Compute the parity of the first half of the response blocks
  27 + blocks_to_correct_first_half = [x[:int(len(x)/2)] for x in blocks_to_correct]
  28 + blocks_return = []
  29 + ref_rep = []
  30 + parities = gpfi.get_parities_from_indices(blocks_to_correct_first_half, response_on_board)
  31 + if len(blocks_to_correct[0]) > 2:
  32 + for i, j in enumerate(parities):
  33 + if par.parity(reference_response[i][:block_size/2], j):
  34 + # Error is in the first half of the block
  35 + blocks_return.append(blocks_to_correct[i][:block_size/2])
  36 + ref_rep.append(reference_response[i][:block_size/2])
  37 + else:
  38 + # Error is in the second half of the block
  39 + blocks_return.append(blocks_to_correct[i][block_size/2:])
  40 + ref_rep.append(reference_response[i][block_size/2:])
  41 + return ref_rep, blocks_return
  42 + elif len(blocks_to_correct[0]) == 2:
  43 + for i, j in enumerate(parities):
  44 + if reference_response[i][0] == j:
  45 + blocks_return.append(blocks_to_correct[i][1])
  46 + else:
  47 + blocks_return.append(blocks_to_correct[i][0])
  48 + return ref_rep, blocks_return
  49 +
  50 +if __name__ == "__main__":
  51 + list_in = [[186, 254, 7, 55, 186, 254, 7, 55],
  52 + [186, 254, 7, 55, 186, 254, 7, 55],
  53 + [186, 254, 7, 55, 186, 254, 7, 55],
  54 + [186, 254, 7, 55, 186, 254, 7, 55]]
  55 + res = binary_par(list_in, "bus_script_in1.txt", "bus_script_out1.txt")
  56 + print(res)
  57 + print([x[0] for x in res])
  58 +
... ... @@ -0,0 +1,134 @@
  1 +# Author: Brice Colombier
  2 +# Laboratoire Hubert Curien
  3 +# 42000 Saint-Etienne - France
  4 +# Contact: b.colombier@univ-st-etienne.fr
  5 +# Project: Demonstrator
  6 +# File: cascade.py
  7 +# Date : 2016-10-12
  8 +
  9 +import binary_par as bi_par
  10 +import parity as par
  11 +import split as split
  12 +import get_parities_from_indices as gpfi
  13 +import flip_bits as fb
  14 +import flatten as fl
  15 +import random as rd
  16 +import swap_blocks as sb
  17 +
  18 +
  19 +def cascade(reference_response, error_rate, nb_passes, response_on_board, initial_block_size=0):
  20 +
  21 + """Implementation of the CASCADE reconciliation protocol"""
  22 +
  23 + powers = [2**i for i in range(12)] # Up to 512-bit responses
  24 + if (not len(reference_response) in powers):
  25 + raise ValueError('Message length is not a power of two or is too large')
  26 +
  27 + if not initial_block_size:
  28 + # Initialize the block size
  29 + block_size = 0.5/error_rate
  30 + # Round the block size to the closest lower power of 2
  31 + diff = [x - block_size for x in powers]
  32 + block_size = min(powers[diff.index(min([x for x in diff if x > 0]))], len(reference_response))
  33 + block_size = int(block_size/2)
  34 + elif initial_block_size in powers:
  35 + block_size = initial_block_size/2
  36 + else:
  37 + raise ValueError("Illegal block size")
  38 +
  39 + even_parity_blocks = []
  40 + odd_parity_blocks = []
  41 + indices_to_flip = []
  42 +
  43 + indices = list(range(len(reference_response)))
  44 +
  45 + for passe in range(0, nb_passes):
  46 + block_size_increased = False
  47 + if block_size < len(reference_response)/2:
  48 + block_size *= 2
  49 + block_size_increased = True
  50 + print "Pass :", passe, ", block size", block_size
  51 + reference_response_indexed = zip(indices, reference_response)
  52 + if passe > 0:
  53 + rd.shuffle(reference_response_indexed)
  54 + indices, reference_response = [list(i) for i in zip(*reference_response_indexed)]
  55 +
  56 + split.split(reference_response, block_size)
  57 + split.split(indices, block_size)
  58 + parities = gpfi.get_parities_from_indices(indices, response_on_board)
  59 + blocks_to_correct = []
  60 + reference_response_to_correct = []
  61 + for block_index, (reference_response_block, block_parity) in enumerate(zip(reference_response, parities)):
  62 + # Identify the blocks to correct with BINARY
  63 + # They have an odd relative parity
  64 + if par.parity(reference_response_block, block_parity):
  65 + if passe > 0:
  66 + odd_parity_blocks.append(indices[block_index])
  67 + reference_response_to_correct.append(reference_response_block)
  68 + blocks_to_correct.append(indices[block_index])
  69 + else:
  70 + if passe > 0:
  71 + even_parity_blocks.append(indices[block_index])
  72 + if blocks_to_correct:
  73 + # Narrow down to single bit errors
  74 + while len(blocks_to_correct[0]) > 2:
  75 + reference_response_to_correct, blocks_to_correct = bi_par.binary_par(reference_response_to_correct, blocks_to_correct, response_on_board)
  76 + # Final BINARY execution where single PUF bits are queried from the board
  77 + _, indices_to_flip = bi_par.binary_par(reference_response_to_correct, blocks_to_correct, response_on_board)
  78 + if passe > 0:
  79 + for index_to_flip in indices_to_flip:
  80 + # Move blocks from one group to the other if they contain the bit to flip
  81 + sb.swap_blocks(even_parity_blocks, odd_parity_blocks, index_to_flip, block_size_increased, block_size)
  82 + else:
  83 + even_parity_blocks.extend(indices)
  84 + indices = fl.flatten(indices)
  85 + reference_response = fl.flatten(reference_response)
  86 + if blocks_to_correct:
  87 + # Error correction step
  88 + fb.flip_bits(reference_response, indices_to_flip, indices)
  89 + indices_to_flip = []
  90 + blocks_to_correct = []
  91 + if passe > 0:
  92 + # Backtracking process
  93 + while odd_parity_blocks:
  94 + backtracked_pos = 0
  95 + block_to_correct = min(odd_parity_blocks, key=len) # Get the smallest block
  96 + reference_response_block = [reference_response[indices.index(x)] for x in block_to_correct]
  97 + while len(block_to_correct) > 2:
  98 + [reference_response_block], [block_to_correct] = bi_par.binary_par([reference_response_block], [block_to_correct], response_on_board)
  99 + # Final BINARY execution where single PUF bits are queried from the board
  100 + _, backtracked_pos = bi_par.binary_par([reference_response_block], [block_to_correct], response_on_board)
  101 + # backtracked_pos = bi.binary(reference_response_block, block_to_correct, response_on_board)
  102 + fb.flip_bits(reference_response, backtracked_pos, indices)
  103 + # Move blocks from one group to the other if they contain the bit to flip
  104 + sb.swap_blocks(even_parity_blocks, odd_parity_blocks, backtracked_pos[0])
  105 + if [x for x in even_parity_blocks if x in odd_parity_blocks]:
  106 + raise ValueError("Blocks are simultaneously in the even and odd group")
  107 + # Un-shuffle
  108 + _, reference_response = zip(*sorted(zip(indices, reference_response)))
  109 + return list(reference_response)
  110 +
  111 +if __name__ == "__main__":
  112 + MSIZE = 256
  113 + ERROR_RATE = 0.02
  114 + NB_PASSES = 6
  115 + NB_ESSAIS = 1
  116 + INITIAL_BLOCK_SIZE = 4
  117 +
  118 + for nb_essai in range(0, NB_ESSAIS):
  119 +
  120 + response_on_board = list(reversed(128*[1, 0])) #sort LSB first
  121 + response_on_server = list(reversed(8*[0, 1]+120*[1, 0])) #sort LSB first
  122 +
  123 + response_on_server = cascade(response_on_server,
  124 + ERROR_RATE,
  125 + NB_PASSES,
  126 + response_on_board,
  127 + INITIAL_BLOCK_SIZE)
  128 +
  129 + if response_on_server == response_on_board:
  130 + print("Correction successfull !\n------------------------\n")
  131 + else:
  132 + errors_location = [0 if a == b else 1 for (a, b) in zip(response_on_board, response_on_server)]
  133 + print "Errors at positions: ", [a for (a, b) in enumerate(errors_location) if b == 1]
  134 +
... ... @@ -0,0 +1,21 @@
  1 +# Author: Brice Colombier
  2 +# Laboratoire Hubert Curien
  3 +# 42000 Saint-Etienne - France
  4 +# Contact: b.colombier@univ-st-etienne.fr
  5 +# Project: Demonstrator
  6 +# File: flatten.py
  7 +# Date : 2016-10-12
  8 +
  9 +import itertools as it
  10 +
  11 +
  12 +def flatten(liste):
  13 +
  14 + """Turns a list of lists into a list.
  15 +
  16 + >>> flatten([[1, 2], [3, 4]])
  17 + [1, 2, 3, 4]
  18 + """
  19 +
  20 + liste = list(it.chain.from_iterable(liste))
  21 + return liste
flip_bits.py View file @ 52e659d
... ... @@ -0,0 +1,33 @@
  1 +# Author: Brice Colombier
  2 +# Laboratoire Hubert Curien
  3 +# 42000 Saint-Etienne - France
  4 +# Contact: b.colombier@univ-st-etienne.fr
  5 +# Project: Demonstrator
  6 +# File: flip_bits.py
  7 +# Date : 2016-10-12
  8 +
  9 +
  10 +def flip_bits(message, indices_to_flip, indices):
  11 +
  12 + """Flip the message bits at specific indices.
  13 +
  14 + >>> flip_bits([1, 1, 1, 1], [1])
  15 + [1, 0, 1, 1]
  16 + >>> flip_bits([0, 1, 0, 1], [2], [2, 0, 3, 1])
  17 + [1, 1, 0, 1]
  18 +
  19 + """
  20 +
  21 + if indices:
  22 + for i in indices_to_flip:
  23 + message[indices.index(i)] ^= 1
  24 + else:
  25 + for i in indices_to_flip:
  26 + message[i] ^= 1
  27 +
  28 +
  29 +if __name__ == "__main__":
  30 + message = [0, 1, 0, 1]
  31 + print(message)
  32 + flip_bits(message, [2])
  33 + print(message)
get_parities_from_indices.py View file @ 52e659d
... ... @@ -0,0 +1,37 @@
  1 +# Author: Brice Colombier
  2 +# Laboratoire Hubert Curien
  3 +# 42000 Saint-Etienne - France
  4 +# Contact: b.colombier@univ-st-etienne.fr
  5 +# Project: Demonstrator
  6 +# File: get_parities_from_indices.py
  7 +# Date : 2016-10-12
  8 +
  9 +import Tkinter
  10 +
  11 +def get_parities_from_indices(indices, response_on_board):
  12 +
  13 + """Get the parities of the on-board response blocks.
  14 +
  15 + Hardware-specific implementation.
  16 + >>> get_parities_from_indices([[1, 5], [7, 2], [3, 6], [4, 0]])
  17 + [0, 1, 1, 0]
  18 + """
  19 +
  20 + tclsh = Tkinter.Tcl()
  21 + parities = []
  22 + tclsh.eval("source {HECTOR_data_acq.tcl}")
  23 + tclsh.eval("set dev [openDevice COM3]")
  24 + tclsh.eval("puts \"Resetting the board\"")
  25 + tclsh.eval("softReset $dev")
  26 + tclsh.eval("sendDaughterReset $dev")
  27 + tclsh.eval("sendFabricReset $dev")
  28 + tclsh.eval("sendFabricCommand $dev 4 4") # generate automatic response
  29 + tclsh.eval("sendFabricCommand $dev 4 3") # offload response to MB
  30 + tclsh.eval("set rep \"[sendFabricCommand $dev 5 3] [sendFabricCommand $dev 5 2] [sendFabricCommand $dev 5 1] [sendFabricCommand $dev 5 0]\"") # Display response block 0
  31 + tclsh.eval("regsub -all { } $rep {} rep")
  32 + response = tclsh.eval("exit $rep")
  33 + print response
  34 +
  35 +
  36 +if __name__ == "__main__":
  37 + print get_parities_from_indices([0, 1, 2, 3])
... ... @@ -0,0 +1,31 @@
  1 +# Author: Brice Colombier
  2 +# Laboratoire Hubert Curien
  3 +# 42000 Saint-Etienne - France
  4 +# Contact: b.colombier@univ-st-etienne.fr
  5 +# Project: Demonstrator
  6 +# File: parity.py
  7 +# Date : 2016-10-12
  8 +
  9 +
  10 +def parity(vect_in_A, par_B):
  11 +
  12 + """Check if the vector parity is equal to a given parity
  13 +
  14 + >>> parity([0, 1, 0, 1], 0)
  15 + 0
  16 + >>> parity([1, 1, 0, 1], 1)
  17 + 0
  18 + >>> parity([1, 1, 1, 1], 1)
  19 + 1
  20 + >>> parity([0, 1, 0, 0], 0)
  21 + 1
  22 +
  23 + """
  24 +
  25 + par_A = 0
  26 + for i in vect_in_A:
  27 + par_A ^= i
  28 + return int(par_A) ^ int(par_B)