├── Images ├── README.md ├── Tartarus.ico ├── i2cdetect1.png └── gpio_readall1.png ├── AgPi codes ├── README.md ├── blink_led.pl ├── pwm_led.pl └── pir_gyro_handlers.pl ├── Tartarus.ico ├── Tartarus_Publications └── Publications.txt ├── Utilities ├── interface.jar ├── README.md └── nxt_interface.pl ├── Archives ├── README.md ├── run_server.bat ├── Start_Tartarus.bat ├── init.pl ├── test_server.pl ├── error_correction.pl └── platform_pi_oct2017.pl ├── User Manuals ├── Tartarus_manual.pdf └── SWI-NXT interface manual.pdf ├── sample_codes ├── cloning_node2.pl ├── agent_movement_node2.pl ├── agent_payload_node2.pl ├── post_agent_example_node2.pl ├── syno_anto_node2.pl ├── syno_anto_node3.pl ├── agent_movement.pl ├── post_agent_example_node1.pl ├── agent_payload.pl ├── cloning_agent.pl ├── README.md └── syno_anto_node1.pl ├── Raspberry-Pi ├── servo.py ├── led.py ├── led.pl ├── servo.pl ├── mpu6050.pl ├── README.md └── mpu6050.py ├── Python_Support └── python_lib.pl ├── LICENSE └── README.md /Images/README.md: -------------------------------------------------------------------------------- 1 | Logos and other images 2 | -------------------------------------------------------------------------------- /AgPi codes/README.md: -------------------------------------------------------------------------------- 1 | This folder contains all the codes developed using the AgPi interface. 2 | -------------------------------------------------------------------------------- /Tartarus.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboticslab-cseiitg/ProjectTartarus/HEAD/Tartarus.ico -------------------------------------------------------------------------------- /Tartarus_Publications/Publications.txt: -------------------------------------------------------------------------------- 1 | All the publications of Tartarus will be added here 2 | -------------------------------------------------------------------------------- /Images/Tartarus.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboticslab-cseiitg/ProjectTartarus/HEAD/Images/Tartarus.ico -------------------------------------------------------------------------------- /Images/i2cdetect1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboticslab-cseiitg/ProjectTartarus/HEAD/Images/i2cdetect1.png -------------------------------------------------------------------------------- /Utilities/interface.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboticslab-cseiitg/ProjectTartarus/HEAD/Utilities/interface.jar -------------------------------------------------------------------------------- /Images/gpio_readall1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboticslab-cseiitg/ProjectTartarus/HEAD/Images/gpio_readall1.png -------------------------------------------------------------------------------- /Archives/README.md: -------------------------------------------------------------------------------- 1 | ## Archives 2 | 3 | This folder contains all archive files which are currently not part of Tartarus tool. 4 | -------------------------------------------------------------------------------- /User Manuals/Tartarus_manual.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboticslab-cseiitg/ProjectTartarus/HEAD/User Manuals/Tartarus_manual.pdf -------------------------------------------------------------------------------- /User Manuals/SWI-NXT interface manual.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboticslab-cseiitg/ProjectTartarus/HEAD/User Manuals/SWI-NXT interface manual.pdf -------------------------------------------------------------------------------- /Utilities/README.md: -------------------------------------------------------------------------------- 1 | # Utilities 2 | 3 | ## Interface to LEGO Mindstorms 4 | - Interface.jar and nxt_interface.pl are files which are part of the interface to LEGO Mindstorms robot 5 | - Refer the user manual SWI_NXTinterface in the folder User Manuals for more information 6 | -------------------------------------------------------------------------------- /sample_codes/cloning_node2.pl: -------------------------------------------------------------------------------- 1 | node2:- % Merely consults the Tartarus platform file and initiates a Tartarus paltform. 2 | consult('platform.pl'), 3 | start_tartarus(localhost,50001,1111),nl, 4 | writeln('BTW: This is the Node-2 of the network'). 5 | -------------------------------------------------------------------------------- /Archives/run_server.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo Please press enter to run relay server on default port 8688 3 | if "%1" == "" set /p portNumber=Enter port number: 4 | 5 | if "%1" NEQ "" set portNumber= %1 6 | 7 | nxjpc -jar %HOMEDRIVE%\Tartarus\interface.jar %portNumber% 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Archives/Start_Tartarus.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo Staring Tartarus platform 3 | 4 | if EXIST "%programfiles%\swipl" set mynewpath="%programfiles%\swipl\bin\swipl-win.exe" 5 | 6 | if EXIST "%programfiles(x86)%\swipl" set mynewpath="%programfiles(x86)%\swipl\bin\swipl-win.exe" 7 | 8 | START "swipl" %mynewpath% -s init.pl -g tart_start 9 | -------------------------------------------------------------------------------- /sample_codes/agent_movement_node2.pl: -------------------------------------------------------------------------------- 1 | %setting up a destination node 2 | node2:- 3 | consult('platform.pl'), %this consults the Tartarus platform file, similar to consulting the file in the swi prolog window by File -> consult 4 | start_tartarus(localhost,60001,1111), %instantiates a tartarus platform with port number 60001 and the IP as localhost 5 | writeln('This is the node2 of the network'). -------------------------------------------------------------------------------- /sample_codes/agent_payload_node2.pl: -------------------------------------------------------------------------------- 1 | %setting up a destination node 2 | node2:- 3 | consult('platform.pl'), %this consults the Tartarus platform file, similar to consulting the file in the swi prolog window by File -> consult 4 | start_tartarus(localhost,70001,1111), %instantiates a tartarus platform with port number 70001 and the IP as localhost 5 | writeln('This is the node2 of the network'). -------------------------------------------------------------------------------- /Raspberry-Pi/servo.py: -------------------------------------------------------------------------------- 1 | import RPi.GPIO as GPIO 2 | 3 | 4 | def init(Pin,Fr,Start): 5 | GPIO.setwarnings(False) 6 | Pin=int(Pin) 7 | Fr=int(Fr) 8 | Start=float(Start) 9 | GPIO.setmode(GPIO.BOARD) 10 | GPIO.setup(Pin,GPIO.OUT) 11 | init.p = GPIO.PWM(Pin,Fr) 12 | init.p.start(Start) 13 | return 'moved' 14 | 15 | 16 | -------------------------------------------------------------------------------- /Raspberry-Pi/led.py: -------------------------------------------------------------------------------- 1 | import RPi.GPIO as GPIO 2 | 3 | GPIO.setmode(GPIO.BOARD) 4 | GPIO.setwarnings(False) 5 | 6 | def On(Pin): 7 | Pin = int(Pin) 8 | GPIO.setup(Pin,GPIO.OUT) 9 | GPIO.output(Pin,GPIO.HIGH) 10 | return 'led on' 11 | 12 | def Off(Pin): 13 | Pin = int(Pin) 14 | GPIO.setup(Pin,GPIO.OUT) 15 | GPIO.output(Pin,GPIO.LOW) 16 | return 'led off' 17 | 18 | -------------------------------------------------------------------------------- /AgPi codes/blink_led.pl: -------------------------------------------------------------------------------- 1 | loop(C):- 2 | (C<20 -> 3 | (0 is mod(C,2)-> 4 | digitalWrite(1,0), 5 | delayMicroseconds(1000000), 6 | writeln('second'), 7 | millis(T), 8 | write(T), 9 | C1 is C+1, 10 | loop(C1) 11 | ; 12 | digitalWrite(1,1), 13 | delayMicroseconds(1000000), 14 | writeln('first'), 15 | C1 is C+1, 16 | loop(C1) 17 | ) 18 | ). 19 | 20 | 21 | start:- 22 | pinMode(1, 1), 23 | pinMode(0, 1), 24 | digitalWrite(0,0), 25 | digitalWrite(1,1), 26 | C is 1, 27 | loop(C), 28 | writeln('done'). 29 | -------------------------------------------------------------------------------- /AgPi codes/pwm_led.pl: -------------------------------------------------------------------------------- 1 | loop2(K):- 2 | ( K > -1 -> 3 | writeln(K), 4 | pwmWrite(1,K), 5 | delay(7), 6 | K1 is K-1, 7 | loop2(K1), 8 | ! 9 | ; 10 | writeln('Stop') 11 | ). 12 | 13 | loop(C):- 14 | ( C < 1025 -> 15 | writeln(C), 16 | pwmWrite(1,C), 17 | delay(7), 18 | C1 is C+1, 19 | loop(C1), 20 | ! 21 | ; 22 | loop2(1024) 23 | ). 24 | 25 | 26 | start:- 27 | wiringPiSetup, 28 | pinMode(1,2), 29 | pinMode(0,1), 30 | digitalWrite(0,0), 31 | pwmSetMode(0), 32 | pwmSetRange(1024), 33 | pwmSetClock(32), 34 | writeln('b'), 35 | pwmWrite(1,1024), 36 | loop(1), 37 | writeln('done'). 38 | -------------------------------------------------------------------------------- /Archives/init.pl: -------------------------------------------------------------------------------- 1 | tart_start:- 2 | writeln('************************************************************'), 3 | ansi_format([bold,fg(blue)],' Tartarus has been setup! ~w.',[.]),nl,nl, 4 | ansi_format([bold,fg(blue)],' Proceed to launch Tartarus using: start_tartarus/2~w',[.]),nl,nl, 5 | ansi_format([fg(red)],'Note: Relevant manuals are available inside the User Manuals folder~w',[.]),nl, 6 | ansi_format([fg(red)],' of the installation directory of Tartarus.~w',[.]),nl, 7 | writeln('************************************************************'), 8 | consult('platform.pl'), 9 | consult('nxt_interface.pl'). 10 | 11 | -------------------------------------------------------------------------------- /sample_codes/post_agent_example_node2.pl: -------------------------------------------------------------------------------- 1 | %this is an example for post agent - this is node2 where the message is received 2 | 3 | %this is to initiate the platform 4 | node2:- 5 | consult('platform.pl'), %this consults the Tartarus platform file, similar to consulting the file in the swi prolog window by File -> consult 6 | start_tartarus(localhost,8888,10), %10 is the token for the platform 7 | writeln('This is the node2 of the network'). 8 | %this is the handler where the posted message from node1 is received 9 | hulk(_,(localhost,9999),W):- %the variable W holds the message posted from the source 10 | writeln('I have received message from localhost 9999 ':W). 11 | 12 | hulk(_,(localhost,55555),W):- %the variable W holds the message posted from the source 13 | writeln('Received message from localhost 55555 ':W). 14 | 15 | hulk1(_,(localhost,9999),X):- %the variable W holds the message posted from the source 16 | writeln('this is hulk1 from localhost 9999 ':X). -------------------------------------------------------------------------------- /Raspberry-Pi/led.pl: -------------------------------------------------------------------------------- 1 | :- module(mpu6050, [python_call/4, ledOn/2, ledOff/2]). 2 | 3 | python_call(File, Function, Args,Result) :- 4 | atomic_list_concat(['from ', File, ' import *;print(', Function, '(''', Args, '''))'], Command), 5 | process_create(path('python'), ['-c', Command], [stdout(pipe(Out))]), 6 | read_lines(Out, Lines), last(Lines, Result). 7 | 8 | 9 | read_lines(Out, Lines) :- 10 | read_line_to_codes(Out, Line1), 11 | read_lines(Line1, Out, Lines). 12 | 13 | read_lines(end_of_file, _, []) :- !. 14 | 15 | read_lines(Codes, Out, [Line|Lines]) :- 16 | atom_codes(Line, Codes), 17 | read_line_to_codes(Out, Line2), 18 | read_lines(Line2, Out, Lines). 19 | 20 | term_string(Term, String) :- 21 | term_to_atom(Term, Atom), 22 | atom_string(Atom, S), 23 | remove_quote(S, String). 24 | 25 | remove_quote(S1, S2) :- 26 | atom_chars(S1, Chars), 27 | delete(Chars, '\'', RChars), 28 | atomic_list_concat(RChars, S2). 29 | 30 | ledOn(Pin,R):-python_call('led','On',Pin,R). 31 | ledOff(Pin,R):-python_call('led','Off',Pin,R). 32 | -------------------------------------------------------------------------------- /sample_codes/syno_anto_node2.pl: -------------------------------------------------------------------------------- 1 | 2 | :-dynamic slist/1. %this is the predicate for the list of synonyms 3 | 4 | node2:- 5 | consult('platform.pl'), %this consults the Tartarus platform file, similar to consulting the file in the swi prolog window by File -> consult 6 | start_tartarus(localhost,8888,20), %instantiates a tartarus platform with port number 8888 and the IP as localhost and the token being 20 7 | writeln('This is the node2 of the network'), 8 | retractall(slist(_)), %clears the slist predicate 9 | assert(slist([])), %asserts the slist predicate with an empty list 10 | slist(BList), %the asserted value is extracted in the variable BList 11 | Wlist=[(intelligence,[intellect,intel,wisdom,wit]),(kind,[considerate,benevolent,gracious])], %Wlist variable is assigned with the words and the synonyms 12 | append(BList,Wlist,AList), %in the Alist the words are asserted - this appends the BList and Wlist in the variable AList 13 | retractall(slist(_)), %past values are cleared from the slist predicate 14 | assert(slist(AList)), %slist predicate is assigned with the Alist variable which has the synonyms of the words 15 | writeln('The Synonym list is ':AList),!. -------------------------------------------------------------------------------- /sample_codes/syno_anto_node3.pl: -------------------------------------------------------------------------------- 1 | :-dynamic alist/1. %this is the predicate for the list of antonyms 2 | 3 | node3:- 4 | consult('platform.pl'), %this consults the Tartarus platform file, similar to consulting the file in the swi prolog window by File -> consult 5 | start_tartarus(localhost,9999,20), %instantiates a tartarus platform with port number 9999 and the IP as localhost and the token being 20 6 | writeln('This is the node3 of the network'), 7 | retractall(alist(_)), %clears the alist predicate 8 | assert(alist([])), %asserts the alist predicate with an empty list 9 | alist(BList), %the asserted value is extracted in the variable BList 10 | Wlist=[(intelligence,[stupidity,foolishness,ignorance]),(kind,[inconsiderate,cruel,harsh])], %Wlist variable is assigned with the words and the antonyms 11 | append(BList,Wlist,AList), %in the Alist the words (along with antonyms) are asserted - this appends the BList and Wlist in the variable AList 12 | retractall(alist(_)), %past values are cleared from the alist predicate 13 | assert(alist(AList)), %alist predicate is assigned with the Alist variable which has the antonyms of the words 14 | writeln('The Antonym list is ':AList),!. -------------------------------------------------------------------------------- /Raspberry-Pi/servo.pl: -------------------------------------------------------------------------------- 1 | :- module(servo, [python_call/6, python_call/3, servo/4]). 2 | 3 | 4 | 5 | 6 | python_call(File, Function, Arg1,Arg2,Arg3,Result) :- 7 | atomic_list_concat(['from ', File, ' import *; print ', Function, '(''',Arg1,''',''',Arg2,''',''',Arg3,''')'], Command), 8 | process_create(path('python'), ['-c', Command], [stdout(pipe(Out))]), 9 | read_lines(Out, Lines), last(Lines, Result). 10 | 11 | python_call(File, Function, Arg) :- 12 | atomic_list_concat(['from ', File, ' import *; print(', Function, '(''', Arg, '''))'], Command), 13 | process_create(path('python'), ['-c', Command], [stdout(pipe(Out))]). 14 | 15 | 16 | read_lines(Out, Lines) :- 17 | read_line_to_codes(Out, Line1), 18 | read_lines(Line1, Out, Lines). 19 | 20 | read_lines(end_of_file, _, []) :- !. 21 | 22 | read_lines(Codes, Out, [Line|Lines]) :- 23 | atom_codes(Line, Codes), 24 | read_line_to_codes(Out, Line2), 25 | read_lines(Line2, Out, Lines). 26 | 27 | term_string(Term, String) :- 28 | term_to_atom(Term, Atom), 29 | atom_string(Atom, S), 30 | remove_quote(S, String). 31 | 32 | remove_quote(S1, S2) :- 33 | atom_chars(S1, Chars), 34 | delete(Chars, '\'', RChars), 35 | atomic_list_concat(RChars, S2). 36 | 37 | servo(Pin,Fr,Start,Result):-python_call('servo','init',Pin,Fr,Start,Result). 38 | -------------------------------------------------------------------------------- /Python_Support/python_lib.pl: -------------------------------------------------------------------------------- 1 | %this is a library to connect prolog and python 2 | :-module(python_lib, [python_call/4, python_call/3]). 3 | 4 | python_call(File, Function, Args, Result) :- 5 | term_string(Args, SArgs), 6 | atomic_list_concat(['from ', File, ' import *;print(', Function, '(''', SArgs, '''))'], Command), 7 | process_create(path('python'), ['-c', Command], [stdout(pipe(Out)),process(PID)]), 8 | %writeln('PID is ':PID), 9 | read_lines(Out, Lines), last(Lines, Result),process_release(PID),close(Out). 10 | 11 | python_call(File, Function, Result) :- 12 | atomic_list_concat(['from ', File, ' import *;print(', Function, '())'], Command), 13 | process_create(path('python'), ['-c', Command], [stdout(pipe(Out))]), 14 | read_lines(Out, Lines), last(Lines, Result). 15 | 16 | read_lines(Out, Lines) :- 17 | read_line_to_codes(Out, Line1), 18 | read_lines(Line1, Out, Lines). 19 | 20 | read_lines(end_of_file, _, []) :- !. 21 | 22 | read_lines(Codes, Out, [Line|Lines]) :- 23 | atom_codes(Line, Codes), 24 | read_line_to_codes(Out, Line2), 25 | read_lines(Line2, Out, Lines). 26 | 27 | term_string(Term, String) :- 28 | term_to_atom(Term, Atom), 29 | atom_string(Atom, S), 30 | remove_quote(S, String). 31 | 32 | remove_quote(S1, S2) :- 33 | atom_chars(S1, Chars), 34 | delete(Chars, '\'', RChars), 35 | atomic_list_concat(RChars, S2). 36 | -------------------------------------------------------------------------------- /sample_codes/agent_movement.pl: -------------------------------------------------------------------------------- 1 | %starting the movement of the agent 2 | :-dynamic jarvis/3. %here jarvis is the name of the handler and should be dynamic. /3 defines the number of arguments in the dynamic predicate 3 | 4 | node1:- 5 | consult('platform.pl'), %this consults the Tartarus platform file, similar to consulting the file in the swi prolog window by File -> consult 6 | start_tartarus(localhost,60000,1111), %instantiates a tartarus platform with port number 60000 and the IP as localhost 7 | writeln('This is the node1 of the network'), 8 | create_mobile_agent(ironman,(localhost,60000),jarvis,[1111]), %this creates a mobile agent with the name "ironman" at the current port and IP address (60000 and localhost) with the handler as "jarvis" and the tokens associated with agent being 1111 9 | writeln('Agent is moving to node 60001'), 10 | move_agent(ironman,(localhost,60001)). % here the agent is moved to the node2 whose ip is localhost and port is 60001 11 | 12 | %handler for the agent 13 | jarvis(guid,(IP,Port),main):- %this handler is executed when the agent moves to the other node. Note: first argument is a keyword, "guid" ; second argument is (IP,Port) - this whole thing in parathesis is one argument ; the third argument is a keyword "main" 14 | writeln('I am agent from the other node and right now on ':IP :Port). %this is to print a message -------------------------------------------------------------------------------- /sample_codes/post_agent_example_node1.pl: -------------------------------------------------------------------------------- 1 | %this is an example for post agent - post the message from node1 to node2 2 | %first run node2_start from the file post_agent_example_node2.pl and 3 | % then run node1_start from the current file 4 | 5 | node1:- 6 | consult('platform.pl'), %this consults the Tartarus platform file, similar to consulting the file in the swi prolog window by File -> consult 7 | start_tartarus(localhost,9999,10), %9999 is the port and 10 is the token 8 | writeln('This is the node1 of the network'). 9 | 10 | post_msg:- 11 | post_agent(platform,(localhost,8888),[hulk,_,(localhost,9999),"Hello"]), %here the last argument is the message to be posted to the destination with IP localhost and the port 8888 12 | writeln("Message posted to the destination"). 13 | 14 | another_msg:- 15 | A=['say','green'], 16 | post_agent(platform,(localhost,8888),[hulk1,_,(localhost,9999),A]), %here the last argument is the message to be posted to the destination with IP localhost and the port 8888 17 | writeln("Message posted to the destination"). 18 | 19 | /* 20 | hulk(_,(localhost,9999),W):- %the variable W holds the message posted from the source 21 | writeln('I have received message from localhost 9999 ':W). 22 | 23 | hulk(_,(localhost,55555),W):- %the variable W holds the message posted from the source 24 | writeln('Received message from localhost 55555 ':W). 25 | 26 | hulk1(_,(localhost,9999),W):- %the variable W holds the message posted from the source 27 | writeln('this is hulk1 from localhost 9999 ':W).*/ 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Raspberry-Pi/mpu6050.pl: -------------------------------------------------------------------------------- 1 | :- module(mpu6050, [python_call/4, python_call/3, mpu6050/2, mpu6050/1]). 2 | 3 | python_call(File, Function, Args, Result) :- 4 | %term_string(Args, SArgs), 5 | %atom_number(SArgs,Int), 6 | atomic_list_concat(['from ', File, ' import *;print(', Function, '(''', Args, '''))'], Command), 7 | process_create(path('python'), ['-c', Command], [stdout(pipe(Out))]), 8 | read_lines(Out, Lines), last(Lines, Result). 9 | 10 | python_call(File, Function, Result) :- 11 | atomic_list_concat(['from ', File, ' import *;print(', Function, '())'], Command), 12 | process_create(path('python'), ['-c', Command], [stdout(pipe(Out))]), 13 | read_lines(Out, Lines), last(Lines, Result). 14 | 15 | read_lines(Out, Lines) :- 16 | read_line_to_codes(Out, Line1), 17 | read_lines(Line1, Out, Lines). 18 | 19 | read_lines(end_of_file, _, []) :- !. 20 | 21 | read_lines(Codes, Out, [Line|Lines]) :- 22 | atom_codes(Line, Codes), 23 | read_line_to_codes(Out, Line2), 24 | read_lines(Line2, Out, Lines). 25 | 26 | term_string(Term, String) :- 27 | term_to_atom(Term, Atom), 28 | atom_string(Atom, S), 29 | remove_quote(S, String). 30 | 31 | remove_quote(S1, S2) :- 32 | atom_chars(S1, Chars), 33 | delete(Chars, '\'', RChars), 34 | atomic_list_concat(RChars, S2). 35 | 36 | mpu6050(roll,Result):-python_call('mpu6050','roll',Result). 37 | mpu6050(yaw,Result):-python_call('mpu6050','yaw',Result). 38 | mpu6050(pitch,Result):-python_call('mpu6050','pitch',Result). 39 | mpu6050(all,Result):-python_call('mpu6050','all',Result). 40 | mpu6050(temp,Result):-python_call('mpu6050','temp',Result). 41 | mpu6050(Result):-python_call('mpu6050','reg',Result). -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2018 by Shivashankar B. Nair 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in 11 | the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of the copyright holders nor the names of 14 | contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | * Source code can be used for academic purpose. 17 | 18 | For commercial use permission form the author needs to be taken. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | POSSIBILITY OF SUCH DAMAGE. 31 | Software released under Creative Commence cc by-nc-sa licence. 32 | For legal information refer to: 33 | http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode 34 | -------------------------------------------------------------------------------- /sample_codes/agent_payload.pl: -------------------------------------------------------------------------------- 1 | :-dynamic number/2,hammer/3. %here number is the name of the payload which the agent will carry and the "hammer" is the name of the handler associated with the agent 2 | 3 | %starting the movement of the agent from node1. Node2 should be instantiated before running this predicate 4 | node1:- 5 | consult('platform.pl'), %this consults the Tartarus platform file, similar to consulting the file in the swi prolog window by File -> consult 6 | start_tartarus(localhost,70000,1111), %instantiates a tartarus platform with port number 70000 and the IP as localhost and the token being 1111 7 | writeln('This is the node1 of the network'), 8 | create_mobile_agent(thor,(localhost,70000),hammer,[1111]), %this creates a mobile agent with the name "thor" at the current port and IP address (70000 and localhost) with the handler as "hammer" and the tokens associated with agent being 1111 9 | retractall(number(_,_)), %this is the payload which will be added to the agent. We need to retract before asserting to clear the past values (if any) 10 | assert(number(guid,150)), %asserting the payload with the value 150 (number). the first argument is a keyword "guid" and the second argument is the value of payload 11 | add_payload(thor,[(number,2)]), %adding the payload "number" to the agent "thor". (number,2) indicates that number is the payload with 2 arguments 12 | writeln('Agent is moving to node 70001'), 13 | move_agent(thor,(localhost,70001)). % here the agent is moved to the node2 whose ip is localhost and port is 70001 14 | 15 | %handler for the agent 16 | hammer(guid,(_,_),main):- %Note that in the second argument, (_,_) the underscore is an anonymous variable. This is used when you do not need to use the variables for any purpose 17 | writeln('I am agent from the other node'), 18 | number(guid,A), %the payload number which the agent carried is extracted in the variable A 19 | writeln('Number which I have carried is ':A). -------------------------------------------------------------------------------- /Archives/test_server.pl: -------------------------------------------------------------------------------- 1 | :-use_module(library(socket)). 2 | 3 | 4 | prolog_server_test(Port, Options) :- 5 | consult('C:\\Tartarus\\platform.pl'), 6 | platform_start(localhost,8989), 7 | set_log_server(localhost,8989), 8 | tcp_socket(ServerSocket), 9 | tcp_setopt(ServerSocket, reuseaddr), 10 | tcp_bind(ServerSocket, Port), 11 | tcp_listen(ServerSocket, 5), 12 | thread_create(server_loop(ServerSocket, Options), _, 13 | [ alias(prolog_server) 14 | ]). 15 | 16 | server_loop(ServerSocket, Options) :- 17 | tcp_accept(ServerSocket, Slave, Peer), 18 | tcp_open_socket(Slave, InStream, OutStream), 19 | 20 | tcp_host_to_address(Host, Peer), 21 | ( Postfix = [] 22 | ; between(2, 1000, Num), 23 | Postfix = [-, Num] 24 | ), 25 | atomic_list_concat(['client@', Host | Postfix], Alias), 26 | catch(thread_create( 27 | service_client(InStream, OutStream, Slave, Options), 28 | _, 29 | [ alias(Alias),attach_console 30 | ]), 31 | error(permission_error(create, thread, Alias), _), 32 | fail), !, 33 | server_loop(ServerSocket, Options). 34 | 35 | 36 | service_client(InStream, OutStream, Slave, _):- 37 | thread_self(Id), 38 | readWord(InStream,Cmd), 39 | %term_to_Atom(D,Cmd), 40 | %atom_string(D,String), 41 | 42 | open('server_log.txt',append,X,[alias(input)]), 43 | current_output(Y), 44 | set_output(X), 45 | write(Cmd), 46 | close(X), 47 | format(OutStream, '~p', [Cmd]), 48 | close(InStream), 49 | close(OutStream), 50 | thread_detach(Id). 51 | 52 | 53 | readWord(InStream,W) :- 54 | get0(InStream,Char), 55 | checkCharAndReadRest(Char,Chars,InStream), 56 | atom_chars(W,Chars). 57 | 58 | checkCharAndReadRest(10,[],_) :- !. % Return 59 | checkCharAndReadRest(32,[],_) :- !. % Space 60 | checkCharAndReadRest(-1,[],_) :- !. % End of Stream 61 | checkCharAndReadRest(end_of_file,[],_) :- !. 62 | checkCharAndReadRest(Char,[Char|Chars],InStream) :- 63 | get0(InStream,NextChar), 64 | checkCharAndReadRest(NextChar,Chars,InStream). 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /Raspberry-Pi/README.md: -------------------------------------------------------------------------------- 1 | ## Tartarus for Raspberry Pi 2 | 3 | The tartarus platform file for the Raspberry Pi is the file tartarus tartarus_2020v2-2.pl. For more information of usage of Tartarus, refer tartarus user manual in the User_Manuals folder. 4 | 5 | These are other utilities available for Raspberry Pi written in SWI Prolog: 6 | 7 | ### MPU6050 8 | 9 | Files: mpu6050.pl ; mpu6050.py 10 | 11 | This package allows control over an MPU6050 IMU sensor using a Raspberry Pi through the following steps: 12 | 13 | 1. Keep the 'mpu6050.py' and the 'mpu6050.pl' files in the same directory as of the 'platform.pl' file. 14 | 2. Consult the 'mpu6050.pl' file into the desired Prolog instantiation. 15 | 3. Wire the MPU6050 IMU sensor to the Raspberry Pi. 16 | 4. Use the 'mpu6050' predicate to use the sensor. 17 | 18 | Please refer the Tartarus User Manual for further details pertaining to the concerned predicate(s). 19 | 20 | Note: Before using the sensor, ensure that is detected by the Raspberry Pi. Use the following command in the Raspberry Pi terminal to check the sensor's address (if detected successfully): 21 | 22 | i2cdetect -y 1 23 | 24 | If an address is displayed, it denotes that the sensor is sucessfully detected. 25 | 26 | 27 | ### Servo Motor 28 | 29 | Files: servo.pl ; servo.py 30 | This package allows control over a servo motor using a Raspberry Pi through the following steps: 31 | 32 | 1. Keep the 'servo.py' and the 'servo.pl' files in the same directory as of the 'platform.pl' file. 33 | 2. Consult the 'servo.pl' file into the desired Prolog instantiation. 34 | 3. Wire the servo motor to the Raspberry Pi as per the BOARD mode. 35 | 4. Use the 'servo' predicate to run the motor. 36 | 37 | Please refer the Tartarus User Manual for further details pertaining to the concerned predicate(s). 38 | 39 | ### LED 40 | 41 | Files: led.pl ; led.py 42 | 43 | This package allows control over an LED using a Raspberry Pi through the following steps: 44 | 45 | 1. Keep the 'led.py' and the 'led.pl' files in the same directory as of the 'platform.pl' file. 46 | 2. Consult the 'led.pl' file into the desired Prolog instantiation. 47 | 3. Wire the LED to the Raspberry Pi as per the BOARD mode. 48 | 4. Use the ledOn/ledOff predicate to control the LED. 49 | 50 | Please refer the Tartarus User Manual for further details pertaining to the concerned predicate(s). 51 | 52 | 53 | Please ensure to use the BOARD mode while wiring the Raspberry Pi. If required, the mode can be changed in the corresponding '.py' files. 54 | -------------------------------------------------------------------------------- /AgPi codes/pir_gyro_handlers.pl: -------------------------------------------------------------------------------- 1 | :-style_check(-singleton). 2 | :-assert(slave(no)). 3 | 4 | :-dynamic master_handler/3. 5 | master_handler(guid,(I,P),main):- 6 | writeln('=================Human_heat Agent======================'), 7 | writeln('ALERT!!! Human activity reported at the Server room!!!'), 8 | writeln('=================================================='),!. 9 | 10 | master_handler(guid,(I,P),gyro):- 11 | writeln('===%%****Vibration Agent reporting*********======='), 12 | writeln('ALERT!!! Activity reported at the Server room!!!'), 13 | writeln('=================================================='),!. 14 | 15 | :-dynamic pir_handler/3. 16 | pir_handler(guid,(Ip,P),main):- 17 | add_token(guid,[1212]), 18 | add_payload(guid,[(init_pir,2),(read_motion,2)]), 19 | platform_port(Port),slave(X), 20 | 21 | (X=no-> 22 | agent_move(guid,('192.168.1.7',8888)) 23 | ; 24 | init_pir(guid,7), 25 | writeln('System Initiated..'), 26 | writeln('Reading human motion--->>'), 27 | read_motion(guid,7) 28 | ),!. 29 | 30 | 31 | :-dynamic init_pir/2. 32 | init_pir(guid,Inpin):- 33 | pinMode(Inpin,0), 34 | writeln('PIR connected to input pin: ':Inpin),!. 35 | 36 | :-dynamic read_motion/2. 37 | read_motion(guid,Pin):- 38 | digitalRead(Pin,Data), 39 | (Data=1-> 40 | writeln('Human Motion detected! Sending alert to the master..'), 41 | agent_post(platform,('192.168.1.3',9999),[master_handler,master,('192.168.1.7',8888),main]), 42 | sleep(1.5),read_motion(guid,Pin) 43 | ; 44 | 45 | sleep(1.5),read_motion(guid,Pin) 46 | ),!. 47 | 48 | 49 | :-dynamic vibration_handler/3. 50 | vibration_handler(guid,(Ip,P),main):- 51 | add_token(guid,[1212]), 52 | add_payload(guid,[(init_mpu,3),(read_gyro,2),(poll_gyro,1)]), 53 | platform_port(Port),slave(X), 54 | 55 | (X=no-> 56 | agent_move(guid,('192.168.1.7',8888)) 57 | ; 58 | writeln('Vibration_agent initiated!!'), 59 | init_mpu(guid,0x68,F), 60 | poll_gyro(guid) 61 | 62 | ),!. 63 | 64 | :-dynamic init_mpu/3. 65 | init_mpu(guid,Addr,Fd):- 66 | wiringPiI2CSetup(Addr,Fd), 67 | wiringPiI2CWriteReg8(Fd,0x6b,0x00), 68 | wiringPiI2CWriteReg8(Fd,0x6c,0x00), 69 | wiringPiI2CWriteReg8(Fd,0x74,0x00), 70 | retractall(fd(_)),assert(fd(Fd)), 71 | writeln('Fd is ':Fd),!. 72 | 73 | :-dynamic read_gyro/2. 74 | read_gyro(guid,Data):- 75 | fd(Fd),wiringPiI2CReadReg8(Fd,0x43,D1),D2 is D1<<8, 76 | wiringPiI2CReadReg8(Fd,0x44,D3),D4 is D2\/D3, 77 | Data is round(D4/16384),!. 78 | 79 | :-dynamic poll_gyro/1. 80 | poll_gyro(guid):- 81 | sleep(0.2),read_gyro(guid,D), 82 | (D<1->writeln('alert'), 83 | agent_post(platform,('192.168.1.3',9999),[master_handler,master,('192.168.1.7',8888),gyro]) 84 | ; 85 | writeln(D) 86 | ), 87 | poll_gyro(guid),!. -------------------------------------------------------------------------------- /sample_codes/cloning_agent.pl: -------------------------------------------------------------------------------- 1 | % THIS IS A NAIVE PROGRAM TO DEMONSTRATE THE ABILITY OF TARTARUS TO CLONE AGENTS (EVEN REMOTELY) 2 | % AN AGENT KEEPS SHUTTLING FROM ONE NODE TO ANOTHER IN A 2-NODE NETWORK 3 | % EVERY TIME IT JUMPS THE ENERGY CONFERRED TO IT INITIALLY DECREMENTS 4 | % FINALLY WHEN ITS ENERGY BECOMES ZERO, IT MAKES A CLONE OF ITSELF IN THE OTHER NODE 5 | :-dynamic energy/2,thanos_task/3. 6 | 7 | node1:- 8 | consult('platform.pl'), 9 | start_tartarus(localhost,50000,1111), 10 | verbose(0), 11 | writeln('BTW: This is Node 1'). 12 | 13 | agent_init:- 14 | create_mobile_agent(thanos,(localhost,50000),thanos_task,[1111]), % Creates an agent named "thanos" in localhost at port# 50000 with handler thanos_task.Provides platform token 1111 too. 15 | retractall(energy(_,_)), % Retract any clauses for energy (just in case) 16 | assert(energy(guid,5)), % and initialize value of energy as 5. 17 | retractall(cloned(_,_)), 18 | assert(cloned(guid,0)), % 0 indicates the agent has not yet been cloned 19 | %add_token(thanos,[1111]), 20 | add_payload(thanos,[(energy,2),(cloned,2)]), % Adds the predicates (& thus facts or programs) for energy and cloned, to the agent 21 | move_agent(thanos,(localhost,50001)). % Make thanos move to the other node at Port# 50001 22 | 23 | thanos_task(guid,(localhost,Port),main):- % Agent Thanos' task handler: Describes what Thanos needs to do when it enters a node 24 | writeln('Thanos' :guid:' has arrived here ':Port),nl, 25 | (Port=50000, NextNode is 50001; % Point the next node to go to, to the other node 26 | Port=50001, NextNode is 50000), 27 | energy(guid,E), % Get the current energy 28 | writeln('Energy of the agent is ':E),nl, 29 | cloned(guid,X), % Get the no. of times the agent has been cloned 30 | 31 | ( 32 | E=0, 33 | ( 34 | X=0, 35 | retractall(cloned(_,_)),assert(cloned(guid,1)), % If Energy is 0 and X=0 (i.e. agent is not cloned) then make X=1 (i,e, agent is cloned) 36 | clone_agent(guid,(localhost,NextNode),Clone_name), % and create a clone of Thanos in the OTHER NODE. This shows we can make a clone remotely 37 | writeln('Thanos cloned with the name ':Clone_name:' on the node ':NextNode),nl 38 | ; 39 | writeln('Thanos is already cloned'),nl 40 | ) % Else it means the agent has already been cloned 41 | ; 42 | E1 is E-1, % Decrement energy and assert it 43 | retractall(energy(guid,_)), 44 | assert(energy(guid,E1)), 45 | writeln('Thanos is preparing to leave this node!'),nl, 46 | sleep(3), % Idle for 3 sec 47 | move_agent(guid,(localhost,NextNode)) % Thanos migrates to the other node 48 | ). 49 | 50 | -------------------------------------------------------------------------------- /sample_codes/README.md: -------------------------------------------------------------------------------- 1 | # Programs to get started with Tartarus 2 | 3 | This repo contains few of the programs to demonstrate the features of tartarus and to get started with Tartarus. 4 | 5 | Visit [here](https://github.com/roboticslab-cseiitg/ProjectTartarus) and get the platform.pl file to run these Tartarus programs. The User manual for Tartrus can also be found in the same link. 6 | 7 | ------------------------------------------------------------------ 8 | ### TO INSTANTIATE A TARTARUS NODE: 9 | 10 | 1. OPEN SWI PROLOG WINDOW (search "swi-prolog" in the search bar in windows start) 11 | 2. Go to file -> consult -> select the "platform.pl" file 12 | 13 | OR 14 | 15 | 1. Double click on platform.pl and open with "swi-prolog" 16 | 17 | -> type 18 | start_tartarus(localhost,60000,1). 19 | in the prompt of swi prolog 20 | 21 | -> node is instantiated on port 60000 22 | 23 | REFER TARTARUS MANUAL FOR MORE DETAILS 24 | 25 | NOTE: THE "platform.pl" IN THE FOLDER TARTARUS MATERIAL IS FOR THE WINDOWS OS. 26 | IN THE FOLDER "Other Platforms", there are platform files for the OS Ubuntu and Raspberry Pi. 27 | ********************************************************************************* 28 | 29 | ### PROGRAM : Program to demonstrate simple agent movement from one node to another 30 | #### RELEVANT FILES : agent_movement.pl ; agent_movement_node2.pl 31 | 32 | 1. Consult the file agent_movement_node2.pl and run the predicate node2. 33 | 2. Consult the file agent_movement.pl and run the predicate node1. 34 | 35 | Observe the movement of agent from node 1 to node 2 36 | 37 | ********************************************************************************** 38 | 39 | ### PROGRAM : Program to demonstrate simple agent (with payload) movement from one node to another 40 | #### RELEVANT FILES : agent_payload.pl ; agent_payload_node2.pl 41 | 42 | 1. Consult the file agent_payload_node2.pl and run the predicate node2. 43 | 2. Consult the file agent_payload.pl and run the predicate node1. 44 | 45 | Observe the movement of agent from node 1 to node 2 with the payload. 46 | 47 | ********************************************************************************** 48 | 49 | ### PROGRAM : Program to demonstrate cloning of an agent 50 | #### RELEVANT FILES : cloning_agent.pl ; cloning_node2.pl 51 | 52 | 1. Consult the file cloning_agent.pl and run the predicate node1.pl (this is node1) 53 | 2. Consult the file cloning_node2.pl and run the predicate node2.pl 54 | 3. from node1 run the predicate agent_init. 55 | 56 | *********************************************************************************** 57 | 58 | ### PROGRAM : Posting a message from one node to another 59 | #### RELEVANT FILES : post_agent_example_node1.pl, post_agent_example_node2.pl 60 | 61 | 1. Consult the post_agent_example_node1.pl file and run the predicate node1 (this is node 1) 62 | 2. Consult the post_agent_example_node2.pl file and run the predicate node2 (this is node 2) 63 | 3. Run the predicate post_msg from node 1 64 | 4. Message will be posted from node 1 to node 2 65 | 66 | *********************************************************************************** 67 | 68 | ### PROGRAM : To get the synonyms and antonyms of the word entered 69 | #### RELEVANT FILES : syno_anto_node1.pl ; syno_anto_node2.pl ; syno_anto_node3.pl 70 | 71 | 1. Run the predicates node1, node2 and node3 from the files syno_anto_node1.pl, syno_anto_node2.pl and syno_anto_node3.pl respectively in three separate swi-prolog windows. 72 | 73 | 2. Run agent_init from the port 7777 i.e., node1 (file syno_anto_node1.pl). 74 | 75 | 3. Enter the word whose synonyms and antonyms are to be fetched (current words : "intelligence" and "kind"). 76 | 77 | ************************************************************************************ 78 | -------------------------------------------------------------------------------- /Raspberry-Pi/mpu6050.py: -------------------------------------------------------------------------------- 1 | from math import * 2 | import smbus 3 | 4 | 5 | PWR_MGMT_1 = 0x6B 6 | SMPLRT_DIV = 0x19 7 | CONFIG = 0x1A 8 | GYRO_CONFIG = 0x1B 9 | INT_ENABLE = 0x38 10 | ACCEL_XOUT_H = 0x3B 11 | ACCEL_YOUT_H = 0x3D 12 | ACCEL_ZOUT_H = 0x3F 13 | GYRO_XOUT_H = 0x43 14 | GYRO_YOUT_H = 0x45 15 | GYRO_ZOUT_H = 0x47 16 | TEMP_OUT = 0x41 17 | bus = smbus.SMBus(1) 18 | Device_Address=0 19 | for device in range(128): 20 | 21 | try: 22 | bus.read_byte(device) 23 | Device_Address=device 24 | except: 25 | pass 26 | 27 | 28 | 29 | def MPU_Init(Device_Address): 30 | bus.write_byte_data(Device_Address, SMPLRT_DIV, 7) 31 | 32 | bus.write_byte_data(Device_Address, PWR_MGMT_1, 1) 33 | 34 | bus.write_byte_data(Device_Address, CONFIG, 0) 35 | 36 | bus.write_byte_data(Device_Address, GYRO_CONFIG, 24) 37 | 38 | bus.write_byte_data(Device_Address, INT_ENABLE, 1) 39 | 40 | def read_raw_data(Device_Address,addr): 41 | high = bus.read_byte_data(Device_Address, addr) 42 | low = bus.read_byte_data(Device_Address, addr+1) 43 | value = ((high << 8) | low) 44 | 45 | if(value > 32768): 46 | value = value - 65536 47 | return value 48 | 49 | def all(): 50 | MPU_Init(Device_Address) 51 | acc_x = read_raw_data(Device_Address,ACCEL_XOUT_H) 52 | acc_y = read_raw_data(Device_Address,ACCEL_YOUT_H) 53 | acc_z = read_raw_data(Device_Address,ACCEL_ZOUT_H) 54 | raw_temp = read_raw_data(Device_Address,TEMP_OUT) 55 | Ax = acc_x/16384.0 56 | Ay = acc_y/16384.0 57 | Az = acc_z/16384.0 58 | temp = (raw_temp/340) + 36.53 59 | vals = [] 60 | roll=(atan2(Ay,Az)*180.0)/pi 61 | pitch=(atan2(Ax,Ay)*180.0)/pi 62 | yaw=(atan2(Ax,Az)*180.0)/pi 63 | vals.append(roll) 64 | vals.append(pitch) 65 | vals.append(yaw) 66 | vals.append(temp) 67 | return vals 68 | 69 | def roll(): 70 | MPU_Init(Device_Address) 71 | acc_y = read_raw_data(Device_Address,ACCEL_YOUT_H) 72 | acc_z = read_raw_data(Device_Address,ACCEL_ZOUT_H) 73 | Ay = acc_y/16384.0 74 | Az = acc_z/16384.0 75 | roll=(atan2(Ay,Az)*180.0)/pi 76 | return roll 77 | 78 | def pitch(): 79 | MPU_Init(Device_Address) 80 | acc_x = read_raw_data(Device_Address,ACCEL_XOUT_H) 81 | acc_y = read_raw_data(Device_Address,ACCEL_YOUT_H) 82 | Ax = acc_x/16384.0 83 | Ay = acc_y/16384.0 84 | pitch=(atan2(Ax,Ay)*180.0)/pi 85 | return pitch 86 | 87 | def yaw(): 88 | MPU_Init(Device_Address) 89 | acc_x = read_raw_data(Device_Address,ACCEL_XOUT_H) 90 | acc_z = read_raw_data(Device_Address,ACCEL_ZOUT_H) 91 | Ax = acc_x/16384.0 92 | Az = acc_z/16384.0 93 | yaw=(atan2(Ax,Az)*180.0)/pi 94 | return yaw 95 | 96 | def temp(): 97 | MPU_Init(Device_Address) 98 | raw_temp = read_raw_data(Device_Address,TEMP_OUT) 99 | temp = (raw_temp/340) + 36.53 100 | return temp 101 | 102 | def reg(): 103 | MPU_Init(Device_Address) 104 | Ax1 = bus.read_byte_data(Device_Address, ACCEL_XOUT_H) 105 | Ax2 = bus.read_byte_data(Device_Address, ACCEL_XOUT_H+1) 106 | Ay1 = bus.read_byte_data(Device_Address, ACCEL_YOUT_H) 107 | Ay2 = bus.read_byte_data(Device_Address, ACCEL_YOUT_H+1) 108 | Az1 = bus.read_byte_data(Device_Address, ACCEL_ZOUT_H) 109 | Az2 = bus.read_byte_data(Device_Address, ACCEL_ZOUT_H+1) 110 | T1 = bus.read_byte_data(Device_Address, TEMP_OUT) 111 | T2 = bus.read_byte_data(Device_Address, TEMP_OUT+1) 112 | rval = [] 113 | rval.append(Ax1) 114 | rval.append(Ax2) 115 | rval.append(Ay1) 116 | rval.append(Ay2) 117 | rval.append(Az1) 118 | rval.append(Az2) 119 | rval.append(T1) 120 | rval.append(T2) 121 | return rval 122 | 123 | -------------------------------------------------------------------------------- /sample_codes/syno_anto_node1.pl: -------------------------------------------------------------------------------- 1 | %this is program to get the synonyms and antonyms 2 | :-dynamic wordhandler/3,word/2,synlist/2,antlist/2. 3 | node1:- 4 | consult('platform.pl'), %this consults the Tartarus platform file, similar to consulting the file in the swi prolog window by File -> consult 5 | start_tartarus(localhost,7777,20), %instantiates a tartarus platform with port number 7777 and the IP as localhost and the token being 20 6 | writeln('This is the node1 of the network'). 7 | 8 | agent_init:- 9 | create_mobile_agent(syn_agent,(localhost,7777),wordhandler,[20]), %this creates a mobile agent with the name "syn_agent" at the current port and IP address (7777 and localhost) with the handler as "wordhandler" and the tokens associated with agent being 20 10 | writeln('Enter the word whose synonyms and antonyms are to be fetched'), 11 | read(Word), %the input word is read from the user and assigned to variable Word 12 | writeln('The word read is ':Word), 13 | retractall(word(_,_)), %the "word" (notice the case) is a dynamic predicate, is cleared to clear all the past values if any 14 | assert(word(guid,Word)), %it assigns payload "word" with the value read from the user in the variable Word 15 | retractall(synlist(_,_)), %synlist is the predicate which will collect the synonyms of the word entered and here it is cleared of any past values 16 | assert(synlist(guid,[])), %synlist is initialised to an empty list 17 | retractall(antlist(_,_)), %antlist is the predicate which will collect the antonyms of the word entered and here it is cleared of any past values 18 | assert(antlist(guid,[])), %antlist is initialised to an empty list 19 | add_payload(syn_agent,[(word,2),(synlist,2),(antlist,2)]), %all the three payloads word,synlist and antlist is added to the agent 20 | move_agent(syn_agent,(localhost,8888)). %agent syn_agent is moved to the port 8888 21 | 22 | 23 | wordhandler(guid,(_,Port),main):- 24 | writeln('The agent has landed at ':Port), 25 | ( 26 | ( Port=8888, % if the port the agent has landed on is 8888 27 | word(guid,Word), % here the word is extracted into the variable Word 28 | NextNode is 9999, % next node which the agent visits from this node is 9999 and is assigned to the variable 9999 29 | slist(WList), % the synonym list is extracted to WList variable of all words 30 | nth0(_,WList,(Word,Slist)), %in the variable Slist, the synonyms of the word in the variable Word is extracted. 31 | writeln('The list of the synonyms is ':Slist), 32 | retractall(synlist(guid,_)), %the synlist is cleared of the old value which was an empty list. Note that the first argument guid is not cleared. guid indicates the agent name, hence this retractall only clears the value associated with this agent 33 | assert(synlist(guid,Slist)), %the extracted synonym list of the Word is asserted in the payload. Note tthat this is not added to the agent again, because it is already added in the agent 34 | move_agent(guid,(localhost,NextNode)) %now the agent is moved to the next node 9999 35 | ) 36 | ; 37 | ( Port=9999, %if the port is 9999 then the following statements are executed 38 | word(guid,Word), %the word is extracted in the variable Word 39 | NextNode is 7777, %next node where the agent should travel to is the node 1 with the port 7777 40 | alist(WList), %in the variable WList all the antonyms of all the words 41 | nth0(_,WList,(Word,Aflist)), %in the variable Aflist, the antonyms of the Word are extracted 42 | writeln('The list of the antonyms is ':Aflist), 43 | retractall(antlist(guid,_)), %the antlist predicate is cleared before asserting the antonyms extracted 44 | assert(antlist(guid,Aflist)), %the antonyms extracted are asserted in the payload and since the payload is already added to the agent 45 | move_agent(guid,(localhost,NextNode)) %here the agent is moved to the next node which is 7777 46 | ); 47 | synlist(guid,S), %here the agent is back to the source node and the synonyms are extracted in the variable S 48 | antlist(guid,A), %here the antonyms are extracted to the variable A 49 | word(guid,W), %the word is extracted in the variable W 50 | writeln('Entered word is ':W), 51 | writeln('List of synonyms is ':S), 52 | writeln('List of antonyms is ':A) 53 | ), 54 | !. 55 | 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ProjectTartarus 2 | ## Overture 3 | As per Greek mythology, Tartarus refers to an oubliette or dungeon, possibly like Hades, where the evil and wicked were sent to be tormented. The name has also been used to refer to a primordial force or deity [Source: Wiki]. In our world, Tartarus refers to a Multi-Agent platform which can take in your problems and churn out solutions. Tartarus is the new version of Typhon and is built using SWI-Prolog. For any queries kindly reach out us tartarus.iitg@gmail.com. You can drop a mail to us after downloading the file : Tartarus.pl, so that we can keep you posted about the updates and revisions. 4 | 5 | ## Introduction 6 | Written in SWI-Prolog, Tartarus, facilitates users to create overlay sort of network of nodes comprising either a single PC/laptop/embedded system or several such devices connected as a LAN (wired/wireless) and then program both static and mobile agents. Agents in Tartarus are basically programs written in Prolog. They can be programmed to perform tasks autonomously at select nodes and even migrate to others in the network they inhabit. Such agents can even be programmed to clone (copy and multiply) on-the-fly and then move around the network and execute tasks concurrently, providing a distributed and decentralized processing environment. These agents can also carry programs as payloads. Payloads could be written in Prolog or Python and executed at desired nodes. One could try out using other languages as well. Agents can communicate amongst one another and also with programs at a node. As of now, Tartarus can be run on Windows, Ubuntu and Raspbian operating systems. 7 | Tartarus can run on the Raspberry Pi. It can be used to sense the sensors on-board and also control the actuators (motors, relays, etc.) connected to the board. 8 | 9 | ***Tartarus - Some salient features*** 10 | 11 | * Multi-threading: Tartarus allows for the threaded execution of agents so that they all function concurrently. These threads are managed by its core engine thereby ridding the developers of comprehending the complexities of implementing mutual exclusion. 12 | 13 | * Heterogeneity: Tartarus supports both Windows, Ubuntu and Raspbian and can thus be installed in most hardware which runs these operating systems. Agents running on top of any of these operating systems can communicate with one another providing cross-platform interchange. 14 | 15 | * Hardware-in-the-loop: Tartarus can be ported on embedded boards such as the Raspberry Pi. It also comes with an interface for the LEGO MINDSTORM NXT robots. These special interfaces allow developers to access and control the underlying hardware, thus making it easier for a developer to build applications with hardware-in-the-loop. 16 | 17 | * Distributed Control: Multi-Agent Systems (MAS) provide for ideal solutions for applications that demand distributed computations and communications among heterogeneous entities. Tartarus agents can share information between nodes, migrate amongst them and even execute the code at a destination/remote node. 18 | 19 | * Mobility & Cloning: Agents can also be mobile and can migrate from one node to another in a network they inhabit. They can also clone as and when required contributing to a degree of parallelism in the network. 20 | 21 | * Payloads: A mobile agent within Tartarus can carry a set of programs/data as a payload to be either executed at the destination node or be downloaded for use at some node. Agents can also be programmed to either upload/download/offload these payloads at specific nodes or based on an event. Changing a payload can thus facilitate the altering of the behaviour of an agent even in runtime. 22 | 23 | * Security: Security implemented for the agents in Tartarus. Mobile agents can enter a node only if they possess a key (provided to them a priori). This key should match with the one in the platform installed at the node; else entry is rejected. Developers can put in a bit of effort to provide for a more sophisticated security arrangement based on their application. 24 | 25 | Check out a video on Tartarus here: https://www.youtube.com/watch?v=VeryfhtT5Tk 26 | 27 | ## What has Tartarus been used for, so far? 28 | Agents provide for distributed, centralized/decentralized and concurrent executions across a network. 29 | They can execute asynchronously and autonomously. At the Robotics Lab. we have used it for a range of application scenarios which include – 30 | Networked Robot control, IoT based control, Indoor Localization, Synchronization, VANETs, Asynchronous Intelligence Sharing across a network, Decentralized Clonal Controller, On-the-fly-Programming, Green Corridors for urban traffic, IoT for Railways, Algorithm selection, Mutual Exclusions in Real Robots, Emulation of Bio-inspired mechanisms such as Pheromoning, Stigmergy, Clonal Selection, Idiotypic Networks, Genetic Algorithms, etc. 31 | 32 | ## How can Tartarus help in other areas? 33 | A fairly stable version of Tartarus is now also available for the Raspberry Pi. We will be making the same available shortly. This version designated Agents-on-Pi (AgPi) also provides an interface to sensors and actuators on-board the Pi making it easier to program for autonomous decision making. This facilitates rapid prototyping of an intelligent Internet of Things (IoT). 34 | With data distributed across several nodes, agents (both static and mobile) can be programmed to process them in a decentralized and concurrent manner. Mobile agents can be made to move from one node to another and autonomously control the flow of information between such data islands. Bio-inspired (optimizing) algorithms, which are mostly decentralized and distributed, can be emulated, in almost the way Mother Nature does. By injecting new programs via agents, the behavior of a system can also be changed on-the-fly. 35 | Thinking aloud, it could be interesting to develop a network wherein the nodes programmed to behave like atoms/molecules in a liquid act concurrently. This could aid in the study of the ways in which a more complex protein molecule develops using mobile agents enacting as portions of the protein chain. Molecule formation could thus be investigated within a network. 36 | The platform could aid in the making smarter homes, even Greenhouses and campuses. 37 | Simulations could be given up for emulations in Tartarus based networks to churn better and more realistic data in decentralized and distributed scenarios. 38 | We leave it to you to think louder (!) and get back to the Tartarus team, if required, with the problems you need to tackle. We shall do our best to aid you in making this demon help you find a solution. 39 | 40 | **To Get Started**, check the [WiKi](https://github.com/roboticslab-cseiitg/ProjectTartarus/wiki) page. 41 | 42 | ## One last yet important note 43 | Tartarus culminated from years of work and yet we offer the same to you free. It is thus only logical that you cite the following papers when you publish your research derived using this software: 44 | 45 | Tushar Semwal, Nikhil S., Shashi Shekhar Jha, Shivashankar B. Nair, TARTARUS: A Multi Agent Platform for Bridging the gap between Cyber and Physical Systems, *Proceedings of the 2016 Autonomous Agents and Multi-Agent Systems Conference, (AAMAS), International Foundation for Autonomous Agents and Multiagent Systems*, pp. 1493-1495, Singapore. 46 | 47 | Tushar Semwal, Shivashankar B. Nair, AgPi: Agents on Raspberry Pi, *Electronics 2016, 5, 72*. 48 | 49 | Cheers, 50 | The Tartarus Team 51 | -------------------------------------------------------------------------------- /Archives/error_correction.pl: -------------------------------------------------------------------------------- 1 | :-dynamic error/0. 2 | :-dynamic ecnt/1. 3 | 4 | ecnt(0). 5 | 6 | check_syntax(assert_file_to_tartarus,FILE):- 7 | catch((atom(FILE)->true;assert(error),retract(ecnt(X)),X1 is X+1,assert(ecnt(X1)),throw(notAtom)),_Error2000,(write('Error# tf1:'),writeln(' The argument is not an atom.'))), chk_err. 8 | 9 | check_syntax(get_new_name_alpha,Agent_name):- 10 | catch((var(Agent_name)->true;assert(error),retract(ecnt(Y)),Y1 is Y+1,assert(ecnt(Y1)),throw(notVar)),_Error400,(write('Error# gnma1:'),writeln(' The argument is not a variable.'))),chk_err. 11 | 12 | check_syntax(add_payload,GUID,AddList):- 13 | catch((atom(GUID)->true;assert(error),retract(ecnt(X)),X1 is X+1,assert(ecnt(X1)),throw(notAtom)),_Error1,(write('Error# ap1:'),writeln(' First argument is not an atom.'))), 14 | catch((is_list(AddList)->true;assert(error),retract(ecnt(Y)),Y1 is Y+1,assert(ecnt(Y1)),throw(notList)),_Error2,(write('Error# ap2:'),writeln(' Last argument is not a list.'))),chk_err. 15 | 16 | check_syntax(remove_payload,GUID,ToRemove):- 17 | catch((atom(GUID)->true;assert(error),retract(ecnt(X)),X1 is X+1,assert(ecnt(X1)),throw(notAtom)),_Error300,(write('Error# rp1:'),writeln(' First argument is not an atom.'))), 18 | catch((is_list(ToRemove)->true;assert(error),retract(ecnt(Y)),Y1 is Y+1,assert(ecnt(Y1)),throw(notList)),_Error301,(write('Error# rp2:'),writeln(' Last argument is not a list.'))),chk_err. 19 | 20 | check_syntax(save_agent,GUID,FileName):- 21 | catch((atom(GUID)->true;assert(error),retract(ecnt(X)),X1 is X+1,assert(ecnt(X1)),throw(notAtom)),_Error1000,(write('Error# sav1:'),writeln(' First argument is not an atom.'))), 22 | catch((atom(FileName)->true;assert(error),retract(ecnt(Y)),Y1 is Y+1,assert(ecnt(Y1)),throw(notList)),_Error1001,(write('Error# sav2:'),writeln(' Last argument is not an atom.'))),chk_err. 23 | 24 | check_syntax(get_tartarus_details,IP,Port,OS):- 25 | catch((var(IP)->true;assert(error),retract(ecnt(X)),X1 is X+1,assert(ecnt(X1)),throw(notVar)),_Error3,(write('Error# td1:'),writeln(' First argument is not a variable.'))), 26 | catch((var(Port)->true;assert(error),retract(ecnt(Y)),Y1 is Y+1,assert(ecnt(Y1)),throw(notVar)),_Error4,(write('Error# td2:'),writeln(' Second argument is not a variable.'))), 27 | catch((var(OS)->true;assert(error),retract(ecnt(Z)),Z1 is Z+1,assert(ecnt(Z1)),throw(notVar)),_Error9876,(write('Error# td3:'),writeln(' Last argument is not a variable.'))), 28 | chk_err. 29 | 30 | check_syntax(start_tartarus,_Ip,Port,Token):- 31 | catch((integer(Port)->true;assert(error),retract(ecnt(X)),X1 is X+1,assert(ecnt(X1)),throw(notInt)),_Error5,(write('Error# t1:'),writeln(' Third argument is not an integer.'))), 32 | catch((integer(Token)->true;assert(error),retract(ecnt(Y)),Y1 is Y+1,assert(ecnt(Y1)),throw(notInt)),_Error6,(write('Error# t2:'),writeln(' Last argument is not an integer.'))), 33 | ((integer(Port)->(catch((pre1(Port)),_Error900,(write('Error# t3:'),writeln(' Second argument is not a positive number.')))));chk_err), 34 | chk_err. 35 | 36 | check_syntax(move_agent,GUID,_Ip_other_end,Port_other_end):- 37 | catch((atom(GUID)->true;assert(error),retract(ecnt(Y)),Y1 is Y+1,assert(ecnt(Y1)),throw(notAtom)),_Err,(write('Error# mov1:'),writeln(' First argument is not an atom.'))), 38 | catch((integer(Port_other_end)->true;assert(error),retract(ecnt(X)),X1 is X+1,assert(ecnt(X1)),throw(notInt)),_Err1,(write('Error# mov2:'),writeln(' Last argument is not an integer.'))), 39 | ((integer(Port_other_end)->(catch((pre1(Port_other_end)),_Err2,(write('Error# mov3:'),writeln(' Last argument is not a positive number.')))));chk_err), 40 | chk_err. 41 | 42 | check_syntax(create_mobile_agent,_GUID,Handler,List):- 43 | catch((atom(Handler)->true;assert(error),retract(ecnt(Y)),Y1 is Y+1,assert(ecnt(Y1)),throw(notAtom)),_Er,(write('Error# ma21:'),writeln(' Second argument is not an atom.'))), 44 | catch((is_list(List)->true;assert(error),retract(ecnt(Z)),Z1 is Z+1,assert(ecnt(Z1)),throw(notList)),_Er1,(write('Error # ma22:'),writeln(' Last argument is not a list.'))), 45 | ((is_list(List)->(catch((pre(List)),_Er2,(write('Error# ma23:'),writeln(' Last argument is not an integer.')))));chk_err),chk_err. 46 | 47 | check_syntax(execute_agent3,Agent_name,_Ip,Port,Handler):- 48 | catch((atom(Agent_name)->true;assert(error),retract(ecnt(X)),X1 is X+1,assert(ecnt(X1)),throw(notAtom)),_Error7,(write('Error# ea1:'),writeln(' First argument is not an atom.'))), 49 | catch((integer(Port)->true;assert(error),retract(ecnt(Y)),Y1 is Y+1,assert(ecnt(Y1)),throw(notInt)),_Error8,(write('Error# ea2:'),writeln(' Third argument is not an integer.'))), 50 | catch((atom(Handler)->true;assert(error),retract(ecnt(Z)),Z1 is Z+1,assert(ecnt(Z1)),throw(notAtom)),_Error9,(write('Error# ea3:'),writeln(' Last argument is not an atom.'))), 51 | ((integer(Port)->(catch((pre1(Port)),_Error50,(write('Error# ea4:'),writeln(' Third argument is not a positive number.')))));chk_err), 52 | chk_err. 53 | 54 | check_syntax(clone_agent,GUID1,_Send_Ip,Send_Port,GUID2):- 55 | catch((atom(GUID1)->true;assert(error),retract(ecnt(X)),X1 is X+1,assert(ecnt(X1)),throw(notAtom)),_Error10,(write('Error# ca1:'),writeln(' First argument is not an atom.'))), 56 | catch((integer(Send_Port)->true;assert(error),retract(ecnt(Y)),Y1 is Y+1,assert(ecnt(Y1)),throw(notInt)),_Error11,(write('Error# ca2:'),writeln(' Third argument is not an integer.'))), 57 | catch((var(GUID2)->true;assert(error),retract(ecnt(Z)),Z1 is Z+1,assert(ecnt(Z1)),throw(notVar)),_Error12,(write('Error# ca3:'),writeln(' Last argument is not a variable.'))), 58 | ((integer(Send_Port)->(catch((pre1(Send_Port)),_Error51,(write('Error# ca4:'),writeln(' Third argument is not a positive number.')))));chk_err), 59 | chk_err. 60 | 61 | check_syntax(create_mobile_agent,_GUID,_Ip,Port,Handler,List):- 62 | catch((integer(Port)->true;assert(error),retract(ecnt(X)),X1 is X+1,assert(ecnt(X1)),throw(notInt)),_Error1600,(write('Error# ma1:'),writeln(' Third argument is not an integer.'))), 63 | catch((atom(Handler)->true;assert(error),retract(ecnt(Y)),Y1 is Y+1,assert(ecnt(Y1)),throw(notAtom)),_Error14,(write('Error# ma2:'),writeln(' Fourth argument is not an atom.'))), 64 | catch((is_list(List)->true;assert(error),retract(ecnt(Z)),Z1 is Z+1,assert(ecnt(Z1)),throw(notList)),_Error15,(write('Error # ma3:'),writeln(' Last argument is not a list.'))), 65 | ((is_list(List)->(catch((pre(List)),_Error56,(write('Error# ma4:'),writeln(' Last argument is not an integer.')))));true), 66 | ((integer(Port)->(catch((pre1(Port)),_Error5300,(write('Error# ma5:'),writeln(' Third argument is not positive.')))));chk_err),chk_err. 67 | 68 | 69 | check_syntax(create_static_agent,_Agent_name,_Platform_Ip,Port,Handler,List):- 70 | catch((integer(Port)->true;assert(error),retract(ecnt(X)),X1 is X+1,assert(ecnt(X1)),throw(notInt)),_Error16,(write('Error# sa1:'),writeln(' Third argument is not an integer.'))), 71 | ((integer(Port)->(catch((pre1(Port)),_Error53,(write('Error# sa2:'),writeln(' Third argument is not positive.')))));true), 72 | catch((atom(Handler)->true;assert(error),retract(ecnt(Y)),Y1 is Y+1,assert(ecnt(Y1)),throw(notAtom)),_Error17,(write('Error# sa3:'),writeln(' Fourth argument is not an atom.'))), 73 | catch((is_list(List)->true;assert(error),retract(ecnt(Z)),Z1 is Z+1,assert(ecnt(Z1)),throw(notList)),_Error18,(write('Error# sa4:'),writeln(' Last argument is not a list.'))), 74 | ((is_list(List)->(catch((pre(List)),_Error55,(write('Error# sa5:'),writeln(' Last argument is not an integer.')))));chk_err), 75 | chk_err. 76 | 77 | check_syntax(execute_agent4,Agent_name,_Ip,Port,Handler,Start_function):- 78 | catch((atom(Agent_name)->true;assert(error),retract(ecnt(X)),X1 is X+1,assert(ecnt(X1)),throw(notAtom)),_Error20,(write('Error# ea5:'),writeln(' First argument is not an atom.'))), 79 | catch((integer(Port)->true;assert(error),retract(ecnt(Y)),Y1 is Y+1,assert(ecnt(Y1)),throw(notInt)),_Error21,(write('Error# ea6:'),writeln(' Third argument is not an integer.'))), 80 | catch((atom(Handler)->true;assert(error),retract(ecnt(Z)),Z1 is Z+1,assert(ecnt(Z1)),throw(notAtom)),_Error22,(write('Error# ea7:'),writeln(' Fourth argument is not an atom.'))), 81 | catch((atom(Start_function)->true;assert(error),retract(ecnt(A)),A1 is A+1,assert(ecnt(A1)),throw(notAtom)),_Error23,(write('Error# ea8:'),writeln(' Last argument is not an atom.'))), 82 | ((integer(Port)->(catch((pre1(Port)),_Error54,(write('Error# ea9:'),writeln(' Third argument is not a positive number.')))));chk_err), 83 | chk_err. 84 | %-----------------------------------------------------------------------------------------------------------------% 85 | 86 | chk_err:- 87 | error,retractall(error), 88 | chk_ecnt. 89 | 90 | chk_err. 91 | 92 | chk_ecnt:- 93 | write('errors found: '),ecnt(Num_err),write(Num_err),nl,retract(ecnt(Num_err)), assert(ecnt(0)),abort. 94 | 95 | chk_ecnt. 96 | %-----------------------------------------------------------------------------------------------------------------% 97 | 98 | %-------- Program to access the elements of a list one by one and check whether it is an integer.--------------% 99 | pre(List):- 100 | length(List,L), 101 | testloop(List,L). 102 | 103 | testloop(_Token_list,0). 104 | testloop(Token_list,N) :- N>0, nth1(N, Token_list, Elem),(integer(Elem)->true;assert(error),retract(ecnt(B)),B1 is B+1,assert(ecnt(B1)),throw(notInt)), M is N-1, testloop(Token_list,M). 105 | %---------------------------------------------------------------------------------------------------------------% 106 | % ----------------------To check whether the given port number is positive---------------------------------------% 107 | pre1(Port):- 108 | ((Port>0)->true;assert(error),retract(ecnt(C)),C1 is C+1,assert(ecnt(C1)),throw(notPositive)). 109 | %----------------------------------------------------------------------------------------------------------------% 110 | -------------------------------------------------------------------------------- /Utilities/nxt_interface.pl: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2016 Robotics Lab., IIT Guwahati 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | 17 | */ 18 | 19 | %============================================================================================================================================ 20 | % Authors :: Vivek Singh 10010172 21 | % Manoj Bode 22 | % Date : 08022015 23 | % 24 | % Project Supervisor : Dr. S.B. Nair. 25 | % 26 | % This is a SWI-Prolog interface for Lego MindStrom NXT Brick running on Lejos Firmware. 27 | % 28 | % (c) Robotics Lab, CSE Department, IIT-Guwahti. 29 | %============================================================================================================================================= 30 | 31 | %To download the initial files to the nxt brick 32 | :- dynamic name_socket/4. %% used for storing name and socket of connection 33 | 34 | my_number_string(Number,String):- 35 | atom_number(String,Number). 36 | 37 | 38 | setup_nxt(NXT):- 39 | writeln('Copying nxtbin file to NXT...'), 40 | join_str('C:\\Tartarus\\copy_files.bat ',NXT,' ',R1), 41 | join_str(R1,'nxtbin',' ',R2), 42 | atom_string(Cmd1,R2), 43 | win_exec(Cmd1,normal), 44 | write('Check nxtbin.nxj file on NXT'),nl,!. 45 | 46 | 47 | %Start the nxt, java server and create the connection stream Link is Ip address 48 | initialize_nxt(Name,Link,Port,Res):- 49 | my_number_string(Port,P), 50 | join_str('C:\\Tartarus\\run_server.bat ',P,' ',R3), %send Robot Name too as a parameter - Nikhil 30/4/2016 51 | atom_string(Cmd,R3), 52 | win_exec(Cmd,normal), 53 | write('Initiating connection with nxt...'),nl, 54 | %atom_string(Link,Link2), 55 | connect2_nxt(Name,Link,Port,Res). 56 | 57 | 58 | %To read the response from the java server the response comes as => 123XMessage 59 | %read_nxt(_Soc,_Text). 60 | read_nxt(ResText,Output):- 61 | format(codes(A),'~q.',[ResText]), 62 | string_codes(Text,A), 63 | nth0(Index,A,45), 64 | sub_atom(Text,0,Index,_,Output),!. 65 | 66 | %Connecting with the java server with error handling 67 | connect2_nxt(Name,Link,Port,T):- 68 | atom(Name)-> 69 | (atom(Link)-> %%%%%%%%%%%%%%%%%%%%%% Atom to string 70 | (number(Port)-> 71 | (atomic(T)->write('Error: 4th Agrument must be Unbound Variable'),nl,abort; 72 | connect_nxt(Name,Link,Port),sleep(0.1)->write('Waiting for reply...'),nl, 73 | read_res_nxt(Name,T), 74 | (T='failed'-> 75 | print_message(error,'Please check the NXT'), 76 | fail; 77 | nl), 78 | write('==================== SWI-PROLOG-NXT INTERFACE ==================='),nl, 79 | write('==== Developed by Robotics Lab, Department of CSE, IIT Guwahati, INDIA ===='),nl, 80 | write('================================================================'),nl,!; 81 | write('Error: Connection Failed, Check if port is available'),nl,abort); 82 | write('Error: 3rd Argument must be number'),nl,abort); 83 | write('Error: 2nd Argument must be atom'),nl,abort); 84 | write('Error: 1st Argument must be atom'),nl,abort. 85 | 86 | %Creating a socket and connecting with the java server 87 | connect_nxt(Name,Link,Port):- 88 | atom_string(Link2,Link), 89 | tcp_socket(Socket), 90 | tcp_connect(Socket,Link2:Port), 91 | retractall(name_socket(Name,_,_,_)), 92 | tcp_open_socket(Socket,In,Out), 93 | asserta(name_socket(Name,Socket,In,Out)),!. 94 | 95 | %To write to the java server, i.e., on the socket 96 | written_nxt(Name,Msg):- 97 | string_codes(Msg,List), 98 | append(List,[36],Nlist), 99 | string_codes(M,Nlist), 100 | atom_string(M2,M), 101 | name_socket(Name,_,In,Out), 102 | %tcp_open_socket(Socket,In,Out), 103 | format(Out,'~q',[M2]), 104 | flush_output(Out), 105 | read(In,Rep), 106 | read_nxt(Rep,_Output). 107 | 108 | socket_recv_code(StreamPair, String, Length) :- 109 | ( at_end_of_stream(StreamPair) 110 | -> String = "", 111 | Length = -1 112 | ; read_pending_input(StreamPair, String, []), 113 | length(String, Length) 114 | ). 115 | 116 | 117 | %Write with error handling 118 | write_nxt(Name,Msg):- 119 | %catch(Error, 120 | written_nxt(Name,Msg),!. 121 | %throw(Error,start_nxt(Name,_Link,_Port,_Response)). 122 | 123 | %To close the complete connection or session 124 | close_nxt(Name):- write_nxt(Name,'@'), 125 | name_socket(Name,Socket,In,Out), 126 | retractall(name_socket(Name,Socket,_,_)), 127 | close(Out,[force(true)]), 128 | close(In,[force(true)]), 129 | tcp_close_socket(Socket),!. 130 | 131 | %To join two string str1 and str2 with a seperator Sep and gives the final string Fstr. 132 | join_str(Str1,Str2,Sep,Fstr):- 133 | string_codes(Str1,S1), 134 | string_codes(Str2,S2), 135 | string_codes(Sep,S3), 136 | append(S1,S3,Slist), 137 | append(Slist,S2,Flist), 138 | string_codes(Fstr,Flist). 139 | 140 | %To move the nxt in forward direction 141 | move_forward_nxt(Name,Port,Speed):- 142 | atom(Name)-> 143 | (atom(Port)-> 144 | (number(Speed)-> 145 | my_number_string(Speed,S), 146 | join_str('0',Port,'-',R1), 147 | join_str(R1,S,'-',R2), 148 | write_nxt(Name,R2),!; 149 | write('Error: in Speed, must be number'),nl,abort); 150 | write('Error: in Port,must be atom A,B,C'),nl,abort); %%%%%%%%%% Atom to string 151 | write('Error: in connection specifier '),nl,abort. 152 | 153 | %To Move forward with two ports at a time 154 | move_forward_nxt(Name,Port1,Port2,Speed):- 155 | move_forward_nxt(Name,Port1,Speed), 156 | move_forward_nxt(Name,Port2,Speed),!. 157 | 158 | %To move the nxt in backward direction 159 | move_backward_nxt(Name,Port,Speed):- 160 | atom(Name)-> 161 | (atom(Port)-> 162 | (number(Speed)-> 163 | my_number_string(Speed,S), 164 | join_str('1',Port,'-',R1), 165 | join_str(R1,S,'-',R2), 166 | write_nxt(Name,R2),!; 167 | write('Error: in Speed, must be number'),nl,abort); 168 | write('Error: in Port,must be atom A,B,C'),nl,abort); 169 | write('Error: in connection specifier '),nl,abort. 170 | 171 | %Move backward with two ports at a time 172 | move_backward_nxt(Name,Port1,Port2,Speed):-move_backward_nxt(Name,Port1,Speed), 173 | move_backward_nxt(Name,Port2,Speed),!. 174 | 175 | %To float the nxt to stop 176 | flt_nxt(Name,Port):-atom(Name)-> 177 | ( 178 | atom(Port)->join_str('2',Port,'-',R1),write_nxt(Name,R1),!; 179 | write('Error: in Port,must be atom A,B,C'),nl,abort 180 | ); 181 | write('Error: in connection specifier '),nl,abort. 182 | 183 | %with two ports 184 | flt_nxt(Name,Port1,Port2):- 185 | flt_nxt(Name,Port1), 186 | flt_nxt(Name,Port2),!. 187 | 188 | %To Stop the nxt motor 189 | stop_nxt(Name,Port):- 190 | atom(Name)-> 191 | (atom(Port)-> 192 | join_str('3',Port,'-',R1), 193 | write_nxt(Name,R1),!; 194 | write('Error: in Port,must be atom A,B,C'),nl,abort); 195 | write('Error: in connection specifier '),nl,abort. 196 | 197 | 198 | %Two motors at a time 199 | stop_nxt(Name,Port1,Port2):- 200 | stop_nxt(Name,Port1), 201 | stop_nxt(Name,Port2),!. 202 | 203 | 204 | %To Rotate the nxt motor by some degrees in clockwise or anticlockwise direction 205 | rotate_nxt(Name,Port,Angle,Direction):- 206 | atom(Name)-> 207 | (atom(Port)-> 208 | (number(Angle)-> 209 | (atom(Direction)-> 210 | my_number_string(Angle,A), 211 | join_str('4',Port,'-',R0), 212 | join_str(R0,A,'-',R1), 213 | join_str(R1,Direction,'-',R2), 214 | write_nxt(Name,R2),!; 215 | write('Error: in Direction,must be atom A for anticlockwise and C for clockwise'),nl,abort); 216 | write('Error: in Angle,must be a number'),nl,abort); 217 | write('Error: in Port,must be atom A,B,C'),nl,abort); 218 | write('Error: in connection specifier '),nl,abort. 219 | 220 | %To rotate a Motor (not the robot itself) upto a certain angle 221 | rotateto_nxt(Name,Port,Angle,Sign):- 222 | atom(Name)-> 223 | (atom(Port)-> 224 | (number(Angle)-> 225 | (atom(Sign)-> 226 | my_number_string(Angle,A), 227 | join_str('61',Port,'-',R0), 228 | join_str(R0,A,'-',R1), 229 | join_str(R1,Sign,'-',R2), 230 | write_nxt(Name,R2),!; 231 | write('Error: in Direction,must be atom A for anticlockwise and C for clockwise'),nl,abort); 232 | write('Error: in Angle,must be a number'),nl,abort); 233 | write('Error: in Port, must be atom A,B,C'),nl,abort); 234 | write('Error: in connection specifier '),nl,abort. 235 | 236 | 237 | %To set the speed of a motor to a certain value 238 | set_motorspeed_nxt(Name,Port,Speed):- 239 | atom(Name)-> 240 | (atom(Port)-> 241 | (number(Speed)-> 242 | my_number_string(Speed,S), 243 | join_str('64',Port,'-',R1), 244 | join_str(R1,S,'-',R2), 245 | write_nxt(Name,R2),!; 246 | write('Error: in Speed, must be number'),nl,abort); 247 | write('Error: in Port, must be atom A,B,C'),nl,abort); 248 | write('Error: in connection specifier '),nl,abort. 249 | 250 | 251 | %To set the speed of two motors at a time 252 | set_motorspeed_nxt(Name,Port1,Port2,Speed1,Speed2):- 253 | set_motorspeed_nxt(Name,Port1,Speed1), 254 | set_motorspeed_nxt(Name,Port2,Speed2),!. 255 | 256 | %To set the acceleration of a motor to a certain value 257 | set_acceleration_nxt(Name,Port,Accel):- 258 | atom(Name)-> 259 | (atom(Port)-> 260 | (number(Accel)-> 261 | my_number_string(Accel,A), 262 | join_str('65',Port,'-',R1), 263 | join_str(R1,A,'-',R2), 264 | write_nxt(Name,R2),!; 265 | write('Error: in Acceleration, must be number'),nl,abort); 266 | write('Error: in Port, must be a atom A,B,C'),nl,abort); 267 | write('Error: in connection specifier '),nl,abort. 268 | 269 | %To set the acceleration of two motors at a time 270 | set_acceleration_nxt(Name,Port1,Port2,Accel1,Accel2):- 271 | set_acceleration_nxt(Name,Port1,Accel1), 272 | set_acceleration_nxt(Name,Port2,Accel2),!. 273 | 274 | %To reverse the direction of the motor movement 275 | reverse_nxt(Name,Port):- 276 | atom(Name)-> 277 | (atom(Port)-> 278 | join_str('5',Port,'-',R1), 279 | write_nxt(Name,R1),!; 280 | write('Error: in Port,must be atom A,B,C'),nl,abort); 281 | write('Error: in connection specifier '),nl,abort. 282 | 283 | %reversing two motors at a time 284 | reverse_nxt(Name,Port1,Port2):- 285 | reverse_nxt(Name,Port1), 286 | reverse_nxt(Name,Port2),!. 287 | 288 | %write on the LCD screen of the NXT 289 | write_lcd_nxt(Name,Corx,Cory,String):- 290 | atom(Name)-> 291 | (number(Corx)-> 292 | (number(Cory)-> 293 | (atom(String)-> 294 | my_number_string(Corx,X), 295 | my_number_string(Cory,Y), 296 | join_str('7',X,'-',R1), 297 | join_str(R1,Y,'-',R2), 298 | join_str(R2,String,'-',R3), 299 | write_nxt(Name,R3),!; 300 | write('Error: in Last argument, must be a atom'),nl,abort); 301 | write('Error: in Co-ordinate, must be a number'),nl,abort); 302 | write('Error: in Co-ordinate, must be a number'),nl,abort); 303 | write('Error: in connection specifier '),nl,abort. 304 | 305 | 306 | 307 | %Clear the LCD screen of the NXT 308 | clear_lcd_nxt(Name):- 309 | atom(Name)-> 310 | join_str('8','','-',R1), 311 | write_nxt(Name,R1),!; 312 | write('Error: in connection specifier '), 313 | nl,abort. 314 | 315 | %Make the NXT Wait for the time specified 316 | wait_nxt(Name,Time):- 317 | atom(Name)-> 318 | (number(Time)-> 319 | my_number_string(Time,T), 320 | join_str('10',T,'-',R1), 321 | write_nxt(Name,R1),!; 322 | write('Error: in Time, must be a number'),nl,abort); 323 | write('Error: in connection specifier '),nl,abort. 324 | 325 | %Execute a program on the NXT 326 | exec_nxt(Name,Program):- 327 | atom(Name)-> 328 | (atom(Program)-> 329 | join_str('11',Program,'-',R1), 330 | write_nxt(Name,R1),!; 331 | write('Error: in program name,must be a atom'),nl,abort); 332 | write('Error: in connection specifier '),nl,abort. 333 | 334 | %Delete a file (Program) present on the NXT 335 | del_nxt(Name,Program):- 336 | atom(Name)-> 337 | (atom(Program)-> 338 | join_str('13',Program,'-',R1), 339 | write_nxt(Name,R1),!; 340 | write('Error: in program name,must be a atom'),nl,abort); 341 | write('Error: in connection specifier '),nl,abort. 342 | 343 | %To check if a Program(File) is present on nxt or NOT 344 | exists_nxt(Name,Program,Res):- 345 | atom(Name)-> 346 | (atom(Program)-> 347 | join_str('12',Program,'-',R0), 348 | join_str('#',R0,'-',R1), 349 | write_nxt(Name,R1),nl, 350 | read_res_nxt(Name,Res),!; 351 | write('Error: in program name,must be a atom'),nl,abort); 352 | write('Error: in connection specifier '),nl,abort. 353 | 354 | %Download a program on to the NXT, File is filename and path if the location of the file 355 | download_nxt(Name,File,Path):- 356 | atom(Name)-> 357 | (atom(File)-> 358 | (atom(Path)-> 359 | join_str('14',File,'-',R0), 360 | join_str(R0,Path,'-',R1), 361 | write_nxt(Name,R1),!; 362 | write('Error: in Path'),nl,abort); 363 | write('Error: in file name'),nl,abort); 364 | write('Error: in connection specifier '),nl,abort. 365 | 366 | %To check if any response is coming from nxt or not 367 | check_res_nxt(Name,T):- 368 | read_nxt(Name,T)-> 369 | write('response'); 370 | write('no response'),!. 371 | 372 | %This Predicates waits until it reads a message from the Java server 373 | read_res_nxt(Name,T):- 374 | name_socket(Name,_,In,_Out), 375 | read(In,Rep), 376 | read_nxt(Rep,T)-> !; 377 | read_res_nxt(Name,T). 378 | 379 | %To check if a motor is moving or not 380 | ismoving_nxt(Name,Port,Res):- 381 | atom(Name)-> 382 | (atom(Port)-> 383 | join_str('6',Port,'-',R0), 384 | join_str('#',R0,'-',R1), 385 | write_nxt(Name,R1),nl, 386 | read_res_nxt(Name,R), 387 | my_number_string(Res,R),!; 388 | write('Error: in port, must be a atom A/B/C'),nl,abort); 389 | write('Error: in connection specifier '),nl,abort. 390 | 391 | %To check two motors at a time for movement 392 | ismoving_nxt(Name,Port1,Port2,Res1,Res2):- 393 | ismoving_nxt(Name,Port1,Res1), 394 | ismoving_nxt(Name,Port2,Res2),!. 395 | 396 | %To get the mode of the motor movement on a port, The response is a numeric code 397 | getmode_nxt(Name,Port,Res):- 398 | atom(Name)-> 399 | (atom(Port)-> 400 | join_str('9',Port,'-',R0), 401 | join_str('#',R0,'-',R1), 402 | write_nxt(Name,R1),nl, 403 | read_res_nxt(Name,R), 404 | my_number_string(Res,R),!; 405 | write('Error: in port, must be a atom A/B/C'),nl,abort); 406 | write('Error: in connection specifier '),nl,abort. 407 | 408 | %To get the mode of movement of two motors at a time 409 | getmode_nxt(Name,Port1,Port2,Res1,Res2):- 410 | getmode_nxt(Name,Port1,Res1), 411 | getmode_nxt(Name,Port2,Res2),!. 412 | 413 | 414 | %To initialize a sensor in a sensor port 415 | init_light_nxt(Name,Port):- 416 | atom(Name)-> 417 | (number(Port)-> 418 | my_number_string(Port,P), 419 | join_str('20',P,'-',R1), 420 | write_nxt(Name,R1),!; 421 | write('Error: in port number,must be a number between 1 to 4'),nl,abort); 422 | write('Error: in connection specifier '),nl,abort. 423 | 424 | init_sound_nxt(Name,Port):- 425 | atom(Name)-> 426 | (number(Port)-> 427 | my_number_string(Port,P),join_str('21',P,'-',R1),write_nxt(Name,R1),!; 428 | write('Error: in port number,must be a number between 1 to 4'),nl,abort); 429 | write('Error: in connection specifier '),nl,abort. 430 | 431 | init_ultrasonic_nxt(Name,Port):- 432 | atom(Name)-> 433 | (number(Port)-> 434 | my_number_string(Port,P),join_str('22',P,'-',R1),write_nxt(Name,R1),!; 435 | write('Error: in port number,must be a number between 1 to 4'),nl,abort); 436 | write('Error: in connection specifier '),nl,abort. 437 | 438 | init_touch_nxt(Name,Port):- 439 | atom(Name)-> 440 | (number(Port)-> 441 | my_number_string(Port,P),join_str('23',P,'-',R1),write_nxt(Name,R1),!; 442 | write('Error: in port number,must be a number between 1 to 4'),nl,abort); 443 | write('Error: in connection specifier '),nl,abort. 444 | 445 | init_color_nxt(Name,Port):- 446 | atom(Name)-> 447 | (number(Port)-> 448 | my_number_string(Port,P),join_str('48',P,'-',R1),write_nxt(Name,R1),!; 449 | write('Error: in port number,must be a number between 1 to 4'),nl,abort); 450 | write('Error: in connection specifier '),nl,abort. 451 | 452 | init_compass_nxt(Name,Port):- 453 | atom(Name)-> 454 | (number(Port)-> 455 | my_number_string(Port,P),join_str('49',P,'-',R1),write_nxt(Name,R1),!; 456 | write('Error: in port number,must be a number between 1 to 4'),nl,abort); 457 | write('Error: in connection specifier '),nl,abort. 458 | 459 | init_gyro_nxt(Name,Port):- 460 | atom(Name)-> 461 | (number(Port)-> 462 | my_number_string(Port,P),join_str('50',P,'-',R1),write_nxt(Name,R1),!; 463 | write('Error: in port number,must be a number between 1 to 4'),nl,abort); 464 | write('Error: in connection specifier '),nl,abort. 465 | 466 | init_irseeker_nxt(Name,Port):- 467 | atom(Name)-> 468 | (number(Port)-> 469 | my_number_string(Port,P),join_str('54',P,'-',R1),write_nxt(Name,R1),!; 470 | write('Error: in port number,must be a number between 1 to 4'),nl,abort); 471 | write('Error: in connection specifier '),nl,abort. 472 | 473 | init_accel_nxt(Name,Port):- 474 | atom(Name)-> 475 | (number(Port)-> 476 | my_number_string(Port,P), 477 | join_str('59',P,'-',R1), 478 | write_nxt(Name,R1),!; 479 | write('Error: in port number,must be a number between 1 to 4'),nl,abort); 480 | write('Error: in connection specifier '),nl,abort. 481 | 482 | 483 | 484 | %To initialize a multiple light sensor 485 | init_light_nxt(Name,Port1,Port2):- 486 | init_light_nxt(Name,Port1), 487 | init_light_nxt(Name,Port2),!. 488 | 489 | init_light_nxt(Name,Port1,Port2,Port3):- 490 | init_light_nxt(Name,Port1), 491 | init_light_nxt(Name,Port2), 492 | init_light_nxt(Name,Port3),!. 493 | 494 | init_light_nxt(Name,Port1,Port2,Port3,Port4):- 495 | init_light_nxt(Name,Port1), 496 | init_light_nxt(Name,Port2), 497 | init_light_nxt(Name,Port3), 498 | init_light_nxt(Name,Port4),!. 499 | 500 | %To initialize a multiple sound sensor 501 | init_sound_nxt(Name,Port1,Port2):- 502 | init_sound_nxt(Name,Port1), 503 | init_sound_nxt(Name,Port2),!. 504 | 505 | init_sound_nxt(Name,Port1,Port2,Port3):- 506 | init_sound_nxt(Name,Port1), 507 | init_sound_nxt(Name,Port2), 508 | init_sound_nxt(Name,Port3),!. 509 | 510 | init_sound_nxt(Name,Port1,Port2,Port3,Port4):- 511 | init_sound_nxt(Name,Port1), 512 | init_sound_nxt(Name,Port2), 513 | init_sound_nxt(Name,Port3), 514 | init_sound_nxt(Name,Port4),!. 515 | 516 | %To initialize a multiple ultrasonic sensor 517 | init_ultrasonic_nxt(Name,Port1,Port2):- 518 | init_ultrasonic_nxt(Name,Port1), 519 | init_ultrasonic_nxt(Name,Port2),!. 520 | 521 | init_ultrasonic_nxt(Name,Port1,Port2,Port3):- 522 | init_ultrasonic_nxt(Name,Port1), 523 | init_ultrasonic_nxt(Name,Port2), 524 | init_ultrasonic_nxt(Name,Port3),!. 525 | 526 | init_ultrasonic_nxt(Name,Port1,Port2,Port3,Port4):- 527 | init_ultrasonic_nxt(Name,Port1), 528 | init_ultrasonic_nxt(Name,Port2), 529 | init_ultrasonic_nxt(Name,Port3), 530 | init_ultrasonic_nxt(Name,Port4),!. 531 | 532 | %To initialize a multiple touch sensor 533 | init_touch_nxt(Name,Port1,Port2):- 534 | init_touch_nxt(Name,Port1), 535 | init_touch_nxt(Name,Port2),!. 536 | 537 | init_touch_nxt(Name,Port1,Port2,Port3):- 538 | init_touch_nxt(Name,Port1), 539 | init_touch_nxt(Name,Port2), 540 | init_touch_nxt(Name,Port3),!. 541 | 542 | init_touch_nxt(Name,Port1,Port2,Port3,Port4):- 543 | init_touch_nxt(Name,Port1), 544 | init_touch_nxt(Name,Port2), 545 | init_touch_nxt(Name,Port3), 546 | init_touch_nxt(Name,Port4),!. 547 | 548 | %To set the flood light of light sensor On or Off; State is On or Off 549 | floodlight_nxt(Name,Port,State):- 550 | atom(Name)-> 551 | (number(Port)-> 552 | my_number_string(Port,P), 553 | join_str('29',P,'-',R0), 554 | join_str(R0,State,'-',R1), 555 | write_nxt(Name,R1),!; 556 | write('Error: in port number,must be a number between 1 to 4'),nl,abort); 557 | write('Error: in connection specifier '),nl,abort. 558 | 559 | %To read sensors at specified ports 560 | read_light_nxt(Name,Port,Res):- 561 | atom(Name)-> 562 | (number(Port)-> 563 | my_number_string(Port,P),join_str('24',P,'-',R0),join_str('#',R0,'-',R1), 564 | write_nxt(Name,R1),read_res_nxt(Name,R),my_number_string(Res,R),!; 565 | write('Error: in port number,must be a number between 1 to 4'),nl,abort); 566 | write('Error: in connection specifier '),nl,abort. 567 | 568 | 569 | read_ultrasonic_nxt(Name,Port,Res):- 570 | atom(Name)-> 571 | (number(Port)-> 572 | my_number_string(Port,P),join_str('26',P,'-',R0),join_str('#',R0,'-',R1), 573 | write_nxt(Name,R1),read_res_nxt(Name,R),my_number_string(Res,R),!; 574 | write('Error: in port number,must be a number between 1 to 4'),nl,abort); 575 | write('Error: in connection specifier '),nl,abort. 576 | 577 | 578 | read_sound_nxt(Name,Port,Res):- 579 | atom(Name)-> 580 | (number(Port)-> 581 | my_number_string(Port,P),join_str('25',P,'-',R0),join_str('#',R0,'-',R1), 582 | write_nxt(Name,R1),read_res_nxt(Name,R),my_number_string(Res,R),!; 583 | write('Error: in port number,must be a number between 1 to 4'),nl,abort); 584 | write('Error: in connection specifier '),nl,abort. 585 | 586 | 587 | read_touch_nxt(Name,Port,Res):- 588 | atom(Name)-> 589 | (number(Port)-> 590 | my_number_string(Port,P),join_str('27',P,'-',R0),join_str('#',R0,'-',R1), 591 | write_nxt(Name,R1),read_res_nxt(Name,R),my_number_string(Res,R),!; 592 | write('Error: in port number,must be a number between 1 to 4'),nl,abort); 593 | write('Error: in connection specifier '),nl,abort. 594 | 595 | 596 | read_color_nxt(Name,Port,Res):- 597 | atom(Name)-> 598 | (number(Port)-> 599 | my_number_string(Port,P),join_str('51',P,'-',R0),join_str('#',R0,'-',R1), 600 | write_nxt(Name,R1),read_res_nxt(Name,R),my_number_string(Res,R),!; 601 | write('Error: in port number,must be a number between 1 to 4'),nl,abort); 602 | write('Error: in connection specifier '),nl,abort. 603 | 604 | 605 | read_compass_nxt(Name,Port,Res):- 606 | atom(Name)-> 607 | (number(Port)-> 608 | my_number_string(Port,P),join_str('52',P,'-',R0),join_str('#',R0,'-',R1), 609 | write_nxt(Name,R1),read_res_nxt(Name,R),my_number_string(Res,R),!; 610 | write('Error: in port number,must be a number between 1 to 4'),nl,abort); 611 | write('Error: in connection specifier '),nl,abort. 612 | 613 | 614 | read_gyro_nxt(Name,Port,Res):- 615 | atom(Name)-> 616 | (number(Port)-> 617 | my_number_string(Port,P),join_str('53',P,'-',R0),join_str('#',R0,'-',R1), 618 | write_nxt(Name,R1),read_res_nxt(Name,R),my_number_string(Res,R),!; 619 | write('Error: in port number,must be a number between 1 to 4'),nl,abort); 620 | write('Error: in connection specifier '),nl,abort. 621 | 622 | 623 | read_irseeker_nxt(Name,Port,Res):- 624 | atom(Name)-> 625 | (number(Port)-> 626 | my_number_string(Port,P),join_str('55',P,'-',R0),join_str('#',R0,'-',R1), 627 | write_nxt(Name,R1),read_res_nxt(Name,R),my_number_string(Res,R),!; 628 | write('Error: in port number,must be a number between 1 to 4'),nl,abort); 629 | write('Error: in connection specifier '),nl,abort. 630 | 631 | 632 | read_accel_nxt(Name,Port,Res1,Res2,Res3):- 633 | atom(Name)-> 634 | (number(Port)-> 635 | my_number_string(Port,P),join_str('60',P,'-',R0),join_str('#',R0,'-',R1), 636 | write_nxt(Name,R1),read_res_nxt(Name,R),my_number_string(Res1,R), 637 | read_res_nxt(Name,R),my_number_string(Res2,R), 638 | read_res_nxt(Name,R),my_number_string(Res3,R),!; 639 | write('Error: in port number,must be a number between 1 to 4'),nl,abort); 640 | write('Error: in connection specifier '),nl,abort. 641 | 642 | 643 | 644 | read_sensorport_nxt(Name,Port,Res):- 645 | atom(Name)-> 646 | (number(Port)-> 647 | my_number_string(Port,P),join_str('28',P,'-',R0),join_str('#',R0,'-',R1), 648 | write_nxt(Name,R1),read_res_nxt(Name,R),my_number_string(Res,R),!; 649 | write('Error: in port number,must be a number between 1 to 4'),nl,abort); 650 | write('Error: in connection specifier '),nl,abort. 651 | 652 | 653 | %To Calibrate Compass Sensor 654 | start_compasscalibration_nxt(Name,Port):- 655 | atom(Name)-> 656 | (number(Port)-> 657 | my_number_string(Port,P),join_str('56',P,'-',R1),write_nxt(Name,R1),!; 658 | write('Error: in port number,must be a number between 1 to 4'),nl,abort); 659 | write('Error: in connection specifier '),nl,abort. 660 | 661 | stop_compasscalibration_nxt(Name,Port):- 662 | atom(Name)-> 663 | (number(Port)-> 664 | my_number_string(Port,P),join_str('57',P,'-',R1),write_nxt(Name,R1),!; 665 | write('Error: in port number,must be a number between 1 to 4'),nl,abort); 666 | write('Error: in connection specifier '),nl,abort. 667 | 668 | %To set Offset for Gyro sensor 669 | set_gyroffset_nxt(Name,Port):- 670 | atom(Name)-> 671 | (number(Port)-> 672 | my_number_string(Port,P),join_str('58',P,'-',R1),write_nxt(Name,R1),!; 673 | write('Error: in port number,must be a number between 1 to 4'),nl,abort); 674 | write('Error: in connection specifier '),nl,abort. 675 | 676 | 677 | %To produce the beep sound in the NXT; Type can be 1, 2, 3 & 4. 678 | beep_nxt(Name,Type):- 679 | atom(Name)-> 680 | (number(Type)-> 681 | my_number_string(Type,T),join_str('30',T,'-',R1),write_nxt(Name,R1),!; 682 | write('Error: in beep type,must be a number between 1 to 4'),nl,abort); 683 | write('Error: in connection specifier '),nl,abort. 684 | 685 | 686 | 687 | %To read multiple sensors at a time 688 | read_light_nxt(Name,Port1,Port2,R1,R2):- 689 | read_light_nxt(Name,Port1,R1), 690 | read_light_nxt(Name,Port2,R2),!. 691 | 692 | read_sound_nxt(Name,Port1,Port2,R1,R2):- 693 | read_sound_nxt(Name,Port1,R1), 694 | read_sound_nxt(Name,Port2,R2),!. 695 | 696 | read_ultrasonic_nxt(Name,Port1,Port2,R1,R2):- 697 | read_ultrasonic_nxt(Name,Port1,R1), 698 | read_ultrasonic_nxt(Name,Port2,R2),!. 699 | 700 | read_touch_nxt(Name,Port1,Port2,R1,R2):- 701 | read_touch_nxt(Name,Port1,R1), 702 | read_touch_nxt(Name,Port2,R2),!. 703 | 704 | %get the files currently present on the NXT 705 | get_files_nxt(Name,Res):- 706 | atom(Name)-> 707 | join_str('47','Files','-',R0), 708 | join_str('#',R0,'-',R1), 709 | write_nxt(Name,R1),nl, 710 | read_res_nxt(Name,Res), 711 | write('Files on NXT : '), 712 | nl,write(Res),nl, 713 | write('**********************************************'),nl,!; 714 | write('Error: in connection specifier '),nl,abort. 715 | 716 | 717 | 718 | %for creating the .pc file. 719 | 720 | create_pc:- save_predicates( [read_nxt,setup_nxt,initialize_nxt,connect2_nxt,written_nxt,connect_nxt,write_nxt,close_nxt,join_str,move_forward_nxt,move_backward_nxt,flt_nxt,stop_nxt,rotate_nxt,reverse_nxt,write_lcd_nxt,clear_lcd_nxt,wait_nxt,exec_nxt,del_nxt,exists_nxt,download_nxt,check_res_nxt,read_res_nxt,ismoving_nxt,getmode_nxt,init_light_nxt,init_sound_nxt,init_ultrasonic_nxt,init_touch_nxt,floodlight_nxt,read_light_nxt,read_ultrasonic_nxt,read_sound_nxt,read_touch_nxt,read_sensorport_nxt,beep_nxt,get_files_nxt,set_motorspeed_nxt,set_acceleration_nxt,rotateto_nxt,init_color_nxt,read_color_nxt,init_compass_nxt,read_compass_nxt,init_gyro_nxt,read_gyro_nxt,init_irseeker_nxt,read_irseeker_nxt,init_accel_nxt,start_compasscalibration_nxt,stop_compasscalibration_nxt],nxt_interface ). 721 | -------------------------------------------------------------------------------- /Archives/platform_pi_oct2017.pl: -------------------------------------------------------------------------------- 1 | %--------------------------------------------------------------------------- 2 | %--------------------------------------------------------------------------- 3 | /* 4 | Copyright (C) 2017 Robotics Lab., Dept. of Computer Science and Engg., Indian Institute of Technology Guwahati 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | 19 | */ 20 | % Indian Institute of Technology Guwahati Assam, India 781039 21 | % Vivek Singh, Manoj Bode, Tushar Semwal 22 | % manojbode@gmail.com 23 | % semwaltushar@gmail.com 24 | % 28-01-2017 25 | % Tartarus: A Multi-Agent Platform 26 | % 27 | %--------------------------------------------------------------------------- 28 | 29 | %--------------------------instructions----------------------------- 30 | % + means input parameter 31 | % - means output parameter 32 | % ? means it could be input or output 33 | % # means optional parameter 34 | %------------------------------------------------------ 35 | 36 | %%------------Ubuntu-----------------%% 37 | 38 | :- use_module(library(socket)). %% using TCP/IP connection 39 | 40 | 41 | % store the socket id of platform 42 | :-dynamic platform_socket_Tartarus_IITG/1. 43 | :-dynamic create_static_agent/3. 44 | :-dynamic platform_state/1. 45 | :-dynamic clean_static_agent/1. 46 | :-dynamic server_Ip/1. 47 | :-dynamic server_Port/1. 48 | :-dynamic temp_list3/2. 49 | :-dynamic temp_list2/2. 50 | 51 | % default values of Ip and port 52 | platform_socket_Tartarus_IITG(_). 53 | 54 | % fact which identifies the acknowledge received from other platforms 55 | % command_acknowledge_Tartarus_IITG have 1 variable which can be used to identify the sender information 56 | command_acknowledge_Tartarus_IITG(_). 57 | 58 | %-----------------------------------------Platform----------------------------------------------- 59 | 60 | % platform is created at input Ip address and port number it removes port number already in use 61 | % and removes old ip address in system asserts new ip address and port number 62 | % creates a global queue to store the messages received from other platforms or itself 63 | % creates a mutex for sending messages in atomic way 64 | 65 | %------------------------------------------------------------------------------------------------- 66 | 67 | 68 | make_platform_Tartarus_IITG(Ip,Port) :- %% create platform at +port +Ip 69 | (platform_state(on)-> %% To verify 70 | nl,write(' Platform already created '),nl 71 | ; 72 | create_socket_Tartarus_IITG(Port, Socket), %% create socket 73 | retractall(platform_socket_Tartarus_IITG(_)), %% retract all values of platform socket id 74 | assert(platform_socket_Tartarus_IITG(Socket)), %% assert new value of socket id 75 | tcp_setopt(Socket,reuseaddr), %% enable tcp to reuse same address, seting option for reusblility 76 | retractall(platform_port(_)), %% retract old port numbers 77 | retractall(platform_Ip(_)), %% retract old ip address of platform 78 | assert(platform_port(Port)), %% assert new port number of platform 79 | assert(platform_Ip(Ip)), %% assert new ip address of platform 80 | catch(( 81 | message_queue_create(clean_platform), 82 | message_queue_create(global_queue), %% global queue to store received messages from other platforms 83 | message_queue_create(client_queue), %% created a 'client_queue' to store all client connection 84 | message_queue_create(clean_agent_queue), 85 | mutex_create(message_queue_mutex), %% mutex to handle global_queue operation 86 | mutex_create(send_message_mutex)), %% mutex for handling message sending function 87 | Error,writeln(Error)), 88 | catch(thread_create(agent_clean(platform,(Ip,Port)),Cleanup_id, [detached(false)]),Error2,writeln(Error2)), 89 | catch(thread_create(worker_Tartarus_IITG(client_queue,Port), Worker_id,[detached(false)]),Error,writeln(Error)), %% workers process each message independently 90 | catch(thread_create(acceptor_Tartarus_IITG(Socket, client_queue),Acceptor_id, [detached(false)]),Error2,writeln(Error2)),!, %% acceptor_Tartarus_IITG thread to wait for incomming connections 91 | asserta(guid_threadid(t_clean,Cleanup_id)), 92 | asserta(guid_threadid(t_acceptor,Acceptor_id)), 93 | asserta(guid_threadid(t_worker,Worker_id)), 94 | retractall(platform_state(_)), 95 | assert(platform_state(on)), 96 | writeln('************************************************'), 97 | ansi_format([bold,fg(green)],'Welcome to Tartarus Multi-Agent Platform ~w.',[.]),nl, 98 | ansi_format([bold,fg(green)],'(Ver.1.1, 30th January 2017)~w',[.]),nl,nl, 99 | ansi_format([fg(blue)],'Copyrights 2017: Robotics Lab.,~w',[.]),nl, 100 | ansi_format([fg(blue)],'Dept. of Computer Science & Engg.,~w',[.]),nl, 101 | ansi_format([fg(blue)],'Indian Institute of Technology Guwahati,~w',[.]),nl,nl, 102 | ansi_format([fg(blue)],'For any query contact~w',[:]),nl, 103 | ansi_format([fg(blue)],'semwaltushar@gmail.~w',[com]),nl, 104 | ansi_format([fg(blue)],'sbnair.tartarus@gmail.~w',[com]),nl, 105 | ansi_format([fg(red)],'Note: Relevant manuals are available inside the User Manuals folder~w',[.]),nl, 106 | ansi_format([fg(red)],' of the installation directory of Tartarus.~w',[.]),nl, 107 | writeln('************************************************'), 108 | nl, 109 | write('==========================================='),nl, 110 | write(' Tartarus Platform launched!'),nl, 111 | write(' @ '),nl, 112 | write(' Running on IP = '),write(Ip),write(', '),write('Port = '),write(Port),nl, 113 | write('==========================================='),nl, 114 | nl). 115 | 116 | 117 | make_platform_Tartarus_IITG(_,_):- print_message(error,'make_platform_Tartarus_IITG(IP,Port) failed'),fail,!. 118 | 119 | 120 | 121 | % setup_Tartarus_IITG/0 sets up the dynamic clauses used later on 122 | % 1. database, execs are from old version of platform. Do not pay much attention to them 123 | % 2. platform_port holds the port on which the platform is running. Form : agent_port(port) 124 | % 3. agent_GUID holds the identifier, handler predicate and port information about all the agents running on the current platform. Form : agent_GUID(id,handler_predicate,Port) 125 | % 4. agent_payload holds the name of the predicates added to the agent as payload. Form : agent_payload(id, [(predicate1,arity1),(predicate2,arity2),...]) 126 | % 5. outgoing_agent holds the information about the outgoing agent (moving outside of the platform). The information is identifier 127 | % and the timestamp. This is later used for calculating hop times for outgoing agents. Form : outgoing_agent(id, Top, Res). Take a look at time/2 in WIN_REF.pdf 128 | % 6. hoptime_stat holds the hop time information. Holds the statistics. 129 | % 7. agent_token holds the list of token a agent has. Form : agent_token(id,[token list]) 130 | % 8. transit_GUID, transit_payload, transit_token and transit_code are same as agent_GUID,agent_payload .. respectively. 131 | % When agents are moving, then transit predicates are used to hold information till we are sure that the agent has reached its destination. 132 | 133 | setup_Tartarus_IITG:- 134 | (dynamic (database/1)), 135 | (dynamic (platform_port/1)), 136 | (dynamic (platform_Ip/1)), 137 | (dynamic (execs/1)), 138 | (dynamic (agent_GUID/3)), 139 | (dynamic (agent_payload/2)), 140 | (dynamic (outgoing_agent/3)), 141 | (dynamic (hoptime_stat/4)), 142 | (dynamic (agent_token/2)), 143 | (dynamic (platform_token/1)), 144 | (dynamic (transit_GUID/3)), 145 | (dynamic (transit_payload/2)), 146 | (dynamic (transit_token/2)), 147 | (dynamic (transit_code/2)), 148 | (dynamic (transfer_queue/1)), 149 | (dynamic (transit_agent/2)), 150 | (dynamic (start_agent/3)), 151 | (dynamic (code_base/2)), 152 | (dynamic (guid_threadid/2)), 153 | (dynamic (static_agent_details/5)). 154 | 155 | 156 | %----------------------------------------------------------------------- 157 | 158 | % Initialize the dynamic facts. 159 | 160 | do:- 161 | assert(database(assert((execs(X):-dynamic X)))). 162 | 163 | start_db:- 164 | setup_Tartarus_IITG,do. 165 | 166 | %----------------------------------------------------------------------- 167 | 168 | % start_tartarus/2 starts the agent platform at a port which can be specified by the user. It creates a platform agent, writes some output for 169 | % the user. It also hides some of the code, so that only the interface predicates are visible to the user and not the entire code. This is achieved by 170 | % hide_mycode/0. Hoptime statistics are set to 0, and port number is also stored.It calls the predicate make_platform_Tartarus_IITG for platform creation 171 | 172 | :-dynamic start_tartarus/1. 173 | 174 | start_tartarus(P):- 175 | start_tartarus(localhost,P). 176 | 177 | start_tartarus(Ip,Port):- 178 | start_db, 179 | make_platform_Tartarus_IITG(Ip,Port),nl, 180 | retractall(hoptime_stat(_,_,_,_)), 181 | assert(hoptime_stat(0,0,0,0)), 182 | retractall(transfer_queue(_)), 183 | assert(transfer_queue([])),ttyflush,!. 184 | 185 | start_tartarus(_Ip,_Port):- 186 | print_message(error,'start_tartarus(Ip,Port) failed, Please enter valid IP address and unused Port number'),fail. 187 | 188 | %---------------------------------------------------------------------- 189 | 190 | % close_tartarus/0 closes the platform agent, retracts the port information, kills all the agent that are running and retracts all the code 191 | % previously loaded by the platform using platform_assert_file. That code is stored in code_base. 192 | 193 | close_tartarus :- 194 | platform_state(on), 195 | forall(agent_GUID(GUID,_,_),agent_kill(GUID)), 196 | forall(code_base(_,FileCodeList),retract_code_Tartarus_IITG(FileCodeList)), 197 | retractall(code_base(_,_)), 198 | close_stream_pool, 199 | catch(forall(guid_threadid(_,ThreadID),( 200 | (thread_property(ThreadID,status(S)),S=running)-> 201 | thread_signal(ThreadID,thread_exit(_)),thread_join(ThreadID,_); 202 | (retractall(guid_threadid(_,ThreadID))) 203 | ) 204 | ),Error,writeln(Error)), 205 | 206 | catch(forall(static_agent_details(Port,_,_,_,_),clean_static_agent(Port)),Error,writeln(Error)), 207 | 208 | retractall(guid_threadid(_,_)), 209 | platform_socket_Tartarus_IITG(Socket), 210 | retractall(platform_socket_Tartarus_IITG(Socket)), %% retract current socket 211 | tcp_close_socket(Socket), 212 | write('socket is ':Socket), 213 | message_queue_destroy(global_queue), 214 | message_queue_destroy(client_queue), 215 | message_queue_destroy(clean_platform), 216 | message_queue_destroy(clean_agent_queue), 217 | mutex_destroy(message_queue_mutex), 218 | mutex_destroy(send_message_mutex), 219 | retractall(platform_port(_)), 220 | retractall(platform_Ip(_)), 221 | retractall(platform_state(_)), 222 | writeln('Platform has been closed'),nl,ttyflush,!. 223 | 224 | close_tartarus:- 225 | print_message(warning,'close_tartarus/0 failed!@! Check if Tartarus platform is already running.'). 226 | 227 | %---------------------------------------------------------------------- 228 | 229 | %%INTERFACE FUNCTION%% 230 | % reset_tartarus/0 closes and starts the platform at the same port 231 | :- dynamic reset_tartarus/0. 232 | 233 | reset_tartarus:- 234 | platform_reset. 235 | 236 | reset_tartarus:- 237 | print_message(warning,'reset_tartarus/0 failed!'). 238 | 239 | 240 | platform_reset:- 241 | handler(platform,(_,_),platform_restart). 242 | 243 | platform_reset:- 244 | print_message(warning,'platform_reset failed!'). 245 | 246 | %% Gives current platform IP address and port number 247 | get_tartarus_details(IP,Port):- 248 | get_platform_details(IP,Port). 249 | 250 | get_tartarus_details(_IP,_Port):- 251 | print_message(warning,'get_tartarus_details/2 failed!'). 252 | 253 | get_platform_details(Ip, Port):- 254 | platform_Ip(Ip), 255 | platform_port(Port). 256 | 257 | 258 | %---------------------------------------------------------------------- 259 | 260 | % set_token/1 sets the token of the current platform. Incoming agent having this token is allowed entry, others are denied entry. This 261 | % implements a security feature of the platform. However this is not complete and is just a prototype. *Need to finish security module* 262 | 263 | set_token(Token):- 264 | retractall(platform_token(_)),assert(platform_token(Token)). 265 | 266 | %---------------------------------------------------------------------- 267 | 268 | % platform_assert_file loads the content of the file into Prolog. Using consult etc are the same thing, but we need to keep track of 269 | % the code that has been asserted. Hence this function has been made. It uses file_to_list_Tartarus_IITG/2, assert_code_Tartarus_IITG/1 which are predicates defined 270 | % below in utilities. Its asserts a mapping of the code vs FILE to keep track of this code. This is used later for saving platform state. 271 | 272 | assert_file_to_tartarus(FILE):- 273 | platform_assert_file(FILE). 274 | 275 | assert_file_to_tartarus(_):- 276 | print_message(warning,'assert_file_to_tartarus/1 (FILE) failed!'). 277 | 278 | 279 | platform_assert_file(FILE):- 280 | file_to_list_Tartarus_IITG(FILE,L), 281 | assert_code_Tartarus_IITG(L), 282 | assert(code_base(FILE,L)). 283 | 284 | platform_assert_file(_FILE):- 285 | print_message(warning,'platform_assert_file(FILE) failed'). 286 | 287 | %----------------------------------------------------------------------- 288 | 289 | 290 | %==================================================% 291 | % Creating socket % 292 | %==================================================% 293 | 294 | create_socket_Tartarus_IITG(Port, Socket) :- %% create socket at port +Port -Socket 295 | tcp_socket(Socket), %% get socket value from tcp_socket inbuilt function 296 | catch(( 297 | tcp_bind(Socket, Port), %% bind socket to given port number 298 | tcp_listen(Socket, 5)), %% listen to Socket provided by socket 299 | Error,(tcp_close_socket(Socket),writeln(Error),fail)),!. 300 | 301 | %--------------------------------------------------- 302 | 303 | acceptor_Tartarus_IITG(Socket, Queue) :- %% predicate that will wait for client to connect +Socket +Queue 304 | tcp_accept(Socket, Client,From), %% accept the incomming -Client and Ip of connection -From is ip of incomming connection 305 | thread_send_message(Queue, connection([Client,From])), %% send the incomming connection properties to +Queue as 'connection' variable name 306 | !,acceptor_Tartarus_IITG(Socket, Queue). %% again wait for other connection after sending previous connection. 307 | 308 | 309 | %--------------------------------------------------- 310 | 311 | % worker_Tartarus_IITG is main scheduler , the commands posted on connection is handled in FCFS basis 312 | 313 | worker_Tartarus_IITG(Queue,Port):- %% Read connection one by one from queue +Queue and process their messages as input 314 | thread_get_message(Queue, connection([Client,From])), %% get top connection from +queue 315 | 316 | tcp_open_socket(Client, In, Out), %% bind socket with +client variable to get streams +In +Out 317 | %format('getting client connection ~q',[From,Client]),nl, %% Display msg 318 | read(In, Command), 319 | %% Read -Command from other platform from +In stream 320 | % thread_join(Thread,Status), %% check the -status of thread 321 | % Status, 322 | [_,Agent_name|_] = Command, 323 | Functor =.. Command, 324 | (agent_GUID(Agent_name,_,(_,Port))-> 325 | %catch(thread_create(execute_msg_Tartarus_IITG(Functor,Out,From),Thread,[]),Error,writeln(Error)) 326 | 327 | execute_msg_Tartarus_IITG(Functor,Out,From) 328 | ; 329 | ((Agent_name = platform; Agent_name= server)-> 330 | %catch(thread_create(execute_msg_Tartarus_IITG(Functor,Out,From),Thread,[]),Error,writeln(Error)); 331 | execute_msg_Tartarus_IITG(Functor,Out,From); 332 | format(Out,'~q.~n',[fail]), 333 | flush_output(Out))), 334 | close(In), %% close input buffer of socket 335 | close(Out), %% close ouput buffer of socket 336 | !,worker_Tartarus_IITG(Queue,Port). %% process other message 337 | 338 | 339 | %===========================================================% 340 | % Execute or process message received % 341 | %===========================================================% 342 | 343 | % Call the command as message and send acknowledge to sender platform as command_acknowledge_Tartarus_IITG function 344 | % if message is end_of_file in case of error still send acknowledge 345 | 346 | execute_msg_Tartarus_IITG(Command,Out,From) :- %% execute the message as command +Command +Out +Fro 347 | %join_threads, 348 | (Command = end_of_file-> 349 | (true,format(Out,'command_acknowledge_Tartarus_IITG(~q).~n',[From])); %% sending acknowledge in case of eof 350 | catch(thread_create(call(Command),_,[detached(true)]),Error,writeln(Error)), %% else create independent thread to process the +command/message 351 | format(Out,'command_acknowledge_Tartarus_IITG(~q).~n',[From]) %% send acknowledgment after thread creation 352 | ), 353 | %writeln('Ack sent successfully'), %% Display 354 | true,!. 355 | 356 | 357 | execute_msg_Tartarus_IITG(_Command,_Out,_From) :- 358 | print_message(warning,'execute_msg_Tartarus_IITG(Command,Out,From) failed'),!. 359 | 360 | % -------------------Message Sending Module--------------------- 361 | 362 | % Send messages to other platform/Agents as agent_post predicate we have to provide 363 | % receiver agent name , its ip address , its port number , sender agent name , function/command 364 | % here function is command/handlers of receiver agent which it have to execute 365 | :- dynamic post_agent/3. 366 | 367 | post_agent(platform,(Ip_receiver,Port_receiver),FunctionList):- 368 | agent_post(platform,(Ip_receiver,Port_receiver),FunctionList). 369 | 370 | agent_post(platform,(Ip_receiver,Port_receiver),FunctionList):- %% +Receiver_Agent +Ip_receiver +Port_receiver +Sender_agent +Function 371 | %repeat, %% Keep sending message until -Ack is received from other side 372 | catch(send_message(Ip_receiver,Port_receiver,FunctionList,Ack),Error,(writeln(Error),mutex_unlock(send_message_mutex),fail)), %% if present then send message 373 | (Ack-> %% -Ack is acknowlegde reciveied from other side should be true 374 | true; %% ack is command_acknowledge_Tartarus_IITG(_) predicate which is being received as true 375 | (sleep(1),fail) 376 | %true 377 | ),!. 378 | 379 | 380 | agent_post(_Platform,(_Ip_receiver,_Port_receiver),_FunctionList):- 381 | print_message(error,'post_agent(platform,(Ip_receiver,Port_receiver),FunctionList) failed'),fail,!. 382 | 383 | %-------------------------------------------------- 384 | 385 | % Independent predicate to send message without Sender agent name or port etc 386 | 387 | send_message(Host, Port,Message,Ack) :- %% Send Message to +Host/IP +Port +Message -Ack 388 | mutex_lock(send_message_mutex), %% Hold the lock while sending message 389 | setup_call_catcher_cleanup(tcp_socket(Socket), %% Get free -socket to send//recieve 390 | tcp_connect(Socket, Host:Port), %% Bind the socket to +Ip and +Port 391 | exception(_), %% Exception value is unused 392 | tcp_close_socket(Socket)),%% Close Socket 393 | setup_call_cleanup(tcp_open_socket(Socket, In, Out), 394 | chat_to_server_Tartarus_IITG(In, Out,Message,Ack), %% call predicate to send message//command 395 | close_connection_Tartarus_IITG(In, Out)), %% after sending message close In Out stream 396 | mutex_unlock(send_message_mutex). %% release mutex to be used by other functions 397 | 398 | 399 | %-------------------------------------------------- 400 | 401 | close_connection_Tartarus_IITG(In, Out) :- %% close the streams input and output at client +In +Out 402 | close(In, [force(true)]), 403 | close(Out, [force(true)]),!. 404 | 405 | 406 | %------------------------------------------------- 407 | 408 | chat_to_server_Tartarus_IITG(In, Out,Message,Ack) :- %% send messages to server with in out stream +In +Out +Message -Ack 409 | Term = Message, %% Assign +Message to term variable 410 | (Term = end_of_file %% If term = end_of_file then return 411 | -> true 412 | ; 413 | format(Out,'~q.~n',[Term]), %% if message is not null then write to +Out stream the +term and append new line character in the end 414 | flush_output(Out), 415 | read(In,Reply), %% wait to get the reply from other side i.e command_acknowledge_Tartarus_IITG(_) as message 416 | (call(Reply) %% call command_acknowledge_Tartarus_IITG(_) predicate 417 | ->Ack = true; %% if ack if valid the Ack is true else fail is returned 418 | Ack = fail 419 | ) 420 | %writeln('got message successfully') %% Display 421 | ),!. 422 | 423 | chat_to_server_Tartarus_IITG(_In, _Out,_Message,_Ack) :- 424 | print_message(warning,'chat_to_server_Tartarus_IITG(In, Out,Message,Ack) failed'),!. 425 | 426 | combine_Tartarus_IITG(Agent_name,Ip,Port,Agent_new_name):- %% predicate to combine_Tartarus_IITG +Agent_name , +Ip and +Port to get -Agent_new_name 427 | atom_concat(Agent_name,'_',A1), %% combine agent_name with '-' 428 | atom_concat(A1,Ip,A2), %% combine above result with Ip 429 | atom_concat(A2,'_',A3), %% combine above result with '-' 430 | atom_concat(A3,Port,Agent_new_name). %% combine above result with Port number 431 | 432 | 433 | %----------------------------------------------------------- 434 | 435 | get_new_name(Agent_name,Agent_new_name):- 436 | gensym(Agent_name,Agent_name2), %% generate a unique -agent_name2 from +agent_name 437 | platform_port(Port), %% check if the port is same as plaform port 438 | platform_Ip(Ip), %% check if the ip of platform is same as platform ip 439 | combine_Tartarus_IITG(Agent_name2,Ip,Port,Agent_new_name),!. %% generate new agent name by combining with its ip and port 440 | 441 | get_new_name(_Agent_name,_Agent_new_name):- 442 | print_message(warning,'get_new_name(Agent_name,Agent_new_name) failed'),!. 443 | 444 | 445 | %----------------------------------------------------------- 446 | 447 | get_new_name_alpha(Agent_name):- 448 | X1 is (random(26) + 97), 449 | X2 is (random(26) + 97), 450 | X3 is (random(26) + 97), 451 | X4 is (random(26) + 97), 452 | X5 is (random(26) + 97), 453 | X6 is (random(26) + 97), 454 | atom_codes(Agent_name,[X1,X2,X3,X4,X5,X6]). 455 | 456 | %--------------------------------------------- 457 | 458 | %======================================================% 459 | %= Static agent =% 460 | %======================================================% 461 | 462 | create_static_agent(Agent_name,(Platform_Ip,Port),Handler):- 463 | platform_state(on), 464 | platform_Ip(Platform_Ip), 465 | %platform_port(Platform_Port), 466 | create_socket_Tartarus_IITG(Port, Socket), 467 | atom_concat('client_queue_', Port, ClientQueue), 468 | message_queue_create(ClientQueue), 469 | catch(thread_create(worker_Tartarus_IITG(ClientQueue, Port), WorkerTr,[detached(false)]),Error,writeln(Error)), %% workers process each message independently 470 | catch(thread_create(acceptor_Tartarus_IITG(Socket, ClientQueue),AccepterTr, [detached(false)]),Error2,writeln(Error2)), %% acceptor_Tartarus_IITG thread to wait for incomming connections 471 | (var(Agent_name)-> 472 | get_new_name_alpha(Agent_name); 473 | true), 474 | ((atom(Agent_name),atom(Handler))->nothing;abort), 475 | (thread_peek_message(clean_agent_queue,agent_guid(Agent_name))-> 476 | cleanup_wait(Agent_name); 477 | %handler(platform,(Platform_Ip,Platform_Port),clean_agent(Agent_name)); 478 | true), 479 | (agent_GUID(Agent_name,_,(Platform_Ip,_))-> 480 | agent_kill(Agent_name); 481 | true), 482 | genhandler(Agent_name,Handler,Result), 483 | assert_code_Tartarus_IITG(Result), 484 | assert(agent_GUID(Agent_name,Handler,(Platform_Ip,Port))), 485 | assert(agent_payload(Agent_name,[])), 486 | assert(agent_token(Agent_name,[])), 487 | assert(static_agent_details(Port, ClientQueue, Socket, WorkerTr, AccepterTr)),!. 488 | 489 | clean_static_agent(Port):- 490 | retract(static_agent_details(Port, ClientQueue, Socket, WorkerTr, AccepterTr)), 491 | catch(((thread_property(WorkerTr,status(S)),S=running)-> 492 | thread_signal(WorkerTr,thread_exit(_)); 493 | writeln(WorkerTr)) 494 | ,Error,writeln(Error)), 495 | catch(((thread_property(AccepterTr,status(S)),S=running)-> 496 | thread_signal(AccepterTr,thread_exit(_)); 497 | writeln(AccepterTr)), 498 | Error,writeln(Error)), 499 | tcp_close_socket(Socket), 500 | message_queue_destroy(ClientQueue). 501 | 502 | 503 | %--------------default handler list------------------------------------ 504 | 505 | answer(Reciver_Agent_name,Sender_Agent_name,Data):- %% send answer from other agents to this agent 506 | mutex_lock(message_queue_mutex), %% hold the global_queue mutex 507 | thread_send_message(global_queue,answer(Reciver_Agent_name,Sender_Agent_name,Data)), %% send 'answer' variable in global_queue with arguments as Agent_name_sender,Data 508 | mutex_unlock(message_queue_mutex),!. %% unlock the global_queue mutex 509 | 510 | answer(_Reciver_Agent_name,_Sender_Agent_name,_Data):- 511 | print_message(warning,'answer(Reciver_Agent_name,Sender_Agent_name,Data) failed'),!. 512 | 513 | %----------------------------------------- 514 | 515 | % Any agent can get answer or wait for answer at platform by calling this method, data is the value sent by other agent. 516 | % The answer is stored in global answer queue from where it is extracted 517 | 518 | get_answer(Receiver_name,Sender_name,Data):- %% get the answer sent by sender agent to self agent 519 | repeat, %% loop untill answer is found 520 | writeln('Waiting for answer...'), 521 | (thread_peek_message(global_queue,answer(Receiver_name,Sender_name,Data))-> 522 | true; 523 | sleep(1), 524 | fail 525 | ), 526 | mutex_lock(message_queue_mutex), 527 | thread_get_message(global_queue,answer(Receiver_name,Sender_name,Data)), 528 | mutex_unlock(message_queue_mutex),ttyflush,!. 529 | 530 | get_answer(_Receiver_name,_Sender_name,_Data):- 531 | print_message(warning,'get_answer(Receiver_name,Sender_name,Data) failed'),!. 532 | 533 | 534 | :-dynamic temp_list4/1. 535 | temp_list4([]). 536 | 537 | add_element4(H,Old,[H|Old]). 538 | 539 | list_code4(H):- 540 | forall( 541 | clause(H,Code), 542 | ( 543 | term_to_atom(H,H2), 544 | term_to_atom(Code,Code2), 545 | atom_concat(H2,':-',H3), 546 | atom_concat(H3,Code2,Code3), 547 | atom_to_term(Code3,Code4,_), 548 | temp_list4(UserHandlerCode), 549 | add_element4(Code4,UserHandlerCode,Result), 550 | retractall(temp_list4(_)), 551 | assert(temp_list4(Result)) 552 | ) 553 | ). 554 | 555 | clauses(Head,List):- 556 | (list_code4(Head),temp_list4(List),retractall(temp_list4(_)),assert(temp_list4([]))). 557 | 558 | %---------------------------------------------------------------------------- 559 | 560 | member(H,[H|_]). 561 | member(H,[_|T]):- member(H,T). 562 | 563 | %------------------------------------------- 564 | 565 | % save_tartarus_state/1 saves all the code that has been loaded previously using platform_assert_file and 566 | % the agent code(its handler code and payload code) into a file. Its a kind of local backup. Can be loaded back into the system 567 | % The interface function loads up an event for the platform. The platform handler then handles the event. For the sake of readability, I have written 568 | % the handler code here instead of writing it later. {PS : the position of the code does not matter.} 569 | % Why event based? Because when you are saving a state, you open a file and push stuff into it. The problem occurs when other event occurs and interrupt. 570 | % These events may issue 'write' calls, which would go into our open stream. But having the entire process in a event handling (which is not interruptable) 571 | % gives you a sense of 'mutual exclusion'. 572 | 573 | 574 | % Intially it looks up at code_base to find out all the generic code, saves it to the file. Then for all the agents, captures the code 575 | % using assimilate_code and saves it. At the last, it stores the meta info such as what agent is linked to what code etc which it uses 576 | % later on to resume the state. Ex : agent_payload contains the names of all predicates linked to each agent. This needs to be fed back 577 | % when we resume from the 'saved state'. 578 | save_tartarus_state(FileName):- 579 | save_platform_state(FileName). 580 | 581 | save_tartarus_state(_FileName):- 582 | print_message(warning,'save_tartarus_state/1(FileName) failed!'). 583 | 584 | save_platform_state(FileName):- 585 | (atom(FileName)->nothing;abort), 586 | platform_Ip(Ip), 587 | platform_port(Port), 588 | agent_post(platform,(Ip,Port),[handler,platform,_,save_state(FileName)]),!. 589 | 590 | save_platform_state(_FileName):- 591 | print_message(warning,'save_platform_state(FileName) failed'). 592 | 593 | %------------------------------------------------------------------------------------------------ 594 | 595 | % load_tartarus_state/1 loads the state back. It loads the predicates, loads the agent code(their handler and payload) and starts the agents. 596 | % Basically, read the file, assert everything, and using the meta information, start the agents at their respective ports. Load the meta information 597 | % as well 598 | load_tartarus_state(FileName):- 599 | load_platform_state(FileName). 600 | 601 | load_tartarus_state(_):- 602 | print_message(warning,'load_tartarus_state/1(FileName) failed!'). 603 | 604 | load_platform_state(FileName):- 605 | (atom(FileName)->nothing;abort), 606 | platform_Ip(Ip), 607 | platform_port(Port), 608 | agent_post(platform,(Ip,Port),[handler,platform,_,load_state(FileName)]),!. 609 | 610 | load_platform_state(_FileName):- 611 | print_message(warning,'load_platform_state(FileName) failed'). 612 | 613 | 614 | %==================================================== Agent predicates =============================================================== 615 | 616 | % agent_create/3 creates a agent. It uses agent_create/3 of Chimera to create an agent. A unique 8character GUID is generated using gensym 617 | % and handler code for the agent is generated and asserted. Assume that abc123 is the name of the agent, then agent_create(abc123,user_handler,Port) is 618 | % invoked. 619 | % The handler code provided by user is ' user_handler(guid,Link,Event):- .. '. Instead a handler code of the form ' user_handler(abc123,Link,Event):- ..' 620 | % is asserted where abc123 is the actual name of the agent. So when the Event is posted on the agent, then since 621 | % its name is abc123, only that agent carries the task and no other. Refer to 'how it works.pdf' 622 | 623 | %====================================================================================================================================== 624 | 625 | cleanup_wait(Agent_name):- 626 | (thread_peek_message(clean_agent_queue,agent_guid(Agent_name))-> 627 | sleep(1), 628 | !,cleanup_wait(Agent_name); 629 | true). 630 | 631 | %========================================================% 632 | % Create mobile agent % 633 | %========================================================% 634 | 635 | %agent_create/2 --> 636 | %Date:06 Nov. 2016 637 | %Added by Tushar: Usually mobile agents are created on current platform and hence unnecessary insertion of IP and Port 638 | 639 | :-dynamic create_mobile_agent/2. 640 | :-dynamic create_mobile_agent/3. 641 | 642 | create_mobile_agent(GUID,Handler):- agent_create(GUID,Handler). % -- to avoid confusion and for easy recalling, a new name is defined -- % 643 | 644 | create_mobile_agent(GUID,(Ip,Port),Handler):- agent_create(GUID,(Ip,Port),Handler). 645 | 646 | :-dynamic agent_create/2. 647 | 648 | agent_create(GUID,Handler):- 649 | get_platform_details(Ip,Port), 650 | agent_create(GUID,(Ip,Port),Handler). 651 | 652 | agent_create(GUID2,(Ip,Port),Handler):- 653 | platform_state(on), 654 | (var(GUID2)->get_new_name_alpha(GUID2);true), 655 | (platform_Ip(Ip)-> 656 | (platform_port(Port)-> 657 | true; 658 | fail) 659 | ; 660 | get_ip(Ip1), 661 | ((Ip1=Ip), (platform_port(Port))-> 662 | true; 663 | ((Ip = localhost), (platform_port(Port))-> 664 | true; 665 | fail))), 666 | ((atom(GUID2),atom(Handler))->nothing;abort), 667 | (thread_peek_message(clean_agent_queue,agent_guid(GUID2))-> 668 | %clean_agent(GUID2); 669 | %handler(platform,(Ip,Port),clean_agent(GUID2)); 670 | cleanup_wait(GUID2); 671 | true 672 | ), 673 | (agent_GUID(GUID2,_,(Ip,_))-> 674 | agent_kill(GUID2), 675 | is_exist(GUID2); 676 | true), 677 | genhandler(GUID2,Handler,Result), 678 | assert_code_Tartarus_IITG(Result), 679 | assert(agent_GUID(GUID2,Handler,(Ip,Port))), 680 | assert(agent_payload(GUID2,[])), 681 | assert(agent_token(GUID2,[])), 682 | format(atom(Str),'Agent with name ~w created',[GUID2]), 683 | nl,writeln(Str),!. 684 | 685 | 686 | agent_create(GUID,(Ip_other_end,Port_other_end),Handler):- 687 | platform_state(on), 688 | nl,write('Creating agent on platform with IP '),write(Ip_other_end),write(' and port number '),write(Port_other_end),nl, 689 | agent_post(platform,(Ip_other_end,Port_other_end),[agent_create,GUID,(Ip_other_end,Port_other_end),Handler]). 690 | 691 | 692 | agent_create(_GUID2,(_Ip,_Port),_Handler):- 693 | print_message(warning,'agent_create(GUID2,(Ip,Port),Handler) failed'). 694 | 695 | %========================================================% 696 | % Execute/run agent % 697 | %========================================================% 698 | %added by tushar 699 | %27 Jan 2016 700 | 701 | :-dynamic execute_agent/3. 702 | :-dynamic execute_agent/4. 703 | 704 | execute_agent(Agent_name,(Ip,Port),Handler):- agent_execute(Agent_name,(Ip,Port),Handler). % -- adding a simple name --% 705 | 706 | agent_execute(Agent_name,(Ip,Port),Handler):- %% create agent +Agent_name +Handler +Ip +Port 707 | (agent_GUID(Agent_name,Handler,(Ip,Port))-> 708 | Functor =.. [Handler,Agent_name,(Ip,Port),main], %% create Functor with handler as predicate name, and arguments as +Agent_new_name, +Ip, +Port 709 | writeln(Functor), 710 | catch(((guid_threadid(Agent_name,X),integer(X),thread_property(X,status(Y)),Y=running)-> 711 | guid_threadid(Agent_name,ThID), 712 | retractall(guid_threadid(Agent_name,X)), 713 | thread_signal(X,thread_exit(true)), 714 | thread_join(ThID,_), 715 | writeln('old agent thread stopped') 716 | ; 717 | (guid_threadid(Agent_name,ThID)-> 718 | retractall(guid_threadid(Agent_name,_)), 719 | thread_join(ThID,_); 720 | true) 721 | ), 722 | Error,writeln(Error)), 723 | 724 | catch(thread_create(call(Functor),ThreadID,[]),Error2,writeln(Error2)), %% call the main handler of agent which will start execution 725 | catch(thread_signal(ThreadID,sleep(0)),Error3,writeln(Error3)), 726 | asserta(guid_threadid(Agent_name,ThreadID)), 727 | 728 | ttyflush,!; 729 | print_message(error,'Agent name provided does not exist'),!). 730 | 731 | agent_execute(_Agent_name,(_Ip,_Port),_Handler):- 732 | print_message(warning,'execute_agent(Agent_name,(Ip,Port),Handler) failed!'),!. 733 | 734 | 735 | execute_agent(Agent_name,(Ip,Port),Handler,Start_function):- agent_execute(Agent_name,(Ip,Port),Handler,Start_function). % -- adding a simple name --% 736 | 737 | agent_execute(Agent_name,(Ip,Port),Handler,Start_function):- %% create agent +Agent_name +Handler +Ip +Port 738 | %writeln('-------agent_execute--------'), 739 | Functor =.. [Handler,Agent_name,(Ip,Port),Start_function], %% create Functor with handler as predicate name, and arguments as +Agent_new_name, +Ip, +Port 740 | writeln(Functor), 741 | catch(((guid_threadid(Agent_name,X),integer(X),thread_property(X,status(Y)),Y=running)-> 742 | (retractall(guid_threadid(Agent_name,X)),thread_signal(X,thread_exit(_)),writeln('old agent thread stopped')); 743 | (retractall(guid_threadid(Agent_name,_)))), 744 | Error,writeln(Error)), 745 | catch(thread_create(call(Functor),ThreadID,[]),Error2,writeln(Error2)), %% call the main handler of agent which will start execution 746 | catch(thread_signal(ThreadID,sleep(0.03)),Error3,writeln(Error3)), 747 | asserta(guid_threadid(Agent_name,ThreadID)), 748 | ttyflush,!. %% Display 749 | 750 | agent_execute(_Agent_name,(_Ip,_Port),_Handler,_Start_function):- 751 | print_message(warning,'execute_agent(Agent_name,(Ip,Port),Handler,Start_function) failed!'),!. 752 | 753 | 754 | 755 | %========================================================% 756 | % Agent post % 757 | %========================================================% 758 | 759 | agent_post(GUID,Event):- 760 | agent_GUID(GUID,_,(Ip,Port)), 761 | agent_post(platform,(Ip,Port),Event). 762 | 763 | 764 | %=======================================================% 765 | % Agent kill % 766 | %=======================================================% 767 | 768 | % agent_kill closes the agent using agent_close/3 of Chimera, retracts all the relevent code and deletes the meta 769 | % informations. assimilate_code/2 is used for gathering all the code, retract_code_Tartarus_IITG/1 retracts it. Other calls are mainly 770 | % to remove agent meta info about payloads and tokens. 771 | 772 | 773 | %added by tushar 774 | %27 Jan 2016 775 | 776 | :-dynamic purge_agent/1. % -- a sober naming convention (less gore than agent_kill/1!!) 777 | 778 | purge_agent(Guid):- agent_kill(Guid). 779 | 780 | 781 | 782 | agent_kill(GUID):- 783 | platform_Ip(Ip), 784 | platform_port(Port), 785 | (agent_GUID(GUID,_,(Ip,UsedPort))-> 786 | catch(thread_create(agent_kill_platform(platform,GUID),_,[detached(true)]),Error2,(writeln(Error2),fail)), 787 | (UsedPort=Port-> 788 | true; 789 | clean_static_agent(UsedPort)); 790 | true 791 | ),!. 792 | 793 | agent_kill(_GUID):- 794 | print_message(warning,'agent_kill(GUID) failed'). 795 | 796 | %-------------------------------------------------------------------------------------------- 797 | 798 | agent_kill_platform(platform,GUID):- 799 | %writeln('--------killing agent start----------'), 800 | (atom(GUID)->nothing;abort), 801 | catch((guid_threadid(GUID,X)-> 802 | ((integer(X),thread_property(X,status(Y)),Y=running)-> 803 | (retractall(guid_threadid(GUID,_)),thread_signal(X,thread_exit(true)),thread_join(X,_)); 804 | (retractall(guid_threadid(GUID,_)),thread_join(X,_))); 805 | true), 806 | Error,(write(Error),fail)), 807 | assimilate_code(GUID,AgentCode), 808 | retractall(agent_GUID(GUID,_Handler,(_Ip,_Port))), 809 | retractall(agent_payload(GUID,_PayloadList)), 810 | retractall(agent_token(GUID,_ListOfTokens)), 811 | retract_code_Tartarus_IITG(AgentCode), 812 | %writeln('--------killing agent end----------'), 813 | ttyflush, 814 | !. 815 | 816 | agent_kill_platform(platform, _GUID):- 817 | print_message(error, 'Agent kill failed'). 818 | 819 | %=============================================================================================% 820 | % Agent save % 821 | % % 822 | % agent_save/2 writes the agent information into a file. This is for possible usage later on. % 823 | % assmilate_code/2 for capturing the code, and then writing the code into the file. % 824 | %=============================================================================================% 825 | :- dynamic save_agent/2. 826 | 827 | save_agent(GUID,FileName):- 828 | agent_save(GUID,FileName). 829 | 830 | agent_save(GUID,FileName):- 831 | ((atom(GUID),atom(FileName))->nothing;abort), 832 | assimilate_code(GUID,Result), 833 | open(FileName,write,X), 834 | current_output(Y), 835 | set_output(X), 836 | forall( 837 | (member(Code,Result)), 838 | (with_output_to(atom(Data),portray_clause(Code)),write(Data)) 839 | ), 840 | set_output(Y),close(X),!. 841 | 842 | agent_save(_GUID,_FileName):- 843 | print_message(warning,'agent_save(GUID,FileName) failed'). 844 | 845 | %------------------------------------------------------------------------------- 846 | 847 | list([]):-false. 848 | list([_|_]):-true. 849 | 850 | %================================================================% 851 | % Add payload % 852 | %================================================================% 853 | 854 | % add_payload /2 adds the payload to the agent. To achieve this, it creates a unique copy of the payload. The payload predicate in its 855 | % parameter contains a term 'guid'[user_code]. Example : ability(guid,X):-print(X). So we replace the 'guid' with the actual identifier/name of the 856 | % agent. Now comes the question why? 857 | % Note that when I made the handler of the agent, i subsitituted all 'guid's by actual identifiers. So in the handler of a agent, if 858 | % user writes something like this : 859 | % myhandler(guid, Link, message(X)):-ability(guid,X). 860 | % Then instead of this handler, something like this is created and asserted [Assume abc123 is the identifier alloted by the system] 861 | % myhandler(abc123, Link, message(X)):- ability(abc123,X). 862 | % So when this agent is notified of the Event 'message(X)'; then 863 | % myhandler with abc123 as its first parameter is invoked. (DUE TO 864 | % CHIMERA) and so when adding ability as payload I create 865 | % ability(abc123,X):- print(X). as the payload, and assert it. THUS we 866 | % have a unique handler code, and unique payload code, their uniqueness 867 | % defined by identifier. 868 | 869 | add_payload(GUID,AddList):- 870 | ((atom(GUID),list(AddList))->nothing;abort), 871 | agent_payload(GUID,List), 872 | subtract(AddList,List,FinalList), 873 | generatePayloadCode(GUID,FinalList,PayloadCode), 874 | assert_code_Tartarus_IITG(PayloadCode), 875 | append(FinalList,List,NewList), 876 | retractall(agent_payload(GUID,List)), 877 | assert(agent_payload(GUID,NewList)),!. 878 | 879 | add_payload(_GUID,_AddList):- 880 | print_message(warning,'add_payload(GUID,AddList) failed'). 881 | 882 | 883 | %================================================================% 884 | % Remove payload % 885 | %================================================================% 886 | 887 | % remove_payload/2 captures the payload code that is specific to the agent. (having the identifier in defination instead of 'guid'). 888 | % After capturing the code, it retracts it. The predicate_header here creates payload_predicate(agent_name,_,_...) sort of header which 889 | % later is later used by clauses/2 to fetch the body of the payload. The permanent list of payload for that agent is edited finally. 890 | 891 | remove_payload(GUID,ToRemove):- 892 | ((atom(GUID),list(ToRemove))->nothing;abort), 893 | agent_payload(GUID,List), 894 | forall(( 895 | member((Predicate,Arity),ToRemove)), 896 | (predicate_header(GUID,Predicate,Arity,Result), 897 | (clauses(Result,Body)-> 898 | retract_code_Tartarus_IITG(Body); 899 | nothing) 900 | ) 901 | ), 902 | delete_list(ToRemove,List,NewList), 903 | retractall(agent_payload(GUID,List)), 904 | assert(agent_payload(GUID,NewList)),!. 905 | 906 | remove_payload(_GUID,_ToRemove):- 907 | print_message(warning,'remove_payload(GUID,ToRemove) failed'). 908 | 909 | %-------------------------------------------------------------------------------- 910 | 911 | % shed_payload/2 basically removes the payload from the agent and puts it in the platform. What ? Let's consider an example 912 | % ability(abc123,X):-write(abc123),write(X). The <- is payload attached to a agent named abc123. 913 | % If u shed, ability; the above code is retracted. And ability(guid,X):-write(guid),write(X) is asserted back. 914 | % This would be the original way the user might have written the ability predicate in his/her file. 915 | % ability is now again available to be attached to some other agent. 916 | 917 | shed_payload(GUID,ToShed):- 918 | ((atom(GUID),list(ToShed))->nothing;abort), 919 | copy_payload(GUID,ToShed), 920 | remove_payload(GUID,ToShed). 921 | 922 | %-------------------------------------------------------------------------------- 923 | 924 | % copy_payload copies the payload. Does not retract it. So the tyhphlet retains its payload while platform also gains the generic defination 925 | % of the payload. The rest of the predicates are pretty much similar and self explanatory 926 | 927 | copy_payload(GUID,ToCopy):- 928 | ((atom(GUID),list(ToCopy))->nothing;abort), 929 | forall(( 930 | member((Predicate,Arity),ToCopy)), 931 | ( 932 | generate_generic_predicate(GUID,Predicate,Arity,Result), %% Make generic defination 933 | assert_code_Tartarus_IITG(Result) 934 | ) 935 | ),!. 936 | %------------------------------------------------------------------------------- 937 | 938 | removeall_payload(GUID):- 939 | (atom(GUID)->nothing;abort), 940 | agent_payload(GUID,List), 941 | remove_payload(GUID,List). 942 | 943 | %-------------------------------------------------------------------------------- 944 | 945 | shedall_payload(GUID):- 946 | (atom(GUID)->nothing;abort), 947 | agent_payload(GUID,List), 948 | shed_payload(GUID,List). % !!!!!!!!!!!!!!!!!!!! CHECK if defination already exists ? 949 | 950 | %-------------------------------------------------------------------------------- 951 | 952 | copyall_payload(GUID):- 953 | (atom(GUID)->nothing;abort), 954 | agent_payload(GUID,List), 955 | copy_payload(GUID,List). 956 | 957 | %-------------------------------------------------------------------------------- 958 | 959 | %==========================================================================% 960 | % Add token % 961 | % % 962 | % add_token adds the a token ( presented as a list [token1,token2] ) with % 963 | % the agent. while remove_token removes token from the list. % 964 | %==========================================================================% 965 | 966 | add_token(GUID,List):- 967 | (list(List)->nothing;abort), 968 | agent_token(GUID,OldList), %% need to put error chceks here 969 | subtract(List,OldList,FinalList), %% Add token only if token already not added 970 | append(OldList,FinalList,NewList), %% // 971 | retractall(agent_token(GUID,OldList)), %% // 972 | assert(agent_token(GUID,NewList)),!. %% // 973 | 974 | add_token(_GUID,_List):- 975 | print_message(warning,'add_token(GUID,List) failed'). 976 | 977 | 978 | %==========================================================================% 979 | % Remove token % 980 | %==========================================================================% 981 | 982 | remove_token(GUID,ToRemove):- %% INTERFACE FUNCTION 983 | (list(List)->nothing;abort), %// 984 | agent_token(GUID,List), %// 985 | delete_list(ToRemove,List,NewList), %// 986 | retractall(agent_token(GUID,List)), %// 987 | assert(agent_token(GUID,NewList)),!. %// 988 | 989 | remove_token(_GUID,_ToRemove):- 990 | print_message(warning,'remove_token(GUID,ToRemove) failed'). 991 | 992 | 993 | %%=====================================================MOBILITY=============================================================================%% 994 | % % 995 | % Agent clone % 996 | % % 997 | % Cloning means creating a copy of the agent at a 'remote' location. Of course, that's the usual way of doing things. % 998 | % {{Future}} feature note for developer : make a agent_clone/1 ..for making a clone and starting it here and not somewhere else. % 999 | % Would that be a better feature than this ? .. But again the same can be achieved by doing agent_clone(xyz,[]).. try this my man ! % 1000 | % % 1001 | % agent_clone creates a new identifier first for the copy of the agent. Then all the code of agent is assimilated and all the places, % 1002 | % where ID1 is written, it is replaced by ID2. Then you send the code to the target destination. The code includes both, Handler code, % 1003 | % and payload code. To calculate time taken for the HOP, a timestamp is saved by time(Top,Res) and it is saved with outgoing_agent/3. % 1004 | % Later on when the clone reaches the destination, an ack is sent which is used to calculate the time taken for hop.[more on hop time later] % 1005 | %%==========================================================================================================================================%% 1006 | 1007 | :- dynamic clone_agent/3. 1008 | 1009 | clone_agent(GUID1,(Send_Ip,Send_Port),GUID2):- 1010 | agent_clone(GUID1,(Send_Ip,Send_Port),GUID2). 1011 | 1012 | agent_clone(GUID1,(Send_Ip,Send_Port),GUID2):- 1013 | ((atom(GUID1),integer(Send_Port))->nothing;abort), 1014 | gensym(GUID1,GUID2), 1015 | get_time(TT), %%time in seconds from begining of os 1016 | assert(outgoing_agent(GUID2,TT,_)), 1017 | assimilate_code(GUID1,AgentCode), 1018 | replaceGUID(AgentCode,GUID1,GUID2,CloneCode), 1019 | agent_payload(GUID1,PayloadList), 1020 | agent_GUID(GUID1,Handler,_), 1021 | agent_token(GUID1,ListOfTokens), 1022 | list_to_set(ListOfTokens,ListOfTokens2), 1023 | agent_post(platform,(Send_Ip,Send_Port),[handler,platform,(Send_Ip,Send_Port),send(GUID2,Handler,PayloadList,CloneCode,ListOfTokens2,TT)]),!. 1024 | 1025 | agent_clone(GUID1,(_Ip,_Port),_):- 1026 | print_message(error,'Clone agent Failed for: '),write(GUID1),nl. 1027 | 1028 | 1029 | %=============================================================% 1030 | % Move agent % 1031 | %=============================================================% 1032 | 1033 | % agent_move is just assmilating the code, and sending it to the destination. The code is retracted after sending it. 1034 | % The code however is not discarded right away. It is stored as a temporary. This is because if a negative ack comes from the recieving platform 1035 | % the code, would be activated once again, and the agent would be started again. 1036 | :- dynamic move_agent/2. 1037 | 1038 | move_agent(GUID,(Ip_other_end,Port_other_end)):- 1039 | agent_move(GUID,(Ip_other_end,Port_other_end)). 1040 | 1041 | agent_move(GUID,(Ip_other_end,Port_other_end)):- 1042 | platform_Ip(Ip1), 1043 | get_ip(Ip), 1044 | platform_port(Port), 1045 | 1046 | ((Ip = Ip_other_end,Port = Port_other_end)->writeln('Agent is already on same platform.'),abort;true), 1047 | ((Ip1 = Ip_other_end,Port = Port_other_end)->writeln('Agent is already on same platform.'),abort;true), 1048 | ((Ip_other_end=localhost,Port = Port_other_end)->writeln('Agent is already on same platform.'),abort;true), 1049 | 1050 | ((atom(GUID),integer(Port_other_end))->nothing;abort), 1051 | 1052 | assimilate_code(GUID,AgentCode), 1053 | agent_payload(GUID,PayloadList), 1054 | agent_GUID(GUID,Handler,(Ip1,Port)), 1055 | agent_token(GUID,ListOfTokens), 1056 | list_to_set(ListOfTokens,ListOfTokens2), 1057 | get_time(TT), 1058 | assertz(outgoing_agent(GUID,TT,_)), 1059 | (agent_post(platform,(Ip_other_end,Port_other_end),[handler,platform,(Ip,Port),send(GUID,Handler,PayloadList,AgentCode,ListOfTokens2,TT)])-> 1060 | (thread_peek_message(clean_agent_queue,agent_guid(GUID))->thread_get_message(clean_agent_queue,agent_guid(GUID));true), 1061 | thread_send_message(clean_agent_queue,agent_guid(GUID)), 1062 | thread_send_message(clean_platform,agent_guid(GUID)) 1063 | %Functor=.. [handler,platform,(Ip,Port),clean_agent(GUID)], 1064 | %catch(thread_create(call(Functor),_,[detached(true)]),Error,writeln(Error)) 1065 | ; 1066 | retractall(outgoing_agent(GUID,_,_))). 1067 | %agent_post(platform,(Ip,Port),[handler,platform,(Ip,Port),clean_agent(GUID)]). 1068 | 1069 | 1070 | agent_move(GUID,(_Ip,_Port)):- print_message(error,'Move agent Failed for ':GUID),nl. 1071 | 1072 | 1073 | %==========================================================% 1074 | % Agent list % 1075 | %==========================================================% 1076 | 1077 | :- dynamic list_agent/0. 1078 | 1079 | 1080 | list_agent:- 1081 | agent_list. 1082 | 1083 | agent_list:- 1084 | writeln('================Agent list==============='), 1085 | forall(agent_GUID(GUID,Handler,(_IP,Port)),( 1086 | write('Agent Name ':GUID),write(', handler name':Handler),write(', residing on port':Port),nl)), 1087 | writeln('========================================='). 1088 | 1089 | :- dynamic list_agent/1. 1090 | 1091 | list_agent(R):- 1092 | agent_list(R). 1093 | 1094 | agent_list(ResultList):- 1095 | get_time(TT), 1096 | assert(temp_agent_list(TT,[])), 1097 | forall(agent_GUID(GUID,Handler,(_IP,Port)),( 1098 | retract(temp_agent_list(TT,List)), 1099 | NewList = [(GUID,Handler,Port)|List], 1100 | assert(temp_agent_list(TT,NewList)))), 1101 | retract(temp_agent_list(TT,ResultList)). 1102 | 1103 | 1104 | :- dynamic isexist_agent/3. 1105 | 1106 | isexist_agent(GUID,(IP,Port),Handler):- 1107 | agent_isexist(GUID,(IP,Port),Handler). 1108 | 1109 | 1110 | agent_isexist(GUID,(IP,Port),Handler):- 1111 | (agent_GUID(GUID,Handler,(IP,Port))-> 1112 | %write('Agent ':GUID),write(' with handler':Handler),write(' exists on port ':Port) 1113 | true;fail). 1114 | 1115 | 1116 | %Added by Tushar 07 NOV 2015 1117 | %agent_list_new/1 returns list of GUIDs of currently present agents on a running platform 1118 | :-dynamic agent_list_new/1. 1119 | agent_list_new(AgentList):- 1120 | get_time(TT), 1121 | assert(temp_agent_list(TT,[])), 1122 | forall(agent_GUID(GUID,_,(_IP,_)),( 1123 | retract(temp_agent_list(TT,List)), 1124 | NewList = [GUID|List], 1125 | assert(temp_agent_list(TT,NewList)))), 1126 | retract(temp_agent_list(TT,AgentList)). 1127 | 1128 | 1129 | %===========================================================================% 1130 | % New Clean code with separate thread % 1131 | %===========================================================================% 1132 | 1133 | agent_clean(platform,(Ip,Port)):- 1134 | ttyflush, 1135 | %writeln('-----------cleaning start----------':GUID), 1136 | thread_get_message(clean_platform, agent_guid(GUID)), 1137 | (thread_peek_message(clean_agent_queue,agent_guid(GUID))-> 1138 | (catch((guid_threadid(GUID,X)-> 1139 | ((integer(X),thread_property(X,status(Y)),Y=running)-> 1140 | (thread_signal(X,thread_exit(true)),retractall(guid_threadid(GUID,X)),thread_join(X,_)); 1141 | (retractall(guid_threadid(GUID,_)),thread_join(X,_))) 1142 | ; 1143 | true 1144 | ),Error,(write('Clean_error: '),writeln(Error))), 1145 | agent_GUID(GUID,Handler,(Ip,Port)), 1146 | assimilate_code(GUID,AgentCode), 1147 | agent_payload(GUID,PayloadList), 1148 | agent_token(GUID,ListOfTokens), 1149 | 1150 | assert(transit_GUID(GUID,Handler,(Ip,Port))), 1151 | assert(transit_payload(GUID,PayloadList)), 1152 | list_to_set(ListOfTokens,ListOfTokens2), 1153 | assert(transit_token(GUID,ListOfTokens2)), 1154 | assert(transit_code(GUID,AgentCode)), 1155 | transit_GUID(GUID,_H,_P), 1156 | 1157 | retractall(agent_GUID(GUID,Handler,(Ip,Port))), 1158 | retractall(agent_payload(GUID,PayloadList)), 1159 | retractall(agent_token(GUID,ListOfTokens)), 1160 | retract_code_Tartarus_IITG(AgentCode), 1161 | %write('Assembled transit code for '),write(GUID), 1162 | (thread_peek_message(clean_agent_queue,agent_guid(GUID))->thread_get_message(clean_agent_queue,agent_guid(GUID));true), 1163 | %write('Transit code is asserted for '),write(GUID),nl, 1164 | !; 1165 | print_message(error,'agent_clean(platform,(Ip,Port)) failed')); 1166 | print_message(warning,'Cleaning already done')), 1167 | %join_threads, 1168 | %writeln('-----------cleaning end-----------'),ttyflush, 1169 | !,agent_clean(platform,(Ip,Port)). 1170 | 1171 | 1172 | is_exist(Agent_name):- 1173 | (agent_GUID(Agent_name,_Handler,(_Ip,_Port))-> 1174 | !,is_exist(Agent_name); 1175 | format(atom(Str),'Old agent with name ~q is killed',[Agent_name]), 1176 | writeln(Str)). 1177 | 1178 | 1179 | %================================================HANDLER CODE FOR PLATFORM================================================== 1180 | 1181 | 1182 | 1183 | handler(platform,(_,_),platform_restart):- 1184 | platform_state(on), 1185 | platform_Ip(Ip), 1186 | platform_port(Port), 1187 | forall(agent_GUID(GUID,_,_),agent_kill(GUID)), 1188 | forall(code_base(_,FileCodeList),retract_code_Tartarus_IITG(FileCodeList)), 1189 | retractall(code_base(_,_)), 1190 | close_stream_pool, 1191 | catch(forall(guid_threadid(_,ThreadID),( 1192 | (thread_property(ThreadID,status(S)),S=running)-> 1193 | thread_signal(ThreadID,thread_exit(_)),thread_join(ThreadID,_); 1194 | (retractall(guid_threadid(_,ThreadID))) 1195 | ) 1196 | ),Error,writeln(Error)), 1197 | 1198 | catch(forall(static_agent_details(Port,_,_,_,_),clean_static_agent(Port)),Error,writeln(Error)), 1199 | 1200 | retractall(guid_threadid(_,_)), 1201 | platform_socket_Tartarus_IITG(Socket), 1202 | retractall(platform_socket_Tartarus_IITG(Socket)), %% retract current socket 1203 | tcp_close_socket(Socket), 1204 | message_queue_destroy(global_queue), 1205 | message_queue_destroy(client_queue), 1206 | message_queue_destroy(clean_platform), 1207 | message_queue_destroy(clean_agent_queue), 1208 | mutex_destroy(message_queue_mutex), 1209 | mutex_destroy(send_message_mutex), 1210 | retractall(platform_port(_)), 1211 | retractall(platform_Ip(_)), 1212 | retractall(platform_state(_)), 1213 | start_db, 1214 | writeln('-------restarting platform in 2 seconds------'), 1215 | sleep(2), %% wait for 2 second for other threads to fail/complete 1216 | make_platform_Tartarus_IITG(Ip,Port),nl, 1217 | writeln('-------platform restarted sucessfully-------'), 1218 | retractall(hoptime_stat(_,_,_,_)), 1219 | assert(hoptime_stat(0,0,0,0)), 1220 | retractall(transfer_queue(_)), 1221 | assert(transfer_queue([])),ttyflush,!. 1222 | 1223 | 1224 | %------------------------------------------------------------------------------------ 1225 | 1226 | handler(platform,(_,_),platform_restart(New_ip,New_port)):- 1227 | platform_state(on), 1228 | %platform_Ip(Ip), 1229 | %platform_port(Port), 1230 | forall(agent_GUID(GUID,_,_),agent_kill(GUID)), 1231 | forall(code_base(_,FileCodeList),retract_code_Tartarus_IITG(FileCodeList)), 1232 | retractall(code_base(_,_)), 1233 | close_stream_pool, 1234 | catch(forall(guid_threadid(_,ThreadID),( 1235 | (thread_property(ThreadID,status(S)),S=running)-> 1236 | thread_signal(ThreadID,thread_exit(_)),thread_join(ThreadID,_); 1237 | (retractall(guid_threadid(_,ThreadID))) 1238 | ) 1239 | ),Error,writeln(Error)), 1240 | 1241 | catch(forall(static_agent_details(Port,_,_,_,_),clean_static_agent(Port)),Error,writeln(Error)), 1242 | 1243 | retractall(guid_threadid(_,_)), 1244 | platform_socket_Tartarus_IITG(Socket), 1245 | retractall(platform_socket_Tartarus_IITG(Socket)), %% retract current socket 1246 | tcp_close_socket(Socket), 1247 | message_queue_destroy(global_queue), 1248 | message_queue_destroy(client_queue), 1249 | message_queue_destroy(clean_platform), 1250 | message_queue_destroy(clean_agent_queue), 1251 | mutex_destroy(message_queue_mutex), 1252 | mutex_destroy(send_message_mutex), 1253 | retractall(platform_port(_)), 1254 | retractall(platform_Ip(_)), 1255 | retractall(platform_state(_)), 1256 | start_db, 1257 | writeln('-------restarting platform in 2 second on new ip port------':New_ip:New_port), 1258 | sleep(2), 1259 | make_platform_Tartarus_IITG(New_ip,New_port), 1260 | writeln('-------platform restarted sucessfully on new ip port-------':New_ip:New_port), 1261 | retractall(hoptime_stat(_,_,_,_)), 1262 | assert(hoptime_stat(0,0,0,0)), 1263 | retractall(transfer_queue(_)), 1264 | assert(transfer_queue([])),ttyflush,!. 1265 | 1266 | 1267 | 1268 | %-----------------------------Agent Create Module---------------------------------------- 1269 | 1270 | handler(platform,(_,_),handler_file):- %% enter the handler file name for agent definition and its handler 1271 | writeln('Enter the file of handler'), %% promt to get file name 1272 | read(File_name), %% read in filename 1273 | consult(File_name), %% consult predicates in file 1274 | writeln('handler asserted successfully'). %% Display 1275 | 1276 | %---------------------------------------------- 1277 | 1278 | handler(platform,(_,_),handler_file(File_name)):- %% enter the handler file name for agent definition and its handler 1279 | consult(File_name), %% consult predicates in file 1280 | writeln('handler asserted successfully'). %% Display 1281 | 1282 | %---------------------------------------------- 1283 | 1284 | handler(platform,(_,_),save_state(FileName)):- 1285 | open(FileName,write,X), 1286 | current_output(Y), 1287 | set_output(X), 1288 | forall(code_base(_,FileCodeList), 1289 | (forall(member(FileCode,FileCodeList), 1290 | (with_output_to(atom(Code_write), 1291 | portray_clause(FileCode)),write(Code_write))) 1292 | ) 1293 | ), 1294 | forall(agent_GUID(GUID,_Handler,(_Ip,_Port)), 1295 | (assimilate_code(GUID,Result), 1296 | forall((member(Code,Result)), 1297 | (with_output_to(atom(Code_write2),portray_clause(Code)),write(Code_write2))) 1298 | 1299 | ) 1300 | ), 1301 | 1302 | (clauses(agent_payload(_Gg,_Ll),PayloadMeta)-> 1303 | forall(member(M,PayloadMeta),(with_output_to(atom(Ss),portray_clause(M)),write(Ss)));nothing 1304 | ), 1305 | 1306 | (forall(agent_GUID(G1,H1,P1),(with_output_to(atom(S1),portray_clause((start_agent(G1,H1,P1)))),write(S1))), 1307 | clauses(agent_GUID(_G,_H,_P),List)-> 1308 | forall(member(L,List),(with_output_to(atom(S),portray_clause(L)),write(S)));nothing 1309 | ), 1310 | (clauses(code_base(_FName,_FCode),FCodeMeta), 1311 | forall(member(FM,FCodeMeta),(with_output_to(atom(Ff),portray_clause(FM)),write(Ff)));nothing 1312 | ), 1313 | set_output(Y), 1314 | close(X),!; 1315 | print_message(warning,'handler(platform,(_,_),save_state(FileName)) failed'). 1316 | 1317 | %-------------------------------------------------------------------------------------------------------------------------- 1318 | 1319 | handler(platform,_Link,load_state(FileName)):- 1320 | file_to_list_Tartarus_IITG(FileName,L), 1321 | forall( 1322 | member(Code,L), 1323 | (Code = (start_agent(G,H,P))-> 1324 | (call(agent_execute(G,P,H)),assert(agent_GUID(G,H,P))); 1325 | assert(Code) 1326 | ) 1327 | ),!; 1328 | print_message(warning,'handler(platform,_Link,load_state(FileName)) failed'). 1329 | 1330 | 1331 | %========================================= 1332 | 1333 | 1334 | 1335 | 1336 | %======================================================================================================% 1337 | % Clean agent % 1338 | % % 1339 | % This predicate is used to clean agent with given guid, it retracts code, relase allocated resources. % 1340 | %======================================================================================================% 1341 | handler(platform,(Ip,Port),clean_agent(GUID)):- 1342 | ttyflush, 1343 | writeln('-----------cleaning start----------':GUID), 1344 | mutex_lock(clean_agent_mutex), 1345 | (thread_peek_message(clean_agent_queue,agent_guid(GUID))-> 1346 | (catch(( 1347 | (guid_threadid(GUID,X),integer(X),thread_property(X,status(Y)),Y=running)-> 1348 | (guid_threadid(GUID,X1),thread_signal(X1,thread_exit(true)),retractall(guid_threadid(GUID,X1))); 1349 | (guid_threadid(GUID,X2),retractall(guid_threadid(GUID,_)),thread_join(X2,_)) 1350 | ),Error,(write('clean_error: '),writeln(Error))), 1351 | agent_GUID(GUID,Handler,(Ip,Port)), 1352 | assimilate_code(GUID,AgentCode), 1353 | agent_payload(GUID,PayloadList), 1354 | agent_token(GUID,ListOfTokens), 1355 | 1356 | assert(transit_GUID(GUID,Handler,(Ip,Port))), 1357 | assert(transit_payload(GUID,PayloadList)), 1358 | list_to_set(ListOfTokens,ListOfTokens2), 1359 | assert(transit_token(GUID,ListOfTokens2)), 1360 | assert(transit_code(GUID,AgentCode)), 1361 | transit_GUID(GUID,_H,_P), 1362 | 1363 | retractall(agent_GUID(GUID,Handler,(Ip,Port))), 1364 | retractall(agent_payload(GUID,PayloadList)), 1365 | retractall(agent_token(GUID,ListOfTokens)), 1366 | retract_code_Tartarus_IITG(AgentCode), 1367 | write('Assembled transit code for '),write(GUID), 1368 | (thread_peek_message(clean_agent_queue,agent_guid(GUID))->thread_get_message(clean_agent_queue,agent_guid(GUID));true), 1369 | write('Transit code is asserted for '),write(GUID),nl, 1370 | !; 1371 | print_message(error,'handler(platform,(Ip,Port),clean_agent(GUID)) failed')); 1372 | print_message(warning,'Cleaning already done')), 1373 | %join_threads, 1374 | mutex_unlock(clean_agent_mutex), 1375 | writeln('Unlocking mutex'), 1376 | writeln('-----------cleaning end-----------'),ttyflush. 1377 | 1378 | 1379 | %-------------------------------------------------------------------------------------------------- 1380 | 1381 | % send_ackm(GUID) event is posted to a platform when a migration of agent is complete. The handler here computes the time it took for the hop 1382 | % Intially, at the time of sending the code, a timestamp was saved. Now when this ackm arrives, we check the time and find the difference. This 1383 | % is done by time/2[CHECK OUT WIN_REF.pdf for how time/2 can be used to find time difference]. After time is calculated, it is posted into the console 1384 | % and all the temporary data of the outgoing agent is removed by retracting the transit predicates. 1385 | 1386 | handler(platform,(Ip,Port),send_ackm(GUID,_X)):- 1387 | ttyflush, 1388 | writeln('--------- positive ACK received----------'), 1389 | %writeln('Got ACK from the destination for '),write(GUID),write(Ip),write(Port), 1390 | (outgoing_agent(GUID,TT,_)-> 1391 | get_time(Finish_TT), 1392 | Time_taken is (Finish_TT - TT), 1393 | %get_platform_details(Platform_Ip,Platform_Port), 1394 | (thread_peek_message(clean_agent_queue,agent_guid(GUID))-> 1395 | %%handler(platform,(Ip,Port),clean_agent(GUID)), 1396 | cleanup_wait(GUID); 1397 | %writeln('Cleanning called'); 1398 | true 1399 | ), 1400 | nl,write('Migration time for agent '),write(GUID),write(':'),write(Time_taken),write(' seconds'),nl;true), 1401 | retractall(outgoing_agent(GUID,_Top,_Res)), 1402 | % nl, 1403 | %write('Agent Bearing '),write(GUID), 1404 | % write(' reached destination : Time : '), 1405 | % write(X), 1406 | % nl, 1407 | retractall(transit_GUID(GUID,_Handler,(Ip,Port))), 1408 | retractall(transit_payload(GUID,_PayloadList)), 1409 | retractall(transit_token(GUID,_ListOfTokens)), 1410 | retractall(transit_code(GUID,_AgentCode)), 1411 | %writeln('--------positive ack processed---------'), 1412 | ttyflush, 1413 | !. 1414 | 1415 | handler(platform,(_Ip,_Port),send_ackm(_GUID,_X)):- print_message(error,'handler(platform,(Ip,Port),send_ackm(GUID,_X)) failed'),!. 1416 | 1417 | %------------------------------------------------------------------------------ 1418 | 1419 | % send_nackm(GUID) is posted to a platform, when a migration is not successful. This happens incase the agent does not carry the correct token 1420 | % required to enter the destination platform[NEGATIVE AUTHENTICATION]. By default, this comes into use when using the security feature of the platform 1421 | % The inactive code is retrieved from the transit predicates and the agent is started again. 1422 | 1423 | handler(platform,(Ip,Port),send_nackm(GUID)):- 1424 | ttyflush, 1425 | writeln('--------negative ACK received-----------'), 1426 | outgoing_agent(GUID,_TT,_), 1427 | %get_platform_details(Platform_Ip,Platform_Port), 1428 | (thread_peek_message(clean_agent_queue,agent_guid(GUID))-> 1429 | cleanup_wait(GUID) 1430 | %handler(platform,(Platform_Ip,Platform_Port),clean_agent(GUID)) 1431 | ;true 1432 | ), 1433 | retractall(outgoing_agent(GUID,_Top,_Res)), 1434 | nl, 1435 | write('Agent '),write(GUID),write(' was not allowed to enter the destination.'), 1436 | nl, 1437 | transit_GUID(GUID,Handler,(Ip,Port)), 1438 | transit_payload(GUID,PayloadList), 1439 | transit_token(GUID,ListOfTokens), 1440 | transit_code(GUID,AgentCode), 1441 | assert(agent_GUID(GUID,Handler,(Ip,Port))), 1442 | assert(agent_payload(GUID,PayloadList)), 1443 | assert(agent_token(GUID,ListOfTokens)), 1444 | assert_code_Tartarus_IITG(AgentCode), 1445 | platform_Ip(Ip), 1446 | platform_port(Port), 1447 | retractall(transit_GUID(GUID,Handler,(Ip,Port))), 1448 | retractall(transit_payload(GUID,PayloadList)), 1449 | retractall(transit_token(GUID,ListOfTokens)), 1450 | retractall(transit_code(GUID,AgentCode)), 1451 | %agent_execute(GUID,(Ip,Port),Handler), 1452 | writeln('--------negative ack processed-----------'),ttyflush, 1453 | !. 1454 | 1455 | handler(platform,(_Ip,_Port),send_nackm(_GUID)):- print_message(error,'handler(platform,(Ip,Port),send_nackm(GUID)):-'),!. 1456 | 1457 | %------------------------------------------------------------------------------------ 1458 | 1459 | % This is the main handler which handles the incoming agent. The identifier(GUID), its Handler name(handler), its code and token comes as 1460 | % parameters. In case a platform has a security token set(via set_token/1), the incoming agent's token list is checked. If it contains the 1461 | % matching token, the execution proceeds, else the entire thing is discarded and a negative ackm is sent to the sending platform. In case the platform 1462 | % does not have a security token set, then no checking is done. A postive ackm is send and the agent is started using agent_create/3. 1463 | 1464 | handler( platform, (Ip_sender,Port_sender), send(GUID,Handler,PayloadList,[Code|CodeList],ListOfTokens,_BackTime)):- %// 1465 | ttyflush, 1466 | %write('Receiving an Agent Posted by link'),writeln(Ip_sender),writeln(Port_sender),writeln(BackTime),nl, 1467 | (platform_token(_)-> 1468 | nothing; 1469 | agent_post(platform,(Ip_sender,Port_sender),[handler,platform,(Ip_sender,Port_sender),send_nackm(GUID)]),fail 1470 | ), 1471 | (platform_token(PToken)-> 1472 | (member(PToken,ListOfTokens)-> 1473 | nothing; 1474 | (agent_post(platform,(Ip_sender,Port_sender),[handler,platform,(Ip_sender,Port_sender),send_nackm(GUID)]),fail) 1475 | ); 1476 | nothing 1477 | ), 1478 | (agent_GUID(GUID,Handler,(_,_))-> % Tushar - added to kill agent already present with same name and handler name 1479 | writeln('Agent already present'), 1480 | agent_kill(GUID) 1481 | ; 1482 | nothing 1483 | ), 1484 | write('Agent bearing '),write(GUID), 1485 | write(' has arrived to this platform. '),nl, 1486 | get_platform_details(Platform_Ip,Platform_Port), 1487 | (thread_peek_message(clean_agent_queue,agent_guid(GUID))-> 1488 | cleanup_wait(GUID) 1489 | %handler(platform,(Platform_Ip,Platform_Port),clean_agent(GUID)) 1490 | ;true 1491 | ), 1492 | assert(agent_payload(GUID,PayloadList)), 1493 | assert(agent_token(GUID,ListOfTokens)), 1494 | assert_code_Tartarus_IITG([Code|CodeList]), 1495 | assert(agent_GUID(GUID,Handler,(Platform_Ip,Platform_Port))), 1496 | get_time(Time), 1497 | agent_post(platform,(Ip_sender,Port_sender),[handler,platform,(Ip_sender,Port_sender),send_ackm(GUID,Time)]), 1498 | agent_execute(GUID,(Platform_Ip, Platform_Port),Handler), 1499 | %nl,write('Agent has been created at this port : '), 1500 | %write(Port2),nl, 1501 | %nl, 1502 | true,!. 1503 | 1504 | handler( platform, (_Ip_sender,_Port_sender), send(_GUID,_Handler,_PayloadList,[_Code|_CodeList],_ListOfTokens,_Bcktime)):- 1505 | print_message(error,'Error in handler. The posted agent not received properly over the Link'). 1506 | 1507 | %------------------------server module------------------------------- 1508 | 1509 | handler(server,(Sender_Ip,Sender_Port),agent_message(GUID,Message)):- 1510 | ttyflush, 1511 | get_time(Timestamp), 1512 | nl,write(Timestamp),write(' '),write(GUID),write(' '),write(Sender_Ip),write(' '),write(Sender_Port),write(' '),write(Message), 1513 | ttyflush, 1514 | open('server_log.txt',append,X), 1515 | current_output(Y), 1516 | set_output(X), 1517 | nl,write(Timestamp),write(' '),write(GUID),write(' '),write(Sender_Ip),write(' '),write(Sender_Port),write(' '),write(Message), 1518 | set_output(Y), 1519 | close(X),!; 1520 | print_message(warning,'handler(server,(Sender_Ip,Sender_Port),agent_message(GUID,Message)) failed'). 1521 | 1522 | %-------------------------------------------------------------------------------------------------------------------- 1523 | 1524 | send_log(GUID,Message):- 1525 | get_platform_details(Agent_Ip,Agent_Port), 1526 | message_server(GUID,(Agent_Ip,Agent_Port),Message). 1527 | 1528 | message_server(GUID,(Agent_Ip,Agent_Port),Message):- 1529 | server_Ip(Ip), 1530 | server_Port(Port), 1531 | agent_post(platform,(Ip,Port),[handler,server,(Agent_Ip,Agent_Port),agent_message(GUID,Message)]). 1532 | 1533 | set_log_server(Ip, Port):- 1534 | retractall(server_Ip(_)), 1535 | retractall(server_Port(_)), 1536 | assert(server_Port(Port)), 1537 | assert(server_Ip(Ip)). 1538 | 1539 | 1540 | %----------------------------------------------------------------------------------------------------------------------------- 1541 | %---------------------------------------------------------utilities----------------------------------------------------------- 1542 | 1543 | % assert_code_Tartarus_IITG/1 works on a list of code and asserts it. After asserting, it prints a message in the console. Its an internal predicate 1544 | % and therefore kept hidden from the user of this platform{Means that if he creates a assert_code_Tartarus_IITG/1 of his own, my predicate here won't 1545 | % affect his predicate's working and vica versa } 1546 | % It checks for clause(Predicate) when reading from the list and if it sees one, it queries a dynamic/1 via execs/1. This effectively wipes 1547 | % all predicates with the name Predicate/arity. 1548 | 1549 | %asserts a list of given code in platform. 1550 | 1551 | assert_code_Tartarus_IITG([]):- true, 1552 | %writeln('Agent/Code recieved and asserted'), 1553 | true. 1554 | 1555 | assert_code_Tartarus_IITG([Code|CodeList]):- 1556 | ( 1557 | retractall(Code)->assert(Code); 1558 | assert(Code) 1559 | ), 1560 | assert_code_Tartarus_IITG(CodeList). 1561 | 1562 | 1563 | %-------------------------------------------------------------------------------------- 1564 | 1565 | % retracts_code/1 retracts the list of code and issues an output when done 1566 | 1567 | retract_code_Tartarus_IITG([]):- 1568 | true, 1569 | %writeln('Agent/Code retracted'), 1570 | true. 1571 | 1572 | 1573 | retract_code_Tartarus_IITG([Code|CodeList]):- 1574 | %writeln(Code),writeln('-----------'), 1575 | ( 1576 | retract(Code)-> 1577 | true; 1578 | (write('Could not retract: '),writeln(Code),true) 1579 | ), 1580 | retract_code_Tartarus_IITG(CodeList). 1581 | 1582 | %------------------------------------------------------------------------------------ 1583 | 1584 | % file_to_list_Tartarus_IITG converts a file(full of prolog code) to a list of code. Because I want to send code as onene entity . 1585 | % Helps me keep check on the code. There are many ways of doing the above thing. This is one way of implementing it. 1586 | % The inquire_Tartarus_IITG builds a list by looping on the read and recursively calling inquire_Tartarus_IITG. Finally, that is reversed and presented 1587 | % in the unbound LIST variable. This is not an interface function. So I have not pushed up all the bounding checks 1588 | 1589 | file_to_list_Tartarus_IITG(FILE,LIST) :- 1590 | open(FILE,read,X), 1591 | inquire_Tartarus_IITG(X,[],R), 1592 | reverse(R,LIST), 1593 | close(X). 1594 | 1595 | inquire_Tartarus_IITG(X,IN,OUT):- 1596 | read_clause(X,Clause,[]), 1597 | (Clause == end_of_file -> OUT = IN ;inquire_Tartarus_IITG(X,[Clause|IN],OUT) ) . 1598 | 1599 | %----------------------------------------- 1600 | 1601 | % predicate_header/4 prepares the head of the predicate. Example : Predicate = platform, Arity = 3, and What = jatin. 1602 | % The Result obtained is Result = platform(jatin,_,_). 1603 | % Working : its uses functor/3 (CHECK WIN_REF.pdf) to create platform(_,_,_). Then =../2 is used to convert the tuple to a list. we 1604 | % get [platform,_,_,_] and we replace the first underscore via replace_underscore/3 by jatin. Finally using =../2 in opposite manner, I get 1605 | % platform(jatin,_,_). 1606 | 1607 | % This is used to generate headers for Handler code, and payload code. The user specifies the Handler and payload name. The What is usually 'guid' 1608 | % or actual identifier for a agent. Once a predicate_header is prepared, we usually call clauses/2 to get the body(code) of the predicate. 1609 | % This is used in lots of predicates below such as generate_unique_predicate, generate_generic_predicate, genhandler etc. 1610 | 1611 | predicate_header(What,Predicate,Arity,Result):- 1612 | functor(R,Predicate,Arity),R=..[H|T], 1613 | replace_underscore(T,What,NT), 1614 | Result=..[H|NT],!. 1615 | 1616 | replace_underscore([_H|T],What,[What|T]). 1617 | 1618 | %------------------------------------------ 1619 | 1620 | % generatePayloadCode is used for generating payload code :D. Given a list of predicates which needs to be 'attached' to a agent, we need 1621 | % to process those predicates inorder to attach them. Given a predicate : ability(guid,X):-body of ability/2 {THE WAY OF DEFINING A PAYLOAD} 1622 | % If we wish to attach ability/2 as payload, then the term 'guid' needs to be replaced by the Agent ID(or GUID). So the above code becomes 1623 | % agent(agent) specific when ability(actual ID of agent,X):-body is generated from above code, by text manipulation. This code is asserted 1624 | 1625 | generatePayloadCode(_,[],[]). 1626 | 1627 | generatePayloadCode(GUID,[(Predicate,Arity)|Tail],PayloadCode):- 1628 | generatePayloadCode(GUID,[(Predicate,Arity)|Tail],[],PayloadCode). 1629 | 1630 | generatePayloadCode(GUID,[(Predicate,Arity)|Tail],TempList,PayloadCode):- 1631 | generate_unique_predicate(GUID,Predicate,Arity,Body), 1632 | append(TempList,Body,NTempList), 1633 | generatePayloadCode(GUID,Tail,NTempList,PayloadCode). 1634 | 1635 | generatePayloadCode(_,[],TempList,TempList). 1636 | 1637 | %------------------------------------------- 1638 | 1639 | % genhandler/2 is similar to what generatePayloadCode. The latter does to payload predicates, while the former does the same thing to Handler predicate 1640 | % of a agent. It replaces all instances of 'guid' and pushed the actual identifier/name of the agent/agent into that code.Uses generate_unique_predicate 1641 | % which is the main thing behind the process. 1642 | 1643 | genhandler(GUID,Handler,Result):- 1644 | generate_unique_predicate(GUID,Handler,3,Result). 1645 | 1646 | %------------------------------------------- 1647 | 1648 | :-dynamic temp_list/1. 1649 | 1650 | temp_list([]). 1651 | 1652 | add_element(H,Old,[H|Old]). 1653 | 1654 | list_code(H):- 1655 | forall( 1656 | clause(H,Code), 1657 | ( 1658 | term_to_atom(H,H2), 1659 | term_to_atom(Code,Code2), 1660 | atom_concat(H2,':-',H3), 1661 | atom_concat(H3,Code2,Code3), 1662 | atom_to_term(Code3,Code4,_), 1663 | temp_list(UserHandlerCode), 1664 | add_element(Code4,UserHandlerCode,Result), 1665 | retractall(temp_list(_)), 1666 | assert(temp_list(Result)) 1667 | ) 1668 | ). 1669 | 1670 | % generate_unique_predicate/4 is the brain behind all the manipulation. The user specifies code of a handler / payload etc . This code is generic in nature 1671 | % since its not attached to any agent. However when we attach code (Handler or otherwise) to a agent, we replace the 'guid' present in the code by the 1672 | % name/identifier of the agent. This makes the said attachment possible. {Try this by doing on a rough copy}. The example given for generatePayloadCode 1673 | % is what happens here. predicate_header/4 is used to make the header predicate(guid,_,_..arity-1 times). The body is then found using clauses. 1674 | % Then generate_unique_predicate/5 is called which recurses through the code of the predicate. It replaces 'guid' by actual idenetifier and pushes 1675 | % all the code so generated into Result. The convert to tuple actually is used to convert the code(which is in text form) back to the tuple form (Try 1676 | % reading code from a .pl file (use file_to_list_Tartarus_IITG/2 ). you will see that the code is in tuples. So regain this back I use covert_to_tuple. Check its code 1677 | % later below 1678 | 1679 | generate_unique_predicate(GUID,Predicate,Arity,Result):- 1680 | var(Result), 1681 | predicate_header(guid,Predicate,Arity,H), 1682 | ((list_code(H),temp_list(UserHandlerCode),retractall(temp_list(_)),assert(temp_list([])))->( 1683 | generate_unique_predicate(GUID,Predicate,UserHandlerCode,[],Result) 1684 | ) 1685 | ; ( 1686 | writeln('Warning :: '),write(Predicate),write(' not found'),nl, 1687 | unify_with_empty_list(Result,[]) 1688 | ) 1689 | ),!. 1690 | 1691 | 1692 | generate_unique_predicate(GUID,Predicate,[Head|Tail],Incoming,Outgoing):- 1693 | term_to_atom(Head,X), 1694 | name(X,CodeList), 1695 | name(guid,Symbol), 1696 | name(GUID,Glist), 1697 | substitute_all(CodeList,Symbol,Glist,R), 1698 | name(Text,R), 1699 | atom_to_term(Text,Text2,_), 1700 | append([Text2],Incoming,NextIncoming), 1701 | generate_unique_predicate(GUID,Predicate,Tail,NextIncoming,Outgoing). 1702 | 1703 | generate_unique_predicate(_,_,[],I,I). 1704 | 1705 | 1706 | %------------------------------------------- 1707 | 1708 | 1709 | 1710 | add_element2(H,Old,[H|Old]). 1711 | 1712 | list_code2(H):- 1713 | forall( 1714 | clause(H,Code), 1715 | ( 1716 | term_to_atom(H,H2), 1717 | term_to_atom(Code,Code2), 1718 | atom_concat(H2,':-',H3), 1719 | atom_concat(H3,Code2,Code3), 1720 | atom_to_term(Code3,Code4,_), 1721 | temp_list2(H,UserHandlerCode), 1722 | add_element2(Code4,UserHandlerCode,Result), 1723 | retractall(temp_list2(H,_)), 1724 | assert(temp_list2(H,Result)) 1725 | ) 1726 | ). 1727 | 1728 | % generate_generate_predicate performs the reverse process of the above predicate. Given a predicate, we find its specific defination with respect 1729 | % to a agent. Here for the above example, we will have ability(absadwf,_,_) and we would convert it to ability(guid,_,_):-blahblah. This predicate 1730 | % is used when you want to shed a payload. This payload is therfore converted into a generic format (the way a user writes a payload in file) 1731 | % and then pushed into the system. You will see this predicate in use in interface functions such as shed_payload,copy_payload . 1732 | 1733 | generate_generic_predicate(GUID,Predicate,Arity,Result):- 1734 | var(Result), 1735 | predicate_header(GUID,Predicate,Arity,H), 1736 | retractall(temp_list2(H,_)), 1737 | assert(temp_list2(H,[])), 1738 | ((list_code2(H),temp_list2(H,UniqueCode),retractall(temp_list2(H,_)))-> 1739 | (generate_generic_predicate(GUID,Predicate,UniqueCode,[],Result)); 1740 | (writeln('Warning :: Agent Predicate '),write(Predicate),write(' not found'),nl, 1741 | unify_with_empty_list(Result,[])) 1742 | ),!. 1743 | 1744 | 1745 | generate_generic_predicate(GUID,Predicate,[Head|Tail],Incoming,Outgoing):- 1746 | term_to_atom(Head,X), 1747 | name(X,CodeList), 1748 | name(GUID,Glist), 1749 | name(guid,SymList), 1750 | substitute_all(CodeList,Glist,SymList,R), 1751 | name(Text,R), 1752 | atom_to_term(Text,Text2,_), 1753 | append(Incoming,[Text2],NextIncoming), 1754 | generate_generic_predicate(GUID,Predicate,Tail,NextIncoming,Outgoing). 1755 | 1756 | generate_generic_predicate(_,_,[],I,I). 1757 | 1758 | 1759 | %--------------------------------------------------- 1760 | 1761 | 1762 | 1763 | add_element3(H,Old,Result):- 1764 | append(Old,[H],Result). 1765 | 1766 | list_code3(GUID,H):- 1767 | (forall( 1768 | clause(H,Code),( 1769 | term_to_atom(H,H2), 1770 | term_to_atom(Code,Code2), 1771 | atom_concat(H2,':-',H3), 1772 | atom_concat(H3,Code2,Code3), 1773 | atom_to_term(Code3,Code4,_), 1774 | temp_list3(GUID,UserHandlerCode), 1775 | add_element3(Code4,UserHandlerCode,Result), 1776 | retractall(temp_list3(GUID,_)), 1777 | assert(temp_list3(GUID,Result)) 1778 | ) 1779 | )). 1780 | 1781 | % assimilate_code/2 fetches all the Agent code and presents it as code list in Result. It calls assimilate_payload_code/4, and assimilate_handler_code/3 1782 | % which do their job and the results are appended and returned. Read the code 1783 | 1784 | assimilate_code(GUID,Result):- 1785 | agent_GUID(GUID,Handler,_), 1786 | assimilate_handler_code(GUID,Handler,HandlerCode), 1787 | agent_payload(GUID,PayloadList), 1788 | assimilate_payload_code(GUID,PayloadList,[],PayloadCode), 1789 | append(HandlerCode,PayloadCode,Result), 1790 | true,!. 1791 | 1792 | assimilate_handler_code(GUID,Handler,HandlerCode):- 1793 | predicate_header(GUID,Handler,3,Result), 1794 | ( 1795 | retractall(temp_list3(GUID,_)), 1796 | assert(temp_list3(GUID,[])), 1797 | (list_code3(GUID,Result),temp_list3(GUID,HandlerCode),retractall(temp_list3(GUID,_)))->nothing; 1798 | ( 1799 | writeln('Warning :: Handler code for agent not found - id '), 1800 | write(GUID),nl, 1801 | unify_with_empty_list(HandlerCode,[]) 1802 | ) 1803 | ). 1804 | 1805 | assimilate_payload_code(GUID,[(Predicate,Arity)|Tail],Incoming,Outgoing):- 1806 | predicate_header(GUID,Predicate,Arity,Result), 1807 | ( 1808 | retractall(temp_list3(GUID,_)), 1809 | assert(temp_list3(GUID,[])), 1810 | (list_code3(GUID,Result),temp_list3(GUID,Body),retractall(temp_list3(GUID,_)))->append(Body,Incoming,NextIncoming) ; 1811 | ( 1812 | unify_with_empty_list(Body,[]), 1813 | append(Body,Incoming,NextIncoming) 1814 | ) 1815 | ), 1816 | assimilate_payload_code(GUID,Tail,NextIncoming,Outgoing). 1817 | 1818 | assimilate_payload_code(_,[],I,I):-!. 1819 | 1820 | %----------------------------------------------------- 1821 | 1822 | % replaceGUID/4 is used for cloning purposes. In cloning(see agent_clone/2), a new identifier is generated and the original agent code is 1823 | % assmilated. This code is AgentCode. All instances of the original identifier in AgentCode is replaced by the new identifier generated before 1824 | % The resulting code is returned as CloneCode. The working of replaceGUID is simple. It parses through the AgentCode, and substitutes using substitute_all/4. 1825 | % AgentCode is list of tuples(each tuple being a predicate definiation). Each tuple is converted into string using portray_clause/2. Then the strings 1826 | % are converted into a List of ascii numbers (for the characters of the string) . Substitution is now performed. After the substitution, the code is packed 1827 | % into text(characters again). And pushed into list again. These are then converted into tuples . Result is the CloneCode 1828 | % Example : original agent is qwertyu(GUID1) and its code is given below. Lets say the new clone ID(GUID2) is zxcvbn 1829 | % AGENTCODE [(hello(qwertyu,X):-abcd(qwertyu),write('heheh')),(bbye(qwertyu):-write(bye))] 1830 | % CLONECODE obtained will be : [(hello(zxcvbn,X):-abcd(zxcvbn),write('heheh')),(bbye(zxcvbn):-write(bye))] 1831 | 1832 | replaceGUID(AgentCode,GUID1,GUID2,CloneCode):- 1833 | replaceGUID(AgentCode,GUID1,GUID2,[],CloneCode),!. 1834 | 1835 | replaceGUID([Head|Tail],GUID1,GUID2,Incoming,Outgoing):- 1836 | term_to_atom(Head,X), 1837 | name(X,CodeList), 1838 | name(GUID1,Remove), 1839 | name(GUID2,Add), 1840 | substitute_all(CodeList,Remove,Add,R), 1841 | name(Text,R), 1842 | atom_to_term(Text,Text2,_), 1843 | append(Incoming,[Text2],NextIncoming), 1844 | replaceGUID(Tail,GUID1,GUID2,NextIncoming,Outgoing). 1845 | 1846 | replaceGUID([],_,_,Incoming,Incoming). 1847 | 1848 | %----------------------------------------------------- 1849 | 1850 | % hoptime_rec/2 is used for recording the times. Its essentially used for calcluating the averages. Given the previous no of agents 1851 | % going out/in and the avg out/in time, a new average is calculated each time an agent moves out/in. The time to go out/in is represented by 1852 | % T. hoptime_rec with second paramter as outgoing computes the new average outgoing time and updates the statistics. The hoptime-rec with incoming as 1853 | % second parameter calculates the same for incoming agents. 1854 | 1855 | hoptime_rec(T,outgoing):- 1856 | hoptime_stat(Out,OutAvg,Inc,IncAvg), 1857 | NewAvg is (((Out *OutAvg)+T)/(Out+1)), 1858 | NewOut is Out +1, 1859 | retractall(hoptime_stat(Out,OutAvg,Inc,IncAvg)), 1860 | assert(hoptime_stat(NewOut,NewAvg,Inc,IncAvg)),!. 1861 | 1862 | hoptime_rec(T,incoming):- 1863 | hoptime_stat(Out,OutAvg,Inc,IncAvg), 1864 | NewAvg is (((Inc *IncAvg)+T)/(Inc+1)), 1865 | NewInc is Inc +1, 1866 | retractall(hoptime_stat(Out,OutAvg,Inc,IncAvg)), 1867 | assert(hoptime_stat(Out,OutAvg,NewInc,NewAvg)),!. 1868 | 1869 | %---------------------------------------------------- 1870 | hoptime(Out,OutAvg,Inc,IncAvg):- 1871 | var(Out),var(OutAvg),var(Inc),var(IncAvg), 1872 | hoptime_stat(Out,OutAvg,Inc,IncAvg). 1873 | 1874 | %---------------------------------------------------------- 1875 | 1876 | % list_agent/0 prints all the agents and their ports onto the console. list_agent/2 lets you do the same, accept that 1877 | % it lets you unify that with variables. 1878 | /* Depracated --- tushar 01 March 2017 1879 | list_agent:- 1880 | forall( 1881 | ( 1882 | agent_GUID(G,_H,P) 1883 | ), 1884 | ( 1885 | writeln('Identifier : '),write(G),write('||| Port : '),write(P),nl,nl 1886 | ) 1887 | ). 1888 | 1889 | 1890 | list_agent(G,P):- 1891 | agent_GUID(G,_,P),!. 1892 | */ 1893 | %------------------------------------------------------ 1894 | 1895 | % hide all inbuilt predicates from user to avoid interference with user defined predicates in case of concurrency . test its working.... 1896 | 1897 | hide_mycode:- 1898 | noprofile(setup_Tartarus_IITG/0), 1899 | noprofile(platform_port/1), 1900 | noprofile(execs/1), 1901 | noprofile(agent_GUID/3), 1902 | noprofile(agent_payload/2), 1903 | noprofile(outgoing_agent/3), 1904 | noprofile(hoptime_stat/4), 1905 | noprofile(agent_token/2), 1906 | noprofile(transit_GUID/3), 1907 | noprofile(transit_payload/2), 1908 | noprofile(transit_token/2), 1909 | noprofile(transit_code/2), 1910 | noprofile(platform_token/1), 1911 | noprofile(code_base/2), 1912 | noprofile(do/1), 1913 | noprofile(start_db/1), 1914 | noprofile(handler/3), 1915 | noprofile(assert_code_Tartarus_IITG/1), 1916 | noprofile(retract_code_Tartarus_IITG/1), 1917 | noprofile(file_to_list_Tartarus_IITG/2), 1918 | noprofile(inquire_Tartarus_IITG/1), 1919 | noprofile(predicate_header/4), 1920 | noprofile(replace_underscore/3), 1921 | noprofile(insert_underscores/1), 1922 | noprofile(generatePayloadCode/1), 1923 | noprofile(genhandler/2), 1924 | noprofile(generate_unique_predicate/4), 1925 | noprofile(generate_generic_predicate/4), 1926 | noprofile(write_unique_code/1), 1927 | noprofile(assimilate_code/2), 1928 | noprofile(assimilate_handler_code/3), 1929 | noprofile(assimilate_payload_code/4), 1930 | noprofile(replaceGUID/4), 1931 | noprofile(hoptime_rec/2), 1932 | noprofile(substitute/4), 1933 | noprofile(substitute_all/4), 1934 | noprofile(unify_with_empty_list/1), 1935 | noprofile(redo/1), 1936 | noprofile(delete_x/1), 1937 | noprofile(delete_list/1), 1938 | noprofile(replace/1). 1939 | 1940 | hide_mycode:- true. 1941 | 1942 | %--------------------------------------------------------- 1943 | 1944 | timeout(Name,Status):- writeln(Name),write(' : gave a timeout'),write(Status),nl. 1945 | 1946 | %--------------------------------------------------------- 1947 | 1948 | substitute(Source, Tag, Content, X) :- 1949 | append(Tag, After, TagAndAfter), 1950 | append(Before, TagAndAfter, Source), 1951 | append(Before, Content, BeforeAndContent), 1952 | append(BeforeAndContent, After, X). 1953 | 1954 | substitute_all(Source, Tag, Content, X) :- 1955 | append(Tag, After, TagAndAfter), 1956 | append(Before, TagAndAfter, Source), 1957 | append(Before, Content, BeforeAndContent), 1958 | append(BeforeAndContent, FinalAfter, X), 1959 | !, 1960 | substitute_all(After, Tag, Content, FinalAfter). 1961 | 1962 | substitute_all(Source, _, _, Source). 1963 | 1964 | 1965 | %---------------------------------------------------------- 1966 | 1967 | aborted :- 1968 | nl, 1969 | write('! ----------------------------------------'),nl, 1970 | write('! ERROR (CHECK PARAMETERS)----------------'),nl, 1971 | write('! ----------------------------------------'),nl, 1972 | abort. 1973 | 1974 | %---------------------------------------------------------- 1975 | 1976 | unify_with_empty_list([],[]). 1977 | redo. 1978 | redo:-redo. 1979 | nothing. 1980 | 1981 | %---------------------------------------------------------- 1982 | 1983 | delete_x(X,[X|T],T). 1984 | delete_x(X,[Y|T],[Y|NT]):-delete_x(X,T,NT). 1985 | 1986 | %---------------------------------------------------------- 1987 | 1988 | delete_list([H|T],[H|T],[]). 1989 | delete_list([X1|Y1],Incoming,Outgoing):- 1990 | delete_x(X1,Incoming,NextIncoming), 1991 | delete_list(Y1,NextIncoming,Outgoing). 1992 | delete_list([],Incoming,Incoming). 1993 | 1994 | %----------------------------------------------------------- 1995 | % add_tail(+List,+Element,-List) 1996 | % Add the given element to the end of the list, without using the "append" predicate. 1997 | add_tail([],X,[X]). 1998 | add_tail([H|T],X,[H|L]):-add_tail(T,X,L). 1999 | %----------------------------------------------------------------------- 2000 | replace([],_A,_B,[]). 2001 | replace([H|T],A,B,[B|Result]) :- 2002 | H=A, 2003 | replace(T,A,B,Result),!. 2004 | replace([H|T],A,B,[H|Result]) :- 2005 | replace(T,A,B,Result). 2006 | 2007 | %----------------------------------------------------------------- 2008 | 2009 | insert_underscores(0). 2010 | insert_underscores(No):- 2011 | write(',_'), 2012 | UnderscoresLeft is No - 1, 2013 | insert_underscores(UnderscoresLeft). 2014 | 2015 | %----------------------------------------------------------------- 2016 | 2017 | write_unique_code([],File):- 2018 | open(File,write,X), 2019 | close(X). 2020 | 2021 | write_unique_code(Code,File):- 2022 | open(File,write,X), 2023 | current_output(Y), 2024 | set_output(X), 2025 | write_unique_code2(Code), 2026 | set_output(Y), 2027 | close(X). 2028 | 2029 | write_unique_code2([Head|Tail]):- 2030 | with_output_to(atom(X),portray_clause(Head)), 2031 | write(X),nl, 2032 | write_unique_code2(Tail). 2033 | 2034 | write_unique_code2([]):-true. 2035 | 2036 | %----------------------------------------------------------------- 2037 | 2038 | /*get_ip(Ip):- 2039 | gethostname(Hostname), 2040 | tcp_host_to_address(Hostname,RawIP), 2041 | ip(I1,I2,I3,I4)=RawIP, 2042 | atom_concat(I1,.,R1),atom_concat(R1,I2,R2), 2043 | atom_concat(R2,.,R3),atom_concat(R3,I3,R4), 2044 | atom_concat(R4,.,R5),atom_concat(R5,I4,Ip). 2045 | 2046 | */ 2047 | 2048 | %--Get_ip: Ubuntu version--% 2049 | 2050 | get_ip(Ip):- 2051 | process_create(path(hostname),['-I'],[stdout(pipe(O))]), 2052 | read_stream_to_codes(O,C1), 2053 | delete(C1,10,C2),delete(C2,32,C3), 2054 | string_codes(S,C3), 2055 | atom_string(Ip,S),close(O). 2056 | 2057 | 2058 | %===========================================debugging utilities================================================== 2059 | print_tartarus_status:- 2060 | print_platform_status. 2061 | 2062 | print_tartarus_status:- 2063 | print_message(warning,'print_tartarus_status/0 failed!'). 2064 | 2065 | 2066 | print_platform_status:- 2067 | ttyflush, 2068 | platform_Ip(Y),write('platform_Ip : '),write(Y),write(' '), 2069 | platform_port(X),write('platform_port : '),write(X),nl, 2070 | (agent_GUID(_,_,_)-> 2071 | writeln('-------------------------------------------'), 2072 | forall(agent_GUID(X1,Y1,Z1),(write('Agent_GUID: '),write(X1),write('|'),write(Y1),write('|'),write(Z1),nl)) 2073 | ;nothing), 2074 | (agent_payload(_,_)-> 2075 | writeln('-------------------------------------------'), 2076 | forall(agent_payload(X2,Y2),(write('Agent_payload: '),write(X2),write('|'),write(Y2),nl)) 2077 | ;nothing), 2078 | (outgoing_agent(_,_,_)-> 2079 | writeln('-------------------------------------------'), 2080 | forall(outgoing_agent(X3,Y3,Z3),(write('outgoing_agent: '),write(X3),write('|'),write(Y3),write('|'),write(Z3),nl)) 2081 | ;nothing), 2082 | (agent_token(_,_)-> 2083 | writeln('-------------------------------------------'), 2084 | forall(agent_token(X4,Y4),(write('Agent_token: '),write(X4),write('|'),write(Y4),nl)) 2085 | ;nothing), 2086 | (platform_token(_)-> 2087 | writeln('-------------------------------------------'), 2088 | forall(platform_token(X5),(write('platform_token: '),write(X5),nl)) 2089 | ;nothing), 2090 | (transit_GUID(_,_,_)-> 2091 | writeln('-------------------------------------------'), 2092 | forall(transit_GUID(X6,Y6,Z6),(write('transit_GUID: '),write(X6),write('|'),write(Y6),write('|'),write(Z6),nl)) 2093 | ;nothing), 2094 | (transit_payload(_,_)-> 2095 | writeln('-------------------------------------------'), 2096 | forall(transit_payload(X7,Y7),(write('transit_payload: '),write(X7),write('|'),write(Y7),nl)) 2097 | ;nothing), 2098 | (transit_token(_,_)-> 2099 | writeln('-------------------------------------------'), 2100 | forall(transit_token(X8,Y8),(write('transit_token: '),write(X8),write('|'),write(Y8),nl)) 2101 | ;nothing), 2102 | (transit_code(_,_)-> 2103 | writeln('-------------------------------------------'), 2104 | forall(transit_code(X9,Y9),(write('transit_code: '),write(X9),write('|'),write(Y9),nl)) 2105 | ;nothing), 2106 | (transit_agent(_,_)-> 2107 | writeln('-------------------------------------------'), 2108 | forall(transit_agent(X10,Y10),(write('transit_agent: '),write(X10),write('|'),write(Y10),nl)) 2109 | ;nothing), 2110 | (code_base(_,_)-> 2111 | writeln('-------------------------------------------'), 2112 | forall(code_base(X11,Y11),(write('code_base: '),write(X11),write('|'),write(Y11),nl)) 2113 | ;nothing), 2114 | writeln('-------------------------------------------'), 2115 | forall(guid_threadid(X12,Y12),(write('guid_threadid: '),write(X12),write('|'),write(Y12),nl)), 2116 | writeln('-------------------------------------------'),ttyflush. 2117 | 2118 | %%Set the Tartarus GUI server IP and Port 2119 | set_gui_server(Ip,Port):- 2120 | retractall(gui_server_Ip(_)), 2121 | retractall(gui_server_Port(_)), 2122 | assert(gui_server_Port(Port)), 2123 | assert(gui_server_Ip(Ip)). 2124 | 2125 | %% Add agent position on GUI 2126 | set_position(Agent_name, Source):- 2127 | gui_server_Port(Port), 2128 | gui_server_Ip(Ip), 2129 | tcp_socket(Socket), 2130 | tcp_connect(Socket,Ip:Port), 2131 | tcp_open_socket(Socket,_In,Out), 2132 | format(Out,'~q-~q-~q\n',[0,Agent_name, Source]), 2133 | flush_output(Out), 2134 | close(Out). 2135 | 2136 | 2137 | %% Remove agent from GUI 2138 | remove_position(Agent_name, Source):- 2139 | gui_server_Port(Port), 2140 | gui_server_Ip(Ip), 2141 | tcp_socket(Socket), 2142 | tcp_connect(Socket,Ip:Port), 2143 | tcp_open_socket(Socket,_In,Out), 2144 | format(Out,'~q-~q-~q\n',[1,Agent_name, Source]), 2145 | flush_output(Out), 2146 | close(Out). 2147 | 2148 | 2149 | %% ------------------------------------------------------------------------------------------------------------ 2150 | %% ---- Tartarus Peripheral Interface code starts here 2151 | %% ----- Embedded into single file for portability 2152 | %% ----- As of now raspberry Pi is supported. 2153 | %% ----- WiringPi Prolog Library must be installed for this to work 2154 | 2155 | 2156 | 2157 | 2158 | %% Start the peripheral interface 2159 | start_peripherals :- 2160 | writeln('Initializing Tartarus Peripheral Interface'), 2161 | tpi_init. 2162 | 2163 | 2164 | %% Tartarus Peripheral interface 2165 | %% Author: Midhul Varma 2166 | %% TODO: Take care of synchronization 2167 | 2168 | :- use_module(library(persistency)). 2169 | 2170 | :- persistent device(devid:atom, iface:atom, aux:any, api:atom). 2171 | 2172 | %% Initializing TPI 2173 | %% Database is initialized 2174 | tpi_init :- 2175 | %% WiringPi setup 2176 | file_search_path(swi, SwiHome), 2177 | directory_file_path(SwiHome, 'wipi/corefunc.so', Corefunc), 2178 | load_foreign_library(Corefunc), 2179 | directory_file_path(SwiHome, 'wipi/i2c.so', I2c), 2180 | load_foreign_library(I2c), 2181 | directory_file_path(SwiHome, 'wipi/setup.so', Setup), 2182 | load_foreign_library(Setup), 2183 | directory_file_path(SwiHome, 'wipi/specifics.so', Specifics), 2184 | load_foreign_library(Specifics), 2185 | directory_file_path(SwiHome, 'wipi/timing.so', Timing), 2186 | load_foreign_library(Timing), 2187 | directory_file_path(SwiHome, 'wipi/interrupt.so', Interrupt), 2188 | load_foreign_library(Interrupt), 2189 | directory_file_path(SwiHome, 'wipi/modes.pl', Modes), 2190 | consult(Modes), 2191 | wiringPiSetup, 2192 | absolute_file_name('devices.db', File, [access(write)]), 2193 | db_attach(File, []), 2194 | %% Initialize all devices 2195 | forall(device(DevId,DevClass,_,Api), ( 2196 | (Api=nothing -> true ; consult(Api),tpi_init_device(DevClass, DevId)), 2197 | mutex_create(DevId) 2198 | )). 2199 | 2200 | %% Register device 2201 | register_device(DevId, Iface, Aux) :- 2202 | assert_device(DevId, Iface, Aux, nothing), 2203 | mutex_create(DevId). 2204 | 2205 | register_device(DevId, Iface, Aux, Api) :- 2206 | consult(Api), 2207 | absolute_file_name(Api, FApi), 2208 | assert_device(DevId, Iface, Aux, FApi), 2209 | mutex_create(DevId), 2210 | tpi_init_device(Iface, DevId). 2211 | 2212 | %% Get device 2213 | get_device(DevId, Iface, Aux) :- 2214 | device(DevId, Iface, Aux, _). 2215 | 2216 | %% Remove device 2217 | remove_device(DevId, Iface, Aux) :- 2218 | mutex_destroy(DevId), 2219 | retract_device(DevId, Iface, Aux, _). 2220 | 2221 | remove_device_all(DevId, Iface, Aux) :- 2222 | forall(get_device(DevId, Iface, Aux), (mutex_destroy(DevId))), 2223 | retractall_device(DevId, Iface, Aux, _). 2224 | 2225 | %% Execute goal aotmically 2226 | device_exec_atomic(DevId, Goal) :- 2227 | with_mutex(DevId, Goal). 2228 | --------------------------------------------------------------------------------