diff --git a/applications/plugins/blackjack/blackjack.c b/applications/plugins/blackjack/blackjack.c index b6d2d0360..95907728b 100644 --- a/applications/plugins/blackjack/blackjack.c +++ b/applications/plugins/blackjack/blackjack.c @@ -6,76 +6,82 @@ #include #include "util.h" #include "defines.h" -#include "card.h" +#include "common/card.h" +#include "common/dml.h" +#include "common/queue.h" #include "util.h" #include "ui.h" -#include "BlackJack_icons.h" +#include "blackjack_icons.h" #define DEALER_MAX 17 -void start_round(GameState* game_state); +void start_round(GameState *game_state); -void init(GameState* game_state); +void init(GameState *game_state); + +static void draw_ui(Canvas *const canvas, const GameState *game_state) { -static void draw_ui(Canvas* const canvas, const GameState* game_state) { draw_money(canvas, game_state->player_score); - draw_score(canvas, true, handCount(game_state->player_cards, game_state->player_card_count)); + draw_score(canvas, true, hand_count(game_state->player_cards, game_state->player_card_count)); - if(!game_state->animating && game_state->state == GameStatePlay) { - draw_play_menu(canvas, game_state); + if (!game_state->queue_state.running && game_state->state == GameStatePlay) { + render_menu(game_state->menu,canvas, 2, 47); } } -static void render_callback(Canvas* const canvas, void* ctx) { - const GameState* game_state = acquire_mutex((ValueMutex*)ctx, 25); +static void render_callback(Canvas *const canvas, void *ctx) { + const GameState *game_state = acquire_mutex((ValueMutex *) ctx, 25); - if(game_state == NULL) { + if (game_state == NULL) { return; } canvas_set_color(canvas, ColorBlack); canvas_draw_frame(canvas, 0, 0, 128, 64); - if(game_state->state == GameStateStart) { + if (game_state->state == GameStateStart) { canvas_draw_icon(canvas, 0, 0, &I_blackjack); } - if(game_state->state == GameStateGameOver) { + if (game_state->state == GameStateGameOver) { canvas_draw_icon(canvas, 0, 0, &I_endscreen); } - if(game_state->state == GameStatePlay || game_state->state == GameStateDealer) { - if(game_state->state == GameStatePlay) + if (game_state->state == GameStatePlay || game_state->state == GameStateDealer) { + if (game_state->state == GameStatePlay) draw_player_scene(canvas, game_state); else draw_dealer_scene(canvas, game_state); - animateQueue(game_state, canvas); + render_queue(&(game_state->queue_state), game_state, canvas); draw_ui(canvas, game_state); - } else if(game_state->state == GameStateSettings) { + } else if (game_state->state == GameStateSettings) { settings_page(canvas, game_state); } - release_mutex((ValueMutex*)ctx, game_state); + release_mutex((ValueMutex *) ctx, game_state); } //region card draw -Card draw_card(GameState* game_state) { +Card draw_card(GameState *game_state) { Card c = game_state->deck.cards[game_state->deck.index]; game_state->deck.index++; return c; } -void drawPlayerCard(GameState* game_state) { + +void drawPlayerCard(void *ctx) { + GameState *game_state = ctx; Card c = draw_card(game_state); game_state->player_cards[game_state->player_card_count] = c; game_state->player_card_count++; - if(game_state->selectedMenu == 0 && - (game_state->player_score < game_state->settings.round_price || game_state->doubled)) - game_state->selectedMenu = 1; + if(game_state->player_score < game_state->settings.round_price || game_state->doubled){ + set_menu_state(game_state->menu, 0, false); + } } -void drawDealerCard(GameState* game_state) { +void drawDealerCard(void *ctx) { + GameState *game_state = ctx; Card c = draw_card(game_state); game_state->dealer_cards[game_state->dealer_card_count] = c; game_state->dealer_card_count++; @@ -83,404 +89,319 @@ void drawDealerCard(GameState* game_state) { //endregion //region queue callbacks -void to_lose_state( - const GameState* game_state, - Canvas* const canvas, - uint32_t duration, - uint32_t margin) { - UNUSED(game_state); - UNUSED(margin); - if(duration == 0) return; +void to_lose_state(const void *ctx, Canvas *const canvas) { + const GameState *game_state = ctx; + if (game_state->settings.message_duration == 0) + return; popup_frame(canvas); elements_multiline_text_aligned(canvas, 64, 22, AlignCenter, AlignCenter, "You lost"); } -void to_bust_state( - const GameState* game_state, - Canvas* const canvas, - uint32_t duration, - uint32_t margin) { - UNUSED(game_state); - UNUSED(margin); - if(duration == 0) return; +void to_bust_state(const void *ctx, Canvas *const canvas) { + const GameState *game_state = ctx; + if (game_state->settings.message_duration == 0) + return; popup_frame(canvas); elements_multiline_text_aligned(canvas, 64, 22, AlignCenter, AlignCenter, "Busted!"); } -void to_draw_state( - const GameState* game_state, - Canvas* const canvas, - uint32_t duration, - uint32_t margin) { - UNUSED(game_state); - UNUSED(margin); - - if(duration == 0) return; +void to_draw_state(const void *ctx, Canvas *const canvas) { + const GameState *game_state = ctx; + if (game_state->settings.message_duration == 0) + return; popup_frame(canvas); elements_multiline_text_aligned(canvas, 64, 22, AlignCenter, AlignCenter, "Draw"); } -void to_dealer_turn( - const GameState* game_state, - Canvas* const canvas, - uint32_t duration, - uint32_t margin) { - UNUSED(game_state); - UNUSED(margin); - - if(duration == 0) return; +void to_dealer_turn(const void *ctx, Canvas *const canvas) { + const GameState *game_state = ctx; + if (game_state->settings.message_duration == 0) + return; popup_frame(canvas); elements_multiline_text_aligned(canvas, 64, 22, AlignCenter, AlignCenter, "Dealers turn"); } -void to_win_state( - const GameState* game_state, - Canvas* const canvas, - uint32_t duration, - uint32_t margin) { - UNUSED(game_state); - UNUSED(margin); - - if(duration == 0) return; +void to_win_state(const void *ctx, Canvas *const canvas) { + const GameState *game_state = ctx; + if (game_state->settings.message_duration == 0) + return; popup_frame(canvas); elements_multiline_text_aligned(canvas, 64, 22, AlignCenter, AlignCenter, "You win"); } -void to_start( - const GameState* game_state, - Canvas* const canvas, - uint32_t duration, - uint32_t margin) { - UNUSED(game_state); - UNUSED(margin); - if(duration == 0) return; +void to_start(const void *ctx, Canvas *const canvas) { + const GameState *game_state = ctx; + if (game_state->settings.message_duration == 0) + return; popup_frame(canvas); elements_multiline_text_aligned(canvas, 64, 22, AlignCenter, AlignCenter, "Round started"); } -void before_start(GameState* gameState) { - gameState->dealer_card_count = 0; - gameState->player_card_count = 0; +void before_start(void *ctx) { + GameState *game_state = ctx; + game_state->dealer_card_count = 0; + game_state->player_card_count = 0; } -void start(GameState* game_state) { + +void start(void *ctx) { + GameState *game_state = ctx; start_round(game_state); } -void draw(GameState* game_state) { +void draw(void *ctx) { + GameState *game_state = ctx; game_state->player_score += game_state->bet; game_state->bet = 0; - queue(game_state, start, before_start, to_start, game_state->settings.message_duration, 0); + enqueue(&(game_state->queue_state), game_state, start, before_start, to_start, + game_state->settings.message_duration); } -void game_over(GameState* game_state) { +void game_over(void *ctx) { + GameState *game_state = ctx; game_state->state = GameStateGameOver; } -void lose(GameState* game_state) { +void lose(void *ctx) { + GameState *game_state = ctx; game_state->state = GameStatePlay; game_state->bet = 0; - if(game_state->player_score >= game_state->settings.round_price) - queue(game_state, start, before_start, to_start, game_state->settings.message_duration, 0); - else - queue(game_state, game_over, NULL, NULL, 0, 0); + if (game_state->player_score >= game_state->settings.round_price) { + enqueue(&(game_state->queue_state), game_state, start, before_start, to_start, + game_state->settings.message_duration); + } else { + enqueue(&(game_state->queue_state), game_state, game_over, NULL, NULL, + 0); + } } -void win(GameState* game_state) { +void win(void *ctx) { + GameState *game_state = ctx; game_state->state = GameStatePlay; game_state->player_score += game_state->bet * 2; game_state->bet = 0; - queue(game_state, start, before_start, to_start, game_state->settings.message_duration, 0); + enqueue(&(game_state->queue_state), game_state, start, before_start, to_start, + game_state->settings.message_duration); } -void dealerTurn(GameState* game_state) { + +void dealerTurn(void *ctx) { + GameState *game_state = ctx; game_state->state = GameStateDealer; } -void dealer_card_animation( - const GameState* game_state, - Canvas* const canvas, - uint32_t duration, - uint32_t margin) { - float t = (float)(furi_get_tick() - game_state->animationStart) / (duration - margin); +float animationTime(const GameState *game_state){ + return (float) (furi_get_tick() - game_state->queue_state.start) / + (float) (game_state->settings.animation_duration); +} + +void dealer_card_animation(const void *ctx, Canvas *const canvas) { + const GameState *game_state = ctx; + float t = animationTime(game_state); Card animatingCard = game_state->deck.cards[game_state->deck.index]; - if(game_state->dealer_card_count > 1) { + if (game_state->dealer_card_count > 1) { Vector end = card_pos_at_index(game_state->dealer_card_count); - if(!is_at_edge(game_state->dealer_card_count)) end.x -= CARD_HALF_WIDTH; - draw_card_animation(animatingCard, (Vector){0, 64}, (Vector){0, 32}, end, t, true, canvas); + draw_card_animation(animatingCard, + (Vector) {0, 64}, + (Vector) {0, 32}, + end, + t, + true, + canvas); } else { - draw_card_animation( - animatingCard, - (Vector){32, -CARD_HEIGHT}, - (Vector){64, 32}, - (Vector){2, 2}, - t, - false, - canvas); - // drawPlayerDeck(game_state->dealer_cards, game_state->dealer_card_count, canvas); + draw_card_animation(animatingCard, + (Vector) {32, -CARD_HEIGHT}, + (Vector) {64, 32}, + (Vector) {2, 2}, + t, + false, + canvas); +// draw_deck(game_state->dealer_cards, game_state->dealer_card_count, canvas); } } -void dealer_back_card_animation( - const GameState* game_state, - Canvas* const canvas, - uint32_t duration, - uint32_t margin) { - float t = (float)(furi_get_tick() - game_state->animationStart) / (duration - margin); - Vector currentPos = - quadratic_2d((Vector){32, -CARD_HEIGHT}, (Vector){64, 32}, (Vector){13, 5}, t); - drawCardBackAt(currentPos.x, currentPos.y, canvas); +void dealer_back_card_animation(const void *ctx, Canvas *const canvas) { + const GameState *game_state = ctx; + float t = animationTime(game_state); + + Vector currentPos = quadratic_2d((Vector) {32, -CARD_HEIGHT}, (Vector) {64, 32}, (Vector) {13, 5}, t); + draw_card_back_at(currentPos.x, currentPos.y, canvas); } -void player_card_animation( - const GameState* game_state, - Canvas* const canvas, - uint32_t duration, - uint32_t margin) { - float t = (float)(furi_get_tick() - game_state->animationStart) / (duration - margin); +void player_card_animation(const void *ctx, Canvas *const canvas) { + const GameState *game_state = ctx; + float t = animationTime(game_state); + Card animatingCard = game_state->deck.cards[game_state->deck.index]; Vector end = card_pos_at_index(game_state->player_card_count); - if(!is_at_edge(game_state->player_card_count)) end.x -= CARD_HALF_WIDTH; - draw_card_animation( - animatingCard, (Vector){32, -CARD_HEIGHT}, (Vector){0, 32}, end, t, true, canvas); - // drawPlayerDeck(game_state->dealer_cards, game_state->player_card_count, canvas); + + draw_card_animation(animatingCard, + (Vector) {32, -CARD_HEIGHT}, + (Vector) {0, 32}, + end, + t, + true, + canvas); +// draw_deck(game_state->dealer_cards, game_state->player_card_count, canvas); } //endregion -void player_tick(GameState* game_state) { - uint8_t score = handCount(game_state->player_cards, game_state->player_card_count); - if((game_state->doubled && score <= 21) || score == 21) { - queue(game_state, dealerTurn, NULL, NULL, game_state->settings.message_duration, 0); - } else if(score > 21) { - queue(game_state, lose, NULL, to_bust_state, game_state->settings.message_duration, 0); +void player_tick(GameState *game_state) { + uint8_t score = hand_count(game_state->player_cards, game_state->player_card_count); + if ((game_state->doubled && score <= 21) || score == 21) { + enqueue(&(game_state->queue_state), game_state, dealerTurn, NULL, to_dealer_turn, + game_state->settings.message_duration); + } else if (score > 21) { + enqueue(&(game_state->queue_state), game_state, lose, NULL, to_bust_state, + game_state->settings.message_duration); } else { - if(game_state->selectDirection == DirectionUp && game_state->selectedMenu > 0 && - game_state->player_score >= game_state->settings.round_price && !game_state->doubled) { - game_state->selectedMenu--; + if(game_state->selectDirection == DirectionUp || game_state->selectDirection == DirectionDown){ + move_menu(game_state->menu, game_state->selectDirection == DirectionUp ? -1 : 1); } - if(game_state->selectDirection == DirectionDown && game_state->selectedMenu < 2) { - game_state->selectedMenu++; - } - if(game_state->selectDirection == Select) { - //double - if(!game_state->doubled && game_state->selectedMenu == 0 && - game_state->player_score >= game_state->settings.round_price) { - game_state->player_score -= game_state->settings.round_price; - game_state->bet += game_state->settings.round_price; - game_state->doubled = true; - game_state->selectedMenu = 1; - queue( - game_state, - drawPlayerCard, - NULL, - player_card_animation, - game_state->settings.animation_duration, - game_state->settings.animation_margin); - game_state->player_cards[game_state->player_card_count] = - game_state->deck.cards[game_state->deck.index]; - score = handCount(game_state->player_cards, game_state->player_card_count + 1); - if(score > 21) - queue( - game_state, - lose, - NULL, - to_bust_state, - game_state->settings.message_duration, - 0); - else - queue( - game_state, - dealerTurn, - NULL, - to_dealer_turn, - game_state->settings.message_duration, - 0); - } //hit - else if(game_state->selectedMenu == 1) { - queue( - game_state, - drawPlayerCard, - NULL, - player_card_animation, - game_state->settings.animation_duration, - game_state->settings.animation_margin); - } //stay - else if(game_state->selectedMenu == 2) { - queue( - game_state, - dealerTurn, - NULL, - to_dealer_turn, - game_state->settings.message_duration, - 0); - } + if (game_state->selectDirection == Select){ + activate_menu(game_state->menu, game_state); + } } } -void dealer_tick(GameState* game_state) { - uint8_t dealer_score = handCount(game_state->dealer_cards, game_state->dealer_card_count); - uint8_t player_score = handCount(game_state->player_cards, game_state->player_card_count); +void dealer_tick(GameState *game_state) { + uint8_t dealer_score = hand_count(game_state->dealer_cards, game_state->dealer_card_count); + uint8_t player_score = hand_count(game_state->player_cards, game_state->player_card_count); - if(dealer_score >= DEALER_MAX) { - if(dealer_score > 21 || dealer_score < player_score) - queue(game_state, win, NULL, to_win_state, game_state->settings.message_duration, 0); - else if(dealer_score > player_score) - queue(game_state, lose, NULL, to_lose_state, game_state->settings.message_duration, 0); - else if(dealer_score == player_score) - queue(game_state, draw, NULL, to_draw_state, game_state->settings.message_duration, 0); + if (dealer_score >= DEALER_MAX) { + if (dealer_score > 21 || dealer_score < player_score) { + enqueue(&(game_state->queue_state), game_state, win, NULL, to_win_state, + game_state->settings.message_duration); + } else if (dealer_score > player_score) { + enqueue(&(game_state->queue_state), game_state, lose, NULL, to_lose_state, + game_state->settings.message_duration); + } else if (dealer_score == player_score) { + enqueue(&(game_state->queue_state), game_state, draw, NULL, to_draw_state, + game_state->settings.message_duration); + } } else { - queue( - game_state, - drawDealerCard, - NULL, - dealer_card_animation, - game_state->settings.animation_duration, - game_state->settings.animation_margin); + enqueue(&(game_state->queue_state), game_state, drawDealerCard, NULL, dealer_card_animation, + game_state->settings.animation_duration); } } -void settings_tick(GameState* game_state) { - if(game_state->selectDirection == DirectionDown && game_state->selectedMenu < 4) { +void settings_tick(GameState *game_state) { + if (game_state->selectDirection == DirectionDown && game_state->selectedMenu < 4) { game_state->selectedMenu++; } - if(game_state->selectDirection == DirectionUp && game_state->selectedMenu > 0) { + if (game_state->selectDirection == DirectionUp && game_state->selectedMenu > 0) { game_state->selectedMenu--; } - if(game_state->selectDirection == DirectionLeft || - game_state->selectDirection == DirectionRight) { + if (game_state->selectDirection == DirectionLeft || game_state->selectDirection == DirectionRight) { int nextScore = 0; - switch(game_state->selectedMenu) { - case 0: - nextScore = game_state->settings.starting_money; - if(game_state->selectDirection == DirectionLeft) - nextScore -= 10; - else - nextScore += 10; - if(nextScore >= (int)game_state->settings.round_price && nextScore < 400) - game_state->settings.starting_money = nextScore; - break; - case 1: - nextScore = game_state->settings.round_price; - if(game_state->selectDirection == DirectionLeft) - nextScore -= 10; - else - nextScore += 10; - if(nextScore >= 5 && nextScore <= (int)game_state->settings.starting_money) - game_state->settings.round_price = nextScore; - break; - case 2: - nextScore = game_state->settings.animation_margin; - if(game_state->selectDirection == DirectionLeft) - nextScore -= 100; - else - nextScore += 100; - if(nextScore >= 0 && nextScore <= (int)game_state->settings.animation_duration) - game_state->settings.animation_margin = nextScore; - break; - case 3: - nextScore = game_state->settings.animation_duration; - if(game_state->selectDirection == DirectionLeft) - nextScore -= 100; - else - nextScore += 100; - if(nextScore >= (int)game_state->settings.animation_margin && nextScore < 2000) - game_state->settings.animation_duration = nextScore; - break; - case 4: - nextScore = game_state->settings.message_duration; - if(game_state->selectDirection == DirectionLeft) - nextScore -= 100; - else - nextScore += 100; - if(nextScore >= 0 && nextScore < 2000) - game_state->settings.message_duration = nextScore; - break; - case 5: - game_state->settings.sound_effects = !game_state->settings.sound_effects; - default: - break; + switch (game_state->selectedMenu) { + case 0: + nextScore = game_state->settings.starting_money; + if (game_state->selectDirection == DirectionLeft) + nextScore -= 10; + else + nextScore += 10; + if (nextScore >= (int) game_state->settings.round_price && nextScore < 400) + game_state->settings.starting_money = nextScore; + break; + case 1: + nextScore = game_state->settings.round_price; + if (game_state->selectDirection == DirectionLeft) + nextScore -= 10; + else + nextScore += 10; + if (nextScore >= 5 && nextScore <= (int) game_state->settings.starting_money) + game_state->settings.round_price = nextScore; + break; + case 2: + nextScore = game_state->settings.animation_duration; + if (game_state->selectDirection == DirectionLeft) + nextScore -= 100; + else + nextScore += 100; + if (nextScore >= 0 && nextScore < 2000) + game_state->settings.animation_duration = nextScore; + break; + case 3: + nextScore = game_state->settings.message_duration; + if (game_state->selectDirection == DirectionLeft) + nextScore -= 100; + else + nextScore += 100; + if (nextScore >= 0 && nextScore < 2000) + game_state->settings.message_duration = nextScore; + break; + case 4: + game_state->settings.sound_effects = !game_state->settings.sound_effects; + default: + break; } } + } -void tick(GameState* game_state) { +void tick(GameState *game_state) { game_state->last_tick = furi_get_tick(); - bool queue_ran = run_queue(game_state); + bool queue_ran = run_queue(&(game_state->queue_state), game_state); - switch(game_state->state) { - case GameStateGameOver: - case GameStateStart: - if(game_state->selectDirection == Select) - init(game_state); - else if(game_state->selectDirection == DirectionRight) { - game_state->selectedMenu = 0; - game_state->state = GameStateSettings; - } - break; - case GameStatePlay: - if(!game_state->started) { - game_state->selectedMenu = 0; - game_state->started = true; - queue( - game_state, - drawDealerCard, - NULL, - dealer_back_card_animation, - game_state->settings.animation_duration, - game_state->settings.animation_margin); - queue( - game_state, - drawPlayerCard, - NULL, - player_card_animation, - game_state->settings.animation_duration, - game_state->settings.animation_margin); - queue( - game_state, - drawDealerCard, - NULL, - dealer_card_animation, - game_state->settings.animation_duration, - game_state->settings.animation_margin); - queue( - game_state, - drawPlayerCard, - NULL, - player_card_animation, - game_state->settings.animation_duration, - game_state->settings.animation_margin); - } - if(!queue_ran) player_tick(game_state); - break; - case GameStateDealer: - if(!queue_ran) dealer_tick(game_state); - break; - case GameStateSettings: - settings_tick(game_state); - break; - default: - break; + switch (game_state->state) { + case GameStateGameOver: + case GameStateStart: + if (game_state->selectDirection == Select) + init(game_state); + else if (game_state->selectDirection == DirectionRight) { + game_state->selectedMenu = 0; + game_state->state = GameStateSettings; + } + break; + case GameStatePlay: + if (!game_state->started) { + game_state->selectedMenu = 0; + game_state->started = true; + enqueue(&(game_state->queue_state), game_state, drawDealerCard, NULL, dealer_back_card_animation, + game_state->settings.animation_duration); + enqueue(&(game_state->queue_state), game_state, drawPlayerCard, NULL, player_card_animation, + game_state->settings.animation_duration); + enqueue(&(game_state->queue_state), game_state, drawDealerCard, NULL, dealer_card_animation, + game_state->settings.animation_duration); + enqueue(&(game_state->queue_state), game_state, drawPlayerCard, NULL, player_card_animation, + game_state->settings.animation_duration); + } + if (!queue_ran) + player_tick(game_state); + break; + case GameStateDealer: + if (!queue_ran) + dealer_tick(game_state); + break; + case GameStateSettings: + settings_tick(game_state); + break; + default: + break; } game_state->selectDirection = None; + } -void start_round(GameState* game_state) { +void start_round(GameState *game_state) { + game_state->menu->current_menu=1; game_state->player_card_count = 0; game_state->dealer_card_count = 0; - game_state->selectedMenu = 0; + set_menu_state(game_state->menu, 0, true); + game_state->menu->enabled=true; game_state->started = false; game_state->doubled = false; - game_state->animating = true; - game_state->animationStart = 0; - shuffleDeck(&(game_state->deck)); + game_state->queue_state.running = true; + shuffle_deck(&(game_state->deck)); game_state->doubled = false; game_state->bet = game_state->settings.round_price; - if(game_state->player_score < game_state->settings.round_price) { + if (game_state->player_score < game_state->settings.round_price) { game_state->state = GameStateGameOver; } else { game_state->player_score -= game_state->settings.round_price; @@ -488,100 +409,145 @@ void start_round(GameState* game_state) { game_state->state = GameStatePlay; } -void init(GameState* game_state) { +void init(GameState *game_state) { + set_menu_state(game_state->menu, 0, true); + game_state->menu->enabled=true; + game_state->menu->current_menu=1; game_state->settings = load_settings(); game_state->last_tick = 0; game_state->processing = true; + game_state->selectedMenu = 0; game_state->player_score = game_state->settings.starting_money; - generateDeck(&(game_state->deck)); + generate_deck(&(game_state->deck), 6); start_round(game_state); } -static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { +static void input_callback(InputEvent *input_event, FuriMessageQueue *event_queue) { furi_assert(event_queue); AppEvent event = {.type = EventTypeKey, .input = *input_event}; furi_message_queue_put(event_queue, &event, FuriWaitForever); } -static void update_timer_callback(FuriMessageQueue* event_queue) { +static void update_timer_callback(FuriMessageQueue *event_queue) { furi_assert(event_queue); AppEvent event = {.type = EventTypeTick}; furi_message_queue_put(event_queue, &event, 0); } -int32_t blackjack_app(void* p) { +void doubleAction(void *state){ + GameState *game_state = state; + if (!game_state->doubled && game_state->player_score >= game_state->settings.round_price) { + game_state->player_score -= game_state->settings.round_price; + game_state->bet += game_state->settings.round_price; + game_state->doubled = true; + enqueue(&(game_state->queue_state), game_state, drawPlayerCard, NULL, player_card_animation, + game_state->settings.animation_duration); + game_state->player_cards[game_state->player_card_count] = game_state->deck.cards[game_state->deck.index]; + uint8_t score = hand_count(game_state->player_cards, game_state->player_card_count + 1); + if (score > 21) { + enqueue(&(game_state->queue_state), game_state, lose, NULL, to_bust_state, + game_state->settings.message_duration); + } else { + enqueue(&(game_state->queue_state), game_state, dealerTurn, NULL, to_dealer_turn, + game_state->settings.message_duration); + } + set_menu_state(game_state->menu, 0, false); + } +} + +void hitAction(void *state){ + GameState *game_state = state; + enqueue(&(game_state->queue_state), game_state, drawPlayerCard, NULL, player_card_animation, + game_state->settings.animation_duration); +} +void stayAction(void *state){ + GameState *game_state = state; + enqueue(&(game_state->queue_state), game_state, dealerTurn, NULL, to_dealer_turn, + game_state->settings.message_duration); +} + +int32_t blackjack_app(void *p) { UNUSED(p); int32_t return_code = 0; - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(AppEvent)); + FuriMessageQueue *event_queue = furi_message_queue_alloc(8, sizeof(AppEvent)); - GameState* game_state = malloc(sizeof(GameState)); + GameState *game_state = malloc(sizeof(GameState)); + game_state->menu= malloc(sizeof(Menu)); + game_state->menu->menu_width=40; init(game_state); + add_menu(game_state->menu, "Double", doubleAction); + add_menu(game_state->menu, "Hit", hitAction); + add_menu(game_state->menu, "Stay", stayAction); + game_state->state = GameStateStart; ValueMutex state_mutex; - if(!init_mutex(&state_mutex, game_state, sizeof(GameState))) { + if (!init_mutex(&state_mutex, game_state, sizeof(GameState))) { FURI_LOG_E(APP_NAME, "cannot create mutex\r\n"); return_code = 255; goto free_and_exit; } - ViewPort* view_port = view_port_alloc(); + ViewPort *view_port = view_port_alloc(); view_port_draw_callback_set(view_port, render_callback, &state_mutex); view_port_input_callback_set(view_port, input_callback, event_queue); - FuriTimer* timer = furi_timer_alloc(update_timer_callback, FuriTimerTypePeriodic, event_queue); + FuriTimer *timer = + furi_timer_alloc(update_timer_callback, FuriTimerTypePeriodic, event_queue); furi_timer_start(timer, furi_kernel_get_tick_frequency() / 25); - Gui* gui = furi_record_open("gui"); + Gui *gui = furi_record_open("gui"); gui_add_view_port(gui, view_port, GuiLayerFullscreen); AppEvent event; - for(bool processing = true; processing;) { + for (bool processing = true; processing;) { FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); - GameState* game_state = (GameState*)acquire_mutex_block(&state_mutex); - if(event_status == FuriStatusOk) { - if(event.type == EventTypeKey) { - if(event.input.type == InputTypePress) { - switch(event.input.key) { - case InputKeyUp: - game_state->selectDirection = DirectionUp; - break; - case InputKeyDown: - game_state->selectDirection = DirectionDown; - break; - case InputKeyRight: - game_state->selectDirection = DirectionRight; - break; - case InputKeyLeft: - game_state->selectDirection = DirectionLeft; - break; - case InputKeyBack: - if(game_state->state == GameStateSettings) { - game_state->state = GameStateStart; - save_settings(game_state->settings); - } else - processing = false; - break; - case InputKeyOk: - game_state->selectDirection = Select; - break; + GameState *localstate = (GameState *) acquire_mutex_block(&state_mutex); + if (event_status == FuriStatusOk) { + if (event.type == EventTypeKey) { + + if (event.input.type == InputTypePress) { + switch (event.input.key) { + case InputKeyUp: + localstate->selectDirection = DirectionUp; + break; + case InputKeyDown: + localstate->selectDirection = DirectionDown; + break; + case InputKeyRight: + localstate->selectDirection = DirectionRight; + break; + case InputKeyLeft: + localstate->selectDirection = DirectionLeft; + break; + case InputKeyBack: + if (localstate->state == GameStateSettings) { + localstate->state = GameStateStart; + save_settings(localstate->settings); + } else + processing = false; + break; + case InputKeyOk: + localstate->selectDirection = Select; + break; } } - } else if(event.type == EventTypeTick) { - tick(game_state); - processing = game_state->processing; + } else if (event.type == EventTypeTick) { + tick(localstate); + processing = localstate->processing; } } else { FURI_LOG_D(APP_NAME, "osMessageQueue: event timeout"); // event timeout } view_port_update(view_port); - release_mutex(&state_mutex, game_state); + release_mutex(&state_mutex, localstate); } + furi_timer_free(timer); view_port_enabled_set(view_port, false); gui_remove_view_port(gui, view_port); @@ -589,8 +555,9 @@ int32_t blackjack_app(void* p) { view_port_free(view_port); delete_mutex(&state_mutex); -free_and_exit: - queue_clear(); + free_and_exit: + free_menu(game_state->menu); + queue_clear(&(game_state->queue_state)); free(game_state); furi_message_queue_free(event_queue); diff --git a/applications/plugins/blackjack/card.c b/applications/plugins/blackjack/card.c deleted file mode 100644 index ace1221b9..000000000 --- a/applications/plugins/blackjack/card.c +++ /dev/null @@ -1,270 +0,0 @@ -#include -#include "card.h" -#include "util.h" - -//region CardDesign -bool pips[4][49] = { - {//spades - 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0}, - { - //hearts - 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, - }, - {//diamonds - 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, - 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0}, - {//clubs - 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0}}; - -bool backDesign[4] = {0, 1, 1, 0}; -//endregion - -uint8_t characters[13] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K', 'A'}; - -uint8_t edge_cards[3] = {0, 8, 15}; -//region Player card positions -uint8_t playerCardPositions[22][4] = { - //first row - {108, 38, 0, 0}, - {98, 38, 0, 1}, - {88, 38, 0, 1}, - {78, 38, 0, 1}, - {68, 38, 0, 1}, - {58, 38, 0, 1}, - {48, 38, 0, 1}, - {38, 38, 0, 1}, - //second row - {104, 26, 1, 0}, - {94, 26, 1, 1}, - {84, 26, 1, 1}, - {74, 26, 1, 1}, - {64, 26, 1, 1}, - {54, 26, 1, 1}, - {44, 26, 1, 1}, - //third row - {99, 14, 1, 0}, - {89, 14, 1, 1}, - {79, 14, 1, 1}, - {69, 14, 1, 1}, - {59, 14, 1, 1}, - {49, 14, 1, 1}, -}; -//endregion - -void drawPlayerDeck(const Card cards[21], uint8_t count, Canvas* const canvas) { - for(uint8_t i = 0; i < count; i++) { - CardState state = Normal; - if(playerCardPositions[i][2] == 1 && playerCardPositions[i][3] == 1) - state = BottomAndRightCut; - else if(playerCardPositions[i][3] == 1) - state = RightCut; - else if(playerCardPositions[i][2] == 1) - state = BottomCut; - drawCardAt( - playerCardPositions[i][0], - playerCardPositions[i][1], - cards[i].pip, - cards[i].character, - state, - canvas); - } -} - -bool is_at_edge(uint8_t index) { - for(uint8_t i = 0; i < 3; i++) - if(edge_cards[i] == index) return true; - - return false; -} - -Vector card_pos_at_index(uint8_t index) { - return (Vector){playerCardPositions[index][0], playerCardPositions[index][1]}; -} - -void drawCardAt( - int8_t pos_x, - int8_t pos_y, - uint8_t pip, - uint8_t character, - CardState state, - Canvas* const canvas) { - if(state == Normal) { - canvas_set_color(canvas, ColorWhite); - canvas_draw_box(canvas, pos_x, pos_y, CARD_WIDTH, CARD_HEIGHT); - - canvas_set_color(canvas, ColorBlack); - canvas_draw_frame(canvas, pos_x, pos_y, CARD_WIDTH, CARD_HEIGHT); - } else { - if(state == BottomCut || state == BottomAndRightCut) - canvas_draw_line( - canvas, pos_x, pos_y, pos_x, pos_y + CARD_HALF_HEIGHT - 1); //half height line - - if(state == BottomCut) { - canvas_draw_line( - canvas, pos_x, pos_y, pos_x + CARD_WIDTH - 1, pos_y); //full width line - canvas_draw_line( - canvas, - pos_x + CARD_WIDTH - 1, - pos_y, - pos_x + CARD_WIDTH - 1, - pos_y + CARD_HALF_HEIGHT - 1); //half height line - } - - if(state == BottomAndRightCut) { - canvas_draw_line( - canvas, pos_x, pos_y, pos_x + CARD_HALF_WIDTH - 1, pos_y); //half width - } - - if(state == RightCut) { - canvas_draw_line( - canvas, pos_x, pos_y, pos_x + CARD_HALF_WIDTH - 1, pos_y); //half width - canvas_draw_line( - canvas, pos_x, pos_y, pos_x, pos_y + CARD_HEIGHT - 1); //full height line - canvas_draw_line( - canvas, - pos_x, - pos_y + CARD_HEIGHT - 1, - pos_x + CARD_HALF_WIDTH - 1, - pos_y + CARD_HEIGHT - 1); //full height line - } - } - - uint8_t left = pos_x + CORNER_MARGIN; - uint8_t right = (pos_x + CARD_WIDTH - CORNER_MARGIN - 7); - uint8_t top = pos_y + CORNER_MARGIN; - uint8_t bottom = (pos_y + CARD_HEIGHT - CORNER_MARGIN - 7); - - for(uint8_t x = 0; x < 7; x++) { - for(uint8_t y = 0; y < 7; y++) { - if(pips[pip][x + y * 7]) { - if(state == Normal || state == BottomCut) - canvas_draw_dot(canvas, right + x + 1, top + y); - if(state == Normal || state == RightCut) - canvas_draw_dot(canvas, left + x - 1, bottom + y); - } - } - } - - canvas_set_font(canvas, FontSecondary); - char drawChar[3]; - if(character < 9) - snprintf(drawChar, sizeof(drawChar), "%i", character + 2); - else { - snprintf(drawChar, sizeof(drawChar), "%c", characters[character]); - } - - canvas_set_font_direction(canvas, CanvasDirectionLeftToRight); - canvas_draw_str_aligned(canvas, left + 2, top + 3, AlignCenter, AlignCenter, drawChar); - - canvas_set_font_direction(canvas, CanvasDirectionRightToLeft); - if(state == Normal) { //flipper crashes on non center aligned text when upside down - uint8_t margin = 9; - if(character == 8) //10 needs bigger margin - margin = 12; - canvas_draw_str_aligned( - canvas, right + margin, bottom - 3, AlignCenter, AlignCenter, drawChar); - } - - canvas_set_font_direction(canvas, CanvasDirectionLeftToRight); - //canvas_draw_str(canvas, left, top, drawChar ); -} - -void drawCardBackAt(int8_t pos_x, int8_t pos_y, Canvas* const canvas) { - canvas_set_color(canvas, ColorWhite); - canvas_draw_box(canvas, pos_x, pos_y, CARD_WIDTH, CARD_HEIGHT); - - canvas_set_color(canvas, ColorBlack); - canvas_draw_frame(canvas, pos_x, pos_y, CARD_WIDTH, CARD_HEIGHT); - for(uint8_t x = 0; x < CARD_WIDTH - 2; x++) { - for(uint8_t y = 0; y < CARD_HEIGHT - 2; y++) { - uint8_t _x = x; - uint8_t _y = y * 2; - if(backDesign[(_x + _y) % 4]) { - canvas_draw_dot(canvas, pos_x + x + 1, pos_y + y + 1); - } - } - } -} - -void generateDeck(Deck* deck_ptr) { - uint16_t counter = 0; - for(uint8_t deck = 0; deck < DECK_COUNT; deck++) { - for(uint8_t pip = 0; pip < 4; pip++) { - for(uint8_t label = 0; label < 13; label++) { - deck_ptr->cards[counter] = (Card){pip, label}; - counter++; - } - } - } -} - -void shuffleDeck(Deck* deck_ptr) { - srand(DWT->CYCCNT); - deck_ptr->index = 0; - int max = DECK_COUNT * 52; - for(int i = 0; i < max; i++) { - int r = i + (rand() % (max - i)); - Card tmp = deck_ptr->cards[i]; - deck_ptr->cards[i] = deck_ptr->cards[r]; - deck_ptr->cards[r] = tmp; - } -} - -uint8_t handCount(const Card cards[21], uint8_t count) { - uint8_t aceCount = 0; - uint8_t score = 0; - - for(uint8_t i = 0; i < count; i++) { - if(cards[i].character == 12) - aceCount++; - else { - if(cards[i].character > 8) - score += 10; - else - score += cards[i].character + 2; - } - } - - for(uint8_t i = 0; i < aceCount; i++) { - if((score + 11) <= 21) - score += 11; - else - score++; - } - - return score; -} - -void draw_card_animation( - Card animatingCard, - Vector from, - Vector control, - Vector to, - float t, - bool extra_margin, - Canvas* const canvas) { - float time = t; - if(extra_margin) { - time += 0.2; - } - - Vector currentPos = quadratic_2d(from, control, to, time); - if(t > 1) { - drawCardAt( - currentPos.x, currentPos.y, animatingCard.pip, animatingCard.character, Normal, canvas); - } else { - if(t < 0.5) - drawCardBackAt(currentPos.x, currentPos.y, canvas); - else - drawCardAt( - currentPos.x, - currentPos.y, - animatingCard.pip, - animatingCard.character, - Normal, - canvas); - } -} \ No newline at end of file diff --git a/applications/plugins/blackjack/card.h b/applications/plugins/blackjack/card.h deleted file mode 100644 index cae87172b..000000000 --- a/applications/plugins/blackjack/card.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef _card_h -#define _card_h - -#include - -#define DECK_COUNT 6 -#define CARD_HEIGHT 24 -#define CARD_HALF_HEIGHT CARD_HEIGHT / 2 -#define CARD_WIDTH 18 -#define CARD_HALF_WIDTH CARD_WIDTH / 2 -#define CORNER_MARGIN 3 -#define LEGEND_SIZE 10 -typedef struct Vector Vector; - -typedef enum { - Normal, - BottomCut, - RightCut, - BottomAndRightCut, - TopCut, - LeftCut, - TopAndLeftCut -} CardState; - -typedef struct { - uint8_t pip; - uint8_t character; -} Card; - -typedef struct { - Card cards[52 * DECK_COUNT]; - int index; -} Deck; - -void drawPlayerDeck(const Card cards[21], uint8_t count, Canvas* const canvas); - -void drawCardAt( - int8_t pos_x, - int8_t pos_y, - uint8_t pip, - uint8_t character, - CardState state, - Canvas* const canvas); - -void drawCardBackAt(int8_t pos_x, int8_t pos_y, Canvas* const canvas); - -void generateDeck(Deck* deck_ptr); - -void shuffleDeck(Deck* deck_ptr); - -void draw_card_animation( - Card animatingCard, - Vector from, - Vector control, - Vector to, - float t, - bool extra_margin, - Canvas* const canvas); - -Vector card_pos_at_index(uint8_t index); -bool is_at_edge(uint8_t index); -uint8_t handCount(const Card cards[21], uint8_t count); - -#endif \ No newline at end of file diff --git a/applications/plugins/blackjack/defines.h b/applications/plugins/blackjack/defines.h index 12a5c140e..78d40d32b 100644 --- a/applications/plugins/blackjack/defines.h +++ b/applications/plugins/blackjack/defines.h @@ -5,14 +5,13 @@ #include #include #include -#include "card.h" +#include "common/card.h" +#include "common/queue.h" +#include "common/menu.h" #define APP_NAME "Blackjack" -//#define ANIMATION_TIME furi_ms_to_ticks(1500) -//#define ANIMATION_END_MARGIN furi_ms_to_ticks(200) #define CONF_ANIMATION_DURATION "AnimationDuration" -#define CONF_ANIMATION_MARGIN "AnimationMargin" #define CONF_MESSAGE_DURATION "MessageDuration" #define CONF_STARTING_MONEY "StartingMoney" #define CONF_ROUND_PRICE "RoundPrice" @@ -23,8 +22,7 @@ typedef enum { EventTypeKey, } EventType; -typedef struct { - uint32_t animation_margin; +typedef struct{ uint32_t animation_duration; uint32_t message_duration; uint32_t starting_money; @@ -45,7 +43,14 @@ typedef enum { GameStateDealer, } PlayState; -typedef enum { DirectionUp, DirectionRight, DirectionDown, DirectionLeft, Select, None } Direction; +typedef enum { + DirectionUp, + DirectionRight, + DirectionDown, + DirectionLeft, + Select, + None +} Direction; typedef struct { Card player_cards[21]; @@ -58,13 +63,14 @@ typedef struct { uint32_t player_score; uint32_t bet; - bool doubled; - bool animating; - bool started; uint8_t selectedMenu; + bool doubled; + bool started; bool processing; Deck deck; PlayState state; + QueueState queue_state; + Menu *menu; unsigned int last_tick; - unsigned int animationStart; } GameState; + diff --git a/applications/plugins/blackjack/ui.c b/applications/plugins/blackjack/ui.c index 6299c65c6..a58c95c6a 100644 --- a/applications/plugins/blackjack/ui.c +++ b/applications/plugins/blackjack/ui.c @@ -2,39 +2,36 @@ #include #include "ui.h" -#include "card.h" -#include "util.h" #define LINE_HEIGHT 16 #define ITEM_PADDING 4 -const char MoneyMul[4] = {'K', 'B', 'T', 'S'}; +const char MoneyMul[4] = { + 'K', 'B', 'T', 'S' +}; -void draw_player_scene(Canvas* const canvas, const GameState* game_state) { +void draw_player_scene(Canvas *const canvas, const GameState *game_state) { int max_card = game_state->player_card_count; - if(max_card > 0) drawPlayerDeck((game_state->player_cards), max_card, canvas); + if (max_card > 0) + draw_deck((game_state->player_cards), max_card, canvas); - if(game_state->dealer_card_count > 0) drawCardBackAt(13, 5, canvas); + if (game_state->dealer_card_count > 0) + draw_card_back_at(13, 5, canvas); max_card = game_state->dealer_card_count; - if(max_card > 1) { - drawCardAt( - 2, - 2, - game_state->dealer_cards[1].pip, - game_state->dealer_cards[1].character, - Normal, - canvas); + if (max_card > 1) { + draw_card_at(2, 2, game_state->dealer_cards[1].pip, game_state->dealer_cards[1].character, + canvas); } } -void draw_dealer_scene(Canvas* const canvas, const GameState* game_state) { +void draw_dealer_scene(Canvas *const canvas, const GameState *game_state) { uint8_t max_card = game_state->dealer_card_count; - drawPlayerDeck((game_state->dealer_cards), max_card, canvas); + draw_deck((game_state->dealer_cards), max_card, canvas); } -void popup_frame(Canvas* const canvas) { +void popup_frame(Canvas *const canvas) { canvas_set_color(canvas, ColorWhite); canvas_draw_box(canvas, 32, 15, 66, 13); canvas_set_color(canvas, ColorBlack); @@ -42,16 +39,15 @@ void popup_frame(Canvas* const canvas) { canvas_set_font(canvas, FontSecondary); } -void draw_play_menu(Canvas* const canvas, const GameState* game_state) { - const char* menus[3] = {"Double", "Hit", "Stay"}; - for(uint8_t m = 0; m < 3; m++) { - if(m == 0 && - (game_state->doubled || game_state->player_score < game_state->settings.round_price)) - continue; + +void draw_play_menu(Canvas *const canvas, const GameState *game_state) { + const char *menus[3] = {"Double", "Hit", "Stay"}; + for (uint8_t m = 0; m < 3; m++) { + if (m == 0 && (game_state->doubled || game_state->player_score < game_state->settings.round_price)) continue; int y = m * 13 + 25; canvas_set_color(canvas, ColorBlack); - if(game_state->selectedMenu == m) { + if (game_state->selectedMenu == m) { canvas_set_color(canvas, ColorBlack); canvas_draw_box(canvas, 1, y, 31, 12); } else { @@ -61,7 +57,7 @@ void draw_play_menu(Canvas* const canvas, const GameState* game_state) { canvas_draw_frame(canvas, 1, y, 31, 12); } - if(game_state->selectedMenu == m) + if (game_state->selectedMenu == m) canvas_set_color(canvas, ColorWhite); else canvas_set_color(canvas, ColorBlack); @@ -69,34 +65,35 @@ void draw_play_menu(Canvas* const canvas, const GameState* game_state) { } } -void draw_screen(Canvas* const canvas, const bool* points) { - for(uint8_t x = 0; x < 128; x++) { - for(uint8_t y = 0; y < 64; y++) { - if(points[y * 128 + x]) canvas_draw_dot(canvas, x, y); +void draw_screen(Canvas *const canvas, const bool *points) { + for (uint8_t x = 0; x < 128; x++) { + for (uint8_t y = 0; y < 64; y++) { + if (points[y * 128 + x]) + canvas_draw_dot(canvas, x, y); } } } -void draw_score(Canvas* const canvas, bool top, uint8_t amount) { +void draw_score(Canvas *const canvas, bool top, uint8_t amount) { char drawChar[20]; snprintf(drawChar, sizeof(drawChar), "Player score: %i", amount); - if(top) + if (top) canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, drawChar); else canvas_draw_str_aligned(canvas, 64, 62, AlignCenter, AlignBottom, drawChar); } -void draw_money(Canvas* const canvas, uint32_t score) { +void draw_money(Canvas *const canvas, uint32_t score) { canvas_set_font(canvas, FontSecondary); char drawChar[10]; uint32_t currAmount = score; - if(currAmount < 1000) { + if (currAmount < 1000) { snprintf(drawChar, sizeof(drawChar), "$%lu", currAmount); } else { char c = 'K'; - for(uint8_t i = 0; i < 4; i++) { + for (uint8_t i = 0; i < 4; i++) { currAmount = currAmount / 1000; - if(currAmount < 1000) { + if (currAmount < 1000) { c = MoneyMul[i]; break; } @@ -107,95 +104,77 @@ void draw_money(Canvas* const canvas, uint32_t score) { canvas_draw_str_aligned(canvas, 126, 2, AlignRight, AlignTop, drawChar); } -void draw_menu( - Canvas* const canvas, - const char* text, - const char* value, - int8_t y, - bool left_caret, - bool right_caret, - bool selected) { - UNUSED(selected); - if(y < 0 || y >= 64) return; - if(selected) { +void draw_menu(Canvas *const canvas, const char *text, const char *value, int8_t y, bool left_caret, bool right_caret, + bool selected) { + UNUSED(selected); + if (y < 0 || y >= 64) return; + + if (selected) { canvas_set_color(canvas, ColorBlack); canvas_draw_box(canvas, 0, y, 122, LINE_HEIGHT); canvas_set_color(canvas, ColorWhite); } canvas_draw_str_aligned(canvas, 4, y + ITEM_PADDING, AlignLeft, AlignTop, text); - if(left_caret) canvas_draw_str_aligned(canvas, 80, y + ITEM_PADDING, AlignLeft, AlignTop, "<"); + if (left_caret) + canvas_draw_str_aligned(canvas, 80, y + ITEM_PADDING, AlignLeft, AlignTop, "<"); canvas_draw_str_aligned(canvas, 100, y + ITEM_PADDING, AlignCenter, AlignTop, value); - if(right_caret) + if (right_caret) canvas_draw_str_aligned(canvas, 120, y + ITEM_PADDING, AlignRight, AlignTop, ">"); canvas_set_color(canvas, ColorBlack); } -void settings_page(Canvas* const canvas, const GameState* gameState) { +void settings_page(Canvas *const canvas, const GameState *gameState) { char drawChar[10]; int startY = 0; - if(LINE_HEIGHT * (gameState->selectedMenu + 1) >= 64) { + if (LINE_HEIGHT * (gameState->selectedMenu + 1) >= 64) { startY -= (LINE_HEIGHT * (gameState->selectedMenu + 1)) - 64; } - int scrollHeight = round(64 / 7.0) + ITEM_PADDING * 2; - int scrollPos = 64 / (7.0 / (gameState->selectedMenu + 1)) - ITEM_PADDING * 2; + int scrollHeight = round(64 / 6.0) + ITEM_PADDING * 2; + int scrollPos = 64 / (6.0 / (gameState->selectedMenu + 1)) - ITEM_PADDING * 2; + canvas_set_color(canvas, ColorBlack); canvas_draw_box(canvas, 123, scrollPos, 4, scrollHeight); canvas_draw_box(canvas, 125, 0, 1, 64); snprintf(drawChar, sizeof(drawChar), "%li", gameState->settings.starting_money); - draw_menu( - canvas, - "Start money", - drawChar, - 0 * LINE_HEIGHT + startY, - gameState->settings.starting_money > gameState->settings.round_price, - gameState->settings.starting_money < 400, - gameState->selectedMenu == 0); + draw_menu(canvas, "Start money", drawChar, + 0 * LINE_HEIGHT + startY, + gameState->settings.starting_money > gameState->settings.round_price, + gameState->settings.starting_money < 400, + gameState->selectedMenu == 0 + ); snprintf(drawChar, sizeof(drawChar), "%li", gameState->settings.round_price); - draw_menu( - canvas, - "Round price", - drawChar, - 1 * LINE_HEIGHT + startY, - gameState->settings.round_price > 10, - gameState->settings.round_price < gameState->settings.starting_money, - gameState->selectedMenu == 1); - snprintf(drawChar, sizeof(drawChar), "%li", gameState->settings.animation_margin); - draw_menu( - canvas, - "Anim. margin", - drawChar, - 2 * LINE_HEIGHT + startY, - gameState->settings.animation_margin > 0, - gameState->settings.animation_margin < gameState->settings.animation_duration, - gameState->selectedMenu == 2); + draw_menu(canvas, "Round price", drawChar, + 1 * LINE_HEIGHT + startY, + gameState->settings.round_price > 10, + gameState->settings.round_price < gameState->settings.starting_money, + gameState->selectedMenu == 1 + ); + snprintf(drawChar, sizeof(drawChar), "%li", gameState->settings.animation_duration); - draw_menu( - canvas, - "Anim. length", - drawChar, - 3 * LINE_HEIGHT + startY, - gameState->settings.animation_duration > gameState->settings.animation_margin, - gameState->settings.animation_duration < 2000, - gameState->selectedMenu == 3); + draw_menu(canvas, "Anim. length", drawChar, + 2 * LINE_HEIGHT + startY, + gameState->settings.animation_duration > 0, + gameState->settings.animation_duration < 2000, + gameState->selectedMenu == 2 + ); snprintf(drawChar, sizeof(drawChar), "%li", gameState->settings.message_duration); - draw_menu( - canvas, - "Popup time", - drawChar, - 4 * LINE_HEIGHT + startY, - gameState->settings.message_duration > 0, - gameState->settings.message_duration < 2000, - gameState->selectedMenu == 4); - // draw_menu(canvas, "Sound", gameState->settings.sound_effects ? "Yes" : "No", - // 5 * LINE_HEIGHT + startY, - // true, - // true, - // gameState->selectedMenu == 5 - // ); + draw_menu(canvas, "Popup time", drawChar, + 3 * LINE_HEIGHT + startY, + gameState->settings.message_duration > 0, + gameState->settings.message_duration < 2000, + gameState->selectedMenu == 3 + ); +// draw_menu(canvas, "Sound", gameState->settings.sound_effects ? "Yes" : "No", +// 5 * LINE_HEIGHT + startY, +// true, +// true, +// gameState->selectedMenu == 5 +// ); + } \ No newline at end of file diff --git a/applications/plugins/blackjack/ui.h b/applications/plugins/blackjack/ui.h index e770ec993..5c20e0332 100644 --- a/applications/plugins/blackjack/ui.h +++ b/applications/plugins/blackjack/ui.h @@ -1,19 +1,18 @@ #pragma once #include "defines.h" -#include "util.h" #include -void draw_player_scene(Canvas* const canvas, const GameState* game_state); +void draw_player_scene(Canvas *const canvas, const GameState *game_state); -void draw_dealer_scene(Canvas* const canvas, const GameState* game_state); +void draw_dealer_scene(Canvas *const canvas, const GameState *game_state); -void draw_play_menu(Canvas* const canvas, const GameState* game_state); +void draw_play_menu(Canvas *const canvas, const GameState *game_state); -void draw_score(Canvas* const canvas, bool top, uint8_t amount); +void draw_score(Canvas *const canvas, bool top, uint8_t amount); -void draw_money(Canvas* const canvas, uint32_t score); -void settings_page(Canvas* const canvas, const GameState* gameState); +void draw_money(Canvas *const canvas, uint32_t score); +void settings_page(Canvas *const canvas, const GameState * gameState); -void popup_frame(Canvas* const canvas); -void draw_screen(Canvas* const canvas, const bool* points); +void popup_frame(Canvas *const canvas); +void draw_screen(Canvas *const canvas, const bool* points); diff --git a/applications/plugins/blackjack/util.c b/applications/plugins/blackjack/util.c index 369e4c1a5..563507a4d 100644 --- a/applications/plugins/blackjack/util.c +++ b/applications/plugins/blackjack/util.c @@ -1,108 +1,16 @@ +#include #include "util.h" -const char* CONFIG_FILE_PATH = EXT_PATH(".blackjack.settings"); - -static QueueItem* afterDelay; - -float lerp(float v0, float v1, float t) { - if(t > 1) return v1; - return (1 - t) * v0 + t * v1; -} - -Vector lerp_2d(Vector start, Vector end, float t) { - return (Vector){ - lerp(start.x, end.x, t), - lerp(start.y, end.y, t), - }; -} - -Vector quadratic_2d(Vector start, Vector control, Vector end, float t) { - return lerp_2d(lerp_2d(start, control, t), lerp_2d(control, end, t), t); -} - -void queue( - GameState* game_state, - void (*callback)(GameState* game_state), - void (*start)(GameState* game_state), - void (*processing)( - const GameState* gameState, - Canvas* const canvas, - uint32_t duration, - uint32_t margin), - uint32_t duration, - uint32_t margin) { - if(afterDelay == NULL) { - game_state->animationStart = game_state->last_tick; - afterDelay = malloc(sizeof(QueueItem)); - afterDelay->callback = callback; - afterDelay->processing = processing; - afterDelay->start = start; - afterDelay->duration = duration; - afterDelay->margin = margin; - afterDelay->next = NULL; - } else { - QueueItem* next = afterDelay; - while(next->next != NULL) { - next = (QueueItem*)(next->next); - } - next->next = malloc(sizeof(QueueItem)); - ((QueueItem*)next->next)->callback = callback; - ((QueueItem*)next->next)->processing = processing; - ((QueueItem*)next->next)->start = start; - ((QueueItem*)next->next)->duration = duration; - ((QueueItem*)next->next)->margin = margin; - ((QueueItem*)next->next)->next = NULL; - } -} - -void queue_clear() { - while(afterDelay != NULL) { - QueueItem* f = afterDelay; - free(f); - afterDelay = f->next; - } -} - -void dequeue(GameState* game_state) { - ((QueueItem*)afterDelay)->callback(game_state); - QueueItem* f = afterDelay; - afterDelay = (QueueItem*)afterDelay->next; - free(f); - if(afterDelay != NULL && afterDelay->start != NULL) afterDelay->start(game_state); - game_state->animationStart = game_state->last_tick; -} - -void animateQueue(const GameState* game_state, Canvas* const canvas) { - if(afterDelay != NULL && ((QueueItem*)afterDelay)->processing != NULL) { - ((QueueItem*)afterDelay) - ->processing(game_state, canvas, afterDelay->duration, afterDelay->margin); - } -} - -bool run_queue(GameState* game_state) { - if(afterDelay != NULL) { - game_state->animating = true; - if((game_state->last_tick - game_state->animationStart) > afterDelay->duration) { - dequeue(game_state); - } - return true; - } - game_state->animating = false; - return false; -} +const char *CONFIG_FILE_PATH = EXT_PATH(".blackjack.settings"); void save_settings(Settings settings) { - Storage* storage = furi_record_open(RECORD_STORAGE); - FlipperFormat* file = flipper_format_file_alloc(storage); + Storage *storage = furi_record_open(RECORD_STORAGE); + FlipperFormat *file = flipper_format_file_alloc(storage); FURI_LOG_D(APP_NAME, "Saving config"); - if(flipper_format_file_open_existing(file, CONFIG_FILE_PATH)) { - FURI_LOG_D( - APP_NAME, "Saving %s: %ld", CONF_ANIMATION_DURATION, settings.animation_duration); - flipper_format_update_uint32( - file, CONF_ANIMATION_DURATION, &(settings.animation_duration), 1); + if (flipper_format_file_open_existing(file, CONFIG_FILE_PATH)) { + FURI_LOG_D(APP_NAME, "Saving %s: %ld", CONF_ANIMATION_DURATION, settings.animation_duration); + flipper_format_update_uint32(file, CONF_ANIMATION_DURATION, &(settings.animation_duration), 1); - FURI_LOG_D(APP_NAME, "Saving %s: %ld", CONF_ANIMATION_MARGIN, settings.animation_margin); - flipper_format_update_uint32(file, CONF_ANIMATION_MARGIN, &(settings.animation_margin), 1); FURI_LOG_D(APP_NAME, "Saving %s: %ld", CONF_MESSAGE_DURATION, settings.message_duration); flipper_format_update_uint32(file, CONF_MESSAGE_DURATION, &(settings.message_duration), 1); @@ -113,10 +21,10 @@ void save_settings(Settings settings) { FURI_LOG_D(APP_NAME, "Saving %s: %ld", CONF_ROUND_PRICE, settings.round_price); flipper_format_update_uint32(file, CONF_ROUND_PRICE, &(settings.round_price), 1); - FURI_LOG_D(APP_NAME, "Saving %s: %i", CONF_SOUND_EFFECTS, settings.sound_effects ? 1 : 0); + FURI_LOG_D(APP_NAME, "Saving %s: %i", CONF_SOUND_EFFECTS, settings.sound_effects?1:0); flipper_format_update_bool(file, CONF_SOUND_EFFECTS, &(settings.sound_effects), 1); FURI_LOG_D(APP_NAME, "Config saved"); - } else { + }else{ FURI_LOG_E(APP_NAME, "Save error"); } flipper_format_file_close(file); @@ -124,13 +32,10 @@ void save_settings(Settings settings) { furi_record_close(RECORD_STORAGE); } -void save_settings_file(FlipperFormat* file, Settings* settings) { +void save_settings_file(FlipperFormat *file, Settings *settings) { flipper_format_write_header_cstr(file, CONFIG_FILE_HEADER, CONFIG_FILE_VERSION); flipper_format_write_comment_cstr(file, "Card animation duration in ms"); flipper_format_write_uint32(file, CONF_ANIMATION_DURATION, &(settings->animation_duration), 1); - flipper_format_write_comment_cstr( - file, "Card animation margin in ms (how long the card will stay besides the played hand)"); - flipper_format_write_uint32(file, CONF_ANIMATION_MARGIN, &(settings->animation_margin), 1); flipper_format_write_comment_cstr(file, "Popup message duration in ms"); flipper_format_write_uint32(file, CONF_MESSAGE_DURATION, &(settings->message_duration), 1); flipper_format_write_comment_cstr(file, "Player's starting money"); @@ -145,70 +50,65 @@ Settings load_settings() { Settings settings; FURI_LOG_D(APP_NAME, "Loading default settings"); - settings.animation_margin = 200; - settings.animation_duration = 1500; + settings.animation_duration = 800; settings.message_duration = 1500; settings.starting_money = 200; settings.round_price = 10; settings.sound_effects = true; FURI_LOG_D(APP_NAME, "Opening storage"); - Storage* storage = furi_record_open(RECORD_STORAGE); + Storage *storage = furi_record_open(RECORD_STORAGE); FURI_LOG_D(APP_NAME, "Allocating file"); - FlipperFormat* file = flipper_format_file_alloc(storage); + FlipperFormat *file = flipper_format_file_alloc(storage); FURI_LOG_D(APP_NAME, "Allocating string"); - FuriString* string_value; + FuriString *string_value; string_value = furi_string_alloc(); - if(storage_common_stat(storage, CONFIG_FILE_PATH, NULL) != FSE_OK) { + if (storage_common_stat(storage, CONFIG_FILE_PATH, NULL) != FSE_OK) { FURI_LOG_D(APP_NAME, "Config file %s not found, creating new one...", CONFIG_FILE_PATH); - if(!flipper_format_file_open_new(file, CONFIG_FILE_PATH)) { + if (!flipper_format_file_open_new(file, CONFIG_FILE_PATH)) { FURI_LOG_E(APP_NAME, "Error creating new file %s", CONFIG_FILE_PATH); flipper_format_file_close(file); } else { save_settings_file(file, &settings); } } else { - if(!flipper_format_file_open_existing(file, CONFIG_FILE_PATH)) { + if (!flipper_format_file_open_existing(file, CONFIG_FILE_PATH)) { FURI_LOG_E(APP_NAME, "Error opening existing file %s", CONFIG_FILE_PATH); flipper_format_file_close(file); - } else { + } + else { uint32_t value; bool valueBool; FURI_LOG_D(APP_NAME, "Checking version"); - if(!flipper_format_read_header(file, string_value, &value)) { + if (!flipper_format_read_header(file, string_value, &value)) { FURI_LOG_E(APP_NAME, "Config file mismatch"); } else { FURI_LOG_D(APP_NAME, "Loading %s", CONF_ANIMATION_DURATION); - if(flipper_format_read_uint32(file, CONF_ANIMATION_DURATION, &value, 1)) { + if (flipper_format_read_uint32(file, CONF_ANIMATION_DURATION, &value, 1)) { settings.animation_duration = value; FURI_LOG_D(APP_NAME, "Loaded %s: %ld", CONF_ANIMATION_DURATION, value); } - FURI_LOG_D(APP_NAME, "Loading %s", CONF_ANIMATION_MARGIN); - if(flipper_format_read_uint32(file, CONF_ANIMATION_MARGIN, &value, 1)) { - settings.animation_margin = value; - FURI_LOG_D(APP_NAME, "Loaded %s: %ld", CONF_ANIMATION_MARGIN, value); - } FURI_LOG_D(APP_NAME, "Loading %s", CONF_MESSAGE_DURATION); - if(flipper_format_read_uint32(file, CONF_MESSAGE_DURATION, &value, 1)) { + if (flipper_format_read_uint32(file, CONF_MESSAGE_DURATION, &value, 1)) { settings.message_duration = value; FURI_LOG_D(APP_NAME, "Loaded %s: %ld", CONF_MESSAGE_DURATION, value); } FURI_LOG_D(APP_NAME, "Loading %s", CONF_STARTING_MONEY); - if(flipper_format_read_uint32(file, CONF_STARTING_MONEY, &value, 1)) { + if (flipper_format_read_uint32(file, CONF_STARTING_MONEY, &value, 1)) { settings.starting_money = value; FURI_LOG_D(APP_NAME, "Loaded %s: %ld", CONF_STARTING_MONEY, value); } FURI_LOG_D(APP_NAME, "Loading %s", CONF_ROUND_PRICE); - if(flipper_format_read_uint32(file, CONF_ROUND_PRICE, &value, 1)) { + if (flipper_format_read_uint32(file, CONF_ROUND_PRICE, &value, 1)) { settings.round_price = value; FURI_LOG_D(APP_NAME, "Loaded %s: %ld", CONF_ROUND_PRICE, value); } FURI_LOG_D(APP_NAME, "Loading %s", CONF_SOUND_EFFECTS); - if(flipper_format_read_bool(file, CONF_SOUND_EFFECTS, &valueBool, 1)) { + if (flipper_format_read_bool(file, CONF_SOUND_EFFECTS, &valueBool, 1)) { settings.sound_effects = valueBool; - FURI_LOG_D(APP_NAME, "Loaded %s: %i", CONF_ROUND_PRICE, valueBool ? 1 : 0); + FURI_LOG_D(APP_NAME, "Loaded %s: %i", CONF_ROUND_PRICE, valueBool?1:0); } } flipper_format_file_close(file); @@ -216,7 +116,7 @@ Settings load_settings() { } furi_string_free(string_value); - // flipper_format_file_close(file); +// flipper_format_file_close(file); flipper_format_free(file); furi_record_close(RECORD_STORAGE); return settings; diff --git a/applications/plugins/blackjack/util.h b/applications/plugins/blackjack/util.h index 99c0f5eeb..4bcc4d890 100644 --- a/applications/plugins/blackjack/util.h +++ b/applications/plugins/blackjack/util.h @@ -3,41 +3,5 @@ #define CONFIG_FILE_HEADER "Blackjack config file" #define CONFIG_FILE_VERSION 1 -typedef struct { - void (*callback)(GameState* game_state); - void (*processing)( - const GameState* game_state, - Canvas* const canvas, - uint32_t duration, - uint32_t margin); - void (*start)(GameState* game_state); - void* next; - uint32_t duration; - uint32_t margin; -} QueueItem; - -struct Vector { - float x; - float y; -}; - -float lerp(float v0, float v1, float t); -void queue( - GameState* game_state, - void (*callback)(GameState* game_state), - void (*start)(GameState* game_state), - void (*processing)( - const GameState* gameState, - Canvas* const canvas, - uint32_t duration, - uint32_t margin), - uint32_t duration, - uint32_t margin); -bool run_queue(GameState* gameState); -void animateQueue(const GameState* gameState, Canvas* const canvas); -void queue_clear(); -Vector lerp_2d(Vector start, Vector end, float t); -Vector quadratic_2d(Vector start, Vector control, Vector end, float t); - void save_settings(Settings settings); Settings load_settings(); \ No newline at end of file diff --git a/applications/plugins/temperature_sensor/temperature_sensor.c b/applications/plugins/temperature_sensor/temperature_sensor.c index 9ffa4719d..02679110a 100644 --- a/applications/plugins/temperature_sensor/temperature_sensor.c +++ b/applications/plugins/temperature_sensor/temperature_sensor.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -11,12 +12,12 @@ #include -#define TS_DEFAULT_VALUE 0xFFFF +#define TS_DEFAULT_VALUE 0xFFFF -#define HTU21D_ADDRESS (0x40 << 1) +#define HTU21D_ADDRESS (0x40 << 1) -#define HTU21D_CMD_TEMPERATURE 0xE3 -#define HTU21D_CMD_HUMIDITY 0xE5 +#define HTU21D_CMD_TEMPERATURE 0xE3 +#define HTU21D_CMD_HUMIDITY 0xE5 #define DATA_BUFFER_SIZE 8 @@ -24,19 +25,19 @@ #define I2C_BUS &furi_hal_i2c_handle_external typedef enum { - TSSInitializing, - TSSNoSensor, - TSSPendingUpdate, + TSSInitializing, + TSSNoSensor, + TSSPendingUpdate, } TSStatus; typedef enum { - TSEventTypeTick, - TSEventTypeInput, + TSEventTypeTick, + TSEventTypeInput, } TSEventType; typedef struct { - TSEventType type; - InputEvent input; + TSEventType type; + InputEvent input; } TSEvent; extern const NotificationSequence sequence_blink_red_100; @@ -47,7 +48,8 @@ static TSStatus temperature_sensor_current_status = TSSInitializing; // Temperature and Humidity data buffers, ready to print char ts_data_buffer_temperature_c[DATA_BUFFER_SIZE]; char ts_data_buffer_temperature_f[DATA_BUFFER_SIZE]; -char ts_data_buffer_humidity[DATA_BUFFER_SIZE]; +char ts_data_buffer_relative_humidity[DATA_BUFFER_SIZE]; +char ts_data_buffer_absolute_humidity[DATA_BUFFER_SIZE]; // // Executes an I2C cmd (trx) @@ -56,32 +58,36 @@ char ts_data_buffer_humidity[DATA_BUFFER_SIZE]; // true if fetch was successful, false otherwise // static bool temperature_sensor_cmd(uint8_t cmd, uint8_t* buffer, uint8_t size) { - uint32_t timeout = furi_ms_to_ticks(100); - bool ret = false; - // Aquire I2C and check if device is ready, then release - furi_hal_i2c_acquire(I2C_BUS); - if(furi_hal_i2c_is_device_ready(I2C_BUS, HTU21D_ADDRESS, timeout)) { - furi_hal_i2c_release(I2C_BUS); + uint32_t timeout = furi_ms_to_ticks(100); + bool ret = false; - furi_hal_i2c_acquire(I2C_BUS); - // Transmit given command - ret = furi_hal_i2c_tx(I2C_BUS, HTU21D_ADDRESS, &cmd, 1, timeout); - furi_hal_i2c_release(I2C_BUS); + // Aquire I2C and check if device is ready, then release + furi_hal_i2c_acquire(I2C_BUS); + if (furi_hal_i2c_is_device_ready(I2C_BUS, HTU21D_ADDRESS, timeout)) + { + furi_hal_i2c_release(I2C_BUS); - if(ret) { - uint32_t wait_ticks = furi_ms_to_ticks(50); - furi_delay_tick(wait_ticks); + furi_hal_i2c_acquire(I2C_BUS); + // Transmit given command + ret = furi_hal_i2c_tx(I2C_BUS, HTU21D_ADDRESS, &cmd, 1, timeout); + furi_hal_i2c_release(I2C_BUS); - furi_hal_i2c_acquire(I2C_BUS); - // Receive data - ret = furi_hal_i2c_rx(I2C_BUS, HTU21D_ADDRESS, buffer, size, timeout); - furi_hal_i2c_release(I2C_BUS); - } - } else - furi_hal_i2c_release(I2C_BUS); + if (ret) + { + uint32_t wait_ticks = furi_ms_to_ticks(50); + furi_delay_tick(wait_ticks); - return ret; + furi_hal_i2c_acquire(I2C_BUS); + // Receive data + ret = furi_hal_i2c_rx(I2C_BUS, HTU21D_ADDRESS, buffer, size, timeout); + furi_hal_i2c_release(I2C_BUS); + } + } + else + furi_hal_i2c_release(I2C_BUS); + + return ret; } // @@ -95,185 +101,212 @@ static bool temperature_sensor_cmd(uint8_t cmd, uint8_t* buffer, uint8_t size) { // true if fetch was successful, false otherwise // static bool temperature_sensor_fetch_data(double* temperature, double* humidity) { - bool ret = false; + bool ret = false; - uint16_t adc_raw; + uint16_t adc_raw; - uint8_t buffer[2] = {0x00}; + uint8_t buffer[2] = { 0x00 }; - // Fetch temperature - ret = temperature_sensor_cmd((uint8_t)HTU21D_CMD_TEMPERATURE, buffer, 2); + // Fetch temperature + ret = temperature_sensor_cmd((uint8_t)HTU21D_CMD_TEMPERATURE, buffer, 2); - if(ret) { - // Calculate temperature - adc_raw = ((uint16_t)(buffer[0] << 8) | (buffer[1])); - *temperature = (float)(adc_raw * 175.72 / 65536.00) - 46.85; + if (ret) + { + // Calculate temperature + adc_raw = ((uint16_t)(buffer[0] << 8) | (buffer[1])); + *temperature = (float)(adc_raw * 175.72 / 65536.00) - 46.85; - // Fetch humidity - ret = temperature_sensor_cmd((uint8_t)HTU21D_CMD_TEMPERATURE, buffer, 2); + // Fetch humidity + ret = temperature_sensor_cmd((uint8_t)HTU21D_CMD_TEMPERATURE, buffer, 2); - if(ret) { - // Calculate humidity - adc_raw = ((uint16_t)(buffer[0] << 8) | (buffer[1])); - *humidity = (float)(adc_raw * 125.0 / 65536.00) - 6.0; - } - } + if (ret) + { + // Calculate humidity + adc_raw = ((uint16_t)(buffer[0] << 8) | (buffer[1])); + *humidity = (float)(adc_raw * 125.0 / 65536.00) - 6.0; + } + } - return ret; + return ret; } + // // Draw callback // static void temperature_sensor_draw_callback(Canvas* canvas, void* ctx) { - UNUSED(ctx); - canvas_clear(canvas); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 2, 10, "HTU21D Sensor"); + UNUSED(ctx); - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 2, 62, "Press back to exit."); + canvas_clear(canvas); + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 2, 10, "HTU21D/Si7021 Sensor"); - switch(temperature_sensor_current_status) { - case TSSInitializing: - canvas_draw_str(canvas, 2, 30, "Initializing.."); - break; - case TSSNoSensor: - canvas_draw_str(canvas, 2, 30, "No sensor found!"); - break; - case TSSPendingUpdate: { - canvas_draw_str(canvas, 6, 24, "Temperature"); - canvas_draw_str(canvas, 80, 24, "Humidity"); + canvas_set_font(canvas, FontSecondary); + canvas_draw_str(canvas, 2, 62, "Press back to exit."); - // Draw vertical lines - canvas_draw_line(canvas, 68, 16, 68, 50); - canvas_draw_line(canvas, 69, 16, 69, 50); + switch (temperature_sensor_current_status) { + case TSSInitializing: + canvas_draw_str(canvas, 2, 30, "Initializing.."); + break; + case TSSNoSensor: + canvas_draw_str(canvas, 2, 30, "No sensor found!"); + break; + case TSSPendingUpdate: { - // Draw horizontal line - canvas_draw_line(canvas, 3, 27, 144, 27); + canvas_draw_str(canvas, 3, 24, "Temperature"); + canvas_draw_str(canvas, 68, 24, "Humidity"); - // Draw temperature and humidity values - canvas_draw_str(canvas, 14, 38, ts_data_buffer_temperature_c); - canvas_draw_str(canvas, 48, 38, "C"); - canvas_draw_str(canvas, 14, 48, ts_data_buffer_temperature_f); - canvas_draw_str(canvas, 48, 48, "F"); - canvas_draw_str(canvas, 78, 42, ts_data_buffer_humidity); - canvas_draw_str(canvas, 112, 42, "%"); + // Draw vertical lines + canvas_draw_line(canvas, 61, 16, 61, 50); + canvas_draw_line(canvas, 62, 16, 62, 50); + + // Draw horizontal line + canvas_draw_line(canvas, 2, 27, 122, 27); + + // Draw temperature and humidity values + canvas_draw_str(canvas, 8, 38, ts_data_buffer_temperature_c); + canvas_draw_str(canvas, 42, 38, "C"); + canvas_draw_str(canvas, 8, 48, ts_data_buffer_temperature_f); + canvas_draw_str(canvas, 42, 48, "F"); + canvas_draw_str(canvas, 68, 38, ts_data_buffer_relative_humidity); + canvas_draw_str(canvas, 100, 38, "%"); + canvas_draw_str(canvas, 68, 48, ts_data_buffer_absolute_humidity); + canvas_draw_str(canvas, 100, 48, "g/m3"); + + } break; + default: + break; + } - } break; - default: - break; - } } // // Input callback // static void temperature_sensor_input_callback(InputEvent* input_event, void* ctx) { - furi_assert(ctx); - FuriMessageQueue* event_queue = ctx; - TSEvent event = {.type = TSEventTypeInput, .input = *input_event}; - furi_message_queue_put(event_queue, &event, FuriWaitForever); + furi_assert(ctx); + FuriMessageQueue* event_queue = ctx; + + TSEvent event = { .type = TSEventTypeInput, .input = *input_event }; + furi_message_queue_put(event_queue, &event, FuriWaitForever); + } // // Timer callback // static void temperature_sensor_timer_callback(FuriMessageQueue* event_queue) { - furi_assert(event_queue); - TSEvent event = {.type = TSEventTypeTick}; - furi_message_queue_put(event_queue, &event, 0); + furi_assert(event_queue); + + TSEvent event = { .type = TSEventTypeTick }; + furi_message_queue_put(event_queue, &event, 0); + } // // App entry point // int32_t temperature_sensor_app(void* p) { - UNUSED(p); - furi_hal_power_suppress_charge_enter(); - // Declare our variables - TSEvent tsEvent; - bool sensorFound = false; - double celsius, fahrenheit, humidity; + UNUSED(p); - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(TSEvent)); + // Declare our variables and assign variables a default value + TSEvent tsEvent; + bool sensorFound = false; + double celsius, fahrenheit, rel_humidity, abs_humidity = TS_DEFAULT_VALUE; - // Register callbacks - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, temperature_sensor_draw_callback, NULL); - view_port_input_callback_set(view_port, temperature_sensor_input_callback, event_queue); + // Used for absolute humidity calculation + double vapour_pressure = 0; - // Create timer and register its callback - FuriTimer* timer = - furi_timer_alloc(temperature_sensor_timer_callback, FuriTimerTypePeriodic, event_queue); - furi_timer_start(timer, furi_kernel_get_tick_frequency()); + FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(TSEvent)); - // Register viewport - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); + // Register callbacks + ViewPort* view_port = view_port_alloc(); + view_port_draw_callback_set(view_port, temperature_sensor_draw_callback, NULL); + view_port_input_callback_set(view_port, temperature_sensor_input_callback, event_queue); - // Used to notify the user by blinking red (error) or blue (fetch successful) - NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION); + // Create timer and register its callback + FuriTimer* timer = furi_timer_alloc(temperature_sensor_timer_callback, FuriTimerTypePeriodic, event_queue); + furi_timer_start(timer, furi_kernel_get_tick_frequency()); - // Assign variables a default value - celsius = fahrenheit = humidity = TS_DEFAULT_VALUE; + // Register viewport + Gui* gui = furi_record_open(RECORD_GUI); + gui_add_view_port(gui, view_port, GuiLayerFullscreen); - while(1) { - furi_check(furi_message_queue_get(event_queue, &tsEvent, FuriWaitForever) == FuriStatusOk); + // Used to notify the user by blinking red (error) or blue (fetch successful) + NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION); - // Handle events - if(tsEvent.type == TSEventTypeInput) { - // Exit on back key - if(tsEvent.input.key == - InputKeyBack) // We dont check for type here, we can check the type of keypress like: (event.input.type == InputTypeShort) - break; + while (1) { - } else if(tsEvent.type == TSEventTypeTick) { - // Update sensor data - // Fetch data and set the sensor current status accordingly - sensorFound = temperature_sensor_fetch_data(&celsius, &humidity); - temperature_sensor_current_status = (sensorFound ? TSSPendingUpdate : TSSNoSensor); + furi_check(furi_message_queue_get(event_queue, &tsEvent, FuriWaitForever) == FuriStatusOk); - if(sensorFound) { - // Blink blue - notification_message(notifications, &sequence_blink_blue_100); + // Handle events + if (tsEvent.type == TSEventTypeInput) { - if(celsius != TS_DEFAULT_VALUE && humidity != TS_DEFAULT_VALUE) { - // Convert celsius to fahrenheit - fahrenheit = (celsius * 9 / 5) + 32; + // Exit on back key + if (tsEvent.input.key == InputKeyBack) // We dont check for type here, we can check the type of keypress like: (event.input.type == InputTypeShort) + break; - // Fill our buffers here, not on the canvas draw callback - snprintf(ts_data_buffer_temperature_c, DATA_BUFFER_SIZE, "%.2f", celsius); - snprintf(ts_data_buffer_temperature_f, DATA_BUFFER_SIZE, "%.2f", fahrenheit); - snprintf(ts_data_buffer_humidity, DATA_BUFFER_SIZE, "%.2f", humidity); - } + } + else if (tsEvent.type == TSEventTypeTick) { - } else { - // Reset our variables to their default values - celsius = fahrenheit = humidity = TS_DEFAULT_VALUE; + // Update sensor data + // Fetch data and set the sensor current status accordingly + sensorFound = temperature_sensor_fetch_data(&celsius, &rel_humidity); + temperature_sensor_current_status = (sensorFound ? TSSPendingUpdate : TSSNoSensor); - // Blink red - notification_message(notifications, &sequence_blink_red_100); - } - } + if (sensorFound) { - uint32_t wait_ticks = furi_ms_to_ticks(!sensorFound ? 100 : 500); - furi_delay_tick(wait_ticks); - } + // Blink blue + notification_message(notifications, &sequence_blink_blue_100); - furi_hal_power_suppress_charge_exit(); - // Dobby is freee (free our variables, Flipper will crash if we don't do this!) - furi_timer_free(timer); - gui_remove_view_port(gui, view_port); - view_port_free(view_port); - furi_message_queue_free(event_queue); + if (celsius != TS_DEFAULT_VALUE && rel_humidity != TS_DEFAULT_VALUE) { - furi_record_close(RECORD_NOTIFICATION); - furi_record_close(RECORD_GUI); + // Convert celsius to fahrenheit + fahrenheit = (celsius * 9 / 5) + 32; - return 0; + // Calculate absolute humidity - For more info refer to https://github.com/Mywk/FlipperTemperatureSensor/issues/1 + // Calculate saturation vapour pressure first + vapour_pressure = (double)6.11 * pow(10, (double)(((double)7.5 * celsius) / ((double)237.3 + celsius))); + // Then the vapour pressure in Pa + vapour_pressure = vapour_pressure * rel_humidity; + // Calculate absolute humidity + abs_humidity = (double)2.16679 * (double)(vapour_pressure / ((double)273.15 + celsius)); + + // Fill our buffers here, not on the canvas draw callback + snprintf(ts_data_buffer_temperature_c, DATA_BUFFER_SIZE, "%.2f", celsius); + snprintf(ts_data_buffer_temperature_f, DATA_BUFFER_SIZE, "%.2f", fahrenheit); + snprintf(ts_data_buffer_relative_humidity, DATA_BUFFER_SIZE, "%.2f", rel_humidity); + snprintf(ts_data_buffer_absolute_humidity, DATA_BUFFER_SIZE, "%.2f", abs_humidity); + } + + } + else { + + // Reset our variables to their default values + celsius = fahrenheit = rel_humidity = abs_humidity = TS_DEFAULT_VALUE; + + // Blink red + notification_message(notifications, &sequence_blink_red_100); + + } + } + + uint32_t wait_ticks = furi_ms_to_ticks(!sensorFound ? 100 : 500); + furi_delay_tick(wait_ticks); + } + + // Dobby is freee (free our variables, Flipper will crash if we don't do this!) + furi_timer_free(timer); + gui_remove_view_port(gui, view_port); + view_port_free(view_port); + furi_message_queue_free(event_queue); + + furi_record_close(RECORD_NOTIFICATION); + furi_record_close(RECORD_GUI); + + return 0; }