I wrote a file to read hex from one file and convert the hex to binary
to another file. The code works well except that it will read the last
data twice. for example, if the data file contains 100 data, the code
will output 101 data. The last data appears two time. Can anybody help
me to find the reason?
here is my code:
set rfid [open boot_rom.dat r]
set wfid [open rom.rcf w]
set line_cnt 0
while {![eof $rfid]} {
set rdata [read $rfid 1]
switch -- $rdata {
"0" {set ten_unit 0}
"1" {set ten_unit 1}
"2" {set ten_unit 2}
"3" {set ten_unit 3}
"4" {set ten_unit 4}
"5" {set ten_unit 5}
"6" {set ten_unit 6}
"7" {set ten_unit 7}
"8" {set ten_unit 8}
"9" {set ten_unit 9}
"a" - "A" {set ten_unit 10}
"b" - "B" {set ten_unit 11}
"c" - "C" {set ten_unit 12}
"d" - "D" {set ten_unit 13}
"e" - "E" {set ten_unit 14}
"f" - "F" {set ten_unit 15}
}
set rdata [read $rfid 1]
switch -- $rdata {
"0" {set unit 0}
"1" {set unit 1}
"2" {set unit 2}
"3" {set unit 3}
"4" {set unit 4}
"5" {set unit 5}
"6" {set unit 6}
"7" {set unit 7}
"8" {set unit 8}
"9" {set unit 9}
"a" - "A" {set unit 10}
"b" - "B" {set unit 11}
"c" - "C" {set unit 12}
"d" - "D" {set unit 13}
"e" - "E" {set unit 14}
"f" - "F" {set unit 15}
}
set rdata [expr $ten_unit*16+$unit]
binary scan [binary format i $rdata] B8 bits
puts $wfid $bits
incr line_cnt
read $rfid 1
}
for {set i 0} {$i<=[expr 255-$line_cnt]} {incr i} {
puts $wfid "00000000"
}
close $rfid
close $wfid
I think it is because [eof] can only be detected _after_ it has been
encountered. Try something along these lines:
while {1} {
set rdata [read $rfid 1]
if { [eof $rdif] } {
break
}
...
}
BTW, your switch statement vcan be replaced by:
array set map {0 0 1 1 ... 9 9 a 10 A 10 b 11 B 11 ...}
set ten_unit $map($rdata)
Regards,
Arjen
Hi Arjen,
thanks for your kind reply.
[1] I have tried the way you said for eof, but it doesn't work. In
fact, I have wrote some test code like this:
set rfid [open boot_rom.dat r]
set wfid [open tmp/w.dat w]
while {![eof $rfid]} {
set rdata1 [read $rfid 1]
set rdata2 [read $rfid 1]
puts $wfid "${rdata1}${rdata2}"
read $rfid 1
}
the code above works well and no extra data appears. The error may be
caused by other "hidden" reason.
[2] as to code for switch state, I like your idea. thanks.
Hm, no time now to investigate it, so I will have to leave to you and
others.
> [2] as to code for switch state, I like your idea.
You're welcome :).
Regards,
Arjen
eof can happen at any of those reads, so rdata1 and rdata2 might not
be useful. I'd check for 'eof' *after* these reads. Since you're
reading only 1 byte in each read, there is no need to handle partial
reads at eof.
while {1} {
set rdata1 [read $rfid 1]
set rdata2 [read $rfid 1]
if {[eof $rfid]} {
break
}
puts $wfid "${rdata1}${rdata2}"
read $rfid 1
}
My EUR 0.01
R'
> set rfid [open boot_rom.dat r]
> set wfid [open tmp/w.dat w]
>
> while {![eof $rfid]} {
> set rdata1 [read $rfid 1]
> set rdata2 [read $rfid 1]
> puts $wfid "${rdata1}${rdata2}"
> read $rfid 1
> }
You are reading/throwing away evrey third char. Ddoes the file have
newlines you are discarding or some other sepearator
(if it is newlines it would be easier to use gets then read)
>
> the code above works well and no extra data appears. The error may be
> caused by other "hidden" reason.
>
> [2] as to code for switch state, I like your idea. thanks.
even better is to use scan
set val [scan $hexchar %x]
and scan can even handle the 2 chars at a time
I would implement this as
set rfid [open boot_rom.dat r]
set wfid [open tmp/w.dat w]
# if data is NOT newline seperated but has
# some other char you are skipping ----------------------
while {![eof $rfid]} {
set hex [read $rfid 2]
set rdata [scan $hex %x]
binary scan [binary format i $rdata] B8 bits
puts $wfid $bits
read $rfid 1
}
# if data *is* newline seperated -------------------------
while {[gets $rfid hex]>=0} {
set rdata [scan $hex %x]
binary scan [binary format i $rdata] B8 bits
puts $wfid $bits
}
close $rfid
close $wfid
Bruce
might as well be caused by spaces/chars at the end of file. remember
that in TCL variables are maintained at proc scope/level (no separate
scope for the loop "block"), so that next loop iteration might see
remains of the previous (if they are not overwritten/unset ...). also
your hex->bin conversion code is probably way too slow, way to long
and way to "manual".
i'd do it like this (if the input file consists of groups of 2 hex
digits separated by precisely one character):
=============
set rfid [open boot_rom.dat r]
set wfid [open rom.rcf w]
proc hex2bin {hex} {
binary scan [binary format H* $hex] B* bin
return $bin
}
while {1} {
set rdata [read $rfid 2]
if {[eof $rfid]} {break}
puts $wfid [hex2bin $rdata]
incr line_cnt
seek $rfid 1 current ;# skip one char
}
for {set i 0} {$i<=[expr 255-$line_cnt]} {incr i} {
puts $wfid "00000000"
}
close $rfid
close $wfid
===================
or you could read the file as whole, [split] the contents, [foreach]
them into the output file (keeping count) ...
hope it helps,
cheers,
carlo.
You should check eof AFTER read not BEFORE.
Let's say your input file looks like:
12
34
The reason you get the last line dumped twice is, the program enters
the while loop three times.
After you finish the second line, it's not "eof" yet. You have to read
one more time to get eof.
So the flow goes into the while loop again, and then you get empty
string in "rdata",
since rdata is empty, the flow won't go into switch,
that means, your variable "ten_unit" and "unit" remain the same value
as "3" and "4".
You need to change it to:
while {1} {
read ..
if { [eof ...]} {
...
break
}
##-- normal flow ---
...
}
> for {set i 0} {$i<=[expr 255-$line_cnt]} {incr i} {
> puts $wfid "00000000"
> }
while {$line_cnt <= 255} {
puts $wfid "00000000"
incr line_cnt
}
and when talking about speed (not that it is needed in that case, just
for info), if you put your toplevel code in a proc (call it main or
watever) and call that proc at the end of the script, it will get
bytecode compiled, otherwise it runs interpreted.
thanks for all of your kind reply and they are very helpful. After
study your ideas, I updated code and found it works. Thanks very much.
here is my updated code:
set rfid [open boot_rom.dat r]
set wfid [open rom.rcf w]
proc hex2bin {hex} {
binary scan [binary format H* $hex] B* bin
return $bin
}
set line_cnt 0
while {1} {
set rdata [read $rfid 2]
if {[eof $rfid]} {break}
puts $wfid [hex2bin $rdata]
incr line_cnt
seek $rfid 1 current;
}
while {$line_cnt<=255} {
puts $wfid "00000000"
incr line_cnt
}
close $rfid
close $wfid
What's wrong with:
set in [open infile r]
set out [open outfile wb]
while {![eof in]} {
puts -nonewline $out [binary decode hex [read $in 4096]]
}
close $in
close $out
(or is binary decode an 8.6 thing? I've been using it exclusively for
years now, it's hard to remember what is exclusive to it)
Cyan
read data
while not eof
process data
read data
end while
/Str
because his data is not in a continuous block it 2 bytes data, skip 1
byte, 2 bytes data, skip one byte ....
(I *think* the byte being skipped is a newline, but not %100 sure)
bruce