Converting this algorithm in TCL - tcl

I need help in converting this algorithm into tcl for my work, I am not so good in tcl language.
Inputs: STA−1, STA−2, STA−3, ..., STA−n
//requests from various stations for channel access
Shared Variables:
for every i, 1 ≤ i ≤ n
counter[i] ∈ { / 0, 1, 2,..., N}, initially 0, updated by stations
Sequence Number, K ∈ { / 0, 1, 2,..., N}, initially 0, will be set to a positive integer
Procedure:
//Initialization
Set sequence number K = m; //based on the action selected
for (i = 1 to n)
counter[i] = 0;
for (i = 1 to n)
{
while (channel access[i])
if (counter[i]! = K)
{
if (channel == idle)
{
if (counter[i]<min(counter[i+1], counter[i+2], ..., counter[i + n]))
access channel;
else
defer access;
}
counter[i]+ +;
}
else
defer access;
}
This is for CPS devices to access internet using a WSN in between..basic network is done but need help with adding this algo to it..
Can someone help me code that algo in tcl?

Your question isn't clear enough.
For syntax, I'd recommend referring TCL online help.
Some quick snippets:
# Inputs: STA−1, STA−2, STA−3, ..., STA−n
set stations [list "STA−1" "STA−2" "STA−3"]
# Shared Variables:
# for every i, 1 ≤ i ≤ n
# counter[i] ∈ { / 0, 1, 2,..., N}, initially 0, updated by stations
array set counter {}
set n 10
set i 0
while {$i < $n} {
set counter($i) 0
incr i
}

The core of your method is converted to this, assuming that counter is converted to an (associative) array, and that channel identifiers are stored in the channel array:
variable K 0
for {set i 1} {$i <= $n} {incr i} {
set counter($i) 0
}
for {set i 1} {$i <= $n} {incr i} {
while {[channelAccess $channel($i)]} {
if {$counter($i) != $K} {
if {[channelIdle $channel($i)]} {
set minimum [getMinimum [expr {$i + 1}] [expr {$i + $n}]]
if {$counter($i) < $minimum} {
accessChannel $channel($i)
} else {
deferAccess $channel($i)
}
}
incr counter($i)
} else {
deferAccess $channel($i)
}
}
}
You'll also need this procedure:
proc getMinimum {from to} {
upvar 1 counter counter
set minVal $counter($from)
for {set i $from} {$i <= $to} {incr i} {
set minVal [expr {min($minVal, $counter($i))}]
}
return $minVal
}
And you'll need to define channelAccess, channelIdle, accessChannel and deferAccess; they're things that your algorithm doesn't specify. There's also nothing to say what various variable are actually updated by. But that's the algorithm converted.
Note the patterns for using for; those are idiomatic Tcl for this sort of thing. Also note the brace positioning; your life will be easiest in Tcl if you use that style.

Related

Does TCL containg built in functions of type get_bits and set_bits?

The get_bits will return specific bits of a value and set_bits will set specific bits of a value to a specified value. Does TCL contain such functions built in or should they be written by the user?
The binary scan command does come close to the get_bits function but is not the same thing.
There's no specific function for getting or setting a particular bit. We can make them.
proc get_bit {value bit} {
expr {($value & (1 << $bit)) != 0}
}
proc set_bit {varName bit {value 1}} {
upvar 1 $varName var
if {$value} {
set var [expr {$var | (1 << $bit)}]
} else {
set var [expr {$var & ~(1 << $bit)}]
}
}
Those will work with integer values of any width; you're not restricted to 32 bits or 64 bits.
# Lots of bits!
set x 123456789012345678901234567890
# Fetch a particular bit
puts [get_bit $x 17]
# Set a bit to 1
set_bit x 78
puts "x = $x"
# Set a bit to 0
set_bit x 75 0
puts "x = $x"

CRC16 calculation in Tcl

