Subversion Repositories HomeAutomation

Rev

Details | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
969 runge 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
{
981 runge 47
	Thread<VirtualMachine>();
969 runge 48
}
49
 
50
VirtualMachine::~VirtualMachine()
51
{
981 runge 52
	stop();
969 runge 53
}
54
 
55
void VirtualMachine::run()
56
{
57
	SyslogStream &slog = SyslogStream::getInstance();
58
 
971 runge 59
	string basePath = Settings::get("BasePath") + "Services/";
969 runge 60
	string scriptName = "Base.js";
971 runge 61
	string scriptFileName = basePath + "System/" + scriptName;
969 runge 62
 
63
	if (!file_exists(scriptFileName))
64
	{
976 runge 65
		slog << "Failed to load :" + scriptFileName + "\n";
969 runge 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));
971 runge 81
	myGlobal->Set(String::New("startIntervalThread"), FunctionTemplate::New(VirtualMachine_startIntervalThread));
82
	myGlobal->Set(String::New("stopIntervalThread"), FunctionTemplate::New(VirtualMachine_stopIntervalThread));
976 runge 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));
981 runge 86
	myGlobal->Set(String::New("uint2hex"), FunctionTemplate::New(VirtualMachine_uint2hex));
969 runge 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());
976 runge 105
		string sError = *error;
106
		slog << "Failed to compile script: " + sError + "\n";
969 runge 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());
976 runge 118
			string sError = *error;
119
			slog << "Constructor: Failed to run script: " << sError << "\n";
969 runge 120
		}
121
		else
122
		{
123
			loadScript("System/Startup.js");
124
 
970 runge 125
			if (file_exists(basePath + "Autostart.js"))
126
			{
127
				loadScript("Autostart.js");
128
			}
129
 
969 runge 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
 
981 runge 193
	string basePath = Settings::get("BasePath") + "Services/";
969 runge 194
	string scriptFileName = basePath + scriptName;
195
 
196
	if (!file_exists(scriptFileName))
197
	{
981 runge 198
		slog << "Failed to load " + scriptFileName + "\n";
969 runge 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());
976 runge 220
		string sError = *error;
221
		slog << "loadScript: Failed to compile script: " + sError + "\n";
969 runge 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());
976 runge 234
			string sError = *error;
235
			slog << "loadScript: Failed to run script: " + sError + "\n";
969 runge 236
			return false;
237
		}
977 runge 238
 
239
		slog << "Loaded " + scriptName + "\n";
969 runge 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;
981 runge 256
 
257
	string jsonData = canMessage.getJSONData();
258
 
969 runge 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()),
981 runge 264
								String::New(jsonData.c_str()) };
969 runge 265
 
266
	Handle<Value> result = myFunctionHandleMessage->Call(myFunctionHandleMessage, argc, argv); // argc and argv are your standard arguments to a function
267
}
268
 
971 runge 269
unsigned int VirtualMachine::startIntervalThread(unsigned int timeout)
969 runge 270
{
971 runge 271
	IntervalThread intervalThread(timeout);
969 runge 272
 
971 runge 273
	myIntervalThreads[intervalThread.getId()] = intervalThread;
274
	myIntervalThreads[intervalThread.getId()].start();
969 runge 275
 
971 runge 276
	return intervalThread.getId();
969 runge 277
}
278
 
971 runge 279
bool VirtualMachine::stopIntervalThread(unsigned int id)
969 runge 280
{
971 runge 281
	if (myIntervalThreads.find(id) != myIntervalThreads.end())
969 runge 282
	{
971 runge 283
		myIntervalThreads.erase(id);
969 runge 284
		return true;
285
	}
286
 
287
	return false;
288
}
289
 
976 runge 290
unsigned int VirtualMachine::startSocketThread(string address, int port, unsigned int reconnectTimeout)
291
{
292
	SocketThread 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
	if (mySocketThreads.find(id) != mySocketThreads.end())
302
	{
303
		mySocketThreads.erase(id);
304
		return true;
305
	}
306
 
307
	return false;
308
}
309
 
310
void VirtualMachine::sendToSocketThread(unsigned int id, string data)
311
{
312
	if (mySocketThreads.find(id) != mySocketThreads.end())
313
	{
314
		mySocketThreads[id].send(data);
315
	}
316
}
317
 
969 runge 318
bool VirtualMachine::runExpression(string expression)
319
{
320
	SyslogStream &slog = SyslogStream::getInstance();
321
 
322
	string scriptName = "runExpression";
323
 
324
	Handle<String> source =  String::New(expression.c_str(), expression.length());
325
	//each script name must be unique , for this demo I just run one embedded script, so the name can be fixed
326
	Handle<String> name = String::New(scriptName.c_str(), scriptName.length());
327
 
328
	//access global context within this scope
329
	Context::Scope context_scope(myContext);
330
	//exception handler
331
	TryCatch try_catch;
332
	//compile script to binary code - JIT
333
	Handle<Script> script = Script::Compile(source, name);
334
 
335
	//check if we got problems on compilation
336
	if (script.IsEmpty())
337
	{
338
		// Print errors that happened during compilation.
339
		String::AsciiValue error(try_catch.Exception());
976 runge 340
		string sError = *error;
341
		slog << "runExpression: Failed to compile script: " + sError + "\n";
342
		slog << expression << "\n\n";
969 runge 343
		return false;
344
	}
345
	else
346
	{
347
		//no errors , let's continue
348
		Handle<Value> result = script->Run();
349
 
350
		//check if execution ended with errors
351
		if (result.IsEmpty())
352
		{
353
			// Print errors that happened during execution.
354
			String::AsciiValue error(try_catch.Exception());
976 runge 355
			string sError = *error;
356
			slog << "runExpression: Failed to run script: " + sError + "\n";
969 runge 357
			return false;
358
		}
359
	}
360
 
361
	return true;
362
}
363
 
