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 <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
 
971 runge 62
	string basePath = Settings::get("BasePath") + "Services/";
969 runge 63
	string scriptName = "Base.js";
971 runge 64
	string scriptFileName = basePath + "System/" + scriptName;
969 runge 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));
971 runge 84
	myGlobal->Set(String::New("startIntervalThread"), FunctionTemplate::New(VirtualMachine_startIntervalThread));
85
	myGlobal->Set(String::New("stopIntervalThread"), FunctionTemplate::New(VirtualMachine_stopIntervalThread));
969 runge 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
 
970 runge 122
			if (file_exists(basePath + "Autostart.js"))
123
			{
124
				loadScript("Autostart.js");
125
			}
126
 
969 runge 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
 
971 runge 259
unsigned int VirtualMachine::startIntervalThread(unsigned int timeout)
969 runge 260
{
971 runge 261
	IntervalThread intervalThread(timeout);
969 runge 262
 
971 runge 263
	myIntervalThreads[intervalThread.getId()] = intervalThread;
264
	myIntervalThreads[intervalThread.getId()].start();
969 runge 265
 
971 runge 266
	return intervalThread.getId();
969 runge 267
}
268
 
971 runge 269
bool VirtualMachine::stopIntervalThread(unsigned int id)
969 runge 270
{
971 runge 271
	if (myIntervalThreads.find(id) != myIntervalThreads.end())
969 runge 272
	{
971 runge 273
		myIntervalThreads.erase(id);
969 runge 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
 
971 runge 382
Handle<Value> VirtualMachine_startIntervalThread(const Arguments& args)
969 runge 383
{
384
	VirtualMachine &vm = VirtualMachine::getInstance();
385
 
971 runge 386
	unsigned int timeout = args[0]->Uint32Value();
969 runge 387
 
971 runge 388
	return Integer::New(vm.startIntervalThread(timeout));
969 runge 389
}
390
 
971 runge 391
Handle<Value> VirtualMachine_stopIntervalThread(const Arguments& args)
969 runge 392
{
393
	VirtualMachine &vm = VirtualMachine::getInstance();
394
 
971 runge 395
	unsigned int id = args[1]->Uint32Value();
969 runge 396
 
971 runge 397
	return Integer::New(vm.stopIntervalThread(id));
969 runge 398
}