mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-07-13 23:58:11 -07:00
fmt fixes
This commit is contained in:
@@ -14,70 +14,68 @@
|
||||
|
||||
#define DEALER_MAX 17
|
||||
|
||||
void start_round(GameState *game_state);
|
||||
void start_round(GameState* game_state);
|
||||
|
||||
void init(GameState *game_state);
|
||||
|
||||
static void draw_ui(Canvas *const canvas, const GameState *game_state) {
|
||||
void init(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));
|
||||
|
||||
if (!game_state->animating && game_state->state == GameStatePlay) {
|
||||
if(!game_state->animating && game_state->state == GameStatePlay) {
|
||||
draw_play_menu(canvas, game_state);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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(GameState* game_state) {
|
||||
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))
|
||||
if(game_state->selectedMenu == 0 &&
|
||||
(game_state->player_score < game_state->settings.round_price || game_state->doubled))
|
||||
game_state->selectedMenu = 1;
|
||||
}
|
||||
|
||||
void drawDealerCard(GameState *game_state) {
|
||||
void drawDealerCard(GameState* game_state) {
|
||||
Card c = draw_card(game_state);
|
||||
game_state->dealer_cards[game_state->dealer_card_count] = c;
|
||||
game_state->dealer_card_count++;
|
||||
@@ -85,326 +83,393 @@ 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) {
|
||||
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;
|
||||
if(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) {
|
||||
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;
|
||||
if(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) {
|
||||
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;
|
||||
if(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) {
|
||||
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;
|
||||
if(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) {
|
||||
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;
|
||||
if(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) {
|
||||
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;
|
||||
if(duration == 0) return;
|
||||
popup_frame(canvas);
|
||||
elements_multiline_text_aligned(canvas, 64, 22, AlignCenter, AlignCenter, "Round started");
|
||||
}
|
||||
|
||||
void before_start(GameState *gameState) {
|
||||
void before_start(GameState* gameState) {
|
||||
gameState->dealer_card_count = 0;
|
||||
gameState->player_card_count = 0;
|
||||
}
|
||||
|
||||
|
||||
void start(GameState *game_state) {
|
||||
void start(GameState* game_state) {
|
||||
start_round(game_state);
|
||||
}
|
||||
|
||||
void draw(GameState *game_state) {
|
||||
void draw(GameState* game_state) {
|
||||
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);
|
||||
}
|
||||
|
||||
void game_over(GameState *game_state) {
|
||||
void game_over(GameState* game_state) {
|
||||
game_state->state = GameStateGameOver;
|
||||
}
|
||||
|
||||
void lose(GameState *game_state) {
|
||||
void lose(GameState* game_state) {
|
||||
game_state->state = GameStatePlay;
|
||||
game_state->bet = 0;
|
||||
if (game_state->player_score >= game_state->settings.round_price)
|
||||
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);
|
||||
}
|
||||
|
||||
void win(GameState *game_state) {
|
||||
void win(GameState* game_state) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
void dealerTurn(GameState *game_state) {
|
||||
void dealerTurn(GameState* game_state) {
|
||||
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);
|
||||
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);
|
||||
|
||||
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);
|
||||
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);
|
||||
} 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);
|
||||
// drawPlayerDeck(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);
|
||||
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 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 GameState* game_state,
|
||||
Canvas* const canvas,
|
||||
uint32_t duration,
|
||||
uint32_t margin) {
|
||||
float t = (float)(furi_get_tick() - game_state->animationStart) / (duration - margin);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
//endregion
|
||||
|
||||
void player_tick(GameState *game_state) {
|
||||
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) {
|
||||
if((game_state->doubled && score <= 21) || score == 21) {
|
||||
queue(game_state, dealerTurn, NULL, NULL, game_state->settings.message_duration, 0);
|
||||
} else if (score > 21) {
|
||||
} else if(score > 21) {
|
||||
queue(game_state, lose, NULL, to_bust_state, game_state->settings.message_duration, 0);
|
||||
} else {
|
||||
if (game_state->selectDirection == DirectionUp && game_state->selectedMenu > 0 &&
|
||||
game_state->player_score >= game_state->settings.round_price && !game_state->doubled) {
|
||||
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 == DirectionDown && game_state->selectedMenu < 2) {
|
||||
if(game_state->selectDirection == DirectionDown && game_state->selectedMenu < 2) {
|
||||
game_state->selectedMenu++;
|
||||
}
|
||||
if (game_state->selectDirection == Select) {
|
||||
if(game_state->selectDirection == Select) {
|
||||
//double
|
||||
if (!game_state->doubled && game_state->selectedMenu == 0 &&
|
||||
game_state->player_score >= game_state->settings.round_price) {
|
||||
|
||||
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];
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
else if(game_state->selectedMenu == 2) {
|
||||
queue(
|
||||
game_state,
|
||||
dealerTurn,
|
||||
NULL,
|
||||
to_dealer_turn,
|
||||
game_state->settings.message_duration,
|
||||
0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dealer_tick(GameState *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);
|
||||
|
||||
if (dealer_score >= DEALER_MAX) {
|
||||
if (dealer_score > 21 || dealer_score < player_score)
|
||||
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)
|
||||
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)
|
||||
else if(dealer_score == player_score)
|
||||
queue(game_state, draw, NULL, to_draw_state, game_state->settings.message_duration, 0);
|
||||
} else {
|
||||
queue(game_state, drawDealerCard, NULL, dealer_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);
|
||||
}
|
||||
}
|
||||
|
||||
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_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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void tick(GameState *game_state) {
|
||||
void tick(GameState* game_state) {
|
||||
game_state->last_tick = furi_get_tick();
|
||||
bool queue_ran = run_queue(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;
|
||||
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;
|
||||
}
|
||||
|
||||
game_state->selectDirection = None;
|
||||
|
||||
}
|
||||
|
||||
void start_round(GameState *game_state) {
|
||||
void start_round(GameState* game_state) {
|
||||
game_state->player_card_count = 0;
|
||||
game_state->dealer_card_count = 0;
|
||||
game_state->selectedMenu = 0;
|
||||
@@ -415,7 +480,7 @@ void start_round(GameState *game_state) {
|
||||
shuffleDeck(&(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;
|
||||
@@ -423,7 +488,7 @@ void start_round(GameState *game_state) {
|
||||
game_state->state = GameStatePlay;
|
||||
}
|
||||
|
||||
void init(GameState *game_state) {
|
||||
void init(GameState* game_state) {
|
||||
game_state->settings = load_settings();
|
||||
game_state->last_tick = 0;
|
||||
game_state->processing = true;
|
||||
@@ -432,82 +497,80 @@ void init(GameState *game_state) {
|
||||
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) {
|
||||
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));
|
||||
init(game_state);
|
||||
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* 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;
|
||||
}
|
||||
}
|
||||
} else if (event.type == EventTypeTick) {
|
||||
} else if(event.type == EventTypeTick) {
|
||||
tick(game_state);
|
||||
processing = game_state->processing;
|
||||
}
|
||||
@@ -519,7 +582,6 @@ int32_t blackjack_app(void *p) {
|
||||
release_mutex(&state_mutex, game_state);
|
||||
}
|
||||
|
||||
|
||||
furi_timer_free(timer);
|
||||
view_port_enabled_set(view_port, false);
|
||||
gui_remove_view_port(gui, view_port);
|
||||
@@ -527,7 +589,7 @@ int32_t blackjack_app(void *p) {
|
||||
view_port_free(view_port);
|
||||
delete_mutex(&state_mutex);
|
||||
|
||||
free_and_exit:
|
||||
free_and_exit:
|
||||
queue_clear();
|
||||
free(game_state);
|
||||
furi_message_queue_free(event_queue);
|
||||
|
||||
@@ -3,150 +3,133 @@
|
||||
#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 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
|
||||
};
|
||||
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 characters[13] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K', 'A'};
|
||||
|
||||
uint8_t edge_cards[3] = {
|
||||
0, 8, 15
|
||||
};
|
||||
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},
|
||||
//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++) {
|
||||
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)
|
||||
if(playerCardPositions[i][2] == 1 && playerCardPositions[i][3] == 1)
|
||||
state = BottomAndRightCut;
|
||||
else if (playerCardPositions[i][3] == 1)
|
||||
else if(playerCardPositions[i][3] == 1)
|
||||
state = RightCut;
|
||||
else if (playerCardPositions[i][2] == 1)
|
||||
else if(playerCardPositions[i][2] == 1)
|
||||
state = BottomCut;
|
||||
drawCardAt(playerCardPositions[i][0], playerCardPositions[i][1], cards[i].pip, cards[i].character, state,
|
||||
canvas);
|
||||
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;
|
||||
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]
|
||||
};
|
||||
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) {
|
||||
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 || 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 == 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 == 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
|
||||
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;
|
||||
@@ -154,12 +137,12 @@ void drawCardAt(int8_t pos_x, int8_t pos_y, uint8_t pip, uint8_t character, Card
|
||||
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)
|
||||
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)
|
||||
if(state == Normal || state == RightCut)
|
||||
canvas_draw_dot(canvas, left + x - 1, bottom + y);
|
||||
}
|
||||
}
|
||||
@@ -167,7 +150,7 @@ void drawCardAt(int8_t pos_x, int8_t pos_y, uint8_t pip, uint8_t character, Card
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
char drawChar[3];
|
||||
if (character < 9)
|
||||
if(character < 9)
|
||||
snprintf(drawChar, sizeof(drawChar), "%i", character + 2);
|
||||
else {
|
||||
snprintf(drawChar, sizeof(drawChar), "%c", characters[character]);
|
||||
@@ -177,54 +160,52 @@ void drawCardAt(int8_t pos_x, int8_t pos_y, uint8_t pip, uint8_t character, Card
|
||||
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
|
||||
if(state == Normal) { //flipper crashes on non center aligned text when upside down
|
||||
uint8_t margin = 9;
|
||||
if (character == 8) //10 needs bigger margin
|
||||
if(character == 8) //10 needs bigger margin
|
||||
margin = 12;
|
||||
canvas_draw_str_aligned(canvas, right + margin, bottom - 3, AlignCenter, AlignCenter, drawChar);
|
||||
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) {
|
||||
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++) {
|
||||
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]) {
|
||||
if(backDesign[(_x + _y) % 4]) {
|
||||
canvas_draw_dot(canvas, pos_x + x + 1, pos_y + y + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void generateDeck(Deck *deck_ptr) {
|
||||
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
|
||||
};
|
||||
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) {
|
||||
void shuffleDeck(Deck* deck_ptr) {
|
||||
srand(DWT->CYCCNT);
|
||||
deck_ptr->index = 0;
|
||||
int max = DECK_COUNT * 52;
|
||||
for (int i = 0; i < max; i++) {
|
||||
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];
|
||||
@@ -236,41 +217,54 @@ 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)
|
||||
for(uint8_t i = 0; i < count; i++) {
|
||||
if(cards[i].character == 12)
|
||||
aceCount++;
|
||||
else {
|
||||
if (cards[i].character > 8)
|
||||
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++;
|
||||
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) {
|
||||
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) {
|
||||
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);
|
||||
if(t > 1) {
|
||||
drawCardAt(
|
||||
currentPos.x, currentPos.y, animatingCard.pip, animatingCard.character, Normal, canvas);
|
||||
} else {
|
||||
if (t < 0.5)
|
||||
if(t < 0.5)
|
||||
drawCardBackAt(currentPos.x, currentPos.y, canvas);
|
||||
else
|
||||
drawCardAt(currentPos.x, currentPos.y, animatingCard.pip,
|
||||
animatingCard.character, Normal, canvas);
|
||||
drawCardAt(
|
||||
currentPos.x,
|
||||
currentPos.y,
|
||||
animatingCard.pip,
|
||||
animatingCard.character,
|
||||
Normal,
|
||||
canvas);
|
||||
}
|
||||
}
|
||||
@@ -5,15 +5,21 @@
|
||||
|
||||
#define DECK_COUNT 6
|
||||
#define CARD_HEIGHT 24
|
||||
#define CARD_HALF_HEIGHT CARD_HEIGHT/2
|
||||
#define CARD_HALF_HEIGHT CARD_HEIGHT / 2
|
||||
#define CARD_WIDTH 18
|
||||
#define CARD_HALF_WIDTH CARD_WIDTH/2
|
||||
#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
|
||||
Normal,
|
||||
BottomCut,
|
||||
RightCut,
|
||||
BottomAndRightCut,
|
||||
TopCut,
|
||||
LeftCut,
|
||||
TopAndLeftCut
|
||||
} CardState;
|
||||
|
||||
typedef struct {
|
||||
@@ -26,17 +32,30 @@ typedef struct {
|
||||
int index;
|
||||
} Deck;
|
||||
|
||||
void drawPlayerDeck(const Card cards[21], uint8_t count, Canvas *const canvas);
|
||||
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 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 drawCardBackAt(int8_t pos_x, int8_t pos_y, Canvas* const canvas);
|
||||
|
||||
void generateDeck(Deck *deck_ptr);
|
||||
void generateDeck(Deck* deck_ptr);
|
||||
|
||||
void shuffleDeck(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);
|
||||
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);
|
||||
|
||||
@@ -23,7 +23,7 @@ typedef enum {
|
||||
EventTypeKey,
|
||||
} EventType;
|
||||
|
||||
typedef struct{
|
||||
typedef struct {
|
||||
uint32_t animation_margin;
|
||||
uint32_t animation_duration;
|
||||
uint32_t message_duration;
|
||||
@@ -45,14 +45,7 @@ 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];
|
||||
@@ -75,4 +68,3 @@ typedef struct {
|
||||
unsigned int last_tick;
|
||||
unsigned int animationStart;
|
||||
} GameState;
|
||||
|
||||
|
||||
@@ -8,32 +8,33 @@
|
||||
#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) drawPlayerDeck((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) drawCardBackAt(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) {
|
||||
drawCardAt(
|
||||
2,
|
||||
2,
|
||||
game_state->dealer_cards[1].pip,
|
||||
game_state->dealer_cards[1].character,
|
||||
Normal,
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -41,15 +42,16 @@ 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 {
|
||||
@@ -59,7 +61,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);
|
||||
@@ -67,35 +69,34 @@ 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;
|
||||
}
|
||||
@@ -106,83 +107,95 @@ 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) {
|
||||
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(y < 0 || y >= 64) return;
|
||||
|
||||
if (selected) {
|
||||
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;
|
||||
|
||||
|
||||
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
|
||||
);
|
||||
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,
|
||||
"Anim. margin",
|
||||
drawChar,
|
||||
2 * LINE_HEIGHT + startY,
|
||||
gameState->settings.animation_margin > 0,
|
||||
gameState->settings.animation_margin < gameState->settings.animation_duration,
|
||||
gameState->selectedMenu == 2);
|
||||
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,
|
||||
3 * LINE_HEIGHT + startY,
|
||||
gameState->settings.animation_duration > gameState->settings.animation_margin,
|
||||
gameState->settings.animation_duration < 2000,
|
||||
gameState->selectedMenu == 3);
|
||||
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,
|
||||
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
|
||||
// );
|
||||
}
|
||||
@@ -4,16 +4,16 @@
|
||||
#include "util.h"
|
||||
#include <gui/gui.h>
|
||||
|
||||
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);
|
||||
|
||||
@@ -1,37 +1,37 @@
|
||||
#include "util.h"
|
||||
|
||||
const char *CONFIG_FILE_PATH = EXT_PATH(".blackjack.settings");
|
||||
const char* CONFIG_FILE_PATH = EXT_PATH(".blackjack.settings");
|
||||
|
||||
static QueueItem *afterDelay;
|
||||
static QueueItem* afterDelay;
|
||||
|
||||
float lerp(float v0, float v1, float t) {
|
||||
if (t > 1) return v1;
|
||||
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),
|
||||
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
|
||||
);
|
||||
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) {
|
||||
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;
|
||||
@@ -41,45 +41,48 @@ void queue(GameState *game_state,
|
||||
afterDelay->margin = margin;
|
||||
afterDelay->next = NULL;
|
||||
} else {
|
||||
QueueItem *next = afterDelay;
|
||||
while (next->next != NULL) { next = (QueueItem *) (next->next); }
|
||||
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;
|
||||
((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;
|
||||
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;
|
||||
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);
|
||||
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);
|
||||
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) {
|
||||
bool run_queue(GameState* game_state) {
|
||||
if(afterDelay != NULL) {
|
||||
game_state->animating = true;
|
||||
if ((game_state->last_tick - game_state->animationStart) > afterDelay->duration) {
|
||||
if((game_state->last_tick - game_state->animationStart) > afterDelay->duration) {
|
||||
dequeue(game_state);
|
||||
}
|
||||
return true;
|
||||
@@ -89,12 +92,14 @@ bool run_queue(GameState *game_state) {
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -108,10 +113,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);
|
||||
@@ -119,12 +124,12 @@ 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_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);
|
||||
@@ -148,62 +153,62 @@ Settings load_settings() {
|
||||
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 {
|
||||
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)) {
|
||||
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);
|
||||
@@ -211,7 +216,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;
|
||||
|
||||
@@ -3,29 +3,38 @@
|
||||
#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;
|
||||
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{
|
||||
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(
|
||||
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);
|
||||
|
||||
@@ -78,10 +78,10 @@ static void app_free(DTMFDolphinApp* app) {
|
||||
free(app);
|
||||
}
|
||||
|
||||
int32_t dtmf_dolphin_app(void *p) {
|
||||
int32_t dtmf_dolphin_app(void* p) {
|
||||
UNUSED(p);
|
||||
DTMFDolphinApp* app = app_alloc();
|
||||
|
||||
|
||||
view_dispatcher_run(app->view_dispatcher);
|
||||
|
||||
app_free(app);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "dtmf_dolphin_audio.h"
|
||||
|
||||
DTMFDolphinAudio *current_player;
|
||||
DTMFDolphinAudio* current_player;
|
||||
|
||||
static void dtmf_dolphin_audio_dma_isr(void* ctx) {
|
||||
FuriMessageQueue *event_queue = ctx;
|
||||
FuriMessageQueue* event_queue = ctx;
|
||||
|
||||
if (LL_DMA_IsActiveFlag_HT1(DMA1)) {
|
||||
if(LL_DMA_IsActiveFlag_HT1(DMA1)) {
|
||||
LL_DMA_ClearFlag_HT1(DMA1);
|
||||
|
||||
DTMFDolphinCustomEvent event = {.type = DTMFDolphinEventDMAHalfTransfer};
|
||||
@@ -21,13 +21,13 @@ static void dtmf_dolphin_audio_dma_isr(void* ctx) {
|
||||
}
|
||||
|
||||
void dtmf_dolphin_audio_clear_samples(DTMFDolphinAudio* player) {
|
||||
for (size_t i = 0; i < player->buffer_length; i++) {
|
||||
for(size_t i = 0; i < player->buffer_length; i++) {
|
||||
player->sample_buffer[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
DTMFDolphinOsc* dtmf_dolphin_osc_alloc() {
|
||||
DTMFDolphinOsc *osc = malloc(sizeof(DTMFDolphinOsc));
|
||||
DTMFDolphinOsc* osc = malloc(sizeof(DTMFDolphinOsc));
|
||||
osc->cached_freq = 0;
|
||||
osc->offset = 0;
|
||||
osc->period = 0;
|
||||
@@ -36,7 +36,7 @@ DTMFDolphinOsc* dtmf_dolphin_osc_alloc() {
|
||||
}
|
||||
|
||||
DTMFDolphinPulseFilter* dtmf_dolphin_pulse_filter_alloc() {
|
||||
DTMFDolphinPulseFilter *pf = malloc(sizeof(DTMFDolphinPulseFilter));
|
||||
DTMFDolphinPulseFilter* pf = malloc(sizeof(DTMFDolphinPulseFilter));
|
||||
pf->duration = 0;
|
||||
pf->period = 0;
|
||||
pf->offset = 0;
|
||||
@@ -45,7 +45,7 @@ DTMFDolphinPulseFilter* dtmf_dolphin_pulse_filter_alloc() {
|
||||
}
|
||||
|
||||
DTMFDolphinAudio* dtmf_dolphin_audio_alloc() {
|
||||
DTMFDolphinAudio *player = malloc(sizeof(DTMFDolphinAudio));
|
||||
DTMFDolphinAudio* player = malloc(sizeof(DTMFDolphinAudio));
|
||||
player->buffer_length = SAMPLE_BUFFER_LENGTH;
|
||||
player->half_buffer_length = SAMPLE_BUFFER_LENGTH / 2;
|
||||
player->sample_buffer = malloc(sizeof(uint16_t) * player->buffer_length);
|
||||
@@ -61,56 +61,58 @@ DTMFDolphinAudio* dtmf_dolphin_audio_alloc() {
|
||||
}
|
||||
|
||||
size_t calc_waveform_period(float freq) {
|
||||
if (!freq) {
|
||||
if(!freq) {
|
||||
return 0;
|
||||
}
|
||||
// DMA Rate calculation, thanks to Dr_Zlo
|
||||
float dma_rate = CPU_CLOCK_FREQ \
|
||||
/ 2 \
|
||||
/ DTMF_DOLPHIN_HAL_DMA_PRESCALER \
|
||||
/ (DTMF_DOLPHIN_HAL_DMA_AUTORELOAD + 1);
|
||||
float dma_rate = CPU_CLOCK_FREQ / 2 / DTMF_DOLPHIN_HAL_DMA_PRESCALER /
|
||||
(DTMF_DOLPHIN_HAL_DMA_AUTORELOAD + 1);
|
||||
|
||||
// Using a constant scaling modifier, which likely represents
|
||||
// the combined system overhead and isr latency.
|
||||
return (uint16_t) dma_rate * 2 / freq * 0.801923;
|
||||
return (uint16_t)dma_rate * 2 / freq * 0.801923;
|
||||
}
|
||||
|
||||
void osc_generate_lookup_table(DTMFDolphinOsc* osc, float freq) {
|
||||
if (osc->lookup_table != NULL) {
|
||||
if(osc->lookup_table != NULL) {
|
||||
free(osc->lookup_table);
|
||||
}
|
||||
osc->offset = 0;
|
||||
osc->cached_freq = freq;
|
||||
osc->period = calc_waveform_period(freq);
|
||||
if (!osc->period) {
|
||||
if(!osc->period) {
|
||||
osc->lookup_table = NULL;
|
||||
return;
|
||||
}
|
||||
osc->lookup_table = malloc(sizeof(float) * osc->period);
|
||||
|
||||
for (size_t i = 0; i < osc->period; i++) {
|
||||
for(size_t i = 0; i < osc->period; i++) {
|
||||
osc->lookup_table[i] = sin(i * PERIOD_2_PI / osc->period) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void filter_generate_lookup_table(DTMFDolphinPulseFilter* pf, uint16_t pulses, uint16_t pulse_ms, uint16_t gap_ms) {
|
||||
if (pf->lookup_table != NULL) {
|
||||
void filter_generate_lookup_table(
|
||||
DTMFDolphinPulseFilter* pf,
|
||||
uint16_t pulses,
|
||||
uint16_t pulse_ms,
|
||||
uint16_t gap_ms) {
|
||||
if(pf->lookup_table != NULL) {
|
||||
free(pf->lookup_table);
|
||||
}
|
||||
pf->offset = 0;
|
||||
|
||||
uint16_t gap_period = calc_waveform_period(1000 / (float) gap_ms);
|
||||
uint16_t pulse_period = calc_waveform_period(1000 / (float) pulse_ms);
|
||||
uint16_t gap_period = calc_waveform_period(1000 / (float)gap_ms);
|
||||
uint16_t pulse_period = calc_waveform_period(1000 / (float)pulse_ms);
|
||||
pf->period = pulse_period + gap_period;
|
||||
|
||||
if (!pf->period) {
|
||||
if(!pf->period) {
|
||||
pf->lookup_table = NULL;
|
||||
return;
|
||||
}
|
||||
pf->duration = pf->period * pulses;
|
||||
pf->lookup_table = malloc(sizeof(bool) * pf->duration);
|
||||
|
||||
for (size_t i = 0; i < pf->duration; i++) {
|
||||
for(size_t i = 0; i < pf->duration; i++) {
|
||||
pf->lookup_table[i] = i % pf->period < pulse_period;
|
||||
}
|
||||
}
|
||||
@@ -118,7 +120,7 @@ void filter_generate_lookup_table(DTMFDolphinPulseFilter* pf, uint16_t pulses, u
|
||||
float sample_frame(DTMFDolphinOsc* osc) {
|
||||
float frame = 0.0;
|
||||
|
||||
if (osc->period) {
|
||||
if(osc->period) {
|
||||
frame = osc->lookup_table[osc->offset];
|
||||
osc->offset = (osc->offset + 1) % osc->period;
|
||||
}
|
||||
@@ -129,8 +131,8 @@ float sample_frame(DTMFDolphinOsc* osc) {
|
||||
bool sample_filter(DTMFDolphinPulseFilter* pf) {
|
||||
bool frame = true;
|
||||
|
||||
if (pf->duration) {
|
||||
if (pf->offset < pf->duration) {
|
||||
if(pf->duration) {
|
||||
if(pf->offset < pf->duration) {
|
||||
frame = pf->lookup_table[pf->offset];
|
||||
pf->offset = pf->offset + 1;
|
||||
} else {
|
||||
@@ -142,14 +144,14 @@ bool sample_filter(DTMFDolphinPulseFilter* pf) {
|
||||
}
|
||||
|
||||
void dtmf_dolphin_osc_free(DTMFDolphinOsc* osc) {
|
||||
if (osc->lookup_table != NULL) {
|
||||
if(osc->lookup_table != NULL) {
|
||||
free(osc->lookup_table);
|
||||
}
|
||||
free(osc);
|
||||
}
|
||||
|
||||
void dtmf_dolphin_filter_free(DTMFDolphinPulseFilter* pf) {
|
||||
if (pf->lookup_table != NULL) {
|
||||
if(pf->lookup_table != NULL) {
|
||||
free(pf->lookup_table);
|
||||
}
|
||||
free(pf);
|
||||
@@ -165,22 +167,19 @@ void dtmf_dolphin_audio_free(DTMFDolphinAudio* player) {
|
||||
current_player = NULL;
|
||||
}
|
||||
|
||||
|
||||
bool generate_waveform(DTMFDolphinAudio* player, uint16_t buffer_index) {
|
||||
uint16_t* sample_buffer_start = &player->sample_buffer[buffer_index];
|
||||
|
||||
for (size_t i = 0; i < player->half_buffer_length; i++) {
|
||||
for(size_t i = 0; i < player->half_buffer_length; i++) {
|
||||
float data = 0;
|
||||
if (player->osc2->period) {
|
||||
data = \
|
||||
(sample_frame(player->osc1) / 2) + \
|
||||
(sample_frame(player->osc2) / 2);
|
||||
if(player->osc2->period) {
|
||||
data = (sample_frame(player->osc1) / 2) + (sample_frame(player->osc2) / 2);
|
||||
} else {
|
||||
data = (sample_frame(player->osc1));
|
||||
}
|
||||
data *= sample_filter(player->filter) ? player->volume : 0.0;
|
||||
data *= UINT8_MAX / 2; // scale -128..127
|
||||
data += UINT8_MAX / 2; // to unsigned
|
||||
data *= UINT8_MAX / 2; // scale -128..127
|
||||
data += UINT8_MAX / 2; // to unsigned
|
||||
|
||||
if(data < 0) {
|
||||
data = 0;
|
||||
@@ -196,8 +195,13 @@ bool generate_waveform(DTMFDolphinAudio* player, uint16_t buffer_index) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dtmf_dolphin_audio_play_tones(float freq1, float freq2, uint16_t pulses, uint16_t pulse_ms, uint16_t gap_ms) {
|
||||
if (current_player != NULL && current_player->playing) {
|
||||
bool dtmf_dolphin_audio_play_tones(
|
||||
float freq1,
|
||||
float freq2,
|
||||
uint16_t pulses,
|
||||
uint16_t pulse_ms,
|
||||
uint16_t gap_ms) {
|
||||
if(current_player != NULL && current_player->playing) {
|
||||
// Cannot start playing while still playing something else
|
||||
return false;
|
||||
}
|
||||
@@ -213,7 +217,8 @@ bool dtmf_dolphin_audio_play_tones(float freq1, float freq2, uint16_t pulses, ui
|
||||
dtmf_dolphin_speaker_init();
|
||||
dtmf_dolphin_dma_init((uint32_t)current_player->sample_buffer, current_player->buffer_length);
|
||||
|
||||
furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, dtmf_dolphin_audio_dma_isr, current_player->queue);
|
||||
furi_hal_interrupt_set_isr(
|
||||
FuriHalInterruptIdDma1Ch1, dtmf_dolphin_audio_dma_isr, current_player->queue);
|
||||
|
||||
dtmf_dolphin_dma_start();
|
||||
dtmf_dolphin_speaker_start();
|
||||
@@ -222,11 +227,12 @@ bool dtmf_dolphin_audio_play_tones(float freq1, float freq2, uint16_t pulses, ui
|
||||
}
|
||||
|
||||
bool dtmf_dolphin_audio_stop_tones() {
|
||||
if (current_player != NULL && !current_player->playing) {
|
||||
if(current_player != NULL && !current_player->playing) {
|
||||
// Can't stop a player that isn't playing.
|
||||
return false;
|
||||
}
|
||||
while(current_player->filter->offset > 0 && current_player->filter->offset < current_player->filter->duration) {
|
||||
while(current_player->filter->offset > 0 &&
|
||||
current_player->filter->offset < current_player->filter->duration) {
|
||||
// run remaining ticks if needed to complete filter sequence
|
||||
dtmf_dolphin_audio_handle_tick();
|
||||
}
|
||||
@@ -236,20 +242,20 @@ bool dtmf_dolphin_audio_stop_tones() {
|
||||
furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, NULL, NULL);
|
||||
|
||||
dtmf_dolphin_audio_free(current_player);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dtmf_dolphin_audio_handle_tick() {
|
||||
bool handled = false;
|
||||
|
||||
if (current_player) {
|
||||
if(current_player) {
|
||||
DTMFDolphinCustomEvent event;
|
||||
if(furi_message_queue_get(current_player->queue, &event, 250) == FuriStatusOk) {
|
||||
if(event.type == DTMFDolphinEventDMAHalfTransfer) {
|
||||
generate_waveform(current_player, 0);
|
||||
handled = true;
|
||||
} else if (event.type == DTMFDolphinEventDMAFullTransfer) {
|
||||
} else if(event.type == DTMFDolphinEventDMAFullTransfer) {
|
||||
generate_waveform(current_player, current_player->half_buffer_length);
|
||||
handled = true;
|
||||
}
|
||||
|
||||
@@ -24,13 +24,13 @@ typedef struct {
|
||||
typedef struct {
|
||||
size_t buffer_length;
|
||||
size_t half_buffer_length;
|
||||
uint8_t *buffer_buffer;
|
||||
uint16_t *sample_buffer;
|
||||
uint8_t* buffer_buffer;
|
||||
uint16_t* sample_buffer;
|
||||
float volume;
|
||||
FuriMessageQueue *queue;
|
||||
DTMFDolphinOsc *osc1;
|
||||
DTMFDolphinOsc *osc2;
|
||||
DTMFDolphinPulseFilter *filter;
|
||||
FuriMessageQueue* queue;
|
||||
DTMFDolphinOsc* osc1;
|
||||
DTMFDolphinOsc* osc2;
|
||||
DTMFDolphinPulseFilter* filter;
|
||||
bool playing;
|
||||
} DTMFDolphinAudio;
|
||||
|
||||
@@ -42,7 +42,12 @@ void dtmf_dolphin_audio_free(DTMFDolphinAudio* player);
|
||||
|
||||
void dtmf_dolphin_osc_free(DTMFDolphinOsc* osc);
|
||||
|
||||
bool dtmf_dolphin_audio_play_tones(float freq1, float freq2, uint16_t pulses, uint16_t pulse_ms, uint16_t gap_ms);
|
||||
bool dtmf_dolphin_audio_play_tones(
|
||||
float freq1,
|
||||
float freq2,
|
||||
uint16_t pulses,
|
||||
uint16_t pulse_ms,
|
||||
uint16_t gap_ms);
|
||||
|
||||
bool dtmf_dolphin_audio_stop_tones();
|
||||
|
||||
|
||||
@@ -7,13 +7,13 @@ typedef struct {
|
||||
} DTMFDolphinTonePos;
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
const char* name;
|
||||
const float frequency_1;
|
||||
const float frequency_2;
|
||||
const DTMFDolphinTonePos pos;
|
||||
const uint16_t pulses; // for Redbox
|
||||
const uint16_t pulse_ms; // for Redbox
|
||||
const uint16_t gap_duration; // for Redbox
|
||||
const uint16_t pulses; // for Redbox
|
||||
const uint16_t pulse_ms; // for Redbox
|
||||
const uint16_t gap_duration; // for Redbox
|
||||
} DTMFDolphinTones;
|
||||
|
||||
typedef struct {
|
||||
@@ -44,41 +44,38 @@ DTMFDolphinSceneData DTMFDolphinSceneDataDialer = {
|
||||
{"0", 941.0, 1336.0, {3, 1, 1}, 0, 0, 0},
|
||||
{"#", 941.0, 1477.0, {3, 2, 1}, 0, 0, 0},
|
||||
{"D", 941.0, 1633.0, {3, 3, 1}, 0, 0, 0},
|
||||
}
|
||||
};
|
||||
}};
|
||||
|
||||
DTMFDolphinSceneData DTMFDolphinSceneDataBluebox = {
|
||||
.name = "Bluebox",
|
||||
.block = DTMF_DOLPHIN_TONE_BLOCK_BLUEBOX,
|
||||
.tone_count = 13,
|
||||
.tones = {
|
||||
{"1", 700.0, 900.0, {0, 0, 1}, 0, 0, 0},
|
||||
{"2", 700.0, 1100.0, {0, 1, 1}, 0, 0, 0},
|
||||
{"3", 900.0, 1100.0, {0, 2, 1}, 0, 0, 0},
|
||||
{"4", 700.0, 1300.0, {1, 0, 1}, 0, 0, 0},
|
||||
{"5", 900.0, 1300.0, {1, 1, 1}, 0, 0, 0},
|
||||
{"6", 1100.0, 1300.0, {1, 2, 1}, 0, 0, 0},
|
||||
{"7", 700.0, 1500.0, {2, 0, 1}, 0, 0, 0},
|
||||
{"8", 900.0, 1500.0, {2, 1, 1}, 0, 0, 0},
|
||||
{"9", 1100.0, 1500.0, {2, 2, 1}, 0, 0, 0},
|
||||
{"0", 1300.0, 1500.0, {3, 1, 1}, 0, 0, 0},
|
||||
{"KP", 1100.0, 1700.0, {0, 3, 2}, 0, 0, 0},
|
||||
{"ST", 1500.0, 1700.0, {1, 3, 2}, 0, 0, 0},
|
||||
{"2600", 2600.0, 0.0, {3, 2, 3}, 0, 0, 0},
|
||||
}
|
||||
};
|
||||
{"1", 700.0, 900.0, {0, 0, 1}, 0, 0, 0},
|
||||
{"2", 700.0, 1100.0, {0, 1, 1}, 0, 0, 0},
|
||||
{"3", 900.0, 1100.0, {0, 2, 1}, 0, 0, 0},
|
||||
{"4", 700.0, 1300.0, {1, 0, 1}, 0, 0, 0},
|
||||
{"5", 900.0, 1300.0, {1, 1, 1}, 0, 0, 0},
|
||||
{"6", 1100.0, 1300.0, {1, 2, 1}, 0, 0, 0},
|
||||
{"7", 700.0, 1500.0, {2, 0, 1}, 0, 0, 0},
|
||||
{"8", 900.0, 1500.0, {2, 1, 1}, 0, 0, 0},
|
||||
{"9", 1100.0, 1500.0, {2, 2, 1}, 0, 0, 0},
|
||||
{"0", 1300.0, 1500.0, {3, 1, 1}, 0, 0, 0},
|
||||
{"KP", 1100.0, 1700.0, {0, 3, 2}, 0, 0, 0},
|
||||
{"ST", 1500.0, 1700.0, {1, 3, 2}, 0, 0, 0},
|
||||
{"2600", 2600.0, 0.0, {3, 2, 3}, 0, 0, 0},
|
||||
}};
|
||||
|
||||
DTMFDolphinSceneData DTMFDolphinSceneDataRedboxUS = {
|
||||
.name = "Redbox (US)",
|
||||
.block = DTMF_DOLPHIN_TONE_BLOCK_REDBOX_US,
|
||||
.tone_count = 4,
|
||||
.tones = {
|
||||
{"Nickel", 1700.0, 2200.0, {0, 0, 5}, 1, 66, 0},
|
||||
{"Dime", 1700.0, 2200.0, {1, 0, 5}, 2, 66, 66},
|
||||
{"Nickel", 1700.0, 2200.0, {0, 0, 5}, 1, 66, 0},
|
||||
{"Dime", 1700.0, 2200.0, {1, 0, 5}, 2, 66, 66},
|
||||
{"Quarter", 1700.0, 2200.0, {2, 0, 5}, 5, 33, 33},
|
||||
{"Dollar", 1700.0, 2200.0, {3, 0, 5}, 1, 650, 0},
|
||||
}
|
||||
};
|
||||
{"Dollar", 1700.0, 2200.0, {3, 0, 5}, 1, 650, 0},
|
||||
}};
|
||||
|
||||
DTMFDolphinSceneData DTMFDolphinSceneDataRedboxUK = {
|
||||
.name = "Redbox (UK)",
|
||||
@@ -87,28 +84,25 @@ DTMFDolphinSceneData DTMFDolphinSceneDataRedboxUK = {
|
||||
.tones = {
|
||||
{"10p", 1000.0, 0.0, {0, 0, 5}, 1, 200, 0},
|
||||
{"50p", 1000.0, 0.0, {1, 0, 5}, 1, 350, 0},
|
||||
}
|
||||
};
|
||||
}};
|
||||
|
||||
DTMFDolphinSceneData DTMFDolphinSceneDataMisc = {
|
||||
.name = "Misc",
|
||||
.block = DTMF_DOLPHIN_TONE_BLOCK_MISC,
|
||||
.tone_count = 3,
|
||||
.tones = {
|
||||
{"CCITT 11", 700.0, 1700.0, {0, 0, 5}, 0, 0, 0},
|
||||
{"CCITT 12", 900.0, 1700.0, {1, 0, 5}, 0, 0, 0},
|
||||
{"CCITT 11", 700.0, 1700.0, {0, 0, 5}, 0, 0, 0},
|
||||
{"CCITT 12", 900.0, 1700.0, {1, 0, 5}, 0, 0, 0},
|
||||
{"CCITT KP2", 1300.0, 1700.0, {2, 0, 5}, 0, 0, 0},
|
||||
}
|
||||
};
|
||||
}};
|
||||
|
||||
DTMFDolphinToneSection current_section;
|
||||
DTMFDolphinSceneData *current_scene_data;
|
||||
DTMFDolphinSceneData* current_scene_data;
|
||||
|
||||
void dtmf_dolphin_data_set_current_section(DTMFDolphinToneSection section) {
|
||||
current_section = section;
|
||||
|
||||
switch (current_section)
|
||||
{
|
||||
switch(current_section) {
|
||||
case DTMF_DOLPHIN_TONE_BLOCK_BLUEBOX:
|
||||
current_scene_data = &DTMFDolphinSceneDataBluebox;
|
||||
break;
|
||||
@@ -131,14 +125,14 @@ DTMFDolphinToneSection dtmf_dolphin_data_get_current_section() {
|
||||
return current_section;
|
||||
}
|
||||
|
||||
DTMFDolphinSceneData *dtmf_dolphin_data_get_current_scene_data() {
|
||||
DTMFDolphinSceneData* dtmf_dolphin_data_get_current_scene_data() {
|
||||
return current_scene_data;
|
||||
}
|
||||
|
||||
bool dtmf_dolphin_data_get_tone_frequencies(float *freq1, float *freq2, uint8_t row, uint8_t col) {
|
||||
for (size_t i = 0; i < current_scene_data->tone_count; i++) {
|
||||
bool dtmf_dolphin_data_get_tone_frequencies(float* freq1, float* freq2, uint8_t row, uint8_t col) {
|
||||
for(size_t i = 0; i < current_scene_data->tone_count; i++) {
|
||||
DTMFDolphinTones tones = current_scene_data->tones[i];
|
||||
if (tones.pos.row == row && tones.pos.col == col) {
|
||||
if(tones.pos.row == row && tones.pos.col == col) {
|
||||
freq1[0] = tones.frequency_1;
|
||||
freq2[0] = tones.frequency_2;
|
||||
return true;
|
||||
@@ -147,10 +141,15 @@ bool dtmf_dolphin_data_get_tone_frequencies(float *freq1, float *freq2, uint8_t
|
||||
return false;
|
||||
}
|
||||
|
||||
bool dtmf_dolphin_data_get_filter_data(uint16_t *pulses, uint16_t *pulse_ms, uint16_t *gap_ms, uint8_t row, uint8_t col) {
|
||||
for (size_t i = 0; i < current_scene_data->tone_count; i++) {
|
||||
bool dtmf_dolphin_data_get_filter_data(
|
||||
uint16_t* pulses,
|
||||
uint16_t* pulse_ms,
|
||||
uint16_t* gap_ms,
|
||||
uint8_t row,
|
||||
uint8_t col) {
|
||||
for(size_t i = 0; i < current_scene_data->tone_count; i++) {
|
||||
DTMFDolphinTones tones = current_scene_data->tones[i];
|
||||
if (tones.pos.row == row && tones.pos.col == col) {
|
||||
if(tones.pos.row == row && tones.pos.col == col) {
|
||||
pulses[0] = tones.pulses;
|
||||
pulse_ms[0] = tones.pulse_ms;
|
||||
gap_ms[0] = tones.gap_duration;
|
||||
@@ -161,9 +160,9 @@ bool dtmf_dolphin_data_get_filter_data(uint16_t *pulses, uint16_t *pulse_ms, uin
|
||||
}
|
||||
|
||||
const char* dtmf_dolphin_data_get_tone_name(uint8_t row, uint8_t col) {
|
||||
for (size_t i = 0; i < current_scene_data->tone_count; i++) {
|
||||
for(size_t i = 0; i < current_scene_data->tone_count; i++) {
|
||||
DTMFDolphinTones tones = current_scene_data->tones[i];
|
||||
if (tones.pos.row == row && tones.pos.col == col) {
|
||||
if(tones.pos.row == row && tones.pos.col == col) {
|
||||
return tones.name;
|
||||
}
|
||||
}
|
||||
@@ -171,7 +170,7 @@ const char* dtmf_dolphin_data_get_tone_name(uint8_t row, uint8_t col) {
|
||||
}
|
||||
|
||||
const char* dtmf_dolphin_data_get_current_section_name() {
|
||||
if (current_scene_data) {
|
||||
if(current_scene_data) {
|
||||
return current_scene_data->name;
|
||||
}
|
||||
return NULL;
|
||||
@@ -181,27 +180,26 @@ void dtmf_dolphin_tone_get_max_pos(uint8_t* max_rows, uint8_t* max_cols, uint8_t
|
||||
max_rows[0] = 0;
|
||||
max_cols[0] = 0;
|
||||
max_span[0] = 0;
|
||||
uint8_t tmp_rowspan[5] = { 0, 0, 0, 0, 0 };
|
||||
for (size_t i = 0; i < current_scene_data->tone_count; i++) {
|
||||
uint8_t tmp_rowspan[5] = {0, 0, 0, 0, 0};
|
||||
for(size_t i = 0; i < current_scene_data->tone_count; i++) {
|
||||
DTMFDolphinTones tones = current_scene_data->tones[i];
|
||||
if (tones.pos.row > max_rows[0]) {
|
||||
if(tones.pos.row > max_rows[0]) {
|
||||
max_rows[0] = tones.pos.row;
|
||||
}
|
||||
if (tones.pos.col > max_cols[0]) {
|
||||
if(tones.pos.col > max_cols[0]) {
|
||||
max_cols[0] = tones.pos.col;
|
||||
}
|
||||
tmp_rowspan[tones.pos.row] += tones.pos.span;
|
||||
if (tmp_rowspan[tones.pos.row] > max_span[0])
|
||||
max_span[0] = tmp_rowspan[tones.pos.row];
|
||||
if(tmp_rowspan[tones.pos.row] > max_span[0]) max_span[0] = tmp_rowspan[tones.pos.row];
|
||||
}
|
||||
max_rows[0]++;
|
||||
max_cols[0]++;
|
||||
}
|
||||
|
||||
uint8_t dtmf_dolphin_get_tone_span(uint8_t row, uint8_t col) {
|
||||
for (size_t i = 0; i < current_scene_data->tone_count; i++) {
|
||||
for(size_t i = 0; i < current_scene_data->tone_count; i++) {
|
||||
DTMFDolphinTones tones = current_scene_data->tones[i];
|
||||
if (tones.pos.row == row && tones.pos.col == col) {
|
||||
if(tones.pos.row == row && tones.pos.col == col) {
|
||||
return tones.pos.span;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +17,14 @@ void dtmf_dolphin_data_set_current_section(DTMFDolphinToneSection section);
|
||||
|
||||
DTMFDolphinToneSection dtmf_dolphin_data_get_current_section();
|
||||
|
||||
bool dtmf_dolphin_data_get_tone_frequencies(float *freq1, float *freq2, uint8_t row, uint8_t col);
|
||||
bool dtmf_dolphin_data_get_tone_frequencies(float* freq1, float* freq2, uint8_t row, uint8_t col);
|
||||
|
||||
bool dtmf_dolphin_data_get_filter_data(uint16_t *pulses, uint16_t *pulse_ms, uint16_t *gap_ms, uint8_t row, uint8_t col);
|
||||
bool dtmf_dolphin_data_get_filter_data(
|
||||
uint16_t* pulses,
|
||||
uint16_t* pulse_ms,
|
||||
uint16_t* gap_ms,
|
||||
uint8_t row,
|
||||
uint8_t col);
|
||||
|
||||
const char* dtmf_dolphin_data_get_tone_name(uint8_t row, uint8_t col);
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
#define TAG "DTMFDolphin"
|
||||
|
||||
|
||||
enum DTMFDolphinSceneState {
|
||||
DTMFDolphinSceneStateDialer,
|
||||
DTMFDolphinSceneStateBluebox,
|
||||
@@ -39,7 +38,4 @@ typedef struct {
|
||||
NotificationApp* notification;
|
||||
} DTMFDolphinApp;
|
||||
|
||||
typedef enum {
|
||||
DTMFDolphinViewMainMenu,
|
||||
DTMFDolphinViewDialer
|
||||
} DTMFDolphinView;
|
||||
typedef enum { DTMFDolphinViewMainMenu, DTMFDolphinViewDialer } DTMFDolphinView;
|
||||
|
||||
@@ -2,17 +2,15 @@
|
||||
// #include "../dtmf_dolphin_data.h"
|
||||
// #include "../dtmf_dolphin_audio.h"
|
||||
|
||||
|
||||
void dtmf_dolphin_scene_dialer_on_enter(void *context) {
|
||||
void dtmf_dolphin_scene_dialer_on_enter(void* context) {
|
||||
DTMFDolphinApp* app = context;
|
||||
DTMFDolphinScene scene_id = DTMFDolphinSceneDialer;
|
||||
enum DTMFDolphinSceneState state = scene_manager_get_scene_state(app->scene_manager, scene_id);
|
||||
|
||||
switch (state)
|
||||
{
|
||||
switch(state) {
|
||||
case DTMFDolphinSceneStateBluebox:
|
||||
dtmf_dolphin_data_set_current_section(DTMF_DOLPHIN_TONE_BLOCK_BLUEBOX);
|
||||
break;
|
||||
break;
|
||||
case DTMFDolphinSceneStateRedboxUS:
|
||||
dtmf_dolphin_data_set_current_section(DTMF_DOLPHIN_TONE_BLOCK_REDBOX_US);
|
||||
break;
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
static void dtmf_dolphin_scene_start_main_menu_enter_callback(void* context, uint32_t index) {
|
||||
DTMFDolphinApp* app = context;
|
||||
uint8_t cust_event = 255;
|
||||
switch (index)
|
||||
{
|
||||
switch(index) {
|
||||
case 0:
|
||||
cust_event = DTMFDolphinEventStartDialer;
|
||||
break;
|
||||
@@ -24,10 +23,7 @@ static void dtmf_dolphin_scene_start_main_menu_enter_callback(void* context, uin
|
||||
return;
|
||||
}
|
||||
|
||||
view_dispatcher_send_custom_event(
|
||||
app->view_dispatcher,
|
||||
cust_event
|
||||
);
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, cust_event);
|
||||
}
|
||||
|
||||
void dtmf_dolphin_scene_start_on_enter(void* context) {
|
||||
@@ -36,9 +32,7 @@ void dtmf_dolphin_scene_start_on_enter(void* context) {
|
||||
|
||||
// VariableItem* item;
|
||||
variable_item_list_set_enter_callback(
|
||||
var_item_list,
|
||||
dtmf_dolphin_scene_start_main_menu_enter_callback,
|
||||
app);
|
||||
var_item_list, dtmf_dolphin_scene_start_main_menu_enter_callback, app);
|
||||
|
||||
variable_item_list_add(var_item_list, "Dialer", 0, NULL, context);
|
||||
variable_item_list_add(var_item_list, "Bluebox", 0, NULL, context);
|
||||
@@ -47,12 +41,9 @@ void dtmf_dolphin_scene_start_on_enter(void* context) {
|
||||
variable_item_list_add(var_item_list, "Misc", 0, NULL, context);
|
||||
|
||||
variable_item_list_set_selected_item(
|
||||
var_item_list,
|
||||
scene_manager_get_scene_state(app->scene_manager, DTMFDolphinSceneStart));
|
||||
var_item_list, scene_manager_get_scene_state(app->scene_manager, DTMFDolphinSceneStart));
|
||||
|
||||
view_dispatcher_switch_to_view(
|
||||
app->view_dispatcher,
|
||||
DTMFDolphinViewMainMenu);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, DTMFDolphinViewMainMenu);
|
||||
}
|
||||
|
||||
bool dtmf_dolphin_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
@@ -63,8 +54,7 @@ bool dtmf_dolphin_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
uint8_t sc_state;
|
||||
|
||||
switch (event.event)
|
||||
{
|
||||
switch(event.event) {
|
||||
case DTMFDolphinEventStartDialer:
|
||||
sc_state = DTMFDolphinSceneStateDialer;
|
||||
break;
|
||||
|
||||
@@ -7,4 +7,4 @@
|
||||
#define DTMF_DOLPHIN_NUMPAD_Y 14
|
||||
#define DTMF_DOLPHIN_BUTTON_WIDTH 13
|
||||
#define DTMF_DOLPHIN_BUTTON_HEIGHT 13
|
||||
#define DTMF_DOLPHIN_BUTTON_PADDING 1 // all sides
|
||||
#define DTMF_DOLPHIN_BUTTON_PADDING 1 // all sides
|
||||
|
||||
@@ -24,53 +24,55 @@ static bool dtmf_dolphin_dialer_process_up(DTMFDolphinDialer* dtmf_dolphin_diale
|
||||
static bool dtmf_dolphin_dialer_process_down(DTMFDolphinDialer* dtmf_dolphin_dialer);
|
||||
static bool dtmf_dolphin_dialer_process_left(DTMFDolphinDialer* dtmf_dolphin_dialer);
|
||||
static bool dtmf_dolphin_dialer_process_right(DTMFDolphinDialer* dtmf_dolphin_dialer);
|
||||
static bool dtmf_dolphin_dialer_process_ok(DTMFDolphinDialer* dtmf_dolphin_dialer, InputEvent* event);
|
||||
static bool
|
||||
dtmf_dolphin_dialer_process_ok(DTMFDolphinDialer* dtmf_dolphin_dialer, InputEvent* event);
|
||||
|
||||
void draw_button(Canvas* canvas, uint8_t row, uint8_t col, bool invert) {
|
||||
|
||||
uint8_t left = DTMF_DOLPHIN_NUMPAD_X + \
|
||||
// ((col + 1) * DTMF_DOLPHIN_BUTTON_PADDING) +
|
||||
(col * DTMF_DOLPHIN_BUTTON_WIDTH);
|
||||
// (col * DTMF_DOLPHIN_BUTTON_PADDING);
|
||||
uint8_t top = DTMF_DOLPHIN_NUMPAD_Y + \
|
||||
// ((row + 1) * DTMF_DOLPHIN_BUTTON_PADDING) +
|
||||
(row * DTMF_DOLPHIN_BUTTON_HEIGHT);
|
||||
// (row * DTMF_DOLPHIN_BUTTON_PADDING);
|
||||
uint8_t left = DTMF_DOLPHIN_NUMPAD_X + // ((col + 1) * DTMF_DOLPHIN_BUTTON_PADDING) +
|
||||
(col * DTMF_DOLPHIN_BUTTON_WIDTH);
|
||||
// (col * DTMF_DOLPHIN_BUTTON_PADDING);
|
||||
uint8_t top = DTMF_DOLPHIN_NUMPAD_Y + // ((row + 1) * DTMF_DOLPHIN_BUTTON_PADDING) +
|
||||
(row * DTMF_DOLPHIN_BUTTON_HEIGHT);
|
||||
// (row * DTMF_DOLPHIN_BUTTON_PADDING);
|
||||
|
||||
uint8_t span = dtmf_dolphin_get_tone_span(row, col);
|
||||
|
||||
if (span == 0) {
|
||||
if(span == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
if (invert)
|
||||
canvas_draw_rbox(canvas, left, top,
|
||||
|
||||
if(invert)
|
||||
canvas_draw_rbox(
|
||||
canvas,
|
||||
left,
|
||||
top,
|
||||
(DTMF_DOLPHIN_BUTTON_WIDTH * span) - (DTMF_DOLPHIN_BUTTON_PADDING * 2),
|
||||
DTMF_DOLPHIN_BUTTON_HEIGHT - (DTMF_DOLPHIN_BUTTON_PADDING * 2),
|
||||
2);
|
||||
else
|
||||
canvas_draw_rframe(canvas, left, top,
|
||||
canvas_draw_rframe(
|
||||
canvas,
|
||||
left,
|
||||
top,
|
||||
(DTMF_DOLPHIN_BUTTON_WIDTH * span) - (DTMF_DOLPHIN_BUTTON_PADDING * 2),
|
||||
DTMF_DOLPHIN_BUTTON_HEIGHT- (DTMF_DOLPHIN_BUTTON_PADDING * 2),
|
||||
DTMF_DOLPHIN_BUTTON_HEIGHT - (DTMF_DOLPHIN_BUTTON_PADDING * 2),
|
||||
2);
|
||||
|
||||
if (invert)
|
||||
canvas_invert_color(canvas);
|
||||
|
||||
if(invert) canvas_invert_color(canvas);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
// canvas_set_color(canvas, invert ? ColorWhite : ColorBlack);
|
||||
canvas_draw_str_aligned(canvas,
|
||||
left - 1 + (int) ((DTMF_DOLPHIN_BUTTON_WIDTH * span) / 2),
|
||||
top + (int) (DTMF_DOLPHIN_BUTTON_HEIGHT / 2),
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
left - 1 + (int)((DTMF_DOLPHIN_BUTTON_WIDTH * span) / 2),
|
||||
top + (int)(DTMF_DOLPHIN_BUTTON_HEIGHT / 2),
|
||||
AlignCenter,
|
||||
AlignCenter,
|
||||
dtmf_dolphin_data_get_tone_name(row, col));
|
||||
|
||||
if (invert)
|
||||
canvas_invert_color(canvas);
|
||||
if(invert) canvas_invert_color(canvas);
|
||||
}
|
||||
|
||||
void draw_dialer(Canvas* canvas, void* _model) {
|
||||
@@ -82,9 +84,9 @@ void draw_dialer(Canvas* canvas, void* _model) {
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
for (int r = 0; r < max_rows; r++) {
|
||||
for (int c = 0; c < max_cols; c++) {
|
||||
if (model->row == r && model->col == c)
|
||||
for(int r = 0; r < max_rows; r++) {
|
||||
for(int c = 0; c < max_cols; c++) {
|
||||
if(model->row == r && model->col == c)
|
||||
draw_button(canvas, r, c, true);
|
||||
else
|
||||
draw_button(canvas, r, c, false);
|
||||
@@ -92,21 +94,22 @@ void draw_dialer(Canvas* canvas, void* _model) {
|
||||
}
|
||||
}
|
||||
|
||||
void update_frequencies(DTMFDolphinDialerModel *model) {
|
||||
void update_frequencies(DTMFDolphinDialerModel* model) {
|
||||
dtmf_dolphin_data_get_tone_frequencies(&model->freq1, &model->freq2, model->row, model->col);
|
||||
dtmf_dolphin_data_get_filter_data(&model->pulses, &model->pulse_ms, &model->gap_ms, model->row, model->col);
|
||||
dtmf_dolphin_data_get_filter_data(
|
||||
&model->pulses, &model->pulse_ms, &model->gap_ms, model->row, model->col);
|
||||
}
|
||||
|
||||
static void dtmf_dolphin_dialer_draw_callback(Canvas* canvas, void* _model) {
|
||||
DTMFDolphinDialerModel* model = _model;
|
||||
if (model->playing) {
|
||||
if(model->playing) {
|
||||
// Leverage the prioritized draw callback to handle
|
||||
// the DMA so that it doesn't skip.
|
||||
dtmf_dolphin_audio_handle_tick();
|
||||
// Don't do any drawing if audio is playing.
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_aligned(
|
||||
canvas,
|
||||
canvas,
|
||||
canvas_width(canvas) / 2,
|
||||
canvas_height(canvas) / 2,
|
||||
AlignCenter,
|
||||
@@ -122,46 +125,41 @@ static void dtmf_dolphin_dialer_draw_callback(Canvas* canvas, void* _model) {
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text(canvas, 2, 10, dtmf_dolphin_data_get_current_section_name());
|
||||
canvas_draw_line(canvas,
|
||||
(max_span * DTMF_DOLPHIN_BUTTON_WIDTH) + 1, 0,
|
||||
(max_span * DTMF_DOLPHIN_BUTTON_WIDTH) + 1, canvas_height(canvas));
|
||||
canvas_draw_line(
|
||||
canvas,
|
||||
(max_span * DTMF_DOLPHIN_BUTTON_WIDTH) + 1,
|
||||
0,
|
||||
(max_span * DTMF_DOLPHIN_BUTTON_WIDTH) + 1,
|
||||
canvas_height(canvas));
|
||||
elements_multiline_text(canvas, (max_span * DTMF_DOLPHIN_BUTTON_WIDTH) + 4, 10, "Detail");
|
||||
canvas_draw_line(canvas, 0, DTMF_DOLPHIN_NUMPAD_Y - 3, canvas_width(canvas), DTMF_DOLPHIN_NUMPAD_Y - 3);
|
||||
canvas_draw_line(
|
||||
canvas, 0, DTMF_DOLPHIN_NUMPAD_Y - 3, canvas_width(canvas), DTMF_DOLPHIN_NUMPAD_Y - 3);
|
||||
// elements_multiline_text_aligned(canvas, 64, 2, AlignCenter, AlignTop, "Dialer Mode");
|
||||
|
||||
draw_dialer(canvas, model);
|
||||
|
||||
FuriString *output = furi_string_alloc();
|
||||
FuriString* output = furi_string_alloc();
|
||||
|
||||
if (model->freq1 && model->freq2) {
|
||||
if(model->freq1 && model->freq2) {
|
||||
furi_string_cat_printf(
|
||||
output,
|
||||
"Dual Tone\nF1: %u Hz\nF2: %u Hz\n",
|
||||
(unsigned int) model->freq1,
|
||||
(unsigned int) model->freq2);
|
||||
} else if (model->freq1) {
|
||||
furi_string_cat_printf(
|
||||
output,
|
||||
"Single Tone\nF: %u Hz\n",
|
||||
(unsigned int) model->freq1);
|
||||
(unsigned int)model->freq1,
|
||||
(unsigned int)model->freq2);
|
||||
} else if(model->freq1) {
|
||||
furi_string_cat_printf(output, "Single Tone\nF: %u Hz\n", (unsigned int)model->freq1);
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
if (model->pulse_ms) {
|
||||
furi_string_cat_printf(
|
||||
output,
|
||||
"P: %u * %u ms\n",
|
||||
model->pulses,
|
||||
model->pulse_ms);
|
||||
if(model->pulse_ms) {
|
||||
furi_string_cat_printf(output, "P: %u * %u ms\n", model->pulses, model->pulse_ms);
|
||||
}
|
||||
if (model->gap_ms) {
|
||||
furi_string_cat_printf(
|
||||
output,
|
||||
"Gaps: %u ms\n",
|
||||
model->gap_ms);
|
||||
if(model->gap_ms) {
|
||||
furi_string_cat_printf(output, "Gaps: %u ms\n", model->gap_ms);
|
||||
}
|
||||
elements_multiline_text(canvas, (max_span * DTMF_DOLPHIN_BUTTON_WIDTH) + 4, 21, furi_string_get_cstr(output));
|
||||
elements_multiline_text(
|
||||
canvas, (max_span * DTMF_DOLPHIN_BUTTON_WIDTH) + 4, 21, furi_string_get_cstr(output));
|
||||
|
||||
furi_string_free(output);
|
||||
}
|
||||
@@ -196,11 +194,11 @@ static bool dtmf_dolphin_dialer_process_up(DTMFDolphinDialer* dtmf_dolphin_diale
|
||||
{
|
||||
uint8_t span = 0;
|
||||
uint8_t cursor = model->row;
|
||||
while (span == 0 && cursor > 0) {
|
||||
while(span == 0 && cursor > 0) {
|
||||
cursor--;
|
||||
span = dtmf_dolphin_get_tone_span(cursor, model->col);
|
||||
}
|
||||
if (span != 0) {
|
||||
if(span != 0) {
|
||||
model->row = cursor;
|
||||
}
|
||||
},
|
||||
@@ -224,7 +222,7 @@ static bool dtmf_dolphin_dialer_process_down(DTMFDolphinDialer* dtmf_dolphin_dia
|
||||
cursor++;
|
||||
span = dtmf_dolphin_get_tone_span(cursor, model->col);
|
||||
}
|
||||
if (span != 0) {
|
||||
if(span != 0) {
|
||||
model->row = cursor;
|
||||
}
|
||||
},
|
||||
@@ -239,11 +237,11 @@ static bool dtmf_dolphin_dialer_process_left(DTMFDolphinDialer* dtmf_dolphin_dia
|
||||
{
|
||||
uint8_t span = 0;
|
||||
uint8_t cursor = model->col;
|
||||
while (span == 0 && cursor > 0) {
|
||||
while(span == 0 && cursor > 0) {
|
||||
cursor--;
|
||||
span = dtmf_dolphin_get_tone_span(model->row, cursor);
|
||||
}
|
||||
if (span != 0) {
|
||||
if(span != 0) {
|
||||
model->col = cursor;
|
||||
}
|
||||
},
|
||||
@@ -267,7 +265,7 @@ static bool dtmf_dolphin_dialer_process_right(DTMFDolphinDialer* dtmf_dolphin_di
|
||||
cursor++;
|
||||
span = dtmf_dolphin_get_tone_span(model->row, cursor);
|
||||
}
|
||||
if (span != 0) {
|
||||
if(span != 0) {
|
||||
model->col = cursor;
|
||||
}
|
||||
},
|
||||
@@ -275,16 +273,18 @@ static bool dtmf_dolphin_dialer_process_right(DTMFDolphinDialer* dtmf_dolphin_di
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool dtmf_dolphin_dialer_process_ok(DTMFDolphinDialer* dtmf_dolphin_dialer, InputEvent* event) {
|
||||
static bool
|
||||
dtmf_dolphin_dialer_process_ok(DTMFDolphinDialer* dtmf_dolphin_dialer, InputEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
with_view_model(
|
||||
dtmf_dolphin_dialer->view,
|
||||
DTMFDolphinDialerModel * model,
|
||||
{
|
||||
if (event->type == InputTypePress) {
|
||||
model->playing = dtmf_dolphin_audio_play_tones(model->freq1, model->freq2, model->pulses, model->pulse_ms, model->gap_ms);
|
||||
} else if (event->type == InputTypeRelease) {
|
||||
if(event->type == InputTypePress) {
|
||||
model->playing = dtmf_dolphin_audio_play_tones(
|
||||
model->freq1, model->freq2, model->pulses, model->pulse_ms, model->gap_ms);
|
||||
} else if(event->type == InputTypeRelease) {
|
||||
model->playing = !dtmf_dolphin_audio_stop_tones();
|
||||
}
|
||||
},
|
||||
@@ -308,15 +308,15 @@ static void dtmf_dolphin_dialer_enter_callback(void* context) {
|
||||
model->freq2 = 0.0;
|
||||
model->playing = false;
|
||||
},
|
||||
true
|
||||
);
|
||||
true);
|
||||
}
|
||||
|
||||
DTMFDolphinDialer* dtmf_dolphin_dialer_alloc() {
|
||||
DTMFDolphinDialer* dtmf_dolphin_dialer = malloc(sizeof(DTMFDolphinDialer));
|
||||
|
||||
dtmf_dolphin_dialer->view = view_alloc();
|
||||
view_allocate_model(dtmf_dolphin_dialer->view, ViewModelTypeLocking, sizeof(DTMFDolphinDialerModel));
|
||||
view_allocate_model(
|
||||
dtmf_dolphin_dialer->view, ViewModelTypeLocking, sizeof(DTMFDolphinDialerModel));
|
||||
|
||||
with_view_model(
|
||||
dtmf_dolphin_dialer->view,
|
||||
@@ -329,8 +329,7 @@ DTMFDolphinDialer* dtmf_dolphin_dialer_alloc() {
|
||||
model->freq2 = 0.0;
|
||||
model->playing = false;
|
||||
},
|
||||
true
|
||||
);
|
||||
true);
|
||||
|
||||
view_set_context(dtmf_dolphin_dialer->view, dtmf_dolphin_dialer);
|
||||
view_set_draw_callback(dtmf_dolphin_dialer->view, dtmf_dolphin_dialer_draw_callback);
|
||||
@@ -349,4 +348,3 @@ View* dtmf_dolphin_dialer_get_view(DTMFDolphinDialer* dtmf_dolphin_dialer) {
|
||||
furi_assert(dtmf_dolphin_dialer);
|
||||
return dtmf_dolphin_dialer->view;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,4 +12,7 @@ void dtmf_dolphin_dialer_free(DTMFDolphinDialer* dtmf_dolphin_dialer);
|
||||
|
||||
View* dtmf_dolphin_dialer_get_view(DTMFDolphinDialer* dtmf_dolphin_dialer);
|
||||
|
||||
void dtmf_dolphin_dialer_set_ok_callback(DTMFDolphinDialer* dtmf_dolphin_dialer, DTMFDolphinDialerOkCallback callback, void* context);
|
||||
void dtmf_dolphin_dialer_set_ok_callback(
|
||||
DTMFDolphinDialer* dtmf_dolphin_dialer,
|
||||
DTMFDolphinDialerOkCallback callback,
|
||||
void* context);
|
||||
|
||||
@@ -133,11 +133,11 @@ static void flappy_game_tick(GameState* const game_state) {
|
||||
}
|
||||
if(pilar->point.x < -FLAPPY_GAB_WIDTH) pilar->visible = 0;
|
||||
|
||||
if(game_state->bird.point.y <= 0 - FLAPPY_BIRD_WIDTH){
|
||||
if(game_state->bird.point.y <= 0 - FLAPPY_BIRD_WIDTH) {
|
||||
game_state->bird.point.y = 64;
|
||||
}
|
||||
|
||||
if(game_state->bird.point.y > 64 - FLAPPY_BIRD_WIDTH){
|
||||
if(game_state->bird.point.y > 64 - FLAPPY_BIRD_WIDTH) {
|
||||
game_state->bird.point.y = FLIPPER_LCD_HEIGHT - FLAPPY_BIRD_WIDTH;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,9 +41,7 @@ VirtualButtonApp* ifttt_virtual_button_app_alloc(uint32_t first_scene) {
|
||||
// Views
|
||||
app->sen_view = send_view_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
VirtualButtonAppViewSendView,
|
||||
send_view_get_view(app->sen_view));
|
||||
app->view_dispatcher, VirtualButtonAppViewSendView, send_view_get_view(app->sen_view));
|
||||
|
||||
app->modul_view = module_view_alloc();
|
||||
view_dispatcher_add_view(
|
||||
@@ -59,9 +57,7 @@ VirtualButtonApp* ifttt_virtual_button_app_alloc(uint32_t first_scene) {
|
||||
|
||||
app->rese_view = reset_view_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
VirtualButtonAppViewResetView,
|
||||
reset_view_get_view(app->rese_view));
|
||||
app->view_dispatcher, VirtualButtonAppViewResetView, reset_view_get_view(app->rese_view));
|
||||
|
||||
app->submenu = submenu_alloc();
|
||||
view_dispatcher_add_view(
|
||||
|
||||
@@ -54,11 +54,11 @@ bool virtual_button_scene_start_on_event(void* context, SceneManagerEvent event)
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == VirtualButtonSubmenuIndexSendView) {
|
||||
scene_manager_next_scene(app->scene_manager, VirtualButtonAppSceneSendView);
|
||||
}else if(event.event == VirtualButtonSubmenuIndexModuleView) {
|
||||
} else if(event.event == VirtualButtonSubmenuIndexModuleView) {
|
||||
scene_manager_next_scene(app->scene_manager, VirtualButtonAppSceneModuleView);
|
||||
}else if(event.event == VirtualButtonSubmenuIndexRebootView) {
|
||||
} else if(event.event == VirtualButtonSubmenuIndexRebootView) {
|
||||
scene_manager_next_scene(app->scene_manager, VirtualButtonAppSceneRebootView);
|
||||
}else if(event.event == VirtualButtonSubmenuIndexResetView) {
|
||||
} else if(event.event == VirtualButtonSubmenuIndexResetView) {
|
||||
scene_manager_next_scene(app->scene_manager, VirtualButtonAppSceneResetView);
|
||||
}
|
||||
scene_manager_set_scene_state(app->scene_manager, VirtualButtonAppSceneStart, event.event);
|
||||
|
||||
@@ -11,11 +11,7 @@
|
||||
|
||||
bool configState;
|
||||
|
||||
typedef enum ESerialCommand
|
||||
{
|
||||
ESerialCommand_Config_On,
|
||||
ESerialCommand_Config_Off
|
||||
} ESerialCommand;
|
||||
typedef enum ESerialCommand { ESerialCommand_Config_On, ESerialCommand_Config_Off } ESerialCommand;
|
||||
|
||||
struct ModuleView {
|
||||
View* view;
|
||||
@@ -34,20 +30,18 @@ static void Shake(void) {
|
||||
}
|
||||
*/
|
||||
|
||||
void send_serial_command_module(ESerialCommand command)
|
||||
{
|
||||
uint8_t data[1] = { 0 };
|
||||
void send_serial_command_module(ESerialCommand command) {
|
||||
uint8_t data[1] = {0};
|
||||
|
||||
switch(command)
|
||||
{
|
||||
case ESerialCommand_Config_On:
|
||||
data[0] = MODULE_CONTROL_COMMAND_CONFIG_ON;
|
||||
break;
|
||||
case ESerialCommand_Config_Off:
|
||||
data[0] = MODULE_CONTROL_COMMAND_CONFIG_OFF;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
switch(command) {
|
||||
case ESerialCommand_Config_On:
|
||||
data[0] = MODULE_CONTROL_COMMAND_CONFIG_ON;
|
||||
break;
|
||||
case ESerialCommand_Config_Off:
|
||||
data[0] = MODULE_CONTROL_COMMAND_CONFIG_OFF;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
};
|
||||
|
||||
furi_hal_uart_tx(FuriHalUartIdUSART1, data, 1);
|
||||
@@ -66,10 +60,10 @@ static void module_view_draw_callback(Canvas* canvas, void* context) {
|
||||
canvas_draw_str_aligned(canvas, 64, 45, AlignCenter, AlignTop, "and hold back to return");
|
||||
canvas_draw_str_aligned(canvas, 64, 55, AlignCenter, AlignTop, "to the menu");
|
||||
|
||||
if(configState == false){
|
||||
if(configState == false) {
|
||||
send_serial_command_module(ESerialCommand_Config_On);
|
||||
configState = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Right
|
||||
if(model->right_pressed) {
|
||||
@@ -149,10 +143,5 @@ View* module_view_get_view(ModuleView* module_view) {
|
||||
void module_view_set_data(ModuleView* module_view, bool connected) {
|
||||
furi_assert(module_view);
|
||||
with_view_model(
|
||||
module_view->view,
|
||||
ModuleViewModel * model,
|
||||
{
|
||||
model->connected = connected;
|
||||
},
|
||||
true);
|
||||
module_view->view, ModuleViewModel * model, { model->connected = connected; }, true);
|
||||
}
|
||||
@@ -8,10 +8,7 @@
|
||||
#define MODULE_CONTROL_COMMAND_REBOOT 'r'
|
||||
#define FLIPPERZERO_SERIAL_BAUD 115200
|
||||
|
||||
typedef enum ESerialCommand
|
||||
{
|
||||
ESerialCommand_Reboot
|
||||
} ESerialCommand;
|
||||
typedef enum ESerialCommand { ESerialCommand_Reboot } ESerialCommand;
|
||||
|
||||
struct RebootView {
|
||||
View* view;
|
||||
@@ -28,17 +25,15 @@ static void Shake(void) {
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
}
|
||||
|
||||
void send_serial_command_reboot(ESerialCommand command)
|
||||
{
|
||||
uint8_t data[1] = { 0 };
|
||||
void send_serial_command_reboot(ESerialCommand command) {
|
||||
uint8_t data[1] = {0};
|
||||
|
||||
switch(command)
|
||||
{
|
||||
case ESerialCommand_Reboot:
|
||||
data[0] = MODULE_CONTROL_COMMAND_REBOOT;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
switch(command) {
|
||||
case ESerialCommand_Reboot:
|
||||
data[0] = MODULE_CONTROL_COMMAND_REBOOT;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
};
|
||||
|
||||
furi_hal_uart_tx(FuriHalUartIdUSART1, data, 1);
|
||||
@@ -62,7 +57,7 @@ static void reboot_view_draw_callback(Canvas* canvas, void* context) {
|
||||
|
||||
static void reboot_view_process(RebootView* reboot_view, InputEvent* event) {
|
||||
with_view_model(
|
||||
reboot_view->view,
|
||||
reboot_view->view,
|
||||
RebootViewModel * model,
|
||||
{
|
||||
if(event->type == InputTypePress) {
|
||||
@@ -133,10 +128,5 @@ View* reboot_view_get_view(RebootView* reboot_view) {
|
||||
void reboot_view_set_data(RebootView* reboot_view, bool connected) {
|
||||
furi_assert(reboot_view);
|
||||
with_view_model(
|
||||
reboot_view->view,
|
||||
RebootViewModel * model,
|
||||
{
|
||||
model->connected = connected;
|
||||
},
|
||||
true);
|
||||
reboot_view->view, RebootViewModel * model, { model->connected = connected; }, true);
|
||||
}
|
||||
@@ -8,10 +8,7 @@
|
||||
#define MODULE_CONTROL_COMMAND_RESET 'a'
|
||||
#define FLIPPERZERO_SERIAL_BAUD 115200
|
||||
|
||||
typedef enum ESerialCommand
|
||||
{
|
||||
ESerialCommand_Reset
|
||||
} ESerialCommand;
|
||||
typedef enum ESerialCommand { ESerialCommand_Reset } ESerialCommand;
|
||||
|
||||
struct ResetView {
|
||||
View* view;
|
||||
@@ -28,17 +25,15 @@ static void Shake(void) {
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
}
|
||||
|
||||
void send_serial_command_reset(ESerialCommand command)
|
||||
{
|
||||
uint8_t data[1] = { 0 };
|
||||
void send_serial_command_reset(ESerialCommand command) {
|
||||
uint8_t data[1] = {0};
|
||||
|
||||
switch(command)
|
||||
{
|
||||
case ESerialCommand_Reset:
|
||||
data[0] = MODULE_CONTROL_COMMAND_RESET;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
switch(command) {
|
||||
case ESerialCommand_Reset:
|
||||
data[0] = MODULE_CONTROL_COMMAND_RESET;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
};
|
||||
|
||||
furi_hal_uart_tx(FuriHalUartIdUSART1, data, 1);
|
||||
@@ -133,10 +128,5 @@ View* reset_view_get_view(ResetView* reset_view) {
|
||||
void reset_view_set_data(ResetView* reset_view, bool connected) {
|
||||
furi_assert(reset_view);
|
||||
with_view_model(
|
||||
reset_view->view,
|
||||
ResetViewModel * model,
|
||||
{
|
||||
model->connected = connected;
|
||||
},
|
||||
true);
|
||||
reset_view->view, ResetViewModel * model, { model->connected = connected; }, true);
|
||||
}
|
||||
@@ -8,10 +8,7 @@
|
||||
#define MODULE_CONTROL_COMMAND_SEND 's'
|
||||
#define FLIPPERZERO_SERIAL_BAUD 115200
|
||||
|
||||
typedef enum ESerialCommand
|
||||
{
|
||||
ESerialCommand_Send
|
||||
} ESerialCommand;
|
||||
typedef enum ESerialCommand { ESerialCommand_Send } ESerialCommand;
|
||||
|
||||
struct SendView {
|
||||
View* view;
|
||||
@@ -28,17 +25,15 @@ static void Shake(void) {
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
}
|
||||
|
||||
void send_serial_command_send(ESerialCommand command)
|
||||
{
|
||||
uint8_t data[1] = { 0 };
|
||||
void send_serial_command_send(ESerialCommand command) {
|
||||
uint8_t data[1] = {0};
|
||||
|
||||
switch(command)
|
||||
{
|
||||
case ESerialCommand_Send:
|
||||
data[0] = MODULE_CONTROL_COMMAND_SEND;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
switch(command) {
|
||||
case ESerialCommand_Send:
|
||||
data[0] = MODULE_CONTROL_COMMAND_SEND;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
};
|
||||
|
||||
furi_hal_uart_tx(FuriHalUartIdUSART1, data, 1);
|
||||
@@ -133,10 +128,5 @@ View* send_view_get_view(SendView* send_view) {
|
||||
void send_view_set_data(SendView* send_view, bool connected) {
|
||||
furi_assert(send_view);
|
||||
with_view_model(
|
||||
send_view->view,
|
||||
SendViewModel * model,
|
||||
{
|
||||
model->connected = connected;
|
||||
},
|
||||
true);
|
||||
send_view->view, SendViewModel * model, { model->connected = connected; }, true);
|
||||
}
|
||||
@@ -11,12 +11,12 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#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 +24,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;
|
||||
@@ -56,36 +56,32 @@ char ts_data_buffer_humidity[DATA_BUFFER_SIZE];
|
||||
// true if fetch was successful, false otherwise
|
||||
// </returns>
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
// 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);
|
||||
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);
|
||||
// Transmit given command
|
||||
ret = furi_hal_i2c_tx(I2C_BUS, HTU21D_ADDRESS, &cmd, 1, timeout);
|
||||
furi_hal_i2c_release(I2C_BUS);
|
||||
if(ret) {
|
||||
uint32_t wait_ticks = furi_ms_to_ticks(50);
|
||||
furi_delay_tick(wait_ticks);
|
||||
|
||||
if (ret)
|
||||
{
|
||||
uint32_t wait_ticks = furi_ms_to_ticks(50);
|
||||
furi_delay_tick(wait_ticks);
|
||||
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);
|
||||
|
||||
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;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// <sumary>
|
||||
@@ -99,201 +95,183 @@ static bool temperature_sensor_cmd(uint8_t cmd, uint8_t* buffer, uint8_t size) {
|
||||
// true if fetch was successful, false otherwise
|
||||
// </returns>
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
// <sumary>
|
||||
// Draw callback
|
||||
// </sumary>
|
||||
static void temperature_sensor_draw_callback(Canvas* canvas, void* ctx) {
|
||||
UNUSED(ctx);
|
||||
|
||||
UNUSED(ctx);
|
||||
canvas_clear(canvas);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 2, 10, "HTU21D Sensor");
|
||||
|
||||
canvas_clear(canvas);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 2, 10, "HTU21D Sensor");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(canvas, 2, 62, "Press back to exit.");
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(canvas, 2, 62, "Press back to exit.");
|
||||
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");
|
||||
|
||||
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 vertical lines
|
||||
canvas_draw_line(canvas, 68, 16, 68, 50);
|
||||
canvas_draw_line(canvas, 69, 16, 69, 50);
|
||||
|
||||
canvas_draw_str(canvas, 6, 24, "Temperature");
|
||||
canvas_draw_str(canvas, 80, 24, "Humidity");
|
||||
// Draw horizontal line
|
||||
canvas_draw_line(canvas, 3, 27, 144, 27);
|
||||
|
||||
// Draw vertical lines
|
||||
canvas_draw_line(canvas, 68, 16, 68, 50);
|
||||
canvas_draw_line(canvas, 69, 16, 69, 50);
|
||||
|
||||
// Draw horizontal line
|
||||
canvas_draw_line(canvas, 3, 27, 144, 27);
|
||||
|
||||
// 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, "%");
|
||||
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// 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, "%");
|
||||
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// <sumary>
|
||||
// Input callback
|
||||
// </sumary>
|
||||
static void temperature_sensor_input_callback(InputEvent* input_event, void* ctx) {
|
||||
furi_assert(ctx);
|
||||
FuriMessageQueue* event_queue = ctx;
|
||||
|
||||
furi_assert(ctx);
|
||||
FuriMessageQueue* event_queue = ctx;
|
||||
|
||||
TSEvent event = { .type = TSEventTypeInput, .input = *input_event };
|
||||
furi_message_queue_put(event_queue, &event, FuriWaitForever);
|
||||
|
||||
TSEvent event = {.type = TSEventTypeInput, .input = *input_event};
|
||||
furi_message_queue_put(event_queue, &event, FuriWaitForever);
|
||||
}
|
||||
|
||||
// <sumary>
|
||||
// Timer callback
|
||||
// </sumary>
|
||||
static void temperature_sensor_timer_callback(FuriMessageQueue* event_queue) {
|
||||
furi_assert(event_queue);
|
||||
|
||||
furi_assert(event_queue);
|
||||
|
||||
TSEvent event = { .type = TSEventTypeTick };
|
||||
furi_message_queue_put(event_queue, &event, 0);
|
||||
|
||||
TSEvent event = {.type = TSEventTypeTick};
|
||||
furi_message_queue_put(event_queue, &event, 0);
|
||||
}
|
||||
|
||||
// <sumary>
|
||||
// App entry point
|
||||
// </sumary>
|
||||
int32_t temperature_sensor_app(void* p) {
|
||||
UNUSED(p);
|
||||
|
||||
UNUSED(p);
|
||||
// Declare our variables
|
||||
TSEvent tsEvent;
|
||||
bool sensorFound = false;
|
||||
double celsius, fahrenheit, humidity;
|
||||
|
||||
// Declare our variables
|
||||
TSEvent tsEvent;
|
||||
bool sensorFound = false;
|
||||
double celsius, fahrenheit, humidity;
|
||||
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(TSEvent));
|
||||
|
||||
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(TSEvent));
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
// 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());
|
||||
|
||||
// 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());
|
||||
// Register viewport
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
// Register viewport
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
// Used to notify the user by blinking red (error) or blue (fetch successful)
|
||||
NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION);
|
||||
|
||||
// Used to notify the user by blinking red (error) or blue (fetch successful)
|
||||
NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION);
|
||||
// Assign variables a default value
|
||||
celsius = fahrenheit = humidity = TS_DEFAULT_VALUE;
|
||||
|
||||
// Assign variables a default value
|
||||
celsius = fahrenheit = humidity = TS_DEFAULT_VALUE;
|
||||
while(1) {
|
||||
furi_check(furi_message_queue_get(event_queue, &tsEvent, FuriWaitForever) == FuriStatusOk);
|
||||
|
||||
while (1) {
|
||||
// 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;
|
||||
|
||||
furi_check(furi_message_queue_get(event_queue, &tsEvent, FuriWaitForever) == FuriStatusOk);
|
||||
} 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);
|
||||
|
||||
// Handle events
|
||||
if (tsEvent.type == TSEventTypeInput) {
|
||||
if(sensorFound) {
|
||||
// Blink blue
|
||||
notification_message(notifications, &sequence_blink_blue_100);
|
||||
|
||||
// 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;
|
||||
if(celsius != TS_DEFAULT_VALUE && humidity != TS_DEFAULT_VALUE) {
|
||||
// Convert celsius to fahrenheit
|
||||
fahrenheit = (celsius * 9 / 5) + 32;
|
||||
|
||||
}
|
||||
else if (tsEvent.type == TSEventTypeTick) {
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
} else {
|
||||
// Reset our variables to their default values
|
||||
celsius = fahrenheit = humidity = TS_DEFAULT_VALUE;
|
||||
|
||||
if (sensorFound) {
|
||||
// Blink red
|
||||
notification_message(notifications, &sequence_blink_red_100);
|
||||
}
|
||||
}
|
||||
|
||||
// Blink blue
|
||||
notification_message(notifications, &sequence_blink_blue_100);
|
||||
uint32_t wait_ticks = furi_ms_to_ticks(!sensorFound ? 100 : 500);
|
||||
furi_delay_tick(wait_ticks);
|
||||
}
|
||||
|
||||
if (celsius != TS_DEFAULT_VALUE && humidity != TS_DEFAULT_VALUE) {
|
||||
// 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);
|
||||
|
||||
// Convert celsius to fahrenheit
|
||||
fahrenheit = (celsius * 9 / 5) + 32;
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
furi_record_close(RECORD_GUI);
|
||||
|
||||
// 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 {
|
||||
|
||||
// Reset our variables to their default values
|
||||
celsius = fahrenheit = 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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#ifndef NOTES
|
||||
#define NOTES
|
||||
|
||||
|
||||
#define C0 16.35f
|
||||
#define Cs0 17.32f
|
||||
#define Db0 17.32f
|
||||
@@ -157,4 +156,3 @@
|
||||
#define B8 7902.13f
|
||||
|
||||
#endif //NOTES
|
||||
|
||||
|
||||
@@ -16,380 +16,381 @@
|
||||
#include "tunings.h"
|
||||
|
||||
typedef enum {
|
||||
EventTypeTick,
|
||||
EventTypeKey,
|
||||
EventTypeTick,
|
||||
EventTypeKey,
|
||||
} EventType;
|
||||
|
||||
typedef struct {
|
||||
EventType type;
|
||||
InputEvent input;
|
||||
EventType type;
|
||||
InputEvent input;
|
||||
} PluginEvent;
|
||||
|
||||
enum Page {
|
||||
Tunings,
|
||||
Notes
|
||||
};
|
||||
enum Page { Tunings, Notes };
|
||||
|
||||
typedef struct {
|
||||
bool playing;
|
||||
enum Page page;
|
||||
int current_tuning_note_index;
|
||||
int current_tuning_index;
|
||||
float volume;
|
||||
TUNING tuning;
|
||||
bool playing;
|
||||
enum Page page;
|
||||
int current_tuning_note_index;
|
||||
int current_tuning_index;
|
||||
float volume;
|
||||
TUNING tuning;
|
||||
} TuningForkState;
|
||||
|
||||
static TUNING current_tuning(TuningForkState* tuningForkState) {
|
||||
return tuningForkState->tuning;
|
||||
return tuningForkState->tuning;
|
||||
}
|
||||
|
||||
static NOTE current_tuning_note(TuningForkState* tuningForkState) {
|
||||
return current_tuning(tuningForkState).notes[tuningForkState->current_tuning_note_index];
|
||||
return current_tuning(tuningForkState).notes[tuningForkState->current_tuning_note_index];
|
||||
}
|
||||
|
||||
static float current_tuning_note_freq(TuningForkState* tuningForkState) {
|
||||
return current_tuning_note(tuningForkState).frequency;
|
||||
return current_tuning_note(tuningForkState).frequency;
|
||||
}
|
||||
|
||||
static void current_tuning_note_label(TuningForkState* tuningForkState, char* outNoteLabel) {
|
||||
for(int i=0; i < 20; ++i){
|
||||
outNoteLabel[i] = current_tuning_note(tuningForkState).label[i];
|
||||
}
|
||||
for(int i = 0; i < 20; ++i) {
|
||||
outNoteLabel[i] = current_tuning_note(tuningForkState).label[i];
|
||||
}
|
||||
}
|
||||
|
||||
static void current_tuning_label(TuningForkState* tuningForkState, char* outTuningLabel) {
|
||||
for(int i=0; i < 20; ++i){
|
||||
outTuningLabel[i] = current_tuning(tuningForkState).label[i];
|
||||
}
|
||||
for(int i = 0; i < 20; ++i) {
|
||||
outTuningLabel[i] = current_tuning(tuningForkState).label[i];
|
||||
}
|
||||
}
|
||||
|
||||
static void updateTuning(TuningForkState* tuning_fork_state) {
|
||||
tuning_fork_state->tuning = TuningList[tuning_fork_state->current_tuning_index];
|
||||
tuning_fork_state->current_tuning_note_index = 0;
|
||||
tuning_fork_state->tuning = TuningList[tuning_fork_state->current_tuning_index];
|
||||
tuning_fork_state->current_tuning_note_index = 0;
|
||||
}
|
||||
|
||||
static void next_tuning(TuningForkState* tuning_fork_state) {
|
||||
if (tuning_fork_state->current_tuning_index == TUNINGS_COUNT - 1) {
|
||||
tuning_fork_state->current_tuning_index = 0;
|
||||
} else {
|
||||
tuning_fork_state->current_tuning_index += 1;
|
||||
}
|
||||
updateTuning(tuning_fork_state);
|
||||
if(tuning_fork_state->current_tuning_index == TUNINGS_COUNT - 1) {
|
||||
tuning_fork_state->current_tuning_index = 0;
|
||||
} else {
|
||||
tuning_fork_state->current_tuning_index += 1;
|
||||
}
|
||||
updateTuning(tuning_fork_state);
|
||||
}
|
||||
|
||||
static void prev_tuning(TuningForkState* tuning_fork_state) {
|
||||
if (tuning_fork_state->current_tuning_index - 1 < 0) {
|
||||
tuning_fork_state->current_tuning_index = TUNINGS_COUNT - 1;
|
||||
} else {
|
||||
tuning_fork_state->current_tuning_index -= 1;
|
||||
}
|
||||
updateTuning(tuning_fork_state);
|
||||
if(tuning_fork_state->current_tuning_index - 1 < 0) {
|
||||
tuning_fork_state->current_tuning_index = TUNINGS_COUNT - 1;
|
||||
} else {
|
||||
tuning_fork_state->current_tuning_index -= 1;
|
||||
}
|
||||
updateTuning(tuning_fork_state);
|
||||
}
|
||||
|
||||
static void next_note(TuningForkState* tuning_fork_state) {
|
||||
if (tuning_fork_state->current_tuning_note_index == current_tuning(tuning_fork_state).notes_length - 1) {
|
||||
tuning_fork_state->current_tuning_note_index = 0;
|
||||
} else {
|
||||
tuning_fork_state->current_tuning_note_index += 1;
|
||||
}
|
||||
if(tuning_fork_state->current_tuning_note_index ==
|
||||
current_tuning(tuning_fork_state).notes_length - 1) {
|
||||
tuning_fork_state->current_tuning_note_index = 0;
|
||||
} else {
|
||||
tuning_fork_state->current_tuning_note_index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void prev_note(TuningForkState* tuning_fork_state) {
|
||||
if (tuning_fork_state->current_tuning_note_index == 0) {
|
||||
tuning_fork_state->current_tuning_note_index = current_tuning(tuning_fork_state).notes_length - 1;
|
||||
} else {
|
||||
tuning_fork_state->current_tuning_note_index -= 1;
|
||||
}
|
||||
if(tuning_fork_state->current_tuning_note_index == 0) {
|
||||
tuning_fork_state->current_tuning_note_index =
|
||||
current_tuning(tuning_fork_state).notes_length - 1;
|
||||
} else {
|
||||
tuning_fork_state->current_tuning_note_index -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void increase_volume(TuningForkState* tuning_fork_state) {
|
||||
if (tuning_fork_state->volume < 1.0f) {
|
||||
tuning_fork_state->volume += 0.1f;
|
||||
}
|
||||
if(tuning_fork_state->volume < 1.0f) {
|
||||
tuning_fork_state->volume += 0.1f;
|
||||
}
|
||||
}
|
||||
|
||||
static void decrease_volume(TuningForkState* tuning_fork_state) {
|
||||
if (tuning_fork_state->volume > 0.0f) {
|
||||
tuning_fork_state->volume -= 0.1f;
|
||||
}
|
||||
if(tuning_fork_state->volume > 0.0f) {
|
||||
tuning_fork_state->volume -= 0.1f;
|
||||
}
|
||||
}
|
||||
|
||||
static void play(TuningForkState* tuning_fork_state) {
|
||||
furi_hal_speaker_start(current_tuning_note_freq(tuning_fork_state), tuning_fork_state->volume);
|
||||
furi_hal_speaker_start(current_tuning_note_freq(tuning_fork_state), tuning_fork_state->volume);
|
||||
}
|
||||
|
||||
static void stop() {
|
||||
furi_hal_speaker_stop();
|
||||
furi_hal_speaker_stop();
|
||||
}
|
||||
|
||||
static void replay(TuningForkState* tuning_fork_state) {
|
||||
stop();
|
||||
play(tuning_fork_state);
|
||||
stop();
|
||||
play(tuning_fork_state);
|
||||
}
|
||||
|
||||
static void render_callback(Canvas* const canvas, void* ctx) {
|
||||
TuningForkState* tuning_fork_state = acquire_mutex((ValueMutex*)ctx, 25);
|
||||
if(tuning_fork_state == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
string_t tempStr;
|
||||
string_init(tempStr);
|
||||
|
||||
canvas_draw_frame(canvas, 0, 0, 128, 64);
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
|
||||
if (tuning_fork_state->page == Tunings) {
|
||||
char tuningLabel[20];
|
||||
current_tuning_label(tuning_fork_state, tuningLabel);
|
||||
string_printf(tempStr, "< %s >", tuningLabel);
|
||||
canvas_draw_str_aligned(canvas, 64, 28, AlignCenter, AlignCenter, string_get_cstr(tempStr));
|
||||
string_reset(tempStr);
|
||||
} else {
|
||||
char tuningLabel[20];
|
||||
current_tuning_label(tuning_fork_state, tuningLabel);
|
||||
string_printf(tempStr, "%s", tuningLabel);
|
||||
canvas_draw_str_aligned(canvas, 64, 8, AlignCenter, AlignCenter, string_get_cstr(tempStr));
|
||||
string_reset(tempStr);
|
||||
|
||||
char tuningNoteLabel[20];
|
||||
current_tuning_note_label(tuning_fork_state, tuningNoteLabel);
|
||||
string_printf(tempStr, "< %s >", tuningNoteLabel);
|
||||
canvas_draw_str_aligned(canvas, 64, 24, AlignCenter, AlignCenter, string_get_cstr(tempStr));
|
||||
string_reset(tempStr);
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_button_left(canvas, "Prev");
|
||||
elements_button_right(canvas, "Next");
|
||||
|
||||
if (tuning_fork_state->page == Notes) {
|
||||
if (tuning_fork_state->playing) {
|
||||
elements_button_center(canvas, "Stop ");
|
||||
} else {
|
||||
elements_button_center(canvas, "Play");
|
||||
TuningForkState* tuning_fork_state = acquire_mutex((ValueMutex*)ctx, 25);
|
||||
if(tuning_fork_state == NULL) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
elements_button_center(canvas, "Select");
|
||||
}
|
||||
if (tuning_fork_state->page == Notes) {
|
||||
elements_progress_bar(canvas, 8, 36, 112, tuning_fork_state->volume);
|
||||
}
|
||||
|
||||
string_clear(tempStr);
|
||||
release_mutex((ValueMutex*)ctx, tuning_fork_state);
|
||||
string_t tempStr;
|
||||
string_init(tempStr);
|
||||
|
||||
canvas_draw_frame(canvas, 0, 0, 128, 64);
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
|
||||
if(tuning_fork_state->page == Tunings) {
|
||||
char tuningLabel[20];
|
||||
current_tuning_label(tuning_fork_state, tuningLabel);
|
||||
string_printf(tempStr, "< %s >", tuningLabel);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 28, AlignCenter, AlignCenter, string_get_cstr(tempStr));
|
||||
string_reset(tempStr);
|
||||
} else {
|
||||
char tuningLabel[20];
|
||||
current_tuning_label(tuning_fork_state, tuningLabel);
|
||||
string_printf(tempStr, "%s", tuningLabel);
|
||||
canvas_draw_str_aligned(canvas, 64, 8, AlignCenter, AlignCenter, string_get_cstr(tempStr));
|
||||
string_reset(tempStr);
|
||||
|
||||
char tuningNoteLabel[20];
|
||||
current_tuning_note_label(tuning_fork_state, tuningNoteLabel);
|
||||
string_printf(tempStr, "< %s >", tuningNoteLabel);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 24, AlignCenter, AlignCenter, string_get_cstr(tempStr));
|
||||
string_reset(tempStr);
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_button_left(canvas, "Prev");
|
||||
elements_button_right(canvas, "Next");
|
||||
|
||||
if(tuning_fork_state->page == Notes) {
|
||||
if(tuning_fork_state->playing) {
|
||||
elements_button_center(canvas, "Stop ");
|
||||
} else {
|
||||
elements_button_center(canvas, "Play");
|
||||
}
|
||||
} else {
|
||||
elements_button_center(canvas, "Select");
|
||||
}
|
||||
if(tuning_fork_state->page == Notes) {
|
||||
elements_progress_bar(canvas, 8, 36, 112, tuning_fork_state->volume);
|
||||
}
|
||||
|
||||
string_clear(tempStr);
|
||||
release_mutex((ValueMutex*)ctx, tuning_fork_state);
|
||||
}
|
||||
|
||||
static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
|
||||
furi_assert(event_queue);
|
||||
furi_assert(event_queue);
|
||||
|
||||
PluginEvent event = {.type = EventTypeKey, .input = *input_event};
|
||||
furi_message_queue_put(event_queue, &event, FuriWaitForever);
|
||||
PluginEvent event = {.type = EventTypeKey, .input = *input_event};
|
||||
furi_message_queue_put(event_queue, &event, FuriWaitForever);
|
||||
}
|
||||
|
||||
static void tuning_fork_state_init(TuningForkState* const tuning_fork_state) {
|
||||
tuning_fork_state->playing = false;
|
||||
tuning_fork_state->page = Tunings;
|
||||
tuning_fork_state->volume = 1.0f;
|
||||
tuning_fork_state->tuning = GuitarStandard6;
|
||||
tuning_fork_state->current_tuning_index = 2;
|
||||
tuning_fork_state->current_tuning_note_index = 0;
|
||||
tuning_fork_state->playing = false;
|
||||
tuning_fork_state->page = Tunings;
|
||||
tuning_fork_state->volume = 1.0f;
|
||||
tuning_fork_state->tuning = GuitarStandard6;
|
||||
tuning_fork_state->current_tuning_index = 2;
|
||||
tuning_fork_state->current_tuning_note_index = 0;
|
||||
}
|
||||
|
||||
int32_t tuning_fork_app() {
|
||||
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
|
||||
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
|
||||
|
||||
TuningForkState* tuning_fork_state = malloc(sizeof(TuningForkState));
|
||||
tuning_fork_state_init(tuning_fork_state);
|
||||
TuningForkState* tuning_fork_state = malloc(sizeof(TuningForkState));
|
||||
tuning_fork_state_init(tuning_fork_state);
|
||||
|
||||
ValueMutex state_mutex;
|
||||
if(!init_mutex(&state_mutex, tuning_fork_state, sizeof(TuningForkState))) {
|
||||
FURI_LOG_E("TuningFork", "cannot create mutex\r\n");
|
||||
free(tuning_fork_state);
|
||||
return 255;
|
||||
}
|
||||
|
||||
// Set system callbacks
|
||||
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);
|
||||
|
||||
Gui* gui = furi_record_open("gui");
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
PluginEvent event;
|
||||
for(bool processing = true; processing;) {
|
||||
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
|
||||
|
||||
TuningForkState* tuning_fork_state = (TuningForkState*)acquire_mutex_block(&state_mutex);
|
||||
|
||||
if(event_status == FuriStatusOk) {
|
||||
if(event.type == EventTypeKey) {
|
||||
if(event.input.type == InputTypeShort) {
|
||||
// push events
|
||||
switch(event.input.key) {
|
||||
case InputKeyUp:
|
||||
if (tuning_fork_state->page == Notes) {
|
||||
increase_volume(tuning_fork_state);
|
||||
if (tuning_fork_state->playing) {
|
||||
replay(tuning_fork_state);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyDown:
|
||||
if (tuning_fork_state->page == Notes) {
|
||||
decrease_volume(tuning_fork_state);
|
||||
if (tuning_fork_state->playing) {
|
||||
replay(tuning_fork_state);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyRight:
|
||||
if (tuning_fork_state->page == Tunings) {
|
||||
next_tuning(tuning_fork_state);
|
||||
} else {
|
||||
next_note(tuning_fork_state);
|
||||
if (tuning_fork_state->playing) {
|
||||
replay(tuning_fork_state);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
if (tuning_fork_state->page == Tunings) {
|
||||
prev_tuning(tuning_fork_state);
|
||||
} else {
|
||||
prev_note(tuning_fork_state);
|
||||
if (tuning_fork_state->playing) {
|
||||
replay(tuning_fork_state);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyOk:
|
||||
if (tuning_fork_state->page == Tunings) {
|
||||
tuning_fork_state->page = Notes;
|
||||
} else {
|
||||
tuning_fork_state->playing = !tuning_fork_state->playing;
|
||||
if (tuning_fork_state->playing) {
|
||||
play(tuning_fork_state);
|
||||
} else {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyBack:
|
||||
if (tuning_fork_state->page == Tunings) {
|
||||
processing = false;
|
||||
} else {
|
||||
tuning_fork_state->playing = false;
|
||||
tuning_fork_state->current_tuning_note_index = 0;
|
||||
stop();
|
||||
tuning_fork_state->page = Tunings;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (event.input.type == InputTypeLong) {
|
||||
// hold events
|
||||
switch(event.input.key) {
|
||||
case InputKeyUp:
|
||||
break;
|
||||
case InputKeyDown:
|
||||
break;
|
||||
case InputKeyRight:
|
||||
if (tuning_fork_state->page == Tunings) {
|
||||
next_tuning(tuning_fork_state);
|
||||
} else {
|
||||
next_note(tuning_fork_state);
|
||||
if (tuning_fork_state->playing) {
|
||||
replay(tuning_fork_state);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
if (tuning_fork_state->page == Tunings) {
|
||||
prev_tuning(tuning_fork_state);
|
||||
} else {
|
||||
prev_note(tuning_fork_state);
|
||||
if (tuning_fork_state->playing) {
|
||||
replay(tuning_fork_state);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case InputKeyOk:
|
||||
break;
|
||||
case InputKeyBack:
|
||||
if (tuning_fork_state->page == Tunings) {
|
||||
processing = false;
|
||||
} else {
|
||||
tuning_fork_state->playing = false;
|
||||
stop();
|
||||
tuning_fork_state->page = Tunings;
|
||||
tuning_fork_state->current_tuning_note_index = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (event.input.type == InputTypeRepeat) {
|
||||
// repeat events
|
||||
switch(event.input.key) {
|
||||
case InputKeyUp:
|
||||
break;
|
||||
case InputKeyDown:
|
||||
break;
|
||||
case InputKeyRight:
|
||||
if (tuning_fork_state->page == Tunings) {
|
||||
next_tuning(tuning_fork_state);
|
||||
} else {
|
||||
next_note(tuning_fork_state);
|
||||
if (tuning_fork_state->playing) {
|
||||
replay(tuning_fork_state);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
if (tuning_fork_state->page == Tunings) {
|
||||
prev_tuning(tuning_fork_state);
|
||||
} else {
|
||||
prev_note(tuning_fork_state);
|
||||
if (tuning_fork_state->playing) {
|
||||
replay(tuning_fork_state);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case InputKeyOk:
|
||||
break;
|
||||
case InputKeyBack:
|
||||
if (tuning_fork_state->page == Tunings) {
|
||||
processing = false;
|
||||
} else {
|
||||
tuning_fork_state->playing = false;
|
||||
stop();
|
||||
tuning_fork_state->page = Tunings;
|
||||
tuning_fork_state->current_tuning_note_index = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_D("TuningFork", "FuriMessageQueue: event timeout");
|
||||
ValueMutex state_mutex;
|
||||
if(!init_mutex(&state_mutex, tuning_fork_state, sizeof(TuningForkState))) {
|
||||
FURI_LOG_E("TuningFork", "cannot create mutex\r\n");
|
||||
free(tuning_fork_state);
|
||||
return 255;
|
||||
}
|
||||
|
||||
view_port_update(view_port);
|
||||
release_mutex(&state_mutex, tuning_fork_state);
|
||||
}
|
||||
// Set system callbacks
|
||||
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);
|
||||
|
||||
view_port_enabled_set(view_port, false);
|
||||
gui_remove_view_port(gui, view_port);
|
||||
furi_record_close("gui");
|
||||
view_port_free(view_port);
|
||||
furi_message_queue_free(event_queue);
|
||||
delete_mutex(&state_mutex);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
free(tuning_fork_state);
|
||||
Gui* gui = furi_record_open("gui");
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
return 0;
|
||||
PluginEvent event;
|
||||
for(bool processing = true; processing;) {
|
||||
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
|
||||
|
||||
TuningForkState* tuning_fork_state = (TuningForkState*)acquire_mutex_block(&state_mutex);
|
||||
|
||||
if(event_status == FuriStatusOk) {
|
||||
if(event.type == EventTypeKey) {
|
||||
if(event.input.type == InputTypeShort) {
|
||||
// push events
|
||||
switch(event.input.key) {
|
||||
case InputKeyUp:
|
||||
if(tuning_fork_state->page == Notes) {
|
||||
increase_volume(tuning_fork_state);
|
||||
if(tuning_fork_state->playing) {
|
||||
replay(tuning_fork_state);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyDown:
|
||||
if(tuning_fork_state->page == Notes) {
|
||||
decrease_volume(tuning_fork_state);
|
||||
if(tuning_fork_state->playing) {
|
||||
replay(tuning_fork_state);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyRight:
|
||||
if(tuning_fork_state->page == Tunings) {
|
||||
next_tuning(tuning_fork_state);
|
||||
} else {
|
||||
next_note(tuning_fork_state);
|
||||
if(tuning_fork_state->playing) {
|
||||
replay(tuning_fork_state);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
if(tuning_fork_state->page == Tunings) {
|
||||
prev_tuning(tuning_fork_state);
|
||||
} else {
|
||||
prev_note(tuning_fork_state);
|
||||
if(tuning_fork_state->playing) {
|
||||
replay(tuning_fork_state);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyOk:
|
||||
if(tuning_fork_state->page == Tunings) {
|
||||
tuning_fork_state->page = Notes;
|
||||
} else {
|
||||
tuning_fork_state->playing = !tuning_fork_state->playing;
|
||||
if(tuning_fork_state->playing) {
|
||||
play(tuning_fork_state);
|
||||
} else {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyBack:
|
||||
if(tuning_fork_state->page == Tunings) {
|
||||
processing = false;
|
||||
} else {
|
||||
tuning_fork_state->playing = false;
|
||||
tuning_fork_state->current_tuning_note_index = 0;
|
||||
stop();
|
||||
tuning_fork_state->page = Tunings;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if(event.input.type == InputTypeLong) {
|
||||
// hold events
|
||||
switch(event.input.key) {
|
||||
case InputKeyUp:
|
||||
break;
|
||||
case InputKeyDown:
|
||||
break;
|
||||
case InputKeyRight:
|
||||
if(tuning_fork_state->page == Tunings) {
|
||||
next_tuning(tuning_fork_state);
|
||||
} else {
|
||||
next_note(tuning_fork_state);
|
||||
if(tuning_fork_state->playing) {
|
||||
replay(tuning_fork_state);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
if(tuning_fork_state->page == Tunings) {
|
||||
prev_tuning(tuning_fork_state);
|
||||
} else {
|
||||
prev_note(tuning_fork_state);
|
||||
if(tuning_fork_state->playing) {
|
||||
replay(tuning_fork_state);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case InputKeyOk:
|
||||
break;
|
||||
case InputKeyBack:
|
||||
if(tuning_fork_state->page == Tunings) {
|
||||
processing = false;
|
||||
} else {
|
||||
tuning_fork_state->playing = false;
|
||||
stop();
|
||||
tuning_fork_state->page = Tunings;
|
||||
tuning_fork_state->current_tuning_note_index = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if(event.input.type == InputTypeRepeat) {
|
||||
// repeat events
|
||||
switch(event.input.key) {
|
||||
case InputKeyUp:
|
||||
break;
|
||||
case InputKeyDown:
|
||||
break;
|
||||
case InputKeyRight:
|
||||
if(tuning_fork_state->page == Tunings) {
|
||||
next_tuning(tuning_fork_state);
|
||||
} else {
|
||||
next_note(tuning_fork_state);
|
||||
if(tuning_fork_state->playing) {
|
||||
replay(tuning_fork_state);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
if(tuning_fork_state->page == Tunings) {
|
||||
prev_tuning(tuning_fork_state);
|
||||
} else {
|
||||
prev_note(tuning_fork_state);
|
||||
if(tuning_fork_state->playing) {
|
||||
replay(tuning_fork_state);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case InputKeyOk:
|
||||
break;
|
||||
case InputKeyBack:
|
||||
if(tuning_fork_state->page == Tunings) {
|
||||
processing = false;
|
||||
} else {
|
||||
tuning_fork_state->playing = false;
|
||||
stop();
|
||||
tuning_fork_state->page = Tunings;
|
||||
tuning_fork_state->current_tuning_note_index = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_D("TuningFork", "FuriMessageQueue: event timeout");
|
||||
}
|
||||
|
||||
view_port_update(view_port);
|
||||
release_mutex(&state_mutex, tuning_fork_state);
|
||||
}
|
||||
|
||||
view_port_enabled_set(view_port, false);
|
||||
gui_remove_view_port(gui, view_port);
|
||||
furi_record_close("gui");
|
||||
view_port_free(view_port);
|
||||
furi_message_queue_free(event_queue);
|
||||
delete_mutex(&state_mutex);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
free(tuning_fork_state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4,185 +4,148 @@
|
||||
#define TUNINGS
|
||||
|
||||
typedef struct {
|
||||
char label[20];
|
||||
float frequency;
|
||||
char label[20];
|
||||
float frequency;
|
||||
} NOTE;
|
||||
|
||||
typedef struct {
|
||||
char label[20];
|
||||
int notes_length;
|
||||
NOTE notes[20];
|
||||
char label[20];
|
||||
int notes_length;
|
||||
NOTE notes[20];
|
||||
} TUNING;
|
||||
|
||||
const TUNING TuningForks = {
|
||||
"Tuning forks", 6, {
|
||||
{ "Common A4 (440)", 440.00f},
|
||||
{ "Sarti's A4 (436)", 436.00f},
|
||||
{ "1858 A4 (435)", 435.00f},
|
||||
{ "Verdi's A4 (432)", 432.00f},
|
||||
{ "1750-1820 A4 (423.5)", 423.50f},
|
||||
{ "Verdi's C4 (256.00)", 256.00f},
|
||||
}
|
||||
};
|
||||
"Tuning forks",
|
||||
6,
|
||||
{
|
||||
{"Common A4 (440)", 440.00f},
|
||||
{"Sarti's A4 (436)", 436.00f},
|
||||
{"1858 A4 (435)", 435.00f},
|
||||
{"Verdi's A4 (432)", 432.00f},
|
||||
{"1750-1820 A4 (423.5)", 423.50f},
|
||||
{"Verdi's C4 (256.00)", 256.00f},
|
||||
}};
|
||||
|
||||
const TUNING ScientificPitch = {
|
||||
"Scientific pitch", 12, {
|
||||
{ "C0 (16Hz)", 16.0f},
|
||||
{ "C1 (32Hz)", 32.0f},
|
||||
{ "C2 (64Hz)", 64.0f},
|
||||
{ "C3 (128Hz)", 128.0f},
|
||||
{ "C4 (256Hz)", 256.0f},
|
||||
{ "C5 (512Hz)", 512.0f},
|
||||
{ "C6 (1024Hz)", 1024.0f},
|
||||
{ "C7 (2048Hz)", 2048.0f},
|
||||
{ "C8 (4096Hz)", 4096.0f},
|
||||
{ "C9 (8192Hz)", 8192.0f},
|
||||
{ "C10 (16384Hz)", 16384.0f},
|
||||
{ "C11 (32768Hz)", 32768.0f}
|
||||
}
|
||||
};
|
||||
"Scientific pitch",
|
||||
12,
|
||||
{{"C0 (16Hz)", 16.0f},
|
||||
{"C1 (32Hz)", 32.0f},
|
||||
{"C2 (64Hz)", 64.0f},
|
||||
{"C3 (128Hz)", 128.0f},
|
||||
{"C4 (256Hz)", 256.0f},
|
||||
{"C5 (512Hz)", 512.0f},
|
||||
{"C6 (1024Hz)", 1024.0f},
|
||||
{"C7 (2048Hz)", 2048.0f},
|
||||
{"C8 (4096Hz)", 4096.0f},
|
||||
{"C9 (8192Hz)", 8192.0f},
|
||||
{"C10 (16384Hz)", 16384.0f},
|
||||
{"C11 (32768Hz)", 32768.0f}}};
|
||||
|
||||
const TUNING GuitarStandard6 = {
|
||||
"Guitar Standard 6", 6, {
|
||||
{"String 1", E4},
|
||||
{"String 2", B3},
|
||||
{"String 3", G3},
|
||||
{"String 4", D3},
|
||||
{"String 5", A2},
|
||||
{"String 6", E2}
|
||||
}
|
||||
};
|
||||
"Guitar Standard 6",
|
||||
6,
|
||||
{{"String 1", E4},
|
||||
{"String 2", B3},
|
||||
{"String 3", G3},
|
||||
{"String 4", D3},
|
||||
{"String 5", A2},
|
||||
{"String 6", E2}}};
|
||||
|
||||
const TUNING GuitarDropD6 = {
|
||||
"Guitar Drop D 6", 6, {
|
||||
{"String 1", E4},
|
||||
{"String 2", B3},
|
||||
{"String 3", G3},
|
||||
{"String 4", D3},
|
||||
{"String 5", A2},
|
||||
{"String 6", D2}
|
||||
}
|
||||
};
|
||||
"Guitar Drop D 6",
|
||||
6,
|
||||
{{"String 1", E4},
|
||||
{"String 2", B3},
|
||||
{"String 3", G3},
|
||||
{"String 4", D3},
|
||||
{"String 5", A2},
|
||||
{"String 6", D2}}};
|
||||
|
||||
const TUNING GuitarD6 = {
|
||||
"Guitar D 6", 6, {
|
||||
{"String 1", D4},
|
||||
{"String 2", A3},
|
||||
{"String 3", F3},
|
||||
{"String 4", C3},
|
||||
{"String 5", G2},
|
||||
{"String 6", D2}
|
||||
}
|
||||
};
|
||||
"Guitar D 6",
|
||||
6,
|
||||
{{"String 1", D4},
|
||||
{"String 2", A3},
|
||||
{"String 3", F3},
|
||||
{"String 4", C3},
|
||||
{"String 5", G2},
|
||||
{"String 6", D2}}};
|
||||
|
||||
const TUNING GuitarDropC6 = {
|
||||
"Guitar Drop C 6", 6, {
|
||||
{"String 1", D4},
|
||||
{"String 2", A3},
|
||||
{"String 3", F3},
|
||||
{"String 4", C3},
|
||||
{"String 5", G2},
|
||||
{"String 6", C2}
|
||||
}
|
||||
};
|
||||
"Guitar Drop C 6",
|
||||
6,
|
||||
{{"String 1", D4},
|
||||
{"String 2", A3},
|
||||
{"String 3", F3},
|
||||
{"String 4", C3},
|
||||
{"String 5", G2},
|
||||
{"String 6", C2}}};
|
||||
|
||||
const TUNING GuitarStandard7 = {
|
||||
"Guitar Standard 7", 7, {
|
||||
{"String 1", E4},
|
||||
{"String 2", B3},
|
||||
{"String 3", G3},
|
||||
{"String 4", D3},
|
||||
{"String 5", A2},
|
||||
{"String 6", E2},
|
||||
{"String 7", B1}
|
||||
}
|
||||
};
|
||||
"Guitar Standard 7",
|
||||
7,
|
||||
{{"String 1", E4},
|
||||
{"String 2", B3},
|
||||
{"String 3", G3},
|
||||
{"String 4", D3},
|
||||
{"String 5", A2},
|
||||
{"String 6", E2},
|
||||
{"String 7", B1}}};
|
||||
|
||||
const TUNING BassStandard4 = {
|
||||
"Bass Standard 4", 4, {
|
||||
{"String 1", G2},
|
||||
{"String 2", D2},
|
||||
{"String 3", A1},
|
||||
{"String 4", E1}
|
||||
}
|
||||
};
|
||||
"Bass Standard 4",
|
||||
4,
|
||||
{{"String 1", G2}, {"String 2", D2}, {"String 3", A1}, {"String 4", E1}}};
|
||||
|
||||
const TUNING BassStandardTenor4 = {
|
||||
"Bass Stand Tenor 4", 4, {
|
||||
{"String 1", C3},
|
||||
{"String 2", G2},
|
||||
{"String 3", D2},
|
||||
{"String 4", A1}
|
||||
}
|
||||
};
|
||||
"Bass Stand Tenor 4",
|
||||
4,
|
||||
{{"String 1", C3}, {"String 2", G2}, {"String 3", D2}, {"String 4", A1}}};
|
||||
|
||||
const TUNING BassStandard5 = {
|
||||
"Bass Standard 5", 5, {
|
||||
{"String 1", G2},
|
||||
{"String 2", D2},
|
||||
{"String 3", A1},
|
||||
{"String 4", E1},
|
||||
{"String 5", B0}
|
||||
}
|
||||
};
|
||||
"Bass Standard 5",
|
||||
5,
|
||||
{{"String 1", G2}, {"String 2", D2}, {"String 3", A1}, {"String 4", E1}, {"String 5", B0}}};
|
||||
|
||||
const TUNING BassStandardTenor5 = {
|
||||
"Bass Stand Tenor 5", 5, {
|
||||
{"String 1", C3},
|
||||
{"String 2", G2},
|
||||
{"String 3", D2},
|
||||
{"String 4", A1},
|
||||
{"String 5", E1}
|
||||
}
|
||||
};
|
||||
"Bass Stand Tenor 5",
|
||||
5,
|
||||
{{"String 1", C3}, {"String 2", G2}, {"String 3", D2}, {"String 4", A1}, {"String 5", E1}}};
|
||||
|
||||
const TUNING BassDropD4 = {
|
||||
"Bass Drop D 4", 4, {
|
||||
{"String 1", G2},
|
||||
{"String 2", D2},
|
||||
{"String 3", A1},
|
||||
{"String 4", D1}
|
||||
}
|
||||
};
|
||||
"Bass Drop D 4",
|
||||
4,
|
||||
{{"String 1", G2}, {"String 2", D2}, {"String 3", A1}, {"String 4", D1}}};
|
||||
|
||||
const TUNING BassD4 = {
|
||||
"Bass D 4", 4, {
|
||||
{"String 1", F2},
|
||||
{"String 2", C2},
|
||||
{"String 3", G1},
|
||||
{"String 4", D1}
|
||||
}
|
||||
};
|
||||
"Bass D 4",
|
||||
4,
|
||||
{{"String 1", F2}, {"String 2", C2}, {"String 3", G1}, {"String 4", D1}}};
|
||||
|
||||
const TUNING BassDropA5 = {
|
||||
"Bass Drop A 5", 5, {
|
||||
{"String 1", G2},
|
||||
{"String 2", D2},
|
||||
{"String 3", A1},
|
||||
{"String 4", E1},
|
||||
{"String 5", A0}
|
||||
}
|
||||
};
|
||||
"Bass Drop A 5",
|
||||
5,
|
||||
{{"String 1", G2}, {"String 2", D2}, {"String 3", A1}, {"String 4", E1}, {"String 5", A0}}};
|
||||
|
||||
#define TUNINGS_COUNT 14
|
||||
|
||||
TUNING TuningList[TUNINGS_COUNT] = {
|
||||
ScientificPitch,
|
||||
TuningForks,
|
||||
ScientificPitch,
|
||||
TuningForks,
|
||||
|
||||
GuitarStandard6,
|
||||
GuitarDropD6,
|
||||
GuitarD6,
|
||||
GuitarDropC6,
|
||||
GuitarStandard7,
|
||||
GuitarStandard6,
|
||||
GuitarDropD6,
|
||||
GuitarD6,
|
||||
GuitarDropC6,
|
||||
GuitarStandard7,
|
||||
|
||||
BassStandard4,
|
||||
BassStandardTenor4,
|
||||
BassStandard5,
|
||||
BassStandardTenor5,
|
||||
BassDropD4,
|
||||
BassD4,
|
||||
BassDropA5
|
||||
};
|
||||
BassStandard4,
|
||||
BassStandardTenor4,
|
||||
BassStandard5,
|
||||
BassStandardTenor5,
|
||||
BassDropD4,
|
||||
BassD4,
|
||||
BassDropA5};
|
||||
|
||||
#endif //TUNINGS
|
||||
|
||||
Reference in New Issue
Block a user