Murata Type YD Wi-Fi driver

Dependents:   easy-connect-type-yd

TypeYDInterface.cpp

Committer:
MACRUM
Date:
2017-07-12
Revision:
0:35a2186cf186

File content as of revision 0:35a2186cf186:

/* Murata Type-YD implementation of NetworkInterfaceAPI
 * Copyright (c) 2017 Murat Manufacturing CO., LTD.
 *
 * 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.
 */

#include <string.h>
#include "TypeYDInterface.h"
#include "SNICInterface/Socket/SNIC_Socket.h"
#include "SNICInterface/Socket/Endpoint.h"
#include "SNICInterface/Socket/SNIC_UDPSocket.h"
#include "SNICInterface/Socket/TCPSocketConnection.h"
#include "SNICInterface/Socket/TCPSocketServer.h"

#include "mbed.h"
#include "mbed-trace/mbed_trace.h"
#define TRACE_GROUP "SNIC"

//#define USE_DYNAMIC_CAST

// socket structure
struct managed_socket {
    nsapi_protocol_t proto;
    bool connected;
    SnicSocket *snic_socket;
    void (*callback)(void *);
    void *data;
};


// TypeYDInterface implementation
TypeYDInterface::TypeYDInterface(PinName tx, PinName rx, PinName cts, PinName rts, PinName reset, PinName alarm, int baud)
    : _snic(tx, rx, cts, rts, reset, alarm, baud)
{
}

int TypeYDInterface::init()
{
    int ret = _snic.init();
    if (ret == 0) {
        tagWIFI_STATUS_T status;
        _snic.getWifiStatus(&status);
        memcpy(mac_address, status.mac_address, sizeof(mac_address));
        sprintf(str_macaddr, "%02x:%02x:%02x:%02x:%02x:%02x",
                mac_address[0], mac_address[1], mac_address[2],
                mac_address[3], mac_address[4], mac_address[5]); 

        ret = _snic.wifi_softap_off();
        if (ret != 0) {
            tr_error("wifi off error");
        }
    }
    return ret;
}

int TypeYDInterface::getFWVersion(unsigned char *version, int length)
{
    int ret = _snic.getFWVersion(version, &length);
    return ret;
}

int TypeYDInterface::connect()
{
    int ret;
    
    if( _snic.disconnect() != 0 ) {
        return NSAPI_ERROR_DEVICE_ERROR;
    }

    int ssid_length = strlen(ap_ssid);
    int pass_length = strlen(ap_pass);

    if (_snic.connect(ap_ssid, ssid_length, ap_esec, ap_pass, pass_length) != 0) {
        ret = NSAPI_ERROR_NO_CONNECTION;
    }
    else if (_snic.setIPConfig(true) != 0) {
        ret = NSAPI_ERROR_DHCP_FAILURE;
    }
    else {
        ret = NSAPI_ERROR_OK;
    }

    return ret;
}


