Added mutex for multiple SPI devices on the same SPI bus
Fork of cc3000_hostdriver_mbedsocket by
cc3000_socket.cpp
- Committer:
- vpcola
- Date:
- 2014-10-16
- Revision:
- 47:cc9a2501e29f
- Parent:
- 45:50ab13d8f2dc
File content as of revision 47:cc9a2501e29f:
/***************************************************************************** * * 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 char* cc3000_socket::inet_ntoa_r(uint32_t s_addr, char *buf, int buflen) { char inv[3]; char *rp; uint8_t *ap; uint8_t rem; uint8_t n; uint8_t i; int len = 0; rp = buf; ap = (uint8_t *)&s_addr; for (n = 0; n < 4; n++) { i = 0; do { rem = *ap % (uint8_t)10; *ap /= (uint8_t)10; inv[i++] = '0' + rem; } while(*ap); while(i--) { if (len++ >= buflen) { return NULL; } *rp++ = inv[i]; } if (len++ >= buflen) { return NULL; } *rp++ = '.'; ap++; } *--rp = 0; return buf; } } // mbed_cc3000 namespace