TwinCAT 3 : Block stays busy - plc

I want to save some data into a .txt file. I can create it, but I can't write text into it because the FB stays busy.
CASE counter OF
1:
fileOpen.sNetId := '';
fileOpen.sPathName := 'C:\test\test.txt';
fileOpen.nMode := FOPEN_MODEWRITE;
fileOpen.bExecute := TRUE;
fileOpen.tTimeout := T#200MS;
fileOpen();
counter := 2;
2:
IF NOT fileOpen.bBusy AND NOT fileOpen.bError THEN (* bBusy stays true*)
counter := 3;
END_IF
3:
fileOpen.bExecute := FALSE;
fbPutFile(sNetId := '', hFile := fileOpen.hFile, sLine := 'FOO', bExecute := TRUE, tTimeout := INT_TO_TIME(200), bBusy =>, bError =>, nErrId =>);
END_CASE
I get into step 2, but I can't get into step 3. Where is the problem?

It's because you have stopped calling the function block for opening the file. What you're doing here is that you're calling the FB_FileOpen in step 1, but then stop calling it. The bBusy-flag goes high (true) in step1, but can never be changed to anything else as you never call the FB again. You need to make a call to it in step2 as well. Remember that bExecute is also a trigger for the ADS-command, so once you've done it in step 2, you can set the bExecute-input to FALSE in step2 and forward as you've already triggered the command.
...
2:
fileOpen(bExecute := false);
IF NOT fileOpen.bBusy AND NOT fileOpen.bError THEN (* bBusy stays true*)
counter := 3;
END_IF
...
Also remember that Beckhoffs FB_FileOpen assumes that the directory C:\test exists (though not the file test.txt if you open it with FOPEN_MODEWRITE it will be automatically created). To create all necessary directores (if they don't already exist) use TwinCATs FB_CreateDir.

Related

How can I implement u^k = M^k u_0?

Let M := Matrix([[0.94, 0.09], [0.06, 0.91]]); and u[0] = Vector([0.8, 0.2]);. What command could I use to get u^k = M^k u_0 for k=5, 10, ..., 50?
I'm guessing you mistyped, and you want to call the result of M^k . u[0] as u[k] rather than (as you wrote it) u^k.
restart;
with(LinearAlgebra):
M := Matrix([[0.94, 0.09], [0.06, 0.91]]):
u[0] := Vector([0.8, 0.2]):
# One (inefficient) way
seq(M^k . u[0],k=5..50,5);
# Another way
M5 := M^5:
for k from 5 to 50 by 5 do
u[k] := M5 . u[k-5];
end do;
# Another way
(evals,evecs) := simplify([Eigenvectors(M)])[]:
seq(evecs . DiagonalMatrix(map(`^`,evals,k))
. evecs^(-1).u[0],
k=5..50,5);

How do a do "while loop" in ocl when server side or Async?

Im using a rest api for getting orders from a webshop, the result is max 100 orders at a time and there is a page param to use for next 100 orders.
I have solve this in a viewmodel using periodic action (disables = not self.oclIsIn(#InProgress)) like this:
vCount := self.Orders->size;
vPage := vPage + 1;
vResponse := selfVM.RestGet(
String.Format('{0}/wp-json/wc/v3/orders?per_page={1}&page={2}',self.Channel.Url, self.Channel.Source.MaxCount, vPage),
self.Channel.UserName,
self.Channel.Password,'');
vResponse := String.Format('{0}{1}{2}','{"orders":', vResponse,'}');
--self.JSonData := self.JSonData + vResponse;
vOutput := vOutput + self.MergeTaJson( ImportBatch.Viewmodels.WooOrderJSon, vResponse );
if ((self.Orders->size - vCount) = 0) then
if vOutput->IsNullOrWhiteSpace then
self.Fail
else
--self.ParsingLog := vOutput;
self.Success
endif;
true
else
vCount := self.Orders->size;
false
endif
It will go on and on until result from the api is 0 then state sets to Done and it stops.
Now I want to do the same server side, but how do I solve this without a periodic action like this? And I want to do the same in a AsyncTicket "action".
Is it possible for you to see the whole serverside job as a periodic action?
Each execution of a SS job should fit in "one go" and saved in one transaction

How come new_duration prints out as blank not allowing my loop to run?

I am using AutoHotKey's latest release of v1.1
I pass 3 arguments to the program from the commandline:
key, duration, and window saved in %1%, %2%, and %3% respectively.
When printing key duration and window using MsgBox, %1% %2% %3%
I get correct values of lets say in this case a 5 Untitled
duration := %2%
new_duration := (duration * 1000)
MsgBox, %new_duration%
while (A_TickCount - start <= new_duration)
{
ControlSend,,{Blind}{%1% down}{Blind}{%1% up},%3%
sleep 50
}
When the above code is executed it prints nothing not allowing my loop to run.
Why?
I read the documentation a bit more carefully and found A_Args[index]
Completed code:
key := A_Args[1]
duration := (A_Args[2] * 1000)
window := A_Args[3]
while (A_TickCount - start <= duration)
{
ControlSend,,{Blind}{%key% down}{Blind}{%key% up},%window%
sleep 50
}

Get String Value of passed ByRef Variable

Say I call a function that uses a byref modifier. Once in the function, I want to fetch the string value of the passed variable.
myvar := "george"
passit(myvar)
passit(byref whatvar){
msgbox % %whatvar% ;I should see a messagebox reporting the string "myvar"
}
Getting the string value of the variable works fine if I'm not passing the variable byref.
Maybe I'm going about this the wrong way. I want the function to know the string name for the variable being referenced.
This approch uses the buildin ListLines-Command to access the needed metadata.
The command ListLines opens the main window of the current script and displays the last executed script lines.
Content looks like this:
Script lines most recently executed (oldest first). Press [F5] to refresh. The seconds elapsed between a line and the one after it is in parentheses to the right (if not 0). The bottommost line's elapsed time is the number of seconds since it executed.
---- D:\Eigene_Dateien\ahk scripts\test3.ahk
002: myvar := "george"
003: passit(myvar)
007: MsgBox,GetOriginalVariableNameForSingleArgumentOfCurrentCall(A_ThisFunc)
012: lines := ListLines()
Press [F5] to refresh.
This data can be parsed to extract the wanted information (what is passed to 'passit').
One problem here is, that there is no buildin programmatically way of access this info.
The function ListLines overrides temporary User32.ShowWindow and User32.SetForgroundWindow to return simply true, so the buildin command ListLines can be used without displaying its window (Might produce problems with multithreaded scripts). From this 'hidden' window its text is received and cleaned up. Function is written by Lexikos (http://www.autohotkey.com/board/topic/20925-listvars/#entry156570 http://www.autohotkey.com/board/topic/58110-printing-listlines-into-a-file/#entry365156).
GetOriginalVariableNameForSingleArgumentOfCurrentCall extracts the variable name with a regular expression, which searches the first call to the passed function above the current call (call to GetOriginalVariableNameForSingleArgumentOfCurrentCall).
myvar := "george"
passit(myvar)
return
passit(whatvar){
msgbox % GetOriginalVariableNameForSingleArgumentOfCurrentCall(A_ThisFunc)
}
GetOriginalVariableNameForSingleArgumentOfCurrentCall(callerFuncName)
{
lines := ListLines()
pattern = O)%callerFuncName%\((.*?)\).*?%A_ThisFunc%\(.*?\)
RegExMatch(lines, pattern, match)
return match[1]
}
; Originally written by Lexikos / Copy of ListGlobalVars http://www.autohotkey.com/board/topic/20925-listvars/#entry156570
; with modifications from here http://www.autohotkey.com/board/topic/58110-printing-listlines-into-a-file/#entry365156
; Tested/Modified for AHK Unicode 64bit v1.1.14.03
ListLines()
{
static hwndEdit, pSFW, pSW, bkpSFW, bkpSW
ListLines Off
if !hwndEdit
{
dhw := A_DetectHiddenWindows
DetectHiddenWindows, On
Process, Exist
ControlGet, hwndEdit, Hwnd,, Edit1, ahk_class AutoHotkey ahk_pid %ErrorLevel%
DetectHiddenWindows, %dhw%
astr := A_IsUnicode ? "astr":"str"
ptr := A_PtrSize=8 ? "ptr":"uint"
hmod := DllCall("GetModuleHandle", "str", "user32.dll")
pSFW := DllCall("GetProcAddress", ptr, hmod, astr, "SetForegroundWindow")
pSW := DllCall("GetProcAddress", ptr, hmod, astr, "ShowWindow")
DllCall("VirtualProtect", ptr, pSFW, ptr, 8, "uint", 0x40, "uint*", 0)
DllCall("VirtualProtect", ptr, pSW, ptr, 8, "uint", 0x40, "uint*", 0)
bkpSFW := NumGet(pSFW+0, 0, "int64")
bkpSW := NumGet(pSW+0, 0, "int64")
}
if (A_PtrSize=8) {
NumPut(0x0000C300000001B8, pSFW+0, 0, "int64") ; return TRUE
NumPut(0x0000C300000001B8, pSW+0, 0, "int64") ; return TRUE
} else {
NumPut(0x0004C200000001B8, pSFW+0, 0, "int64") ; return TRUE
NumPut(0x0008C200000001B8, pSW+0, 0, "int64") ; return TRUE
}
ListLines
NumPut(bkpSFW, pSFW+0, 0, "int64")
NumPut(bkpSW, pSW+0, 0, "int64")
; Retrieve ListLines text and strip out some unnecessary stuff:
ControlGetText, ListLinesText,, ahk_id %hwndEdit%
RegExMatch(ListLinesText, ".*`r`n`r`n\K[\s\S]*(?=`r`n`r`n.*$)", ListLinesText)
StringReplace, ListLinesText, ListLinesText, `r`n, `n, All
ListLines On
return ListLinesText ; This line appears in ListLines if we're called more than once.
}
The closest to what you would want...? This reminds of a question I had.
See http://ahkscript.org/boards/viewtopic.php?f=14&t=3651
myvar:="test"
passit("myvar") ; display value, and change it
msgbox % "myvar = " myvar
passit(byref whatvar){ ; no more need for byref here...
msgbox % whatvar " = " (%whatvar%)
%whatvar%:="blah" ; edit globalvar "hack"
}

Console application via network in eiffel?

Hey I'm working in project, but i cant manage to connect from a IP not located in the same network (LAN). The code bellow works fine locally, but I cant figure out how to make work from different IP located in different locations?, and google cant see to help, any ideas?
class
RG_NETWORK_SERVER
inherit
STORABLE
NETWORK_SERVER
redefine
receive,
received,
close
end
create
make_server
feature
connections: LINKED_LIST [RG_CONNECTION]
max_to_poll: INTEGER
message_out: RG_MESSAGE
received: detachable RG_MESSAGE
poll: MEDIUM_POLLER
make_server
require
local
l_message_out: detachable like message_out
l_connections: detachable like connections
l_in: detachable like in
do
make (1337)
max_to_poll := 1
create poll.make_read_only
in.set_non_blocking
l_in := in
create l_message_out.make
message_out := l_message_out
create l_connections.make
connections := l_connections
connections.compare_objects
execute
end
process_message
local
stop: BOOLEAN
pos: INTEGER
do
from
connections.start
until
connections.after or stop
loop
if connections.item.is_waiting then
if attached {RG_MESSAGE} retrieved (connections.item.active_medium) as l_message_in then
if l_message_in.new then
connections.item.set_client_name (l_message_in.client_name)
create message_out.make
message_out.set_client_name (l_message_in.client_name)
message_out.extend (l_message_in.client_name)
message_out.extend (" has just joined the server%N")
elseif l_message_in.over then
poll.remove_associated_read_command (connections.item.active_medium)
connections.remove
create message_out.make
message_out.set_client_name (l_message_in.client_name)
message_out.extend (l_message_in.client_name)
message_out.extend (" has just gone%N")
stop := True
else
message_out := l_message_in.deep_twin
message_out.put_front (" has just sent that :%N")
message_out.put_front (message_out.client_name)
message_out.put_front ("-> ")
end
pos := connections.index
-- l_message_in.print_message
message_out.print_message
broadcast
connections.go_i_th (pos)
-- Post status to client
create message_out.make
message_out.extend ("Got it! %N")
message_out.independent_store (connections.item.active_medium)
end
end
if not stop then
connections.forth
end
end
end
broadcast
local
client_name: detachable STRING
do
client_name := message_out.client_name
if client_name /= Void then
from
connections.start
until
connections.after
loop
if connections.item.client_name /~ client_name then
message_out.independent_store (connections.item.active_medium)
end
connections.forth
end
end
end
receive
do
in.accept
if attached {like outflow} in.accepted as l_outflow then
l_outflow.set_blocking
new_client (l_outflow)
end
from
connections.start
until
connections.after
loop
connections.item.initialize
connections.forth
end
poll.execute (max_to_poll, 1000)
end
new_client (a_flow: attached like outflow)
local
new_connection: RG_CONNECTION
do
if max_to_poll <= a_flow.descriptor then
max_to_poll := a_flow.descriptor + 1
end
create new_connection.make (a_flow)
connections.extend (new_connection)
create message_out.make
message_out.extend ("Welcome! %N")
message_out.independent_store (a_flow)
poll.put_read_command (new_connection)
end
end
and the client:
class
RG_NETWORK_CLIENT
inherit
NETWORK_CLIENT
redefine
received
end
create
make_join
feature
make_join(ip:STRING)
require
is_ip_void : ip /= Void
local
l_client_name: detachable like client_name
do
check_name
l_client_name := client_name
make (1337, ip)
max_to_poll := in_out.descriptor + 1
create connection.make (in_out)
create poll.make_read_only
poll.put_read_command (connection)
send_name_to_server
auto_scan_server
processing
end
feature
connection: RG_CONNECTION
std_input: detachable RG_CONNECTION
message_out: RG_MESSAGE
received: detachable RG_MESSAGE
client_name: STRING
over: BOOLEAN
poll: MEDIUM_POLLER
input_poll: detachable MEDIUM_POLLER
max_to_poll: INTEGER
waiting:BOOLEAN
send_name_to_server
do
create message_out.make
message_out.set_client_name (client_name)
message_out.set_new (True)
message_out.set_over (False)
send (message_out)
end
processing
do
from
over := False
until
over
loop
scan_from_server
if not over then
read_content
end
end
cleanup
end
read_content
local
temp: detachable STRING
do
io.put_string ("Enter message: ")
io.readline
temp := io.laststring
if temp /= Void and not temp.is_empty then
if temp.is_equal ("bye") then
over := True
end
create message_out.make
message_out.extend (temp)
message_out.extend ("%N")
message_out.set_over (over)
message_out.set_client_name (client_name)
message_out.set_new (False)
send (message_out)
auto_scan_server
end
end
check_name
local
l_name: detachable STRING
do
io.putstring ("Enter your name : ")
io.readline
l_name := io.laststring
check
l_name_attached: l_name /= Void
end
client_name := l_name.twin
end
scan_from_server
local
l_received: like received
do
connection.initialize
poll.execute (max_to_poll, 1000)
if connection.is_waiting then
receive
l_received := received
if l_received /= Void then
waiting := FALSE
l_received.print_message
if l_received.over then
over := True
end
end
end
end
auto_scan_server
do
waiting := True
from until not waiting
loop
scan_from_server
end
end
end
The work around is the work with the samples provided from Eiffel, it works as longest the two persons are connected in the same network. for example as follow:
Here we define if the user has receive the message or is waiting for one, also redefine the poll_command to be able to use it.
inherit
POLL_COMMAND
redefine
make
end
create
make
feature {NONE} -- Initialization
make (s: IO_MEDIUM)
do
Precursor (s)
create client_name.make_empty
end
feature
is_waiting: BOOLEAN
client_name: STRING
execute (arg: ANY)
do
is_waiting := True
end
initialize
do
is_waiting := False
end
set_client_name (s: STRING)
require
s_exists: s /= Void
do
client_name := s.twin
end
end
Then following the chat sample, that can be found in the samples folder, in the message handler, we create the follow:
set_client_name (s: STRING)
require
s_not_void: s /= Void
do
client_name := s.twin
end
set_new (flag: BOOLEAN)
do
new := flag
end
Later in the connection class we are able to connect to a server ip, which it can be pass true command line or via GUI input.
make_join (name: STRING; ip: STRING; gc: RG_CLIENT)
require
is_ip_void: ip /= Void
do
-- Connects to IP on port 1337
make (1337, ip)
max_to_poll := in_out.descriptor + 1
create connection.make (in_out)
create poll.make_read_only
poll.put_read_command (connection)
-- Sets client name and refrence
client_name := name
p_client := gc
-- Sends name to server and receives ID
client_id := send_name_to_server
-- Launches instance as thread
make_thread
launch
execute
end
Then in the server class...
make_server (gs: RG_SERVER)
local
l_message_out: detachable like message_out
l_connections: detachable like connections
l_in: detachable like in
do
-- Instantiate reference and create server listening on port 1337
game_server := gs
make (1337)
max_to_poll := 1
create poll.make_read_only
in.set_non_blocking
l_in := in
create l_connections.make
connections := l_connections
connections.compare_objects
-- Launches instance as tread
make_thread
launch
end
There is a bit more code, but this is a good sample in how to do it, there must be a method to handle the connections, but this is a good start, also remember that all this is based on their samples, chat sample is a good point of start..
enjoy eiffel while is not crashing .