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.
Dependents: cc3000_hello_world_demo cc3000_simple_socket_demo cc3000_ntp_demo cc3000_ping_demo ... more
cc3000_socket.cpp
- Committer:
- Kojto
- Date:
- 2013-10-08
- Revision:
- 33:9e23b24fb4f3
- Parent:
- 20:30b6ed7bf8fd
- Child:
- 42:bd2c631a031a
File content as of revision 33:9e23b24fb4f3:
/*****************************************************************************
*
* 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 */
SimpleLink Wi-Fi CC3000
Avnet Wi-Go System