int TypeYDInterface::connect(const char *ssid, const char *pass, nsapi_security_t security,
                                        uint8_t channel)
{
    int ret;

    if (channel != 0) {
        return NSAPI_ERROR_UNSUPPORTED;
    }

    set_credentials(ssid, pass, security);
    int ssid_length = strlen(ap_ssid);
    int pass_length = strlen(ap_pass);
#if 0
    int repeat = 0;
    bool bFound = false;
    do {
        tr_info("scan...%d\n", repeat);
        WiFiAccessPoint res[10];
        ret = scan(res,10);
        if (ret < 0) {
            tr_info("scan fail %d\n",ret);
        }
        else {
            tr_info("scan result = %d\n", ret);
            for (int i = 0; i < ret; i++) {
                tr_info("ssid        :%s\n", res[i].get_ssid());
                tr_info("channel     :%d\n", res[i].get_channel());
                if (strcmp(ap_ssid, res[i].get_ssid()) == 0) {
                    bFound = true;
                    tr_info("-------- BSS ---------\n");
                    tr_info("ssid        :%s\n", res[i].get_ssid());
                    tr_info("channel     :%d\n", res[i].get_channel());
                    tr_info("rssi        :%d\n", res[i].get_rssi());
                    tr_info("security    :%d\n", res[i].get_security());
                    const uint8_t *bssid = res[i].get_bssid();
                    tr_info("bssid       :%02x-%02x-%02x-%02x-%02x-%02x\n",
                           bssid[0],bssid[1],bssid[2],
                           bssid[3],bssid[4],bssid[5]);
                    break;
                }
            }
        } 
    }while((bFound == false) && (repeat++ < 10));
#endif
    do {
        wait(0.5);
        if( _snic.disconnect() != 0 ) {
            return NSAPI_ERROR_DEVICE_ERROR;
        }
        wait(0.5);

        /*
        ret = _snic.getWifiStatus(&status);
        if (ret == 0) {
            printf("status:%02x\n", status.status);
            printf("mac   :%02x-%02x-%02x-%02x-%02x-%02x\n",
                   status.mac_address[0],status.mac_address[1],status.mac_address[2],
                   status.mac_address[3],status.mac_address[4],status.mac_address[5]);
        }*/
        tr_info("TryConnect\r\n");

        if (_snic.connect(ap_ssid, ssid_length, ap_esec, ap_pass, pass_length) != 0) {
            ret = NSAPI_ERROR_NO_CONNECTION;
        }
        else if (_snic.setIPConfig(true) != 0) {
            ret = NSAPI_ERROR_DHCP_FAILURE;
        }
        else {
            ret = NSAPI_ERROR_OK;
        }
    } while (ret != NSAPI_ERROR_OK);
    
    return ret;
}


int TypeYDInterface::set_credentials(const char *ssid, const char *pass, nsapi_security_t security)
{
    ap_esec = e_SEC_WPA2_MIXED;
    switch(security) {
    case    NSAPI_SECURITY_NONE:      /*!< open access point */
        ap_esec = e_SEC_OPEN;
        break;
    case    NSAPI_SECURITY_WEP:       /*!< phrase conforms to WEP */
        ap_esec = e_SEC_WEP;
        break;
    case    NSAPI_SECURITY_WPA:       /*!< phrase conforms to WPA */
        ap_esec = e_SEC_WPA_TKIP;
        break;
    case    NSAPI_SECURITY_WPA2:      /*!< phrase conforms to WPA2 */
        ap_esec = e_SEC_WPA2_MIXED;
        break;
    case    NSAPI_SECURITY_WPA_WPA2:  /*!< phrase conforms to WPA/WPA2 */
        ap_esec = e_SEC_WPA2_MIXED;
        break;
    default:
        break;
    }

    strncpy(ap_ssid, ssid, sizeof(ap_ssid));
    ap_ssid[sizeof(ap_ssid)-1] = 0;

    strncpy(ap_pass, pass, sizeof(ap_pass));
    ap_pass[sizeof(ap_pass)-1] = 0;

    return 0;
}

int TypeYDInterface::set_channel(uint8_t channel)
{
    return NSAPI_ERROR_UNSUPPORTED;
}

int TypeYDInterface::disconnect()
{
    if (!_snic.disconnect()) {
        return NSAPI_ERROR_DEVICE_ERROR;
    }

    return NSAPI_ERROR_OK;
}

const char *TypeYDInterface::get_ip_address()
{
    return _snic.getIPAddress();
}

const char *TypeYDInterface::get_mac_address()
{

    return (const char*)str_macaddr;
}

const char *TypeYDInterface::get_gateway()
{
    return _snic.getGatewayAddress();
}

const char *TypeYDInterface::get_netmask()
{
    return _snic.getSubnetAddress();
}

int8_t TypeYDInterface::get_rssi()
{
    signed char rssi;
    _snic.getRssi(&rssi);

    return (int8_t)rssi;
}

