/*
* Copyright (c) 2019, Mathias Küsel
* MIT License
*/
#include
namespace node_snap7 {
static uv_async_t event_async_g;
static uv_async_t rw_async_g;
static uv_mutex_t mutex_rw;
static uv_mutex_t mutex_event;
static uv_sem_t sem_rw;
static std::deque event_list_g;
static struct rw_event_baton_t {
int Sender;
int Operation;
TS7Tag Tag;
void *pUsrData;
} rw_event_baton_g;
void S7API EventCallBack(void *usrPtr, PSrvEvent PEvent, int Size) {
uv_mutex_lock(&mutex_event);
event_list_g.push_back(*PEvent);
uv_mutex_unlock(&mutex_event);
uv_async_send(&event_async_g);
}
int S7API RWAreaCallBack(void *usrPtr, int Sender, int Operation, PS7Tag PTag
, void *pUsrData
) {
uv_mutex_lock(&mutex_rw);
rw_event_baton_g.Sender = Sender;
rw_event_baton_g.Operation = Operation;
rw_event_baton_g.Tag = *PTag;
rw_event_baton_g.pUsrData = pUsrData;
uv_async_send(&rw_async_g);
uv_sem_wait(&sem_rw);
uv_mutex_unlock(&mutex_rw);
return 0;
}
Nan::Persistent S7Server::constructor;
NAN_MODULE_INIT(S7Server::Init) {
Nan::HandleScope scope;
v8::Local tpl;
tpl = Nan::New(S7Server::New);
v8::Local name = Nan::New("S7Server")
.ToLocalChecked();
tpl->SetClassName(name);
tpl->InstanceTemplate()->SetInternalFieldCount(1);
// Setup the prototype
Nan::SetPrototypeMethod(
tpl
, "Start"
, S7Server::Start);
Nan::SetPrototypeMethod(
tpl
, "StartTo"
, S7Server::StartTo);
Nan::SetPrototypeMethod(
tpl
, "Stop"
, S7Server::Stop);
Nan::SetPrototypeMethod(
tpl
, "SetParam"
, S7Server::SetParam);
Nan::SetPrototypeMethod(
tpl
, "GetParam"
, S7Server::GetParam);
Nan::SetPrototypeMethod(
tpl
, "SetResourceless"
, S7Server::SetResourceless);
Nan::SetPrototypeMethod(
tpl
, "RegisterArea"
, S7Server::RegisterArea);
Nan::SetPrototypeMethod(
tpl
, "UnregisterArea"
, S7Server::UnregisterArea);
Nan::SetPrototypeMethod(
tpl
, "LockArea"
, S7Server::LockArea);
Nan::SetPrototypeMethod(
tpl
, "UnlockArea"
, S7Server::UnlockArea);
Nan::SetPrototypeMethod(
tpl
, "SetArea"
, S7Server::SetArea);
Nan::SetPrototypeMethod(
tpl
, "GetArea"
, S7Server::GetArea);
Nan::SetPrototypeMethod(
tpl
, "SetEventMask"
, S7Server::SetEventsMask);
Nan::SetPrototypeMethod(
tpl
, "GetEventsMask"
, S7Server::GetEventsMask);
Nan::SetPrototypeMethod(
tpl
, "ErrorText"
, S7Server::ErrorText);
Nan::SetPrototypeMethod(
tpl
, "LastError"
, S7Server::LastError);
Nan::SetPrototypeMethod(
tpl
, "EventText"
, S7Server::EventText);
Nan::SetPrototypeMethod(
tpl
, "ServerStatus"
, S7Server::ServerStatus);
Nan::SetPrototypeMethod(
tpl
, "ClientsCount"
, S7Server::ClientsCount);
Nan::SetPrototypeMethod(
tpl
, "GetCpuStatus"
, S7Server::GetCpuStatus);
Nan::SetPrototypeMethod(
tpl
, "SetCpuStatus"
, S7Server::SetCpuStatus);
// Error codes
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errSrvCannotStart").ToLocalChecked()
, Nan::New(errSrvCannotStart)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errSrvDBNullPointer").ToLocalChecked()
, Nan::New(errSrvDBNullPointer)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errSrvAreaAlreadyExists").ToLocalChecked()
, Nan::New(errSrvAreaAlreadyExists)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errSrvUnknownArea").ToLocalChecked()
, Nan::New(errSrvUnknownArea)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errSrvInvalidParams").ToLocalChecked()
, Nan::New(errSrvInvalidParams)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errSrvTooManyDB").ToLocalChecked()
, Nan::New(errSrvTooManyDB)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errSrvInvalidParamNumber").ToLocalChecked()
, Nan::New(errSrvInvalidParamNumber)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("errSrvCannotChangeParam").ToLocalChecked()
, Nan::New(errSrvCannotChangeParam)
, v8::ReadOnly);
// Server area IDs
Nan::SetPrototypeTemplate(
tpl
, Nan::New("srvAreaPE").ToLocalChecked()
, Nan::New(srvAreaPE)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("srvAreaPA").ToLocalChecked()
, Nan::New(srvAreaPA)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("srvAreaMK").ToLocalChecked()
, Nan::New(srvAreaMK)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("srvAreaCT").ToLocalChecked()
, Nan::New(srvAreaCT)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("srvAreaTM").ToLocalChecked()
, Nan::New(srvAreaTM)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("srvAreaDB").ToLocalChecked()
, Nan::New(srvAreaDB)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("operationWrite").ToLocalChecked()
, Nan::New(OperationWrite)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("operationRead").ToLocalChecked()
, Nan::New(OperationRead)
, v8::ReadOnly);
// TCP server event codes
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evcServerStarted").ToLocalChecked()
, Nan::New(evcServerStarted)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evcServerStopped").ToLocalChecked()
, Nan::New(evcServerStopped)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evcListenerCannotStart").ToLocalChecked()
, Nan::New(evcListenerCannotStart)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evcClientAdded").ToLocalChecked()
, Nan::New(evcClientAdded)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evcClientRejected").ToLocalChecked()
, Nan::New(evcClientRejected)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evcClientNoRoom").ToLocalChecked()
, Nan::New(evcClientNoRoom)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evcClientException").ToLocalChecked()
, Nan::New(evcClientException)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evcClientDisconnected").ToLocalChecked()
, Nan::New(evcClientDisconnected)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evcClientTerminated").ToLocalChecked()
, Nan::New(evcClientTerminated)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evcClientsDropped").ToLocalChecked()
, Nan::New(evcClientsDropped)
, v8::ReadOnly);
// S7 server event codes
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evcPDUincoming").ToLocalChecked()
, Nan::New(evcPDUincoming)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evcDataRead").ToLocalChecked()
, Nan::New(evcDataRead)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evcDataWrite").ToLocalChecked()
, Nan::New(evcDataWrite)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evcNegotiatePDU").ToLocalChecked()
, Nan::New(evcNegotiatePDU)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evcReadSZL").ToLocalChecked()
, Nan::New(evcReadSZL)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evcClock").ToLocalChecked()
, Nan::New(evcClock)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evcUpload").ToLocalChecked()
, Nan::New(evcUpload)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evcDownload").ToLocalChecked()
, Nan::New(evcDownload)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evcDirectory").ToLocalChecked()
, Nan::New(evcDirectory)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evcSecurity").ToLocalChecked()
, Nan::New(evcSecurity)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evcControl").ToLocalChecked()
, Nan::New(evcControl)
, v8::ReadOnly);
// Masks to enable/disable all events
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evcAll").ToLocalChecked()
, Nan::New(evcAll)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evcNone").ToLocalChecked()
, Nan::New(evcNone)
, v8::ReadOnly);
// Event subcodes
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evsUnknown").ToLocalChecked()
, Nan::New(evsUnknown)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evsStartUpload").ToLocalChecked()
, Nan::New(evsStartUpload)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evsStartDownload").ToLocalChecked()
, Nan::New(evsStartDownload)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evsGetBlockList").ToLocalChecked()
, Nan::New(evsGetBlockList)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evsStartListBoT").ToLocalChecked()
, Nan::New(evsStartListBoT)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evsListBoT").ToLocalChecked()
, Nan::New(evsListBoT)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evsGetBlockInfo").ToLocalChecked()
, Nan::New(evsGetBlockInfo)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evsGetClock").ToLocalChecked()
, Nan::New(evsGetClock)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evsSetClock").ToLocalChecked()
, Nan::New(evsSetClock)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evsSetPassword").ToLocalChecked()
, Nan::New(evsSetPassword)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evsClrPassword").ToLocalChecked()
, Nan::New(evsClrPassword)
, v8::ReadOnly);
// Event params : functions group
Nan::SetPrototypeTemplate(
tpl
, Nan::New("grProgrammer").ToLocalChecked()
, Nan::New(grProgrammer)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("grCyclicData").ToLocalChecked()
, Nan::New(grCyclicData)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("grBlocksInfo").ToLocalChecked()
, Nan::New(grBlocksInfo)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("grSZL").ToLocalChecked()
, Nan::New(grSZL)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("grPassword").ToLocalChecked()
, Nan::New(grPassword)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("grBSend").ToLocalChecked()
, Nan::New(grBSend)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("grClock").ToLocalChecked()
, Nan::New(grClock)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("grSecurity").ToLocalChecked()
, Nan::New(grSecurity)
, v8::ReadOnly);
// Event params : control codes
Nan::SetPrototypeTemplate(
tpl
, Nan::New("CodeControlUnknown").ToLocalChecked()
, Nan::New(CodeControlUnknown)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("CodeControlColdStart").ToLocalChecked()
, Nan::New(CodeControlColdStart)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("CodeControlWarmStart").ToLocalChecked()
, Nan::New(CodeControlWarmStart)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("CodeControlStop").ToLocalChecked()
, Nan::New(CodeControlStop)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("CodeControlCompress").ToLocalChecked()
, Nan::New(CodeControlCompress)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("CodeControlCpyRamRom").ToLocalChecked()
, Nan::New(CodeControlCpyRamRom)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("CodeControlInsDel").ToLocalChecked()
, Nan::New(CodeControlInsDel)
, v8::ReadOnly);
// Event results
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evrNoError").ToLocalChecked()
, Nan::New(evrNoError)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evrFragmentRejected").ToLocalChecked()
, Nan::New(evrFragmentRejected)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evrMalformedPDU").ToLocalChecked()
, Nan::New(evrMalformedPDU)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evrSparseBytes").ToLocalChecked()
, Nan::New(evrSparseBytes)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evrCannotHandlePDU").ToLocalChecked()
, Nan::New(evrCannotHandlePDU)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evrNotImplemented").ToLocalChecked()
, Nan::New(evrNotImplemented)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evrErrException").ToLocalChecked()
, Nan::New(evrErrException)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evrErrAreaNotFound").ToLocalChecked()
, Nan::New(evrErrAreaNotFound)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evrErrOutOfRange").ToLocalChecked()
, Nan::New(evrErrOutOfRange)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evrErrOverPDU").ToLocalChecked()
, Nan::New(evrErrOverPDU)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evrErrTransportSize").ToLocalChecked()
, Nan::New(evrErrTransportSize)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evrInvalidGroupUData").ToLocalChecked()
, Nan::New(evrInvalidGroupUData)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evrInvalidSZL").ToLocalChecked()
, Nan::New(evrInvalidSZL)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evrDataSizeMismatch").ToLocalChecked()
, Nan::New(evrDataSizeMismatch)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evrCannotUpload").ToLocalChecked()
, Nan::New(evrCannotUpload)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evrCannotDownload").ToLocalChecked()
, Nan::New(evrCannotDownload)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evrUploadInvalidID").ToLocalChecked()
, Nan::New(evrUploadInvalidID)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("evrResNotFound").ToLocalChecked()
, Nan::New(evrResNotFound)
, v8::ReadOnly);
// Server parameter
Nan::SetPrototypeTemplate(
tpl
, Nan::New("LocalPort").ToLocalChecked()
, Nan::New(p_u16_LocalPort)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("WorkInterval").ToLocalChecked()
, Nan::New(p_i32_WorkInterval)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("PDURequest").ToLocalChecked()
, Nan::New(p_i32_PDURequest)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("MaxClients").ToLocalChecked()
, Nan::New(p_i32_MaxClients)
, v8::ReadOnly);
// CPU status codes
Nan::SetPrototypeTemplate(
tpl
, Nan::New("S7CpuStatusUnknown").ToLocalChecked()
, Nan::New(S7CpuStatusUnknown)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("S7CpuStatusRun").ToLocalChecked()
, Nan::New(S7CpuStatusRun)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("S7CpuStatusStop").ToLocalChecked()
, Nan::New(S7CpuStatusStop)
, v8::ReadOnly);
// Server status codes
Nan::SetPrototypeTemplate(
tpl
, Nan::New("SrvStopped").ToLocalChecked()
, Nan::New(0)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("SrvRunning").ToLocalChecked()
, Nan::New(1)
, v8::ReadOnly);
Nan::SetPrototypeTemplate(
tpl
, Nan::New("SrvError").ToLocalChecked()
, Nan::New(2)
, v8::ReadOnly);
constructor.Reset(tpl);
Nan::Set(target, name, Nan::GetFunction(tpl).ToLocalChecked());
}
NAN_METHOD(S7Server::New) {
if (info.IsConstructCall()) {
S7Server *s7Server = new S7Server(info.This());
s7Server->Wrap(info.This());
info.GetReturnValue().Set(info.This());
} else {
v8::Local constructorHandle;
constructorHandle = Nan::New(constructor);
info.GetReturnValue().Set(
Nan::NewInstance(Nan::GetFunction(constructorHandle).ToLocalChecked()).ToLocalChecked());
}
}
S7Server::S7Server(v8::Local resource)
: async_resource("S7Server:emit", resource) {
lastError = 0;
snap7Server = new TS7Server();
event_async_g.data = rw_async_g.data = this;
uv_async_init(uv_default_loop(), &event_async_g, S7Server::HandleEvent);
uv_async_init(uv_default_loop(), &rw_async_g, S7Server::HandleReadWriteEvent);
uv_unref(reinterpret_cast(&event_async_g));
uv_unref(reinterpret_cast(&rw_async_g));
uv_mutex_init(&mutex);
uv_mutex_init(&mutex_rw);
uv_mutex_init(&mutex_event);
uv_sem_init(&sem_rw, 0);
snap7Server->SetEventsCallback(&EventCallBack, NULL);
}
S7Server::~S7Server() {
snap7Server->Stop();
delete snap7Server;
constructor.Reset();
uv_close(reinterpret_cast(&event_async_g), 0);
uv_close(reinterpret_cast(&rw_async_g), 0);
uv_sem_destroy(&sem_rw);
uv_mutex_destroy(&mutex_event);
uv_mutex_destroy(&mutex_rw);
uv_mutex_destroy(&mutex);
}
int S7Server::GetByteCountFromWordLen(int WordLen) {
switch (WordLen) {
case S7WLBit:
case S7WLByte:
return 1;
case S7WLWord:
case S7WLCounter:
case S7WLTimer:
return 2;
case S7WLReal:
case S7WLDWord:
return 4;
default:
return 0;
}
}
NAN_METHOD(S7Server::RWBufferCallback) {
Nan::HandleScope scope;
if (rw_event_baton_g.Operation == OperationRead) {
if (!node::Buffer::HasInstance(info[0])) {
return Nan::ThrowTypeError("Wrong argument");
}
int byteCount, size;
byteCount = S7Server::GetByteCountFromWordLen(rw_event_baton_g.Tag.WordLen);
size = byteCount * rw_event_baton_g.Tag.Size;
if (node::Buffer::Length(info[0].As()) < size) {
return Nan::ThrowTypeError("Buffer length too small");
}
memcpy(
rw_event_baton_g.pUsrData
, node::Buffer::Data(info[0].As())
, size);
}
uv_sem_post(&sem_rw);
}
#if NODE_VERSION_AT_LEAST(0, 11, 13)
void S7Server::HandleEvent(uv_async_t* handle) {
#else
void S7Server::HandleEvent(uv_async_t* handle, int status) {
#endif
Nan::HandleScope scope;
S7Server *s7server = static_cast(handle->data);
uv_mutex_lock(&mutex_event);
while (!event_list_g.empty()) {
PSrvEvent Event = &event_list_g.front();
in_addr sin;
sin.s_addr = Event->EvtSender;
double time = static_cast(Event->EvtTime * 1000);
v8::Local event_obj = Nan::New();
Nan::Set(event_obj, Nan::New("EvtTime").ToLocalChecked()
, Nan::New(time).ToLocalChecked());
Nan::Set(event_obj, Nan::New("EvtSender").ToLocalChecked()
, Nan::New(inet_ntoa(sin)).ToLocalChecked());
Nan::Set(event_obj, Nan::New("EvtCode").ToLocalChecked()
, Nan::New(Event->EvtCode));
Nan::Set(event_obj, Nan::New("EvtRetCode").ToLocalChecked()
, Nan::New(Event->EvtRetCode));
Nan::Set(event_obj, Nan::New("EvtParam1").ToLocalChecked()
, Nan::New(Event->EvtParam1));
Nan::Set(event_obj, Nan::New("EvtParam2").ToLocalChecked()
, Nan::New(Event->EvtParam2));
Nan::Set(event_obj, Nan::New("EvtParam3").ToLocalChecked()
, Nan::New(Event->EvtParam3));
Nan::Set(event_obj, Nan::New("EvtParam4").ToLocalChecked()
, Nan::New(Event->EvtParam4));
v8::Local argv[2] = {
Nan::New("event").ToLocalChecked(),
event_obj
};
s7server->async_resource.runInAsyncScope(s7server->handle(), "emit", 2, argv);
event_list_g.pop_front();
}
uv_mutex_unlock(&mutex_event);
}
#if NODE_VERSION_AT_LEAST(0, 11, 13)
void S7Server::HandleReadWriteEvent(uv_async_t* handle) {
#else
void S7Server::HandleReadWriteEvent(uv_async_t* handle, int status) {
#endif
Nan::HandleScope scope;
S7Server *s7server = static_cast(handle->data);
in_addr sin;
sin.s_addr = rw_event_baton_g.Sender;
v8::Local rw_tag_obj = Nan::New();
Nan::Set(rw_tag_obj, Nan::New("Area").ToLocalChecked()
, Nan::New(rw_event_baton_g.Tag.Area));
Nan::Set(rw_tag_obj, Nan::New("DBNumber").ToLocalChecked()
, Nan::New(rw_event_baton_g.Tag.DBNumber));
Nan::Set(rw_tag_obj, Nan::New("Start").ToLocalChecked()
, Nan::New(rw_event_baton_g.Tag.Start));
Nan::Set(rw_tag_obj, Nan::New("Size").ToLocalChecked()
, Nan::New(rw_event_baton_g.Tag.Size));
Nan::Set(rw_tag_obj, Nan::New("WordLen").ToLocalChecked()
, Nan::New(rw_event_baton_g.Tag.WordLen));
int byteCount, size;
byteCount = S7Server::GetByteCountFromWordLen(rw_event_baton_g.Tag.WordLen);
size = byteCount * rw_event_baton_g.Tag.Size;
v8::Local buffer;
if (rw_event_baton_g.Operation == OperationWrite) {
buffer = Nan::CopyBuffer(
static_cast(rw_event_baton_g.pUsrData),
size).ToLocalChecked();
} else {
buffer = Nan::NewBuffer(size).ToLocalChecked();
memset(node::Buffer::Data(buffer), 0, size);
}
v8::Local argv[6] = {
Nan::New("readWrite").ToLocalChecked(),
Nan::New(inet_ntoa(sin)).ToLocalChecked(),
Nan::New(rw_event_baton_g.Operation),
rw_tag_obj,
buffer,
Nan::New(S7Server::RWBufferCallback)
};
s7server->async_resource.runInAsyncScope(s7server->handle(), "emit", 6, argv);
}
void IOWorkerServer::Execute() {
uv_mutex_lock(&s7server->mutex);
switch (caller) {
case STARTTO:
ret = s7server->snap7Server->StartTo(
**static_cast(pData));
if (ret == 0) {
uv_ref(reinterpret_cast(&event_async_g));
}
break;
case START:
ret = s7server->snap7Server->Start();
if (ret == 0) {
uv_ref(reinterpret_cast(&event_async_g));
}
break;
case STOP:
ret = s7server->snap7Server->Stop();
if (ret == 0) {
uv_unref(reinterpret_cast(&event_async_g));
}
break;
}
uv_mutex_unlock(&s7server->mutex);
}
void IOWorkerServer::HandleOKCallback() {
Nan::HandleScope scope;
v8::Local argv1[1];
v8::Local argv2[2];
if (ret == 0) {
argv2[0] = argv1[0] = Nan::Null();
} else {
argv2[0] = argv1[0] = Nan::New(ret);
}
switch (caller) {
case STARTTO:
delete static_cast(pData);
callback->Call(1, argv1, async_resource);
break;
case START:
case STOP:
callback->Call(1, argv1, async_resource);
break;
}
}
NAN_METHOD(S7Server::Start) {
S7Server *s7server = ObjectWrap::Unwrap(info.Holder());
if (!info[0]->IsFunction()) {
int ret = s7server->snap7Server->Start();
if (ret == 0) {
uv_ref(reinterpret_cast(&event_async_g));
}
s7server->lastError = ret;
info.GetReturnValue().Set(Nan::New(ret == 0));
} else {
Nan::Callback *callback = new Nan::Callback(info[0].As());
Nan::AsyncQueueWorker(new IOWorkerServer(callback, s7server, START));
info.GetReturnValue().SetUndefined();
}
}
NAN_METHOD(S7Server::StartTo) {
S7Server *s7server = ObjectWrap::Unwrap