Subversion Repositories HomeAutomation

Rev

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