Subversion Repositories HomeAutomation

Rev

Rev 970 | Blame | 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/";
  63.     string scriptName = "Base.js";
  64.     string scriptFileName = basePath + "System/" + 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("startIntervalThread"), FunctionTemplate::New(VirtualMachine_startIntervalThread));
  85.     myGlobal->Set(String::New("stopIntervalThread"), FunctionTemplate::New(VirtualMachine_stopIntervalThread));
  86.  
  87.     //create context for the script
  88.     myContext = Context::New(NULL, myGlobal);
  89.  
  90.  
  91.     //access global context within this scope
  92.     Context::Scope context_scope(myContext);
  93.     //exception handler
  94.     TryCatch try_catch;
  95.     //compile script to binary code - JIT
  96.     Handle<Script> script = Script::Compile(source, name);
  97.  
  98.     //check if we got problems on compilation
  99.     if (script.IsEmpty())
  100.     {
  101.  
  102.         // Print errors that happened during compilation.
  103.         String::AsciiValue error(try_catch.Exception());
  104.         slog << "Failed to compile script: " << *error << "\n";
  105.     }
  106.     else
  107.     {
  108.         //no errors , let's continue
  109.         Handle<Value> result = script->Run();
  110.  
  111.         //check if execution ended with errors
  112.         if (result.IsEmpty())
  113.         {
  114.             // Print errors that happened during execution.
  115.             String::AsciiValue error(try_catch.Exception());
  116.             slog << "Constructor: Failed to run script: " << *error << "\n";
  117.         }
  118.         else
  119.         {
  120.             loadScript("System/Startup.js");
  121.  
  122.             if (file_exists(basePath + "Autostart.js"))
  123.             {
  124.                 loadScript("Autostart.js");
  125.             }
  126.            
  127.             myFunctionHandleHeartbeat = Handle<Function>::Cast(myContext->Global()->Get(String::New("handleHeartbeat")));
  128.             myFunctionOfflineCheck = Handle<Function>::Cast(myContext->Global()->Get(String::New("offlineCheck")));
  129.             myFunctionHandleMessage = Handle<Function>::Cast(myContext->Global()->Get(String::New("handleMessage")));
  130.             myFunctionStartup = Handle<Function>::Cast(myContext->Global()->Get(String::New("startup")));
  131.         }
  132.     }
  133.  
  134.     const int argc = 0;
  135.     Handle<Value> argv[argc] = { };
  136.  
  137.     Handle<Value> result = myFunctionStartup->Call(myFunctionStartup, argc, argv); // argc and argv are your standard arguments to a function
  138.  
  139.     mySemaphore.lock();
  140.  
  141.     while (1)
  142.     {
  143.         string expression;
  144.  
  145.         while (myExpressions.size() > 0)
  146.         {
  147.             expression = myExpressions.pop();
  148.  
  149.             runExpression(expression);
  150.         }
  151.  
  152.         CanMessage canMessage;
  153.  
  154.         while (myCanMessages.size() > 0)
  155.         {
  156.             canMessage = myCanMessages.pop();
  157.  
  158.             if (canMessage.isHeartbeat())
  159.             {
  160.                 callHandleHeartbeat(stoi(canMessage.getData()["HardwareId"].getValue()));
  161.             }
  162.             else
  163.             {
  164.                 callHandleMessage(canMessage);
  165.             }
  166.         }
  167.  
  168.         mySemaphore.wait();
  169.     }
  170.  
  171.     mySemaphore.unlock();
  172. }
  173.  
  174. void VirtualMachine::queueCanMessage(CanMessage canMessage)
  175. {
  176.     myCanMessages.push(canMessage);
  177.     mySemaphore.broadcast();
  178. }
  179.  
  180. void VirtualMachine::queueExpression(string expression)
  181. {
  182.     myExpressions.push(expression);
  183.     mySemaphore.broadcast();
  184. }
  185.  
  186. bool VirtualMachine::loadScript(string scriptName)
  187. {
  188.     SyslogStream &slog = SyslogStream::getInstance();
  189.  
  190.     string basePath = Settings::get("BasePath") + "/Services/";
  191.     string scriptFileName = basePath + scriptName;
  192.  
  193.     if (!file_exists(scriptFileName))
  194.     {
  195.         slog << "Failed to load :" << scriptFileName << "\n";
  196.         return false;
  197.     }
  198.  
  199.     string scriptSource = file_get_contents(scriptFileName);
  200.  
  201.     Handle<String> source =  String::New(scriptSource.c_str(), scriptSource.length());
  202.     //each script name must be unique , for this demo I just run one embedded script, so the name can be fixed
  203.     Handle<String> name = String::New(scriptName.c_str(), scriptName.length());
  204.  
  205.     //access global context within this scope
  206.     Context::Scope context_scope(myContext);
  207.     //exception handler
  208.     TryCatch try_catch;
  209.     //compile script to binary code - JIT
  210.     Handle<Script> script = Script::Compile(source, name);
  211.  
  212.     //check if we got problems on compilation
  213.     if (script.IsEmpty())
  214.     {
  215.         // Print errors that happened during compilation.
  216.         String::AsciiValue error(try_catch.Exception());
  217.         slog << "Failed to compile script: " << *error << "\n";
  218.         return false;
  219.     }
  220.     else
  221.     {
  222.         //no errors , let's continue
  223.         Handle<Value> result = script->Run();
  224.  
  225.         //check if execution ended with errors
  226.         if (result.IsEmpty())
  227.         {
  228.             // Print errors that happened during execution.
  229.             String::AsciiValue error(try_catch.Exception());
  230.             slog << "loadScript: Failed to run script: " << *error << "\n";
  231.             return false;
  232.         }
  233.     }
  234.  
  235.     return true;
  236. }
  237.  
  238. void VirtualMachine::callHandleHeartbeat(int hardwareId)
  239. {
  240.     const int argc = 1;
  241.     Handle<Value> argv[argc] = { Integer::New(hardwareId) };
  242.  
  243.     Handle<Value> result = myFunctionHandleHeartbeat->Call(myFunctionHandleHeartbeat, argc, argv); // argc and argv are your standard arguments to a function
  244. }
  245.  
  246. void VirtualMachine::callHandleMessage(CanMessage canMessage)
  247. {
  248.     const int argc = 6;
  249.     Handle<Value> argv[argc] = {String::New(canMessage.getClassName().c_str()),
  250.                                 String::New(canMessage.getDirectionFlag().c_str()),
  251.                                 String::New(canMessage.getModuleName().c_str()),
  252.                                 Integer::New(canMessage.getModuleId()),
  253.                                 String::New(canMessage.getCommandName().c_str()),
  254.                                 String::New(canMessage.getJSONData().c_str()) };
  255.  
  256.     Handle<Value> result = myFunctionHandleMessage->Call(myFunctionHandleMessage, argc, argv); // argc and argv are your standard arguments to a function
  257. }
  258.  
  259. unsigned int VirtualMachine::startIntervalThread(unsigned int timeout)
  260. {
  261.     IntervalThread intervalThread(timeout);
  262.  
  263.     myIntervalThreads[intervalThread.getId()] = intervalThread;
  264.     myIntervalThreads[intervalThread.getId()].start();
  265.  
  266.     return intervalThread.getId();
  267. }
  268.  
  269. bool VirtualMachine::stopIntervalThread(unsigned int id)
  270. {
  271.     if (myIntervalThreads.find(id) != myIntervalThreads.end())
  272.     {
  273.         myIntervalThreads.erase(id);
  274.         return true;
  275.     }
  276.  
  277.     return false;
  278. }
  279.  
  280. bool VirtualMachine::runExpression(string expression)
  281. {
  282.     SyslogStream &slog = SyslogStream::getInstance();
  283.  
  284.     string scriptName = "runExpression";
  285.  
  286.     Handle<String> source =  String::New(expression.c_str(), expression.length());
  287.     //each script name must be unique , for this demo I just run one embedded script, so the name can be fixed
  288.     Handle<String> name = String::New(scriptName.c_str(), scriptName.length());
  289.  
  290.     //access global context within this scope
  291.     Context::Scope context_scope(myContext);
  292.     //exception handler
  293.     TryCatch try_catch;
  294.     //compile script to binary code - JIT
  295.     Handle<Script> script = Script::Compile(source, name);
  296.  
  297.     //check if we got problems on compilation
  298.     if (script.IsEmpty())
  299.     {
  300.         // Print errors that happened during compilation.
  301.         String::AsciiValue error(try_catch.Exception());
  302.         slog << "Failed to compile script: " << *error << "\n";
  303.        
  304.         return false;
  305.     }
  306.     else
  307.     {
  308.         //no errors , let's continue
  309.         Handle<Value> result = script->Run();
  310.  
  311.         //check if execution ended with errors
  312.         if (result.IsEmpty())
  313.         {
  314.             // Print errors that happened during execution.
  315.             String::AsciiValue error(try_catch.Exception());
  316.             slog << "runExpression: Failed to run script: " << *error << "\n";
  317.             return false;
  318.         }
  319.     }
  320.  
  321.     return true;
  322. }
  323.  
  324. Handle<Value> VirtualMachine_log(const Arguments& args)
  325. {
  326.     SyslogStream &slog = SyslogStream::getInstance();
  327.  
  328.     String::AsciiValue str(args[0]);
  329.  
  330.     slog << *str;
  331.  
  332.     return Undefined();
  333. }
  334.  
  335. Handle<Value> VirtualMachine_sendCanMessage(const Arguments& args)
  336. {
  337.     SyslogStream &slog = SyslogStream::getInstance();
  338.     CanNetManager &canMan = CanNetManager::getInstance();
  339.  
  340.     CanMessage canMessage;
  341.  
  342.     String::AsciiValue className(args[0]);
  343.     canMessage.setClassName(*className);
  344.     String::AsciiValue directionFlag(args[1]);
  345.     canMessage.setDirectionFlag(*directionFlag);
  346.     String::AsciiValue moduleName(args[2]);
  347.     canMessage.setModuleName(*moduleName);
  348.     canMessage.setModuleId(args[3]->Uint32Value());
  349.     String::AsciiValue commandName(args[4]);
  350.     canMessage.setCommandName(*commandName);
  351.  
  352.     String::AsciiValue dataString(args[5]);
  353.  
  354.     vector<string> parts = explode(",", trim(*dataString, ','));
  355.     map<string, CanVariable> data;
  356.  
  357.     for (int n = 0; n < parts.size(); n++)
  358.     {
  359.         vector<string> keyAndValue = explode(":", parts[n]);
  360.  
  361.         //string key = trim(keyAndValue[0], ' ');
  362.         //string value = trim(keyAndValue[1], ' ');
  363.         data[keyAndValue[0]] = CanVariable(keyAndValue[0], keyAndValue[1]);
  364.     }
  365.  
  366.     canMessage.setData(data);
  367.    
  368.     canMan.sendMessage(canMessage);
  369.  
  370.     return Undefined();
  371. }
  372.  
  373. Handle<Value> VirtualMachine_loadScript(const Arguments& args)
  374. {
  375.     VirtualMachine &vm = VirtualMachine::getInstance();
  376.  
  377.     String::AsciiValue str(args[0]);
  378.  
  379.     return Boolean::New(vm.loadScript(*str));
  380. }
  381.  
  382. Handle<Value> VirtualMachine_startIntervalThread(const Arguments& args)
  383. {
  384.     VirtualMachine &vm = VirtualMachine::getInstance();
  385.  
  386.     unsigned int timeout = args[0]->Uint32Value();
  387.  
  388.     return Integer::New(vm.startIntervalThread(timeout));
  389. }
  390.  
  391. Handle<Value> VirtualMachine_stopIntervalThread(const Arguments& args)
  392. {
  393.     VirtualMachine &vm = VirtualMachine::getInstance();
  394.  
  395.     unsigned int id = args[1]->Uint32Value();
  396.  
  397.     return Integer::New(vm.stopIntervalThread(id));
  398. }
  399.