Merge changes Ie1b0c687,I4e6dfdfa,I2da14a56,I47041785,I34388f76, ... into main
* changes: [Thread] Add socket interface support in thread chip [Thread] Implement read on socket interface [Thread] Implement write on socket interface [Thread] Wait until socket created to create interface [Thread] Implement init/deinit socket interface [Thread] Initialize socket interface
This commit is contained in:
commit
57220562b0
4 changed files with 564 additions and 0 deletions
|
@ -37,6 +37,7 @@ cc_binary {
|
|||
srcs: [
|
||||
"main.cpp",
|
||||
"service.cpp",
|
||||
"socket_interface.cpp",
|
||||
"thread_chip.cpp",
|
||||
"utils.cpp",
|
||||
],
|
||||
|
@ -63,6 +64,7 @@ cc_fuzz {
|
|||
],
|
||||
|
||||
srcs: [
|
||||
"socket_interface.cpp",
|
||||
"thread_chip.cpp",
|
||||
"utils.cpp",
|
||||
"fuzzer.cpp",
|
||||
|
|
301
threadnetwork/aidl/default/socket_interface.cpp
Normal file
301
threadnetwork/aidl/default/socket_interface.cpp
Normal file
|
@ -0,0 +1,301 @@
|
|||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
* This file includes the implementation for the Socket interface to radio
|
||||
* (RCP).
|
||||
*/
|
||||
|
||||
#include "socket_interface.hpp"
|
||||
|
||||
#include <errno.h>
|
||||
#include <openthread/logging.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
#include "openthread/openthread-system.h"
|
||||
#include "platform-posix.h"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace threadnetwork {
|
||||
|
||||
SocketInterface::SocketInterface(const ot::Url::Url& aRadioUrl)
|
||||
: mReceiveFrameCallback(nullptr),
|
||||
mReceiveFrameContext(nullptr),
|
||||
mReceiveFrameBuffer(nullptr),
|
||||
mSockFd(-1),
|
||||
mRadioUrl(aRadioUrl) {
|
||||
memset(&mInterfaceMetrics, 0, sizeof(mInterfaceMetrics));
|
||||
mInterfaceMetrics.mRcpInterfaceType = kSpinelInterfaceTypeVendor;
|
||||
}
|
||||
|
||||
otError SocketInterface::Init(ReceiveFrameCallback aCallback, void* aCallbackContext,
|
||||
RxFrameBuffer& aFrameBuffer) {
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
VerifyOrExit(mSockFd == -1, error = OT_ERROR_ALREADY);
|
||||
|
||||
WaitForSocketFileCreated(mRadioUrl.GetPath());
|
||||
|
||||
mSockFd = OpenFile(mRadioUrl);
|
||||
VerifyOrExit(mSockFd != -1, error = OT_ERROR_FAILED);
|
||||
|
||||
mReceiveFrameCallback = aCallback;
|
||||
mReceiveFrameContext = aCallbackContext;
|
||||
mReceiveFrameBuffer = &aFrameBuffer;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
SocketInterface::~SocketInterface(void) {
|
||||
Deinit();
|
||||
}
|
||||
|
||||
void SocketInterface::Deinit(void) {
|
||||
CloseFile();
|
||||
|
||||
mReceiveFrameCallback = nullptr;
|
||||
mReceiveFrameContext = nullptr;
|
||||
mReceiveFrameBuffer = nullptr;
|
||||
}
|
||||
|
||||
otError SocketInterface::SendFrame(const uint8_t* aFrame, uint16_t aLength) {
|
||||
Write(aFrame, aLength);
|
||||
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
otError SocketInterface::WaitForFrame(uint64_t aTimeoutUs) {
|
||||
otError error = OT_ERROR_NONE;
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = static_cast<time_t>(aTimeoutUs / US_PER_S);
|
||||
timeout.tv_usec = static_cast<suseconds_t>(aTimeoutUs % US_PER_S);
|
||||
|
||||
fd_set readFds;
|
||||
fd_set errorFds;
|
||||
int rval;
|
||||
|
||||
FD_ZERO(&readFds);
|
||||
FD_ZERO(&errorFds);
|
||||
FD_SET(mSockFd, &readFds);
|
||||
FD_SET(mSockFd, &errorFds);
|
||||
|
||||
rval = TEMP_FAILURE_RETRY(select(mSockFd + 1, &readFds, nullptr, &errorFds, &timeout));
|
||||
|
||||
if (rval > 0) {
|
||||
if (FD_ISSET(mSockFd, &readFds)) {
|
||||
Read();
|
||||
} else if (FD_ISSET(mSockFd, &errorFds)) {
|
||||
DieNowWithMessage("RCP error", OT_EXIT_FAILURE);
|
||||
} else {
|
||||
DieNow(OT_EXIT_FAILURE);
|
||||
}
|
||||
} else if (rval == 0) {
|
||||
ExitNow(error = OT_ERROR_RESPONSE_TIMEOUT);
|
||||
} else {
|
||||
DieNowWithMessage("wait response", OT_EXIT_FAILURE);
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void SocketInterface::UpdateFdSet(void* aMainloopContext) {
|
||||
otSysMainloopContext* context = reinterpret_cast<otSysMainloopContext*>(aMainloopContext);
|
||||
|
||||
assert(context != nullptr);
|
||||
|
||||
FD_SET(mSockFd, &context->mReadFdSet);
|
||||
|
||||
if (context->mMaxFd < mSockFd) {
|
||||
context->mMaxFd = mSockFd;
|
||||
}
|
||||
}
|
||||
|
||||
void SocketInterface::Process(const void* aMainloopContext) {
|
||||
const otSysMainloopContext* context =
|
||||
reinterpret_cast<const otSysMainloopContext*>(aMainloopContext);
|
||||
|
||||
assert(context != nullptr);
|
||||
|
||||
if (FD_ISSET(mSockFd, &context->mReadFdSet)) {
|
||||
Read();
|
||||
}
|
||||
}
|
||||
|
||||
void SocketInterface::Read(void) {
|
||||
uint8_t buffer[kMaxFrameSize];
|
||||
|
||||
ssize_t rval = TEMP_FAILURE_RETRY(read(mSockFd, buffer, sizeof(buffer)));
|
||||
|
||||
if (rval > 0) {
|
||||
ProcessReceivedData(buffer, static_cast<uint16_t>(rval));
|
||||
} else if (rval < 0) {
|
||||
DieNow(OT_EXIT_ERROR_ERRNO);
|
||||
} else {
|
||||
otLogCritPlat("Socket connection is closed by remote.");
|
||||
exit(OT_EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void SocketInterface::Write(const uint8_t* aFrame, uint16_t aLength) {
|
||||
ssize_t rval = TEMP_FAILURE_RETRY(write(mSockFd, aFrame, aLength));
|
||||
VerifyOrDie(rval >= 0, OT_EXIT_ERROR_ERRNO);
|
||||
VerifyOrDie(rval > 0, OT_EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void SocketInterface::ProcessReceivedData(const uint8_t* aBuffer, uint16_t aLength) {
|
||||
while (aLength--) {
|
||||
uint8_t byte = *aBuffer++;
|
||||
if (mReceiveFrameBuffer->CanWrite(sizeof(uint8_t))) {
|
||||
IgnoreError(mReceiveFrameBuffer->WriteByte(byte));
|
||||
} else {
|
||||
HandleSocketFrame(this, OT_ERROR_NO_BUFS);
|
||||
return;
|
||||
}
|
||||
}
|
||||
HandleSocketFrame(this, OT_ERROR_NONE);
|
||||
}
|
||||
|
||||
void SocketInterface::HandleSocketFrame(void* aContext, otError aError) {
|
||||
static_cast<SocketInterface*>(aContext)->HandleSocketFrame(aError);
|
||||
}
|
||||
|
||||
void SocketInterface::HandleSocketFrame(otError aError) {
|
||||
VerifyOrExit((mReceiveFrameCallback != nullptr) && (mReceiveFrameBuffer != nullptr));
|
||||
|
||||
if (aError == OT_ERROR_NONE) {
|
||||
mReceiveFrameCallback(mReceiveFrameContext);
|
||||
} else {
|
||||
mReceiveFrameBuffer->DiscardFrame();
|
||||
otLogWarnPlat("Process socket frame failed: %s", otThreadErrorToString(aError));
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
int SocketInterface::OpenFile(const ot::Url::Url& aRadioUrl) {
|
||||
int fd = -1;
|
||||
sockaddr_un serverAddress;
|
||||
|
||||
VerifyOrExit(sizeof(serverAddress.sun_path) > strlen(aRadioUrl.GetPath()),
|
||||
otLogCritPlat("Invalid file path length"));
|
||||
strncpy(serverAddress.sun_path, aRadioUrl.GetPath(), sizeof(serverAddress.sun_path));
|
||||
serverAddress.sun_family = AF_UNIX;
|
||||
|
||||
fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
|
||||
VerifyOrExit(fd != -1, otLogCritPlat("open(): errno=%s", strerror(errno)));
|
||||
|
||||
if (connect(fd, reinterpret_cast<struct sockaddr*>(&serverAddress), sizeof(serverAddress)) ==
|
||||
-1) {
|
||||
otLogCritPlat("connect(): errno=%s", strerror(errno));
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
exit:
|
||||
return fd;
|
||||
}
|
||||
|
||||
void SocketInterface::CloseFile(void) {
|
||||
VerifyOrExit(mSockFd != -1);
|
||||
|
||||
VerifyOrExit(0 == close(mSockFd), otLogCritPlat("close(): errno=%s", strerror(errno)));
|
||||
VerifyOrExit(wait(nullptr) != -1 || errno == ECHILD,
|
||||
otLogCritPlat("wait(): errno=%s", strerror(errno)));
|
||||
|
||||
mSockFd = -1;
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void SocketInterface::WaitForSocketFileCreated(const char* aPath) {
|
||||
int inotifyFd;
|
||||
int wd;
|
||||
int lastSlashIdx;
|
||||
std::string folderPath;
|
||||
std::string socketPath(aPath);
|
||||
|
||||
VerifyOrExit(!IsSocketFileExisted(aPath));
|
||||
|
||||
inotifyFd = inotify_init();
|
||||
VerifyOrDie(inotifyFd != -1, OT_EXIT_ERROR_ERRNO);
|
||||
|
||||
lastSlashIdx = socketPath.find_last_of('/');
|
||||
VerifyOrDie(lastSlashIdx != std::string::npos, OT_EXIT_ERROR_ERRNO);
|
||||
|
||||
folderPath = socketPath.substr(0, lastSlashIdx);
|
||||
wd = inotify_add_watch(inotifyFd, folderPath.c_str(), IN_CREATE);
|
||||
VerifyOrDie(wd != -1, OT_EXIT_ERROR_ERRNO);
|
||||
|
||||
otLogInfoPlat("Waiting for socket file %s be created...", aPath);
|
||||
|
||||
while (true) {
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(inotifyFd, &fds);
|
||||
struct timeval timeout = {kMaxSelectTimeMs / MS_PER_S,
|
||||
(kMaxSelectTimeMs % MS_PER_S) * MS_PER_S};
|
||||
|
||||
int rval = select(inotifyFd + 1, &fds, nullptr, nullptr, &timeout);
|
||||
VerifyOrDie(rval >= 0, OT_EXIT_ERROR_ERRNO);
|
||||
|
||||
if (rval == 0 && IsSocketFileExisted(aPath)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (FD_ISSET(inotifyFd, &fds)) {
|
||||
char buffer[sizeof(struct inotify_event)];
|
||||
ssize_t bytesRead = read(inotifyFd, buffer, sizeof(buffer));
|
||||
|
||||
VerifyOrDie(bytesRead >= 0, OT_EXIT_ERROR_ERRNO);
|
||||
|
||||
struct inotify_event* event = reinterpret_cast<struct inotify_event*>(buffer);
|
||||
if ((event->mask & IN_CREATE) && IsSocketFileExisted(aPath)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close(inotifyFd);
|
||||
|
||||
exit:
|
||||
otLogInfoPlat("Socket file: %s is created", aPath);
|
||||
return;
|
||||
}
|
||||
|
||||
bool SocketInterface::IsSocketFileExisted(const char* aPath) {
|
||||
struct stat st;
|
||||
return stat(aPath, &st) == 0 && S_ISSOCK(st.st_mode);
|
||||
}
|
||||
|
||||
} // namespace threadnetwork
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
258
threadnetwork/aidl/default/socket_interface.hpp
Normal file
258
threadnetwork/aidl/default/socket_interface.hpp
Normal file
|
@ -0,0 +1,258 @@
|
|||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* 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
|
||||
* This file includes definitions for the Socket interface interface to radio
|
||||
* (RCP).
|
||||
*/
|
||||
|
||||
#include "lib/spinel/spinel_interface.hpp"
|
||||
#include "lib/url/url.hpp"
|
||||
|
||||
namespace aidl {
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace threadnetwork {
|
||||
|
||||
/**
|
||||
* Defines a Socket interface to the Radio Co-processor (RCP)
|
||||
*
|
||||
*/
|
||||
class SocketInterface : public ot::Spinel::SpinelInterface {
|
||||
public:
|
||||
/**
|
||||
* Initializes the object.
|
||||
*
|
||||
* @param[in] aRadioUrl RadioUrl parsed from radio url.
|
||||
*
|
||||
*/
|
||||
explicit SocketInterface(const ot::Url::Url& aRadioUrl);
|
||||
|
||||
/**
|
||||
* This destructor deinitializes the object.
|
||||
*
|
||||
*/
|
||||
~SocketInterface();
|
||||
|
||||
/**
|
||||
* Initializes the interface to the Radio Co-processor (RCP)
|
||||
*
|
||||
* @note This method should be called before reading and sending Spinel
|
||||
* frames to the interface.
|
||||
*
|
||||
* @param[in] aCallback Callback on frame received
|
||||
* @param[in] aCallbackContext Callback context
|
||||
* @param[in] aFrameBuffer A reference to a `RxFrameBuffer` object.
|
||||
*
|
||||
* @retval OT_ERROR_NONE The interface is initialized successfully
|
||||
* @retval OT_ERROR_ALREADY The interface is already initialized.
|
||||
* @retval OT_ERROR_FAILED Failed to initialize the interface.
|
||||
*
|
||||
*/
|
||||
otError Init(ReceiveFrameCallback aCallback, void* aCallbackContext,
|
||||
RxFrameBuffer& aFrameBuffer);
|
||||
|
||||
/**
|
||||
* Deinitializes the interface to the RCP.
|
||||
*
|
||||
*/
|
||||
void Deinit(void);
|
||||
|
||||
/**
|
||||
* Sends a Spinel frame to Radio Co-processor (RCP) over the
|
||||
* socket.
|
||||
*
|
||||
* @param[in] aFrame A pointer to buffer containing the Spinel frame to
|
||||
* send.
|
||||
* @param[in] aLength The length (number of bytes) in the frame.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully sent the Spinel frame.
|
||||
* @retval OT_ERROR_FAILED Failed to send a frame.
|
||||
*
|
||||
*/
|
||||
otError SendFrame(const uint8_t* aFrame, uint16_t aLength);
|
||||
|
||||
/**
|
||||
* Waits for receiving part or all of Spinel frame within specified
|
||||
* interval.
|
||||
*
|
||||
* @param[in] aTimeout The timeout value in microseconds.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Part or all of Spinel frame is
|
||||
* received.
|
||||
* @retval OT_ERROR_RESPONSE_TIMEOUT No Spinel frame is received within @p
|
||||
* aTimeout.
|
||||
* @retval OT_EXIT_FAILURE RCP error
|
||||
*
|
||||
*/
|
||||
otError WaitForFrame(uint64_t aTimeoutUs);
|
||||
|
||||
/**
|
||||
* Updates the file descriptor sets with file descriptors used by the radio
|
||||
* driver.
|
||||
*
|
||||
* @param[in,out] aMainloopContext A pointer to the mainloop context
|
||||
* containing fd_sets.
|
||||
*
|
||||
*/
|
||||
void UpdateFdSet(void* aMainloopContext);
|
||||
|
||||
/**
|
||||
* Performs radio driver processing.
|
||||
*
|
||||
* @param[in] aMainloopContext A pointer to the mainloop context
|
||||
* containing fd_sets.
|
||||
*
|
||||
*/
|
||||
void Process(const void* aMainloopContext);
|
||||
|
||||
/**
|
||||
* Returns the bus speed between the host and the radio.
|
||||
*
|
||||
* @return Bus speed in bits/second.
|
||||
*
|
||||
*/
|
||||
uint32_t GetBusSpeed(void) const { return 1000000; }
|
||||
|
||||
/**
|
||||
* Hardware resets the RCP.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully reset the RCP.
|
||||
* @retval OT_ERROR_NOT_IMPLEMENT The hardware reset is not implemented.
|
||||
*
|
||||
*/
|
||||
otError HardwareReset(void) { return OT_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
/**
|
||||
* Returns the RCP interface metrics.
|
||||
*
|
||||
* @return The RCP interface metrics.
|
||||
*
|
||||
*/
|
||||
const otRcpInterfaceMetrics* GetRcpInterfaceMetrics(void) const { return &mInterfaceMetrics; }
|
||||
|
||||
/**
|
||||
* Indicates whether or not the given interface matches this interface name.
|
||||
*
|
||||
* @param[in] aInterfaceName A pointer to the interface name.
|
||||
*
|
||||
* @retval TRUE The given interface name matches this interface name.
|
||||
* @retval FALSE The given interface name doesn't match this interface
|
||||
* name.
|
||||
*/
|
||||
static bool IsInterfaceNameMatch(const char* aInterfaceName) {
|
||||
static const char kInterfaceName[] = "spinel+socket";
|
||||
return (strncmp(aInterfaceName, kInterfaceName, strlen(kInterfaceName)) == 0);
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Instructs `SocketInterface` to read data from radio over the
|
||||
* socket.
|
||||
*
|
||||
* If a full Spinel frame is received, this method invokes the
|
||||
* `HandleSocketFrame()` (on the `aCallback` object from constructor) to
|
||||
* pass the received frame to be processed.
|
||||
*
|
||||
*/
|
||||
void Read(void);
|
||||
|
||||
/**
|
||||
* Writes a given frame to the socket.
|
||||
*
|
||||
* @param[in] aFrame A pointer to buffer containing the frame to write.
|
||||
* @param[in] aLength The length (number of bytes) in the frame.
|
||||
*
|
||||
*/
|
||||
void Write(const uint8_t* aFrame, uint16_t aLength);
|
||||
|
||||
/**
|
||||
* Process received data.
|
||||
*
|
||||
* If a full frame is finished processing and we obtain the raw Spinel
|
||||
* frame, this method invokes the `HandleSocketFrame()` (on the `aCallback`
|
||||
* object from constructor) to pass the received frame to be processed.
|
||||
*
|
||||
* @param[in] aBuffer A pointer to buffer containing data.
|
||||
* @param[in] aLength The length (number of bytes) in the buffer.
|
||||
*
|
||||
*/
|
||||
void ProcessReceivedData(const uint8_t* aBuffer, uint16_t aLength);
|
||||
|
||||
static void HandleSocketFrame(void* aContext, otError aError);
|
||||
void HandleSocketFrame(otError aError);
|
||||
|
||||
/**
|
||||
* Opens file specified by aRadioUrl.
|
||||
*
|
||||
* @param[in] aRadioUrl A reference to object containing path to file and
|
||||
* data for configuring the connection with tty type file.
|
||||
*
|
||||
* @retval The file descriptor of newly opened file.
|
||||
* @retval -1 Fail to open file.
|
||||
*
|
||||
*/
|
||||
int OpenFile(const ot::Url::Url& aRadioUrl);
|
||||
|
||||
/**
|
||||
* Closes file associated with the file descriptor.
|
||||
*
|
||||
*/
|
||||
void CloseFile(void);
|
||||
|
||||
/**
|
||||
* Check if socket file is created.
|
||||
*
|
||||
* @param[in] aPath Socket file path name.
|
||||
*
|
||||
* @retval TRUE The required socket file is created.
|
||||
* @retval FALSE The required socket file is not created.
|
||||
*
|
||||
*/
|
||||
bool IsSocketFileExisted(const char* aPath);
|
||||
|
||||
/**
|
||||
* Wait until the socket file is created.
|
||||
*
|
||||
* @param[in] aPath Socket file path name.
|
||||
*
|
||||
*/
|
||||
void WaitForSocketFileCreated(const char* aPath);
|
||||
|
||||
enum {
|
||||
kMaxSelectTimeMs = 2000, ///< Maximum wait time in Milliseconds for file
|
||||
///< descriptor to become available.
|
||||
};
|
||||
|
||||
ReceiveFrameCallback mReceiveFrameCallback;
|
||||
void* mReceiveFrameContext;
|
||||
RxFrameBuffer* mReceiveFrameBuffer;
|
||||
|
||||
int mSockFd;
|
||||
const ot::Url::Url& mRadioUrl;
|
||||
|
||||
otRcpInterfaceMetrics mInterfaceMetrics;
|
||||
|
||||
// Non-copyable, intentionally not implemented.
|
||||
SocketInterface(const SocketInterface&);
|
||||
SocketInterface& operator=(const SocketInterface&);
|
||||
};
|
||||
|
||||
} // namespace threadnetwork
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
} // namespace aidl
|
|
@ -24,6 +24,7 @@
|
|||
#include <utils/Log.h>
|
||||
|
||||
#include "hdlc_interface.hpp"
|
||||
#include "socket_interface.hpp"
|
||||
#include "spi_interface.hpp"
|
||||
|
||||
namespace aidl {
|
||||
|
@ -43,6 +44,8 @@ ThreadChip::ThreadChip(char* url) : mUrl(), mRxFrameBuffer(), mCallback(nullptr)
|
|||
mSpinelInterface = std::make_shared<ot::Posix::SpiInterface>(mUrl);
|
||||
} else if (ot::Posix::HdlcInterface::IsInterfaceNameMatch(interfaceName)) {
|
||||
mSpinelInterface = std::make_shared<ot::Posix::HdlcInterface>(mUrl);
|
||||
} else if (SocketInterface::IsInterfaceNameMatch(interfaceName)) {
|
||||
mSpinelInterface = std::make_shared<SocketInterface>(mUrl);
|
||||
} else {
|
||||
ALOGE("The interface \"%s\" is not supported", interfaceName);
|
||||
exit(EXIT_FAILURE);
|
||||
|
|
Loading…
Reference in a new issue