/* * Copyright (c) 2019 Actions Semiconductor Co., Ltd * * SPDX-License-Identifier: Apache-2.0 */ /** * @file led manager interface */ #include #include #include #include #include #include #define SYS_LOG_NO_NEWLINE #ifdef SYS_LOG_DOMAIN #undef SYS_LOG_DOMAIN #endif #define SYS_LOG_DOMAIN "seg_led_manager" #include struct seg_led_image { sys_snode_t snode; uint8_t num[4]; uint8_t icon; uint8_t flash_state:1; uint8_t num_state:4; uint8_t flash_cnt; uint8_t flash_period; uint8_t current_period; uint16_t flash_map; seg_led_flash_callback cb; }; struct seg_led_manager_ctx_t { struct device *dev; struct seg_led_image image; uint8_t timeout; uint8_t update_direct:1; uint8_t timeout_event_lock:1; seg_led_timeout_callback timeout_cb; sys_slist_t image_list; }; static struct seg_led_manager_ctx_t global_seg_led_manager_ctx; OS_MUTEX_DEFINE(seg_led_manager_mutex); static struct seg_led_manager_ctx_t *_seg_led_get_ctx(void) { return &global_seg_led_manager_ctx; } static int _seg_led_display_update(void) { int i = 0; struct seg_led_manager_ctx_t *ctx = _seg_led_get_ctx(); if (ctx->timeout_event_lock || ctx->update_direct) { return 0; } for (i = 0 ; i < 8; i++) { bool display = (((1 << i) & ctx->image.icon) != 0); if ((ctx->image.flash_map & (1 << i))) { display = ctx->image.flash_state; } segled_display_icon(ctx->dev, i, display); } for (i = 0 ; i < 4; i++) { bool display = (((1 << i) & ctx->image.num_state) != 0); if ((ctx->image.flash_map & (1 << (i + 8)))) { display = ctx->image.flash_state; } segled_display_number(ctx->dev, i, ctx->image.num[i], display); } return 0; } int seg_led_display_number(uint8_t num_addr, uint8_t c, bool display) { int ret = 0; struct seg_led_manager_ctx_t *ctx = _seg_led_get_ctx(); os_mutex_lock(&seg_led_manager_mutex, OS_FOREVER); num_addr -= SLED_NUMBER1; if (!ctx->update_direct) { ctx->image.num[num_addr] = c; if (display) { ctx->image.num_state |= (1 << num_addr); } else { ctx->image.num_state &= (~(1 << num_addr)); } } if (!ctx->timeout_event_lock || ctx->update_direct) { ret = segled_display_number(ctx->dev, num_addr, c, display); } os_mutex_unlock(&seg_led_manager_mutex); return ret; } int seg_led_display_string(uint8_t start_pos, const uint8_t *str, bool display) { int ret = 0; struct seg_led_manager_ctx_t *ctx = _seg_led_get_ctx(); int len = strlen(str); os_mutex_lock(&seg_led_manager_mutex, OS_FOREVER); start_pos -= SLED_NUMBER1; if (len + start_pos > sizeof(ctx->image.num)) { len = sizeof(ctx->image.num) - start_pos; } if (!ctx->update_direct) { for (int i = start_pos; i < (len + start_pos); i++) { if (display) { ctx->image.num_state |= (1 << i); } else { ctx->image.num_state &= (~(1 << i)); } } memcpy(&ctx->image.num[start_pos], str, len); } if (!ctx->timeout_event_lock || ctx->update_direct) { ret = segled_display_number_string(ctx->dev, start_pos, str, display); } os_mutex_unlock(&seg_led_manager_mutex); return ret; } int seg_led_display_icon(uint8_t icon_idx, bool display) { int ret = 0; struct seg_led_manager_ctx_t *ctx = _seg_led_get_ctx(); os_mutex_lock(&seg_led_manager_mutex, OS_FOREVER); if (!ctx->update_direct) { if (display) { ctx->image.icon |= (1 << icon_idx); } else { ctx->image.icon &= (~(1 << icon_idx)); } ctx->image.flash_map &= ~(1 << icon_idx); if (!ctx->image.flash_map) { ctx->image.flash_state = 0; } } if (!ctx->timeout_event_lock || ctx->update_direct) { ret = segled_display_icon(ctx->dev, icon_idx, display); } os_mutex_unlock(&seg_led_manager_mutex); return ret; } int seg_led_display_set_flash(uint16_t flash_map, uint16_t flash_period, uint16_t flash_cnt, seg_led_flash_callback cb) { struct seg_led_manager_ctx_t *ctx = _seg_led_get_ctx(); os_mutex_lock(&seg_led_manager_mutex, OS_FOREVER); ctx->image.flash_map = flash_map; ctx->image.flash_period = flash_period / CONFIG_MONITOR_PERIOD / 2; if (flash_cnt < FLASH_FOREVER / 2) { ctx->image.flash_cnt = flash_cnt * 2; } else { ctx->image.flash_cnt = FLASH_FOREVER; } ctx->image.flash_state = 1; ctx->image.current_period = ctx->image.flash_period; ctx->image.cb = cb; _seg_led_display_update(); os_mutex_unlock(&seg_led_manager_mutex); return 0; } int seg_led_manager_clear_screen(uint8_t clr_mode) { int ret = 0; struct seg_led_manager_ctx_t *ctx = _seg_led_get_ctx(); os_mutex_lock(&seg_led_manager_mutex, OS_FOREVER); if (!ctx->update_direct && clr_mode == LED_CLEAR_ALL) { memset(&ctx->image, 0, sizeof(struct seg_led_image)); } if (!ctx->timeout_event_lock || ctx->update_direct) { ret = segled_clear_screen(ctx->dev, clr_mode); } os_mutex_unlock(&seg_led_manager_mutex); return ret; } int seg_led_manager_sleep(void) { int ret = 0; struct seg_led_manager_ctx_t *ctx = _seg_led_get_ctx(); seg_led_manager_store(); os_mutex_lock(&seg_led_manager_mutex, OS_FOREVER); ret = segled_sleep(ctx->dev); os_mutex_unlock(&seg_led_manager_mutex); return ret; } int seg_led_manager_wake_up(void) { int ret = 0; struct seg_led_manager_ctx_t *ctx = _seg_led_get_ctx(); os_mutex_lock(&seg_led_manager_mutex, OS_FOREVER); ret = segled_wakeup(ctx->dev); os_mutex_unlock(&seg_led_manager_mutex); seg_led_manager_restore(); return ret; } int seg_led_manager_store(void) { struct seg_led_manager_ctx_t *ctx = _seg_led_get_ctx(); struct seg_led_image *image_history = mem_malloc(sizeof(struct seg_led_image)); if (!image_history) return -ENOMEM; os_mutex_lock(&seg_led_manager_mutex, OS_FOREVER); memcpy(image_history, &ctx->image, sizeof(struct seg_led_image)); sys_slist_append(&ctx->image_list, (sys_snode_t *)image_history); os_mutex_unlock(&seg_led_manager_mutex); return 0; } int seg_led_manager_restore(void) { struct seg_led_manager_ctx_t *ctx = _seg_led_get_ctx(); struct seg_led_image *image_history = (struct seg_led_image *)sys_slist_peek_tail(&ctx->image_list); os_mutex_lock(&seg_led_manager_mutex, OS_FOREVER); if (image_history) { memcpy(&ctx->image, image_history, sizeof(struct seg_led_image)); sys_slist_find_and_remove(&ctx->image_list, (sys_snode_t *)image_history); mem_free(image_history); } else { SYS_LOG_ERR("no history"); return -ENODEV; } _seg_led_display_update(); os_mutex_unlock(&seg_led_manager_mutex); return 0; } int seg_led_manager_set_timeout_restore(int timeout) { struct seg_led_manager_ctx_t *ctx = _seg_led_get_ctx(); os_mutex_lock(&seg_led_manager_mutex, OS_FOREVER); if (ctx->timeout == FLASH_FOREVER) { os_mutex_unlock(&seg_led_manager_mutex); seg_led_manager_store(); os_mutex_lock(&seg_led_manager_mutex, OS_FOREVER); } ctx->timeout = timeout / CONFIG_MONITOR_PERIOD; ctx->timeout_cb = seg_led_manager_restore; os_mutex_unlock(&seg_led_manager_mutex); return 0; } int seg_led_manager_set_timeout_event_start(void) { struct seg_led_manager_ctx_t *ctx = _seg_led_get_ctx(); os_mutex_lock(&seg_led_manager_mutex, OS_FOREVER); ctx->update_direct = 1; ctx->timeout_event_lock = 1; os_mutex_unlock(&seg_led_manager_mutex); return 0; } int seg_led_manager_set_timeout_event(int timeout, seg_led_flash_callback cb) { struct seg_led_manager_ctx_t *ctx = _seg_led_get_ctx(); os_mutex_lock(&seg_led_manager_mutex, OS_FOREVER); ctx->timeout_cb = cb; ctx->timeout = timeout / CONFIG_MONITOR_PERIOD; ctx->update_direct = 0; os_mutex_unlock(&seg_led_manager_mutex); return 0; } static int _seg_led_manager_work_handle(void) { struct seg_led_manager_ctx_t *ctx = _seg_led_get_ctx(); os_mutex_lock(&seg_led_manager_mutex, OS_FOREVER); if (ctx->timeout != FLASH_FOREVER) { if (ctx->timeout-- == 0) { ctx->timeout = FLASH_FOREVER; ctx->update_direct = 0; ctx->timeout_event_lock = 0; _seg_led_display_update(); os_mutex_unlock(&seg_led_manager_mutex); if (ctx->timeout_cb) { ctx->timeout_cb(); ctx->timeout_cb = NULL; } return 0; } } ctx->image.current_period--; if (ctx->image.flash_map != 0 && !ctx->image.current_period) { ctx->image.current_period = ctx->image.flash_period; if (ctx->image.flash_state) { ctx->image.flash_state = 0; } else { ctx->image.flash_state = 1; } _seg_led_display_update(); if (ctx->image.flash_cnt != FLASH_FOREVER) { ctx->image.flash_cnt--; if (ctx->image.flash_cnt == 0) { ctx->image.flash_map = 0; if (ctx->image.cb) { os_mutex_unlock(&seg_led_manager_mutex); ctx->image.cb(); os_mutex_lock(&seg_led_manager_mutex, OS_FOREVER); } } } } os_mutex_unlock(&seg_led_manager_mutex); return 0; } int seg_led_manager_init(void) { memset(&global_seg_led_manager_ctx, 0, sizeof(struct seg_led_manager_ctx_t)); global_seg_led_manager_ctx.dev = device_get_binding(CONFIG_SEG_LED_DEVICE_NAME); if (!global_seg_led_manager_ctx.dev) return -ENODEV; if (sys_monitor_add_work(_seg_led_manager_work_handle)) { SYS_LOG_ERR("add work failed\n"); return -EFAULT; } sys_slist_init(&global_seg_led_manager_ctx.image_list); global_seg_led_manager_ctx.timeout = FLASH_FOREVER; return 0; } int seg_led_manager_deinit(void) { return 0; }