fmt fixes

This commit is contained in:
RogueMaster
2022-10-17 00:38:01 -04:00
parent dca21c1e53
commit 0ec04b54bf
30 changed files with 1493 additions and 1505 deletions
+310 -248
View File
@@ -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);
+140 -146
View File
@@ -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);
}
}
+28 -9
View File
@@ -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);
+2 -10
View File
@@ -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;
+92 -79
View File
@@ -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
// );
}
+8 -8
View File
@@ -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);
+70 -65
View File
@@ -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;
+23 -14
View File
@@ -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);
+15 -26
View File
@@ -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);
}
+11 -21
View File
@@ -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);
}
+10 -20
View File
@@ -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);
}
+10 -20
View File
@@ -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;
}
-2
View File
@@ -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
+304 -303
View File
@@ -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;
}
+105 -142
View File
@@ -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