Subversion Repositories HomeAutomation

Rev

Rev 969 | Rev 971 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. /***************************************************************************
  2.  *   Copyright (C) December 10, 2008 by Mattias Runge                             *
  3.  *   mattias@runge.se                                                      *
  4.  *   virtualmachine.cpp                                            *
  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 2 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, write to the                         *
  18.  *   Free Software Foundation, Inc.,                                       *
  19.  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  20.  ***************************************************************************/
  21.  
  22. #include <map>
  23.  
  24.  
  25. #include "virtualmachine.h"
  26.  
  27. VirtualMachine* VirtualMachine::myInstance = NULL;
  28.  
  29. VirtualMachine& VirtualMachine::getInstance()
  30. {
  31.     if (myInstance == NULL)
  32.     {
  33.         myInstance = new VirtualMachine();
  34.     }
  35.  
  36.     return *myInstance;
  37. }
  38.  
  39. void VirtualMachine::deleteInstance()
  40. {
  41.     if (myInstance != NULL)
  42.     {
  43.         delete myInstance;
  44.         myInstance = NULL;
  45.     }
  46. }
  47.  
  48. VirtualMachine::VirtualMachine()
  49. {
  50.    
  51. }
  52.  
  53. VirtualMachine::~VirtualMachine()
  54. {
  55.    
  56. }
  57.  
  58. void VirtualMachine::run()
  59. {
  60.     SyslogStream &slog = SyslogStream::getInstance();
  61.  
  62.     string basePath = Settings::get("BasePath") + "/Services/System/";
  63.     string scriptName = "Base.js";
  64.     string scriptFileName = basePath + scriptName;
  65.  
  66.     if (!file_exists(scriptFileName))
  67.     {
  68.         slog << "Failed to load :" << scriptFileName << "\n";
  69.     }
  70.  
  71.     string scriptSource = file_get_contents(scriptFileName);
  72.  
  73.     Handle<String> source =  String::New(scriptSource.c_str(), scriptSource.length());
  74.     //each script name must be unique , for this demo I just run one embedded script, so the name can be fixed
  75.     Handle<String> name = String::New(scriptName.c_str(), scriptName.length());
  76.  
  77.     // Create a template for the global object.
  78.     myGlobal = ObjectTemplate::New();
  79.  
  80.     //associates "print" on script to the Print function
  81.     myGlobal->Set(String::New("log"), FunctionTemplate::New(VirtualMachine_log));
  82.     myGlobal->Set(String::New("sendCanMessage"), FunctionTemplate::New(VirtualMachine_sendCanMessage));
  83.     myGlobal->Set(String::New("loadScript"), FunctionTemplate::New(VirtualMachine_loadScript));
  84.     myGlobal->Set(String::New("setTimeout"), FunctionTemplate::New(VirtualMachine_setTimeout));
  85.     myGlobal->Set(String::New("setInterval"), FunctionTemplate::New(VirtualMachine_setInterval));
  86.     myGlobal->Set(String::New("clearTimeout"), FunctionTemplate::New(VirtualMachine_clearInterval));
  87.     myGlobal->Set(String::New("clearInterval"), FunctionTemplate::New(VirtualMachine_clearInterval));
  88.  
  89.     //create context for the script
  90.     myContext = Context::New(NULL, myGlobal);
  91.  
  92.  
  93.     //access global context within this scope
  94.     Context::Scope context_scope(myContext);
  95.     //exception handler
  96.     TryCatch try_catch;
  97.     //compile script to binary code - JIT
  98.     Handle<Script> script = Script::Compile(source, name);
  99.  
  100.     //check if we got problems on compilation
  101.     if (script.IsEmpty())
  102.     {
  103.  
  104.         // Print errors that happened during compilation.
  105.         String::AsciiValue error(try_catch.Exception());
  106.         slog << "Failed to compile script: " << *error << "\n";
  107.     }
  108.     else
  109.     {
  110.         //no errors , let's continue
  111.         Handle<Value> result = script->Run();
  112.  
  113.         //check if execution ended with errors
  114.         if (result.IsEmpty())
  115.         {
  116.             // Print errors that happened during execution.
  117.             String::AsciiValue error(try_catch.Exception());
  118.             slog << "Constructor: Failed to run script: " << *error << "\n";
  119.         }
  120.         else
  121.         {
  122.             loadScript("System/Service.js");
  123.             loadScript("System/ServiceManager.js");
  124.             loadScript("System/CanMessage.js");
  125.             loadScript("System/CanManager.js");
  126.             loadScript("System/CanService.js");
  127.             loadScript("System/Startup.js");
  128.  
  129.             if (file_exists(basePath + "Autostart.js"))
  130.             {
  131.                 loadScript("Autostart.js");
  132.             }
  133.            
  134.             myFunctionHandleHeartbeat = Handle<Function>::Cast(myContext->Global()->Get(String::New("handleHeartbeat")));
  135.             myFunctionOfflineCheck = Handle<Function>::Cast(myContext->Global()->Get(String::New("offlineCheck")));
  136.             myFunctionHandleMessage = Handle<Function>::Cast(myContext->Global()->Get(String::New("handleMessage")));
  137.             myFunctionStartup = Handle<Function>::Cast(myContext->Global()->Get(String::New("startup")));
  138.         }
  139.     }
  140.  
  141.     const int argc = 0;
  142.     Handle<Value> argv[argc] = { };
  143.  
  144.     Handle<Value> result = myFunctionStartup->Call(myFunctionStartup, argc, argv); // argc and argv are your standard arguments to a function
  145.  
  146.     mySemaphore.lock();
  147.  
  148.     while (1)
  149.     {
  150.         string expression;
  151.  
  152.         while (myExpressions.size() > 0)
  153.         {
  154.             expression = myExpressions.pop();
  155.  
  156.             runExpression(expression);
  157.         }
  158.  
  159.         CanMessage canMessage;
  160.  
  161.         while (myCanMessages.size() > 0)
  162.         {
  163.             canMessage = myCanMessages.pop();
  164.  
  165.             if (canMessage.isHeartbeat())
  166.             {
  167.                 callHandleHeartbeat(stoi(canMessage.getData()["HardwareId"].getValue()));
  168.             }
  169.             else
  170.             {
  171.                 callHandleMessage(canMessage);
  172.             }
  173.         }
  174.  
  175.         mySemaphore.wait();
  176.     }
  177.  
  178.     mySemaphore.unlock();
  179. }
  180.  
  181. void VirtualMachine::queueCanMessage(CanMessage canMessage)
  182. {
  183.     myCanMessages.push(canMessage);
  184.     mySemaphore.broadcast();
  185. }
  186.  
  187. void VirtualMachine::queueExpression(string expression)
  188. {
  189.     myExpressions.push(expression);
  190.     mySemaphore.broadcast();
  191. }
  192.  
  193. bool VirtualMachine::loadScript(string scriptName)
  194. {
  195.     SyslogStream &slog = SyslogStream::getInstance();
  196.  
  197.     string basePath = Settings::get("BasePath") + "/Services/";
  198.     string scriptFileName = basePath + scriptName;
  199.  
  200.     if (!file_exists(scriptFileName))
  201.     {
  202.         slog << "Failed to load :" << scriptFileName << "\n";
  203.         return false;
  204.     }
  205.  
  206.     string scriptSource = file_get_contents(scriptFileName);
  207.  
  208.     Handle<String> source =  String::New(scriptSource.c_str(), scriptSource.length());
  209.     //each script name must be unique , for this demo I just run one embedded script, so the name can be fixed
  210.     Handle<String> name = String::New(scriptName.c_str(), scriptName.length());
  211.  
  212.     //access global context within this scope
  213.     Context::Scope context_scope(myContext);
  214.     //exception handler
  215.     TryCatch try_catch;
  216.     //compile script to binary code - JIT
  217.     Handle<Script> script = Script::Compile(source, name);
  218.  
  219.     //check if we got problems on compilation
  220.     if (script.IsEmpty())
  221.     {
  222.         // Print errors that happened during compilation.
  223.         String::AsciiValue error(try_catch.Exception());
  224.         slog << "Failed to compile script: " << *error << "\n";
  225.         return false;
  226.     }
  227.     else
  228.     {
  229.         //no errors , let's continue
  230.         Handle<Value> result = script->Run();
  231.  
  232.         //check if execution ended with errors
  233.         if (result.IsEmpty())
  234.         {
  235.             // Print errors that happened during execution.
  236.             String::AsciiValue error(try_catch.Exception());
  237.             slog << "loadScript: Failed to run script: " << *error << "\n";
  238.             return false;
  239.         }
  240.     }
  241.  
  242.     return true;
  243. }
  244.  
  245. void VirtualMachine::callHandleHeartbeat(int hardwareId)
  246. {
  247.     const int argc = 1;
  248.     Handle<Value> argv[argc] = { Integer::New(hardwareId) };
  249.  
  250.     Handle<Value> result = myFunctionHandleHeartbeat->Call(myFunctionHandleHeartbeat, argc, argv); // argc and argv are your standard arguments to a function
  251. }
  252.  
  253. void VirtualMachine::callHandleMessage(CanMessage canMessage)
  254. {
  255.     const int argc = 6;
  256.     Handle<Value> argv[argc] = {String::New(canMessage.getClassName().c_str()),
  257.                                 String::New(canMessage.getDirectionFlag().c_str()),
  258.                                 String::New(canMessage.getModuleName().c_str()),
  259.                                 Integer::New(canMessage.getModuleId()),
  260.                                 String::New(canMessage.getCommandName().c_str()),
  261.                                 String::New(canMessage.getJSONData().c_str()) };
  262.  
  263.     Handle<Value> result = myFunctionHandleMessage->Call(myFunctionHandleMessage, argc, argv); // argc and argv are your standard arguments to a function
  264. }
  265.  
  266. int VirtualMachine::setInterval(string expression, int interval, bool single)
  267. {
  268.     IntervalThread intervalThread(expression, interval, single);
  269.     intervalThread.start();
  270.  
  271.     int timeoutId = myTimers.size();
  272.     myTimers[timeoutId] = intervalThread;
  273.     myTimers[timeoutId].start();
  274.  
  275.     return timeoutId;
  276. }
  277.  
  278. bool VirtualMachine::clearInterval(int timeoutId)
  279. {
  280.     if (myTimers.find(timeoutId) != myTimers.end())
  281.     {
  282.         myTimers.erase(timeoutId);
  283.         return true;
  284.     }
  285.  
  286.     return false;
  287. }
  288.  
  289. bool VirtualMachine::runExpression(string expression)
  290. {
  291.     SyslogStream &slog = SyslogStream::getInstance();
  292.  
  293.     string scriptName = "runExpression";
  294.  
  295.     Handle<String> source =  String::New(expression.c_str(), expression.length());
  296.     //each script name must be unique , for this demo I just run one embedded script, so the name can be fixed
  297.     Handle<String> name = String::New(scriptName.c_str(), scriptName.length());
  298.  
  299.     //access global context within this scope
  300.     Context::Scope context_scope(myContext);
  301.     //exception handler
  302.     TryCatch try_catch;
  303.     //compile script to binary code - JIT
  304.     Handle<Script> script = Script::Compile(source, name);
  305.  
  306.     //check if we got problems on compilation
  307.     if (script.IsEmpty())
  308.     {
  309.         // Print errors that happened during compilation.
  310.         String::AsciiValue error(try_catch.Exception());
  311.         slog << "Failed to compile script: " << *error << "\n";
  312.        
  313.         return false;
  314.     }
  315.     else
  316.     {
  317.         //no errors , let's continue
  318.         Handle<Value> result = script->Run();
  319.  
  320.         //check if execution ended with errors
  321.         if (result.IsEmpty())
  322.         {
  323.             // Print errors that happened during execution.
  324.             String::AsciiValue error(try_catch.Exception());
  325.             slog << "runExpression: Failed to run script: " << *error << "\n";
  326.             return false;
  327.         }
  328.     }
  329.  
  330.     return true;
  331. }
  332.  
  333. Handle<Value> VirtualMachine_log(const Arguments& args)
  334. {
  335.     SyslogStream &slog = SyslogStream::getInstance();
  336.  
  337.     String::AsciiValue str(args[0]);
  338.  
  339.     slog << *str;
  340.  
  341.     return Undefined();
  342. }
  343.  
  344. Handle<Value> VirtualMachine_sendCanMessage(const Arguments& args)
  345. {
  346.     SyslogStream &slog = SyslogStream::getInstance();
  347.     CanNetManager &canMan = CanNetManager::getInstance();
  348.  
  349.     CanMessage canMessage;
  350.  
  351.     String::AsciiValue className(args[0]);
  352.     canMessage.setClassName(*className);
  353.     String::AsciiValue directionFlag(args[1]);
  354.     canMessage.setDirectionFlag(*directionFlag);
  355.     String::AsciiValue moduleName(args[2]);
  356.     canMessage.setModuleName(*moduleName);
  357.     canMessage.setModuleId(args[3]->Uint32Value());
  358.     String::AsciiValue commandName(args[4]);
  359.     canMessage.setCommandName(*commandName);
  360.  
  361.     String::AsciiValue dataString(args[5]);
  362.  
  363.     vector<string> parts = explode(",", trim(*dataString, ','));
  364.     map<string, CanVariable> data;
  365.  
  366.     for (int n = 0; n < parts.size(); n++)
  367.     {
  368.         vector<string> keyAndValue = explode(":", parts[n]);
  369.  
  370.         //string key = trim(keyAndValue[0], ' ');
  371.         //string value = trim(keyAndValue[1], ' ');
  372.         data[keyAndValue[0]] = CanVariable(keyAndValue[0], keyAndValue[1]);
  373.     }
  374.  
  375.     canMessage.setData(data);
  376.    
  377.     canMan.sendMessage(canMessage);
  378.  
  379.     return Undefined();
  380. }
  381.  
  382. Handle<Value> VirtualMachine_loadScript(const Arguments& args)
  383. {
  384.     VirtualMachine &vm = VirtualMachine::getInstance();
  385.  
  386.     String::AsciiValue str(args[0]);
  387.  
  388.     return Boolean::New(vm.loadScript(*str));
  389. }
  390.  
  391. Handle<Value> VirtualMachine_setInterval(const Arguments& args)
  392. {
  393.     VirtualMachine &vm = VirtualMachine::getInstance();
  394.  
  395.     String::AsciiValue expression(args[0]);
  396.     unsigned int interval = args[1]->Uint32Value();
  397.  
  398.     return Integer::New(vm.setInterval(*expression, interval, false));
  399. }
  400.  
  401. Handle<Value> VirtualMachine_setTimeout(const Arguments& args)
  402. {
  403.     VirtualMachine &vm = VirtualMachine::getInstance();
  404.  
  405.     String::AsciiValue expression(args[0]);
  406.     unsigned int interval = args[1]->Uint32Value();
  407.  
  408.     return Integer::New(vm.setInterval(*expression, interval, true));
  409. }
  410.  
  411. Handle<Value> VirtualMachine_clearInterval(const Arguments& args)
  412. {
  413.     VirtualMachine &vm = VirtualMachine::getInstance();
  414.  
  415.     return Boolean::New(vm.clearInterval(args[0]->Uint32Value()));
  416. }
  417.