364
Handle<Value> VirtualMachine_log(const Arguments& args)
365
{
366
	SyslogStream &slog = SyslogStream::getInstance();
367
 
368
	String::AsciiValue str(args[0]);
369
 
370
	slog << *str;
371
 
372
	return Undefined();
373
}
374
 
375
Handle<Value> VirtualMachine_sendCanMessage(const Arguments& args)
376
{
976 runge 377
	//SyslogStream &slog = SyslogStream::getInstance();
969 runge 378
	CanNetManager &canMan = CanNetManager::getInstance();
379
 
380
	CanMessage canMessage;
381
 
382
	String::AsciiValue className(args[0]);
383
	canMessage.setClassName(*className);
384
	String::AsciiValue directionFlag(args[1]);
385
	canMessage.setDirectionFlag(*directionFlag);
386
	String::AsciiValue moduleName(args[2]);
387
	canMessage.setModuleName(*moduleName);
388
	canMessage.setModuleId(args[3]->Uint32Value());
389
	String::AsciiValue commandName(args[4]);
390
	canMessage.setCommandName(*commandName);
391
 
392
	String::AsciiValue dataString(args[5]);
393
 
394
	vector<string> parts = explode(",", trim(*dataString, ','));
395
	map<string, CanVariable> data;
396
 
397
	for (int n = 0; n < parts.size(); n++)
398
	{
399
		vector<string> keyAndValue = explode(":", parts[n]);
400
 
401
		//string key = trim(keyAndValue[0], ' ');
402
		//string value = trim(keyAndValue[1], ' ');
403
		data[keyAndValue[0]] = CanVariable(keyAndValue[0], keyAndValue[1]);
404
	}
405
 
406
	canMessage.setData(data);
407
 
408
	canMan.sendMessage(canMessage);
409
 
410
	return Undefined();
411
}
412
 
413
Handle<Value> VirtualMachine_loadScript(const Arguments& args)
414
{
415
	VirtualMachine &vm = VirtualMachine::getInstance();
416
 
417
	String::AsciiValue str(args[0]);
418
 
419
	return Boolean::New(vm.loadScript(*str));
420
}
421
 
971 runge 422
Handle<Value> VirtualMachine_startIntervalThread(const Arguments& args)
969 runge 423
{
424
	VirtualMachine &vm = VirtualMachine::getInstance();
425
 
971 runge 426
	unsigned int timeout = args[0]->Uint32Value();
969 runge 427
 
971 runge 428
	return Integer::New(vm.startIntervalThread(timeout));
969 runge 429
}
430
 
971 runge 431
Handle<Value> VirtualMachine_stopIntervalThread(const Arguments& args)
969 runge 432
{
433
	VirtualMachine &vm = VirtualMachine::getInstance();
434
 
973 runge 435
	unsigned int id = args[0]->Uint32Value();
969 runge 436
 
976 runge 437
	return Boolean::New(vm.stopIntervalThread(id));
969 runge 438
}
976 runge 439
 
440
Handle<Value> VirtualMachine_startSocketThread(const Arguments& args)
441
{
442
	VirtualMachine &vm = VirtualMachine::getInstance();
443
 
444
	String::AsciiValue address(args[0]);
445
	int port = args[1]->Uint32Value();
446
	unsigned int reconnectTimeout = args[2]->Uint32Value();
447
 
448
	return Integer::New(vm.startSocketThread(*address, port, reconnectTimeout));
449
}
450
 
451
Handle<Value> VirtualMachine_stopSocketThread(const Arguments& args)
452
{
453
	VirtualMachine &vm = VirtualMachine::getInstance();
454
 
455
	unsigned int id = args[0]->Uint32Value();
456
 
457
	return Boolean::New(vm.stopSocketThread(id));
458
}
459
 
460
Handle<Value> VirtualMachine_sendToSocketThread(const Arguments& args)
461
{
462
	VirtualMachine &vm = VirtualMachine::getInstance();
463
 
464
	unsigned int id = args[0]->Uint32Value();
465
	String::AsciiValue data(args[1]);
466
 
467
	vm.sendToSocketThread(id, *data);
468
 
469
	return Undefined();
470
}
471
 
981 runge 472
Handle<Value> VirtualMachine_uint2hex(const Arguments& args)
473
{
474
	VirtualMachine &vm = VirtualMachine::getInstance();
475
 
476
	unsigned int id = args[0]->Uint32Value();
477
	unsigned int length = args[1]->Uint32Value();
478
	string hexId = uint2hex(id, length);
479
 
480
	return String::New(hexId.c_str());
481
}
482