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; }
// 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); }