1%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    2%
    3%  FILE     : Env/env_rcx.pl
    4%
    5%  AUTHOR : Sebastian Sardina (2002)
    6%  EMAIL  : ssardina@cs.toronto.edu
    7%  WWW    : www.cs.toronto.edu/~ssardina www.cs.toronto.edu/cogrobo
    8%  TYPE   : system dependent predicates (uses event_after to query RCX)
    9%  TESTED : ECLiPSe 5.3 on RedHat Linux 6.2-8.0
   10%
   11% This files provides the environment for working with the RCX.
   12%  An event-after event is used to talk to the RCX every some number of
   13%  seconds. At each talk, if there is an action pending to be executed
   14%  (to_execute/3), such action is sent to the RCX. Otherwise, the RCX is
   15%  queried for an occurred exogenous action.
   16%
   17% This environment is self-contained (automatically it loads the required
   18%  libraries). It should be called as follows:
   19%
   20%   eclipse host=<HOST> port=<PORT> -b env_rcx.pl -e start
   21%
   22% where HOST/PORT is the address of the environment manager socket.
   23%
   24%
   25% Written for ECLiPSe Prolog (http://www.icparc.ic.ac.uk/eclipse/)
   26% running under Linux 6.2-7.2-8.0
   27%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   28%
   29%                             November 15, 2002
   30%
   31% This software was developed by the Cognitive Robotics Group under the
   32% direction of Hector Levesque and Ray Reiter.
   33%
   34%        Do not distribute without permission.
   35%        Include this notice in any copy made.
   36%
   37%
   38%         Copyright (c) 2000 by The University of Toronto,
   39%                        Toronto, Ontario, Canada.
   40%
   41%                          All Rights Reserved
   42%
   43% Permission to use, copy, and modify, this software and its
   44% documentation for non-commercial research purpose is hereby granted
   45% without fee, provided that the above copyright notice appears in all
   46% copies and that both the copyright notice and this permission notice
   47% appear in supporting documentation, and that the name of The University
   48% of Toronto not be used in advertising or publicity pertaining to
   49% distribution of the software without specific, written prior
   50% permission.  The University of Toronto makes no representations about
   51% the suitability of this software for any purpose.  It is provided "as
   52% is" without express or implied warranty.
   53% 
   54% THE UNIVERSITY OF TORONTO DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
   55% SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
   56% FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF TORONTO BE LIABLE FOR ANY
   57% SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
   58% RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
   59% CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
   60% CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   61% 
   62%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   63% 
   64% This file assumes that the following is defined in env_gen.pl:
   65%
   66% -- start/0     : initialization of the environment (called when loaded)
   67% -- finalize/0  : finalization of the environment (called when exiting)
   68% -- main_dir/1  : obtain the root IndiGolog directory
   69% -- report_exog_event(A, M): 
   70%                  report exogenous event A with message M to the
   71%                  environment manager
   72%
   73% -- All compatibility libraries depending on the architecture such us:
   74%    -- compat_swi/compat_ecl compatibility libraries providing:
   75%
   76% -- The following two dynamic predicates should be available:
   77%
   78%    -- listen_to(Type, Name, Channel) 
   79%            listen to Channel of Type (stream/socket) with Name
   80%    -- terminate/0
   81%            order the termination of the application
   82%
   83%
   84% -- The following should be implemented here:
   85%
   86%  -- name_dev/1              : mandatory *
   87%  -- initializeInterfaces(L) : mandatory *
   88%  -- finalizeInterfaces(L)   : mandatory *
   89%  -- execute/4               : mandatory *
   90%  -- handle_steam/1          : as needed
   91%  -- listen_to/3             : as needed
   92%
   93%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   94:- include(env_gen).      % INCLUDE THE CORE OF THE DEVICE MANAGER
   95
   96% Consult Lego low-level subsystem manager
   97%  This file is in charge of the actual communication with the RCX brick 
   98:- use_module(rcx_ecl).   99
  100%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  101% CONSTANTS TO BE USED
  102%
  103% name_dev/1 : state the name of the device manager (e.g., simulator, rcx)
  104%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  105% This predicate is used to state that an action should be executed
  106% whenever possible.
  107:- dynamic to_execute/3.  108   
  109% Name of the environment: <RCX>
  110% Set name of the environment here.
  111% THIS CONSTANT IS MANDATORY, DO NOT DELETE!
  112name_dev(rcx). 
  113
  114% Set verbose debug level
  115:- set_debug_level(1).  116
  117
  118% No of times we should retry when sending an action order to the RCX
  119noTries(10).
  120
  121% Frequency to trigger a new comunication to the RCX
  122ask_rcx_every(3).    
  123
  124
  125%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  126% A - INITIALIZATION AND FINALIZATION OF INTERFACES
  127%     initializeInterfaces/1 and finalizeInterfaces/1
  128%
  129% HERE YOU SHOULD INITIALIZE AND FINALIZE EACH OF THE INTERFACES TO BE USED
  130%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  131
  132initializeInterfaces(_) :- initializeExog(rcx).
  133finalizeInterfaces(_)   :- finalizeExog(rcx).
  134
  135
  136%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  137% COMMUNICATION Process with the RCX via after_every/2 event
  138%
  139% A special after_every/2 event is set to continously communicatate the PC
  140% with the RCX. Every some number of seconds the PC talks to the RCX:
  141%
  142%   If there is a pending action to be executed (to_execute/4), such action
  143%     is sent to the RCX. Sensing outcome is stored in the database.
  144%   If no action is pending, then the process asks the RCX for any exogenous
  145%     action. If there is an exogenous event from the RCX, it is handled 
  146%     by calling the corresponding handle_event/2
  147%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  148% Set up an after_every event to trigger event rcx_talk every Sec seconds
  149initializeExog(rcx) :-
  150        printKbInstructions,
  151        initializeRcx,
  152        set_event_handler(rcx_talk, rcx_com/0),
  153        ask_rcx_every(Sec), 
  154        event_after_every(rcx_talk, Sec),
  155        report_message(system(3), 'Opening RCX communication').
  156
  157% Stop the after_every event
  158finalizeExogRcx(rcx) :- 
  159        cancel_after_event(rcx_talk),
  160        report_message(system(3), 'Closing RCX communication').
  161
  162% If there is something pending to execute, execute it on the RCX
  163% Otherwise ask for possible exogenous events
  164rcx_com :- 
  165        retract(to_execute(Action, T, N)) -> 
  166            report_message(action,['Executing action: *', Action,'*']),
  167            executeRcx(Action, 1, T, S),
  168            report_sensing(Action, N, S, _)  % REPORT SENSING OUTCOME!
  169        ;
  170            report_message(system(2), 'Querying the RCX for exogenous events'),
  171            queryRcxExogAction, 
  172            report_message(system(3), 'Finished with RCX communication').
  173
  174% Ask for exogenous events. If there is one, then send it to the
  175% environment manager via soutput
  176queryRcxExogAction:- 
  177        checkRcxExog(ExogList), !, 
  178        (ExogList == [] -> 
  179             true 
  180        ; 
  181             ExogList = [A], 
  182             Message = ['Exogenous action *',A,'* received from RCX'],
  183             report_exog_event(A, Message)    % REPORT EXOGENOUS ACTION!
  184        ).
  185
  186queryRcxExogAction :- 
  187        report_message(warning, 'No reply from the RCX for exog. events').
  188
  189
  190% checkRcxExog(-RcxExogList): Check for occurrence of exogenous actions
  191%     at RCX. At present RCX can only report one exogenous action at a time
  192checkRcxExog([Action]) :- receiveRcxActionNumber([Action]), !.
  193checkRcxExog([]).    % No exogenous action from RCX
  194
  195% printKbInstructions: Print instructions on how to enter keyboard input
  196printKbInstructions :-
  197    writeln('*********************************************************'), 
  198    writeln('* NOTE: This is the RCX device manager'), 
  199    writeln('*   This window will show the communication'), 
  200    writeln('*   with the RCX brick'), 
  201    writeln('*********************************************************'), nl.
  202
  203
  204%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  205% B - HANDLERS FOR EACH STREAM/SOCKET THAT IS BEING HEARD:  handle_stream/1
  206%
  207% HERE YOU SHOULD WRITE HOW TO HANDLE DATA COMMING FROM EACH OF THE
  208% INTERFACES/CHANNELS USED
  209%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  210
  211% Handle tcl/tk stream: called when there is data comming from the tcl/tk app
  212handle_stream(tcltk) :- 
  213        read(tcltk, A),
  214        (A=end_of_file ->
  215             true          % Tcl/Tk finished
  216        ;
  217             Message = ['Exogenous action *',A,'* received from TCL/TK'],
  218             report_exog_event(A, Message)
  219        ).
  220
  221
  222%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  223% C - EXECUTION MODULE: execute/4
  224%
  225% This part implements the execution capabilities of the environment
  226%
  227% execute(Action, Type, N, Sensing) : execute Action of Type and return Sensing
  228%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  229
  230% Just assert the action to_execute/3 so that it is sent to the rcx
  231% in the next communication
  232% No sensing is sent now, but it will be sent in rcx_com/0.
  233execute(Action, Type, N, null) :- 
  234        report_message(action,['Action to be executed received: ', Action]),
  235        assert(to_execute(Action, Type, N)).
  236
  237
  238% executeRcx(Action, NoTry, Type, Sensing) 
  239%       execute Action for the NoTry time on the RCX
  240executeRcx(ActionCode, _, sim_sensing, SensingResult) :- 
  241        sendRcxActionNumber(ActionCode, _), !,
  242        write('---> Enter Sensing value, terminate with ".": '),
  243        read(SensingResult).
  244
  245executeRcx(ActionCode, _, T, SensingResult) :- T\== sim_sensing,
  246        sendRcxActionNumber(ActionCode, SensingResult), !.
  247
  248executeRcx(A, NoTry, T, S) :- 
  249        NoTry2 is NoTry+1,
  250        noTries(Limit),
  251        Limit >= NoTry2, !,
  252        report_message(warning, ['Error executing action ', A,  
  253                                 ' Trying again for the ', NoTry2, ' time.']), 
  254        executeRcx(A, NoTry2, T, S).
  255
  256executeRcx(A, _, _, failed) :- 
  257        report_message(action, ['Execution of action ', A, ' has failed!']).
  258
  259
  260
  261%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  262%%%%%%%%%%%%%%%%%%%%%%%%%%%% OTHER CODE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  263%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  264:- set_event_handler(170, my_system_error_handler/2).  265
  266my_system_error_handler(E, Goal) :-
  267        (
  268            errno_id(`Interrupted system call`),
  269%            errno_id(170, M), errno_id(M),  % M is "Unknown error 170" ??
  270            restartable_builtin(Goal)
  271        ->
  272            call(Goal)
  273        ;
  274            errno_id(M),
  275            report_message(error, M),
  276            read(_),
  277            error(default(E), Goal)
  278        ).
  279
  280% Builtins that can raise EINTR and can be restarted after that
  281restartable_builtin(accept(_,_,_)).
  282restartable_builtin(cd(_)).
  283restartable_builtin(close(_)).
  284restartable_builtin(connect(_,_)).
  285restartable_builtin(select(_,_,_)).
  286restartable_builtin(wait(_,_)).
  287
  288
  289%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  290% EOF:  Env/env_rcx.pl
  291%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%