未验证 提交 9b84e6ab 编写于 作者: O openharmony_ci 提交者: Gitee

!52 OpenHarmony lwip低功耗修改

Merge pull request !52 from Huge_Dream/lwip_lowpower
......@@ -53,6 +53,7 @@ COREFILES = [
"$LWIPDIR/core/timeouts.c",
"$LWIPDIR/core/udp.c",
"$LWIPDIR/core/net_group.c",
"$LWIPDIR/core/lowpower.c",
]
CORE4FILES = [
......
......@@ -53,6 +53,7 @@ set(lwipcore_SRCS
${LWIP_DIR}/src/core/timeouts.c
${LWIP_DIR}/src/core/udp.c
${LWIP_DIR}/src/core/net_group.c
${LWIP_DIR}/src/core/lowpower.c
)
set(lwipcore4_SRCS
${LWIP_DIR}/src/core/ipv4/autoip.c
......
......@@ -50,7 +50,8 @@ COREFILES=$(LWIPDIR)/core/init.c \
$(LWIPDIR)/core/tcp_out.c \
$(LWIPDIR)/core/timeouts.c \
$(LWIPDIR)/core/udp.c \
$(LWIPDIR)/core/net_group.c
$(LWIPDIR)/core/net_group.c \
$(LWIPDIR)/core/lowpower.c
CORE4FILES=$(LWIPDIR)/core/ipv4/autoip.c \
$(LWIPDIR)/core/ipv4/dhcp.c \
......
......@@ -387,6 +387,35 @@ poll_tcp(void *arg, struct tcp_pcb *pcb)
return ERR_OK;
}
#if LWIP_LOWPOWER
/* check wether need to poll tcp */
u8_t
poll_tcp_needed(void *arg, struct tcp_pcb *pcb)
{
struct netconn *conn = (struct netconn *)arg;
u8_t ret = 0;
LWIP_UNUSED_ARG(pcb);
if (conn == NULL) {
return 0;
}
if ((conn->state == NETCONN_WRITE) || (conn->state == NETCONN_CLOSE)) {
ret = 1;
}
/* Did a nonblocking write fail before? Then check available write-space. */
if ((conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) != 0) {
/* If the queued byte- or pbuf-count drops below the configured low-water limit,
let select mark this pcb as writable again. */
if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
(tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
ret = 1;
}
}
return ret;
}
#endif /* LWIP_LOWPOWER */
/**
* Sent callback function for TCP netconns.
* Signals the conn->sem and calls API_EVENT.
......
......@@ -384,4 +384,45 @@ netifapi_netif_index_to_name(u8_t idx, char *name)
return err;
}
#if LWIP_LOWPOWER
static err_t
netifapi_do_set_lowpower_mod(struct tcpip_api_call_data *m)
{
struct netifapi_msg *msg = (struct netifapi_msg *)(void *)m;
enum lowpower_mod mod = msg->msg.lp.mod;
set_lowpower_mod(mod);
return ERR_OK;
}
err_t
netifapi_enable_lowpower(void)
{
err_t err;
NETIFAPI_VAR_DECLARE(msg);
NETIFAPI_VAR_ALLOC(msg);
NETIFAPI_VAR_REF(msg).msg.lp.mod = LOW_TMR_LOWPOWER_MOD;
err = tcpip_api_call(netifapi_do_set_lowpower_mod, &API_VAR_REF(msg).call);
NETIFAPI_VAR_FREE(msg);
return err;
}
err_t
netifapi_disable_lowpower(void)
{
err_t err;
NETIFAPI_VAR_DECLARE(msg);
NETIFAPI_VAR_ALLOC(msg);
NETIFAPI_VAR_REF(msg).msg.lp.mod = LOW_TMR_NORMAL_MOD;
err = tcpip_api_call(netifapi_do_set_lowpower_mod, &API_VAR_REF(msg).call);
NETIFAPI_VAR_FREE(msg);
return err;
}
#endif /* LWIP_LOWPOWER */
#endif /* LWIP_NETIF_API */
......@@ -72,6 +72,10 @@
#include LWIP_HOOK_FILENAME
#endif
#if LWIP_LOWPOWER
#include "lwip/lowpower.h"
#endif
/* If the netconn API is not required publicly, then we include the necessary
files here to get the implementation */
#if !LWIP_NETCONN
......@@ -3300,6 +3304,9 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt
LOCK_TCPIP_CORE();
err = lwip_setsockopt_impl(s, level, optname, optval, optlen);
UNLOCK_TCPIP_CORE();
#if LWIP_LOWPOWER
tcpip_send_msg_na(LOW_NON_BLOCK);
#endif
#else /* LWIP_TCPIP_CORE_LOCKING */
......
......@@ -49,6 +49,9 @@
#include "lwip/pbuf.h"
#include "lwip/etharp.h"
#include "netif/ethernet.h"
#if LWIP_LOWPOWER
#include "lwip/lowpower.h"
#endif
#define TCPIP_MSG_VAR_REF(name) API_VAR_REF(name)
#define TCPIP_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct tcpip_msg, name)
......@@ -73,6 +76,7 @@ static void tcpip_thread_handle_msg(struct tcpip_msg *msg);
#else /* !LWIP_TIMERS */
/* wait for a message, timeouts are processed while waiting */
#define TCPIP_MBOX_FETCH(mbox, msg) tcpip_timeouts_mbox_fetch(mbox, msg)
#if !LWIP_LOWPOWER
/**
* Wait (forever) for a message to arrive in an mbox.
* While waiting, timeouts are processed.
......@@ -111,6 +115,7 @@ again:
goto again;
}
}
#endif /* !LWIP_LOWPOWER */
#endif /* !LWIP_TIMERS */
/**
......@@ -201,7 +206,17 @@ tcpip_thread_handle_msg(struct tcpip_msg *msg)
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg));
msg->msg.cb.function(msg->msg.cb.ctx);
break;
#if LWIP_LOWPOWER
/* just wake up thread do nothing */
case TCPIP_MSG_NA:
if (msg->msg.lowpower.type == LOW_BLOCK) {
LOWPOWER_SIGNAL(msg->msg.lowpower.wait_up);
} else {
memp_free(MEMP_TCPIP_MSG_LOWPOWER, msg);
}
sys_timeout_set_wake_time(LOW_TMR_DELAY);
break;
#endif
default:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type));
LWIP_ASSERT("tcpip_thread: invalid message", 0);
......@@ -209,6 +224,58 @@ tcpip_thread_handle_msg(struct tcpip_msg *msg)
}
}
#if LWIP_LOWPOWER
/* send a na msg to wake up tcpip_thread */
void
tcpip_send_msg_na(enum lowpower_msg_type type)
{
struct tcpip_msg *msg = NULL;
err_t val;
/* is not used lowpower mode */
if ((type != LOW_FORCE_NON_BLOCK) && (get_lowpowper_mod() == LOW_TMR_NORMAL_MOD)) {
return;
}
if (sys_timeout_waiting_long() == 0) {
return;
}
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_LOWPOWER);
if (msg == NULL) {
LWIP_DEBUGF(LOWPOWER_DEBUG, ("tcpip_send_msg_na alloc faild\n"));
return;
}
/* just wake up thread if nonblock */
msg->type = TCPIP_MSG_NA;
msg->msg.lowpower.type = type;
if (type == LOW_BLOCK) {
LOWPOWER_SEM_NEW(msg->msg.lowpower.wait_up, val);
if (val != ERR_OK) {
LWIP_DEBUGF(LOWPOWER_DEBUG, ("alloc sem faild\n"));
memp_free(MEMP_TCPIP_MSG_LOWPOWER, msg);
return;
}
}
if (sys_mbox_trypost(&tcpip_mbox, msg) != ERR_OK) {
if (type == LOW_BLOCK) {
LOWPOWER_SEM_FREE(msg->msg.lowpower.wait_up);
}
memp_free(MEMP_TCPIP_MSG_LOWPOWER, msg);
LWIP_DEBUGF(LOWPOWER_DEBUG, ("tcpip_send_msg_na post faild\n"));
return;
}
if (type == LOW_BLOCK) {
LOWPOWER_SEM_WAIT(msg->msg.lowpower.wait_up);
LOWPOWER_SEM_FREE(msg->msg.lowpower.wait_up);
memp_free(MEMP_TCPIP_MSG_LOWPOWER, msg);
}
}
#endif /* LWIP_LOWPOWER */
#ifdef TCPIP_THREAD_TEST
/** Work on queued items in single-threaded test mode */
int
......@@ -242,6 +309,9 @@ tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn)
#if LWIP_TCPIP_CORE_LOCKING_INPUT
err_t ret;
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_inpkt: PACKET %p/%p\n", (void *)p, (void *)inp));
#if LWIP_LOWPOWER
tcpip_send_msg_na(LOW_BLOCK);
#endif
LOCK_TCPIP_CORE();
ret = input_fn(p, inp);
UNLOCK_TCPIP_CORE();
......@@ -438,6 +508,9 @@ tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t *sem)
{
#if LWIP_TCPIP_CORE_LOCKING
LWIP_UNUSED_ARG(sem);
#if LWIP_LOWPOWER
tcpip_send_msg_na(LOW_BLOCK);
#endif
LOCK_TCPIP_CORE();
fn(apimsg);
UNLOCK_TCPIP_CORE();
......@@ -474,6 +547,9 @@ tcpip_api_call(tcpip_api_call_fn fn, struct tcpip_api_call_data *call)
{
#if LWIP_TCPIP_CORE_LOCKING
err_t err;
#if LWIP_LOWPOWER
tcpip_send_msg_na(LOW_BLOCK);
#endif
LOCK_TCPIP_CORE();
err = fn(call);
UNLOCK_TCPIP_CORE();
......
......@@ -407,6 +407,31 @@ dns_tmr(void)
dns_check_entries();
}
#if LWIP_LOWPOWER
#include "lwip/lowpower.h"
u32_t
dns_tmr_tick(void)
{
u32_t tick = 0;
u32_t val;
s32_t i;
for (i = 0; i < DNS_TABLE_SIZE; i++) {
if ((dns_table[i].state == DNS_STATE_NEW) ||
(dns_table[i].state == DNS_STATE_ASKING)) {
LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: 1\n", "dns_tmr_tick"));
return 1;
}
if (dns_table[i].state == DNS_STATE_DONE) {
val = dns_table[i].ttl;
SET_TMR_TICK(tick, val);
}
}
LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "dns_tmr_tick", tick));
return tick;
}
#endif
#if DNS_LOCAL_HOSTLIST
static void
dns_init_local(void)
......
......@@ -360,6 +360,29 @@ autoip_stop(struct netif *netif)
return ERR_OK;
}
#if LWIP_LOWPOWER
#include "lwip/lowpower.h"
u32_t
autoip_tmr_tick(void)
{
struct netif *netif = NULL;
u32_t tick = 0;
NETIF_FOREACH(netif) {
struct autoip *autoip = netif_autoip_data(netif);
if ((autoip != NULL) && (autoip->ttw > 0)) {
if ((autoip->state == AUTOIP_STATE_PROBING) ||
(autoip->state == AUTOIP_STATE_ANNOUNCING)) {
SET_TMR_TICK(tick, autoip->ttw);
}
}
}
LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "autoip_tmr_tick", tick));
return tick;
}
#endif
/**
* Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds
*/
......
......@@ -467,6 +467,65 @@ dhcp_coarse_tmr(void)
}
}
#if LWIP_LOWPOWER
#include "lwip/lowpower.h"
u32_t
dhcp_coarse_tmr_tick(void)
{
struct netif *netif;
u32_t tick = 0;
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_coarse_tmr()\n"));
/* iterate through all network interfaces */
#ifdef LOSCFG_NET_CONTAINER
NETIF_FOREACH(netif, get_root_net_group())
#else
NETIF_FOREACH(netif)
#endif
{
struct dhcp *dhcp = netif_dhcp_data(netif);
if ((dhcp != NULL) && (dhcp->state != DHCP_STATE_OFF)) {
if (dhcp->t0_timeout > 0) {
if (dhcp->t0_timeout > dhcp->lease_used) {
SET_TMR_TICK(tick, dhcp->t0_timeout - dhcp->lease_used);
} else {
SET_TMR_TICK(tick, 1);
}
}
if (dhcp->t2_rebind_time > 0) {
SET_TMR_TICK(tick, dhcp->t2_rebind_time);
}
if (dhcp->t1_renew_time > 0) {
SET_TMR_TICK(tick, dhcp->t1_renew_time);
}
}
}
return tick;
}
u32_t
dhcp_fine_tmr_tick(void)
{
struct netif *netif;
u32_t tick = 0;
/* loop through netif's */
#ifdef LOSCFG_NET_CONTAINER
NETIF_FOREACH(netif, get_root_net_group())
#else
NETIF_FOREACH(netif)
#endif
{
struct dhcp *dhcp = netif_dhcp_data(netif);
if (dhcp != NULL) {
if (dhcp->request_timeout > 0) {
SET_TMR_TICK(tick, dhcp->request_timeout);
}
}
}
return tick;
}
#endif /* LWIP_LOWPOWER */
/**
* DHCP transaction timeout handling (this function must be called every 500ms,
* see @ref DHCP_FINE_TIMER_MSECS).
......
......@@ -187,6 +187,35 @@ etharp_free_entry(int i)
#endif /* LWIP_DEBUG */
}
#if LWIP_LOWPOWER
#include "lwip/lowpower.h"
u32_t
etharp_tmr_tick(void)
{
s32_t i;
u32_t tick = 0;
u32_t time;
for (i = 0; i < ARP_TABLE_SIZE; i++) {
u8_t state = arp_table[i].state;
if ((state != ETHARP_STATE_EMPTY)
#if ETHARP_SUPPORT_STATIC_ENTRIES
&& (state != ETHARP_STATE_STATIC)
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
) {
if (arp_table[i].state != ETHARP_STATE_STABLE) {
LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: 1\n", "etharp_tmr_tick"));
return 1;
}
time = (u32_t)ARP_MAXAGE - arp_table[i].ctime;
SET_TMR_TICK(tick, time);
}
}
LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "etharp_tmr_tick", tick));
return tick;
}
#endif /* LWIP_LOWPOWER */
/**
* Clears expired entries in the ARP table.
*
......
......@@ -668,6 +668,32 @@ igmp_tmr(void)
}
}
#if LWIP_LOWPOWER
#include "lwip/lowpower.h"
u32_t
igmp_tmr_tick(void)
{
struct netif *netif = NULL;
u32_t tick = 0;
#ifdef LOSCFG_NET_CONTAINER
NETIF_FOREACH(netif, get_root_net_group())
#else
NETIF_FOREACH(netif)
#endif
{
struct igmp_group *group = netif_igmp_data(netif);
while (group != NULL) {
if (group->timer > 0) {
SET_TMR_TICK(tick, group->timer);
}
group = group->next;
}
}
LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "igmp_tmr_tick", tick));
return tick;
}
#endif
/**
* Called if a timeout for one group is reached.
* Sends a report for this group.
......
......@@ -213,6 +213,26 @@ ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *p
return pbufs_freed;
}
#if LWIP_LOWPOWER
#include "lwip/lowpower.h"
u32_t
ip_reass_tmr_tick(void)
{
struct ip_reassdata *r = NULL;
u32_t tick = 0;
u32_t val;
r = reassdatagrams;
while (r != NULL) {
val = r->timer + 1;
SET_TMR_TICK(tick, val);
r = r->next;
}
LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "ip_reass_tmr_tick", tick));
return tick;
}
#endif /* LWIP_LOWPOWER */
#if IP_REASS_FREE_OLDEST
/**
* Free the oldest datagram to make room for enqueueing new fragments.
......
......@@ -822,4 +822,29 @@ dhcp6_tmr(void)
}
}
#if LWIP_LOWPOWER
#include "lwip/lowpower.h"
u32_t
dhcp6_tmr_tick()
{
struct netif *netif = NULL;
u32_t tick = 0;
/* loop through netif's */
#ifdef LOSCFG_NET_CONTAINER
NETIF_FOREACH(netif, get_root_net_group())
#else
NETIF_FOREACH(netif)
#endif
{
struct dhcp6 *dhcp6 = netif_dhcp6_data(netif);
/* only act on DHCPv6 configured interfaces */
if ((dhcp6 != NULL) && (dhcp6->request_timeout > 0)) {
SET_TMR_TICK(tick, dhcp6->request_timeout);
}
}
LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "dhcp6_tmr_tick", tick));
return tick;
}
#endif /* LWIP_LOWPOWER */
#endif /* LWIP_IPV6 && LWIP_IPV6_DHCP6 */
......@@ -137,6 +137,26 @@ ip6_reass_tmr(void)
}
}
#if LWIP_LOWPOWER
#include "lwip/lowpower.h"
u32_t
ip6_reass_tmr_tick(void)
{
u32_t tick = 0;
u32_t val = 0;
struct ip6_reassdata *r = NULL;
r = reassdatagrams;
while (r != NULL) {
val = r->timer + 1;
SET_TMR_TICK(tick, val);
r = r->next;
}
LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "ip6_reass_tmr_tick", tick));
return tick;
}
#endif /* LWIP_LOWPOWER */
/**
* Free a datagram (struct ip6_reassdata) and all its pbufs.
* Updates the total count of enqueued pbufs (ip6_reass_pbufcount),
......
......@@ -529,6 +529,35 @@ mld6_tmr(void)
}
}
#if LWIP_LOWPOWER
#include "lwip/lowpower.h"
u32_t
mld6_tmr_tick(void)
{
struct netif *netif = NULL;
u32_t tick = 0;
#ifdef LOSCFG_NET_CONTAINER
NETIF_FOREACH(netif, get_root_net_group())
#else
NETIF_FOREACH(netif)
#endif
{
struct mld_group *group = netif_mld6_data(netif);
while (group != NULL) {
if (group->timer > 0) {
SET_TMR_TICK(tick, group->timer);
}
group = group->next;
}
}
LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "mld6_tmr_tick", tick));
return tick;
}
#endif
/**
* Schedule a delayed membership report for a group
*
......
......@@ -1167,6 +1167,106 @@ nd6_tmr(void)
}
#if LWIP_LOWPOWER
#include "lwip/lowpower.h"
u32_t
nd6_tmr_tick(void)
{
s8_t i;
struct netif *netif = NULL;
u32_t tick = 0;
u32_t val = 0;
for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
switch (neighbor_cache[i].state) {
case ND6_PROBE:
case ND6_INCOMPLETE: /* state PROBE and INCOMPLETE return 1 */
return 1;
case ND6_REACHABLE:
/* Send queued packets, if any are left. Should have been sent already. */
if (neighbor_cache[i].q != NULL) {
return 1;
}
if (neighbor_cache[i].counter.reachable_time >= ND6_TMR_INTERVAL) {
val = neighbor_cache[i].counter.reachable_time / ND6_TMR_INTERVAL;
SET_TMR_TICK(tick, val);
}
break;
case ND6_DELAY:
val = neighbor_cache[i].counter.delay_time;
SET_TMR_TICK(tick, val);
break;
default:
/* Do nothing. */
break;
}
}
/* Process router entries. */
for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) {
if (default_router_list[i].neighbor_entry != NULL) {
val = default_router_list[i].invalidation_timer;
SET_TMR_TICK(tick, val);
}
}
/* Process prefix entries. */
for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) {
if (prefix_list[i].netif != NULL) {
val = prefix_list[i].invalidation_timer;
SET_TMR_TICK(tick, val);
}
}
/* Process our own addresses, updating address lifetimes and/or DAD state. */
#ifdef LOSCFG_NET_CONTAINER
NETIF_FOREACH(netif, get_root_net_group())
#else
NETIF_FOREACH(netif)
#endif
{
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) {
u8_t addr_state;
#if LWIP_IPV6_ADDRESS_LIFETIMES
/* Step 1: update address lifetimes (valid and preferred). */
addr_state = netif_ip6_addr_state(netif, i);
if (!ip6_addr_isinvalid(addr_state) &&
!netif_ip6_addr_isstatic(netif, i)) {
u32_t life = netif_ip6_addr_valid_life(netif, i);
if (!ip6_addr_life_isinfinite(life)) {
SET_TMR_TICK(tick, life);
}
life = netif_ip6_addr_pref_life(netif, i);
if (!ip6_addr_life_isinfinite(life)) {
SET_TMR_TICK(tick, life);
}
}
/* The address state may now have changed, so reobtain it next. */
#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */
/* Step 2: update DAD state. */
addr_state = netif_ip6_addr_state(netif, i);
if (ip6_addr_istentative(addr_state)) {
LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: 1\n", "nd6_tmr_tick"));
return 1;
}
}
}
/* Router solicitations are sent in 4 second intervals (see RFC 4861, ch. 6.3.7) */
/* ND6_RTR_SOLICITATION_INTERVAL */
#if LWIP_IPV6_SEND_ROUTER_SOLICIT
if (nd6_tmr_rs_reduction > 0) {
val = nd6_tmr_rs_reduction;
SET_TMR_TICK(tick, val);
}
#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "nd6_tmr_tick", tick));
return tick;
}
#endif /* LWIP_LOWPOWER */
/** Send a neighbor solicitation message for a specific neighbor cache entry
*
* @param entry the neightbor cache entry for wich to send the message
......
/*
* Copyright (c) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "lwip/opt.h"
#if LWIP_LOWPOWER
#include "lwip/priv/tcp_priv.h"
#include "lwip/def.h"
#include "lwip/memp.h"
#include "lwip/priv/tcpip_priv.h"
#include "lwip/ip4_frag.h"
#include "lwip/etharp.h"
#include "lwip/dhcp.h"
#include "lwip/autoip.h"
#include "lwip/igmp.h"
#include "lwip/dns.h"
#include "lwip/nd6.h"
#include "lwip/ip6_frag.h"
#include "lwip/mld6.h"
#include "lwip/dhcp6.h"
#include "lwip/sys.h"
#include "lwip/pbuf.h"
#include "netif/lowpan6.h"
#include "lwip/api.h"
#include "lwip/lowpower.h"
#define TIMEOUT_MAX 120000 /* two mins */
#define SYS_TIMEOUT_WAIT_TICKS 30
#define SYS_TIMEOUT_WAIT_TIME_MS 3
static u32_t g_wake_up_time = TIMEOUT_MAX;
static enum lowpower_mod g_lowpower_switch = LOW_TMR_LOWPOWER_MOD;
static struct timer_entry *g_timer_header = NULL;
static struct timer_mng g_timer_mng = { LOW_TMR_TIMER_HANDLING, 0 };
static u32_t g_last_check_timeout = 0;
static const struct timer_handler lowpower_timer_handler[] = {
#if LWIP_TCP
/*
* The TCP timer is a special case: it does not have to run always and
* is triggered to start from TCP using tcp_timer_needed()
*/
{TCP_FAST_INTERVAL, tcp_fasttmr, tcp_fast_tmr_tick TCP_FASTTMR_NAME},
{TCP_SLOW_INTERVAL, tcp_slowtmr, tcp_slow_tmr_tick TCP_SLOWTMR_NAME},
#endif /* LWIP_TCP */
#if LWIP_IPV4
#if IP_REASSEMBLY
{IP_TMR_INTERVAL, ip_reass_tmr, ip_reass_tmr_tick IP_REASSTRM_NAME},
#endif /* IP_REASSEMBLY */
#if LWIP_ARP
{ARP_TMR_INTERVAL, etharp_tmr, etharp_tmr_tick ETHARPTMR_NAME},
#endif /* LWIP_ARP */
#if LWIP_DHCP
{DHCP_FINE_TIMER_MSECS, dhcp_fine_tmr, dhcp_fine_tmr_tick DHCP_FINETMR_NAME},
{DHCP_COARSE_TIMER_MSECS, dhcp_coarse_tmr, dhcp_coarse_tmr_tick DHCP_COARSETMR_NAME},
#endif /* LWIP_DHCP */
#if LWIP_AUTOIP
{AUTOIP_TMR_INTERVAL, autoip_tmr, autoip_tmr_tick AUTOIPTMR_NAME},
#endif /* LWIP_AUTOIP */
#if LWIP_IGMP
{IGMP_TMR_INTERVAL, igmp_tmr, igmp_tmr_tick IGMPTMR_NAME},
#endif /* LWIP_IGMP */
#endif /* LWIP_IPV4 */
#if LWIP_DNS
{DNS_TMR_INTERVAL, dns_tmr, dns_tmr_tick DNSTMR_NAME},
#endif /* LWIP_DNS */
#if LWIP_IPV6
{ND6_TMR_INTERVAL, nd6_tmr, nd6_tmr_tick ND6TMR_NAME},
#if LWIP_IPV6_REASS
{IP6_REASS_TMR_INTERVAL, ip6_reass_tmr, ip6_reass_tmr_tick IP6_TREASSTMR_NAME},
#endif /* LWIP_IPV6_REASS */
#if LWIP_IPV6_MLD
{MLD6_TMR_INTERVAL, mld6_tmr, mld6_tmr_tick MLD6TMR_NAME},
#endif /* LWIP_IPV6_MLD */
#if LWIP_IPV6_DHCP6
{DHCP6_TIMER_MSECS, dhcp6_tmr, dhcp6_tmr_tick DHCP6TMR_NAME},
#endif /* LWIP_IPV6_DHCP6 */
#if LWIP_6LOWPAN
{LOWPAN6_TMR_INTERVAL, lowpan6_tmr, lowpan6_tmr_tick LOWPAN6TMR_NAME},
#endif /* LWIP_6LOWPAN */
#endif /* LWIP_IPV6 */
};
void
set_timer_state(enum timer_state state, u32_t waiting_time)
{
g_timer_mng.waiting_time = waiting_time;
g_timer_mng.state = state;
}
/* should not call by tcpip_thread */
u8_t
sys_timeout_waiting_long(void)
{
u8_t i = 0;
u8_t j = 0;
while (g_timer_mng.state == LOW_TMR_GETING_TICKS) {
i++;
if (i == SYS_TIMEOUT_WAIT_TICKS) {
i = 0;
j++;
if (j == SYS_TIMEOUT_WAIT_TIME_MS) {
break;
}
sys_msleep(1);
}
}
if (g_timer_mng.state == LOW_TMR_TIMER_WAITING) {
return ((g_timer_mng.waiting_time > TIMEOUT_TICK) ? 1 : 0);
}
return 0;
}
err_t
sys_timeout_reg(
u32_t msec,
sys_timeout_handler handler,
void *arg,
#if LOWPOWER_TIMER_DEBUG
char *name,
#endif
get_next_timeout next_tick)
{
struct timer_entry *timeout = NULL;
struct timer_entry *temp = NULL;
if (handler == NULL) {
return -1;
}
timeout = (struct timer_entry *)memp_malloc(MEMP_SYS_TIMEOUT);
if (timeout == NULL) {
LWIP_DEBUGF(LOWPOWER_DEBUG, ("sys_timeout_reg: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty"));
return -1;
}
timeout->handler = handler;
timeout->clock_max = msec / TIMEOUT_TICK; /* time interval */
timeout->next_tick = next_tick;
timeout->timeout = sys_now();
timeout->args = arg;
timeout->enable = 0;
#if LOWPOWER_TIMER_DEBUG
timeout->name = name;
#endif
/* add list tail */
timeout->next = NULL;
if (g_timer_header == NULL) {
g_timer_header = timeout;
} else {
temp = g_timer_header;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = timeout;
}
return 0;
}
/* deal timeout and return next timer prev */
static void
timeout_handler(struct timer_entry *t, u32_t now)
{
#if LOWPOWER_TIMER_DEBUG
if (t->name != NULL) {
LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s timeout: now:%u\n", t->name, now));
}
#endif
t->handler(t->args);
LWIP_UNUSED_ARG(now);
t->timeout += t->clock_max * TIMEOUT_TICK;
}
static u32_t
get_timer_tick(struct timer_entry *t)
{
u32_t tick;
/* disable lowpower, need to timeout once a tick */
if (g_lowpower_switch == LOW_TMR_NORMAL_MOD) {
return t->clock_max;
}
if (t->next_tick != NULL) {
tick = t->next_tick();
} else {
tick = 1;
LWIP_DEBUGF(LOWPOWER_DEBUG, ("next->tick is NULL\n"));
}
tick *= t->clock_max;
return tick;
}
static void
handle_timer_and_free(struct timer_entry **pt, struct timer_entry **pn, struct timer_entry *p)
{
struct timer_entry *t = *pt;
struct timer_entry *n = *pn;
/* insert after previous node or as the header */
if (p == NULL) {
g_timer_header = n;
} else {
p->next = n;
}
t->next = NULL;
sys_timeout_handler handler = t->handler;
void *args = t->args;
memp_free(MEMP_SYS_TIMEOUT, t);
*pt = NULL;
handler(args);
/* the last entry */
if ((n == NULL) && (p != NULL)) {
*pn = p->next;
}
}
static u32_t
get_sleep_time(u32_t now)
{
struct timer_entry *t = NULL;
struct timer_entry *n = NULL;
struct timer_entry *p = NULL;
u32_t msec = TIMEOUT_MAX;
u32_t tick;
u32_t temp;
LWIP_DEBUGF(LOWPOWER_DEBUG, ("\n*******get_sleep_time*****************\n"));
for (t = g_timer_header, p = NULL; t != NULL; t = n) {
n = t->next;
again:
tick = get_timer_tick(t);
if (tick == 0) {
t->enable = 0;
p = t;
continue;
}
if (t->enable == 0) {
t->timeout = now;
}
t->enable = 1;
temp = tick * TIMEOUT_TICK;
if (temp <= now - t->timeout) {
if (t->next_tick == NULL) {
handle_timer_and_free(&t, &n, p);
/* t is free p=p */
continue;
}
timeout_handler(t, now);
goto again;
}
temp = temp - (now - t->timeout);
msec = msec > temp ? temp : msec;
p = t;
}
LWIP_DEBUGF(LOWPOWER_DEBUG, ("msec = %u now = %u\n", msec, now));
return msec;
}
static void
check_timeout(u32_t now)
{
struct timer_entry *t = NULL;
struct timer_entry *n = NULL;
struct timer_entry *p = NULL;
u32_t msec;
u32_t ticks;
u32_t i;
LWIP_DEBUGF(LOWPOWER_DEBUG, ("\n**********timeout**************\n"));
LWIP_DEBUGF(LOWPOWER_DEBUG, ("now = %u\n", now));
for (t = g_timer_header, p = NULL; t != NULL; t = n) {
n = t->next;
if (t->enable == 0) {
p = t;
continue;
}
msec = now - t->timeout;
ticks = msec / TIMEOUT_TICK;
ticks = ticks / t->clock_max;
for (i = 0; i < ticks; i++) {
/* remove timer_entry form list */
if (t->next_tick == NULL) {
handle_timer_and_free(&t, &n, p);
break;
}
timeout_handler(t, now);
PBUF_CHECK_FREE_OOSEQ();
}
if (t != NULL) {
p = t;
}
}
}
void
tcpip_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)
{
u32_t sleeptime;
u32_t ret;
u32_t now;
again:
if (g_timer_header == NULL) {
UNLOCK_TCPIP_CORE();
(void)sys_arch_mbox_fetch(mbox, msg, 0);
LOCK_TCPIP_CORE();
return;
}
set_timer_state(LOW_TMR_GETING_TICKS, 0);
sleeptime = get_sleep_time(sys_now());
sleeptime = sleeptime > sys_timeout_get_wake_time() ? sys_timeout_get_wake_time() : sleeptime;
set_timer_state(LOW_TMR_TIMER_WAITING, sleeptime);
sys_timeout_set_wake_time(TIMEOUT_MAX);
UNLOCK_TCPIP_CORE();
ret = sys_arch_mbox_fetch(mbox, msg, sleeptime);
LOCK_TCPIP_CORE();
set_timer_state(LOW_TMR_TIMER_HANDLING, 0);
now = sys_now();
if ((now - g_last_check_timeout) >= TIMEOUT_CHECK) {
check_timeout(sys_now());
g_last_check_timeout = sys_now();
}
if (ret == SYS_ARCH_TIMEOUT) {
goto again;
}
}
void
lowpower_cycle_tmr(void *args)
{
struct timer_handler *handler = (struct timer_handler *)args;
handler->handler();
}
err_t
set_timer_interval(u8_t i, u32_t interval)
{
if (i >= LWIP_ARRAYSIZE(lowpower_timer_handler)) {
return -1;
}
return sys_timeout_reg(interval, lowpower_cycle_tmr,
(void *)(&lowpower_timer_handler[i]),
#if LOWPOWER_TIMER_DEBUG
lowpower_timer_handler[i].name,
#endif
lowpower_timer_handler[i].next_tick);
}
/* registed when init */
void
tcp_timer_needed(void)
{}
void
sys_timeouts_init(void)
{
u8_t i;
for (i = 0; i < LWIP_ARRAYSIZE(lowpower_timer_handler); i++) {
if (set_timer_interval(i, lowpower_timer_handler[i].interval) != 0) {
LWIP_DEBUGF(LOWPOWER_DEBUG, ("ERROR:regist timer faild! i = %u\n", i));
}
}
}
void
sys_untimeout(sys_timeout_handler handler, void *arg)
{
struct timer_entry *t = NULL;
struct timer_entry *p = NULL;
struct timer_entry *n = NULL;
for (t = g_timer_header, p = NULL; t != NULL; t = n) {
n = t->next;
if ((t->handler == handler) && (t->args == arg)) {
if (p == NULL) {
g_timer_header = t->next;
} else {
p->next = t->next;
}
t->next = NULL;
memp_free(MEMP_SYS_TIMEOUT, t);
t = NULL;
}
if (t != NULL) {
p = t;
}
}
}
void
sys_restart_timeouts(void)
{}
err_t
sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)
{
return sys_timeout_reg(msecs, handler, arg,
#if LOWPOWER_TIMER_DEBUG
NULL,
#endif
NULL);
}
void
sys_timeout_set_wake_time(u32_t val)
{
g_wake_up_time = val;
}
u32_t
sys_timeout_get_wake_time(void)
{
return g_wake_up_time;
}
void
set_lowpower_mod(enum lowpower_mod sw)
{
g_lowpower_switch = sw;
}
enum lowpower_mod
get_lowpowper_mod(void)
{
return g_lowpower_switch;
}
#endif /* LWIP_LOWPOWER */
......@@ -111,6 +111,9 @@
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/nd6.h"
#if LWIP_LOWPOWER
#include "lwip/priv/api_msg.h"
#endif
#include <string.h>
......@@ -254,6 +257,150 @@ tcp_tmr(void)
}
}
#if LWIP_LOWPOWER
#include "lwip/lowpower.h"
static u32_t
tcp_set_timer_tick_by_persist(struct tcp_pcb *pcb, u32_t tick)
{
u32_t val;
if (pcb->persist_backoff > 0) {
u8_t backoff_cnt = tcp_persist_backoff[pcb->persist_backoff - 1];
SET_TMR_TICK(tick, backoff_cnt);
return tick;
}
/* timer not running */
if (pcb->rtime >= 0) {
val = pcb->rto - pcb->rtime;
if (val == 0) {
val = 1;
}
SET_TMR_TICK(tick, val);
}
return tick;
}
static u32_t
tcp_set_timer_tick_by_keepalive(struct tcp_pcb *pcb, u32_t tick)
{
u32_t val;
if (ip_get_option(pcb, SOF_KEEPALIVE) &&
((pcb->state == ESTABLISHED) ||
(pcb->state == CLOSE_WAIT))) {
u32_t idle = (pcb->keep_idle) / TCP_SLOW_INTERVAL;
if (pcb->keep_cnt_sent == 0) {
val = idle - (tcp_ticks - pcb->tmr);
} else {
val = (tcp_ticks - pcb->tmr) - idle;
idle = (TCP_KEEP_INTVL(pcb) / TCP_SLOW_INTERVAL);
val = idle - (val % idle);
}
/* need add 1 to trig timer */
val++;
SET_TMR_TICK(tick, val);
}
return tick;
}
static u32_t tcp_set_timer_tick_by_tcp_state(struct tcp_pcb *pcb, u32_t tick)
{
u32_t val;
/* Check if this PCB has stayed too long in FIN-WAIT-2 */
if (pcb->state == FIN_WAIT_2) {
/* If this PCB is in FIN_WAIT_2 because of SHUT_WR don't let it time out. */
if (pcb->flags & TF_RXCLOSED) {
val = TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL;
SET_TMR_TICK(tick, val);
}
}
/* Check if this PCB has stayed too long in SYN-RCVD */
if (pcb->state == SYN_RCVD) {
val = TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL;
SET_TMR_TICK(tick, val);
}
/* Check if this PCB has stayed too long in LAST-ACK */
if (pcb->state == LAST_ACK) {
/*
* In a TCP connection the end that performs the active close
* is required to stay in TIME_WAIT state for 2MSL of time
*/
val = (2 * TCP_MSL) / TCP_SLOW_INTERVAL;
SET_TMR_TICK(tick, val);
}
return tick;
}
u32_t
tcp_slow_tmr_tick(void)
{
struct tcp_pcb *pcb = NULL;
u32_t tick = 0;
pcb = tcp_active_pcbs;
while (pcb != NULL) {
if (((pcb->state == SYN_SENT) && (pcb->nrtx >= TCP_SYNMAXRTX)) ||
((pcb->state == FIN_WAIT_1) || (pcb->state == CLOSING)) ||
(pcb->nrtx >= TCP_MAXRTX)) {
return 1;
}
tick = tcp_set_timer_tick_by_persist(pcb, tick);
tick = tcp_set_timer_tick_by_keepalive(pcb, tick);
/*
* If this PCB has queued out of sequence data, but has been
* inactive for too long, will drop the data (it will eventually
* be retransmitted).
*/
#if TCP_QUEUE_OOSEQ
if (pcb->ooseq != NULL) {
SET_TMR_TICK(tick, 1);
}
#endif /* TCP_QUEUE_OOSEQ */
tick = tcp_set_timer_tick_by_tcp_state(pcb, tick);
u8_t ret = poll_tcp_needed(pcb->callback_arg, pcb);
if ((pcb->poll != NULL) && (ret != 0)) {
SET_TMR_TICK(tick, 1);
}
pcb = pcb->next;
}
LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "tcp_slow_tmr_tick", tick));
return tick;
}
u32_t
tcp_fast_tmr_tick(void)
{
struct tcp_pcb *pcb = NULL;
pcb = tcp_active_pcbs;
while (pcb != NULL) {
/* send delayed ACKs or send pending FIN */
if ((pcb->flags & TF_ACK_DELAY) ||
(pcb->flags & TF_CLOSEPEND) ||
(pcb->refused_data != NULL)
) {
LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: 1\n", "tcp_fast_tmr_tick"));
return 1;
}
pcb = pcb->next;
}
LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: 0\n", "tcp_fast_tmr_tick"));
return 0;
}
#endif /* LWIP_LOWPOWER */
#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG
/** Called when a listen pcb is closed. Iterates one pcb list and removes the
* closed listener pcb from pcb->listener if matching.
......
......@@ -61,6 +61,8 @@
#include "lwip/sys.h"
#include "lwip/pbuf.h"
#if !LWIP_LOWPOWER
#if LWIP_DEBUG_TIMERNAMES
#define HANDLER(x) x, #x
#else /* LWIP_DEBUG_TIMERNAMES */
......@@ -449,3 +451,4 @@ tcp_timer_needed(void)
{
}
#endif /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */
#endif /* !LWIP_LOWPOWER */
......@@ -90,6 +90,10 @@ u8_t autoip_accept_packet(struct netif *netif, const ip4_addr_t *addr);
#define netif_autoip_data(netif) ((struct autoip*)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP))
#if LWIP_LOWPOWER
u32_t autoip_tmr_tick(void);
#endif
#ifdef __cplusplus
}
#endif
......
......@@ -160,6 +160,11 @@ void dhcp_coarse_tmr(void);
/* to be called every half second */
void dhcp_fine_tmr(void);
#if LWIP_LOWPOWER
u32_t dhcp_coarse_tmr_tick(void);
u32_t dhcp_fine_tmr_tick(void);
#endif
#if LWIP_DHCP_GET_NTP_SRV
/** This function must exist, in other to add offered NTP servers to
* the NTP (or SNTP) engine.
......
......@@ -95,6 +95,10 @@ extern void dhcp6_set_ntp_servers(u8_t num_ntp_servers, const ip_addr_t* ntp_ser
#define netif_dhcp6_data(netif) ((struct dhcp6*)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP6))
#if LWIP_LOWPOWER
u32_t dhcp6_tmr_tick();
#endif
#ifdef __cplusplus
}
#endif
......
......@@ -86,6 +86,10 @@ struct local_hostlist_entry {
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
#endif /* DNS_LOCAL_HOSTLIST */
#if LWIP_LOWPOWER
u32_t dns_tmr_tick(void);
#endif
#if LWIP_IPV4
extern const ip_addr_t dns_mquery_v4group;
#endif /* LWIP_IPV4 */
......
......@@ -93,6 +93,10 @@ err_t etharp_add_static_entry(const ip4_addr_t *ipaddr, struct eth_addr *ethaddr
err_t etharp_remove_static_entry(const ip4_addr_t *ipaddr);
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
#if LWIP_LOWPOWER
u32_t etharp_tmr_tick(void);
#endif /* LWIP_LOWPOWER */
void etharp_input(struct pbuf *p, struct netif *netif);
#ifdef __cplusplus
......
......@@ -99,6 +99,10 @@ err_t igmp_leavegroup(const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr);
err_t igmp_leavegroup_netif(struct netif *netif, const ip4_addr_t *groupaddr);
void igmp_tmr(void);
#if LWIP_LOWPOWER
u32_t igmp_tmr_tick(void);
#endif
/** @ingroup igmp
* Get list head of IGMP groups for netif.
* Note: The allsystems group IP is contained in the list as first entry.
......
......@@ -89,6 +89,11 @@ struct pbuf_custom_ref {
#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */
err_t ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest);
#if LWIP_LOWPOWER
u32_t ip_reass_tmr_tick(void);
#endif /* LWIP_LOWPOWER */
#endif /* IP_FRAG */
#ifdef __cplusplus
......
......@@ -115,6 +115,10 @@ struct ip6_reassdata {
void ip6_reass_tmr(void);
struct pbuf *ip6_reass(struct pbuf *p);
#if LWIP_LOWPOWER
u32_t ip6_reass_tmr_tick(void);
#endif
#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */
#if LWIP_IPV6 && LWIP_IPV6_FRAG /* don't build if not configured for use in lwipopts.h */
......
/*
* Copyright (c) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LWIP_HDR_LOWPOWER_H
#define LWIP_HDR_LOWPOWER_H
#include "lwip/opt.h"
#if LWIP_LOWPOWER
#include "lwip/err.h"
#if !NO_SYS
#include "lwip/sys.h"
#endif
#define LOWPOWER_TIMER_DEBUG 0
#define TIMEOUT_TICK 100 /* 100ms */
#define TIMEOUT_CHECK 30
#if LOWPOWER_TIMER_DEBUG
#define TCP_FASTTMR_NAME , "tcp_fasttmr"
#define TCP_SLOWTMR_NAME , "tcp_slowtmr"
#define IP_REASSTRM_NAME , "ip_reass_tmr"
#define ETHARPTMR_NAME , "etharp_tmr"
#define DHCP_COARSETMR_NAME , "dhcp_coarse_tmr"
#define DHCP_FINETMR_NAME , "dhcp_fine_tmr"
#define AUTOIPTMR_NAME , "autoip_tmr"
#define IGMPTMR_NAME , "igmp_tmr"
#define DNSTMR_NAME , "dns_tmr"
#define NAT64TMR_NAME , "nat64_tmr"
#define ND6TMR_NAME , "nd6_tmr"
#define IP6_TREASSTMR_NAME , "ip6_reass_tmr"
#define MLD6TMR_NAME , "mld6_tmr"
#define DHCP6TMR_NAME , "dhcp6_tmr"
#define LOWPAN6TMR_NAME , "lowpan6_tmr"
#else
#define TCP_FASTTMR_NAME
#define TCP_SLOWTMR_NAME
#define IP_REASSTRM_NAME
#define ETHARPTMR_NAME
#define DHCP_COARSETMR_NAME
#define DHCP_FINETMR_NAME
#define AUTOIPTMR_NAME
#define IGMPTMR_NAME
#define DNSTMR_NAME
#define NAT64TMR_NAME
#define ND6TMR_NAME
#define IP6_TREASSTMR_NAME
#define MLD6TMR_NAME
#define DHCP6TMR_NAME
#define LOWPAN6TMR_NAME
#endif
#define SET_TMR_TICK(tick, val) do { \
if ((val) > 0) { \
if ((tick) == 0) { \
(tick) = (val); \
} else { \
(tick) = (tick) > (val) ? (val) : (tick); \
} \
} \
} while (0)
typedef void (*lwip_timer_handler)(void);
typedef void (*sys_timeout_handler)(void *args);
/* get time count to trigger */
typedef u32_t (*get_next_timeout)(void);
struct timer_handler {
u32_t interval;
lwip_timer_handler handler;
get_next_timeout next_tick;
#if LOWPOWER_TIMER_DEBUG
char *name;
#endif
};
struct timer_entry {
u32_t clock_max; /* tmr interval */
u32_t timeout;
sys_timeout_handler handler;
void *args;
get_next_timeout next_tick;
struct timer_entry *next;
#if LOWPOWER_TIMER_DEBUG
char *name;
#endif
u8_t enable;
};
enum timer_state {
LOW_TMR_GETING_TICKS = 0,
LOW_TMR_TIMER_WAITING,
LOW_TMR_TIMER_HANDLING,
};
struct timer_mng {
enum timer_state state;
u32_t waiting_time;
};
enum lowpower_msg_type {
LOW_NON_BLOCK = 0,
LOW_BLOCK = 1,
LOW_FORCE_NON_BLOCK = 2,
};
enum lowpower_mod {
LOW_TMR_LOWPOWER_MOD = 0,
LOW_TMR_NORMAL_MOD = 1,
};
#define lowpower_sem_t sys_sem_t
#define LOWPOWER_SEM_WAIT(lock) sys_sem_wait(&(lock))
#define LOWPOWER_SIGNAL(lock) sys_sem_signal(&(lock))
#define LOWPOWER_SEM_NEW(lock, val) \
do { \
(val) = sys_sem_new(&(lock), 0); \
} while (0)
#define LOWPOWER_SEM_FREE(lock) sys_sem_free(&(lock))
/* all timer use the same timeout step */
#define STEP_TIMEOUT_TO_TICK(step, type) (((step) * lwip_cyclic_timers[(type)].interval_ms) / TIMEOUT_TICK)
#define STEP_TICK_TO_TIMEOUT(tick, type) (((tick) * TIMEOUT_TICK) / lwip_cyclic_timers[(type)].interval_ms)
#define LOW_TMR_DELAY 20
void sys_timeout_set_wake_time(u32_t val);
u32_t sys_timeout_get_wake_time(void);
void sys_untimeout(sys_timeout_handler handler, void *arg);
void sys_restart_timeouts(void);
void tcpip_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg);
void sys_timeouts_init(void);
err_t sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg);
u8_t sys_timeout_waiting_long(void);
void set_lowpower_mod(enum lowpower_mod sw);
enum lowpower_mod get_lowpowper_mod(void);
#endif /* LOWEPOWER */
#endif /* LWIP_HDR_LOWPOWER_H */
......@@ -82,6 +82,10 @@ err_t mld6_joingroup_netif(struct netif *netif, const ip6_addr_t *groupaddr);
err_t mld6_leavegroup(const ip6_addr_t *srcaddr, const ip6_addr_t *groupaddr);
err_t mld6_leavegroup_netif(struct netif *netif, const ip6_addr_t *groupaddr);
#if LWIP_LOWPOWER
u32_t mld6_tmr_tick(void);
#endif
/** @ingroup mld6
* Get list head of MLD6 groups for netif.
* Note: The allnodes group IP is NOT in the list, since it must always
......
......@@ -81,6 +81,10 @@ void nd6_adjust_mld_membership(struct netif *netif, s8_t addr_idx, u8_t new_stat
#endif /* LWIP_IPV6_MLD */
void nd6_restart_netif(struct netif *netif);
#ifdef LWIP_LOWPOWER
u32_t nd6_tmr_tick(void);
#endif
#ifdef __cplusplus
}
#endif
......
......@@ -156,6 +156,11 @@ err_t netifapi_netif_index_to_name(u8_t index, char *name);
*/
#define netifapi_autoip_stop(n) netifapi_netif_common(n, NULL, autoip_stop)
#if LWIP_LOWPOWER
err_t netifapi_enable_lowpower(void);
err_t netifapi_disable_lowpower(void);
#endif
#ifdef __cplusplus
}
#endif
......
......@@ -3523,4 +3523,38 @@
* @}
*/
/**
* enable LWIP_LOWPOWER macro to use lowpower function
*/
#undef LWIP_LOWPOWER
#if LWIP_TIMERS && !LWIP_TIMERS_CUSTOM
#if defined (CONFIG_LWIP_LOWPOWER)
#define LWIP_LOWPOWER 1
#else
#define LWIP_LOWPOWER 0
#endif
#else
#define LWIP_LOWPOWER 0
#endif
#if LWIP_LOWPOWER
/**
* LOWPOWER_DEBUG: Enable debugging in lowpower.c.
*/
#if !defined LOWPOWER_DEBUG || defined __DOXYGEN__
#define LOWPOWER_DEBUG LWIP_DBG_OFF
#endif
#ifndef MEMP_NUM_TCPIP_MSG_LOWPOWER
#define MEMP_NUM_TCPIP_MSG_LOWPOWER 10
#endif
#define LWIP_SNTP_TIMER 2
#define LOWPOWER_TCP_TIMER 1
#define MEMP_NUM_SYS_TIMEOUT_LOW (MEMP_NUM_SYS_TIMEOUT + LWIP_SNTP_TIMER + LOWPOWER_TCP_TIMER)
#endif /* LWIP_LOWPOWER */
#endif /* LWIP_HDR_OPT_H */
......@@ -187,6 +187,11 @@ struct dns_api_msg {
};
#endif /* LWIP_DNS */
#if LWIP_LOWPOWER
/* check wether need to poll tcp */
u8_t poll_tcp_needed(void *arg, struct tcp_pcb *pcb);
#endif
#if LWIP_NETCONN_FULLDUPLEX
int lwip_netconn_is_deallocated_msg(void *msg);
#endif
......@@ -260,6 +265,11 @@ struct netifapi_msg {
#endif /* LWIP_MPU_COMPATIBLE */
u8_t index;
} ifs;
#if LWIP_LOWPOWER
struct {
enum lowpower_mod mod;
} lp;
#endif
} msg;
};
......
......@@ -99,7 +99,12 @@ LWIP_MEMPOOL(IGMP_GROUP, MEMP_NUM_IGMP_GROUP, sizeof(struct igmp_group)
#endif /* LWIP_IGMP */
#if LWIP_TIMERS && !LWIP_TIMERS_CUSTOM
#if LWIP_LOWPOWER
LWIP_MEMPOOL(SYS_TIMEOUT, MEMP_NUM_SYS_TIMEOUT_LOW, sizeof(struct timer_entry), "SYS_TIMEOUT")
LWIP_MEMPOOL(TCPIP_MSG_LOWPOWER, MEMP_NUM_TCPIP_MSG_LOWPOWER, sizeof(struct tcpip_msg), "TCPIP_MSG_NA")
#else
LWIP_MEMPOOL(SYS_TIMEOUT, MEMP_NUM_SYS_TIMEOUT, sizeof(struct sys_timeo), "SYS_TIMEOUT")
#endif /* LWIP_LOWPOWER */
#endif /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */
#if LWIP_DNS && LWIP_SOCKET
......
......@@ -123,7 +123,10 @@ enum tcpip_msg_type {
TCPIP_MSG_UNTIMEOUT,
#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */
TCPIP_MSG_CALLBACK,
TCPIP_MSG_CALLBACK_STATIC
TCPIP_MSG_CALLBACK_STATIC,
#if LWIP_LOWPOWER
TCPIP_MSG_NA,
#endif
};
struct tcpip_msg {
......@@ -158,6 +161,12 @@ struct tcpip_msg {
void *arg;
} tmo;
#endif /* LWIP_TCPIP_TIMEOUT && LWIP_TIMERS */
#if LWIP_LOWPOWER
struct {
enum lowpower_msg_type type;
lowpower_sem_t wait_up;
} lowpower;
#endif
} msg;
};
......
......@@ -424,6 +424,11 @@ void tcp_accept (struct tcp_pcb *pcb, tcp_accept_fn accept);
#endif /* LWIP_CALLBACK_API */
void tcp_poll (struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval);
#if LWIP_LOWPOWER
u32_t tcp_fast_tmr_tick(void);
u32_t tcp_slow_tmr_tick(void);
#endif
#define tcp_set_flags(pcb, set_flags) do { (pcb)->flags = (tcpflags_t)((pcb)->flags | (set_flags)); } while(0)
#define tcp_clear_flags(pcb, clr_flags) do { (pcb)->flags = (tcpflags_t)((pcb)->flags & (tcpflags_t)(~(clr_flags) & TCP_ALLFLAGS)); } while(0)
#define tcp_is_flag_set(pcb, flag) (((pcb)->flags & (flag)) != 0)
......
......@@ -104,6 +104,10 @@ err_t tcpip_untimeout(sys_timeout_handler h, void *arg);
int tcpip_thread_poll_one(void);
#endif
#if LWIP_LOWPOWER
void tcpip_send_msg_na(enum lowpower_msg_type type);
#endif
#ifdef __cplusplus
}
#endif
......
......@@ -43,11 +43,15 @@
#if !NO_SYS
#include "lwip/sys.h"
#endif
#if LWIP_LOWPOWER
#include "lwip/lowpower.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if !LWIP_LOWPOWER
#ifndef LWIP_DEBUG_TIMERNAMES
#ifdef LWIP_DEBUG
#define LWIP_DEBUG_TIMERNAMES SYS_DEBUG
......@@ -120,7 +124,7 @@ void lwip_cyclic_timer(void *arg);
#endif
#endif /* LWIP_TIMERS */
#endif /* !LWIP_LOWPOWER */
#ifdef __cplusplus
}
#endif
......
......@@ -60,6 +60,9 @@ extern "C" {
#define LOWPAN6_TMR_INTERVAL 1000
void lowpan6_tmr(void);
#if LWIP_LOWPOWER
u32_t lowpan6_tmr_tick(void);
#endif
err_t lowpan6_set_context(u8_t idx, const ip6_addr_t * context);
err_t lowpan6_set_short_addr(u8_t addr_high, u8_t addr_low);
......
......@@ -63,6 +63,9 @@
#include "lwip/snmp.h"
#include "netif/ieee802154.h"
#if LWIP_LOWPOWER
#include "lwip/lowpower.h"
#endif
#include <string.h>
#if LWIP_6LOWPAN_802154_HW_CRC
......@@ -118,6 +121,28 @@ static const struct lowpan6_link_addr ieee_802154_broadcast = {2, {0xff, 0xff}};
static struct lowpan6_link_addr short_mac_addr = {2, {0, 0}};
#endif /* LWIP_6LOWPAN_INFER_SHORT_ADDRESS */
#if LWIP_LOWPOWER
u32_t
lowpan6_tmr_tick()
{
struct lowpan6_reass_helper *lrh = NULL;
struct lowpan6_reass_helper *lrh_temp = NULL;
u32_t tick = 0;
lrh = lowpan6_data.reass_list;
while (lrh != NULL) {
lrh_temp = lrh->next_packet;
if (lrh->timer > 0) {
SET_TMR_TICK(tick, lrh->timer);
}
lrh = lrh_temp;
}
LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "lowpan6_tmr_tick", tick));
return tick;
}
#endif /* LWIP_LOWPOWER */
/* IEEE 802.15.4 specific functions: */
/** Write the IEEE 802.15.4 header that encapsulates the 6LoWPAN frame.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册