Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of cc3000_hostdriver_mbedsocket by
cc3000_socket.cpp
- Committer:
- SolderSplashLabs
- Date:
- 2013-10-03
- Revision:
- 23:fed7f64dd520
- Parent:
- 16:f3676ae62f96
- Child:
- 42:bd2c631a031a
File content as of revision 23:fed7f64dd520:
/*****************************************************************************
*
* C++ interface/implementation created by Martin Kojtal (0xc0170). Thanks to
* Jim Carver and Frank Vannieuwkerke for their inital cc3000 mbed port and
* provided help.
*
* This version of "host driver" uses CC3000 Host Driver Implementation. Thus
* read the following copyright:
*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 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.
*
* Neither the name of Texas Instruments Incorporated 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
* OWNER 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.
*
*****************************************************************************/
#include "cc3000.h"
#include "cc3000_socket.h"
#include "cc3000_event.h" //TODO - remove this
#include "cc3000_common.h"
namespace mbed_cc3000 {
cc3000_socket::cc3000_socket(cc3000_simple_link &simplelink, cc3000_hci &hci, cc3000_event &event)
: _simple_link(simplelink), _hci(hci), _event(event)
{
}
cc3000_socket::~cc3000_socket()
{
}
int32_t cc3000_socket::HostFlowControlConsumeBuff(int32_t sd) {
#ifndef SEND_NON_BLOCKING
/* wait in busy loop */
do
{
// When the last transmission failed, return the last failure reason.
// Note that the buffer will not be allocated in this case
if (_simple_link.get_transmit_error() != 0)
{
errno = _simple_link.get_transmit_error();
_simple_link.set_transmit_error(0);
return errno;
}
if(SOCKET_STATUS_ACTIVE != _event.get_socket_active_status(sd))
return -1;
} while(0 == _simple_link.get_number_free_buffers());
uint16_t free_buffer = _simple_link.get_number_free_buffers();
free_buffer--;
_simple_link.set_number_free_buffers(free_buffer);
return 0;
#else
// When the last transmission failed, return the last failure reason.
// Note that the buffer will not be allocated in this case
if (_simple_link.get_transmit_error() != 0)
{
errno = _simple_link.get_transmit_error();
_simple_link.set_transmit_error(0);
return errno;
}
if(SOCKET_STATUS_ACTIVE != _event.get_socket_active_status(sd))
return -1;
// If there are no available buffers, return -2. It is recommended to use
// select or receive to see if there is any buffer occupied with received data
// If so, call receive() to release the buffer.
if(0 == _simple_link.get_number_free_buffers())
{
return -2;
}
else
{
uint16_t free_buffer = _simple_link.get_number_free_buffers();
free_buffer--;
_simple_link.set_number_free_buffers(free_buffer);
return 0;
}
#endif
}
int32_t cc3000_socket::socket(int32_t domain, int32_t type, int32_t protocol) {
int32_t ret;
uint8_t *ptr, *args;
ret = EFAIL;
ptr = _simple_link.get_transmit_buffer();
args = (ptr + HEADERS_SIZE_CMD);
// Fill in HCI packet structure
args = UINT32_TO_STREAM(args, domain);
args = UINT32_TO_STREAM(args, type);
args = UINT32_TO_STREAM(args, protocol);
// Initiate a HCI command
_hci.command_send(HCI_CMND_SOCKET, ptr, SOCKET_OPEN_PARAMS_LEN);
// Since we are in blocking state - wait for event complete
_event.simplelink_wait_event(HCI_CMND_SOCKET, &ret);
// Process the event
errno = ret;
_event.set_socket_active_status(ret, SOCKET_STATUS_ACTIVE);
return(ret);
}
int32_t cc3000_socket::closesocket(int32_t sd) {
int32_t ret;
uint8_t *ptr, *args;
while(_simple_link.get_number_free_buffers() != SOCKET_MAX_FREE_BUFFERS);
ret = EFAIL;
ptr = _simple_link.get_transmit_buffer();
args = (ptr + HEADERS_SIZE_CMD);
// Fill in HCI packet structure
args = UINT32_TO_STREAM(args, sd);
// Initiate a HCI command
_hci.command_send(HCI_CMND_CLOSE_SOCKET, ptr, SOCKET_CLOSE_PARAMS_LEN);
// Since we are in blocking state - wait for event complete
_event.simplelink_wait_event(HCI_CMND_CLOSE_SOCKET, &ret);
errno = ret;
// since 'close' call may result in either OK (and then it closed) or error, mark this socket as invalid
_event.set_socket_active_status(sd, SOCKET_STATUS_INACTIVE);
return(ret);
}
int32_t cc3000_socket::accept(int32_t sd, sockaddr *addr, socklen_t *addrlen) {
int32_t ret;
uint8_t *ptr, *args;
tBsdReturnParams tAcceptReturnArguments;
ret = EFAIL;
ptr = _simple_link.get_transmit_buffer();
args = (ptr + HEADERS_SIZE_CMD);
// Fill in temporary command buffer
args = UINT32_TO_STREAM(args, sd);
// Initiate a HCI command
_hci.command_send(HCI_CMND_ACCEPT, ptr, SOCKET_ACCEPT_PARAMS_LEN);
// Since we are in blocking state - wait for event complete
_event.simplelink_wait_event(HCI_CMND_ACCEPT, &tAcceptReturnArguments);
// need specify return parameters!!!
memcpy(addr, &tAcceptReturnArguments.tSocketAddress, ASIC_ADDR_LEN);
*addrlen = ASIC_ADDR_LEN;
errno = tAcceptReturnArguments.iStatus;
ret = errno;
// if succeeded, iStatus = new socket descriptor. otherwise - error number
if(M_IS_VALID_SD(ret))
{
_event.set_socket_active_status(ret, SOCKET_STATUS_ACTIVE);
}
else
{
_event.set_socket_active_status(sd, SOCKET_STATUS_INACTIVE);
}
return(ret);
}
int32_t cc3000_socket::bind(int32_t sd, const sockaddr *addr, int32_t addrlen) {
int32_t ret;
uint8_t *ptr, *args;
ret = EFAIL;
ptr = _simple_link.get_transmit_buffer();
args = (ptr + HEADERS_SIZE_CMD);
addrlen = ASIC_ADDR_LEN;
// Fill in temporary command buffer
args = UINT32_TO_STREAM(args, sd);
args = UINT32_TO_STREAM(args, 0x00000008);
args = UINT32_TO_STREAM(args, addrlen);
ARRAY_TO_STREAM(args, ((uint8_t *)addr), addrlen);
// Initiate a HCI command
_hci.command_send(HCI_CMND_BIND, ptr, SOCKET_BIND_PARAMS_LEN);
// Since we are in blocking state - wait for event complete
_event.simplelink_wait_event(HCI_CMND_BIND, &ret);
errno = ret;
return(ret);
}
int32_t cc3000_socket::listen(int32_t sd, int32_t backlog) {
int32_t ret;
uint8_t *ptr, *args;
ret = EFAIL;
ptr = _simple_link.get_transmit_buffer();
args = (ptr + HEADERS_SIZE_CMD);
// Fill in temporary command buffer
args = UINT32_TO_STREAM(args, sd);
args = UINT32_TO_STREAM(args, backlog);
// Initiate a HCI command
_hci.command_send(HCI_CMND_LISTEN, ptr, SOCKET_LISTEN_PARAMS_LEN);
// Since we are in blocking state - wait for event complete
_event.simplelink_wait_event(HCI_CMND_LISTEN, &ret);
errno = ret;
return(ret);
}
int32_t cc3000_socket::connect(int32_t sd, const sockaddr *addr, int32_t addrlen) {
int32_t ret;
uint8_t *ptr, *args;
ret = EFAIL;
ptr = _simple_link.get_transmit_buffer();
args = (ptr + SIMPLE_LINK_HCI_CMND_TRANSPORT_HEADER_SIZE);
addrlen = 8;
// Fill in temporary command buffer
args = UINT32_TO_STREAM(args, sd);
args = UINT32_TO_STREAM(args, 0x00000008);
args = UINT32_TO_STREAM(args, addrlen);
ARRAY_TO_STREAM(args, ((uint8_t *)addr), addrlen);
// Initiate a HCI command
_hci.command_send(HCI_CMND_CONNECT, ptr, SOCKET_CONNECT_PARAMS_LEN);
// Since we are in blocking state - wait for event complete
_event.simplelink_wait_event(HCI_CMND_CONNECT, &ret);
errno = ret;
return((int32_t)ret);
}
int32_t cc3000_socket::select(int32_t nfds, fd_set *readsds, fd_set *writesds, fd_set *exceptsds, struct timeval *timeout) {
uint8_t *ptr, *args;
tBsdSelectRecvParams tParams;
uint32_t is_blocking;
if( timeout == NULL)
{
is_blocking = 1; /* blocking , infinity timeout */
}
else
{
is_blocking = 0; /* no blocking, timeout */
}
// Fill in HCI packet structure
ptr = _simple_link.get_transmit_buffer();
args = (ptr + HEADERS_SIZE_CMD);
// Fill in temporary command buffer
args = UINT32_TO_STREAM(args, nfds);
args = UINT32_TO_STREAM(args, 0x00000014);
args = UINT32_TO_STREAM(args, 0x00000014);
args = UINT32_TO_STREAM(args, 0x00000014);
args = UINT32_TO_STREAM(args, 0x00000014);
args = UINT32_TO_STREAM(args, is_blocking);
args = UINT32_TO_STREAM(args, ((readsds) ? *(uint32_t*)readsds : 0));
args = UINT32_TO_STREAM(args, ((writesds) ? *(uint32_t*)writesds : 0));
args = UINT32_TO_STREAM(args, ((exceptsds) ? *(uint32_t*)exceptsds : 0));
if (timeout)
{
if ( 0 == timeout->tv_sec && timeout->tv_usec < SELECT_TIMEOUT_MIN_MICRO_SECONDS)
{
timeout->tv_usec = SELECT_TIMEOUT_MIN_MICRO_SECONDS;
}
args = UINT32_TO_STREAM(args, timeout->tv_sec);
args = UINT32_TO_STREAM(args, timeout->tv_usec);
}
// Initiate a HCI command
_hci.command_send(HCI_CMND_BSD_SELECT, ptr, SOCKET_SELECT_PARAMS_LEN);
// Since we are in blocking state - wait for event complete
_event.simplelink_wait_event(HCI_EVNT_SELECT, &tParams);
// Update actually read FD
if (tParams.iStatus >= 0)
{
if (readsds)
{
memcpy(readsds, &tParams.uiRdfd, sizeof(tParams.uiRdfd));
}
if (writesds)
{
memcpy(writesds, &tParams.uiWrfd, sizeof(tParams.uiWrfd));
}
if (exceptsds)
{
memcpy(exceptsds, &tParams.uiExfd, sizeof(tParams.uiExfd));
}
return(tParams.iStatus);
}
else
{
errno = tParams.iStatus;
return(-1);
}
}
int32_t cc3000_socket::getsockopt (int32_t sd, int32_t level, int32_t optname, void *optval, socklen_t *optlen) {
uint8_t *ptr, *args;
tBsdGetSockOptReturnParams tRetParams;
ptr = _simple_link.get_transmit_buffer();
args = (ptr + HEADERS_SIZE_CMD);
// Fill in temporary command buffer
args = UINT32_TO_STREAM(args, sd);
args = UINT32_TO_STREAM(args, level);
args = UINT32_TO_STREAM(args, optname);
// Initiate a HCI command
_hci.command_send(HCI_CMND_GETSOCKOPT, ptr, SOCKET_GET_SOCK_OPT_PARAMS_LEN);
// Since we are in blocking state - wait for event complete
_event.simplelink_wait_event(HCI_CMND_GETSOCKOPT, &tRetParams);
if (((int8_t)tRetParams.iStatus) >= 0)
{
*optlen = 4;
memcpy(optval, tRetParams.ucOptValue, 4);
return (0);
}
else
{
errno = tRetParams.iStatus;
return errno;
}
}
int32_t cc3000_socket::simple_link_recv(int32_t sd, void *buf, int32_t len, int32_t flags, sockaddr *from, socklen_t *fromlen, int32_t opcode) {
uint8_t *ptr, *args;
tBsdReadReturnParams tSocketReadEvent;
ptr = _simple_link.get_transmit_buffer();
args = (ptr + HEADERS_SIZE_CMD);
// Fill in HCI packet structure
args = UINT32_TO_STREAM(args, sd);
args = UINT32_TO_STREAM(args, len);
args = UINT32_TO_STREAM(args, flags);
// Generate the read command, and wait for the
_hci.command_send(opcode, ptr, SOCKET_RECV_FROM_PARAMS_LEN);
// Since we are in blocking state - wait for event complete
_event.simplelink_wait_event(opcode, &tSocketReadEvent);
// In case the number of bytes is more then zero - read data
if (tSocketReadEvent.iNumberOfBytes > 0)
{
// Wait for the data in a synchronous way. Here we assume that the bug is
// big enough to store also parameters of receive from too....
_event.simplelink_wait_data((uint8_t *)buf, (uint8_t *)from, (uint8_t *)fromlen);
}
errno = tSocketReadEvent.iNumberOfBytes;
return(tSocketReadEvent.iNumberOfBytes);
}
int32_t cc3000_socket::recv(int32_t sd, void *buf, int32_t len, int32_t flags) {
return(simple_link_recv(sd, buf, len, flags, NULL, NULL, HCI_CMND_RECV));
}
int32_t cc3000_socket::recvfrom(int32_t sd, void *buf, int32_t len, int32_t flags, sockaddr *from, socklen_t *fromlen) {
return(simple_link_recv(sd, buf, len, flags, from, fromlen, HCI_CMND_RECVFROM));
}
int32_t cc3000_socket::simple_link_send(int32_t sd, const void *buf, int32_t len, int32_t flags, const sockaddr *to, int32_t tolen, int32_t opcode) {
uint8_t uArgSize = 0x00, addrlen = 0x00;
uint8_t *ptr, *pDataPtr = NULL, *args;
uint32_t addr_offset = 0x00;
int32_t res;
tBsdReadReturnParams tSocketSendEvent;
// Check the bsd_arguments
if (0 != (res = HostFlowControlConsumeBuff(sd)))
{
return res;
}
//Update the number of sent packets
uint16_t sent_packets = _simple_link.get_sent_packets();
sent_packets++;
_simple_link.set_sent_packets(sent_packets);
// Allocate a buffer and construct a packet and send it over spi
ptr = _simple_link.get_transmit_buffer();
args = (ptr + HEADERS_SIZE_DATA);
// Update the offset of data and parameters according to the command
switch(opcode)
{
case HCI_CMND_SENDTO:
{
addr_offset = len + sizeof(len) + sizeof(len);
addrlen = 8;
uArgSize = SOCKET_SENDTO_PARAMS_LEN;
pDataPtr = ptr + HEADERS_SIZE_DATA + SOCKET_SENDTO_PARAMS_LEN;
break;
}
case HCI_CMND_SEND:
{
tolen = 0;
to = NULL;
uArgSize = HCI_CMND_SEND_ARG_LENGTH;
pDataPtr = ptr + HEADERS_SIZE_DATA + HCI_CMND_SEND_ARG_LENGTH;
break;
}
default:
{
break;
}
}
// Fill in temporary command buffer
args = UINT32_TO_STREAM(args, sd);
args = UINT32_TO_STREAM(args, uArgSize - sizeof(sd));
args = UINT32_TO_STREAM(args, len);
args = UINT32_TO_STREAM(args, flags);
if (opcode == HCI_CMND_SENDTO)
{
args = UINT32_TO_STREAM(args, addr_offset);
args = UINT32_TO_STREAM(args, addrlen);
}
// Copy the data received from user into the TX Buffer
ARRAY_TO_STREAM(pDataPtr, ((uint8_t *)buf), len);
// In case we are using SendTo, copy the to parameters
if (opcode == HCI_CMND_SENDTO)
{
ARRAY_TO_STREAM(pDataPtr, ((uint8_t *)to), tolen);
}
// Initiate a HCI command
_hci.data_send(opcode, ptr, uArgSize, len,(uint8_t*)to, tolen);
if (opcode == HCI_CMND_SENDTO)
_event.simplelink_wait_event(HCI_EVNT_SENDTO, &tSocketSendEvent);
else
_event.simplelink_wait_event(HCI_EVNT_SEND, &tSocketSendEvent);
return (len);
}
int32_t cc3000_socket::send(int32_t sd, const void *buf, int32_t len, int32_t flags) {
return(simple_link_send(sd, buf, len, flags, NULL, 0, HCI_CMND_SEND));
}
int32_t cc3000_socket::sendto(int32_t sd, const void *buf, int32_t len, int32_t flags, const sockaddr *to, socklen_t tolen) {
return(simple_link_send(sd, buf, len, flags, to, tolen, HCI_CMND_SENDTO));
}
int32_t cc3000_socket::mdns_advertiser(uint16_t mdns_enabled, uint8_t *device_service_name, uint16_t device_service_name_length) {
int32_t ret;
uint8_t *pTxBuffer, *pArgs;
if (device_service_name_length > MDNS_DEVICE_SERVICE_MAX_LENGTH)
{
return EFAIL;
}
pTxBuffer = _simple_link.get_transmit_buffer();
pArgs = (pTxBuffer + SIMPLE_LINK_HCI_CMND_TRANSPORT_HEADER_SIZE);
// Fill in HCI packet structure
pArgs = UINT32_TO_STREAM(pArgs, mdns_enabled);
pArgs = UINT32_TO_STREAM(pArgs, 8);
pArgs = UINT32_TO_STREAM(pArgs, device_service_name_length);
ARRAY_TO_STREAM(pArgs, device_service_name, device_service_name_length);
// Initiate a HCI command
_hci.command_send(HCI_CMND_MDNS_ADVERTISE, pTxBuffer, SOCKET_MDNS_ADVERTISE_PARAMS_LEN + device_service_name_length);
// Since we are in blocking state - wait for event complete
_event.simplelink_wait_event(HCI_EVNT_MDNS_ADVERTISE, &ret);
return ret;
}
#ifndef CC3000_TINY_DRIVER
int32_t cc3000_socket::gethostbyname(uint8_t *hostname, uint16_t name_length, uint32_t *out_ip_addr) {
tBsdGethostbynameParams ret;
uint8_t *ptr, *args;
errno = EFAIL;
if (name_length > HOSTNAME_MAX_LENGTH)
{
return errno;
}
ptr = _simple_link.get_transmit_buffer();
args = (ptr + SIMPLE_LINK_HCI_CMND_TRANSPORT_HEADER_SIZE);
// Fill in HCI packet structure
args = UINT32_TO_STREAM(args, 8);
args = UINT32_TO_STREAM(args, name_length);
ARRAY_TO_STREAM(args, hostname, name_length);
// Initiate a HCI command
_hci.command_send(HCI_CMND_GETHOSTNAME, ptr, SOCKET_GET_HOST_BY_NAME_PARAMS_LEN + name_length - 1);
// Since we are in blocking state - wait for event complete
_event.simplelink_wait_event(HCI_EVNT_BSD_GETHOSTBYNAME, &ret);
errno = ret.retVal;
(*((int32_t*)out_ip_addr)) = ret.outputAddress;
return (errno);
}
int32_t cc3000_socket::setsockopt(int32_t sd, int32_t level, int32_t optname, const void *optval, socklen_t optlen) {
int32_t ret;
uint8_t *ptr, *args;
ptr = _simple_link.get_transmit_buffer();
args = (ptr + HEADERS_SIZE_CMD);
// Fill in temporary command buffer
args = UINT32_TO_STREAM(args, sd);
args = UINT32_TO_STREAM(args, level);
args = UINT32_TO_STREAM(args, optname);
args = UINT32_TO_STREAM(args, 0x00000008);
args = UINT32_TO_STREAM(args, optlen);
ARRAY_TO_STREAM(args, ((uint8_t *)optval), optlen);
// Initiate a HCI command
_hci.command_send(HCI_CMND_SETSOCKOPT, ptr, SOCKET_SET_SOCK_OPT_PARAMS_LEN + optlen);
// Since we are in blocking state - wait for event complete
_event.simplelink_wait_event(HCI_CMND_SETSOCKOPT, &ret);
if (ret >= 0)
{
return (0);
}
else
{
errno = ret;
return ret;
}
}
#endif
} /* end of cc3000 namespace */
