Subversion Repositories HomeAutomation

Rev

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