blob: 3518f94600ab929652bf8f66a1c350b76dc103cf [file] [log] [blame]
/*
*
* Copyright (c) 2020 Project CHIP Authors
* Copyright (c) 2019-2020 Google LLC.
* Copyright (c) 2013-2018 Nest Labs, Inc.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* Implementation of the native methods expected by the Python
* version of Chip Device Manager.
*
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#include <system/SystemError.h>
#include <system/SystemLayer.h>
#include <inttypes.h>
#include <net/if.h>
#if CONFIG_NETWORK_LAYER_BLE
#include "ChipDeviceController-BleApplicationDelegate.h"
#include "ChipDeviceController-BlePlatformDelegate.h"
#endif /* CONFIG_NETWORK_LAYER_BLE */
#include "ChipDeviceController-ScriptDevicePairingDelegate.h"
#include <controller/CHIPDeviceController_deprecated.h>
#include <support/CHIPMem.h>
#include <support/CodeUtils.h>
#include <support/DLLUtil.h>
#include <support/logging/CHIPLogging.h>
using namespace chip::Ble;
using namespace chip::DeviceController;
extern "C" {
typedef void * (*GetBleEventCBFunct)(void);
typedef void (*ConstructBytesArrayFunct)(const uint8_t * dataBuf, uint32_t dataLen);
typedef void (*LogMessageFunct)(uint64_t time, uint64_t timeUS, const char * moduleName, uint8_t category, const char * msg);
typedef void (*OnConnectFunct)(chip::DeviceController::ChipDeviceController * dc,
const chip::Transport::PeerConnectionState * state, void * appReqState);
typedef void (*OnErrorFunct)(chip::DeviceController::ChipDeviceController * dc, void * appReqState, CHIP_ERROR err,
const chip::Inet::IPPacketInfo * pi);
typedef void (*OnMessageFunct)(chip::DeviceController::ChipDeviceController * dc, void * appReqState,
chip::System::PacketBufferHandle buffer);
}
enum BleEventType
{
kBleEventType_Rx = 1,
kBleEventType_Tx = 2,
kBleEventType_Subscribe = 3,
kBleEventType_Disconnect = 4
};
enum BleSubscribeOperation
{
kBleSubOp_Subscribe = 1,
kBleSubOp_Unsubscribe = 2
};
class BleEventBase
{
public:
int32_t eventType;
};
class BleRxEvent : public BleEventBase
{
public:
void * connObj;
void * svcId;
void * charId;
void * buffer;
uint16_t length;
};
class BleTxEvent : public BleEventBase
{
public:
void * connObj;
void * svcId;
void * charId;
bool status;
};
class BleSubscribeEvent : public BleEventBase
{
public:
void * connObj;
void * svcId;
void * charId;
int32_t operation;
bool status;
};
class BleDisconnectEvent : public BleEventBase
{
public:
void * connObj;
int32_t error;
};
static chip::System::Layer sSystemLayer;
static chip::Inet::InetLayer sInetLayer;
// NOTE: Remote device ID is in sync with the echo server device id
// At some point, we may want to add an option to connect to a device without
// knowing its id, because the ID can be learned on the first response that is received.
chip::NodeId kLocalDeviceId = chip::kTestControllerNodeId;
chip::NodeId kRemoteDeviceId = chip::kTestDeviceNodeId;
#if CONFIG_NETWORK_LAYER_BLE
static BleLayer sBle;
static BLEEndPoint * spBleEndPoint = NULL;
static DeviceController_BlePlatformDelegate sBlePlatformDelegate(&sBle);
static DeviceController_BleApplicationDelegate sBleApplicationDelegate;
static volatile GetBleEventCBFunct GetBleEventCB = NULL;
static int BleWakePipe[2];
union
{
CompleteHandler General;
} sOnComplete;
ErrorHandler sOnError;
#endif /* CONFIG_NETWORK_LAYER_BLE */
extern "C" {
// Trampolined callback types
CHIP_ERROR nl_Chip_DeviceController_DriveIO(uint32_t sleepTimeMS);
#if CONFIG_NETWORK_LAYER_BLE
CHIP_ERROR nl_Chip_DeviceController_WakeForBleIO();
CHIP_ERROR nl_Chip_DeviceController_SetBleEventCB(GetBleEventCBFunct getBleEventCB);
CHIP_ERROR nl_Chip_DeviceController_SetBleWriteCharacteristic(WriteBleCharacteristicCBFunct writeBleCharacteristicCB);
CHIP_ERROR nl_Chip_DeviceController_SetBleSubscribeCharacteristic(SubscribeBleCharacteristicCBFunct subscribeBleCharacteristicCB);
CHIP_ERROR nl_Chip_DeviceController_SetBleClose(CloseBleCBFunct closeBleCB);
#endif /* CONFIG_NETWORK_LAYER_BLE */
CHIP_ERROR nl_Chip_DeviceController_NewDeviceController(chip::DeviceController::ChipDeviceController ** outDevCtrl);
CHIP_ERROR nl_Chip_DeviceController_DeleteDeviceController(chip::DeviceController::ChipDeviceController * devCtrl);
// Rendezvous
CHIP_ERROR nl_Chip_DeviceController_Connect(chip::DeviceController::ChipDeviceController * devCtrl, BLE_CONNECTION_OBJECT connObj,
uint32_t setupPinCode, OnConnectFunct onConnect, OnMessageFunct onMessage,
OnErrorFunct onError);
// Network Provisioning
CHIP_ERROR
nl_Chip_ScriptDevicePairingDelegate_NewPairingDelegate(chip::DeviceController::ScriptDevicePairingDelegate ** pairingDelegate);
CHIP_ERROR
nl_Chip_ScriptDevicePairingDelegate_SetWifiCredential(chip::DeviceController::ScriptDevicePairingDelegate * pairingDelegate,
const char * ssid, const char * password);
CHIP_ERROR nl_Chip_DeviceController_SetDevicePairingDelegate(chip::DeviceController::ChipDeviceController * devCtrl,
chip::Controller::DevicePairingDelegate * pairingDelegate);
#if CONFIG_NETWORK_LAYER_BLE
CHIP_ERROR nl_Chip_DeviceController_ValidateBTP(chip::DeviceController::ChipDeviceController * devCtrl,
BLE_CONNECTION_OBJECT connObj, CompleteHandler onComplete, ErrorHandler onError);
#endif /* CONFIG_NETWORK_LAYER_BLE */
bool nl_Chip_DeviceController_IsConnected(chip::DeviceController::ChipDeviceController * devCtrl);
void nl_Chip_DeviceController_Close(chip::DeviceController::ChipDeviceController * devCtrl);
uint8_t nl_Chip_DeviceController_GetLogFilter();
void nl_Chip_DeviceController_SetLogFilter(uint8_t category);
CHIP_ERROR nl_Chip_Stack_Init();
CHIP_ERROR nl_Chip_Stack_Shutdown();
const char * nl_Chip_Stack_ErrorToString(CHIP_ERROR err);
const char * nl_Chip_Stack_StatusReportToString(uint32_t profileId, uint16_t statusCode);
void nl_Chip_Stack_SetLogFunct(LogMessageFunct logFunct);
}
CHIP_ERROR nl_Chip_DeviceController_NewDeviceController(chip::DeviceController::ChipDeviceController ** outDevCtrl)
{
CHIP_ERROR err = CHIP_NO_ERROR;
*outDevCtrl = new chip::DeviceController::ChipDeviceController();
VerifyOrExit(*outDevCtrl != NULL, err = CHIP_ERROR_NO_MEMORY);
err = (*outDevCtrl)->Init(kLocalDeviceId, &sSystemLayer, &sInetLayer);
SuccessOrExit(err);
exit:
if (err != CHIP_NO_ERROR && *outDevCtrl != NULL)
{
delete *outDevCtrl;
*outDevCtrl = NULL;
}
return err;
}
CHIP_ERROR nl_Chip_DeviceController_DeleteDeviceController(chip::DeviceController::ChipDeviceController * devCtrl)
{
if (devCtrl != NULL)
{
devCtrl->Shutdown();
delete devCtrl;
}
return CHIP_NO_ERROR;
}
CHIP_ERROR nl_Chip_DeviceController_DriveIO(uint32_t sleepTimeMS)
{
CHIP_ERROR err = CHIP_NO_ERROR;
#if !CHIP_SYSTEM_CONFIG_USE_SOCKETS
ExitNow(err = CHIP_ERROR_NOT_IMPLEMENTED);
#else /* CHIP_SYSTEM_CONFIG_USE_SOCKETS */
struct timeval sleepTime;
fd_set readFDs, writeFDs, exceptFDs;
int maxFDs = 0;
#if CONFIG_NETWORK_LAYER_BLE
uint8_t bleWakeByte;
chip::System::PacketBufferHandle msgBuf;
ChipBleUUID svcId, charId;
union
{
const BleEventBase * ev;
const BleTxEvent * txEv;
const BleRxEvent * rxEv;
const BleSubscribeEvent * subscribeEv;
const BleDisconnectEvent * dcEv;
} evu;
#endif /* CONFIG_NETWORK_LAYER_BLE */
FD_ZERO(&readFDs);
FD_ZERO(&writeFDs);
FD_ZERO(&exceptFDs);
sleepTime.tv_sec = sleepTimeMS / 1000;
sleepTime.tv_usec = (sleepTimeMS % 1000) * 1000;
if (sSystemLayer.State() == chip::System::kLayerState_Initialized)
sSystemLayer.PrepareSelect(maxFDs, &readFDs, &writeFDs, &exceptFDs, sleepTime);
if (sInetLayer.State == chip::Inet::InetLayer::kState_Initialized)
sInetLayer.PrepareSelect(maxFDs, &readFDs, &writeFDs, &exceptFDs, sleepTime);
#if CONFIG_NETWORK_LAYER_BLE
// Add read end of BLE wake pipe to readFDs.
FD_SET(BleWakePipe[0], &readFDs);
if (BleWakePipe[0] + 1 > maxFDs)
maxFDs = BleWakePipe[0] + 1;
#endif /* CONFIG_NETWORK_LAYER_BLE */
int selectRes = select(maxFDs, &readFDs, &writeFDs, &exceptFDs, &sleepTime);
VerifyOrExit(selectRes >= 0, err = chip::System::MapErrorPOSIX(errno));
#if CONFIG_NETWORK_LAYER_BLE
// Drive IO to InetLayer and/or BleLayer.
if (FD_ISSET(BleWakePipe[0], &readFDs))
{
while (true)
{
if (read(BleWakePipe[0], &bleWakeByte, 1) == -1)
{
if (errno == EAGAIN)
break;
else
{
err = errno;
printf("bleWakePipe calling ExitNow()\n");
ExitNow();
}
}
if (GetBleEventCB)
{
evu.ev = static_cast<const BleEventBase *>(GetBleEventCB());
if (evu.ev)
{
switch (evu.ev->eventType)
{
case kBleEventType_Rx:
// build a packet buffer from the rxEv and send to blelayer.
msgBuf = chip::System::PacketBuffer::New();
VerifyOrExit(!msgBuf.IsNull(), err = CHIP_ERROR_NO_MEMORY);
memcpy(msgBuf->Start(), evu.rxEv->buffer, evu.rxEv->length);
msgBuf->SetDataLength(evu.rxEv->length);
// copy the svcId and charId from the event.
memcpy(svcId.bytes, evu.rxEv->svcId, sizeof(svcId.bytes));
memcpy(charId.bytes, evu.rxEv->charId, sizeof(charId.bytes));
sBle.HandleIndicationReceived(evu.txEv->connObj, &svcId, &charId, std::move(msgBuf));
break;
case kBleEventType_Tx:
// copy the svcId and charId from the event.
memcpy(svcId.bytes, evu.txEv->svcId, sizeof(svcId.bytes));
memcpy(charId.bytes, evu.txEv->charId, sizeof(charId.bytes));
sBle.HandleWriteConfirmation(evu.txEv->connObj, &svcId, &charId);
break;
case kBleEventType_Subscribe:
memcpy(svcId.bytes, evu.subscribeEv->svcId, sizeof(svcId.bytes));
memcpy(charId.bytes, evu.subscribeEv->charId, sizeof(charId.bytes));
switch (evu.subscribeEv->operation)
{
case kBleSubOp_Subscribe:
if (evu.subscribeEv->status)
{
sBle.HandleSubscribeComplete(evu.subscribeEv->connObj, &svcId, &charId);
}
else
{
sBle.HandleConnectionError(evu.subscribeEv->connObj, BLE_ERROR_GATT_SUBSCRIBE_FAILED);
}
break;
case kBleSubOp_Unsubscribe:
if (evu.subscribeEv->status)
{
sBle.HandleUnsubscribeComplete(evu.subscribeEv->connObj, &svcId, &charId);
}
else
{
sBle.HandleConnectionError(evu.subscribeEv->connObj, BLE_ERROR_GATT_UNSUBSCRIBE_FAILED);
}
break;
default:
printf("Error: unhandled subscribe operation. Calling ExitNow()\n");
ExitNow();
break;
}
break;
case kBleEventType_Disconnect:
sBle.HandleConnectionError(evu.dcEv->connObj, evu.dcEv->error);
break;
default:
printf("Error: unhandled sBle EventType. Calling ExitNow()\n");
ExitNow();
break;
}
}
else
{
printf("no event\n");
}
}
}
// Don't bother InetLayer if we only got BLE IO.
selectRes--;
}
#endif /* CONFIG_NETWORK_LAYER_BLE */
if (sSystemLayer.State() == chip::System::kLayerState_Initialized)
sSystemLayer.HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs);
if (sInetLayer.State == chip::Inet::InetLayer::kState_Initialized)
sInetLayer.HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs);
#endif /* CHIP_SYSTEM_CONFIG_USE_SOCKETS */
exit:
return err;
}
#if CONFIG_NETWORK_LAYER_BLE
CHIP_ERROR nl_Chip_DeviceController_WakeForBleIO()
{
if (BleWakePipe[1] == 0)
{
return CHIP_ERROR_INCORRECT_STATE;
}
// Write a single byte to the BLE wake pipe. This wakes the IO thread's select loop for BLE input.
if (write(BleWakePipe[1], "x", 1) == -1 && errno != EAGAIN)
{
return errno;
}
return CHIP_NO_ERROR;
}
CHIP_ERROR nl_Chip_DeviceController_SetBleEventCB(GetBleEventCBFunct getBleEventCB)
{
GetBleEventCB = getBleEventCB;
return CHIP_NO_ERROR;
}
CHIP_ERROR nl_Chip_DeviceController_SetBleWriteCharacteristic(WriteBleCharacteristicCBFunct writeBleCharacteristicCB)
{
sBlePlatformDelegate.SetWriteCharCB(writeBleCharacteristicCB);
return CHIP_NO_ERROR;
}
CHIP_ERROR nl_Chip_DeviceController_SetBleSubscribeCharacteristic(SubscribeBleCharacteristicCBFunct subscribeBleCharacteristicCB)
{
sBlePlatformDelegate.SetSubscribeCharCB(subscribeBleCharacteristicCB);
return CHIP_NO_ERROR;
}
CHIP_ERROR nl_Chip_DeviceController_SetBleClose(CloseBleCBFunct closeBleCB)
{
sBlePlatformDelegate.SetCloseCB(closeBleCB);
return CHIP_NO_ERROR;
}
#endif /* CONFIG_NETWORK_LAYER_BLE */
void nl_Chip_DeviceController_Close(chip::DeviceController::ChipDeviceController * devCtrl)
{
#if CONFIG_NETWORK_LAYER_BLE
if (spBleEndPoint != NULL)
{
spBleEndPoint->Close();
spBleEndPoint = NULL;
}
#endif
}
#if CONFIG_NETWORK_LAYER_BLE
static void HandleBleConnectComplete(BLEEndPoint * endPoint, BLE_ERROR err)
{
if (err != BLE_NO_ERROR)
{
ChipLogError(MessageLayer, "ChipoBle con failed %d", err);
spBleEndPoint->Abort();
sOnError(NULL, NULL, err, NULL);
}
else
{
ChipLogProgress(Controller, "ChipoBle con complete\n");
sOnComplete.General(NULL, NULL);
spBleEndPoint->Close();
}
spBleEndPoint = NULL;
}
static void HandleBleConnectionClosed(BLEEndPoint * endPoint, BLE_ERROR err)
{
ChipLogProgress(Controller, "ChipoBle con close\n");
}
CHIP_ERROR nl_Chip_DeviceController_ValidateBTP(chip::DeviceController::ChipDeviceController * devCtrl,
BLE_CONNECTION_OBJECT connObj, CompleteHandler onComplete, ErrorHandler onError)
{
CHIP_ERROR err = CHIP_NO_ERROR;
ChipLogProgress(Controller, "begin BTPConnect validation");
err = sBle.NewBleEndPoint(&spBleEndPoint, connObj, kBleRole_Central, false);
SuccessOrExit(err);
spBleEndPoint->mAppState = NULL;
spBleEndPoint->OnConnectComplete = HandleBleConnectComplete;
spBleEndPoint->OnConnectionClosed = HandleBleConnectionClosed;
sOnComplete.General = onComplete;
sOnError = onError;
err = spBleEndPoint->StartConnect();
SuccessOrExit(err);
exit:
return err;
}
#endif /* CONFIG_NETWORK_LAYER_BLE */
bool nl_Chip_DeviceController_IsConnected(chip::DeviceController::ChipDeviceController * devCtrl)
{
return devCtrl->IsConnected();
}
const char * nl_Chip_DeviceController_ErrorToString(CHIP_ERROR err)
{
return chip::ErrorStr(err);
}
const char * nl_Chip_DeviceController_StatusReportToString(uint32_t profileId, uint16_t statusCode)
{
// return chip::StatusReportStr(profileId, statusCode);
return NULL;
}
uint8_t nl_Chip_DeviceController_GetLogFilter()
{
#if _CHIP_USE_LOGGING
return chip::Logging::GetLogFilter();
#else
return chip::Logging::kLogCategory_None;
#endif
}
void nl_Chip_DeviceController_SetLogFilter(uint8_t category)
{
#if _CHIP_USE_LOGGING
chip::Logging::SetLogFilter(category);
#endif
}
CHIP_ERROR nl_Chip_DeviceController_Connect(chip::DeviceController::ChipDeviceController * devCtrl, BLE_CONNECTION_OBJECT connObj,
uint32_t setupPINCode, OnConnectFunct onConnect, OnMessageFunct onMessage,
OnErrorFunct onError)
{
CHIP_ERROR err = CHIP_NO_ERROR;
chip::RendezvousParameters params =
chip::RendezvousParameters().SetSetupPINCode(setupPINCode).SetConnectionObject(connObj).SetBleLayer(&sBle);
err = devCtrl->ConnectDevice(kRemoteDeviceId, params, (void *) devCtrl, onConnect, onMessage, onError);
SuccessOrExit(err);
exit:
return err;
}
CHIP_ERROR
nl_Chip_ScriptDevicePairingDelegate_NewPairingDelegate(chip::DeviceController::ScriptDevicePairingDelegate ** pairingDelegate)
{
CHIP_ERROR err = CHIP_NO_ERROR;
VerifyOrExit(pairingDelegate != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
*pairingDelegate = new chip::DeviceController::ScriptDevicePairingDelegate();
exit:
if (err != CHIP_NO_ERROR && pairingDelegate != nullptr && *pairingDelegate != nullptr)
{
delete *pairingDelegate;
*pairingDelegate = nullptr;
}
return err;
}
CHIP_ERROR
nl_Chip_ScriptDevicePairingDelegate_SetWifiCredential(chip::DeviceController::ScriptDevicePairingDelegate * pairingDelegate,
const char * ssid, const char * password)
{
CHIP_ERROR err = CHIP_NO_ERROR;
VerifyOrExit(pairingDelegate != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrExit(ssid != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrExit(password != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
pairingDelegate->SetWifiCredential(ssid, password);
exit:
return err;
}
CHIP_ERROR nl_Chip_DeviceController_SetDevicePairingDelegate(chip::DeviceController::ChipDeviceController * devCtrl,
chip::Controller::DevicePairingDelegate * pairingDelegate)
{
CHIP_ERROR err = CHIP_NO_ERROR;
VerifyOrExit(devCtrl != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrExit(pairingDelegate != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
devCtrl->SetDevicePairingDelegate(pairingDelegate);
exit:
return err;
}
CHIP_ERROR nl_Chip_Stack_Init()
{
CHIP_ERROR err = CHIP_NO_ERROR;
err = chip::Platform::MemoryInit();
SuccessOrExit(err);
#if CHIP_SYSTEM_CONFIG_USE_SOCKETS && CONFIG_NETWORK_LAYER_BLE
int flags;
#endif /* CHIP_SYSTEM_CONFIG_USE_SOCKETS && CONFIG_NETWORK_LAYER_BLE */
#if !CHIP_SYSTEM_CONFIG_USE_SOCKETS
ExitNow(err = CHIP_ERROR_NOT_IMPLEMENTED);
#else /* CHIP_SYSTEM_CONFIG_USE_SOCKETS */
if (sSystemLayer.State() == chip::System::kLayerState_Initialized)
ExitNow();
err = sSystemLayer.Init(NULL);
SuccessOrExit(err);
if (sInetLayer.State == chip::Inet::InetLayer::kState_Initialized)
ExitNow();
// Initialize the InetLayer object.
err = sInetLayer.Init(sSystemLayer, NULL);
SuccessOrExit(err);
#if CONFIG_NETWORK_LAYER_BLE
// Initialize the BleLayer object. For now, assume Device Controller is always a central.
err = sBle.Init(&sBlePlatformDelegate, nullptr, &sBleApplicationDelegate, &sSystemLayer);
SuccessOrExit(err);
// Create BLE wake pipe and make it non-blocking.
if (pipe(BleWakePipe) == -1)
{
err = chip::System::MapErrorPOSIX(errno);
ExitNow();
}
// Make read end non-blocking.
flags = fcntl(BleWakePipe[0], F_GETFL);
if (flags == -1)
{
err = chip::System::MapErrorPOSIX(errno);
ExitNow();
}
flags |= O_NONBLOCK;
if (fcntl(BleWakePipe[0], F_SETFL, flags) == -1)
{
err = chip::System::MapErrorPOSIX(errno);
ExitNow();
}
// Make write end non-blocking.
flags = fcntl(BleWakePipe[1], F_GETFL);
if (flags == -1)
{
err = chip::System::MapErrorPOSIX(errno);
ExitNow();
}
flags |= O_NONBLOCK;
if (fcntl(BleWakePipe[1], F_SETFL, flags) == -1)
{
err = chip::System::MapErrorPOSIX(errno);
ExitNow();
}
#endif /* CONFIG_NETWORK_LAYER_BLE */
#endif /* CHIP_SYSTEM_CONFIG_USE_SOCKETS */
exit:
if (err != CHIP_NO_ERROR)
nl_Chip_Stack_Shutdown();
return err;
}
CHIP_ERROR nl_Chip_Stack_Shutdown()
{
CHIP_ERROR err = CHIP_NO_ERROR;
if (sInetLayer.State == chip::Inet::InetLayer::kState_NotInitialized)
ExitNow();
if (sSystemLayer.State() == chip::System::kLayerState_NotInitialized)
ExitNow();
exit:
return err;
}
const char * nl_Chip_Stack_ErrorToString(CHIP_ERROR err)
{
return chip::ErrorStr(err);
}
const char * nl_Chip_Stack_StatusReportToString(uint32_t profileId, uint16_t statusCode)
{
// return chip::StatusReportStr(profileId, statusCode);
return NULL;
}
#if _CHIP_USE_LOGGING && CHIP_LOG_ENABLE_DYNAMIC_LOGING_FUNCTION
// A pointer to the python logging function.
static LogMessageFunct sLogMessageFunct = NULL;
// This function is called by the Chip logging code whenever a developer message
// is logged. It serves as glue to adapt the logging arguments to what is expected
// by the python code.
// NOTE that this function MUST be thread-safe.
static void LogMessageToPython(uint8_t module, uint8_t category, const char * msg, va_list ap)
{
if (IsCategoryEnabled(category))
{
// Capture the timestamp of the log message.
struct timeval tv;
gettimeofday(&tv, NULL);
// Get the module name
char moduleName[nlChipLoggingModuleNameLen + 1];
::chip:: ::Logging::GetModuleName(moduleName, module);
// Format the log message into a dynamic memory buffer, growing the
// buffer as needed to fit the message.
char * msgBuf = NULL;
size_t msgBufSize = 0;
size_t msgSize = 0;
constexpr size_t kInitialBufSize = 120;
do
{
va_list apCopy;
va_copy(apCopy, ap);
msgBufSize = max(msgSize + 1, kInitialBufSize);
msgBuf = (char *) realloc(msgBuf, msgBufSize);
if (msgBuf == NULL)
{
return;
}
int res = vsnprintf(msgBuf, msgBufSize, msg, apCopy);
if (res < 0)
{
return;
}
msgSize = (size_t) res;
va_end(apCopy);
} while (msgSize >= msgBufSize);
// Call the configured python logging function.
sLogMessageFunct((int64_t) tv.tv_sec, (int64_t) tv.tv_usec, moduleName, category, msgBuf);
// Release the message buffer.
free(msgBuf);
}
}
void nl_Chip_Stack_SetLogFunct(LogMessageFunct logFunct)
{
if (logFunct != NULL)
{
sLogMessageFunct = logFunct;
::chip::Logging::SetLogFunct(LogMessageToPython);
}
else
{
sLogMessageFunct = NULL;
::chip::Logging::SetLogFunct(NULL);
}
}
#else // CHIP_LOG_ENABLE_DYNAMIC_LOGING_FUNCTION
void nl_Chip_Stack_SetLogFunct(LogMessageFunct logFunct) {}
#endif // CHIP_LOG_ENABLE_DYNAMIC_LOGING_FUNCTION