bool Usb::dispatch(Msg& msg) { uint8_t b; uint32_t i; uint32_t count; if ( msg.is(os,SIG_ERC,fd(),0)) { logger.level(Logger::WARN) << " error occured. Reconnecting."; logger.flush(); disconnect(); // connect(); return 0; } PT_BEGIN ( ); while(true) { PT_YIELD_UNTIL ( msg.is(this,SIG_CONNECTED)); while( true ) { PT_YIELD_UNTIL(msg.is(os,SIG_RXD,fd(),0)|| msg.is(os,SIG_ERC,fd(),0));//event->is(RXD) || event->is(FREE) || ( inBuffer.hasData() && (_isComplete==false)) ); if ( msg.is(os,SIG_RXD,fd(),0) && hasData()) { count =hasData(); for(i=0; i<count; i++) { b=read(); inBuffer.write(b); } logger.level(Logger::DEBUG)<< "recvd: " << inBuffer.size() << " bytes."; logger.flush(); while( inBuffer.hasData() ) { if ( _inBytes.Feed(inBuffer.read())) { Str l(256); _inBytes.toString(l); logger.level(Logger::DEBUG)<< "recv : " << l; logger.flush(); _inBytes.Decode(); if ( _inBytes.isGoodCrc() ) { _inBytes.RemoveCrc(); Str l(256); _inBytes.toString(l); logger.level(Logger::INFO)<<" recv clean : " <<l; logger.flush(); MqttIn* _mqttIn=new MqttIn(256); _inBytes.offset(0); while(_inBytes.hasData()) _mqttIn->Feed(_inBytes.read()); if ( _mqttIn->parse()) { MsgQueue::publish(this,SIG_RXD,_mqttIn->type(),_mqttIn); // _mqttIn will be deleted by msg process } else { Sys::warn(EINVAL, "MQTT"); delete _mqttIn; } } else { logger.level(Logger::WARN)<<"Bad CRC. Dropped packet. "; logger.flush(); _inBytes.clear(); // throw away bad data } _inBytes.clear(); } } } else if ( msg.is(os,SIG_ERC,fd(),0) ) { _inBytes.clear(); break; } PT_YIELD ( ); } } PT_END ( ); }
//----------------------------------------------------------------------------- // <Security::EncryptMessage> // Encrypt and send a Z-Wave message securely. //----------------------------------------------------------------------------- bool Security::EncryptMessage ( uint8 const* _nonce ) { #if 1 if( m_nonceTimer.GetMilliseconds() > 10000 ) { // The nonce was not received within 10 seconds // of us sending the nonce request. Send it again RequestNonce(); return false; } // Fetch the next payload from the queue and encapsulate it m_queueMutex->Lock(); if( m_queue.empty() ) { // Nothing to do m_queueMutex->Release(); return false; } SecurityPayload * payload = m_queue.front(); m_queue.pop_front(); //uint32 queueSize = m_queue.size(); m_queueMutex->Unlock(); #else uint32 queueSize = m_queue.size(); struct SecurityPayload payload; payload.m_length = 7; payload.m_part = 0; uint8 tmpdata[7] = {0x62, 0x03, 0x00, 0x10, 0x02, 0xfe, 0xfe}; for (int i = 0; i < payload.m_length; i++) payload.m_data[i] = tmpdata[i]; #endif // Encapsulate the message fragment /* MessageEncapNonceGet doesn't seem to work */ //Msg* msg = new Msg( (queueSize>1) ? "SecurityCmd_MessageEncapNonceGet" : "SecurityCmd_MessageEncap", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true ); string LogMessage("SecurityCmd_MessageEncap ("); LogMessage.append(payload->logmsg); LogMessage.append(")"); Msg* msg = new Msg( LogMessage, GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( GetNodeId() ); msg->Append( payload->m_length + 20 ); msg->Append( GetCommandClassId() ); //msg->Append( (queueSize>1) ? SecurityCmd_MessageEncapNonceGet : SecurityCmd_MessageEncap ); msg->Append( SecurityCmd_MessageEncap ); /* create the iv * */ uint8 initializationVector[16]; /* the first 8 bytes of a outgoing IV are random */ for (int i = 0; i < 8; i++) { //initializationVector[i] = (rand()%0xFF)+1; initializationVector[i] = 0xAA; } /* the remaining 8 bytes are the NONCE we got from the device */ for (int i = 0; i < 8; i++) { initializationVector[8+i] = _nonce[i]; } /* Append the first 8 bytes of the initialization vector * to the message. The remaining 8 bytes are the NONCE we recieved from * the node, and is ommitted from sending back to the Node. But we use the full 16 bytes to * as the IV to encrypt out message. */ for(int i=0; i<8; ++i ) { msg->Append( initializationVector[i] ); } // Append the sequence data uint8 sequence = 0; if( payload->m_part == 0 ) { sequence = 0; } else if( payload->m_part == 1 ) { sequence = (++m_sequenceCounter) & 0x0f; sequence |= 0x10; // Sequenced, first frame } if( payload->m_part == 2 ) { sequence = m_sequenceCounter & 0x0f; sequence |= 0x30; // Sequenced, second frame } /* at most, the payload will be 28 bytes + 1 byte for the Sequence. */ uint8 plaintextmsg[32]; plaintextmsg[0] = sequence; for (int i = 0; i < payload->m_length; i++) plaintextmsg[i+1] = payload->m_data[i]; /* Append the message payload after encrypting it with AES-OFB (key is EncryptPassword, * full IV (16 bytes - 8 Random and 8 NONCE) and payload.m_data */ PrintHex("Input Packet:", plaintextmsg, payload->m_length+1); #ifdef DEBUG PrintHex("IV:", initializationVector, 16); #endif uint8 encryptedpayload[30]; aes_mode_reset(this->EncryptKey); if (aes_ofb_encrypt(plaintextmsg, encryptedpayload, payload->m_length+1, initializationVector, this->EncryptKey) == EXIT_FAILURE) { Log::Write(LogLevel_Warning, GetNodeId(), "Failed to Encrypt Packet"); delete msg; return false; } #ifdef DEBUG PrintHex("Encrypted Output", encryptedpayload, payload->m_length+1); /* The Following Code attempts to Decrypt the Packet and Verify */ /* the first 8 bytes of a outgoing IV are random */ for (int i = 0; i < 8; i++) { //initializationVector[i] = (rand()%0xFF)+1; initializationVector[i] = 0xAA; } /* the remaining 8 bytes are the NONCE we got from the device */ for (int i = 0; i < 8; i++) { initializationVector[8+i] = _nonce[i]; } aes_mode_reset(this->EncryptKey); uint8 tmpoutput[16]; if (aes_ofb_encrypt(encryptedpayload, tmpoutput, payload->m_length+1, initializationVector, this->EncryptKey) == EXIT_FAILURE) { Log::Write(LogLevel_Warning, GetNodeId(), "Failed to Encrypt Packet"); delete msg; return false; } PrintHex("Decrypted output", tmpoutput, payload->m_length+1); #endif for(int i=0; i<payload->m_length+1; ++i ) { msg->Append( encryptedpayload[i] ); } // Append the nonce identifier :) msg->Append(_nonce[0]); /* Append space for the authentication data Set with AES-CBCMAC (key is AuthPassword, * Full IV (16 bytes - 8 random and 8 NONCE) and sequence|SrcNode|DstNode|payload.m_length|payload.m_data * */ /* Regenerate IV */ /* the first 8 bytes of a outgoing IV are random */ for (int i = 0; i < 8; i++) { //initializationVector[i] = (rand()%0xFF)+1; initializationVector[i] = 0xAA; } /* the remaining 8 bytes are the NONCE we got from the device */ for (int i = 0; i < 8; i++) { initializationVector[8+i] = _nonce[i]; } uint8 mac[8]; this->GenerateAuthentication(&msg->GetBuffer()[7], msg->GetLength()+2, GetDriver()->GetNodeId(), GetNodeId(), initializationVector, mac); for(int i=0; i<8; ++i ) { msg->Append( mac[i] ); } #ifdef DEBUG PrintHex("Auth", mac, 8); #endif msg->Append( GetDriver()->GetTransmitOptions() ); #ifdef DEBUG PrintHex("Outgoing", msg->GetBuffer(), msg->GetLength()); #endif GetDriver()->SendMsg(msg, Driver::MsgQueue_Security); /* finally, if the message we just sent is a NetworkKeySet, then we need to reset our Network Key here * as the reply we will get back will be encrypted with the new Network key */ if ((this->m_networkkeyset == false) && (payload->m_data[0] == 0x98) && (payload->m_data[1] == 0x06)) { Log::Write(LogLevel_Info, GetNodeId(), "Reseting Network Key after Inclusion"); this->m_networkkeyset = true; SetupNetworkKey(); } delete payload; return true; }
bool Wifi::dispatch(Msg& msg) { // INFO("line : %d ",_ptLine); // INFO("msg : %d:%d",msg.src(),msg.signal()); PT_BEGIN(); INIT : { PT_WAIT_UNTIL(msg.is(0,SIG_INIT)); struct station_config stationConf; INFO("WIFI_INIT"); if ( wifi_set_opmode(STATION_MODE) ){ ; // STATIONAP_MODE was STATION_MODE INFO("line : %d",__LINE__); if ( wifi_set_phy_mode(PHY_MODE_11B)) { os_memset(&stationConf, 0, sizeof(struct station_config)); ets_strncpy((char*)stationConf.ssid,_ssid,sizeof(stationConf.ssid)); ets_strncpy((char*)stationConf.password,_pswd,sizeof(stationConf.password)); stationConf.bssid_set=0; INFO("line : %d",__LINE__); if ( wifi_station_set_config(&stationConf) ){ if ( wifi_station_connect() ){ INFO("line : %d",__LINE__); goto DISCONNECTED;// wifi_station_set_auto_connect(TRUE); } } } } // wifi_station_set_auto_connect(FALSE); INFO(" WIFI INIT failed , retrying... "); goto INIT; }; DISCONNECTED: { while(true) { timeout(1000); PT_YIELD_UNTIL(timeout()); struct ip_info ipConfig; wifi_get_ip_info(STATION_IF, &ipConfig); wifiStatus = wifi_station_get_connect_status(); if ( wifi_station_get_connect_status()== STATION_NO_AP_FOUND || wifi_station_get_connect_status()==STATION_WRONG_PASSWORD || wifi_station_get_connect_status()==STATION_CONNECT_FAIL) { INFO(" NOT CONNECTED "); wifi_station_connect(); } else if (wifiStatus == STATION_GOT_IP && ipConfig.ip.addr != 0) { _connections++; union { uint32_t addr; uint8_t ip[4]; } v; v.addr = ipConfig.ip.addr; INFO(" IP Address : %d.%d.%d.%d ",v.ip[0],v.ip[1],v.ip[2],v.ip[3]); INFO(" CONNECTED "); Msg::publish(this,SIG_CONNECTED); _connected=true; timeout(2000); goto CONNECTED; } else { INFO(" STATION_IDLE "); } timeout(500); } }; CONNECTED : { while(true) { PT_YIELD_UNTIL(timeout()); struct ip_info ipConfig; wifi_get_ip_info(STATION_IF, &ipConfig); wifiStatus = wifi_station_get_connect_status(); if (wifiStatus != STATION_GOT_IP ) { Msg::publish(this,SIG_DISCONNECTED); timeout(500); _connected=false; goto DISCONNECTED; } timeout(2000); } }; PT_END(); }
void ABTMessageTest::test_accessors(void) { using namespace maxmm::ma; { typedef ABTMessage<uint32_t> Msg; Msg msg; msg.make_ok(); msg.ok().agent_assignment().value() = 2; msg.ok().agent_assignment().agent_id() = ma::AgentId(1); CPPUNIT_ASSERT_EQUAL(uint32_t(2), msg.ok().agent_assignment().value()); CPPUNIT_ASSERT_EQUAL(uint32_t(1), msg.ok().agent_assignment().agent_id().id()); Msg msg2; msg2 = msg; Msg msg3; } { typedef ABTMessage<uint32_t> Msg; Msg msg; msg.make_nogood().nogoods().push_back(AgentAssignment<uint32_t>()); CPPUNIT_ASSERT_EQUAL(std::size_t(1), msg.nogood().nogoods().size()); msg.nogood().nogoods().push_back(AgentAssignment<uint32_t>()); CPPUNIT_ASSERT_EQUAL(std::size_t(2), msg.nogood().nogoods().size()); msg.nogood().nogoods().at(0).value() = 2; msg.nogood().nogoods().at(1).value() = 3; CPPUNIT_ASSERT_EQUAL(uint32_t(2), msg.nogood().nogoods().at(0).value()); CPPUNIT_ASSERT_EQUAL(uint32_t(3), msg.nogood().nogoods().at(1).value()); } }
bool Security::Init ( ) { /* if we are adding this node, then instead to a SchemeGet Command instead - This * will start the Network Key Exchange */ if (GetNodeUnsafe()->IsAddingNode()) { Msg * msg = new Msg ("SecurityCmd_SchemeGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( GetNodeId() ); msg->Append( 3 ); msg->Append( GetCommandClassId() ); msg->Append( SecurityCmd_SchemeGet ); msg->Append( 0 ); msg->Append( GetDriver()->GetTransmitOptions() ); /* SchemeGet is unencrypted */ GetDriver()->SendMsg(msg, Driver::MsgQueue_Security); } else { Msg* msg = new Msg( "SecurityCmd_SupportedGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( GetNodeId() ); msg->Append( 2 ); msg->Append( GetCommandClassId() ); msg->Append( SecurityCmd_SupportedGet ); msg->Append( GetDriver()->GetTransmitOptions() ); this->SendMsg( msg); } return true; }
// // routine: receive and send on incoming messages // // Notes: // No analysis of the message is performed - that is left // to the command processor task. Instead, the local copy // of the header // is demarshalled to determined whether or not there // is associated data; if there is, space is allocated to // contain it. void * SseInputTask::routine() { extractArgs(); Timer timer; if (cmdArgs->noSSE()) { processIpFromFile(); while (1) timer.sleep(3000); }; // run forever, waiting for messages from the SSE bool stopIssued = false; bool done = false; uint32_t lastCode = MESSAGE_CODE_UNINIT; int32_t lastLen = 0; uint32_t lastTime = 0; while (!done) { // if there's no connection, request that it be // established, then wait for that to happen if (!sse->isConnected()) { requestConnection(); while (!sse->isConnected()) timer.sleep(3000); } stopIssued = false; // got a connection - wait for data to come in SseInterfaceHeader hdr; Error err = sse->recv((void *) &hdr, sizeof(hdr)); if (err) { switch (err) { case EAGAIN: case EINTR: case ENOTCONN: case ECONNRESET: stopAllActivities(stopIssued); continue; default: Fatal(err); break; } } // demarshall the header hdr.demarshall(); if (cmdArgs->logSseMessages()) { LogWarning(ERR_NE, hdr.activityId, "bad msg from Sse, code = %d, len = %d", hdr.code, hdr.dataLength); } // allocate a message to hold the incoming message Msg *msg = msgList->alloc(); msg->setHeader(hdr); msg->setUnit((sonata_lib::Unit) UnitSse); // if there's data associated with the message, // allocate space and retrieve it, demarshall it // based on the message type, // then send it on to the command processor void *data = 0; int32_t len = hdr.dataLength; timeval tv; gettimeofday(&tv, NULL); if (len > 10000) { LogWarning(ERR_NE, hdr.activityId, "msg code = %d, len = %d, t = %u, last msg = %d, last len = %d, last t = %u", hdr.code, len, tv.tv_sec, lastCode, lastLen, lastTime); Timer t; t.sleep(100); } else { lastCode = hdr.code; lastLen = len; lastTime = tv.tv_sec; } if (len) { MemBlk *blk = partitionSet->alloc(len); Assert(blk); if (!blk) Fatal(ERR_MAF); data = blk->getData(); err = sse->recv(data, len); if (err) { switch (err) { case EAGAIN: case EINTR: case ENOTCONN: case ECONNRESET: blk->free(); Assert(msgList->free(msg)); stopAllActivities(stopIssued); continue; default: Fatal(err); break; } } msg->setData(data, len, blk); } // demarshall the data of the message depending on // the message type switch (hdr.code) { case REQUEST_INTRINSICS: break; case CONFIGURE_DX: (static_cast<DxConfiguration *> (data))->demarshall(); break; case PERM_RFI_MASK: case BIRDIE_MASK: case RCVR_BIRDIE_MASK: case TEST_SIGNAL_MASK: demarshallFrequencyMask(data); break; case RECENT_RFI_MASK: demarshallRecentRFIMask(data); break; case REQUEST_DX_STATUS: break; case SEND_DX_ACTIVITY_PARAMETERS: (static_cast<DxActivityParameters *> (data))->demarshall(); break; case DX_SCIENCE_DATA_REQUEST: (static_cast<DxScienceDataRequest *> (data))->demarshall(); break; #ifdef notdef case SEND_DOPPLER_PARAMETERS: (static_cast<DopplerParameters *> (data))->demarshall(); break; #endif case BEGIN_SENDING_FOLLOW_UP_SIGNALS: (static_cast<Count *> (data))->demarshall(); break; case SEND_FOLLOW_UP_CW_SIGNAL: (static_cast<FollowUpCwSignal *> (data))->demarshall(); break; case SEND_FOLLOW_UP_PULSE_SIGNAL: (static_cast<FollowUpPulseSignal *> (data))->demarshall(); break; case DONE_SENDING_FOLLOW_UP_SIGNALS: break; case START_TIME: (static_cast<StartActivity *> (data))->demarshall(); break; case BEGIN_SENDING_CANDIDATES: (static_cast<Count *> (data))->demarshall(); break; case SEND_CANDIDATE_CW_POWER_SIGNAL: (static_cast<CwPowerSignal *> (data))->demarshall(); break; case SEND_CANDIDATE_PULSE_SIGNAL: demarshallPulseSignal(data); break; case DONE_SENDING_CANDIDATES: break; case BEGIN_SENDING_CW_COHERENT_SIGNALS: break; case SEND_CW_COHERENT_SIGNAL: (static_cast<CwCoherentSignal *> (data))->demarshall(); break; case DONE_SENDING_CW_COHERENT_SIGNALS: break; case REQUEST_ARCHIVE_DATA: (static_cast<ArchiveRequest *> (data))->demarshall(); break; case DISCARD_ARCHIVE_DATA: (static_cast<ArchiveRequest *> (data))->demarshall(); break; // the following commands arrive with no data case STOP_DX_ACTIVITY: case SHUTDOWN_DX: case RESTART_DX: Debug(DEBUG_CONTROL, hdr.activityId, "STOP_DX_ACTIVITY, act"); break; default: LogError(ERR_IMT, hdr.activityId, "activity %d, type %d", hdr.activityId, hdr.code); Err(ERR_IMT); ErrStr(hdr.code, "msg code"); Assert(msgList->free(msg)); continue; } // at this point, the entire marshalled message is in // a generic Msg; send the message on for processing, // then go back to waiting cmdQ->send(msg); } return (0); }
bool HControlPointPrivate::processDeviceDiscovery( const Msg& msg, const HEndpoint& source, HControlPointSsdpHandler*) { HLOG2(H_AT, H_FUN, m_loggingIdentifier); const HUdn& resourceUdn = msg.usn().udn(); HDefaultClientDevice* device = static_cast<HDefaultClientDevice*>( m_deviceStorage.searchDeviceByUdn(msg.usn().udn(), AllDevices)); if (device) { // according to the UDA v1.1 spec, if a control point receives an // alive announcement of any type for a device tree, the control point // can assume that all devices and services are available. // ==> reset timeouts for entire device tree and all services. device = static_cast<HDefaultClientDevice*>(device->rootDevice()); device->startStatusNotifier(HDefaultClientDevice::All); // it cannot be that only some embedded device is available at certain // interface, since the device description is always fetched from the // the location that the root device specifies ==> the entire device // tree has to be available at that location. if (device->addLocation(msg.location())) { HLOG_DBG(QString("Existing device [%1] now available at [%2]").arg( resourceUdn.toString(), msg.location().toString())); } if (!device->deviceStatus()->online()) { device->deviceStatus()->setOnline(true); emit q_ptr->rootDeviceOnline(device); processDeviceOnline(device, false); } return true; } // it does not matter if the device is an embedded device, since the // location of the device always points to the root device's description // and the internal device model is built of that. Hence, any advertisement // will do to build the entire model correctly. DeviceBuildTask* dbp = m_deviceBuildTasks.get(msg); if (dbp) { if (!dbp->m_locations.contains(msg.location())) { dbp->m_locations.push_back(msg.location()); } return true; } if (!q_ptr->acceptResource(msg.usn(), source)) { HLOG_DBG(QString("Resource advertisement [%1] rejected").arg( msg.usn().toString())); return true; } DeviceBuildTask* newBuildTask = new DeviceBuildTask(this, msg); newBuildTask->setAutoDelete(false); m_deviceBuildTasks.add(newBuildTask); bool ok = connect( newBuildTask, SIGNAL(done(Herqq::Upnp::HUdn)), this, SLOT(deviceModelBuildDone(Herqq::Upnp::HUdn))); Q_ASSERT(ok); Q_UNUSED(ok) HLOG_INFO(QString( "New resource [%1] is available @ [%2]. " "Attempting to build the device model.").arg( msg.usn().toString(), msg.location().toString())); m_threadPool->start(newBuildTask); return true; }
//----------------------------------------------------------------------------- // <BasicWindowCovering::SetValue> // Set a value on the Z-Wave device //----------------------------------------------------------------------------- bool BasicWindowCovering::SetValue ( Value const& _value ) { if( ValueID::ValueType_Button == _value.GetID().GetType() ) { ValueButton const* button = static_cast<ValueButton const*>(&_value); uint8 action = 0x40; if( button->GetID().GetIndex() ) // Open is index zero, so non-zero is close. { // Close action = 0; } if( button && button->IsPressed() ) { Log::Write( LogLevel_Info, GetNodeId(), "BasicWindowCovering - Start Level Change (%s)", action ? "Open" : "Close" ); Msg* msg = new Msg( "Basic Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true ); msg->SetInstance( this, _value.GetID().GetInstance() ); msg->Append( GetNodeId() ); msg->Append( 3 ); msg->Append( GetCommandClassId() ); msg->Append( BasicWindowCoveringCmd_StartLevelChange ); msg->Append( action ); msg->Append( GetDriver()->GetTransmitOptions() ); GetDriver()->SendMsg( msg, Driver::MsgQueue_Send ); return true; } else { Log::Write( LogLevel_Info, GetNodeId(), "BasicWindowCovering - Stop Level Change" ); Msg* msg = new Msg( "Basic Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true ); msg->SetInstance( this, _value.GetID().GetInstance() ); msg->Append( GetNodeId() ); msg->Append( 2 ); msg->Append( GetCommandClassId() ); msg->Append( BasicWindowCoveringCmd_StopLevelChange ); msg->Append( GetDriver()->GetTransmitOptions() ); GetDriver()->SendMsg( msg, Driver::MsgQueue_Send ); return true; } } return false; }
//----------------------------------------------------------------------------- // <ManufacturerProprietary::SetValue> // Set the lock's state //----------------------------------------------------------------------------- bool ManufacturerProprietary::SetValue ( Value const& _value ) { uint64 value_id = _value.GetID().GetIndex(); Msg* msg = new Msg( "ManufacturerProprietary_SetValue", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); if (FibaroVenetianBlindsValueIds_Blinds == value_id || FibaroVenetianBlindsValueIds_Tilt == value_id){ ValueByte const* value = static_cast<ValueByte const*>(&_value); msg->SetInstance( this, _value.GetID().GetInstance() ); msg->Append( GetNodeId() ); msg->Append( 2 + // length of data sizeof(MANUFACTURER_ID_FIBARO) + sizeof(FIBARO_VENETIAN_BLINDS_GET_POSITION_TILT) ); msg->Append( GetCommandClassId() ); msg->AppendArray( MANUFACTURER_ID_FIBARO, sizeof(MANUFACTURER_ID_FIBARO) ); if (FibaroVenetianBlindsValueIds_Blinds == value_id) { msg->AppendArray( FIBARO_VENETIAN_BLINDS_SET_POSITION, sizeof(FIBARO_VENETIAN_BLINDS_SET_POSITION) ); msg->Append( value->GetValue() ); msg->Append( 0x00 ); } else if (FibaroVenetianBlindsValueIds_Tilt == value_id) { msg->AppendArray( FIBARO_VENETIAN_BLINDS_SET_TILT, sizeof(FIBARO_VENETIAN_BLINDS_SET_TILT) ); msg->Append( value->GetValue() ); } msg->Append( GetDriver()->GetTransmitOptions() ); GetDriver()->SendMsg( msg, Driver::MsgQueue_Send ); return true; } else { Log::Write( LogLevel_Info, GetNodeId(), "ManufacturerProprietary_SetValue %d not supported on node %d", value_id, GetNodeId()); return false; } }
//----------------------------------------------------------------------------- // <ClimateControlSchedule::SetValue> // Set a value in the device //----------------------------------------------------------------------------- bool ClimateControlSchedule::SetValue ( Value const& _value ) { // bool res = false; uint8 instance = _value.GetID().GetInstance(); uint8 idx = _value.GetID().GetIndex(); if( idx < 8 ) { // Set a schedule ValueSchedule const* value = static_cast<ValueSchedule const*>(&_value); Log::Write( LogLevel_Info, GetNodeId(), instance, "Set the climate control schedule for %s", c_dayNames[idx]); Msg* msg = new Msg( "ClimateControlScheduleCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->SetInstance( this, instance ); msg->Append( GetNodeId() ); msg->Append( 30 ); msg->Append( GetCommandClassId() ); msg->Append( ClimateControlScheduleCmd_Set ); msg->Append( idx ); // Day of week for( uint8 i=0; i<9; ++i ) { uint8 hours; uint8 minutes; int8 setback; if( value->GetSwitchPoint( i, &hours, &minutes, &setback ) ) { msg->Append( hours ); msg->Append( minutes ); msg->Append( setback ); } else { // Unused switch point msg->Append( 0 ); msg->Append( 0 ); msg->Append( 0x7f ); } } msg->Append( GetDriver()->GetTransmitOptions() ); GetDriver()->SendMsg( msg, Driver::MsgQueue_Send ); } else { // Set an override ValueList* state = static_cast<ValueList*>( GetValue( instance, ClimateControlScheduleIndex_OverrideState ) ); ValueByte* setback = static_cast<ValueByte*>( GetValue( instance, ClimateControlScheduleIndex_OverrideSetback ) ); if( state && setback ) { ValueList::Item const *item = state->GetItem(); if (item == NULL) { return false; } Msg* msg = new Msg( "ClimateControlScheduleCmd_OverrideSet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->SetInstance( this, instance ); msg->Append( GetNodeId() ); msg->Append( 4 ); msg->Append( GetCommandClassId() ); msg->Append( ClimateControlScheduleCmd_OverrideSet ); msg->Append( (uint8)item->m_value ); msg->Append( setback->GetValue() ); msg->Append( GetDriver()->GetTransmitOptions() ); GetDriver()->SendMsg( msg, Driver::MsgQueue_Send ); } } return true; }
//----------------------------------------------------------------------------- // <ThermostatMode::RequestValue> // Get the static thermostat mode details from the device //----------------------------------------------------------------------------- bool ThermostatMode::RequestValue ( uint32 const _requestFlags, uint8 const _getTypeEnum, uint8 const _instance, Driver::MsgQueue const _queue ) { if( _getTypeEnum == ThermostatModeCmd_SupportedGet ) { // Request the supported modes Msg* msg = new Msg( "Request Supported Thermostat Modes", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->SetInstance( this, _instance ); msg->Append( GetNodeId() ); msg->Append( 2 ); msg->Append( GetCommandClassId() ); msg->Append( ThermostatModeCmd_SupportedGet ); msg->Append( GetDriver()->GetTransmitOptions() ); GetDriver()->SendMsg( msg, _queue ); return true; } if( _getTypeEnum == 0 ) // get current mode { // Request the current mode Msg* msg = new Msg( "Request Current Thermostat Mode", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->SetInstance( this, _instance ); msg->Append( GetNodeId() ); msg->Append( 2 ); msg->Append( GetCommandClassId() ); msg->Append( ThermostatModeCmd_Get ); msg->Append( GetDriver()->GetTransmitOptions() ); GetDriver()->SendMsg( msg, _queue ); return true; } return false; }
//----------------------------------------------------------------------------- // <ClimateControlSchedule::HandleMsg> // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool ClimateControlSchedule::HandleMsg ( uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if( ClimateControlScheduleCmd_Report == (ClimateControlScheduleCmd)_data[0] ) { uint8 day = _data[1] & 0x07; if (day > 7) /* size of c_dayNames */ { Log::Write (LogLevel_Warning, GetNodeId(), _instance, "Day Value was greater than range. Setting to Invalid"); day = 0; } Log::Write( LogLevel_Info, GetNodeId(), _instance, "Received climate control schedule report for %s", c_dayNames[day] ); if( ValueSchedule* value = static_cast<ValueSchedule*>( GetValue( _instance, day ) ) ) { // Remove any existing data value->ClearSwitchPoints(); // Parse the switch point data for( uint8 i=2; i<29; i+=3 ) { uint8 setback = _data[i+2]; if( setback == 0x7f ) { // Switch point is unused, so we stop parsing here break; } uint8 hours = _data[i] & 0x1f; uint8 minutes = _data[i+1] & 0x3f; if( setback == 0x79 ) { Log::Write( LogLevel_Info, GetNodeId(), _instance, " Switch point at %02d:%02d, Frost Protection Mode", hours, minutes, c_dayNames[day] ); } else if( setback == 0x7a ) { Log::Write( LogLevel_Info, GetNodeId(), _instance, " Switch point at %02d:%02d, Energy Saving Mode", hours, minutes, c_dayNames[day] ); } else { Log::Write( LogLevel_Info, GetNodeId(), _instance, " Switch point at %02d:%02d, Setback %+.1fC", hours, minutes, ((float)setback)*0.1f ); } value->SetSwitchPoint( hours, minutes, setback ); } if( !value->GetNumSwitchPoints() ) { Log::Write( LogLevel_Info, GetNodeId(), _instance, " No Switch points have been set" ); } // Notify the user value->OnValueRefreshed(); value->Release(); } return true; } if( ClimateControlScheduleCmd_ChangedReport == (ClimateControlScheduleCmd)_data[0] ) { Log::Write( LogLevel_Info, GetNodeId(), _instance, "Received climate control schedule changed report:" ); if( _data[1] ) { if( _data[1] != m_changeCounter ) { m_changeCounter = _data[1]; // The schedule has changed and is not in override mode, so request reports for each day for( int i=1; i<=7; ++i ) { Log::Write(LogLevel_Info, GetNodeId(), _instance, "Get climate control schedule for %s", c_dayNames[i] ); Msg* msg = new Msg( "ClimateControlScheduleCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( GetNodeId() ); msg->Append( 3 ); msg->Append( GetCommandClassId() ); msg->Append( ClimateControlScheduleCmd_Get ); msg->Append( i ); msg->Append( GetDriver()->GetTransmitOptions() ); GetDriver()->SendMsg( msg, Driver::MsgQueue_Send ); } } } else { // Device is in override mode, so we request details of that instead Msg* msg = new Msg( "ClimateControlScheduleCmd_OverrideGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( GetNodeId() ); msg->Append( 2 ); msg->Append( GetCommandClassId() ); msg->Append( ClimateControlScheduleCmd_OverrideGet ); msg->Append( GetDriver()->GetTransmitOptions() ); GetDriver()->SendMsg( msg, Driver::MsgQueue_Send ); } return true; } if( ClimateControlScheduleCmd_OverrideReport == (ClimateControlScheduleCmd)_data[0] ) { uint8 overrideState = _data[1] & 0x03; if (overrideState > 3) /* size of c_overrideStateNames */ { Log::Write (LogLevel_Warning, GetNodeId(), _instance, "overrideState Value was greater than range. Setting to Invalid"); overrideState = 3; } Log::Write( LogLevel_Info, GetNodeId(), _instance, "Received climate control schedule override report:" ); Log::Write( LogLevel_Info, GetNodeId(), _instance, " Override State: %s:", c_overrideStateNames[overrideState] ); if( ValueList* valueList = static_cast<ValueList*>( GetValue( _instance, ClimateControlScheduleIndex_OverrideState ) ) ) { valueList->OnValueRefreshed( (int)overrideState ); valueList->Release(); } uint8 setback = _data[2]; if( overrideState ) { if( setback == 0x79 ) { Log::Write( LogLevel_Info, GetNodeId(), _instance, " Override Setback: Frost Protection Mode" ); } else if( setback == 0x7a ) { Log::Write( LogLevel_Info, GetNodeId(), _instance, " Override Setback: Energy Saving Mode" ); } else { Log::Write( LogLevel_Info, GetNodeId(), _instance, " Override Setback: %+.1fC", ((float)setback)*0.1f ); } } if( ValueByte* valueByte = static_cast<ValueByte*>( GetValue( _instance, ClimateControlScheduleIndex_OverrideSetback ) ) ) { valueByte->OnValueRefreshed( setback ); valueByte->Release(); } return true; } return false; }
void Stub::OnRead(ssize_t nread, uv_buf_t buff) { GTimer timer; m_uInputBufferPos += nread; if (STUB_INPUTBUFFER_SIZE - m_uInputBufferPos < STUB_INPUTBUFFER_SIZE/4) { g_Log.SaveLog(LOG_LV_ERROR, "Stub alloc error! used too much<%d, %d>", STUB_INPUTBUFFER_SIZE, m_uInputBufferPos); Close(); return; } size_t nStartPos = 0; MSG_ID_t uMsgID; MSG_LEN_t uMsgLen; size_t uIDLen = sizeof(uMsgID); size_t uLenLen = sizeof(uMsgLen); size_t uMsgTotalLen = 0; while (nStartPos + uIDLen + uLenLen <= m_uInputBufferPos) { memcpy(&uMsgID, m_pInputBuffers + nStartPos, uIDLen); memcpy(&uMsgLen, m_pInputBuffers + nStartPos + uIDLen, uLenLen); uMsgTotalLen = uIDLen + uLenLen + uMsgLen; if (uMsgLen > STUB_INPUTBUFFER_SIZE / 2) { g_Log.SaveLog(LOG_LV_ERROR, "Stub read Error! illegality msg<%d, %d> from<%s,>", uMsgID, uMsgLen, m_sIP.c_str()); Close(); break; } if (nStartPos + uMsgTotalLen > m_uInputBufferPos) { break; } IMsgFactory* pFactory = g_MsgFactoryManager.GetFactory(uMsgID); if (pFactory == NULL) { g_Log.SaveLog(LOG_LV_WARNING, "Stub Read Warning! can not find the factory<id:%d, len:%d>", uMsgID, uMsgLen); } else { Msg* pMsg = pFactory->GetMsg(); if (pMsg == NULL) { g_Log.SaveLog(LOG_LV_ERROR, "Stub Read Warning! create msg<id:%d, len:%d> failed!", uMsgID, uMsgLen); } else { pMsg->Len(uMsgLen); if (!pFactory->Read(pMsg, m_pInputBuffers + nStartPos + uIDLen + uLenLen, uMsgLen)) { g_Log.SaveLog(LOG_LV_ERROR, "Stub Read Warning! read<id:%d, len:%d> failed!", uMsgID, uMsgLen); } else { pFactory->HandleMsg(pMsg, this); } } } nStartPos += uMsgTotalLen; } assert(m_uInputBufferPos >= nStartPos); size_t uLeft = m_uInputBufferPos - nStartPos; if (uLeft > 0 && nStartPos > 0) { memcpy(m_pInputBuffers, m_pInputBuffers + nStartPos, uLeft); } m_uInputBufferPos = uLeft; //g_Log.SaveLog(LOG_LV_NORMAL, "cost time:%f", timer.Seconds()); }
bool DWM1000_Tag::dispatch(Msg& msg) { PT_BEGIN() PT_WAIT_UNTIL(msg.is(0, SIG_INIT)); init(); POLL_SEND: { while (true) { timeout(1000); // delay between POLL PT_YIELD_UNTIL(timeout()); /* Write frame data to DW1000 and prepare transmission. See NOTE 7 below. */ tx_poll_msg[ALL_MSG_SN_IDX] = frame_seq_nb; dwt_writetxdata(sizeof(tx_poll_msg), tx_poll_msg, 0); dwt_writetxfctrl(sizeof(tx_poll_msg), 0); /* Start transmission, indicating that a response is expected so that reception is enabled automatically after the frame is sent and the delay * set by dwt_setrxaftertxdelay() has elapsed. */ LOG<< " Start TXF " << FLUSH; dwt_starttx(DWT_START_TX_IMMEDIATE | DWT_RESPONSE_EXPECTED);// SEND POLL MSG dwt_setinterrupt(DWT_INT_TFRS, 0); dwt_setinterrupt(DWT_INT_RFCG, 1); // enable clearInterrupt(); _timeoutCounter = 0; /* We assume that the transmission is achieved correctly, poll for reception of a frame or error/timeout. See NOTE 8 below. */ timeout(10); PT_YIELD_UNTIL(timeout() || isInterruptDetected()); // WAIT RESP MSG if (isInterruptDetected()) LOG<< " INTERRUPT DETECTED " << FLUSH; status_reg = dwt_read32bitreg(SYS_STATUS_ID); LOG<< HEX <<" SYS_STATUS " << status_reg << FLUSH; if (status_reg == 0xDEADDEAD) { init(); } else if (status_reg & SYS_STATUS_RXFCG) goto RESP_RECEIVED; else if (status_reg & SYS_STATUS_ALL_RX_ERR) { if (status_reg & SYS_STATUS_RXRFTO) INFO(" RX Timeout"); else INFO(" RX error "); dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_ALL_RX_ERR); /* Clear RX error events in the DW1000 status register. */ } } } RESP_RECEIVED: { LOG<< " Received " <<FLUSH; frame_seq_nb++; /* Increment frame sequence number after transmission of the poll message (modulo 256). */ uint32 frame_len; /* Clear good RX frame event and TX frame sent in the DW1000 status register. */ dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_RXFCG | SYS_STATUS_TXFRS); /* A frame has been received, read iCHANGEt into the local buffer. */ frame_len = dwt_read32bitreg(RX_FINFO_ID) & RX_FINFO_RXFLEN_MASK; if (frame_len <= RX_BUF_LEN) { dwt_readrxdata(rx_buffer, frame_len, 0); } /* Check that the frame is the expected response from the companion "DS TWR responder" example. * As the sequence number field of the frame is not relevant, it is cleared to simplify the validation of the frame. */ rx_buffer[ALL_MSG_SN_IDX] = 0; if (memcmp(rx_buffer, rx_resp_msg, ALL_MSG_COMMON_LEN) == 0) { // CHECK RESP MSG uint32 final_tx_time; /* Retrieve poll transmission and response reception timestamp. */ poll_tx_ts = get_tx_timestamp_u64(); resp_rx_ts = get_rx_timestamp_u64(); /* Compute final message transmission time. See NOTE 9 below. */ final_tx_time = (resp_rx_ts + (RESP_RX_TO_FINAL_TX_DLY_UUS * UUS_TO_DWT_TIME)) >> 8; dwt_setdelayedtrxtime(final_tx_time); /* Final TX timestamp is the transmission time we programmed plus the TX antenna delay. */ final_tx_ts = (((uint64) (final_tx_time & 0xFFFFFFFE)) << 8) + TX_ANT_DLY; /* Write all timestamps in the final message. See NOTE 10 below. */ final_msg_set_ts(&tx_final_msg[FINAL_MSG_POLL_TX_TS_IDX], poll_tx_ts); final_msg_set_ts(&tx_final_msg[FINAL_MSG_RESP_RX_TS_IDX], resp_rx_ts); final_msg_set_ts(&tx_final_msg[FINAL_MSG_FINAL_TX_TS_IDX], final_tx_ts); /* Write and send final message. See NOTE 7 below. */ tx_final_msg[ALL_MSG_SN_IDX] = frame_seq_nb; dwt_writetxdata(sizeof(tx_final_msg), tx_final_msg, 0); dwt_writetxfctrl(sizeof(tx_final_msg), 0); dwt_starttx(DWT_START_TX_DELAYED); // SEND FINAL MSG /* Poll DW1000 until TX frame sent event set. See NOTE 8 below. */ timeout(10); PT_YIELD_UNTIL((dwt_read32bitreg(SYS_STATUS_ID) & SYS_STATUS_TXFRS) || timeout());; /* Clear TXFRS event. */ dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_TXFRS); /* Increment frame sequence number after transmission of the final message (modulo 256). */ frame_seq_nb++; } else {
/* static */ void Server :: receiveHandler(NetworkClient* aClient, uint8_t* aBuf, size_t aLen) { if (aClient != nullptr && aBuf != nullptr) { if (aLen < sizeof(Msg::Header)) return; uint8_t* received = new uint8_t[aLen]; memcpy(received, aBuf, aLen); // TODO? clean this line and add some checks Client* client = (Client*)aClient->getOwner(); client->getCipher().decrypt(received, aLen); size_t size = 0; for (size_t i = 0; i < aLen; i += size) { #if BYTE_ORDER == BIG_ENDIAN size = bswap16(((Msg::Header*)(received + i))->Length); #else size = ((Msg::Header*)(received + i))->Length; #endif ASSERT(size <= 1024); // invalid msg size... if (size < aLen) { uint8_t* packet = new uint8_t[size]; memcpy(packet, received + i, size); #if BYTE_ORDER == BIG_ENDIAN Msg::Header* header = (Msg::Header*)packet; header->Length = bswap16(header->Length); header->Type = bswap16(header->Type); #endif Msg* msg = nullptr; Msg::create(&msg, &packet, size); msg->process(client); SAFE_DELETE(msg); SAFE_DELETE_ARRAY(packet); } else { #if BYTE_ORDER == BIG_ENDIAN Msg::Header* header = (Msg::Header*)received; header->Length = bswap16(header->Length); header->Type = bswap16(header->Type); #endif Msg* msg = nullptr; Msg::create(&msg, &received, size); msg->process(client); SAFE_DELETE(msg); } } SAFE_DELETE_ARRAY(received); } }
//----------------------------------------------------------------------------- // <MultiInstance::HandleMultiChannelEndPointReport> // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- void MultiInstance::HandleMultiChannelEndPointReport ( uint8 const* _data, uint32 const _length ) { if( m_numEndpoints != 0 ) { return; } m_numEndPointsCanChange = (( _data[1] & 0x80 ) != 0 ); // Number of endpoints can change. m_endPointsAreSameClass = (( _data[1] & 0x40 ) != 0 ); // All endpoints are the same command class. m_numEndpoints = _data[2] & 0x7f; if( m_endPointsAreSameClass ) { Log::Write( LogLevel_Info, GetNodeId(), "Received MultiChannelEndPointReport from node %d. All %d endpoints are the same.", GetNodeId(), m_numEndpoints ); // Send a single capability request to endpoint 1 (since all classes are the same) char str[128]; snprintf( str, sizeof( str ), "MultiChannelCmd_CapabilityGet for endpoint 1" ); Msg* msg = new Msg( str, GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( GetNodeId() ); msg->Append( 3 ); msg->Append( GetCommandClassId() ); msg->Append( MultiChannelCmd_CapabilityGet ); msg->Append( 1 ); msg->Append( TRANSMIT_OPTION_ACK | TRANSMIT_OPTION_AUTO_ROUTE ); GetDriver()->SendMsg( msg, Driver::MsgQueue_Send ); } else { Log::Write( LogLevel_Info, GetNodeId(), "Received MultiChannelEndPointReport from node %d. Endpoints are not all the same.", GetNodeId() ); Log::Write( LogLevel_Info, GetNodeId(), " Starting search for endpoints by generic class..." ); // This is where things get really ugly. We need to get the capabilities of each // endpoint, but we only know how many there are, not which indices they // are at. We will first try to use MultiChannelCmd_EndPointFind to get // lists of indices. We have to specify a generic device class in the find, // so we try generic classes in an order likely to find the endpoints the quickest. m_endPointFindIndex = 0; m_numEndPointsFound = 0; char str[128]; snprintf( str, 128, "MultiChannelCmd_EndPointFind for generic device class 0x%.2x (%s)", c_genericClass[m_endPointFindIndex], c_genericClassName[m_endPointFindIndex] ); Msg* msg = new Msg( str, GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( GetNodeId() ); msg->Append( 4 ); msg->Append( GetCommandClassId() ); msg->Append( MultiChannelCmd_EndPointFind ); msg->Append( c_genericClass[m_endPointFindIndex] ); // Generic device class msg->Append( 0xff ); // Any specific device class msg->Append( TRANSMIT_OPTION_ACK | TRANSMIT_OPTION_AUTO_ROUTE ); GetDriver()->SendMsg( msg, Driver::MsgQueue_Send ); } }
//----------------------------------------------------------------------------- // <SensorMultilevel::RequestValue> // Request current value from the device //----------------------------------------------------------------------------- bool SensorMultilevel::RequestValue ( uint32 const _requestFlags, uint8 const _dummy, // = 0 (not used) uint8 const _instance, Driver::MsgQueue const _queue ) { bool res = false; if( GetVersion() < 5 ) { Msg* msg = new Msg( "SensorMultilevelCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->SetInstance( this, _instance ); msg->Append( GetNodeId() ); msg->Append( 2 ); msg->Append( GetCommandClassId() ); msg->Append( SensorMultilevelCmd_Get ); msg->Append( GetDriver()->GetTransmitOptions() ); GetDriver()->SendMsg( msg, _queue ); res = true; } else { for( uint8 i = 1; i < SensorType_MaxType; i++ ) { Value* value = GetValue( _instance, i ); if( value != NULL ) { value->Release(); Msg* msg = new Msg( "SensorMultilevelCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->SetInstance( this, _instance ); msg->Append( GetNodeId() ); msg->Append( 3 ); msg->Append( GetCommandClassId() ); msg->Append( SensorMultilevelCmd_Get ); msg->Append( i ); msg->Append( GetDriver()->GetTransmitOptions() ); GetDriver()->SendMsg( msg, _queue ); res = true; } } } return res; }
//----------------------------------------------------------------------------- // <MultiInstance::HandleMultiChannelCapabilityReport> // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- void MultiInstance::HandleMultiChannelCapabilityReport ( uint8 const* _data, uint32 const _length ) { if( Node* node = GetNodeUnsafe() ) { uint8 endPoint = _data[1] & 0x7f; bool dynamic = ((_data[1] & 0x80)!=0); Log::Write( LogLevel_Info, GetNodeId(), "Received MultiChannelCapabilityReport from node %d for endpoint %d", GetNodeId(), endPoint ); Log::Write( LogLevel_Info, GetNodeId(), " Endpoint is%sdynamic, and is a %s", dynamic ? " " : " not ", node->GetEndPointDeviceClassLabel( _data[2], _data[3] ).c_str() ); Log::Write( LogLevel_Info, GetNodeId(), " Command classes supported by the endpoint are:" ); // Store the command classes for later use bool afterMark = false; m_endPointCommandClasses.clear(); uint8 numCommandClasses = _length - 5; for( uint8 i=0; i<numCommandClasses; ++i ) { uint8 commandClassId = _data[i+4]; if( commandClassId == 0xef ) { afterMark = true; continue; } m_endPointCommandClasses.insert( commandClassId ); // Ensure the node supports this command class CommandClass* cc = node->GetCommandClass( commandClassId ); if( !cc ) { cc = node->AddCommandClass( commandClassId ); if( cc && afterMark ) { cc->SetAfterMark(); } } if( cc ) { Log::Write( LogLevel_Info, GetNodeId(), " %s", cc->GetCommandClassName().c_str() ); } } if( ( endPoint == 1 ) && m_endPointsAreSameClass ) { Log::Write( LogLevel_Info, GetNodeId(), "All endpoints in this device are the same as endpoint 1. Searching for the other endpoints..." ); // All end points have the same command classes. // We just need to find them... if (node->MultiEndPointFindSupported()) { char str[128]; snprintf( str, sizeof( str ), "MultiChannelCmd_EndPointFind for generic device class 0x%.2x", _data[2] ); Msg* msg = new Msg( str, GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( GetNodeId() ); msg->Append( 4 ); msg->Append( GetCommandClassId() ); msg->Append( MultiChannelCmd_EndPointFind ); msg->Append( _data[2] ); // Generic device class msg->Append( 0xff ); // Any specific device class msg->Append( TRANSMIT_OPTION_ACK | TRANSMIT_OPTION_AUTO_ROUTE ); GetDriver()->SendMsg( msg, Driver::MsgQueue_Send ); } else { // no way to find them, assume they are in ascending order for( uint8 endPoint=1; endPoint<=m_numEndpoints; ++endPoint ) { // Use the stored command class list to set up the endpoint. for( set<uint8>::iterator it=m_endPointCommandClasses.begin(); it!=m_endPointCommandClasses.end(); ++it ) { uint8 commandClassId = *it; CommandClass* cc = node->GetCommandClass( commandClassId ); if( cc ) { Log::Write( LogLevel_Info, GetNodeId(), " Endpoint %d: Adding %s", endPoint, cc->GetCommandClassName().c_str() ); cc->SetInstance( endPoint ); } } } } } else { // Create instances (endpoints) for each command class in the list for( set<uint8>::iterator it=m_endPointCommandClasses.begin(); it!=m_endPointCommandClasses.end(); ++it ) { uint8 commandClassId = *it; CommandClass* cc = node->GetCommandClass( commandClassId ); if( cc ) { cc->SetInstance( endPoint ); } } } } }
void AudioDriver::AudioThread() { HANDLE mmcssHandle = NULL; DWORD mmcssTaskIndex = 0; HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); if (hr != S_OK) { Log::Print("Unable to initialize COM in render thread: %x\n", hr); return; } // Gain access to the system multimedia audio endpoint and associate an // audio client object with it. if (InitializeAudioClient() == false) { goto Exit; } // Hook up to the Multimedia Class Scheduler Service to prioritise // our render activities. mmcssHandle = AvSetMmThreadCharacteristics(L"Audio", &mmcssTaskIndex); if (mmcssHandle == NULL) { Log::Print("Unable to enable MMCSS on render thread: %d\n", GetLastError()); goto Exit; } // Native events waited on in this thread. HANDLE waitArray[2] = {iAudioSessionDisconnectedEvent, iAudioSamplesReadyEvent}; // Pipeline processing loop. try { for (;;) { #ifdef _TIMINGS_DEBUG LARGE_INTEGER StartingTime, EndingTime, ElapsedMicroseconds; LARGE_INTEGER Frequency; QueryPerformanceFrequency(&Frequency); QueryPerformanceCounter(&StartingTime); #endif /* _TIMINGS_DEBUG */ TUint32 padding = 0; // // Calculate the number of bytes in the render buffer // for this period. // // This is the maximum we will pull from the pipeline. // // If the Audio Engine has not been initialized yet stick with // the default value. // if (iAudioEngineInitialised && ! iAudioSessionDisconnected) { hr = iAudioClient->GetCurrentPadding(&padding); if (hr == S_OK) { iRenderBytesThisPeriod = (iBufferSize - padding) * iFrameSize; } else { Log::Print("ERROR: Couldn't read render buffer padding\n"); iRenderBytesThisPeriod = 0; } iRenderBytesRemaining = iRenderBytesThisPeriod; } // // Process pipeline messages until we've reached the maximum for // this period. // // The pull will block if there are no messages. // for(;;) { if (iPlayable != NULL) { ProcessAudio(iPlayable); } else { Msg* msg = iPipeline.Pull(); ASSERT(msg != NULL); msg = msg->Process(*this); ASSERT(msg == NULL); } // // Have we reached the data limit for this period or been told // to exit ? // if (iPlayable != NULL || iQuit) { break; } } if (iQuit) { break; } // Log some interesting data if we can't fill at least half // of the available space in the render buffer. if (iRenderBytesThisPeriod * 0.5 < iRenderBytesRemaining) { Log::Print("Audio period: Requested Bytes [%u] : Returned Bytes" " [%u]\n", iRenderBytesThisPeriod, iRenderBytesThisPeriod - iRenderBytesRemaining); if (iPlayable) { TUint bytes = iPlayable->Bytes(); if (iResamplingInput) { // Calculate the bytes that will be generated by the // translation. long long tmp = (long long)bytes * (long long)iResampleOutputBps / (long long)iResampleInputBps; bytes = TUint(tmp); // Round up to the nearest frame. bytes += iMixFormat->nBlockAlign; bytes -= bytes % iMixFormat->nBlockAlign; } Log::Print(" Available Bytes [%u]\n", bytes); } else { Log::Print(" Available Bytes [0]\n"); } if (iAudioEngineInitialised) { Log::Print(" Period Start Frames In Buffer [%u]\n", padding); hr = iAudioClient->GetCurrentPadding(&padding); if (hr == S_OK) { Log::Print(" Current Frames In Buffer [%u]\n", padding); } } } #ifdef _TIMINGS_DEBUG QueryPerformanceCounter(&EndingTime); ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart; // // We now have the elapsed number of ticks, along with the // number of ticks-per-second. We use these values // to convert to the number of elapsed microseconds. // To guard against loss-of-precision, we convert // to microseconds *before* dividing by ticks-per-second. // ElapsedMicroseconds.QuadPart *= 1000000; ElapsedMicroseconds.QuadPart /= Frequency.QuadPart; Log::Print("Time To Process Messages This Audio Period [%lld us]\n", ElapsedMicroseconds.QuadPart); #endif /* _TIMINGS_DEBUG */ // The audio client isn't capable of playing this stream. // Continue to pull from pipeline until the next playable // stream is available. if (! iStreamFormatSupported) { continue; } // The audio session has been disconnected. // Continue to pull from pipeline until we are instructed to quit. if (iAudioSessionDisconnected) { continue; } // // Start the Audio client once we have pre-loaded some // data to the render buffer. // // This will prevent any initial audio glitches.. // if (! iAudioClientStarted) { // There was no data read this period so try again next period. if (iRenderBytesThisPeriod == iRenderBytesRemaining) { continue; } hr = iAudioClient->Start(); if (hr != S_OK) { Log::Print("Unable to start render client: %x.\n", hr); break; } iAudioClientStarted = true; } // Apply any volume changes if (iAudioClientStarted && iVolumeChanged) { iAudioSessionVolume->SetMasterVolume(iVolumeLevel, NULL); iVolumeChanged = false; } // Wait for a kick from the native audio engine. DWORD waitResult = WaitForMultipleObjects(2, waitArray, FALSE, INFINITE); switch (waitResult) { case WAIT_OBJECT_0 + 0: // iAudioSessionDisconnectedEvent // Stop the audio client iAudioClient->Stop(); iAudioClient->Reset(); iAudioClientStarted = false; iAudioSessionDisconnected = true; break; case WAIT_OBJECT_0 + 1: // iAudioSamplesReadyEvent break; default: Log::Print("ERROR: Unexpected event received [%d]\n", waitResult); } } } catch (ThreadKill&) {} Exit: // Complete any previous resampling session. if (iResamplingInput) { WWMFSampleData sampleData; hr = iResampler.Drain((iBufferSize * iFrameSize), &sampleData); if (hr == S_OK) { Log::Print("Resampler drained correctly [%d bytes].\n", sampleData.bytes); sampleData.Release(); } else { Log::Print("Resampler drain failed.\n"); } } iResampler.Finalize(); // Now we've stopped reading the pipeline, stop the native audio. StopAudioEngine(); // Free up native resources. ShutdownAudioEngine(); // Unhook from MMCSS. AvRevertMmThreadCharacteristics(mmcssHandle); CoUninitialize(); }
//----------------------------------------------------------------------------- // <MultiInstance::HandleMultiChannelEndPointFindReport> // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- void MultiInstance::HandleMultiChannelEndPointFindReport ( uint8 const* _data, uint32 const _length ) { Log::Write( LogLevel_Info, GetNodeId(), "Received MultiChannelEndPointFindReport from node %d", GetNodeId() ); uint8 numEndPoints = _length - 5; for( uint8 i=0; i<numEndPoints; ++i ) { uint8 endPoint = _data[i+4] & 0x7f; if( m_endPointsAreSameClass ) { // Use the stored command class list to set up the endpoint. if( Node* node = GetNodeUnsafe() ) { for( set<uint8>::iterator it=m_endPointCommandClasses.begin(); it!=m_endPointCommandClasses.end(); ++it ) { uint8 commandClassId = *it; CommandClass* cc = node->GetCommandClass( commandClassId ); if( cc ) { Log::Write( LogLevel_Info, GetNodeId(), " Endpoint %d: Adding %s", endPoint, cc->GetCommandClassName().c_str() ); cc->SetInstance( endPoint ); } } } } else { // Endpoints are different, so request the capabilities char str[128]; snprintf( str, 128, "MultiChannelCmd_CapabilityGet for node %d, endpoint %d", GetNodeId(), endPoint ); Msg* msg = new Msg( str, GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( GetNodeId() ); msg->Append( 3 ); msg->Append( GetCommandClassId() ); msg->Append( MultiChannelCmd_CapabilityGet ); msg->Append( endPoint ); msg->Append( TRANSMIT_OPTION_ACK | TRANSMIT_OPTION_AUTO_ROUTE ); GetDriver()->SendMsg( msg, Driver::MsgQueue_Send ); } } m_numEndPointsFound += numEndPoints; if( !m_endPointsAreSameClass ) { if( _data[1] == 0 ) { // No more reports to follow this one, so we can continue the search. if( m_numEndPointsFound < numEndPoints ) { // We have not yet found all the endpoints, so move to the next generic class request ++m_endPointFindIndex; if( c_genericClass[m_endPointFindIndex] > 0 ) { char str[128]; snprintf( str, 128, "MultiChannelCmd_EndPointFind for generic device class 0x%.2x (%s)", c_genericClass[m_endPointFindIndex], c_genericClassName[m_endPointFindIndex] ); Msg* msg = new Msg( str, GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( GetNodeId() ); msg->Append( 4 ); msg->Append( GetCommandClassId() ); msg->Append( MultiChannelCmd_EndPointFind ); msg->Append( c_genericClass[m_endPointFindIndex] ); // Generic device class msg->Append( 0xff ); // Any specific device class msg->Append( TRANSMIT_OPTION_ACK | TRANSMIT_OPTION_AUTO_ROUTE ); GetDriver()->SendMsg( msg, Driver::MsgQueue_Send ); } } } } }
std::string Raw_formatter::do_formatting(const Msg & msg) { return msg.getMsg_txt(); }
//----------------------------------------------------------------------------- // <MultiInstance::SendEncap> // Send a message encasulated in a MultiInstance/MultiChannel command //----------------------------------------------------------------------------- void MultiInstance::SendEncap ( uint8 const* _data, uint32 const _length, uint32 const _instance, uint32 const _requestFlags ) { char str[128]; Msg* msg; if( GetVersion() == 1 ) { // MultiInstance snprintf( str, sizeof( str ), "MultiInstanceCmd_Encap (Instance=%d)", _instance ); msg = new Msg( str, GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( GetNodeId() ); msg->Append( 3+_length ); msg->Append( GetCommandClassId() ); msg->Append( MultiInstanceCmd_Encap ); } else { // MultiChannel snprintf( str, sizeof( str ), "MultiChannelCmd_Encap (Instance=%d)", _instance ); msg = new Msg( str, GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( GetNodeId() ); msg->Append( 4+_length ); msg->Append( GetCommandClassId() ); msg->Append( MultiChannelCmd_Encap ); msg->Append( 0 ); } msg->Append( _instance ); for( uint8 i=0; i<_length; ++i ) { msg->Append( _data[i] ); } msg->Append( TRANSMIT_OPTION_ACK | TRANSMIT_OPTION_AUTO_ROUTE ); GetDriver()->SendMsg( msg, Driver::MsgQueue_Send ); }
void ABTMessageTest::test_xml(void) { using namespace maxmm::ma; { typedef ABTMessage<uint32_t> Msg; Msg msg; msg.make_ok(); msg.ok().agent_assignment().value() = 2; msg.ok().agent_assignment().agent_id() = AgentId(1); xmlpp::Document document; document.create_root_node("abt_message"); XmlEncoder encoder(document); msg.encode(encoder); std::cout << document.write_to_string() << std::endl; } { typedef ABTMessage<uint32_t> Msg; Msg msg; msg.make_nogood().nogoods().push_back(AgentAssignment<uint32_t>()); msg.nogood().nogoods().push_back(AgentAssignment<uint32_t>()); msg.nogood().nogoods().at(0).value() = 2; msg.nogood().nogoods().at(1).value() = 3; msg.nogood().nogoods().at(0).agent_id() = ma::AgentId(0); msg.nogood().nogoods().at(1).agent_id() = ma::AgentId(1); xmlpp::Document document; document.create_root_node("abt_message"); XmlEncoder encoder(document); msg.encode(encoder); std::cout << document.write_to_string() << std::endl; } }
//----------------------------------------------------------------------------- // <MultiInstance::RequestInstances> // Request number of instances of the specified command class from the device //----------------------------------------------------------------------------- bool MultiInstance::RequestInstances ( ) { bool res = false; if( GetVersion() == 1 ) { if( Node* node = GetNodeUnsafe() ) { // MULTI_INSTANCE char str[128]; for( map<uint8,CommandClass*>::const_iterator it = node->m_commandClassMap.begin(); it != node->m_commandClassMap.end(); ++it ) { CommandClass* cc = it->second; if( cc->HasStaticRequest( StaticRequest_Instances ) ) { snprintf( str, sizeof( str ), "MultiInstanceCmd_Get for %s", cc->GetCommandClassName().c_str() ); Msg* msg = new Msg( str, GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( GetNodeId() ); msg->Append( 3 ); msg->Append( GetCommandClassId() ); msg->Append( MultiInstanceCmd_Get ); msg->Append( cc->GetCommandClassId() ); msg->Append( TRANSMIT_OPTION_ACK | TRANSMIT_OPTION_AUTO_ROUTE ); GetDriver()->SendMsg( msg, Driver::MsgQueue_Query ); res = true; } } } } else { // MULTI_CHANNEL char str[128]; snprintf( str, sizeof( str ), "MultiChannelCmd_EndPointGet for node %d", GetNodeId() ); Msg* msg = new Msg( str, GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( GetNodeId() ); msg->Append( 2 ); msg->Append( GetCommandClassId() ); msg->Append( MultiChannelCmd_EndPointGet ); msg->Append( TRANSMIT_OPTION_ACK | TRANSMIT_OPTION_AUTO_ROUTE ); GetDriver()->SendMsg( msg, Driver::MsgQueue_Query ); res = true; } return res; }
//----------------------------------------------------------------------------- // <Security::HandleMsg> // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool Security::HandleMsg ( uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { switch( (SecurityCmd)_data[0] ) { case SecurityCmd_SupportedReport: { /* this is a list of CommandClasses that should be Encrypted. * and it might contain new command classes that were not present in the NodeInfoFrame * so we have to run through, mark existing Command Classes as SetSecured (so SendMsg in the Driver * class will route the unecrypted messages to our SendMsg) and for New Command * Classes, create them, and of course, also do a SetSecured on them. * * This means we must do a SecurityCmd_SupportedGet request ASAP so we dont have * Command Classes created after the Discovery Phase is completed! */ Log::Write(LogLevel_Info, GetNodeId(), "Received SecurityCmd_SupportedReport from node %d", GetNodeId() ); HandleSupportedReport(&_data[2], _length-2); break; } case SecurityCmd_SchemeReport: { Log::Write(LogLevel_Info, GetNodeId(), "Received SecurityCmd_SchemeReport from node %d: %d", GetNodeId(), _data[1]); uint8 schemes = _data[1]; if (m_schemeagreed == true) { Log::Write(LogLevel_Warning, GetNodeId(), " Already Received a SecurityCmd_SchemeReport from the node. Ignoring"); break; } if( schemes == SecurityScheme_Zero ) { /* We're good to go. We now should send our NetworkKey to the device if this is the first * time we have seen it */ Log::Write(LogLevel_Info, GetNodeId(), " Security scheme agreed." ); /* create the NetworkKey Packet. EncryptMessage will encrypt it for us (And request the NONCE) */ Msg * msg = new Msg ("SecurityCmd_NetworkKeySet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( GetNodeId() ); msg->Append( 18 ); msg->Append( GetCommandClassId() ); msg->Append( SecurityCmd_NetworkKeySet ); for (int i = 0; i < 16; i++) msg->Append(GetDriver()->GetNetworkKey()[i]); msg->Append( GetDriver()->GetTransmitOptions() ); this->SendMsg( msg); m_schemeagreed = true; } else { /* No common security scheme. The device should continue as an unsecured node. * but Some Command Classes might not be present... */ Log::Write(LogLevel_Warning, GetNodeId(), " No common security scheme. The device will continue as an unsecured node." ); } break; } case SecurityCmd_NetworkKeySet: { /* we shouldn't get a NetworkKeySet from a node if we are the controller * as we send it out to the Devices */ Log::Write(LogLevel_Info, GetNodeId(), "Received SecurityCmd_NetworkKeySet from node %d", GetNodeId() ); break; } case SecurityCmd_NetworkKeyVerify: { /* if we can decrypt this packet, then we are assured that our NetworkKeySet is successfull * and thus should set the Flag referenced in SecurityCmd_SchemeReport */ Log::Write(LogLevel_Info, GetNodeId(), "Received SecurityCmd_NetworkKeyVerify from node %d", GetNodeId() ); /* now as for our SupportedGet */ Msg* msg = new Msg( "SecurityCmd_SupportedGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( GetNodeId() ); msg->Append( 2 ); msg->Append( GetCommandClassId() ); msg->Append( SecurityCmd_SupportedGet ); msg->Append( GetDriver()->GetTransmitOptions() ); this->SendMsg( msg); break; } case SecurityCmd_SchemeInherit: { /* only used in a Controller Replication Type enviroment. * */ Log::Write(LogLevel_Info, GetNodeId(), "Received SecurityCmd_SchemeInherit from node %d", GetNodeId() ); break; } case SecurityCmd_NonceGet: { /* the Device wants to send us a Encrypted Packet, and thus requesting for our latest NONCE * */ Log::Write(LogLevel_Info, GetNodeId(), "Received SecurityCmd_NonceGet from node %d", GetNodeId() ); SendNonceReport(); break; } case SecurityCmd_NonceReport: { /* we recieved a NONCE from a device, so assume that there is something in a queue to send * out */ Log::Write(LogLevel_Info, GetNodeId(), "Received SecurityCmd_NonceReport from node %d", GetNodeId() ); EncryptMessage( &_data[1] ); m_waitingForNonce = false; break; } case SecurityCmd_MessageEncap: { /* We recieved a Encrypted single packet from the Device. Decrypt it. * */ Log::Write(LogLevel_Info, GetNodeId(), "Received SecurityCmd_MessageEncap from node %d", GetNodeId() ); DecryptMessage( _data, _length ); break; } case SecurityCmd_MessageEncapNonceGet: { /* we recieved a encrypted packet from the device, and the device is also asking us to send a * new NONCE to it, hence there must be multiple packets. */ Log::Write(LogLevel_Info, GetNodeId(), "Received SecurityCmd_MessageEncapNonceGet from node %d", GetNodeId() ); DecryptMessage( _data, _length ); /* Regardless of the success/failure of Decrypting, send a new NONCE */ SendNonceReport(); break; } default: { return false; } } return true; }
//----------------------------------------------------------------------------- // <ControllerReplication::SendNextData> // Send the next block of replication data //----------------------------------------------------------------------------- void ControllerReplication::SendNextData ( ) { uint16 i = 255; if( !m_busy ) { return; } while( 1 ) { if( m_groupIdx != -1 ) { m_groupIdx++; if( m_groupIdx <= m_groupCount ) { break; } } i = m_nodeId == -1 ? 0 : m_nodeId+1; LockGuard LG(GetDriver()->m_nodeMutex); while( i < 256 ) { if( GetDriver()->m_nodes[i] ) { m_groupCount = GetDriver()->m_nodes[i]->GetNumGroups(); if( m_groupCount != 0 ) { m_groupName = GetDriver()->m_nodes[i]->GetGroupLabel( m_groupIdx ); m_groupIdx = m_groupName.length() > 0 ? 0 : 1; break; } } i++; } m_nodeId = i; break; } if( i < 255 ) { Msg* msg = new Msg( (m_groupName.length() > 0 ? "ControllerReplicationCmd_TransferGroupName" : "ControllerReplicationCmd_TransferGroup"), m_targetNodeId, REQUEST, FUNC_ID_ZW_REPLICATION_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( m_targetNodeId ); if( m_groupName.length() > 0 ) { msg->Append((uint8) (m_groupName.length() + 4 )); msg->Append( GetCommandClassId() ); msg->Append( ControllerReplicationCmd_TransferGroupName ); msg->Append( 0 ); msg->Append( m_groupIdx ); for( uint8 j = 0; j < m_groupName.length(); j++ ) { msg->Append( m_groupName[j] ); } m_groupName = ""; } else { msg->Append( 5 ); msg->Append( GetCommandClassId() ); msg->Append( ControllerReplicationCmd_TransferGroup ); msg->Append( 0 ); msg->Append( m_groupIdx ); msg->Append( m_nodeId ); } msg->Append( TRANSMIT_OPTION_ACK ); GetDriver()->SendMsg( msg, Driver::MsgQueue_Command ); } else { GetDriver()->AddNodeStop( m_funcId ); m_busy = false; } }
//----------------------------------------------------------------------------- // <MultiInstance::HandleMultiChannelEndPointFindReport> // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- void MultiInstance::HandleMultiChannelEndPointFindReport ( uint8 const* _data, uint32 const _length ) { Log::Write( LogLevel_Info, GetNodeId(), "Received MultiChannelEndPointFindReport from node %d", GetNodeId() ); uint8 numEndPoints = _length - 5; for( uint8 i=0; i<numEndPoints; ++i ) { uint8 endPoint = _data[i+4] & 0x7f; if( m_endPointsAreSameClass ) { // Use the stored command class list to set up the endpoint. if( Node* node = GetNodeUnsafe() ) { for( set<uint8>::iterator it=m_endPointCommandClasses.begin(); it!=m_endPointCommandClasses.end(); ++it ) { uint8 commandClassId = *it; CommandClass* cc = node->GetCommandClass( commandClassId ); if( cc ) { Log::Write( LogLevel_Info, GetNodeId(), " Endpoint %d: Adding %s", endPoint, cc->GetCommandClassName().c_str() ); cc->SetInstance( endPoint ); } } } } else { // Endpoints are different, so request the capabilities Log::Write(LogLevel_Info, GetNodeId(), "MultiChannelCmd_CapabilityGet for node %d, endpoint %d", GetNodeId(), endPoint ); Msg* msg = new Msg( "MultiChannelCmd_CapabilityGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( GetNodeId() ); msg->Append( 3 ); msg->Append( GetCommandClassId() ); msg->Append( MultiChannelCmd_CapabilityGet ); msg->Append( endPoint ); msg->Append( GetDriver()->GetTransmitOptions() ); GetDriver()->SendMsg( msg, Driver::MsgQueue_Send ); } } m_numEndPointsFound += numEndPoints; if( !m_endPointsAreSameClass ) { if( _data[1] == 0 ) { // No more reports to follow this one, so we can continue the search. if( m_numEndPointsFound < numEndPoints ) { // We have not yet found all the endpoints, so move to the next generic class request ++m_endPointFindIndex; if (m_endPointFindIndex <= 13) /* we are finished */ { if( c_genericClass[m_endPointFindIndex] > 0 ) { if (m_endPointFindIndex > 13) /* size of c_genericClassName minus Unknown Entry */ { Log::Write (LogLevel_Warning, GetNodeId(), "m_endPointFindIndex Value was greater than range. Setting to Unknown"); m_endPointFindIndex = 14; } Log::Write(LogLevel_Info, GetNodeId(), "MultiChannelCmd_EndPointFind for generic device class 0x%.2x (%s)", c_genericClass[m_endPointFindIndex], c_genericClassName[m_endPointFindIndex] ); Msg* msg = new Msg( "MultiChannelCmd_EndPointFind", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( GetNodeId() ); msg->Append( 4 ); msg->Append( GetCommandClassId() ); msg->Append( MultiChannelCmd_EndPointFind ); msg->Append( c_genericClass[m_endPointFindIndex] ); // Generic device class msg->Append( 0xff ); // Any specific device class msg->Append( GetDriver()->GetTransmitOptions() ); GetDriver()->SendMsg( msg, Driver::MsgQueue_Send ); } } else { Log::Write (LogLevel_Warning, GetNodeId(), "m_endPointFindIndex is higher than range. Not Sending MultiChannelCmd_EndPointFind message"); } } } } }
//----------------------------------------------------------------------------- // <Security::HandleMsg> // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool Security::HandleMsg ( uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { switch( (SecurityCmd)_data[0] ) { case SecurityCmd_SupportedReport: { /* this is a list of CommandClasses that should be Encrypted. * and it might contain new command classes that were not present in the NodeInfoFrame * so we have to run through, mark existing Command Classes as SetSecured (so SendMsg in the Driver * class will route the unecrypted messages to our SendMsg) and for New Command * Classes, create them, and of course, also do a SetSecured on them. * * This means we must do a SecurityCmd_SupportedGet request ASAP so we dont have * Command Classes created after the Discovery Phase is completed! */ Log::Write(LogLevel_Info, GetNodeId(), "Received SecurityCmd_SupportedReport from node %d", GetNodeId() ); m_secured = true; if( ValueBool* value = static_cast<ValueBool*>( GetValue( _instance, 0 ) ) ) { value->OnValueRefreshed( m_secured ); value->Release(); } HandleSupportedReport(&_data[2], _length-2); break; } case SecurityCmd_SchemeReport: { Log::Write(LogLevel_Info, GetNodeId(), "Received SecurityCmd_SchemeReport from node %d: %d", GetNodeId(), _data[1]); uint8 schemes = _data[1]; if (m_schemeagreed == true) { Log::Write(LogLevel_Warning, GetNodeId(), " Already Received a SecurityCmd_SchemeReport from the node. Ignoring"); break; } if( schemes == SecurityScheme_Zero ) { /* We're good to go. We now should send our NetworkKey to the device if this is the first * time we have seen it */ Log::Write(LogLevel_Info, GetNodeId(), " Security scheme agreed." ); /* create the NetworkKey Packet. EncryptMessage will encrypt it for us (And request the NONCE) */ Msg * msg = new Msg ("SecurityCmd_NetworkKeySet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( GetNodeId() ); msg->Append( 18 ); msg->Append( GetCommandClassId() ); msg->Append( SecurityCmd_NetworkKeySet ); for (int i = 0; i < 16; i++) msg->Append(GetDriver()->GetNetworkKey()[i]); msg->Append( GetDriver()->GetTransmitOptions() ); msg->setEncrypted(); GetDriver()->SendMsg( msg, Driver::MsgQueue_Security); m_schemeagreed = true; } else { /* No common security scheme. The device should continue as an unsecured node. * but Some Command Classes might not be present... */ Log::Write(LogLevel_Warning, GetNodeId(), " No common security scheme. The device will continue as an unsecured node." ); } break; } case SecurityCmd_NetworkKeySet: { /* we shouldn't get a NetworkKeySet from a node if we are the controller * as we send it out to the Devices */ Log::Write(LogLevel_Info, GetNodeId(), "Received SecurityCmd_NetworkKeySet from node %d", GetNodeId() ); break; } case SecurityCmd_NetworkKeyVerify: { /* if we can decrypt this packet, then we are assured that our NetworkKeySet is successfull * and thus should set the Flag referenced in SecurityCmd_SchemeReport */ Log::Write(LogLevel_Info, GetNodeId(), "Received SecurityCmd_NetworkKeyVerify from node %d", GetNodeId() ); /* now as for our SupportedGet */ Msg* msg = new Msg( "SecurityCmd_SupportedGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( GetNodeId() ); msg->Append( 2 ); msg->Append( GetCommandClassId() ); msg->Append( SecurityCmd_SupportedGet ); msg->Append( GetDriver()->GetTransmitOptions() ); msg->setEncrypted(); GetDriver()->SendMsg( msg, Driver::MsgQueue_Security); break; } case SecurityCmd_SchemeInherit: { /* only used in a Controller Replication Type enviroment. * */ Log::Write(LogLevel_Info, GetNodeId(), "Received SecurityCmd_SchemeInherit from node %d", GetNodeId() ); break; } /* the rest of these should be handled by the Driver Code (in Driver::ProcessMsg) */ case SecurityCmd_NonceGet: case SecurityCmd_NonceReport: case SecurityCmd_MessageEncap: case SecurityCmd_MessageEncapNonceGet: { Log::Write(LogLevel_Warning, GetNodeId(), "Recieved a Security Message that should have been handled in the Driver"); break; } default: { return false; } } return true; }
//----------------------------------------------------------------------------- // <MultiInstance::RequestInstances> // Request number of instances of the specified command class from the device //----------------------------------------------------------------------------- bool MultiInstance::RequestInstances ( ) { bool res = false; if( GetVersion() == 1 ) { if( Node* node = GetNodeUnsafe() ) { // MULTI_INSTANCE for( map<uint8,CommandClass*>::const_iterator it = node->m_commandClassMap.begin(); it != node->m_commandClassMap.end(); ++it ) { CommandClass* cc = it->second; if( cc->GetCommandClassId() == NoOperation::StaticGetCommandClassId() ) { continue; } if( cc->HasStaticRequest( StaticRequest_Instances ) ) { Log::Write( LogLevel_Info, GetNodeId(), "MultiInstanceCmd_Get for %s", cc->GetCommandClassName().c_str() ); Msg* msg = new Msg( "MultiInstanceCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( GetNodeId() ); msg->Append( 3 ); msg->Append( GetCommandClassId() ); msg->Append( MultiInstanceCmd_Get ); msg->Append( cc->GetCommandClassId() ); msg->Append( GetDriver()->GetTransmitOptions() ); GetDriver()->SendMsg( msg, Driver::MsgQueue_Query ); res = true; } } } } else { // MULTI_CHANNEL Log::Write( LogLevel_Info, GetNodeId(), "MultiChannelCmd_EndPointGet for node %d", GetNodeId() ); Msg* msg = new Msg( "MultiChannelCmd_EndPointGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( GetNodeId() ); msg->Append( 2 ); msg->Append( GetCommandClassId() ); msg->Append( MultiChannelCmd_EndPointGet ); msg->Append( GetDriver()->GetTransmitOptions() ); GetDriver()->SendMsg( msg, Driver::MsgQueue_Query ); res = true; } return res; }
//----------------------------------------------------------------------------- // <SensorAlarm::RequestValue> // Get the sensor alarm details from the device //----------------------------------------------------------------------------- void SensorAlarm::RequestValue ( uint8 const _alarmType, uint8 const _dummy // = 0 (not used) ) { if( _alarmType == 0xff ) { // Request the supported setpoints Msg* msg = new Msg( "Request Supported Alarm Types", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( GetNodeId() ); msg->Append( 2 ); msg->Append( GetCommandClassId() ); msg->Append( SensorAlarmCmd_SupportedGet ); msg->Append( TRANSMIT_OPTION_ACK | TRANSMIT_OPTION_AUTO_ROUTE ); GetDriver()->SendMsg( msg ); return; } else { // Request the setpoint value Msg* msg = new Msg( "Request alarm state", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() ); msg->Append( GetNodeId() ); msg->Append( 3 ); msg->Append( GetCommandClassId() ); msg->Append( SensorAlarmCmd_Get ); msg->Append( _alarmType ); msg->Append( TRANSMIT_OPTION_ACK | TRANSMIT_OPTION_AUTO_ROUTE ); GetDriver()->SendMsg( msg ); } }