/**************************************************************************** * apps/lte/alt1250/alt1250_devevent.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you 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. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include "alt1250_dbg.h" #include "alt1250_evt.h" #include "alt1250_devif.h" #include "alt1250_devevent.h" #include "alt1250_postproc.h" #include "alt1250_container.h" #include "alt1250_usockif.h" #include "alt1250_usockevent.h" #include "alt1250_socket.h" #include "alt1250_usrsock_hdlr.h" #include "alt1250_select.h" #include "alt1250_sms.h" #include "alt1250_netdev.h" #include "alt1250_reset_seq.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ #define IS_PV1_FIRMWARE(d) (!strncmp(MODEM_FWVERSION(d), \ "RK_02_01_", 9)) /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: handle_replypkt ****************************************************************************/ static int handle_replypkt(FAR struct alt1250_s *dev, FAR struct alt_container_s *reply, FAR int32_t *usock_result, uint32_t *usock_xid, FAR struct usock_ackinfo_s *ackinfo) { int ret; FAR struct usock_s *usock; FAR struct postproc_s *pp = CONTAINER_POSTPROC(reply); usock = usocket_search(dev, CONTAINER_SOCKETID(reply)); dbg_alt1250("reply->result: %d\n", CONTAINER_RESPRES(reply)); *usock_result = CONTAINER_RESPRES(reply); *usock_xid = usock ? USOCKET_XID(usock) : -1; ret = usock ? REP_SEND_ACK : REP_NO_ACK; if (pp && pp->hdlr) { ret = pp->hdlr(dev, reply, usock, usock_result, usock_xid, ackinfo, pp->priv); } return ret; } /**************************************************************************** * Name: perform_alt1250_reply ****************************************************************************/ static int perform_alt1250_reply(FAR struct alt1250_s *dev, FAR struct alt_container_s *container) { int ret = REP_NO_ACK; int32_t ack_result = OK; uint32_t ack_xid = 0; struct usock_ackinfo_s ackinfo; ret = handle_replypkt(dev, container, &ack_result, &ack_xid, &ackinfo); if (LTE_IS_ASYNC_CMD(container->cmdid)) { ret = REP_NO_ACK; } usock_reply(dev->usockfd, ret, ack_result, ack_xid, &ackinfo); return ret; } /**************************************************************************** * Name: handle_normal_reset ****************************************************************************/ static int handle_normal_reset(FAR struct alt1250_s *dev) { alt1250_clrevtcb(ALT1250_CLRMODE_WO_RESTART); dev->recvfrom_processing = false; dev->lwm2m_apply_xid = -1; alt1250_netdev_ifdown(dev); usocket_freeall(dev); reset_fwupdate_info(dev); alt1250_reset_sms_info(dev); reset_usock_device(dev->usockfd); return REP_MODEM_RESET; } /**************************************************************************** * name: handle_intentional_reset ****************************************************************************/ static int handle_intentional_reset(FAR struct alt1250_s *dev) { if (dev->lwm2m_apply_xid >= 0) { usockif_sendack(dev->usockfd, 0, (uint32_t)dev->lwm2m_apply_xid, false); dev->lwm2m_apply_xid = -1; } alt1250_clrevtcb(ALT1250_CLRMODE_WO_RESTART); dev->recvfrom_processing = false; alt1250_netdev_ifdown(dev); usocket_freeall(dev); alt1250_reset_sms_info(dev); reset_usock_device(dev->usockfd); MODEM_STATE_PON(dev); return REP_NO_ACK; } /**************************************************************************** * Name: perform_alt1250_resetevt ****************************************************************************/ static int perform_alt1250_resetevt(FAR struct alt1250_s *dev, FAR struct alt_container_s *rlist) { int ret; container_free_all(rlist); dev->sid = -1; switch (MODEM_STATE(dev)) { case MODEM_BEFORE_PON: ret = handle_poweron_reset(dev); break; case MODEM_BEFORE_PON_STAGE2: ret = handle_poweron_reset_stage2(dev); break; case MODEM_RST_INTENTIONAL: ret = handle_intentional_reset(dev); break; default: ret = handle_normal_reset(dev); break; } return ret; } #ifdef CONFIG_LTE_ALT1250_ENABLE_HIBERNATION_MODE /**************************************************************************** * Name: perform_alt1250_apistopevt ****************************************************************************/ static void perform_alt1250_apistopevt(FAR struct alt1250_s *dev) { int ret = OK; int w_cnt = 0; /* The "ALT1250_EVTBIT_STOPAPI" command isn't supported for PV1 firmware */ if (IS_PV1_FIRMWARE(dev)) { dbg_alt1250("This firmware doesn't support hibernation mode.\n"); ret = ERROR; goto exit; } /* All LTE API/Socket requests must be stopped to enter Suspend mode. */ ret = alt1250_set_api_enable(dev, false); if (ret < 0) { dbg_alt1250("Failed to stop API call.\n"); ret = ERROR; goto exit; } /* Application need to context data when LTE function resume from * hibernation. */ if (!dev->context_cb) { dbg_alt1250("Context save callback not registered.\n"); ret = ERROR; goto exit; } /* When entering Suspend mode, all Sockets must be closed. */ ret = alt1250_count_opened_sockets(dev); if (ret < 0) { dbg_alt1250("Failed to count opened sockets.\n"); ret = ERROR; goto exit; } else if (ret > 0) { dbg_alt1250("There are opened socket, " "could not entering hibernation mode.\n"); ret = ERROR; goto exit; } /* Refuse to enter Suspend mode if the LTE API already running has not yet * completed. */ ret = alt1250_is_api_in_progress(dev); if (ret < 0) { dbg_alt1250("Failed to check API call status.\n"); ret = ERROR; goto exit; } else if (ret > 0) { dbg_alt1250("There are in progress API call, " "could not entering hibernation mode.\n"); ret = ERROR; goto exit; } /* When Wakelock is acquired, Suspend mode is rejected because * it is not possible to enter Suspend mode. */ w_cnt = altdevice_powercontrol(dev->altfd, LTE_CMDID_COUNTWLOCK); if (w_cnt == 0) { ret = OK; } else if (w_cnt > 0) { dbg_alt1250("Cannot enter hibernation due to wakelock is aquired.\n"); ret = -EBUSY; } else { dbg_alt1250("Failed to get wakelock count.\n"); ret = w_cnt; } exit: if (ret < 0) { alt1250_set_api_enable(dev, true); } altdevice_powerresponse(dev->altfd, LTE_CMDID_STOPAPI, ret); } /**************************************************************************** * Name: perform_alt1250_suspendevt ****************************************************************************/ static void perform_alt1250_suspendevt(FAR struct alt1250_s *dev) { /* TODO: Register Select to be notified by ALT1250 when an event is * received during Sleep for a Socket in Suspend. */ /* Notify the application of the context data required for resume. */ alt1250_collect_daemon_context(dev); altdevice_powerresponse(dev->altfd, LTE_CMDID_SUSPEND, 0); } #endif /**************************************************************************** * Name: perform_netinfo_report_event ****************************************************************************/ uint64_t perform_netinfo_report_event(FAR struct alt1250_s *dev, uint64_t bitmap) { uint64_t bit = 0ULL; FAR void **arg; FAR lte_netinfo_t *info; FAR lte_pdn_t *pdn; if (alt1250_checkcmdid(LTE_CMDID_REPNETINFO, bitmap, &bit)) { arg = alt1250_getevtarg(LTE_CMDID_REPNETINFO); if (arg && arg[0]) { /* arg[0]: Network information (see lte_netinfo_t) */ info = (FAR lte_netinfo_t *)arg[0]; if (info->pdn_num == 0) { alt1250_netdev_ifdown(dev); } else { pdn = &info->pdn_stat[0]; if (pdn->active == LTE_PDN_ACTIVE) { alt1250_netdev_ifup(dev, pdn); } else { alt1250_netdev_ifdown(dev); } } } } return bit; } /**************************************************************************** * Public functions ****************************************************************************/ /**************************************************************************** * Name: perform_alt1250events ****************************************************************************/ int perform_alt1250events(FAR struct alt1250_s *dev) { int ret = OK; uint64_t bitmap; uint64_t eventbit; FAR struct alt_container_s *reply_list; FAR struct alt_container_s *container; ret = altdevice_getevent(dev->altfd, &bitmap, &reply_list); ASSERT(ret == OK); if (bitmap & ALT1250_EVTBIT_RESET) { /* Handling reset event */ ret = perform_alt1250_resetevt(dev, reply_list); if (ret != REP_MODEM_RESET) { /* No need to send reset event to application * in case of intentional reset */ bitmap &= ~ALT1250_EVTBIT_RESET; } } #ifdef CONFIG_LTE_ALT1250_ENABLE_HIBERNATION_MODE else if (bitmap & ALT1250_EVTBIT_STOPAPI) { /* Handling API stop request */ perform_alt1250_apistopevt(dev); } else if (bitmap & ALT1250_EVTBIT_SUSPEND) { /* Handling Suspend request */ perform_alt1250_suspendevt(dev); } #endif else { /* Handling reply containers */ if (bitmap & ALT1250_EVTBIT_REPLY) { while ((container = container_pick_listtop(&reply_list)) != NULL) { ret = perform_alt1250_reply(dev, container); if (IS_NEED_CONTAINER_FREE(ret)) { container_free(container); } } bitmap &= ~ALT1250_EVTBIT_REPLY; } /* Handling select async event */ if ((eventbit = perform_select_event(dev, bitmap)) != 0ULL) { bitmap &= ~eventbit; } /* Handling sms report event */ if ((eventbit = perform_sms_report_event(dev, bitmap)) != 0ULL) { bitmap &= ~eventbit; } /* Handling report network information event */ perform_netinfo_report_event(dev, bitmap); /* Do not clear the bit here to notify the event task */ } if (bitmap) { alt1250_evttask_sendmsg(dev, bitmap); } return ret; }