/* @brief Stop command timeout detection timer.
 */
void WiFiEngine__CommandTimeoutStop(void)
{
   DE_TRACE_STATIC(TR_NOISE, "stopping command timeout timer\n");
   DriverEnvironment_CancelTimer(wifiEngineState.cmd_timer_id);
   WES_CLEAR_FLAG(WES_FLAG_CMD_TIMEOUT_RUNNING);
}
/*!
 * @brief Requests to release the hic interface resource.
 *
 * @param id Identifies the user that requests the release.
 *
 * @return nothing.
 */
void wei_release_resource_hic(int id)
{
   int users;
   int thisUser;
   DE_TRACE_STATIC(TR_PS, "===========> wei_release_resource_hic\n"); 
   DE_TRACE_STRING(TR_PS_DEBUG,"State is: %s \n",state_name[state]);   
   WIFI_RESOURCE_HIC_LOCK(); 
   
   if((wifiEngineState.users & id) == 0)
   {
      /* nothing to release */
      WIFI_RESOURCE_HIC_UNLOCK();
      return;
   }
   thisUser = id;
   users = wifiEngineState.users;

   wifiEngineState.users &= ~id;

   /* trace this only while ps_enabled==TRUE */
   DE_TRACE_INT3(TR_PS, "id: %d users: %d=>%d \n",id, users,wifiEngineState.users);      

   if((id == RESOURCE_DISABLE_PS)&&(state == INTERFACE_PS_DISABLED))
   {
      /* The resource to disable power save mechansim for hic
         interface is released */
      state = INTERFACE_PS_OPEN; 
      we_ind_send(WE_IND_HIC_PS_INTERFACE_ENABLED, NULL );
   }

   if (wifiEngineState.users != 0)
   {
      /* There is someone that has requested to use the interface*/
      WIFI_RESOURCE_HIC_UNLOCK();
      return;
   }

   /* None is using the interface */
   switch(state)
   {
      case INTERFACE_PS_DISABLED:
      {;
         /* Interface has been disabled now it is time to enable it again */       
         state = INTERFACE_PS_CLOSED_WAIT;
         /* Inform firmware that ps hic interface is not used anymore */
         WiFiEngine_PsSendInterface_Down();
         state = INTERFACE_PS_CLOSED;  
      }
      break; 

      case INTERFACE_PS_OPEN:
      {
         rPowerManagementProperties *powerManagementProperties = NULL; 
         powerManagementProperties = (rPowerManagementProperties *)Registry_GetProperty(ID_powerManagement);
         
         /* Interface is temporary open - close it */   
         if(isLegacyPsNoPsPoll() && (thisUser == RESOURCE_USER_DATA_PATH) && (powerManagementProperties->psTxTrafficTimeout > 0))

         {
            /* Start a tx traffic timeout that will hold firware
               awake if more data is about to be sent */
            if(WES_TEST_FLAG(WES_FLAG_PS_TRAFFIC_TIMEOUT_RUNNING))
            {
               /* Cancel the timer so we can restart it */
               DriverEnvironment_CancelTimer(wifiEngineState.ps_traffic_timeout_timer_id);
               WES_CLEAR_FLAG(WES_FLAG_PS_TRAFFIC_TIMEOUT_RUNNING);
            }

            WIFI_RESOURCE_HIC_UNLOCK();
            wei_request_resource_hic(RESOURCE_USER_TX_TRAFFIC_TMO);
            WIFI_RESOURCE_HIC_LOCK();            
            
            if (DriverEnvironment_RegisterTimerCallback(powerManagementProperties->psTxTrafficTimeout, 
                     wifiEngineState.ps_traffic_timeout_timer_id,ps_traffic_timeout_cb,0) != 1)
            {
                DE_TRACE_STATIC(TR_SEVERE,"Failed to register timer callback\n");
                /* Skip timer and go to sleep */
                wifiEngineState.users = 0;
                wifiEngineState.dataPathState = DATA_PATH_CLOSED;
                state = INTERFACE_PS_CLOSED_WAIT;
                /* Inform firmware that ps hic interface is not used anymore */
                WiFiEngine_PsSendInterface_Down();
                state = INTERFACE_PS_CLOSED; 
            }
            else
            {
               WES_SET_FLAG(WES_FLAG_PS_TRAFFIC_TIMEOUT_RUNNING);
            }          

         }
         else
         { 
            wifiEngineState.dataPathState = DATA_PATH_CLOSED;
            state = INTERFACE_PS_CLOSED_WAIT;
            /* Inform firmware that ps hic interface is not used anymore */
            WiFiEngine_PsSendInterface_Down();
            state = INTERFACE_PS_CLOSED;
         }
      }      
      break;

      case INTERFACE_PS_CLOSED:
         DE_TRACE_STATIC(TR_PS, "State is closed no action\n"); 
      break;

      case INTERFACE_PS_OPEN_WAIT:
         DE_TRACE_STATIC(TR_PS, "Transit to OPEN state no action\n"); 
      break;         
      case INTERFACE_PS_CLOSED_WAIT:
         DE_TRACE_STATIC(TR_PS, "Transit to CLOSE state no action\n");          
      break;

      default:
         DE_TRACE_INT(TR_PS,"Unknown state is: %d \n",state);
         DE_ASSERT(FALSE);
      break;

   }

   WIFI_RESOURCE_HIC_UNLOCK();
   DE_TRACE_STRING(TR_PS_DEBUG,"State is: %s \n",state_name[state]);
   DE_TRACE_STATIC(TR_PS, "<=========== wei_release_resource_hic\n");    
}
/*!
 * @brief Handles packet received when core dump is enabled.
 *
 * @param pkt Received packet.
 *
 * @return 
 * - Always returns WIFI_ENGINE_SUCCESS
 */