static volatile int _scan_wait = 0;
static WiFiAccessPoint *_scan_results = 0; 
static int _scan_count;
static int _scan_limit;
static void scan_results_callback(tagSCAN_RESULT_T *scan_result)
{
    nsapi_wifi_ap_t ap;

    if (_scan_count < _scan_limit) {
        memcpy(ap.ssid, scan_result->ssid, 33);
        memcpy(ap.bssid, scan_result->bssid, 6);
        switch(scan_result->security) {
        case    e_SEC_OPEN:
            ap.security = NSAPI_SECURITY_NONE;
            break;
        case    e_SEC_WEP:
            ap.security = NSAPI_SECURITY_WEP;
            break;
        case    e_SEC_WPA_TKIP:
            ap.security = NSAPI_SECURITY_WPA;
            break;
        case    e_SEC_WPA2_AES:
            ap.security = NSAPI_SECURITY_WPA2;
            break;
        case    e_SEC_WPA2_MIXED:
            ap.security = NSAPI_SECURITY_WPA_WPA2;
            break;
        case    e_SEC_WPA_AES:
            ap.security = NSAPI_SECURITY_WPA;
            break;
        default:
            ap.security = NSAPI_SECURITY_UNKNOWN;
            break;
        }
        ap.rssi    = scan_result->rssi;
        ap.channel = scan_result->channel;
        _scan_results[_scan_count++] = WiFiAccessPoint(ap);
    }
    
    if (scan_result->is_complete == 0) _scan_wait = 1;
}

int TypeYDInterface::scan(WiFiAccessPoint *res, unsigned count)
{
    _scan_results = res;
    _scan_limit = count;
    _scan_count = 0;
    int ret = _snic.scan(NULL, NULL, scan_results_callback);
    if (ret == 0) {
        _scan_wait = 0;
        while(_scan_wait == 0) {
            wait(1);
        }
    }

    return _scan_count;
}

nsapi_error_t TypeYDInterface::gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version)
{
    int ret;
    unsigned char ipaddr[4];

    ret = _snic.resolveName(name, ipaddr);
    if (ret != 0) {
        tr_error("DNS failure\n");
        return NSAPI_ERROR_DNS_FAILURE;
    }

    tr_info("DNS res:%u.%u.%u.%u\n", ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);

    address->set_ip_bytes(ipaddr, NSAPI_IPv4);
    
    return NSAPI_ERROR_OK;
}

int TypeYDInterface::socket_open(void **handle, nsapi_protocol_t proto)
{
    tr_info("socket_open"); 
 
    struct managed_socket *socket = new struct managed_socket;
    if (!socket) {
        return NSAPI_ERROR_NO_SOCKET;
    }
    
    socket->proto = proto;
    socket->connected = false;
    socket->snic_socket = NULL;
    socket->callback = NULL;
    socket->data = NULL;
    *handle = socket;

    return 0;
}

int TypeYDInterface::socket_close(void *handle)
{
    struct managed_socket *socket = (struct managed_socket *)handle;

    tr_info("socket_close"); 

    int err = 0;
    if (socket->snic_socket != NULL) {
        err = socket->snic_socket->close();
        delete socket->snic_socket;
    }
 
    delete socket;
    return err;
}

int TypeYDInterface::socket_bind(void *handle, const SocketAddress &address)
{
    int ret;
    uint16_t port;

    struct managed_socket *socket = (struct managed_socket *)handle;

    port = address.get_port();
    if (port == 0) {
#if defined(ST)
        srand(HAL_GetTick());
#else
        srand(0);
#endif
        port = (rand() % 10240) + 20000;
    }
    
    tr_info("socket_bind IP:%s:%u\n", address.get_ip_address(), port);

    if (socket->proto == NSAPI_UDP) {
        SnicUDPSocket *udp = new SnicUDPSocket();
        socket->snic_socket = udp;
        if (socket->snic_socket == NULL) {
            return NSAPI_ERROR_DEVICE_ERROR;
        }
        socket->snic_socket->socket_attach(socket->callback, socket->data);
        ret = udp->bind(port);
        if (ret != 0) {
            tr_info("bind err %d\n", ret);
            return NSAPI_ERROR_DEVICE_ERROR;
        }
        socket->connected = true;
    }
    else {
        TCPSocketConnection *tcp = new TCPSocketConnection();
        socket->snic_socket = tcp;
        if (socket->snic_socket == NULL) {
            tr_error("tcp bind err\n");
            return NSAPI_ERROR_DEVICE_ERROR;
        }
        socket->snic_socket->socket_attach(socket->callback, socket->data);
        ret = tcp->bind(port);
        if (ret != 0) {
            tr_error("tcp bind err %d\n", ret);
            return NSAPI_ERROR_DEVICE_ERROR;
        }
        socket->connected = false;
    }

    return ret;
}

