long hci_unsolicited_event_handler(void)
{
  unsigned long res = 0;
  uint8_t *pucReceivedData;

  if (tSLInformation.usEventOrDataReceived != 0)
    {
      pucReceivedData = (tSLInformation.pucReceivedData);

      if (*pucReceivedData == HCI_TYPE_EVNT)
        {
          /* In case unsolicited event received - here the handling finished */

          if (hci_unsol_event_handler((char *)pucReceivedData) == 1)
            {
              /* There was an unsolicited event received - we can release the buffer
               * and clean the event received
               */

              tSLInformation.usEventOrDataReceived = 0;

              res = 1;
              cc3000_resume();
            }
        }
    }

  return res;
}
uint8_t *hci_event_handler(void *pRetParams, uint8_t *from, uint8_t *fromlen)
{
  uint8_t *pucReceivedData, ucArgsize;
  uint16_t usLength;
  uint8_t *pucReceivedParams;
  uint16_t usReceivedEventOpcode = 0;
  unsigned long retValue32;
  uint8_t * RecvParams;
  uint8_t *RetParams;

  while (1)
    {
      if (tSLInformation.usEventOrDataReceived != 0) {
          pucReceivedData = (tSLInformation.pucReceivedData);

          if (*pucReceivedData == HCI_TYPE_EVNT)
            {
              /* Event Received */

              STREAM_TO_UINT16((char *)pucReceivedData,
                               HCI_EVENT_OPCODE_OFFSET,
                               usReceivedEventOpcode);

              pucReceivedParams = pucReceivedData + HCI_EVENT_HEADER_SIZE;
              RecvParams = pucReceivedParams;
              RetParams = (uint8_t *)pRetParams;

              /* In case unsolicited event received - here the handling finished */

              if (hci_unsol_event_handler((char *)pucReceivedData) == 0)
                {
                  STREAM_TO_UINT8(pucReceivedData, HCI_DATA_LENGTH_OFFSET, usLength);

                  switch(usReceivedEventOpcode)
                    {
                    case HCI_CMND_READ_BUFFER_SIZE:
                      {
                        STREAM_TO_UINT8((char *)pucReceivedParams, 0,
                                        tSLInformation.usNumberOfFreeBuffers);
                        STREAM_TO_UINT16((char *)pucReceivedParams, 1,
                                         tSLInformation.usSlBufferLength);
                      }
                      break;

                    case HCI_CMND_WLAN_CONFIGURE_PATCH:
                    case HCI_NETAPP_DHCP:
                    case HCI_NETAPP_PING_SEND:
                    case HCI_NETAPP_PING_STOP:
                    case HCI_NETAPP_ARP_FLUSH:
                    case HCI_NETAPP_SET_DEBUG_LEVEL:
                    case HCI_NETAPP_SET_TIMERS:
                    case HCI_EVNT_NVMEM_READ:
                    case HCI_EVNT_NVMEM_CREATE_ENTRY:
                    case HCI_CMND_NVMEM_WRITE_PATCH:
                    case HCI_NETAPP_PING_REPORT:
                    case HCI_EVNT_MDNS_ADVERTISE:

                      STREAM_TO_UINT8(pucReceivedData, HCI_EVENT_STATUS_OFFSET,
                                      *(uint8_t *)pRetParams);
                      break;

                    case HCI_CMND_SETSOCKOPT:
                    case HCI_CMND_WLAN_CONNECT:
                    case HCI_CMND_WLAN_IOCTL_STATUSGET:
                    case HCI_EVNT_WLAN_IOCTL_ADD_PROFILE:
                    case HCI_CMND_WLAN_IOCTL_DEL_PROFILE:
                    case HCI_CMND_WLAN_IOCTL_SET_CONNECTION_POLICY:
                    case HCI_CMND_WLAN_IOCTL_SET_SCANPARAM:
                    case HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_START:
                    case HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_STOP:
                    case HCI_CMND_WLAN_IOCTL_SIMPLE_CONFIG_SET_PREFIX:
                    case HCI_CMND_EVENT_MASK:
                    case HCI_EVNT_WLAN_DISCONNECT:
                    case HCI_EVNT_SOCKET:
                    case HCI_EVNT_BIND:
                    case HCI_CMND_LISTEN:
                    case HCI_EVNT_CLOSE_SOCKET:
                    case HCI_EVNT_CONNECT:
                    case HCI_EVNT_NVMEM_WRITE:

                      STREAM_TO_UINT32((char *)pucReceivedParams, 0,
                                       *(unsigned long *)pRetParams);
                      break;

                    case HCI_EVNT_READ_SP_VERSION:

                      STREAM_TO_UINT8(pucReceivedData, HCI_EVENT_STATUS_OFFSET,
                                      *(uint8_t *)pRetParams);
                      pRetParams = ((char *)pRetParams) + 1;
                      STREAM_TO_UINT32((char *)pucReceivedParams, 0, retValue32);
                      UINT32_TO_STREAM((uint8_t *)pRetParams, retValue32);
                      break;

                    case HCI_EVNT_BSD_GETHOSTBYNAME:

                      STREAM_TO_UINT32((char *)pucReceivedParams,
                                       GET_HOST_BY_NAME_RETVAL_OFFSET,
                                       *(unsigned long *)pRetParams);
                      pRetParams = ((char *)pRetParams) + 4;
                      STREAM_TO_UINT32((char *)pucReceivedParams,
                                       GET_HOST_BY_NAME_ADDR_OFFSET,
                                       *(unsigned long *)pRetParams);
                      break;

                    case HCI_EVNT_ACCEPT:
                      {
                        STREAM_TO_UINT32((char *)pucReceivedParams,
                                         ACCEPT_SD_OFFSET,
                                         *(unsigned long *)pRetParams);
                        pRetParams = ((char *)pRetParams) + 4;
                        STREAM_TO_UINT32((char *)pucReceivedParams,
                                         ACCEPT_RETURN_STATUS_OFFSET,
                                         *(unsigned long *)pRetParams);
                        pRetParams = ((char *)pRetParams) + 4;

                        /* This argument returns in network order */

                        memcpy((uint8_t *)pRetParams,
                               pucReceivedParams + ACCEPT_ADDRESS__OFFSET,
                               sizeof(struct sockaddr));
                      }
                      break;

                    case HCI_EVNT_RECV:
                    case HCI_EVNT_RECVFROM:
                      {
                        STREAM_TO_UINT32((char *)pucReceivedParams,
                                         SL_RECEIVE_SD_OFFSET,
                                         *(unsigned long *)pRetParams);
                        pRetParams = ((char *)pRetParams) + 4;
                        STREAM_TO_UINT32((char *)pucReceivedParams,
                                         SL_RECEIVE_NUM_BYTES_OFFSET,
                                         *(unsigned long *)pRetParams);
                        pRetParams = ((char *)pRetParams) + 4;
                        STREAM_TO_UINT32((char *)pucReceivedParams,
                                         SL_RECEIVE__FLAGS__OFFSET,
                                         *(unsigned long *)pRetParams);

                        if (((tBsdReadReturnParams *)pRetParams)->iNumberOfBytes ==
                            ERROR_SOCKET_INACTIVE)
                          {
                            set_socket_active_status
                              (((tBsdReadReturnParams *)pRetParams)->iSocketDescriptor,
                              SOCKET_STATUS_INACTIVE);
                          }
                      }
                      break;

                    case HCI_EVNT_SEND:
                    case HCI_EVNT_SENDTO:
                      {
                        STREAM_TO_UINT32((char *)pucReceivedParams,
                                         SL_RECEIVE_SD_OFFSET,
                                         *(unsigned long *)pRetParams);
                        pRetParams = ((char *)pRetParams) + 4;
                        STREAM_TO_UINT32((char *)pucReceivedParams,
                                         SL_RECEIVE_NUM_BYTES_OFFSET,
                                         *(unsigned long *)pRetParams);
                        pRetParams = ((char *)pRetParams) + 4;
                      }
                    break;

                    case HCI_EVNT_SELECT:
                      {
                        STREAM_TO_UINT32((char *)pucReceivedParams,
                                         SELECT_STATUS_OFFSET,
                                         *(unsigned long *)pRetParams);
                        pRetParams = ((char *)pRetParams) + 4;
                        STREAM_TO_UINT32((char *)pucReceivedParams,
                                         SELECT_READFD_OFFSET,
                                         *(unsigned long *)pRetParams);
                        pRetParams = ((char *)pRetParams) + 4;
                        STREAM_TO_UINT32((char *)pucReceivedParams,
                                         SELECT_WRITEFD_OFFSET,
                                         *(unsigned long *)pRetParams);
                        pRetParams = ((char *)pRetParams) + 4;
                        STREAM_TO_UINT32((char *)pucReceivedParams,
                                         SELECT_EXFD_OFFSET,
                                         *(unsigned long *)pRetParams);
                      }
                      break;

                    case HCI_CMND_GETSOCKOPT:

                      STREAM_TO_UINT8(pucReceivedData, HCI_EVENT_STATUS_OFFSET,
                                      ((tBsdGetSockOptReturnParams *)pRetParams)->iStatus);

                      /* This argument returns in network order */

                      memcpy((uint8_t *)pRetParams, pucReceivedParams, 4);
                      break;

                    case HCI_CMND_WLAN_IOCTL_GET_SCAN_RESULTS:

                      STREAM_TO_UINT32((char *)pucReceivedParams,
                                       GET_SCAN_RESULTS_TABlE_COUNT_OFFSET,
                                       *(unsigned long *)pRetParams);
                      pRetParams = ((char *)pRetParams) + 4;
                      STREAM_TO_UINT32((char *)pucReceivedParams,
                                       GET_SCAN_RESULTS_SCANRESULT_STATUS_OFFSET,
                                       *(unsigned long *)pRetParams);
                      pRetParams = ((char *)pRetParams) + 4;

                      STREAM_TO_UINT16((char *)pucReceivedParams,
                                       GET_SCAN_RESULTS_ISVALID_TO_SSIDLEN_OFFSET,
                                       *(unsigned long *)pRetParams);
                      pRetParams = ((char *)pRetParams) + 2;
                      STREAM_TO_UINT16((char *)pucReceivedParams,
                                       GET_SCAN_RESULTS_FRAME_TIME_OFFSET,
                                       *(unsigned long *)pRetParams);
                      pRetParams = ((char *)pRetParams) + 2;
                      memcpy((uint8_t *)pRetParams,
                             (char *)(pucReceivedParams +
                             GET_SCAN_RESULTS_FRAME_TIME_OFFSET + 2),
                             GET_SCAN_RESULTS_SSID_MAC_LENGTH);
                      break;

                    case HCI_CMND_SIMPLE_LINK_START:
                      break;

                    case HCI_NETAPP_IPCONFIG:

                      /* Read IP address */

                      STREAM_TO_STREAM(RecvParams,RetParams,NETAPP_IPCONFIG_IP_LENGTH);
                      RecvParams += 4;

                      /* Read subnet */

                      STREAM_TO_STREAM(RecvParams,RetParams,NETAPP_IPCONFIG_IP_LENGTH);
                      RecvParams += 4;

                      /* Read default GW */

                      STREAM_TO_STREAM(RecvParams,RetParams,NETAPP_IPCONFIG_IP_LENGTH);
                      RecvParams += 4;

                      /* Read DHCP server */

                      STREAM_TO_STREAM(RecvParams,RetParams,NETAPP_IPCONFIG_IP_LENGTH);
                      RecvParams += 4;

                      /* Read DNS server */

                      STREAM_TO_STREAM(RecvParams,RetParams,NETAPP_IPCONFIG_IP_LENGTH);
                      RecvParams += 4;

                      /* Read Mac address */

                      STREAM_TO_STREAM(RecvParams,RetParams,NETAPP_IPCONFIG_MAC_LENGTH);
                      RecvParams += 6;

                      /* Read SSID */

                      STREAM_TO_STREAM(RecvParams,RetParams,NETAPP_IPCONFIG_SSID_LENGTH);
                      break;

                    default:
                      PANIC();
                      break;
                    }
                }

             if (usReceivedEventOpcode == tSLInformation.usRxEventOpcode)
                {
                  tSLInformation.usRxEventOpcode = 0;
                }
            }
          else
            {
              pucReceivedParams = pucReceivedData;
              STREAM_TO_UINT8((char *)pucReceivedData,
                              HCI_PACKET_ARGSIZE_OFFSET, ucArgsize);

              STREAM_TO_UINT16((char *)pucReceivedData,
                               HCI_PACKET_LENGTH_OFFSET, usLength);

              /* Data received: note that the only case where from and from length
               * are not null is in recv from, so fill the args accordingly
               */

              if (from)
                {
                  STREAM_TO_UINT32((char *)(pucReceivedData + HCI_DATA_HEADER_SIZE),
                                   BSD_RECV_FROM_FROMLEN_OFFSET,
                                   *(unsigned long *)fromlen);
                  memcpy(from,
                        (pucReceivedData + HCI_DATA_HEADER_SIZE + BSD_RECV_FROM_FROM_OFFSET),
                        *fromlen);
                }

              memcpy(pRetParams, pucReceivedParams + HCI_DATA_HEADER_SIZE + ucArgsize,
                     usLength - ucArgsize);

              tSLInformation.usRxDataPending = 0;
            }

          tSLInformation.usEventOrDataReceived = 0;

          cc3000_resume();

          /* Since we are going to TX - we need to handle this event after the
           * ResumeSPi since we need interrupts
           */

          if ((*pucReceivedData == HCI_TYPE_EVNT) &&
              (usReceivedEventOpcode == HCI_EVNT_PATCHES_REQ))
            {
              hci_unsol_handle_patch_request((char *)pucReceivedData);
            }

          if ((tSLInformation.usRxEventOpcode == 0) &&
              (tSLInformation.usRxDataPending == 0))
            {
              break;
            }
        }
    }

  return NULL;
}
Example #3
0
// returns 0 as long as it hasn't finished
// if we get to the error state, error_post_fsm_state contains the state in which the error occurred.
uint8_t post_fsm(){
#if DEBUG_POST_INFO
    uint32_t retip, netmask, gateway, dhcpserv, dnsserv;
#endif
    prev_post_fsm_state = post_fsm_state;
    
    switch(post_fsm_state){
        case PFSM_IDLE:
            break;
        case PFSM_POWER_UP:
            DPOST_INFO_PRINTF("power up :%lu\r\n", millis());
            cc3000_resume();
            DPOST_INFO_PRINTF("connec... :%lu\r\n", millis());
            timeout_end = set_timeout(millis() + CONNECT_TIMEOUT_MS);
            post_fsm_state = PFSM_CONNECTION;
            break;
        case PFSM_CONNECTION:
            // check that the CC3000 has connected
            DPOST_INFO_PRINTF( "cntd:%u dhcp:%u status:%u, get_ip:%u, %lu\r\n", cc3000_checkConnected(), cc3000_checkDHCP(), cc3000_getStatus(), cc3000_getIPAddress(&retip, &netmask, &gateway, &dhcpserv, &dnsserv), millis() );
            
            if ( cc3000_checkDHCP() ){
                // OK we're connected
                post_fsm_state = PFSM_GET_BACKEND_IP;
            } else {
                //DPOST_INFO_PRINTF("no DHCP %lu\r\n", millis());
                if ( millis() > timeout_end ){
#if SET_PROFILE_AND_RETRY
                    if (timeout_count == 0){ // first timeout
                        // try reseting the profile
                        timeout_count++;
                        post_fsm_state = PFSM_SET_PROFILE;
                    } else {
#endif
                        // this is serious, we could not connect even after reseting the profile :(
                        DPOST_ERR_PRINTLN("ERR connect/dhcp timeout");
                        post_fsm_state = PFSM_ERROR;
#if SET_PROFILE_AND_RETRY
                    }
#endif

                } else {
                    _delay_ms(100);
                }
            }
            break;
#if SET_PROFILE_AND_RETRY
        case PFSM_SET_PROFILE: // restore profile from the MCU's EEPROM
            if (!wifi_config_load()){
                error_set_post(POST_ERROR_WIFI_NO_CONFIG);
                post_fsm_state = PFSM_ERROR;
                break;
            }
            wifi_set_profile(wifi_ap_ssid, wifi_ap_password, wifi_ap_encrypt_mode); // TODO what if it fails?
            _delay_ms(10);
            cc3000_stop();
            _delay_ms(50);
            post_fsm_state = PFSM_POWER_UP;
            break;
#endif
        case PFSM_GET_BACKEND_IP:
            DPOST_INFO_PRINTLN("check backend ip");
            // this takes around a 1 second
            // TODO clean it up every hour maybe? or just put it all the time ?
            // backend_ip = 0; // HACK to test recovering the IP every time
            timeout_end = set_timeout(millis() + GET_BACKEND_IP_TIMEOUT_MS);
            post_fsm_state = PFSM_GET_BACKEND_IP_2;
            break;
        case PFSM_GET_BACKEND_IP_2:
            //backend_ip = cc3000_IP2U32(192,168,1,1);
            if (backend_ip){ // we have a back-end IP
                post_fsm_state = PFSM_START_TCP;
            } else {
                if (millis() > timeout_end){
                    DPOST_ERR_PRINTLN("ERR IP resolve timeout");
                    post_fsm_state = PFSM_ERROR;
                } else {
                    DPOST_INFO_PRINTF("get backend ip :%lu\r\n", millis());
                    cc3000_getHostByName(BACKEND_NAME, &backend_ip);
                }
            }
            break;
        case PFSM_START_TCP:
            DPOST_INFO_PRINTF("connect TCP...:%lu\r\n", millis());
            sock = cc3000_connectTCP(backend_ip, BACKEND_PORT);  
			DPOST_INFO_PRINTF("Sock : %s",sock);
            //********************
            // HUGE UGLY HACK : this has been modified to return an unconnected socket if it takes too long, and the device has to reboot the CC3000 when it fails.
            // cf lib CC3000, even_handler.cpp, hci_event_handler() to set the timeout... :/ 
            //********************
            DPOST_INFO_PRINTF("connect TCP ended:%lu\r\n", millis());
            
            if (cc3000_cli_connected(sock)){
                post_fsm_state = PFSM_POST;
            } else {
                cc3000_cli_close(sock); // cleanup is very important to avoid memory leaks!
                sock = NULL;
                tcp_retries++;
                DPOST_INFO_PRINTF("TCP pb: %u\r\n", tcp_retries);
                if (tcp_retries > TCP_CONNECT_RETRIES){
                    DPOST_ERR_PRINTLN("ERR no TCP connect");
                    post_fsm_state = PFSM_ERROR;
                } else {
                    _delay_ms(10);
                    cc3000_stop();
                    _delay_ms(50);
                    post_fsm_state = PFSM_POWER_UP;
                }
            }
            //Note: we don't ping anymore, since it's redundant, and the API is slow and inadequate for what we want.
            break;
        case PFSM_POST:
            // do the actual posting
            post_do(sock);
            DPOST_INFO_PRINTF("post done :%lu\r\n", millis());
            timeout_end = set_timeout(millis() + HTTP_REPLY_TIMEOUT_MS);
            memset(ret_string, 0, sizeof(ret_string));
            ret_string_pos = 0;
            post_fsm_state = PFSM_WAIT_FOR_REPLY;
            break;
        case PFSM_WAIT_FOR_REPLY:
            if ( cc3000_cli_available(sock) ){
                DPOST_INFO_PRINTF("HTTP resp :%lu\r\n", millis());
                
                do {
                    uint8_t c = cc3000_cli_read(sock);
                    if (ret_string_pos < HTTP_RESPONSE_EXPECTED_LEN){
                        ret_string[ret_string_pos++] = c;
                    }
                    DPOST_INFO_PRINTF("%c", c);
                } while (
                    cc3000_cli_available(sock)
                    && !(millis() > timeout_end)
                    );
                DPOST_INFO_PRINT("<EOF>\r\n");
                if ( !strncmp(ret_string, HTTP_RESPONSE_EXPECTED, HTTP_RESPONSE_EXPECTED_LEN) ){
                    DPOST_INFO_PRINTLN("HTTP resp OK");
                    post_fsm_state = PFSM_POST_GET_LED;
                } else {
                    DPOST_ERR_PRINTLN("ERR bad HTTP response");
                    post_fsm_state = PFSM_ERROR;
                }
            } else if (millis() > timeout_end){
                DPOST_ERR_PRINTLN("ERR HTTP response timeout");
                post_fsm_state = PFSM_ERROR;
            }
            break;

        case PFSM_POST_GET_LED:
            post_get_leds(sock);
            timeout_end = set_timeout(millis() + HTTP_REPLY_TIMEOUT_MS*2);
            memset(ret_string, 0, sizeof(ret_string));
            ret_string_pos = 0;
            post_fsm_state = PFSM_WAIT_FOR_LED_REPLY;
            break;
        case PFSM_WAIT_FOR_LED_REPLY:
            if ( cc3000_cli_available(sock) ){
                DPOST_INFO_PRINTF("GET resp :%lu\r\n", millis());
                
                do {
                    uint8_t c = cc3000_cli_read(sock);
                    if (ret_string_pos < HTTP_RESPONSE_EXPECTED_LEN){
                        ret_string[ret_string_pos] = c;
                    }
                    if (ret_string_pos == 160){ // the 160th char is the LED state, and is '0' or '1'
                        returned_led_state = c - '0';
                    }
                    ret_string_pos++;
                    // TODO save the useful byte, the one that says if the LEDs should be ON or not!!
                    DPOST_INFO_PRINTF("%c", c);
                } while (
                    cc3000_cli_available(sock)
                    && !(millis() > timeout_end)
                    );
                DPOST_INFO_PRINT("<EOF>\r\n");
                if ( !strncmp(ret_string, HTTP_RESPONSE_EXPECTED, HTTP_RESPONSE_EXPECTED_LEN) ){
                    DPOST_INFO_PRINTF("GET resp OK, %u\r\n", returned_led_state);
                    post_fsm_state = PFSM_OK;
                } else {
                    DPOST_ERR_PRINTLN("ERR bad GET response");
                    post_fsm_state = PFSM_OK; // don't fail the whole process, it's not that important
                }
            } else if (millis() > timeout_end){
                DPOST_ERR_PRINTLN("ERR GET response timeout");
                post_fsm_state = PFSM_OK; // don't fail the whole process, it's not that important
            }

            break;
            
        case PFSM_OK:
            // end state
            //DPOST_INFO_PRINTLN("OK!");
            end_fsm();
            _delay_ms(8); // it seems to be important to wait a little after closing the port and before shutting down the CC3000...
            cc3000_stop();
            break;
        case PFSM_ERROR:
            // end state
            end_fsm();
            _delay_ms(8); // it seems to be important to wait a little after closing the port and before shutting down the CC3000...
            cc3000_stop();
            //DPOST_INFO_PRINTLN("ERROR!");
            break;
    }
    
    if (prev_post_fsm_state != post_fsm_state && post_fsm_state == PFSM_ERROR){
        error_post_fsm_state = prev_post_fsm_state;
    }
    
    return (prev_post_fsm_state == PFSM_OK || prev_post_fsm_state == PFSM_ERROR);
}