void WiFiEngine_HandleCoreDumpPkt(char* pkt)
{
   size_t size;
   unsigned char *msg =  NULL;
   
   if (!WES_TEST_FLAG(WES_FLAG_HW_PRESENT)) 
      return;
   
   switch(core_dump_state)
   {
      case W4_SCB_ERROR_CFM:
      {
         unsigned char tx_desc[TX_DESC_SIZE];
         hic_message_context_t msg_ref;
         uint8_t  messageId;
         uint8_t  messageType;
         Blob_t blob;
         Mlme_CreateMessageContext(msg_ref);

         INIT_BLOB(&blob, pkt, 1500); /* XXX */
         /* Remove HIC header and add type/id info to msg_ref */
         packer_HIC_Unpack(&msg_ref, &blob); 
         messageId = msg_ref.msg_id;
         messageType = msg_ref.msg_type;
         msg_ref.packed = NULL;
         Mlme_ReleaseMessageContext(msg_ref);

         if((messageType == HIC_MESSAGE_TYPE_CTRL) && (messageId == HIC_CTRL_SCB_ERROR_CFM))
            {
               /* Handle confirm message */         
               if(handleSCBErrorCfm(pkt) == 0) 
               {

                  /* SCB_ERROR_CFM has error code 0, this means that firmware.
                   * is executing "normally" (no scb error has occured).
                   * However a command timeout has occured so it would be nice
                   * to force firmware in scb error and try to get a core dump.
                   */
                  DE_TRACE_STATIC(TR_ALWAYS,"Cancel timer\n");
                  DriverEnvironment_CancelTimer(wifiEngineState.cmd_timer_id);
                  DE_TRACE_STATIC(TR_ALWAYS,"Suicide requested\n");  
                  sendCommitSuicideRequest();
                  wifiEngineState.core_dump_state = WEI_CORE_DUMP_DISABLED;
                  return;
               }


            if(m_ext_ctx) 
            {
               /* Coredump already started */
               DriverEnvironment_Core_Dump_Abort(
                                          registry.network.basic.enableCoredump, 
                                          registry.network.basic.restartTargetAfterCoredump,
                                          m_objId,
                                          m_errCode, 
                                          &m_ext_ctx);
            } 
            else 
            {
               DriverEnvironment_indicate(WE_IND_CORE_DUMP_START, NULL, 0);
            }
            DriverEnvironment_Core_Dump_Started(
                                          registry.network.basic.enableCoredump, 
                                          registry.network.basic.restartTargetAfterCoredump,
                                          m_objId,
                                          m_errCode, 
                                          dump_total_size(dump_address_table),
                                          dump_total_size(dump_address_table),
                                          &m_ext_ctx);

            /* Turn off traces */
            //trace_mask &= ~(TR_CMD | TR_NOISE | TR_PS | TR_HIGH_RES | TR_DATA );
            trace_mask = 0;

            DriverEnvironment_Enable_Boot();

            /* This is to prevent command timeout logic to re-start the timer */
            WES_SET_FLAG(WES_FLAG_CMD_TIMEOUT_RUNNING);

            /* Initiate physical bm-descriptor to point to tx-descriptors */
            createDataReq_u32(&msg, StartDescriptorAddress, 
                              StartTxBmDesc + OFFSET_TO_POINTER_BM_DESC, &size);
            /* Clear any pending flags and flush queue*/
            wifiEngineState.cmdReplyPending = 0;
            wei_clear_cmd_queue();
            
            wei_send_cmd_raw((char *)msg, size);

            /* Initiate targets tx-descriptor to be used */
            createTxDescriptor(tx_desc);
            createDataReq(&msg, tx_desc, sizeof(tx_desc),
                          StartDescriptorAddress, &size);
            /* Clear any pending flags and flush queue*/
            wifiEngineState.cmdReplyPending = 0;
            wei_clear_cmd_queue();
            wei_send_cmd_raw((char *)msg, size);

            core_dump_state = W4_MEMORY_DUMP;
            /*
             * if m_ext_ctx==NULL we are not interested in the coredump and can restart the target directly
             * Not sure of how to do this in a safe way so will go ahead with the coredump anyway for now and fix this later 
             */
            if(m_ext_ctx==NULL) { 
               trace_mask = old_trace_mask; 
               DriverEnvironment_Core_Dump_Complete(
                                                FALSE,
                                                registry.network.basic.restartTargetAfterCoredump,
                                                m_objId,
                                                m_errCode, 
                                                &m_ext_ctx);
               DriverEnvironment_indicate(WE_IND_CORE_DUMP_COMPLETE, NULL, 0);
               DriverEnvironment_CancelTimer(wifiEngineState.cmd_timer_id);
               WES_CLEAR_FLAG(WES_FLAG_CMD_TIMEOUT_RUNNING);
               return;
            }

            currentRegion = dump_address_table;
            currentAddress = dump_region_start(currentRegion);

            getNextBlock(currentAddress);
         }
         else
         {
            DE_TRACE_INT2(TR_ALWAYS, "unexpected message %u.%u\n",
                          messageType,
                          messageId); 
         }
      }
      break;

      case W4_MEMORY_DUMP:
      {
         uint32_t len;
         /* Store recevied packet in a file */
         
         len = HIC_MESSAGE_LENGTH_GET(pkt);
         /* Move beyond size */ 
         pkt += 2;
         len -= 2;
         
         /* Write dumpfile header (for nrx600 coredumps) */
         if (dump_address_table == dump_address_table_nrx600
             && m_ext_ctx
             && currentAddress == dump_region_start(currentRegion)) {
            DriverEnvironment_Core_Dump_Write(m_ext_ctx, 
                                              (char *)currentRegion, 
                                              sizeof(*currentRegion));
         }
         
         len = DE_MIN(len, dump_region_end(currentRegion) - currentAddress);
         /* Copy to buffer */
         if (m_ext_ctx) {
            DriverEnvironment_Core_Dump_Write(m_ext_ctx, pkt, len);
         }

         currentAddress += len;

         if(currentAddress >= dump_region_end(currentRegion)) {
            /* end of region, skip forward */
            currentRegion++;
            currentAddress = dump_region_start(currentRegion);
            if(dump_region_size(currentRegion) == 0) {
               /* Complete - Start store data on a file and restart driver */
               trace_mask = old_trace_mask;
               DE_TRACE_STATIC(TR_ALWAYS,"Coredump complete - cancel timer\n");
               DriverEnvironment_CancelTimer(wifiEngineState.cmd_timer_id);
               WES_CLEAR_FLAG(WES_FLAG_CMD_TIMEOUT_RUNNING);
               DriverEnvironment_Core_Dump_Complete(registry.network.basic.enableCoredump && m_ext_ctx != NULL, /* see driverenv.h */
                                                    registry.network.basic.restartTargetAfterCoredump,
                                                    m_objId,
                                                    m_errCode, 
                                                    &m_ext_ctx);
               DriverEnvironment_indicate(WE_IND_CORE_DUMP_COMPLETE, NULL, 0);
               return;
            }
         }
         getNextBlock(currentAddress);
      }
      break;

      default:
         DE_BUG_ON(TRUE, "Invalid core dump state\n");
         break;
   }
}