int TypeYDInterface::socket_listen(void *handle, int backlog)
{
    int ret;
    struct managed_socket *socket = (struct managed_socket *)handle;

    if (socket->proto == NSAPI_UDP) {
        tr_info("unsupport:socket_listen\n");
        return NSAPI_ERROR_UNSUPPORTED;
    }
    else {
        TCPSocketServer* tcp;
        #ifdef USE_DYNAMIC_CAST
        tcp = dynamic_cast<TCPSocketServer*>(socket->snic_socket);
        if (tcp == NULL){
            return NSAPI_ERROR_DEVICE_ERROR;
        }
        #else
        tcp = (TCPSocketServer*)(socket->snic_socket);
        #endif
        ret = tcp->listen(backlog);
        if (ret != 0) {
            tr_error("tcp listen err %d\n",ret);
            return NSAPI_ERROR_DEVICE_ERROR;
        }
    }
    return 0;
}

int TypeYDInterface::socket_connect(void *handle, const SocketAddress &addr)
{
    struct managed_socket *socket = (struct managed_socket *)handle;
    
    //tr_info("socket_connect(%d)\n",socket->proto);

    if (socket->proto == NSAPI_UDP) {
        tr_error("un sup:socket_connect");
        return NSAPI_ERROR_DEVICE_ERROR;
    }
    else {
        TCPSocketConnection *tcp;
        if (socket->snic_socket == NULL) {
            tcp = new TCPSocketConnection();
            socket->snic_socket = tcp;
            if (socket->snic_socket == NULL) {
                tr_error("tcp connect err\n");
                return NSAPI_ERROR_DEVICE_ERROR;
            }
            socket->snic_socket->socket_attach(socket->callback, socket->data);
        }
        else {
            #ifdef USE_DYNAMIC_CAST
            tcp = dynamic_cast<TCPSocketConnection*>(socket->snic_socket);
            if (tcp == NULL){
                return NSAPI_ERROR_DEVICE_ERROR;
            }
            #else
            tcp = (TCPSocketConnection*)(socket->snic_socket);
            #endif
        }

        tr_info("socket_connect IP:%s:%u\n", addr.get_ip_address(), addr.get_port());
        if (tcp->connect(addr.get_ip_address(), addr.get_port()) != 0) {
            return NSAPI_ERROR_DEVICE_ERROR;
        }
    }

    //tr_info("socket_connect success\n");
    socket->connected = true;
    return 0;
}
    
int TypeYDInterface::socket_accept(void *handle, void **client_socket, SocketAddress *addr)
{
    int ret;
    struct managed_socket *server = (struct managed_socket *)handle;
    
    if (server->proto == NSAPI_UDP) {
        tr_info("unsupport:accept");
        return NSAPI_ERROR_UNSUPPORTED;
    }
    else {
        TCPSocketServer *tcp;
        #ifdef USE_DYNAMIC_CAST
        tcp = dynamic_cast<TCPSocketServer*>(server->snic_socket);
        if (tcp == NULL){
            return NSAPI_ERROR_DEVICE_ERROR;
        }
        #else
        tcp = (TCPSocketServer*)(server->snic_socket);
        #endif
        socket_open(client_socket, NSAPI_TCP);
        struct managed_socket *client = (struct managed_socket *)*client_socket;
        TCPSocketConnection *conn = new TCPSocketConnection();
        client->snic_socket = conn;
        if (client->snic_socket == NULL) {
            tr_error("tcp accept err\n");
            return NSAPI_ERROR_DEVICE_ERROR;
        }
        ret = tcp->accept(*conn, addr);
        if (ret != 0) {
            tr_error("tcp listen err %d",ret);
            return NSAPI_ERROR_DEVICE_ERROR;
        }
    }
    return 0;
}