Im trying to compute the CRC16 of a binary file.
I started by reading 2 Bytes from the Binary file and compute a CRC16 with a Polynome= 1021 and 0xFFFF Initial Value. I used a C code and tried to translate it to TCL. I couldnt use the bytes format because i get by the computation an error about using non numeric string. So i converted the bytes to strings.
proc main {}{
# open binary file
set file_read [open "$input_file" rb]
while {1} {
if {! [eof $fr]} {
append binary_data [read $file_read 2]
}
binary scan [string range $binary_data 0 1] H4 str_bin_data
set CRC_data [CRC_calculation $str_bin_data]
puts " CRC_data := $CRC_data"
}
}
proc CRC_calculation {str_bin_data} {
set Polynome 0x1021
set Highbit 0x8000
set CRC_data 0xFFFF
set byte 0
set bit 0
set data_ln [string length $str_bin_data]
# puts " data_ln := $data_ln"
for {set byte 0} {$byte < $data_ln} {incr byte} {
set CRC_data [ expr {$CRC_data ^ ([lindex $str_bin_data $byte] << 8)} ]
for {set bit 8} {$bit > 0} {incr bit -1} {
if {($CRC_data && $Highbit)} {
set CRC_data [expr {($CRC_data << 1) ^ $Polynome}]
} else {
set CRC_data [expr {$CRC_data << 1}]
}
}
puts " byte_index := $byte"
puts " CRC_data := $CRC_data"
}
return $CRC_data
}
In C when i define a byte array example( first 8 Bytes in the binary file):
unsigned char bytes[3]= {0x55,0x55,0x55,0x55};
then CRC = 0x82b8
In Tcl I dont get the correct value not even a 32 bit CRC value.
Here the C code that i m using:
#include<stdio.h>
#define Polynom 0x1021
#define Highbit 0x8000
unsigned short getCRC(const unsigned char data[])
{
unsigned short rem = 0xFFFF;
unsigned long byte = 0;
int bit = 0;
for (byte = 0; byte < 3; ++byte)
{
rem ^= (data[byte]<< 8);
for (bit = 8; bit > 0; --bit)
{
if (rem & Highbit)
rem = (rem << 1) ^ Polynom;
else
rem = (rem << 1);
}
}
return (rem);
}
int main() {
int rem ;
unsigned char data[]= {0x55,0x55,0x55,0x55};
rem = getCRC (data);
printf("%x", rem);
}
There's a few problems. Firstly, and most importantly, the scanning of the binary data isn't right as we want to end up with unsigned bytes (for parallel operation with that C) and not hex characters. You'd be better with:
# I'm assuming you've got Tcl 8.6, this is how you read 2 bytes as unsigned chars
binary scan [read $file_read 2] "cu*" str_bin_data
# Process the list of parsed byte data here; I'm not sure if you want this in the loop or not
The other big problem is that your CRC calculation isn't correct.
proc CRC_calculation {str_bin_data} {
set Polynom 0x1021
set Highbit 0x8000
set MASK 0xFFFF; # 16 bit mask; for clamping to C unsigned short range
set rem 0xFFFF
# Assume str_bin_data holds a list of unsigned char values
foreach byte $str_bin_data {
set rem [expr {$rem ^ ($byte << 8)}]
foreach _ {7 6 5 4 3 2 1 0} {
set rem [expr {
(($rem << 1) ^ ($rem & $Highbit ? $Polynom : 0)) & $MASK
}]
}
}
return $rem
}
Key observation here? Tcl's numbers are arbitrary precision integers (and IEEE doubles, though not relevant here). This means that you need to clamp the range. Minimally, that would be an AND with 0xFFFF (16-bit mask) after any operation that can increase the number of bits in use, which is just << in this algorithm. That, plus the problems with converting the binary data in the first place, are why things weren't working for you. I've also switched to using foreach as that's fast and clearer for operations where “do every one of them” is the fundamental idea, and merged the inner bits into a single expr (yes, expr expressions can be multiline if you want).
The biggest single problem was that you were passing entirely the wrong thing to the CRC_calculation code. Changing the binary scan is vital.

efficient grid lookup by coordinate in Tcl

