blob: 754d56eb3bd119a092380f6e08b91ad3b309148f [file] [log] [blame]
/*
* Copyright (c) 2016-2017, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file implements the OpenThread platform abstraction for cli over ip socket communication.
*
*/
#include "platform_qorvo.h"
#include "alarm_qorvo.h"
#include "uart_qorvo.h"
#include <assert.h>
#include <fcntl.h>
#include <poll.h>
#include <stdlib.h>
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <pthread.h>
#include <openthread/config.h>
#include <common/code_utils.hpp>
#include <openthread/platform/uart.h>
#include "utils/code_utils.h"
#define BUFFER_MAX_SIZE 255
#define SOCKET_PORT 9190
#define SOCKET_WRITE(socketInfo, buf, length) sendto(socketInfo.socketId, (const char*)buf, length, 0, &socketInfo.addr, sizeof(socketInfo.addr))
#define SOCKET_READ(socketId, buf, length) recv(socketId, buf, length, 0)
typedef struct
{
uint32_t socketId;
bool isValid;
struct sockaddr addr;
pthread_t rfReadThread;
} PlatSocket_t;
PlatSocket_t PlatSocketConnection;
int PlatSocketPipeFd [2];
int PlatServerSocketId;
void PlatSocketRxNewConn(uint8_t id);
void PlatSocketInit(void);
void PlatSocketDeInit(void);
int PlatSocketTxData(uint16_t length, uint8_t *pData, uint32_t socketId);
#define PLAT_UART_MAX_CHAR 1024
uint32_t PlatSocketId = 0;
void PlatSocketSendInput(void *buffer)
{
uint8_t len = 0;
uint8_t *buf = (uint8_t *) buffer;
len = strlen((char *)buf);
otPlatUartReceived((uint8_t *) buf, (uint16_t)len);
free(buf);
buf = 0;
len = 0;
}
void PlatSocketRx(uint16_t length, const char *buffer, uint32_t socketId)
{
uint8_t *buf = 0;
PlatSocketId = socketId;
if (length > 0)
{
buf = malloc(length + 2);
memcpy(buf, buffer, length);
buf[length] = '\n';
buf[length + 1] = 0;
qorvoAlarmScheduleEventArg(0, PlatSocketSendInput, (void *) buf);
}
}
void PlatSocketClose(uint32_t socketId)
{
OT_UNUSED_VARIABLE(socketId);
}
otError otPlatUartEnable(void)
{
PlatSocketInit();
return OT_ERROR_NONE;
}
otError otPlatUartDisable(void)
{
PlatSocketDeInit();
return OT_ERROR_NONE;
}
otError otPlatUartSend(const uint8_t *aBuf, uint16_t aBufLength)
{
otError error = OT_ERROR_NONE;
char localbuf[PLAT_UART_MAX_CHAR];
memcpy(localbuf, aBuf, aBufLength);
localbuf[aBufLength] = 0;
printf("%s", localbuf);
if (PlatSocketId)
{
PlatSocketTxData(aBufLength, (uint8_t *) aBuf, PlatSocketId);
}
otPlatUartSendDone();
return error;
}
otError otPlatUartFlush(void)
{
return OT_ERROR_NOT_IMPLEMENTED;
}
void platformUartInit(void)
{
}
void platformUartProcess(void)
{
}
int PlatSocketListenForClients()
{
//Setup server side socket
int sockfd;
struct sockaddr_in serv_addr;
uint32_t flag = 1;
int ret;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
otEXPECT_ACTION(sockfd >= 0, sockfd = -1);
// disable Nagle's algorithm to avoid long latency
setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag));
// allow reuse of the same address
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, sizeof(flag));
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SOCKET_PORT);
ret = bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
otEXPECT_ACTION(ret >= 0, close(sockfd); sockfd = -1);
ret = listen(sockfd, 10);
otEXPECT_ACTION(ret != -1, exit(1));
exit:
return sockfd;
}
void PlatSocketRxSignaled(uint8_t id)
{
OT_UNUSED_VARIABLE(id);
//Dummy callback function to flush pipe
uint8_t readChar;
//Remove trigger byte from pipe
read(PlatSocketPipeFd [0], &readChar, 1);
}
void *PlatSocketReadThread(void *pClientSocket)
{
char buffer[BUFFER_MAX_SIZE];
PlatSocket_t *clientSocket = ((PlatSocket_t *)pClientSocket);
memset(buffer, 0, BUFFER_MAX_SIZE);
while (1)
{
int readLen = SOCKET_READ(clientSocket->socketId, buffer, BUFFER_MAX_SIZE);
if (readLen < 0)
{
perror("Reading socket");
break;
}
else
{
if (readLen == 0)
{
break;
}
{
uint8_t someByte = 0x12; //No functional use only using pipe to kick main thread
PlatSocketRx(readLen, buffer, clientSocket->socketId);
write(PlatSocketPipeFd [1], &someByte, 1); //[1] = write fd
}
}
}
clientSocket->isValid = 0;
qorvoPlatUnRegisterPollFunction(clientSocket->socketId);
close(clientSocket->socketId);
PlatSocketClose(clientSocket->socketId);
return NULL;
}
void PlatSocketRxNewConn(uint8_t id)
{
//Find first non-valid client in list - add here
if (PlatSocketConnection.isValid == 0)
{
//Add new client to client list
socklen_t len;
len = sizeof(PlatSocketConnection.addr);
int retval = accept(id, (struct sockaddr *)&PlatSocketConnection.addr, (socklen_t *) &len);
if (retval >= 0)
{
int retErr;
PlatSocketConnection.socketId = retval;
retErr = pthread_create(&PlatSocketConnection.rfReadThread,
NULL,
PlatSocketReadThread,
&PlatSocketConnection);
if (retErr)
{
close(PlatSocketConnection.socketId);
}
else
{
PlatSocketConnection.isValid = 1;
}
}
}
else
{
int tempfd;
tempfd = accept(id, (struct sockaddr *)NULL, NULL);
if (tempfd >= 0)
{
close(tempfd);
}
}
}
/*****************************************************************************
* Public Function Definitions
*****************************************************************************/
void PlatSocketInit(void)
{
memset(&PlatSocketConnection, 0, sizeof(PlatSocketConnection));
// in case we are a server, setup listening for client
PlatServerSocketId = PlatSocketListenForClients();
qorvoPlatRegisterPollFunction(PlatServerSocketId, PlatSocketRxNewConn);
// hack
pipe(PlatSocketPipeFd);
qorvoPlatRegisterPollFunction(PlatSocketPipeFd [0], PlatSocketRxSignaled);
}
void platformUartRestore(void)
{
PlatSocketDeInit();
}
void PlatSocketDeInit(void)
{
qorvoPlatUnRegisterPollFunction(PlatServerSocketId);
close(PlatServerSocketId);
qorvoPlatUnRegisterPollFunction(PlatSocketPipeFd[0]);
close(PlatSocketPipeFd[0]);
close(PlatSocketPipeFd[1]);
close(PlatSocketConnection.socketId);
}
int PlatSocketTxData(uint16_t length, uint8_t *pData, uint32_t socketId)
{
int result = -1;
//All sockets
if (PlatSocketConnection.isValid)
{
if (PlatSocketConnection.socketId == socketId)
{
if (SOCKET_WRITE(PlatSocketConnection, (const char *)pData, length) < 0)
{
perror("TxSocket: Error Writing to client");
close(PlatSocketConnection.socketId);
PlatSocketConnection.isValid = 0;
}
else
{
result = 0;
}
}
}
return result;
}