int TypeYDInterface::socket_send(void *handle, const void *data, unsigned size)
{
    struct managed_socket *socket = (struct managed_socket *)handle;

    //tr_info("socket_send");

    if (socket->proto != NSAPI_TCP) {
        tr_error("un sup:socket_send");
        return NSAPI_ERROR_DEVICE_ERROR;
    }

    #ifdef USE_DYNAMIC_CAST
    TCPSocketConnection *tcp = dynamic_cast<TCPSocketConnection*>(socket->snic_socket);
    if ((tcp == NULL) || ) {
        return NSAPI_ERROR_DEVICE_ERROR;
    }
    #else
    TCPSocketConnection *tcp = (TCPSocketConnection*)(socket->snic_socket);
    #endif
    if (tcp->send((char*)data, size) < 0) {
        tr_error("socket_send");
        return NSAPI_ERROR_DEVICE_ERROR;
    }

    return size;
}

int TypeYDInterface::socket_recv(void *handle, void *data, unsigned size)
{
    struct managed_socket *socket = (struct managed_socket *)handle;

    //tr_info("socket_recv");

    if (socket->proto != NSAPI_TCP) {
        tr_error("not sup:socket_recv");
        return NSAPI_ERROR_DEVICE_ERROR;
    }

    int recv;
    #ifdef USE_DYNAMIC_CAST
    TCPSocketConnection *tcp = dynamic_cast<TCPSocketConnection*>(socket->snic_socket);
    if (tcp == NULL){
        return NSAPI_ERROR_DEVICE_ERROR;
    }
    #else
    TCPSocketConnection *tcp = (TCPSocketConnection*)(socket->snic_socket);
    #endif
    if ((recv = tcp->receive((char*)data, size)) < 0) {
        return NSAPI_ERROR_WOULD_BLOCK;
    }

    return recv;
}

int TypeYDInterface::socket_sendto(void *handle, const SocketAddress &addr, const void *data, unsigned size)
{
    struct managed_socket *socket = (struct managed_socket *)handle;
    int ret;

    //tr_info("socket_sendto");

    if (!socket->connected) {
        int err = socket_connect(socket, addr);
        if (err < 0) {
            return err;
        }
    }

    if (socket->proto == NSAPI_UDP) {
        Endpoint remote;
        remote.set_address(addr.get_ip_address(), addr.get_port());
        #ifdef USE_DYNAMIC_CAST
        SnicUDPSocket *udp = dynamic_cast<SnicUDPSocket*>(socket->snic_socket);
        if (udp == NULL) {
            return NSAPI_ERROR_DEVICE_ERROR;
        }
        #else
        SnicUDPSocket *udp = (SnicUDPSocket*)(socket->snic_socket);
        #endif
        ret = udp->sendTo(remote, (char*)data, size);
    }
    else {
        tr_error("TCP sendto\n");
        return -1;
    }

    return ret;
}

int TypeYDInterface::socket_recvfrom(void *handle, SocketAddress *addr, void *data, unsigned size)
{
    struct managed_socket *socket = (struct managed_socket *)handle;
    int recv;

    //tr_info("socket_recvfrom");
        
    if (socket->proto == NSAPI_UDP) {
        Endpoint remote;
        #ifdef USE_DYNAMIC_CAST
        SnicUDPSocket *udp = dynamic_cast<SnicUDPSocket*>(socket->snic_socket);
        if (udp == NULL) {
            return NSAPI_ERROR_DEVICE_ERROR;
        }
        #else
        SnicUDPSocket *udp = (SnicUDPSocket*)(socket->snic_socket);
        #endif
        recv = udp->receiveFrom(remote, (char*)data, size);
        if (recv > 0) {
            addr->set_ip_address(remote.get_address());
            addr->set_port(remote.get_port());
        }
    }
    else {
        tr_error("TCP recvfrom\n");
        return -1;
    }

    return recv;
}


void TypeYDInterface::socket_attach(void *handle, void (*callback)(void *), void *data)
{
    struct managed_socket *socket = (struct managed_socket *)handle;    

    //tr_info("socket_attach");
    socket->callback = callback;
    socket->data = data;
    if (socket->snic_socket != NULL) {
        socket->snic_socket->socket_attach(callback, data);
    }
}