I'm trying to implement a simple grid lookup in Tcl. You can think of the grid items as boxes within a grid. Something like the following.
I have the x and y coordinates of the boundaries (left, right , top bottom) of each of the blue boxes within the coordinate space shown in a dictionary called boxcoordinates
given an arbitrary X and Y point, what is the most efficient way to identify which (if any) of the blue boxes are intercepted by the X,Y pair?
I'm currently doing a check for each box, on the conditions where Left < X < Right and Bottom < Y < Top to see which box satisfies those conditions.
Something like
foreach boxid [dict keys boxcoordinates] {
if {([dict get $boxcoordinates $boxid LEFT] < $x) && ([dict get $boxcoordinates $boxid RIGHT] > $x) && ([dict get $boxcoordinates $boxid BOTTOM] < $y) && ([dict get $boxcoordinates $boxid TOP] > $y)} {
set selected $boxid
break
}
}
But that seems very inefficient since there are a lot of boxes to scan through. Is there a more efficient way to do this?
If you sort the coordinate list in a regular fashion, you can do a binary search to find the coordinates you are looking for. The example below only has 9 entries, but should give you the idea. The coordinates used in this exampled are ordered as x1, x2, y1, y2.
global vars
proc init { } {
global vars
set vars(d) {
0 {1 4 1 4}
1 {1 4 6 8}
2 {1 4 10 12}
3 {6 8 1 4}
4 {6 8 6 8}
5 {6 8 10 12}
6 {10 12 1 4}
7 {10 12 6 8}
8 {10 12 10 12}
}
}
proc lCompare { a b } {
lassign $a ax1 ax2 ay1 ay2
lassign $b bx1 bx2 by1 by2
if { $bx1 < $ax1 } {
return -1
} elseif { $bx2 > $ax2 } {
return 1
} elseif { $by1 < $ay1 } {
return -1
} elseif { $by2 > $ay2 } {
return 1
}
return 0
}
proc bsearch { mx my } {
global vars
set target [list $mx $mx $my $my]
set low 0
set high [expr {[dict size $vars(d)]-1}]
while { $low <= $high } {
set mid [expr {($low+$high)/2}] ; # integer division
set lrc [lCompare [dict get $vars(d) $mid] $target]
if { $lrc > 0 } {
set low [expr {$mid+1}]
} elseif { $lrc < 0 } {
set high [expr {$mid-1}]
} else {
return $mid
}
}
return -1
}
init
set idx [bsearch 3 10]
puts "A:$idx"
set idx [bsearch 10 10]
puts "B:$idx"
set idx [bsearch 3 3]
puts "C:$idx"
set idx [bsearch 5 9]
puts "D:$idx"
Output:
bll-tecra:bll$ tclsh z.tcl
A:2
B:8
C:0
D:-1
References: wikipedia: Binary Search Algorithm

conversion of and operation having a function from c# to tcl

how to do the and operation given as one line statement in tcl in tcl where pcieDeviceControlRegister is a function given as in the code:
code:
pcieDeviceControlRegister = cfgSpace.pcieDeviceControlRegister & (~((uint)0xF));
Reference for pcieDeviceControlRegister function is :
public uint pcieDeviceControlRegister
{
get
{
if (pcieCapabilityOffset != 0)
return (ReadDW((int)(pcieCapabilityOffset + 8) / 4, 0xF)) & 0xFFFF;
else
return 0;
}
set
{
if (pcieCapabilityOffset != 0)
{
uint val = ReadDW((int)(pcieCapabilityOffset + 8) / 4, 0xF)& 0xFFFF0000;
val |= value;
// write should be done with byte enables !!!
WriteDW((int)(pcieCapabilityOffset + 8) / 4, val, 0xF);
}
}
}
You'll have to arrange for the mapping of ReadDW and WriteDW into Tcl, probably by writing a little C or C++ code that makes commands (with the same names) that do those operations. I'm assuming that you've already done that. (SWIG can generate the glue code if you need it.)
Then, we define a command like this:
proc pcieDeviceControlRegister {{newValue ""}} {
global pcieCapabilityOffset
# Filter the bogus setup case early; if this is really an error case though,
# it is better to actually throw an error instead of struggling on badly.
if {$pcieCapabilityOffset == 0} {
return 0
# error "PCIE capability offset is zero"
}
set offset [expr {($pcieCapabilityOffset + 8) / 4}]
if {$newValue eq ""} {
# This is a read operation
return [expr {[ReadDW $offset 0xF] & 0xFFFF}]
} else {
# This is a write operation
set val [expr {[ReadDW $offset 0xF] & 0xFFFF0000}]
# Note that we do the bit filtering HERE
set val [expr {$val | ($newValue & 0xFFFF)}]
WriteDW $offset $val 0xF
return
}
}
With that, which you should be able to see is a pretty simple translation of the C# property code (with a bit of minor refactoring), you can then write your calling code like this:
pcieDeviceControlRegister [expr {[pcieDeviceControlRegister] & ~0xF}]
With Tcl, you don't write casts to different types of integers: Tcl just has numbers (which are theoretically of infinite width) so instead you need to do a few more bit masks in key places.
The conversion of the above code to a method on an object is left as an exercise. It doesn't change very much…

how to use Tcl language to control simulation

I want to use tcl to control simulation iteration.
In each iteration, I get some random value, and save the results
set set_of_double_values{0}
foreach y_val $set_of_double_values {
set_parameter Snr $y_val ;
set numsim 2;
set_value/$env(sim_name)/numsim $numsim;
for {set i 0} {$i < $numsim} {incr i 1} {
some random value
}
run_iteration;
}
run_iteration
using this code, I always run the inner part many times, and I can not save the right results...